浏览代码

Merge pull request #5599 from open-webui/dev

0.3.24
Timothy Jaeryang Baek 10 月之前
父节点
当前提交
7ec72679f0
共有 80 个文件被更改,包括 1659 次插入872 次删除
  1. 29 0
      CHANGELOG.md
  2. 1 1
      backend/open_webui/apps/audio/main.py
  3. 81 62
      backend/open_webui/apps/socket/main.py
  4. 59 0
      backend/open_webui/apps/socket/utils.py
  5. 2 1
      backend/open_webui/apps/webui/utils.py
  6. 1 0
      backend/open_webui/env.py
  7. 2 1
      backend/open_webui/main.py
  8. 1 1
      backend/requirements.txt
  9. 73 73
      package-lock.json
  10. 1 1
      package.json
  11. 1 1
      pyproject.toml
  12. 220 156
      src/lib/components/chat/Chat.svelte
  13. 8 3
      src/lib/components/chat/ChatControls.svelte
  14. 14 8
      src/lib/components/chat/MessageInput.svelte
  15. 45 5
      src/lib/components/chat/MessageInput/Commands/Prompts.svelte
  16. 177 216
      src/lib/components/chat/Messages.svelte
  17. 23 13
      src/lib/components/chat/Messages/CitationsModal.svelte
  18. 15 1
      src/lib/components/chat/Messages/CodeBlock.svelte
  19. 1 1
      src/lib/components/chat/Messages/Markdown/MarkdownTokens.svelte
  20. 166 0
      src/lib/components/chat/Messages/Message.svelte
  21. 139 123
      src/lib/components/chat/Messages/MultiResponseMessages.svelte
  22. 31 21
      src/lib/components/chat/Messages/ResponseMessage.svelte
  23. 39 15
      src/lib/components/chat/Messages/UserMessage.svelte
  24. 24 5
      src/lib/components/chat/Overview/Node.svelte
  25. 31 2
      src/lib/components/chat/Settings/Advanced/AdvancedParams.svelte
  26. 2 0
      src/lib/components/chat/Settings/General.svelte
  27. 0 30
      src/lib/components/chat/Settings/Interface.svelte
  28. 19 3
      src/lib/components/common/Loader.svelte
  29. 3 1
      src/lib/components/common/Tooltip.svelte
  30. 1 1
      src/lib/components/layout/Sidebar.svelte
  31. 17 1
      src/lib/components/layout/Sidebar/UserMenu.svelte
  32. 44 0
      src/lib/components/layout/UpdateInfoToast.svelte
  33. 1 1
      src/lib/components/workspace/Documents.svelte
  34. 17 3
      src/lib/components/workspace/Models.svelte
  35. 3 1
      src/lib/constants.ts
  36. 4 0
      src/lib/i18n/locales/ar-BH/translation.json
  37. 4 0
      src/lib/i18n/locales/bg-BG/translation.json
  38. 4 0
      src/lib/i18n/locales/bn-BD/translation.json
  39. 4 0
      src/lib/i18n/locales/ca-ES/translation.json
  40. 4 0
      src/lib/i18n/locales/ceb-PH/translation.json
  41. 4 0
      src/lib/i18n/locales/de-DE/translation.json
  42. 4 0
      src/lib/i18n/locales/dg-DG/translation.json
  43. 4 0
      src/lib/i18n/locales/en-GB/translation.json
  44. 4 0
      src/lib/i18n/locales/en-US/translation.json
  45. 4 0
      src/lib/i18n/locales/es-ES/translation.json
  46. 4 0
      src/lib/i18n/locales/fa-IR/translation.json
  47. 4 0
      src/lib/i18n/locales/fi-FI/translation.json
  48. 4 0
      src/lib/i18n/locales/fr-CA/translation.json
  49. 4 0
      src/lib/i18n/locales/fr-FR/translation.json
  50. 4 0
      src/lib/i18n/locales/he-IL/translation.json
  51. 4 0
      src/lib/i18n/locales/hi-IN/translation.json
  52. 4 0
      src/lib/i18n/locales/hr-HR/translation.json
  53. 4 0
      src/lib/i18n/locales/id-ID/translation.json
  54. 4 0
      src/lib/i18n/locales/it-IT/translation.json
  55. 4 0
      src/lib/i18n/locales/ja-JP/translation.json
  56. 4 0
      src/lib/i18n/locales/ka-GE/translation.json
  57. 4 0
      src/lib/i18n/locales/ko-KR/translation.json
  58. 4 0
      src/lib/i18n/locales/lt-LT/translation.json
  59. 4 0
      src/lib/i18n/locales/ms-MY/translation.json
  60. 4 0
      src/lib/i18n/locales/nb-NO/translation.json
  61. 4 0
      src/lib/i18n/locales/nl-NL/translation.json
  62. 4 0
      src/lib/i18n/locales/pa-IN/translation.json
  63. 4 0
      src/lib/i18n/locales/pl-PL/translation.json
  64. 4 0
      src/lib/i18n/locales/pt-BR/translation.json
  65. 4 0
      src/lib/i18n/locales/pt-PT/translation.json
  66. 4 0
      src/lib/i18n/locales/ro-RO/translation.json
  67. 4 0
      src/lib/i18n/locales/ru-RU/translation.json
  68. 4 0
      src/lib/i18n/locales/sr-RS/translation.json
  69. 4 0
      src/lib/i18n/locales/sv-SE/translation.json
  70. 4 0
      src/lib/i18n/locales/th-TH/translation.json
  71. 4 0
      src/lib/i18n/locales/tk-TW/translation.json
  72. 119 115
      src/lib/i18n/locales/tr-TR/translation.json
  73. 4 0
      src/lib/i18n/locales/uk-UA/translation.json
  74. 4 0
      src/lib/i18n/locales/vi-VN/translation.json
  75. 5 1
      src/lib/i18n/locales/zh-CN/translation.json
  76. 5 1
      src/lib/i18n/locales/zh-TW/translation.json
  77. 47 1
      src/lib/utils/index.ts
  78. 28 1
      src/routes/(app)/+layout.svelte
  79. 11 1
      src/routes/+layout.svelte
  80. 1 1
      src/routes/s/[id]/+page.svelte

+ 29 - 0
CHANGELOG.md

@@ -5,6 +5,35 @@ 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/),
 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).
 and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
 
 
+## [0.3.24] - 2024-09-24
+
+### Added
+
+- **🚀 Rendering Optimization**: Significantly improved message rendering performance, enhancing user experience and webui responsiveness.
+- **💖 Favorite Response Feature in Chat Overview**: Users can now mark responses as favorite directly from the chat overview, enhancing ease of retrieval and organization of preferred responses.
+- **💬 Create Message Pairs with Shortcut**: Implemented creation of new message pairs using Cmd/Ctrl+Shift+Enter, making conversation editing faster and more intuitive.
+- **🌍 Expanded User Prompt Variables**: Added weekday, timezone, and language information variables to user prompts to match system prompt variables.
+- **🎵 Enhanced Audio Support**: Now includes support for 'audio/x-m4a' files, broadening compatibility with audio content within the platform.
+- **🔏 Model URL Search Parameter**: Added an ability to select a model directly via URL parameters, streamlining navigation and model access.
+- **📄 Enhanced PDF Citations**: PDF citations now open at the associated page, streamlining reference checks and document handling.
+- **🔧Use of Redis in Sockets**: Enhanced socket implementation to fully support Redis, enabling effective stateless instances suitable for scalable load balancing.
+- **🌍 Stream Individual Model Responses**: Allows specific models to have individualized streaming settings, enhancing performance and customization.
+- **🕒 Display Model Hash and Last Modified Timestamp for Ollama Models**: Provides critical model details directly in the Models workspace for enhanced tracking.
+- **❗ Update Info Notification for Admins**: Ensures administrators receive immediate updates upon login, keeping them informed of the latest changes and system statuses.
+
+### Fixed
+
+- **🗑️ Temporary File Handling On Windows**: Fixed an issue causing errors when accessing a temporary file being used by another process, Tools & Functions should now work as intended.
+- **🔓 Authentication Toggle Issue**: Resolved the malfunction where setting 'WEBUI_AUTH=False' did not appropriately disable authentication, ensuring that user experience and system security settings function as configured.
+- **🔧 Save As Copy Issue for Many Model Chats**: Resolved an error preventing users from save messages as copies in many model chats.
+- **🔒 Sidebar Closure on Mobile**: Resolved an issue where the mobile sidebar remained open after menu engagement, improving user interface responsivity and comfort.
+- **🛡️ Tooltip XSS Vulnerability**: Resolved a cross-site scripting (XSS) issue within tooltips, ensuring enhanced security and data integrity during user interactions.
+
+### Changed
+
+- **↩️ Deprecated Interface Stream Response Settings**: Moved to advanced parameters to streamline interface settings and enhance user clarity.
+- **⚙️ Renamed 'speedRate' to 'playbackRate'**: Standardizes terminology, improving usability and understanding in media settings.
+
 ## [0.3.23] - 2024-09-21
 ## [0.3.23] - 2024-09-21
 
 
 ### Added
 ### Added

+ 1 - 1
backend/open_webui/apps/audio/main.py

@@ -360,7 +360,7 @@ def transcribe(
 ):
 ):
     log.info(f"file.content_type: {file.content_type}")
     log.info(f"file.content_type: {file.content_type}")
 
 
-    if file.content_type not in ["audio/mpeg", "audio/wav", "audio/ogg"]:
+    if file.content_type not in ["audio/mpeg", "audio/wav", "audio/ogg", "audio/x-m4a"]:
         raise HTTPException(
         raise HTTPException(
             status_code=status.HTTP_400_BAD_REQUEST,
             status_code=status.HTTP_400_BAD_REQUEST,
             detail=ERROR_MESSAGES.FILE_NOT_SUPPORTED,
             detail=ERROR_MESSAGES.FILE_NOT_SUPPORTED,

+ 81 - 62
backend/open_webui/apps/socket/main.py

@@ -1,6 +1,9 @@
 import asyncio
 import asyncio
-
 import socketio
 import socketio
+import logging
+import sys
+import time
+
 from open_webui.apps.webui.models.users import Users
 from open_webui.apps.webui.models.users import Users
 from open_webui.env import (
 from open_webui.env import (
     ENABLE_WEBSOCKET_SUPPORT,
     ENABLE_WEBSOCKET_SUPPORT,
@@ -8,6 +11,17 @@ from open_webui.env import (
     WEBSOCKET_REDIS_URL,
     WEBSOCKET_REDIS_URL,
 )
 )
 from open_webui.utils.utils import decode_token
 from open_webui.utils.utils import decode_token
+from open_webui.apps.socket.utils import RedisDict
+
+from open_webui.env import (
+    GLOBAL_LOG_LEVEL,
+    SRC_LOG_LEVELS,
+)
+
+
+logging.basicConfig(stream=sys.stdout, level=GLOBAL_LOG_LEVEL)
+log = logging.getLogger(__name__)
+log.setLevel(SRC_LOG_LEVELS["SOCKET"])
 
 
 
 
 if WEBSOCKET_MANAGER == "redis":
 if WEBSOCKET_MANAGER == "redis":
@@ -38,13 +52,72 @@ app = socketio.ASGIApp(sio, socketio_path="/ws/socket.io")
 
 
 # Dictionary to maintain the user pool
 # Dictionary to maintain the user pool
 
 
-SESSION_POOL = {}
-USER_POOL = {}
-USAGE_POOL = {}
+if WEBSOCKET_MANAGER == "redis":
+    SESSION_POOL = RedisDict("open-webui:session_pool", redis_url=WEBSOCKET_REDIS_URL)
+    USER_POOL = RedisDict("open-webui:user_pool", redis_url=WEBSOCKET_REDIS_URL)
+    USAGE_POOL = RedisDict("open-webui:usage_pool", redis_url=WEBSOCKET_REDIS_URL)
+else:
+    SESSION_POOL = {}
+    USER_POOL = {}
+    USAGE_POOL = {}
+
+
 # Timeout duration in seconds
 # Timeout duration in seconds
 TIMEOUT_DURATION = 3
 TIMEOUT_DURATION = 3
 
 
 
 
+async def periodic_usage_pool_cleanup():
+    while True:
+        now = int(time.time())
+        for model_id, connections in list(USAGE_POOL.items()):
+            # Creating a list of sids to remove if they have timed out
+            expired_sids = [
+                sid
+                for sid, details in connections.items()
+                if now - details["updated_at"] > TIMEOUT_DURATION
+            ]
+
+            for sid in expired_sids:
+                del connections[sid]
+
+            if not connections:
+                log.debug(f"Cleaning up model {model_id} from usage pool")
+                del USAGE_POOL[model_id]
+            else:
+                USAGE_POOL[model_id] = connections
+
+            # Emit updated usage information after cleaning
+            await sio.emit("usage", {"models": get_models_in_use()})
+
+        await asyncio.sleep(TIMEOUT_DURATION)
+
+
+# Start the cleanup task when your app starts
+asyncio.create_task(periodic_usage_pool_cleanup())
+
+
+def get_models_in_use():
+    # List models that are currently in use
+    models_in_use = list(USAGE_POOL.keys())
+    return models_in_use
+
+
+@sio.on("usage")
+async def usage(sid, data):
+    model_id = data["model"]
+    # Record the timestamp for the last update
+    current_time = int(time.time())
+
+    # Store the new usage data and task
+    USAGE_POOL[model_id] = {
+        **(USAGE_POOL[model_id] if model_id in USAGE_POOL else {}),
+        sid: {"updated_at": current_time},
+    }
+
+    # Broadcast the usage data to all clients
+    await sio.emit("usage", {"models": get_models_in_use()})
+
+
 @sio.event
 @sio.event
 async def connect(sid, environ, auth):
 async def connect(sid, environ, auth):
     user = None
     user = None
@@ -62,8 +135,7 @@ async def connect(sid, environ, auth):
                 USER_POOL[user.id] = [sid]
                 USER_POOL[user.id] = [sid]
 
 
             # print(f"user {user.name}({user.id}) connected with session ID {sid}")
             # print(f"user {user.name}({user.id}) connected with session ID {sid}")
-
-            await sio.emit("user-count", {"count": len(set(USER_POOL))})
+            await sio.emit("user-count", {"count": len(USER_POOL.items())})
             await sio.emit("usage", {"models": get_models_in_use()})
             await sio.emit("usage", {"models": get_models_in_use()})
 
 
 
 
@@ -91,65 +163,12 @@ async def user_join(sid, data):
 
 
     # print(f"user {user.name}({user.id}) connected with session ID {sid}")
     # print(f"user {user.name}({user.id}) connected with session ID {sid}")
 
 
-    await sio.emit("user-count", {"count": len(set(USER_POOL))})
+    await sio.emit("user-count", {"count": len(USER_POOL.items())})
 
 
 
 
 @sio.on("user-count")
 @sio.on("user-count")
 async def user_count(sid):
 async def user_count(sid):
-    await sio.emit("user-count", {"count": len(set(USER_POOL))})
-
-
-def get_models_in_use():
-    # Aggregate all models in use
-    models_in_use = []
-    for model_id, data in USAGE_POOL.items():
-        models_in_use.append(model_id)
-
-    return models_in_use
-
-
-@sio.on("usage")
-async def usage(sid, data):
-    model_id = data["model"]
-
-    # Cancel previous callback if there is one
-    if model_id in USAGE_POOL:
-        USAGE_POOL[model_id]["callback"].cancel()
-
-    # Store the new usage data and task
-
-    if model_id in USAGE_POOL:
-        USAGE_POOL[model_id]["sids"].append(sid)
-        USAGE_POOL[model_id]["sids"] = list(set(USAGE_POOL[model_id]["sids"]))
-
-    else:
-        USAGE_POOL[model_id] = {"sids": [sid]}
-
-    # Schedule a task to remove the usage data after TIMEOUT_DURATION
-    USAGE_POOL[model_id]["callback"] = asyncio.create_task(
-        remove_after_timeout(sid, model_id)
-    )
-
-    # Broadcast the usage data to all clients
-    await sio.emit("usage", {"models": get_models_in_use()})
-
-
-async def remove_after_timeout(sid, model_id):
-    try:
-        await asyncio.sleep(TIMEOUT_DURATION)
-        if model_id in USAGE_POOL:
-            # print(USAGE_POOL[model_id]["sids"])
-            USAGE_POOL[model_id]["sids"].remove(sid)
-            USAGE_POOL[model_id]["sids"] = list(set(USAGE_POOL[model_id]["sids"]))
-
-            if len(USAGE_POOL[model_id]["sids"]) == 0:
-                del USAGE_POOL[model_id]
-
-            # Broadcast the usage data to all clients
-            await sio.emit("usage", {"models": get_models_in_use()})
-    except asyncio.CancelledError:
-        # Task was cancelled due to new 'usage' event
-        pass
+    await sio.emit("user-count", {"count": len(USER_POOL.items())})
 
 
 
 
 @sio.event
 @sio.event
@@ -158,7 +177,7 @@ async def disconnect(sid):
         user_id = SESSION_POOL[sid]
         user_id = SESSION_POOL[sid]
         del SESSION_POOL[sid]
         del SESSION_POOL[sid]
 
 
-        USER_POOL[user_id].remove(sid)
+        USER_POOL[user_id] = [_sid for _sid in USER_POOL[user_id] if _sid != sid]
 
 
         if len(USER_POOL[user_id]) == 0:
         if len(USER_POOL[user_id]) == 0:
             del USER_POOL[user_id]
             del USER_POOL[user_id]

+ 59 - 0
backend/open_webui/apps/socket/utils.py

@@ -0,0 +1,59 @@
+import json
+import redis
+
+
+class RedisDict:
+    def __init__(self, name, redis_url):
+        self.name = name
+        self.redis = redis.Redis.from_url(redis_url, decode_responses=True)
+
+    def __setitem__(self, key, value):
+        serialized_value = json.dumps(value)
+        self.redis.hset(self.name, key, serialized_value)
+
+    def __getitem__(self, key):
+        value = self.redis.hget(self.name, key)
+        if value is None:
+            raise KeyError(key)
+        return json.loads(value)
+
+    def __delitem__(self, key):
+        result = self.redis.hdel(self.name, key)
+        if result == 0:
+            raise KeyError(key)
+
+    def __contains__(self, key):
+        return self.redis.hexists(self.name, key)
+
+    def __len__(self):
+        return self.redis.hlen(self.name)
+
+    def keys(self):
+        return self.redis.hkeys(self.name)
+
+    def values(self):
+        return [json.loads(v) for v in self.redis.hvals(self.name)]
+
+    def items(self):
+        return [(k, json.loads(v)) for k, v in self.redis.hgetall(self.name).items()]
+
+    def get(self, key, default=None):
+        try:
+            return self[key]
+        except KeyError:
+            return default
+
+    def clear(self):
+        self.redis.delete(self.name)
+
+    def update(self, other=None, **kwargs):
+        if other is not None:
+            for k, v in other.items() if hasattr(other, "items") else other:
+                self[k] = v
+        for k, v in kwargs.items():
+            self[k] = v
+
+    def setdefault(self, key, default=None):
+        if key not in self:
+            self[key] = default
+        return self[key]

+ 2 - 1
backend/open_webui/apps/webui/utils.py

@@ -87,7 +87,7 @@ def load_toolkit_module_by_id(toolkit_id, content=None):
     # Create a temporary file and use it to define `__file__` so
     # Create a temporary file and use it to define `__file__` so
     # that it works as expected from the module's perspective.
     # that it works as expected from the module's perspective.
     temp_file = tempfile.NamedTemporaryFile(delete=False)
     temp_file = tempfile.NamedTemporaryFile(delete=False)
-
+    temp_file.close()
     try:
     try:
         with open(temp_file.name, "w", encoding="utf-8") as f:
         with open(temp_file.name, "w", encoding="utf-8") as f:
             f.write(content)
             f.write(content)
@@ -131,6 +131,7 @@ def load_function_module_by_id(function_id, content=None):
     # Create a temporary file and use it to define `__file__` so
     # Create a temporary file and use it to define `__file__` so
     # that it works as expected from the module's perspective.
     # that it works as expected from the module's perspective.
     temp_file = tempfile.NamedTemporaryFile(delete=False)
     temp_file = tempfile.NamedTemporaryFile(delete=False)
+    temp_file.close()
     try:
     try:
         with open(temp_file.name, "w", encoding="utf-8") as f:
         with open(temp_file.name, "w", encoding="utf-8") as f:
             f.write(content)
             f.write(content)

+ 1 - 0
backend/open_webui/env.py

@@ -84,6 +84,7 @@ log_sources = [
     "OPENAI",
     "OPENAI",
     "RAG",
     "RAG",
     "WEBHOOK",
     "WEBHOOK",
+    "SOCKET",
 ]
 ]
 
 
 SRC_LOG_LEVELS = {}
 SRC_LOG_LEVELS = {}

+ 2 - 1
backend/open_webui/main.py

@@ -2329,10 +2329,11 @@ async def get_manifest_json():
     return {
     return {
         "name": WEBUI_NAME,
         "name": WEBUI_NAME,
         "short_name": WEBUI_NAME,
         "short_name": WEBUI_NAME,
+        "description": "Open WebUI is an open, extensible, user-friendly interface for AI that adapts to your workflow.",
         "start_url": "/",
         "start_url": "/",
         "display": "standalone",
         "display": "standalone",
         "background_color": "#343541",
         "background_color": "#343541",
-        "orientation": "portrait-primary",
+        "orientation": "any",
         "icons": [
         "icons": [
             {
             {
                 "src": "/static/logo.png",
                 "src": "/static/logo.png",

+ 1 - 1
backend/requirements.txt

@@ -69,7 +69,7 @@ rank-bm25==0.2.2
 faster-whisper==1.0.3
 faster-whisper==1.0.3
 
 
 PyJWT[crypto]==2.9.0
 PyJWT[crypto]==2.9.0
-authlib==1.3.1
+authlib==1.3.2
 
 
 black==24.8.0
 black==24.8.0
 langfuse==2.44.0
 langfuse==2.44.0

+ 73 - 73
package-lock.json

@@ -1,12 +1,12 @@
 {
 {
 	"name": "open-webui",
 	"name": "open-webui",
-	"version": "0.3.23",
+	"version": "0.3.24",
 	"lockfileVersion": 3,
 	"lockfileVersion": 3,
 	"requires": true,
 	"requires": true,
 	"packages": {
 	"packages": {
 		"": {
 		"": {
 			"name": "open-webui",
 			"name": "open-webui",
-			"version": "0.3.23",
+			"version": "0.3.24",
 			"dependencies": {
 			"dependencies": {
 				"@codemirror/lang-javascript": "^6.2.2",
 				"@codemirror/lang-javascript": "^6.2.2",
 				"@codemirror/lang-python": "^6.1.6",
 				"@codemirror/lang-python": "^6.1.6",
@@ -1167,9 +1167,9 @@
 			}
 			}
 		},
 		},
 		"node_modules/@rollup/rollup-android-arm-eabi": {
 		"node_modules/@rollup/rollup-android-arm-eabi": {
-			"version": "4.20.0",
-			"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.20.0.tgz",
-			"integrity": "sha512-TSpWzflCc4VGAUJZlPpgAJE1+V60MePDQnBd7PPkpuEmOy8i87aL6tinFGKBFKuEDikYpig72QzdT3QPYIi+oA==",
+			"version": "4.22.4",
+			"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.22.4.tgz",
+			"integrity": "sha512-Fxamp4aEZnfPOcGA8KSNEohV8hX7zVHOemC8jVBoBUHu5zpJK/Eu3uJwt6BMgy9fkvzxDaurgj96F/NiLukF2w==",
 			"cpu": [
 			"cpu": [
 				"arm"
 				"arm"
 			],
 			],
@@ -1179,9 +1179,9 @@
 			]
 			]
 		},
 		},
 		"node_modules/@rollup/rollup-android-arm64": {
 		"node_modules/@rollup/rollup-android-arm64": {
-			"version": "4.20.0",
-			"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.20.0.tgz",
-			"integrity": "sha512-u00Ro/nok7oGzVuh/FMYfNoGqxU5CPWz1mxV85S2w9LxHR8OoMQBuSk+3BKVIDYgkpeOET5yXkx90OYFc+ytpQ==",
+			"version": "4.22.4",
+			"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.22.4.tgz",
+			"integrity": "sha512-VXoK5UMrgECLYaMuGuVTOx5kcuap1Jm8g/M83RnCHBKOqvPPmROFJGQaZhGccnsFtfXQ3XYa4/jMCJvZnbJBdA==",
 			"cpu": [
 			"cpu": [
 				"arm64"
 				"arm64"
 			],
 			],
@@ -1191,9 +1191,9 @@
 			]
 			]
 		},
 		},
 		"node_modules/@rollup/rollup-darwin-arm64": {
 		"node_modules/@rollup/rollup-darwin-arm64": {
-			"version": "4.20.0",
-			"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.20.0.tgz",
-			"integrity": "sha512-uFVfvzvsdGtlSLuL0ZlvPJvl6ZmrH4CBwLGEFPe7hUmf7htGAN+aXo43R/V6LATyxlKVC/m6UsLb7jbG+LG39Q==",
+			"version": "4.22.4",
+			"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.22.4.tgz",
+			"integrity": "sha512-xMM9ORBqu81jyMKCDP+SZDhnX2QEVQzTcC6G18KlTQEzWK8r/oNZtKuZaCcHhnsa6fEeOBionoyl5JsAbE/36Q==",
 			"cpu": [
 			"cpu": [
 				"arm64"
 				"arm64"
 			],
 			],
@@ -1203,9 +1203,9 @@
 			]
 			]
 		},
 		},
 		"node_modules/@rollup/rollup-darwin-x64": {
 		"node_modules/@rollup/rollup-darwin-x64": {
-			"version": "4.20.0",
-			"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.20.0.tgz",
-			"integrity": "sha512-xbrMDdlev53vNXexEa6l0LffojxhqDTBeL+VUxuuIXys4x6xyvbKq5XqTXBCEUA8ty8iEJblHvFaWRJTk/icAQ==",
+			"version": "4.22.4",
+			"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.22.4.tgz",
+			"integrity": "sha512-aJJyYKQwbHuhTUrjWjxEvGnNNBCnmpHDvrb8JFDbeSH3m2XdHcxDd3jthAzvmoI8w/kSjd2y0udT+4okADsZIw==",
 			"cpu": [
 			"cpu": [
 				"x64"
 				"x64"
 			],
 			],
@@ -1215,9 +1215,9 @@
 			]
 			]
 		},
 		},
 		"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
 		"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
-			"version": "4.20.0",
-			"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.20.0.tgz",
-			"integrity": "sha512-jMYvxZwGmoHFBTbr12Xc6wOdc2xA5tF5F2q6t7Rcfab68TT0n+r7dgawD4qhPEvasDsVpQi+MgDzj2faOLsZjA==",
+			"version": "4.22.4",
+			"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.22.4.tgz",
+			"integrity": "sha512-j63YtCIRAzbO+gC2L9dWXRh5BFetsv0j0va0Wi9epXDgU/XUi5dJKo4USTttVyK7fGw2nPWK0PbAvyliz50SCQ==",
 			"cpu": [
 			"cpu": [
 				"arm"
 				"arm"
 			],
 			],
@@ -1227,9 +1227,9 @@
 			]
 			]
 		},
 		},
 		"node_modules/@rollup/rollup-linux-arm-musleabihf": {
 		"node_modules/@rollup/rollup-linux-arm-musleabihf": {
-			"version": "4.20.0",
-			"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.20.0.tgz",
-			"integrity": "sha512-1asSTl4HKuIHIB1GcdFHNNZhxAYEdqML/MW4QmPS4G0ivbEcBr1JKlFLKsIRqjSwOBkdItn3/ZDlyvZ/N6KPlw==",
+			"version": "4.22.4",
+			"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.22.4.tgz",
+			"integrity": "sha512-dJnWUgwWBX1YBRsuKKMOlXCzh2Wu1mlHzv20TpqEsfdZLb3WoJW2kIEsGwLkroYf24IrPAvOT/ZQ2OYMV6vlrg==",
 			"cpu": [
 			"cpu": [
 				"arm"
 				"arm"
 			],
 			],
@@ -1239,9 +1239,9 @@
 			]
 			]
 		},
 		},
 		"node_modules/@rollup/rollup-linux-arm64-gnu": {
 		"node_modules/@rollup/rollup-linux-arm64-gnu": {
-			"version": "4.20.0",
-			"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.20.0.tgz",
-			"integrity": "sha512-COBb8Bkx56KldOYJfMf6wKeYJrtJ9vEgBRAOkfw6Ens0tnmzPqvlpjZiLgkhg6cA3DGzCmLmmd319pmHvKWWlQ==",
+			"version": "4.22.4",
+			"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.22.4.tgz",
+			"integrity": "sha512-AdPRoNi3NKVLolCN/Sp4F4N1d98c4SBnHMKoLuiG6RXgoZ4sllseuGioszumnPGmPM2O7qaAX/IJdeDU8f26Aw==",
 			"cpu": [
 			"cpu": [
 				"arm64"
 				"arm64"
 			],
 			],
@@ -1251,9 +1251,9 @@
 			]
 			]
 		},
 		},
 		"node_modules/@rollup/rollup-linux-arm64-musl": {
 		"node_modules/@rollup/rollup-linux-arm64-musl": {
-			"version": "4.20.0",
-			"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.20.0.tgz",
-			"integrity": "sha512-+it+mBSyMslVQa8wSPvBx53fYuZK/oLTu5RJoXogjk6x7Q7sz1GNRsXWjn6SwyJm8E/oMjNVwPhmNdIjwP135Q==",
+			"version": "4.22.4",
+			"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.22.4.tgz",
+			"integrity": "sha512-Gl0AxBtDg8uoAn5CCqQDMqAx22Wx22pjDOjBdmG0VIWX3qUBHzYmOKh8KXHL4UpogfJ14G4wk16EQogF+v8hmA==",
 			"cpu": [
 			"cpu": [
 				"arm64"
 				"arm64"
 			],
 			],
@@ -1263,9 +1263,9 @@
 			]
 			]
 		},
 		},
 		"node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
 		"node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
-			"version": "4.20.0",
-			"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.20.0.tgz",
-			"integrity": "sha512-yAMvqhPfGKsAxHN8I4+jE0CpLWD8cv4z7CK7BMmhjDuz606Q2tFKkWRY8bHR9JQXYcoLfopo5TTqzxgPUjUMfw==",
+			"version": "4.22.4",
+			"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.22.4.tgz",
+			"integrity": "sha512-3aVCK9xfWW1oGQpTsYJJPF6bfpWfhbRnhdlyhak2ZiyFLDaayz0EP5j9V1RVLAAxlmWKTDfS9wyRyY3hvhPoOg==",
 			"cpu": [
 			"cpu": [
 				"ppc64"
 				"ppc64"
 			],
 			],
@@ -1275,9 +1275,9 @@
 			]
 			]
 		},
 		},
 		"node_modules/@rollup/rollup-linux-riscv64-gnu": {
 		"node_modules/@rollup/rollup-linux-riscv64-gnu": {
-			"version": "4.20.0",
-			"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.20.0.tgz",
-			"integrity": "sha512-qmuxFpfmi/2SUkAw95TtNq/w/I7Gpjurx609OOOV7U4vhvUhBcftcmXwl3rqAek+ADBwSjIC4IVNLiszoj3dPA==",
+			"version": "4.22.4",
+			"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.22.4.tgz",
+			"integrity": "sha512-ePYIir6VYnhgv2C5Xe9u+ico4t8sZWXschR6fMgoPUK31yQu7hTEJb7bCqivHECwIClJfKgE7zYsh1qTP3WHUA==",
 			"cpu": [
 			"cpu": [
 				"riscv64"
 				"riscv64"
 			],
 			],
@@ -1287,9 +1287,9 @@
 			]
 			]
 		},
 		},
 		"node_modules/@rollup/rollup-linux-s390x-gnu": {
 		"node_modules/@rollup/rollup-linux-s390x-gnu": {
-			"version": "4.20.0",
-			"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.20.0.tgz",
-			"integrity": "sha512-I0BtGXddHSHjV1mqTNkgUZLnS3WtsqebAXv11D5BZE/gfw5KoyXSAXVqyJximQXNvNzUo4GKlCK/dIwXlz+jlg==",
+			"version": "4.22.4",
+			"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.22.4.tgz",
+			"integrity": "sha512-GqFJ9wLlbB9daxhVlrTe61vJtEY99/xB3C8e4ULVsVfflcpmR6c8UZXjtkMA6FhNONhj2eA5Tk9uAVw5orEs4Q==",
 			"cpu": [
 			"cpu": [
 				"s390x"
 				"s390x"
 			],
 			],
@@ -1299,9 +1299,9 @@
 			]
 			]
 		},
 		},
 		"node_modules/@rollup/rollup-linux-x64-gnu": {
 		"node_modules/@rollup/rollup-linux-x64-gnu": {
-			"version": "4.20.0",
-			"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.20.0.tgz",
-			"integrity": "sha512-y+eoL2I3iphUg9tN9GB6ku1FA8kOfmF4oUEWhztDJ4KXJy1agk/9+pejOuZkNFhRwHAOxMsBPLbXPd6mJiCwew==",
+			"version": "4.22.4",
+			"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.22.4.tgz",
+			"integrity": "sha512-87v0ol2sH9GE3cLQLNEy0K/R0pz1nvg76o8M5nhMR0+Q+BBGLnb35P0fVz4CQxHYXaAOhE8HhlkaZfsdUOlHwg==",
 			"cpu": [
 			"cpu": [
 				"x64"
 				"x64"
 			],
 			],
@@ -1311,9 +1311,9 @@
 			]
 			]
 		},
 		},
 		"node_modules/@rollup/rollup-linux-x64-musl": {
 		"node_modules/@rollup/rollup-linux-x64-musl": {
-			"version": "4.20.0",
-			"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.20.0.tgz",
-			"integrity": "sha512-hM3nhW40kBNYUkZb/r9k2FKK+/MnKglX7UYd4ZUy5DJs8/sMsIbqWK2piZtVGE3kcXVNj3B2IrUYROJMMCikNg==",
+			"version": "4.22.4",
+			"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.22.4.tgz",
+			"integrity": "sha512-UV6FZMUgePDZrFjrNGIWzDo/vABebuXBhJEqrHxrGiU6HikPy0Z3LfdtciIttEUQfuDdCn8fqh7wiFJjCNwO+g==",
 			"cpu": [
 			"cpu": [
 				"x64"
 				"x64"
 			],
 			],
@@ -1323,9 +1323,9 @@
 			]
 			]
 		},
 		},
 		"node_modules/@rollup/rollup-win32-arm64-msvc": {
 		"node_modules/@rollup/rollup-win32-arm64-msvc": {
-			"version": "4.20.0",
-			"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.20.0.tgz",
-			"integrity": "sha512-psegMvP+Ik/Bg7QRJbv8w8PAytPA7Uo8fpFjXyCRHWm6Nt42L+JtoqH8eDQ5hRP7/XW2UiIriy1Z46jf0Oa1kA==",
+			"version": "4.22.4",
+			"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.22.4.tgz",
+			"integrity": "sha512-BjI+NVVEGAXjGWYHz/vv0pBqfGoUH0IGZ0cICTn7kB9PyjrATSkX+8WkguNjWoj2qSr1im/+tTGRaY+4/PdcQw==",
 			"cpu": [
 			"cpu": [
 				"arm64"
 				"arm64"
 			],
 			],
@@ -1335,9 +1335,9 @@
 			]
 			]
 		},
 		},
 		"node_modules/@rollup/rollup-win32-ia32-msvc": {
 		"node_modules/@rollup/rollup-win32-ia32-msvc": {
-			"version": "4.20.0",
-			"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.20.0.tgz",
-			"integrity": "sha512-GabekH3w4lgAJpVxkk7hUzUf2hICSQO0a/BLFA11/RMxQT92MabKAqyubzDZmMOC/hcJNlc+rrypzNzYl4Dx7A==",
+			"version": "4.22.4",
+			"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.22.4.tgz",
+			"integrity": "sha512-SiWG/1TuUdPvYmzmYnmd3IEifzR61Tragkbx9D3+R8mzQqDBz8v+BvZNDlkiTtI9T15KYZhP0ehn3Dld4n9J5g==",
 			"cpu": [
 			"cpu": [
 				"ia32"
 				"ia32"
 			],
 			],
@@ -1347,9 +1347,9 @@
 			]
 			]
 		},
 		},
 		"node_modules/@rollup/rollup-win32-x64-msvc": {
 		"node_modules/@rollup/rollup-win32-x64-msvc": {
-			"version": "4.20.0",
-			"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.20.0.tgz",
-			"integrity": "sha512-aJ1EJSuTdGnM6qbVC4B5DSmozPTqIag9fSzXRNNo+humQLG89XpPgdt16Ia56ORD7s+H8Pmyx44uczDQ0yDzpg==",
+			"version": "4.22.4",
+			"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.22.4.tgz",
+			"integrity": "sha512-j8pPKp53/lq9lMXN57S8cFz0MynJk8OWNuUnXct/9KCpKU7DgU3bYMJhwWmcqC0UU29p8Lr0/7KEVcaM6bf47Q==",
 			"cpu": [
 			"cpu": [
 				"x64"
 				"x64"
 			],
 			],
@@ -7906,9 +7906,9 @@
 			"integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg=="
 			"integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg=="
 		},
 		},
 		"node_modules/rollup": {
 		"node_modules/rollup": {
-			"version": "4.20.0",
-			"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.20.0.tgz",
-			"integrity": "sha512-6rbWBChcnSGzIlXeIdNIZTopKYad8ZG8ajhl78lGRLsI2rX8IkaotQhVas2Ma+GPxJav19wrSzvRvuiv0YKzWw==",
+			"version": "4.22.4",
+			"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.22.4.tgz",
+			"integrity": "sha512-vD8HJ5raRcWOyymsR6Z3o6+RzfEPCnVLMFJ6vRslO1jt4LO6dUo5Qnpg7y4RkZFM2DMe3WUirkI5c16onjrc6A==",
 			"dependencies": {
 			"dependencies": {
 				"@types/estree": "1.0.5"
 				"@types/estree": "1.0.5"
 			},
 			},
@@ -7920,22 +7920,22 @@
 				"npm": ">=8.0.0"
 				"npm": ">=8.0.0"
 			},
 			},
 			"optionalDependencies": {
 			"optionalDependencies": {
-				"@rollup/rollup-android-arm-eabi": "4.20.0",
-				"@rollup/rollup-android-arm64": "4.20.0",
-				"@rollup/rollup-darwin-arm64": "4.20.0",
-				"@rollup/rollup-darwin-x64": "4.20.0",
-				"@rollup/rollup-linux-arm-gnueabihf": "4.20.0",
-				"@rollup/rollup-linux-arm-musleabihf": "4.20.0",
-				"@rollup/rollup-linux-arm64-gnu": "4.20.0",
-				"@rollup/rollup-linux-arm64-musl": "4.20.0",
-				"@rollup/rollup-linux-powerpc64le-gnu": "4.20.0",
-				"@rollup/rollup-linux-riscv64-gnu": "4.20.0",
-				"@rollup/rollup-linux-s390x-gnu": "4.20.0",
-				"@rollup/rollup-linux-x64-gnu": "4.20.0",
-				"@rollup/rollup-linux-x64-musl": "4.20.0",
-				"@rollup/rollup-win32-arm64-msvc": "4.20.0",
-				"@rollup/rollup-win32-ia32-msvc": "4.20.0",
-				"@rollup/rollup-win32-x64-msvc": "4.20.0",
+				"@rollup/rollup-android-arm-eabi": "4.22.4",
+				"@rollup/rollup-android-arm64": "4.22.4",
+				"@rollup/rollup-darwin-arm64": "4.22.4",
+				"@rollup/rollup-darwin-x64": "4.22.4",
+				"@rollup/rollup-linux-arm-gnueabihf": "4.22.4",
+				"@rollup/rollup-linux-arm-musleabihf": "4.22.4",
+				"@rollup/rollup-linux-arm64-gnu": "4.22.4",
+				"@rollup/rollup-linux-arm64-musl": "4.22.4",
+				"@rollup/rollup-linux-powerpc64le-gnu": "4.22.4",
+				"@rollup/rollup-linux-riscv64-gnu": "4.22.4",
+				"@rollup/rollup-linux-s390x-gnu": "4.22.4",
+				"@rollup/rollup-linux-x64-gnu": "4.22.4",
+				"@rollup/rollup-linux-x64-musl": "4.22.4",
+				"@rollup/rollup-win32-arm64-msvc": "4.22.4",
+				"@rollup/rollup-win32-ia32-msvc": "4.22.4",
+				"@rollup/rollup-win32-x64-msvc": "4.22.4",
 				"fsevents": "~2.3.2"
 				"fsevents": "~2.3.2"
 			}
 			}
 		},
 		},
@@ -8724,11 +8724,11 @@
 			}
 			}
 		},
 		},
 		"node_modules/svelte-sonner": {
 		"node_modules/svelte-sonner": {
-			"version": "0.3.19",
-			"resolved": "https://registry.npmjs.org/svelte-sonner/-/svelte-sonner-0.3.19.tgz",
-			"integrity": "sha512-jpPOgLtHwRaB6Vqo2dUQMv15/yUV/BQWTjKpEqQ11uqRSHKjAYUKZyGrHB2cQsGmyjR0JUzBD58btpgNqINQ/Q==",
+			"version": "0.3.28",
+			"resolved": "https://registry.npmjs.org/svelte-sonner/-/svelte-sonner-0.3.28.tgz",
+			"integrity": "sha512-K3AmlySeFifF/cKgsYNv5uXqMVNln0NBAacOYgmkQStLa/UoU0LhfAACU6Gr+YYC8bOCHdVmFNoKuDbMEsppJg==",
 			"peerDependencies": {
 			"peerDependencies": {
-				"svelte": ">=3 <5"
+				"svelte": "^3.0.0 || ^4.0.0 || ^5.0.0-next.1"
 			}
 			}
 		},
 		},
 		"node_modules/svelte/node_modules/estree-walker": {
 		"node_modules/svelte/node_modules/estree-walker": {

+ 1 - 1
package.json

@@ -1,6 +1,6 @@
 {
 {
 	"name": "open-webui",
 	"name": "open-webui",
-	"version": "0.3.23",
+	"version": "0.3.24",
 	"private": true,
 	"private": true,
 	"scripts": {
 	"scripts": {
 		"dev": "npm run pyodide:fetch && vite dev --host",
 		"dev": "npm run pyodide:fetch && vite dev --host",

+ 1 - 1
pyproject.toml

@@ -76,7 +76,7 @@ dependencies = [
     "faster-whisper==1.0.3",
     "faster-whisper==1.0.3",
 
 
     "PyJWT[crypto]==2.9.0",
     "PyJWT[crypto]==2.9.0",
-    "authlib==1.3.1",
+    "authlib==1.3.2",
 
 
     "black==24.8.0",
     "black==24.8.0",
     "langfuse==2.44.0",
     "langfuse==2.44.0",

+ 220 - 156
src/lib/components/chat/Chat.svelte

@@ -5,6 +5,8 @@
 	import { PaneGroup, Pane, PaneResizer } from 'paneforge';
 	import { PaneGroup, Pane, PaneResizer } from 'paneforge';
 
 
 	import { getContext, onDestroy, onMount, tick } from 'svelte';
 	import { getContext, onDestroy, onMount, tick } from 'svelte';
+	const i18n: Writable<i18nType> = getContext('i18n');
+
 	import { goto } from '$app/navigation';
 	import { goto } from '$app/navigation';
 	import { page } from '$app/stores';
 	import { page } from '$app/stores';
 
 
@@ -67,11 +69,9 @@
 	import Navbar from '$lib/components/layout/Navbar.svelte';
 	import Navbar from '$lib/components/layout/Navbar.svelte';
 	import ChatControls from './ChatControls.svelte';
 	import ChatControls from './ChatControls.svelte';
 	import EventConfirmDialog from '../common/ConfirmDialog.svelte';
 	import EventConfirmDialog from '../common/ConfirmDialog.svelte';
-	import EllipsisVertical from '../icons/EllipsisVertical.svelte';
-
-	const i18n: Writable<i18nType> = getContext('i18n');
 
 
 	export let chatIdProp = '';
 	export let chatIdProp = '';
+
 	let loaded = false;
 	let loaded = false;
 	const eventTarget = new EventTarget();
 	const eventTarget = new EventTarget();
 	let controlPane;
 	let controlPane;
@@ -89,11 +89,10 @@
 	let eventConfirmationInputValue = '';
 	let eventConfirmationInputValue = '';
 	let eventCallback = null;
 	let eventCallback = null;
 
 
-	let showModelSelector = true;
+	let chatIdUnsubscriber: Unsubscriber | undefined;
 
 
 	let selectedModels = [''];
 	let selectedModels = [''];
 	let atSelectedModel: Model | undefined;
 	let atSelectedModel: Model | undefined;
-
 	let selectedModelIds = [];
 	let selectedModelIds = [];
 	$: selectedModelIds = atSelectedModel !== undefined ? [atSelectedModel.id] : selectedModels;
 	$: selectedModelIds = atSelectedModel !== undefined ? [atSelectedModel.id] : selectedModels;
 
 
@@ -104,35 +103,17 @@
 	let tags = [];
 	let tags = [];
 
 
 	let title = '';
 	let title = '';
-	let prompt = '';
-
-	let chatFiles = [];
-	let files = [];
-	let messages = [];
 	let history = {
 	let history = {
 		messages: {},
 		messages: {},
 		currentId: null
 		currentId: null
 	};
 	};
 
 
+	// Chat Input
+	let prompt = '';
+	let chatFiles = [];
+	let files = [];
 	let params = {};
 	let params = {};
 
 
-	let chatIdUnsubscriber: Unsubscriber | undefined;
-
-	$: if (history.currentId !== null) {
-		let _messages = [];
-		let currentMessage = history.messages[history.currentId];
-		while (currentMessage) {
-			_messages.unshift({ ...currentMessage });
-			currentMessage =
-				currentMessage.parentId !== null ? history.messages[currentMessage.parentId] : null;
-		}
-
-		// This is most likely causing the performance issue
-		messages = _messages;
-	} else {
-		messages = [];
-	}
-
 	$: if (chatIdProp) {
 	$: if (chatIdProp) {
 		(async () => {
 		(async () => {
 			console.log(chatIdProp);
 			console.log(chatIdProp);
@@ -150,6 +131,7 @@
 	}
 	}
 
 
 	const showMessage = async (message) => {
 	const showMessage = async (message) => {
+		const _chatId = JSON.parse(JSON.stringify($chatId));
 		let _messageId = JSON.parse(JSON.stringify(message.id));
 		let _messageId = JSON.parse(JSON.stringify(message.id));
 
 
 		let messageChildrenIds = history.messages[_messageId].childrenIds;
 		let messageChildrenIds = history.messages[_messageId].childrenIds;
@@ -169,6 +151,9 @@
 		if (messageElement) {
 		if (messageElement) {
 			messageElement.scrollIntoView({ behavior: 'smooth' });
 			messageElement.scrollIntoView({ behavior: 'smooth' });
 		}
 		}
+
+		await tick();
+		saveChatHandler(_chatId);
 	};
 	};
 
 
 	const chatEventHandler = async (event, cb) => {
 	const chatEventHandler = async (event, cb) => {
@@ -226,7 +211,7 @@
 				console.log('Unknown message type', data);
 				console.log('Unknown message type', data);
 			}
 			}
 
 
-			messages = messages;
+			history.messages[event.message_id] = message;
 		}
 		}
 	};
 	};
 
 
@@ -308,6 +293,9 @@
 				showOverview.set(false);
 				showOverview.set(false);
 			}
 			}
 		});
 		});
+
+		const chatInput = document.getElementById('chat-textarea');
+		chatInput?.focus();
 	});
 	});
 
 
 	onDestroy(() => {
 	onDestroy(() => {
@@ -329,7 +317,6 @@
 		autoScroll = true;
 		autoScroll = true;
 
 
 		title = '';
 		title = '';
-		messages = [];
 		history = {
 		history = {
 			messages: {},
 			messages: {},
 			currentId: null
 			currentId: null
@@ -340,6 +327,8 @@
 
 
 		if ($page.url.searchParams.get('models')) {
 		if ($page.url.searchParams.get('models')) {
 			selectedModels = $page.url.searchParams.get('models')?.split(',');
 			selectedModels = $page.url.searchParams.get('models')?.split(',');
+		} else if ($page.url.searchParams.get('model')) {
+			selectedModels = $page.url.searchParams.get('model')?.split(',');
 		} else if ($settings?.models) {
 		} else if ($settings?.models) {
 			selectedModels = $settings?.models;
 			selectedModels = $settings?.models;
 		} else if ($config?.default_models) {
 		} else if ($config?.default_models) {
@@ -424,8 +413,8 @@
 				autoScroll = true;
 				autoScroll = true;
 				await tick();
 				await tick();
 
 
-				if (messages.length > 0) {
-					history.messages[messages.at(-1).id].done = true;
+				if (history.currentId) {
+					history.messages[history.currentId].done = true;
 				}
 				}
 				await tick();
 				await tick();
 
 
@@ -444,8 +433,12 @@
 	};
 	};
 
 
 	const createMessagesList = (responseMessageId) => {
 	const createMessagesList = (responseMessageId) => {
+		if (responseMessageId === null) {
+			return [];
+		}
+
 		const message = history.messages[responseMessageId];
 		const message = history.messages[responseMessageId];
-		if (message.parentId) {
+		if (message?.parentId) {
 			return [...createMessagesList(message.parentId), message];
 			return [...createMessagesList(message.parentId), message];
 		} else {
 		} else {
 			return [message];
 			return [message];
@@ -506,6 +499,8 @@
 	};
 	};
 
 
 	const chatActionHandler = async (chatId, actionId, modelId, responseMessageId, event = null) => {
 	const chatActionHandler = async (chatId, actionId, modelId, responseMessageId, event = null) => {
+		const messages = createMessagesList(responseMessageId);
+
 		const res = await chatAction(localStorage.token, actionId, {
 		const res = await chatAction(localStorage.token, actionId, {
 			model: modelId,
 			model: modelId,
 			messages: messages.map((m) => ({
 			messages: messages.map((m) => ({
@@ -564,6 +559,66 @@
 		}, 1000);
 		}, 1000);
 	};
 	};
 
 
+	const createMessagePair = async (userPrompt) => {
+		prompt = '';
+		if (selectedModels.length === 0) {
+			toast.error($i18n.t('Model not selected'));
+		} else {
+			const modelId = selectedModels[0];
+			const model = $models.filter((m) => m.id === modelId).at(0);
+
+			const messages = createMessagesList(history.currentId);
+			const parentMessage = messages.length !== 0 ? messages.at(-1) : null;
+
+			const userMessageId = uuidv4();
+			const responseMessageId = uuidv4();
+
+			const userMessage = {
+				id: userMessageId,
+				parentId: parentMessage ? parentMessage.id : null,
+				childrenIds: [responseMessageId],
+				role: 'user',
+				content: userPrompt ? userPrompt : `[PROMPT] ${userMessageId}`,
+				timestamp: Math.floor(Date.now() / 1000)
+			};
+
+			const responseMessage = {
+				id: responseMessageId,
+				parentId: userMessageId,
+				childrenIds: [],
+				role: 'assistant',
+				content: `[RESPONSE] ${responseMessageId}`,
+				done: true,
+
+				model: modelId,
+				modelName: model.name ?? model.id,
+				modelIdx: 0,
+				timestamp: Math.floor(Date.now() / 1000)
+			};
+
+			if (parentMessage) {
+				parentMessage.childrenIds.push(userMessageId);
+				history.messages[parentMessage.id] = parentMessage;
+			}
+			history.messages[userMessageId] = userMessage;
+			history.messages[responseMessageId] = responseMessage;
+
+			history.currentId = responseMessageId;
+
+			await tick();
+
+			if (autoScroll) {
+				scrollToBottom();
+			}
+
+			if (messages.length === 0) {
+				await initChatHandler();
+			} else {
+				await saveChatHandler($chatId);
+			}
+		}
+	};
+
 	//////////////////////////
 	//////////////////////////
 	// Chat functions
 	// Chat functions
 	//////////////////////////
 	//////////////////////////
@@ -571,6 +626,7 @@
 	const submitPrompt = async (userPrompt, { _raw = false } = {}) => {
 	const submitPrompt = async (userPrompt, { _raw = false } = {}) => {
 		let _responses = [];
 		let _responses = [];
 		console.log('submitPrompt', $chatId);
 		console.log('submitPrompt', $chatId);
+		const messages = createMessagesList(history.currentId);
 
 
 		selectedModels = selectedModels.map((modelId) =>
 		selectedModels = selectedModels.map((modelId) =>
 			$models.map((m) => m.id).includes(modelId) ? modelId : ''
 			$models.map((m) => m.id).includes(modelId) ? modelId : ''
@@ -664,8 +720,16 @@
 		parentId: string,
 		parentId: string,
 		{ modelId = null, modelIdx = null, newChat = false } = {}
 		{ modelId = null, modelIdx = null, newChat = false } = {}
 	) => {
 	) => {
-		let _responses: string[] = [];
+		// Create new chat if newChat is true and first user message
+		if (
+			newChat &&
+			history.messages[history.currentId].parentId === null &&
+			history.messages[history.currentId].role === 'user'
+		) {
+			await initChatHandler();
+		}
 
 
+		let _responses: string[] = [];
 		// If modelId is provided, use it, else use selected model
 		// If modelId is provided, use it, else use selected model
 		let selectedModelIds = modelId
 		let selectedModelIds = modelId
 			? [modelId]
 			? [modelId]
@@ -710,38 +774,14 @@
 		}
 		}
 		await tick();
 		await tick();
 
 
-		// Create new chat if only one message in messages
-		if (newChat && messages.length == 2) {
-			if (!$temporaryChatEnabled) {
-				chat = await createNewChat(localStorage.token, {
-					id: $chatId,
-					title: $i18n.t('New Chat'),
-					models: selectedModels,
-					system: $settings.system ?? undefined,
-					params: params,
-					messages: messages,
-					history: history,
-					tags: [],
-					timestamp: Date.now()
-				});
-
-				currentChatPage.set(1);
-				await chats.set(await getChatList(localStorage.token, $currentChatPage));
-				await chatId.set(chat.id);
-			} else {
-				await chatId.set('local');
-			}
-			await tick();
-		}
-
 		const _chatId = JSON.parse(JSON.stringify($chatId));
 		const _chatId = JSON.parse(JSON.stringify($chatId));
-
 		await Promise.all(
 		await Promise.all(
 			selectedModelIds.map(async (modelId, _modelIdx) => {
 			selectedModelIds.map(async (modelId, _modelIdx) => {
 				console.log('modelId', modelId);
 				console.log('modelId', modelId);
 				const model = $models.filter((m) => m.id === modelId).at(0);
 				const model = $models.filter((m) => m.id === modelId).at(0);
 
 
 				if (model) {
 				if (model) {
+					const messages = createMessagesList(parentId);
 					// If there are image files, check if model is vision capable
 					// If there are image files, check if model is vision capable
 					const hasImages = messages.some((message) =>
 					const hasImages = messages.some((message) =>
 						message.files?.some((file) => file.type === 'image')
 						message.files?.some((file) => file.type === 'image')
@@ -840,7 +880,7 @@
 						}`
 						}`
 					}
 					}
 				: undefined,
 				: undefined,
-			...messages
+			...createMessagesList(responseMessageId)
 		]
 		]
 			.filter((message) => message?.content?.trim())
 			.filter((message) => message?.content?.trim())
 			.map((message) => {
 			.map((message) => {
@@ -891,7 +931,7 @@
 				}
 				}
 			];
 			];
 			files.push(...model.info.meta.knowledge);
 			files.push(...model.info.meta.knowledge);
-			messages = messages; // Trigger Svelte update
+			history.messages[responseMessageId] = responseMessage;
 		}
 		}
 		files.push(
 		files.push(
 			...(userMessage?.files ?? []).filter((item) =>
 			...(userMessage?.files ?? []).filter((item) =>
@@ -912,7 +952,11 @@
 
 
 		await tick();
 		await tick();
 
 
-		const stream = $settings?.streamResponse ?? true;
+		const stream =
+			model?.info?.params?.stream_response ??
+			$settings?.params?.stream_response ??
+			params?.stream_response ??
+			true;
 		const [res, controller] = await generateChatCompletion(localStorage.token, {
 		const [res, controller] = await generateChatCompletion(localStorage.token, {
 			stream: stream,
 			stream: stream,
 			model: model.id,
 			model: model.id,
@@ -965,7 +1009,7 @@
 					const { value, done } = await reader.read();
 					const { value, done } = await reader.read();
 					if (done || stopResponseFlag || _chatId !== $chatId) {
 					if (done || stopResponseFlag || _chatId !== $chatId) {
 						responseMessage.done = true;
 						responseMessage.done = true;
-						messages = messages;
+						history.messages[responseMessageId] = responseMessage;
 
 
 						if (stopResponseFlag) {
 						if (stopResponseFlag) {
 							controller.abort('User: Stop Response');
 							controller.abort('User: Stop Response');
@@ -1032,7 +1076,7 @@
 											);
 											);
 										}
 										}
 
 
-										messages = messages;
+										history.messages[responseMessageId] = responseMessage;
 									}
 									}
 								} else {
 								} else {
 									responseMessage.done = true;
 									responseMessage.done = true;
@@ -1055,7 +1099,8 @@
 										eval_count: data.eval_count,
 										eval_count: data.eval_count,
 										eval_duration: data.eval_duration
 										eval_duration: data.eval_duration
 									};
 									};
-									messages = messages;
+
+									history.messages[responseMessageId] = responseMessage;
 
 
 									if ($settings.notificationEnabled && !document.hasFocus()) {
 									if ($settings.notificationEnabled && !document.hasFocus()) {
 										const notification = new Notification(`${model.id}`, {
 										const notification = new Notification(`${model.id}`, {
@@ -1124,7 +1169,7 @@
 				);
 				);
 			}
 			}
 
 
-			messages = messages;
+			history.messages[responseMessageId] = responseMessage;
 		}
 		}
 		await saveChatHandler(_chatId);
 		await saveChatHandler(_chatId);
 
 
@@ -1157,7 +1202,8 @@
 			scrollToBottom();
 			scrollToBottom();
 		}
 		}
 
 
-		if (messages.length == 2 && messages.at(1).content !== '' && selectedModels[0] === model.id) {
+		const messages = createMessagesList(responseMessageId);
+		if (messages.length == 2 && messages.at(-1).content !== '' && selectedModels[0] === model.id) {
 			window.history.replaceState(history.state, '', `/c/${_chatId}`);
 			window.history.replaceState(history.state, '', `/c/${_chatId}`);
 			const _title = await generateChatTitle(userPrompt);
 			const _title = await generateChatTitle(userPrompt);
 			await setChatTitle(_chatId, _title);
 			await setChatTitle(_chatId, _title);
@@ -1185,7 +1231,7 @@
 				}
 				}
 			];
 			];
 			files.push(...model.info.meta.knowledge);
 			files.push(...model.info.meta.knowledge);
-			messages = messages; // Trigger Svelte update
+			history.messages[responseMessageId] = responseMessage;
 		}
 		}
 		files.push(
 		files.push(
 			...(userMessage?.files ?? []).filter((item) =>
 			...(userMessage?.files ?? []).filter((item) =>
@@ -1206,7 +1252,12 @@
 		await tick();
 		await tick();
 
 
 		try {
 		try {
-			const stream = $settings?.streamResponse ?? true;
+			const stream =
+				model?.info?.params?.stream_response ??
+				$settings?.params?.stream_response ??
+				params?.stream_response ??
+				true;
+
 			const [res, controller] = await generateOpenAIChatCompletion(
 			const [res, controller] = await generateOpenAIChatCompletion(
 				localStorage.token,
 				localStorage.token,
 				{
 				{
@@ -1236,7 +1287,7 @@
 									}`
 									}`
 								}
 								}
 							: undefined,
 							: undefined,
-						...messages
+						...createMessagesList(responseMessageId)
 					]
 					]
 						.filter((message) => message?.content?.trim())
 						.filter((message) => message?.content?.trim())
 						.map((message, idx, arr) => ({
 						.map((message, idx, arr) => ({
@@ -1314,7 +1365,7 @@
 						}
 						}
 						if (done || stopResponseFlag || _chatId !== $chatId) {
 						if (done || stopResponseFlag || _chatId !== $chatId) {
 							responseMessage.done = true;
 							responseMessage.done = true;
-							messages = messages;
+							history.messages[responseMessageId] = responseMessage;
 
 
 							if (stopResponseFlag) {
 							if (stopResponseFlag) {
 								controller.abort('User: Stop Response');
 								controller.abort('User: Stop Response');
@@ -1369,7 +1420,7 @@
 								);
 								);
 							}
 							}
 
 
-							messages = messages;
+							history.messages[responseMessageId] = responseMessage;
 						}
 						}
 
 
 						if (autoScroll) {
 						if (autoScroll) {
@@ -1410,7 +1461,7 @@
 
 
 		await saveChatHandler(_chatId);
 		await saveChatHandler(_chatId);
 
 
-		messages = messages;
+		history.messages[responseMessageId] = responseMessage;
 
 
 		stopResponseFlag = false;
 		stopResponseFlag = false;
 		await tick();
 		await tick();
@@ -1441,9 +1492,9 @@
 			scrollToBottom();
 			scrollToBottom();
 		}
 		}
 
 
+		const messages = createMessagesList(responseMessageId);
 		if (messages.length == 2 && selectedModels[0] === model.id) {
 		if (messages.length == 2 && selectedModels[0] === model.id) {
 			window.history.replaceState(history.state, '', `/c/${_chatId}`);
 			window.history.replaceState(history.state, '', `/c/${_chatId}`);
-
 			const _title = await generateChatTitle(userPrompt);
 			const _title = await generateChatTitle(userPrompt);
 			await setChatTitle(_chatId, _title);
 			await setChatTitle(_chatId, _title);
 		}
 		}
@@ -1493,7 +1544,7 @@
 			);
 			);
 		}
 		}
 
 
-		messages = messages;
+		history.messages[responseMessage.id] = responseMessage;
 	};
 	};
 
 
 	const stopResponse = () => {
 	const stopResponse = () => {
@@ -1504,7 +1555,7 @@
 	const regenerateResponse = async (message) => {
 	const regenerateResponse = async (message) => {
 		console.log('regenerateResponse');
 		console.log('regenerateResponse');
 
 
-		if (messages.length != 0) {
+		if (history.currentId) {
 			let userMessage = history.messages[message.parentId];
 			let userMessage = history.messages[message.parentId];
 			let userPrompt = userMessage.content;
 			let userPrompt = userMessage.content;
 
 
@@ -1522,11 +1573,11 @@
 		}
 		}
 	};
 	};
 
 
-	const continueGeneration = async () => {
-		console.log('continueGeneration');
+	const continueResponse = async () => {
+		console.log('continueResponse');
 		const _chatId = JSON.parse(JSON.stringify($chatId));
 		const _chatId = JSON.parse(JSON.stringify($chatId));
 
 
-		if (messages.length != 0 && messages.at(-1).done == true) {
+		if (history.currentId && history.messages[history.currentId].done == true) {
 			const responseMessage = history.messages[history.currentId];
 			const responseMessage = history.messages[history.currentId];
 			responseMessage.done = false;
 			responseMessage.done = false;
 			await tick();
 			await tick();
@@ -1554,6 +1605,53 @@
 		}
 		}
 	};
 	};
 
 
+	const mergeResponses = async (messageId, responses, _chatId) => {
+		console.log('mergeResponses', messageId, responses);
+		const message = history.messages[messageId];
+		const mergedResponse = {
+			status: true,
+			content: ''
+		};
+		message.merged = mergedResponse;
+		history.messages[messageId] = message;
+
+		try {
+			const [res, controller] = await generateMoACompletion(
+				localStorage.token,
+				message.model,
+				history.messages[message.parentId].content,
+				responses
+			);
+
+			if (res && res.ok && res.body) {
+				const textStream = await createOpenAITextStream(res.body, $settings.splitLargeChunks);
+				for await (const update of textStream) {
+					const { value, done, citations, error, usage } = update;
+					if (error || done) {
+						break;
+					}
+
+					if (mergedResponse.content == '' && value == '\n') {
+						continue;
+					} else {
+						mergedResponse.content += value;
+						history.messages[messageId] = message;
+					}
+
+					if (autoScroll) {
+						scrollToBottom();
+					}
+				}
+
+				await saveChatHandler(_chatId);
+			} else {
+				console.error(res);
+			}
+		} catch (e) {
+			console.error(e);
+		}
+	};
+
 	const generateChatTitle = async (userPrompt) => {
 	const generateChatTitle = async (userPrompt) => {
 		if ($settings?.title?.auto ?? true) {
 		if ($settings?.title?.auto ?? true) {
 			const title = await generateTitle(
 			const title = await generateTitle(
@@ -1596,7 +1694,7 @@
 				description: $i18n.t('Generating search query')
 				description: $i18n.t('Generating search query')
 			}
 			}
 		];
 		];
-		messages = messages;
+		history.messages[responseMessageId] = responseMessage;
 
 
 		const prompt = userMessage.content;
 		const prompt = userMessage.content;
 		let searchQuery = await generateSearchQuery(
 		let searchQuery = await generateSearchQuery(
@@ -1616,7 +1714,7 @@
 				action: 'web_search',
 				action: 'web_search',
 				description: $i18n.t('No search query generated')
 				description: $i18n.t('No search query generated')
 			});
 			});
-			messages = messages;
+			history.messages[responseMessageId] = responseMessage;
 			return;
 			return;
 		}
 		}
 
 
@@ -1625,7 +1723,7 @@
 			action: 'web_search',
 			action: 'web_search',
 			description: $i18n.t(`Searching "{{searchQuery}}"`, { searchQuery })
 			description: $i18n.t(`Searching "{{searchQuery}}"`, { searchQuery })
 		});
 		});
-		messages = messages;
+		history.messages[responseMessageId] = responseMessage;
 
 
 		const results = await runWebSearch(localStorage.token, searchQuery).catch((error) => {
 		const results = await runWebSearch(localStorage.token, searchQuery).catch((error) => {
 			console.log(error);
 			console.log(error);
@@ -1653,8 +1751,7 @@
 				type: 'web_search_results',
 				type: 'web_search_results',
 				urls: results.filenames
 				urls: results.filenames
 			});
 			});
-
-			messages = messages;
+			history.messages[responseMessageId] = responseMessage;
 		} else {
 		} else {
 			responseMessage.statusHistory.push({
 			responseMessage.statusHistory.push({
 				done: true,
 				done: true,
@@ -1662,7 +1759,7 @@
 				action: 'web_search',
 				action: 'web_search',
 				description: 'No search results found'
 				description: 'No search results found'
 			});
 			});
-			messages = messages;
+			history.messages[responseMessageId] = responseMessage;
 		}
 		}
 	};
 	};
 
 
@@ -1672,13 +1769,34 @@
 		});
 		});
 	};
 	};
 
 
+	const initChatHandler = async () => {
+		if (!$temporaryChatEnabled) {
+			chat = await createNewChat(localStorage.token, {
+				id: $chatId,
+				title: $i18n.t('New Chat'),
+				models: selectedModels,
+				system: $settings.system ?? undefined,
+				params: params,
+				history: history,
+				tags: [],
+				timestamp: Date.now()
+			});
+
+			currentChatPage.set(1);
+			await chats.set(await getChatList(localStorage.token, $currentChatPage));
+			await chatId.set(chat.id);
+		} else {
+			await chatId.set('local');
+		}
+		await tick();
+	};
+
 	const saveChatHandler = async (_chatId) => {
 	const saveChatHandler = async (_chatId) => {
 		if ($chatId == _chatId) {
 		if ($chatId == _chatId) {
 			if (!$temporaryChatEnabled) {
 			if (!$temporaryChatEnabled) {
 				chat = await updateChatById(localStorage.token, _chatId, {
 				chat = await updateChatById(localStorage.token, _chatId, {
-					messages: messages,
-					history: history,
 					models: selectedModels,
 					models: selectedModels,
+					history: history,
 					params: params,
 					params: params,
 					files: chatFiles
 					files: chatFiles
 				});
 				});
@@ -1688,52 +1806,6 @@
 			}
 			}
 		}
 		}
 	};
 	};
-	const mergeResponses = async (messageId, responses, _chatId) => {
-		console.log('mergeResponses', messageId, responses);
-		const message = history.messages[messageId];
-		const mergedResponse = {
-			status: true,
-			content: ''
-		};
-		message.merged = mergedResponse;
-		messages = messages;
-
-		try {
-			const [res, controller] = await generateMoACompletion(
-				localStorage.token,
-				message.model,
-				history.messages[message.parentId].content,
-				responses
-			);
-
-			if (res && res.ok && res.body) {
-				const textStream = await createOpenAITextStream(res.body, $settings.splitLargeChunks);
-				for await (const update of textStream) {
-					const { value, done, citations, error, usage } = update;
-					if (error || done) {
-						break;
-					}
-
-					if (mergedResponse.content == '' && value == '\n') {
-						continue;
-					} else {
-						mergedResponse.content += value;
-						messages = messages;
-					}
-
-					if (autoScroll) {
-						scrollToBottom();
-					}
-				}
-
-				await saveChatHandler(_chatId);
-			} else {
-				console.error(res);
-			}
-		} catch (e) {
-			console.error(e);
-		}
-	};
 </script>
 </script>
 
 
 <svelte:head>
 <svelte:head>
@@ -1784,18 +1856,11 @@
 			/>
 			/>
 		{/if}
 		{/if}
 
 
-		<Navbar
-			{title}
-			bind:selectedModels
-			bind:showModelSelector
-			shareEnabled={messages.length > 0}
-			{chat}
-			{initNewChat}
-		/>
+		<Navbar {chat} {title} bind:selectedModels shareEnabled={!!history.currentId} {initNewChat} />
 
 
 		<PaneGroup direction="horizontal" class="w-full h-full">
 		<PaneGroup direction="horizontal" class="w-full h-full">
 			<Pane defaultSize={50} class="h-full flex w-full relative">
 			<Pane defaultSize={50} class="h-full flex w-full relative">
-				{#if $banners.length > 0 && messages.length === 0 && !$chatId && selectedModels.length <= 1}
+				{#if $banners.length > 0 && !history.currentId && !$chatId && selectedModels.length <= 1}
 					<div class="absolute top-3 left-0 right-0 w-full z-20">
 					<div class="absolute top-3 left-0 right-0 w-full z-20">
 						<div class=" flex flex-col gap-1 w-full">
 						<div class=" flex flex-col gap-1 w-full">
 							{#each $banners.filter( (b) => (b.dismissible ? !JSON.parse(localStorage.getItem('dismissedBannerIds') ?? '[]').includes(b.id) : true) ) as banner}
 							{#each $banners.filter( (b) => (b.dismissible ? !JSON.parse(localStorage.getItem('dismissedBannerIds') ?? '[]').includes(b.id) : true) ) as banner}
@@ -1834,31 +1899,31 @@
 						<div class=" h-full w-full flex flex-col {chatIdProp ? 'py-4' : 'pt-2 pb-4'}">
 						<div class=" h-full w-full flex flex-col {chatIdProp ? 'py-4' : 'pt-2 pb-4'}">
 							<Messages
 							<Messages
 								chatId={$chatId}
 								chatId={$chatId}
-								{selectedModels}
-								{processing}
 								bind:history
 								bind:history
-								bind:messages
 								bind:autoScroll
 								bind:autoScroll
 								bind:prompt
 								bind:prompt
-								bottomPadding={files.length > 0}
+								{selectedModels}
 								{sendPrompt}
 								{sendPrompt}
-								{continueGeneration}
+								{showMessage}
+								{continueResponse}
 								{regenerateResponse}
 								{regenerateResponse}
 								{mergeResponses}
 								{mergeResponses}
 								{chatActionHandler}
 								{chatActionHandler}
-								{showMessage}
+								bottomPadding={files.length > 0}
 							/>
 							/>
 						</div>
 						</div>
 					</div>
 					</div>
 
 
 					<div class="">
 					<div class="">
 						<MessageInput
 						<MessageInput
+							{history}
 							bind:files
 							bind:files
 							bind:prompt
 							bind:prompt
 							bind:autoScroll
 							bind:autoScroll
 							bind:selectedToolIds
 							bind:selectedToolIds
 							bind:webSearchEnabled
 							bind:webSearchEnabled
 							bind:atSelectedModel
 							bind:atSelectedModel
+							{selectedModels}
 							availableToolIds={selectedModelIds.reduce((a, e, i, arr) => {
 							availableToolIds={selectedModelIds.reduce((a, e, i, arr) => {
 								const model = $models.find((m) => m.id === e);
 								const model = $models.find((m) => m.id === e);
 								if (model?.info?.meta?.toolIds ?? false) {
 								if (model?.info?.meta?.toolIds ?? false) {
@@ -1867,10 +1932,9 @@
 								return a;
 								return a;
 							}, [])}
 							}, [])}
 							transparentBackground={$settings?.backgroundImageUrl ?? false}
 							transparentBackground={$settings?.backgroundImageUrl ?? false}
-							{selectedModels}
-							{messages}
 							{submitPrompt}
 							{submitPrompt}
 							{stopResponse}
 							{stopResponse}
+							{createMessagePair}
 							on:call={async () => {
 							on:call={async () => {
 								await showControls.set(true);
 								await showControls.set(true);
 							}}
 							}}
@@ -1880,6 +1944,13 @@
 			</Pane>
 			</Pane>
 
 
 			<ChatControls
 			<ChatControls
+				bind:history
+				bind:chatFiles
+				bind:params
+				bind:files
+				bind:pane={controlPane}
+				chatId={$chatId}
+				modelId={selectedModelIds?.at(0) ?? null}
 				models={selectedModelIds.reduce((a, e, i, arr) => {
 				models={selectedModelIds.reduce((a, e, i, arr) => {
 					const model = $models.find((m) => m.id === e);
 					const model = $models.find((m) => m.id === e);
 					if (model) {
 					if (model) {
@@ -1887,16 +1958,9 @@
 					}
 					}
 					return a;
 					return a;
 				}, [])}
 				}, [])}
-				bind:history
-				bind:chatFiles
-				bind:params
-				bind:files
-				bind:pane={controlPane}
 				{submitPrompt}
 				{submitPrompt}
 				{stopResponse}
 				{stopResponse}
 				{showMessage}
 				{showMessage}
-				modelId={selectedModelIds?.at(0) ?? null}
-				chatId={$chatId}
 				{eventTarget}
 				{eventTarget}
 			/>
 			/>
 		</PaneGroup>
 		</PaneGroup>

+ 8 - 3
src/lib/components/chat/ChatControls.svelte

@@ -115,9 +115,9 @@
 		{/if}
 		{/if}
 	{:else}
 	{:else}
 		<!-- if $showControls -->
 		<!-- if $showControls -->
-		<PaneResizer class="relative flex w-2 items-center justify-center bg-background">
+		<PaneResizer class="relative flex w-2 items-center justify-center bg-background group">
 			<div class="z-10 flex h-7 w-5 items-center justify-center rounded-sm">
 			<div class="z-10 flex h-7 w-5 items-center justify-center rounded-sm">
-				<EllipsisVertical />
+				<EllipsisVertical className="size-4 invisible group-hover:visible" />
 			</div>
 			</div>
 		</PaneResizer>
 		</PaneResizer>
 		<Pane
 		<Pane
@@ -128,7 +128,6 @@
 					: 30
 					: 30
 				: 0}
 				: 0}
 			onResize={(size) => {
 			onResize={(size) => {
-				console.log(size);
 				if (size === 0) {
 				if (size === 0) {
 					showControls.set(false);
 					showControls.set(false);
 				} else {
 				} else {
@@ -164,6 +163,12 @@
 							<Overview
 							<Overview
 								{history}
 								{history}
 								on:nodeclick={(e) => {
 								on:nodeclick={(e) => {
+									if (e.detail.node.data.message.favorite) {
+										history.messages[e.detail.node.data.message.id].favorite = true;
+									} else {
+										history.messages[e.detail.node.data.message.id].favorite = null;
+									}
+
 									showMessage(e.detail.node.data.message);
 									showMessage(e.detail.node.data.message);
 								}}
 								}}
 								on:close={() => {
 								on:close={() => {

+ 14 - 8
src/lib/components/chat/MessageInput.svelte

@@ -41,6 +41,7 @@
 	export let transparentBackground = false;
 	export let transparentBackground = false;
 
 
 	export let submitPrompt: Function;
 	export let submitPrompt: Function;
+	export let createMessagePair: Function;
 	export let stopResponse: Function;
 	export let stopResponse: Function;
 
 
 	export let autoScroll = false;
 	export let autoScroll = false;
@@ -61,15 +62,14 @@
 	let user = null;
 	let user = null;
 	let chatInputPlaceholder = '';
 	let chatInputPlaceholder = '';
 
 
-	export let files = [];
+	export let history;
 
 
+	export let prompt = '';
+	export let files = [];
 	export let availableToolIds = [];
 	export let availableToolIds = [];
 	export let selectedToolIds = [];
 	export let selectedToolIds = [];
 	export let webSearchEnabled = false;
 	export let webSearchEnabled = false;
 
 
-	export let prompt = '';
-	export let messages = [];
-
 	let visionCapableModels = [];
 	let visionCapableModels = [];
 	$: visionCapableModels = [...(atSelectedModel ? [atSelectedModel] : selectedModels)].filter(
 	$: visionCapableModels = [...(atSelectedModel ? [atSelectedModel] : selectedModels)].filter(
 		(model) => $models.find((m) => m.id === model)?.info?.meta?.capabilities?.vision ?? true
 		(model) => $models.find((m) => m.id === model)?.info?.meta?.capabilities?.vision ?? true
@@ -107,7 +107,7 @@
 		files = [...files, fileItem];
 		files = [...files, fileItem];
 
 
 		// Check if the file is an audio file and transcribe/convert it to text file
 		// Check if the file is an audio file and transcribe/convert it to text file
-		if (['audio/mpeg', 'audio/wav', 'audio/ogg'].includes(file['type'])) {
+		if (['audio/mpeg', 'audio/wav', 'audio/ogg', 'audio/x-m4a'].includes(file['type'])) {
 			const res = await transcribeAudio(localStorage.token, file).catch((error) => {
 			const res = await transcribeAudio(localStorage.token, file).catch((error) => {
 				toast.error(error);
 				toast.error(error);
 				return null;
 				return null;
@@ -272,7 +272,7 @@
 	<div class=" -mb-0.5 mx-auto inset-x-0 bg-transparent flex justify-center">
 	<div class=" -mb-0.5 mx-auto inset-x-0 bg-transparent flex justify-center">
 		<div class="flex flex-col max-w-6xl px-2.5 md:px-6 w-full">
 		<div class="flex flex-col max-w-6xl px-2.5 md:px-6 w-full">
 			<div class="relative">
 			<div class="relative">
-				{#if autoScroll === false && messages.length > 0}
+				{#if autoScroll === false && history?.currentId}
 					<div
 					<div
 						class=" absolute -top-12 left-0 right-0 flex justify-center z-30 pointer-events-none"
 						class=" absolute -top-12 left-0 right-0 flex justify-center z-30 pointer-events-none"
 					>
 					>
@@ -555,6 +555,12 @@
 										const isCtrlPressed = e.ctrlKey || e.metaKey; // metaKey is for Cmd key on Mac
 										const isCtrlPressed = e.ctrlKey || e.metaKey; // metaKey is for Cmd key on Mac
 										const commandsContainerElement = document.getElementById('commands-container');
 										const commandsContainerElement = document.getElementById('commands-container');
 
 
+										// Command/Ctrl + Shift + Enter to submit a message pair
+										if (isCtrlPressed && e.key === 'Enter' && e.shiftKey) {
+											e.preventDefault();
+											createMessagePair(prompt);
+										}
+
 										// Check if Ctrl + R is pressed
 										// Check if Ctrl + R is pressed
 										if (prompt === '' && isCtrlPressed && e.key.toLowerCase() === 'r') {
 										if (prompt === '' && isCtrlPressed && e.key.toLowerCase() === 'r') {
 											e.preventDefault();
 											e.preventDefault();
@@ -692,7 +698,7 @@
 								/>
 								/>
 
 
 								<div class="self-end mb-2 flex space-x-1 mr-1">
 								<div class="self-end mb-2 flex space-x-1 mr-1">
-									{#if messages.length == 0 || messages.at(-1).done == true}
+									{#if !history?.currentId || history.messages[history.currentId]?.done == true}
 										<Tooltip content={$i18n.t('Record voice')}>
 										<Tooltip content={$i18n.t('Record voice')}>
 											<button
 											<button
 												id="voice-input-button"
 												id="voice-input-button"
@@ -744,7 +750,7 @@
 							</div>
 							</div>
 						</div>
 						</div>
 						<div class="flex items-end w-10">
 						<div class="flex items-end w-10">
-							{#if messages.length == 0 || messages.at(-1).done == true}
+							{#if !history.currentId || history.messages[history.currentId]?.done == true}
 								{#if prompt === ''}
 								{#if prompt === ''}
 									<div class=" flex items-center mb-1">
 									<div class=" flex items-center mb-1">
 										<Tooltip content={$i18n.t('Call')}>
 										<Tooltip content={$i18n.t('Call')}>

+ 45 - 5
src/lib/components/chat/MessageInput/Commands/Prompts.svelte

@@ -1,6 +1,14 @@
 <script lang="ts">
 <script lang="ts">
 	import { prompts } from '$lib/stores';
 	import { prompts } from '$lib/stores';
-	import { findWordIndices } from '$lib/utils';
+	import {
+		findWordIndices,
+		getUserPosition,
+		getFormattedDate,
+		getFormattedTime,
+		getCurrentDateTime,
+		getUserTimezone,
+		getWeekday
+	} from '$lib/utils';
 	import { tick, getContext } from 'svelte';
 	import { tick, getContext } from 'svelte';
 	import { toast } from 'svelte-sonner';
 	import { toast } from 'svelte-sonner';
 
 
@@ -39,8 +47,6 @@
 				return '{{CLIPBOARD}}';
 				return '{{CLIPBOARD}}';
 			});
 			});
 
 
-			console.log(clipboardText);
-
 			const clipboardItems = await navigator.clipboard.read();
 			const clipboardItems = await navigator.clipboard.read();
 
 
 			let imageUrl = null;
 			let imageUrl = null;
@@ -50,7 +56,6 @@
 					if (type.startsWith('image/')) {
 					if (type.startsWith('image/')) {
 						const blob = await item.getType(type);
 						const blob = await item.getType(type);
 						imageUrl = URL.createObjectURL(blob);
 						imageUrl = URL.createObjectURL(blob);
-						console.log(`Image URL (${type}): ${imageUrl}`);
 					}
 					}
 				}
 				}
 			}
 			}
@@ -65,7 +70,42 @@
 				];
 				];
 			}
 			}
 
 
-			text = command.content.replaceAll('{{CLIPBOARD}}', clipboardText);
+			text = text.replaceAll('{{CLIPBOARD}}', clipboardText);
+		}
+
+		if (command.content.includes('{{USER_LOCATION}}')) {
+			const location = await getUserPosition();
+			text = text.replaceAll('{{USER_LOCATION}}', String(location));
+		}
+
+		if (command.content.includes('{{USER_LANGUAGE}}')) {
+			const language = localStorage.getItem('locale') || 'en-US';
+			text = text.replaceAll('{{USER_LANGUAGE}}', language);
+		}
+
+		if (command.content.includes('{{CURRENT_DATE}}')) {
+			const date = getFormattedDate();
+			text = text.replaceAll('{{CURRENT_DATE}}', date);
+		}
+
+		if (command.content.includes('{{CURRENT_TIME}}')) {
+			const time = getFormattedTime();
+			text = text.replaceAll('{{CURRENT_TIME}}', time);
+		}
+
+		if (command.content.includes('{{CURRENT_DATETIME}}')) {
+			const dateTime = getCurrentDateTime();
+			text = text.replaceAll('{{CURRENT_DATETIME}}', dateTime);
+		}
+
+		if (command.content.includes('{{CURRENT_TIMEZONE}}')) {
+			const timezone = getUserTimezone();
+			text = text.replaceAll('{{CURRENT_TIMEZONE}}', timezone);
+		}
+
+		if (command.content.includes('{{CURRENT_WEEKDAY}}')) {
+			const weekday = getWeekday();
+			text = text.replaceAll('{{CURRENT_WEEKDAY}}', weekday);
 		}
 		}
 
 
 		prompt = text;
 		prompt = text;

+ 177 - 216
src/lib/components/chat/Messages.svelte

@@ -7,31 +7,63 @@
 	import { getChatList, updateChatById } from '$lib/apis/chats';
 	import { getChatList, updateChatById } from '$lib/apis/chats';
 	import { copyToClipboard, findWordIndices } from '$lib/utils';
 	import { copyToClipboard, findWordIndices } from '$lib/utils';
 
 
-	import UserMessage from './Messages/UserMessage.svelte';
-	import ResponseMessage from './Messages/ResponseMessage.svelte';
 	import Placeholder from './Messages/Placeholder.svelte';
 	import Placeholder from './Messages/Placeholder.svelte';
-	import MultiResponseMessages from './Messages/MultiResponseMessages.svelte';
+	import Message from './Messages/Message.svelte';
+	import Loader from '../common/Loader.svelte';
+	import Spinner from '../common/Spinner.svelte';
 
 
 	const i18n = getContext('i18n');
 	const i18n = getContext('i18n');
 
 
 	export let chatId = '';
 	export let chatId = '';
-	export let readOnly = false;
+	export let user = $_user;
+
+	export let prompt;
+	export let history = {};
+	export let selectedModels;
+
+	let messages = [];
+
 	export let sendPrompt: Function;
 	export let sendPrompt: Function;
-	export let continueGeneration: Function;
+	export let continueResponse: Function;
 	export let regenerateResponse: Function;
 	export let regenerateResponse: Function;
 	export let mergeResponses: Function;
 	export let mergeResponses: Function;
 	export let chatActionHandler: Function;
 	export let chatActionHandler: Function;
 	export let showMessage: Function = () => {};
 	export let showMessage: Function = () => {};
 
 
-	export let user = $_user;
-	export let prompt;
-	export let processing = '';
+	export let readOnly = false;
+
 	export let bottomPadding = false;
 	export let bottomPadding = false;
 	export let autoScroll;
 	export let autoScroll;
-	export let history = {};
-	export let messages = [];
 
 
-	export let selectedModels;
+	let messagesCount = 20;
+	let messagesLoading = false;
+
+	const loadMoreMessages = async () => {
+		// scroll slightly down to disable continuous loading
+		const element = document.getElementById('messages-container');
+		element.scrollTop = element.scrollTop + 100;
+
+		messagesLoading = true;
+		messagesCount += 20;
+
+		await tick();
+
+		messagesLoading = false;
+	};
+
+	$: if (history.currentId) {
+		let _messages = [];
+
+		let message = history.messages[history.currentId];
+		while (message && _messages.length <= messagesCount) {
+			_messages.unshift({ ...message });
+			message = message.parentId !== null ? history.messages[message.parentId] : null;
+		}
+
+		messages = _messages;
+	} else {
+		messages = [];
+	}
 
 
 	$: if (autoScroll && bottomPadding) {
 	$: if (autoScroll && bottomPadding) {
 		(async () => {
 		(async () => {
@@ -45,56 +77,9 @@
 		element.scrollTop = element.scrollHeight;
 		element.scrollTop = element.scrollHeight;
 	};
 	};
 
 
-	const copyToClipboardWithToast = async (text) => {
-		const res = await copyToClipboard(text);
-		if (res) {
-			toast.success($i18n.t('Copying to clipboard was successful!'));
-		}
-	};
-
-	const confirmEditMessage = async (messageId, content, submit = true) => {
-		if (submit) {
-			let userPrompt = content;
-			let userMessageId = uuidv4();
-
-			let userMessage = {
-				id: userMessageId,
-				parentId: history.messages[messageId].parentId,
-				childrenIds: [],
-				role: 'user',
-				content: userPrompt,
-				...(history.messages[messageId].files && { files: history.messages[messageId].files }),
-				models: selectedModels
-			};
-
-			let messageParentId = history.messages[messageId].parentId;
-
-			if (messageParentId !== null) {
-				history.messages[messageParentId].childrenIds = [
-					...history.messages[messageParentId].childrenIds,
-					userMessageId
-				];
-			}
-
-			history.messages[userMessageId] = userMessage;
-			history.currentId = userMessageId;
-
-			await tick();
-			await sendPrompt(userPrompt, userMessageId);
-		} else {
-			history.messages[messageId].content = content;
-			await tick();
-			await updateChatById(localStorage.token, chatId, {
-				messages: messages,
-				history: history
-			});
-		}
-	};
-
-	const updateChatMessages = async () => {
+	const updateChatHistory = async () => {
 		await tick();
 		await tick();
 		await updateChatById(localStorage.token, chatId, {
 		await updateChatById(localStorage.token, chatId, {
-			messages: messages,
 			history: history
 			history: history
 		});
 		});
 
 
@@ -102,49 +87,6 @@
 		await chats.set(await getChatList(localStorage.token, $currentChatPage));
 		await chats.set(await getChatList(localStorage.token, $currentChatPage));
 	};
 	};
 
 
-	const confirmEditResponseMessage = async (messageId, content) => {
-		history.messages[messageId].originalContent = history.messages[messageId].content;
-		history.messages[messageId].content = content;
-
-		await updateChatMessages();
-	};
-
-	const saveNewResponseMessage = async (message, content) => {
-		const responseMessageId = uuidv4();
-		const parentId = message.parentId;
-
-		const responseMessage = {
-			...message,
-			id: responseMessageId,
-			parentId: parentId,
-			childrenIds: [],
-			content: content,
-			timestamp: Math.floor(Date.now() / 1000) // Unix epoch
-		};
-
-		history.messages[responseMessageId] = responseMessage;
-		history.currentId = responseMessageId;
-
-		// Append messageId to childrenIds of parent message
-		if (parentId !== null) {
-			history.messages[parentId].childrenIds = [
-				...history.messages[parentId].childrenIds,
-				responseMessageId
-			];
-		}
-
-		await updateChatMessages();
-	};
-
-	const rateMessage = async (messageId, rating) => {
-		history.messages[messageId].annotation = {
-			...history.messages[messageId].annotation,
-			rating: rating
-		};
-
-		await updateChatMessages();
-	};
-
 	const showPreviousMessage = async (message) => {
 	const showPreviousMessage = async (message) => {
 		if (message.parentId !== null) {
 		if (message.parentId !== null) {
 			let messageId =
 			let messageId =
@@ -243,7 +185,89 @@
 		}
 		}
 	};
 	};
 
 
-	const deleteMessageHandler = async (messageId) => {
+	const rateMessage = async (messageId, rating) => {
+		history.messages[messageId].annotation = {
+			...history.messages[messageId].annotation,
+			rating: rating
+		};
+
+		await updateChatHistory();
+	};
+
+	const editMessage = async (messageId, content, submit = true) => {
+		if (history.messages[messageId].role === 'user') {
+			if (submit) {
+				// New user message
+				let userPrompt = content;
+				let userMessageId = uuidv4();
+
+				let userMessage = {
+					id: userMessageId,
+					parentId: history.messages[messageId].parentId,
+					childrenIds: [],
+					role: 'user',
+					content: userPrompt,
+					...(history.messages[messageId].files && { files: history.messages[messageId].files }),
+					models: selectedModels
+				};
+
+				let messageParentId = history.messages[messageId].parentId;
+
+				if (messageParentId !== null) {
+					history.messages[messageParentId].childrenIds = [
+						...history.messages[messageParentId].childrenIds,
+						userMessageId
+					];
+				}
+
+				history.messages[userMessageId] = userMessage;
+				history.currentId = userMessageId;
+
+				await tick();
+				await sendPrompt(userPrompt, userMessageId);
+			} else {
+				// Edit user message
+				history.messages[messageId].content = content;
+				await updateChatHistory();
+			}
+		} else {
+			if (submit) {
+				// New response message
+				const responseMessageId = uuidv4();
+				const message = history.messages[messageId];
+				const parentId = message.parentId;
+
+				const responseMessage = {
+					...message,
+					id: responseMessageId,
+					parentId: parentId,
+					childrenIds: [],
+					content: content,
+					timestamp: Math.floor(Date.now() / 1000) // Unix epoch
+				};
+
+				history.messages[responseMessageId] = responseMessage;
+				history.currentId = responseMessageId;
+
+				// Append messageId to childrenIds of parent message
+				if (parentId !== null) {
+					history.messages[parentId].childrenIds = [
+						...history.messages[parentId].childrenIds,
+						responseMessageId
+					];
+				}
+
+				await updateChatHistory();
+			} else {
+				// Edit response message
+				history.messages[messageId].originalContent = history.messages[messageId].content;
+				history.messages[messageId].content = content;
+				await updateChatHistory();
+			}
+		}
+	};
+
+	const deleteMessage = async (messageId) => {
 		const messageToDelete = history.messages[messageId];
 		const messageToDelete = history.messages[messageId];
 		const parentMessageId = messageToDelete.parentId;
 		const parentMessageId = messageToDelete.parentId;
 		const childMessageIds = messageToDelete.childrenIds ?? [];
 		const childMessageIds = messageToDelete.childrenIds ?? [];
@@ -278,15 +302,12 @@
 		showMessage({ id: parentMessageId });
 		showMessage({ id: parentMessageId });
 
 
 		// Update the chat
 		// Update the chat
-		await updateChatById(localStorage.token, chatId, {
-			messages: messages,
-			history: history
-		});
+		await updateChatHistory();
 	};
 	};
 </script>
 </script>
 
 
 <div class="h-full flex">
 <div class="h-full flex">
-	{#if messages.length == 0}
+	{#if Object.keys(history?.messages ?? {}).length == 0}
 		<Placeholder
 		<Placeholder
 			modelIds={selectedModels}
 			modelIds={selectedModels}
 			submitPrompt={async (p) => {
 			submitPrompt={async (p) => {
@@ -327,115 +348,55 @@
 	{:else}
 	{:else}
 		<div class="w-full pt-2">
 		<div class="w-full pt-2">
 			{#key chatId}
 			{#key chatId}
-				{#each messages as message, messageIdx (message.id)}
-					<div class=" w-full {messageIdx === messages.length - 1 ? ' pb-12' : ''}">
-						<div
-							class="flex flex-col justify-between px-5 mb-3 {($settings?.widescreenMode ?? null)
-								? 'max-w-full'
-								: 'max-w-5xl'} mx-auto rounded-lg group"
+				<div class="w-full">
+					{#if messages.at(0)?.parentId !== null}
+						<Loader
+							on:visible={(e) => {
+								console.log('visible');
+								if (!messagesLoading) {
+									loadMoreMessages();
+								}
+							}}
 						>
 						>
-							{#if message.role === 'user'}
-								<UserMessage
-									on:delete={() => deleteMessageHandler(message.id)}
-									{user}
-									{readOnly}
-									{message}
-									isFirstMessage={messageIdx === 0}
-									siblings={message.parentId !== null
-										? (history.messages[message.parentId]?.childrenIds ?? [])
-										: (Object.values(history.messages)
-												.filter((message) => message.parentId === null)
-												.map((message) => message.id) ?? [])}
-									{confirmEditMessage}
-									{showPreviousMessage}
-									{showNextMessage}
-									copyToClipboard={copyToClipboardWithToast}
-								/>
-							{:else if (history.messages[message.parentId]?.models?.length ?? 1) === 1}
-								{#key message.id}
-									<ResponseMessage
-										{message}
-										siblings={history.messages[message.parentId]?.childrenIds ?? []}
-										isLastMessage={messageIdx + 1 === messages.length}
-										{readOnly}
-										{updateChatMessages}
-										{confirmEditResponseMessage}
-										{saveNewResponseMessage}
-										{showPreviousMessage}
-										{showNextMessage}
-										{rateMessage}
-										copyToClipboard={copyToClipboardWithToast}
-										{continueGeneration}
-										{regenerateResponse}
-										on:action={async (e) => {
-											console.log('action', e);
-											if (typeof e.detail === 'string') {
-												await chatActionHandler(chatId, e.detail, message.model, message.id);
-											} else {
-												const { id, event } = e.detail;
-												await chatActionHandler(chatId, id, message.model, message.id, event);
-											}
-										}}
-										on:save={async (e) => {
-											console.log('save', e);
-
-											const message = e.detail;
-											history.messages[message.id] = message;
-											await updateChatById(localStorage.token, chatId, {
-												messages: messages,
-												history: history
-											});
-										}}
-									/>
-								{/key}
-							{:else}
-								{#key message.parentId}
-									<MultiResponseMessages
-										bind:history
-										isLastMessage={messageIdx + 1 === messages.length}
-										{messages}
-										{readOnly}
-										{chatId}
-										parentMessage={history.messages[message.parentId]}
-										{messageIdx}
-										{updateChatMessages}
-										{confirmEditResponseMessage}
-										{rateMessage}
-										copyToClipboard={copyToClipboardWithToast}
-										{continueGeneration}
-										{mergeResponses}
-										{regenerateResponse}
-										on:action={async (e) => {
-											console.log('action', e);
-											if (typeof e.detail === 'string') {
-												await chatActionHandler(chatId, e.detail, message.model, message.id);
-											} else {
-												const { id, event } = e.detail;
-												await chatActionHandler(chatId, id, message.model, message.id, event);
-											}
-										}}
-										on:change={async () => {
-											await updateChatById(localStorage.token, chatId, {
-												messages: messages,
-												history: history
-											});
-
-											if (autoScroll) {
-												const element = document.getElementById('messages-container');
-												autoScroll =
-													element.scrollHeight - element.scrollTop <= element.clientHeight + 50;
-												setTimeout(() => {
-													scrollToBottom();
-												}, 100);
-											}
-										}}
-									/>
-								{/key}
-							{/if}
-						</div>
-					</div>
-				{/each}
-
+							<div class="w-full flex justify-center py-1 text-xs animate-pulse items-center gap-2">
+								<Spinner className=" size-4" />
+								<div class=" ">Loading...</div>
+							</div>
+						</Loader>
+					{/if}
+
+					{#each messages as message, messageIdx (message.id)}
+						<Message
+							{chatId}
+							bind:history
+							messageId={message.id}
+							idx={messageIdx}
+							{user}
+							{showPreviousMessage}
+							{showNextMessage}
+							{editMessage}
+							{deleteMessage}
+							{rateMessage}
+							{regenerateResponse}
+							{continueResponse}
+							{mergeResponses}
+							{updateChatHistory}
+							{chatActionHandler}
+							{readOnly}
+							on:scroll={() => {
+								if (autoScroll) {
+									const element = document.getElementById('messages-container');
+									autoScroll =
+										element.scrollHeight - element.scrollTop <= element.clientHeight + 50;
+									setTimeout(() => {
+										scrollToBottom();
+									}, 100);
+								}
+							}}
+						/>
+					{/each}
+				</div>
+				<div class="pb-12" />
 				{#if bottomPadding}
 				{#if bottomPadding}
 					<div class="  pb-6" />
 					<div class="  pb-6" />
 				{/if}
 				{/if}

+ 23 - 13
src/lib/components/chat/Messages/CitationsModal.svelte

@@ -1,6 +1,7 @@
 <script lang="ts">
 <script lang="ts">
 	import { getContext, onMount, tick } from 'svelte';
 	import { getContext, onMount, tick } from 'svelte';
 	import Modal from '$lib/components/common/Modal.svelte';
 	import Modal from '$lib/components/common/Modal.svelte';
+	import Tooltip from '$lib/components/common/Tooltip.svelte';
 	const i18n = getContext('i18n');
 	const i18n = getContext('i18n');
 
 
 	export let show = false;
 	export let show = false;
@@ -55,19 +56,28 @@
 						</div>
 						</div>
 
 
 						{#if document.source?.name}
 						{#if document.source?.name}
-							<div class="text-sm dark:text-gray-400">
-								<a
-									href={document?.metadata?.file_id
-										? `/api/v1/files/${document?.metadata?.file_id}/content`
-										: document.source.name.includes('http')
-											? document.source.name
-											: `#`}
-									target="_blank"
-								>
-									{document?.metadata?.name ?? document.source.name}
-								</a>
-								{document?.metadata?.page ? `(page ${document.metadata.page + 1})` : ''}
-							</div>
+							<Tooltip
+								content={$i18n.t('Open file')}
+								placement="left"
+								tippyOptions={{ duration: [500, 0], animation: 'perspective' }}
+							>
+								<div class="text-sm dark:text-gray-400">
+									<a
+										class="hover:text-gray-500 hover:dark:text-gray-100 underline"
+										href={document?.metadata?.file_id
+											? `/api/v1/files/${document?.metadata?.file_id}/content${document?.metadata?.page !== undefined ? `#page=${document.metadata.page + 1}` : ''}`
+											: document.source.name.includes('http')
+												? document.source.name
+												: `#`}
+										target="_blank"
+									>
+										{document?.metadata?.name ?? document.source.name}
+									</a>
+									{document?.metadata?.page
+										? `(${$i18n.t('page')} ${document.metadata.page + 1})`
+										: ''}
+								</div>
+							</Tooltip>
 						{:else}
 						{:else}
 							<div class="text-sm dark:text-gray-400">
 							<div class="text-sm dark:text-gray-400">
 								{$i18n.t('No source available')}
 								{$i18n.t('No source available')}

+ 15 - 1
src/lib/components/chat/Messages/CodeBlock.svelte

@@ -20,6 +20,8 @@
 	export let lang = '';
 	export let lang = '';
 	export let code = '';
 	export let code = '';
 
 
+	let _token = null;
+
 	let mermaidHtml = null;
 	let mermaidHtml = null;
 
 
 	let highlightedCode = null;
 	let highlightedCode = null;
@@ -226,7 +228,7 @@ __builtins__.input = input`);
 		}
 		}
 	};
 	};
 
 
-	$: if (token.raw) {
+	const render = async () => {
 		if (lang === 'mermaid' && (token?.raw ?? '').slice(-4).includes('```')) {
 		if (lang === 'mermaid' && (token?.raw ?? '').slice(-4).includes('```')) {
 			(async () => {
 			(async () => {
 				await drawMermaidDiagram();
 				await drawMermaidDiagram();
@@ -242,9 +244,21 @@ __builtins__.input = input`);
 			// Set a new timeout to debounce the code highlighting
 			// Set a new timeout to debounce the code highlighting
 			debounceTimeout = setTimeout(highlightCode, 10);
 			debounceTimeout = setTimeout(highlightCode, 10);
 		}
 		}
+	};
+
+	$: if (token) {
+		if (JSON.stringify(token) !== JSON.stringify(_token)) {
+			console.log('hi');
+			_token = token;
+		}
+	}
+
+	$: if (_token) {
+		render();
 	}
 	}
 
 
 	onMount(async () => {
 	onMount(async () => {
+		console.log('codeblock', lang, code);
 		if (document.documentElement.classList.contains('dark')) {
 		if (document.documentElement.classList.contains('dark')) {
 			mermaid.initialize({
 			mermaid.initialize({
 				startOnLoad: true,
 				startOnLoad: true,

+ 1 - 1
src/lib/components/chat/Messages/Markdown/MarkdownTokens.svelte

@@ -19,7 +19,7 @@
 </script>
 </script>
 
 
 <!-- {JSON.stringify(tokens)} -->
 <!-- {JSON.stringify(tokens)} -->
-{#each tokens as token, tokenIdx}
+{#each tokens as token, tokenIdx (tokenIdx)}
 	{#if token.type === 'hr'}
 	{#if token.type === 'hr'}
 		<hr />
 		<hr />
 	{:else if token.type === 'heading'}
 	{:else if token.type === 'heading'}

+ 166 - 0
src/lib/components/chat/Messages/Message.svelte

@@ -0,0 +1,166 @@
+<script lang="ts">
+	import { toast } from 'svelte-sonner';
+
+	import { tick, getContext, onMount, createEventDispatcher } from 'svelte';
+	const dispatch = createEventDispatcher();
+	const i18n = getContext('i18n');
+
+	import { settings } from '$lib/stores';
+	import { copyToClipboard } from '$lib/utils';
+
+	import MultiResponseMessages from './MultiResponseMessages.svelte';
+	import ResponseMessage from './ResponseMessage.svelte';
+	import UserMessage from './UserMessage.svelte';
+	import { updateChatById } from '$lib/apis/chats';
+
+	export let chatId;
+	export let idx = 0;
+
+	export let history;
+	export let messageId;
+
+	export let user;
+
+	export let updateChatHistory;
+	export let chatActionHandler;
+
+	export let showPreviousMessage;
+	export let showNextMessage;
+
+	export let editMessage;
+	export let deleteMessage;
+	export let rateMessage;
+
+	export let regenerateResponse;
+	export let continueResponse;
+
+	// MultiResponseMessages
+	export let mergeResponses;
+
+	export let autoScroll = false;
+	export let readOnly = false;
+
+	onMount(() => {
+		// console.log('message', idx);
+	});
+</script>
+
+<div
+	class="flex flex-col justify-between px-5 mb-3 w-full {($settings?.widescreenMode ?? null)
+		? 'max-w-full'
+		: 'max-w-5xl'} mx-auto rounded-lg group"
+>
+	{#if history.messages[messageId]}
+		{#if history.messages[messageId].role === 'user'}
+			<UserMessage
+				{user}
+				{history}
+				{messageId}
+				isFirstMessage={idx === 0}
+				siblings={history.messages[messageId].parentId !== null
+					? (history.messages[history.messages[messageId].parentId]?.childrenIds ?? [])
+					: (Object.values(history.messages)
+							.filter((message) => message.parentId === null)
+							.map((message) => message.id) ?? [])}
+				{showPreviousMessage}
+				{showNextMessage}
+				{editMessage}
+				on:delete={() => deleteMessage(messageId)}
+				{readOnly}
+			/>
+		{:else if (history.messages[history.messages[messageId].parentId]?.models?.length ?? 1) === 1}
+			<ResponseMessage
+				{history}
+				{messageId}
+				isLastMessage={messageId === history.currentId}
+				siblings={history.messages[history.messages[messageId].parentId]?.childrenIds ?? []}
+				{showPreviousMessage}
+				{showNextMessage}
+				{editMessage}
+				{rateMessage}
+				{continueResponse}
+				{regenerateResponse}
+				on:action={async (e) => {
+					console.log('action', e);
+					const message = history.messages[messageId];
+					if (typeof e.detail === 'string') {
+						await chatActionHandler(chatId, e.detail, message.model, message.id);
+					} else {
+						const { id, event } = e.detail;
+						await chatActionHandler(chatId, id, message.model, message.id, event);
+					}
+				}}
+				on:update={async (e) => {
+					console.log('update', e);
+					updateChatHistory();
+				}}
+				on:save={async (e) => {
+					console.log('save', e);
+
+					const message = e.detail;
+					if (message) {
+						history.messages[message.id] = message;
+						await updateChatById(localStorage.token, chatId, {
+							history: history
+						});
+					} else {
+						await updateChatById(localStorage.token, chatId, {
+							history: history
+						});
+					}
+				}}
+				{readOnly}
+			/>
+		{:else}
+			<MultiResponseMessages
+				bind:history
+				{chatId}
+				{messageId}
+				isLastMessage={messageId === history?.currentId}
+				{rateMessage}
+				{editMessage}
+				{continueResponse}
+				{regenerateResponse}
+				{mergeResponses}
+				on:action={async (e) => {
+					console.log('action', e);
+					const message = history.messages[messageId];
+					if (typeof e.detail === 'string') {
+						await chatActionHandler(chatId, e.detail, message.model, message.id);
+					} else {
+						const { id, event } = e.detail;
+						await chatActionHandler(chatId, id, message.model, message.id, event);
+					}
+				}}
+				on:update={async (e) => {
+					console.log('update', e);
+					updateChatHistory();
+				}}
+				on:save={async (e) => {
+					console.log('save', e);
+
+					const message = e.detail;
+					if (message) {
+						history.messages[message.id] = message;
+						await updateChatById(localStorage.token, chatId, {
+							history: history
+						});
+					} else {
+						await updateChatById(localStorage.token, chatId, {
+							history: history
+						});
+					}
+				}}
+				on:change={async () => {
+					await tick();
+					await updateChatById(localStorage.token, chatId, {
+						history: history
+					});
+
+					dispatch('scroll');
+				}}
+				{readOnly}
+			/>
+		{/if}
+	{/if}
+</div>

+ 139 - 123
src/lib/components/chat/Messages/MultiResponseMessages.svelte

@@ -20,40 +20,39 @@
 	const i18n = getContext('i18n');
 	const i18n = getContext('i18n');
 
 
 	export let chatId;
 	export let chatId;
-
 	export let history;
 	export let history;
-	export let messages = [];
-	export let messageIdx;
+	export let messageId;
 
 
-	export let parentMessage;
 	export let isLastMessage;
 	export let isLastMessage;
-
 	export let readOnly = false;
 	export let readOnly = false;
 
 
-	export let updateChatMessages: Function;
-	export let confirmEditResponseMessage: Function;
+	export let editMessage: Function;
 	export let rateMessage: Function;
 	export let rateMessage: Function;
 
 
-	export let copyToClipboard: Function;
-	export let continueGeneration: Function;
-	export let mergeResponses: Function;
+	export let continueResponse: Function;
 	export let regenerateResponse: Function;
 	export let regenerateResponse: Function;
+	export let mergeResponses: Function;
 
 
 	const dispatch = createEventDispatcher();
 	const dispatch = createEventDispatcher();
 
 
 	let currentMessageId;
 	let currentMessageId;
-	let groupedMessages = {};
-	let groupedMessagesIdx = {};
-
-	$: if (parentMessage) {
-		initHandler();
+	let parentMessage;
+	let groupedMessageIds = {};
+	let groupedMessageIdsIdx = {};
+
+	let message = JSON.parse(JSON.stringify(history.messages[messageId]));
+	$: if (history.messages) {
+		if (JSON.stringify(message) !== JSON.stringify(history.messages[messageId])) {
+			message = JSON.parse(JSON.stringify(history.messages[messageId]));
+		}
 	}
 	}
 
 
 	const showPreviousMessage = (modelIdx) => {
 	const showPreviousMessage = (modelIdx) => {
-		groupedMessagesIdx[modelIdx] = Math.max(0, groupedMessagesIdx[modelIdx] - 1);
-		let messageId = groupedMessages[modelIdx].messages[groupedMessagesIdx[modelIdx]].id;
+		groupedMessageIdsIdx[modelIdx] = Math.max(0, groupedMessageIdsIdx[modelIdx] - 1);
 
 
+		let messageId = groupedMessageIds[modelIdx].messageIds[groupedMessageIdsIdx[modelIdx]];
 		console.log(messageId);
 		console.log(messageId);
+
 		let messageChildrenIds = history.messages[messageId].childrenIds;
 		let messageChildrenIds = history.messages[messageId].childrenIds;
 
 
 		while (messageChildrenIds.length !== 0) {
 		while (messageChildrenIds.length !== 0) {
@@ -66,12 +65,12 @@
 	};
 	};
 
 
 	const showNextMessage = (modelIdx) => {
 	const showNextMessage = (modelIdx) => {
-		groupedMessagesIdx[modelIdx] = Math.min(
-			groupedMessages[modelIdx].messages.length - 1,
-			groupedMessagesIdx[modelIdx] + 1
+		groupedMessageIdsIdx[modelIdx] = Math.min(
+			groupedMessageIds[modelIdx].messageIds.length - 1,
+			groupedMessageIdsIdx[modelIdx] + 1
 		);
 		);
 
 
-		let messageId = groupedMessages[modelIdx].messages[groupedMessagesIdx[modelIdx]].id;
+		let messageId = groupedMessageIds[modelIdx].messageIds[groupedMessageIdsIdx[modelIdx]];
 		console.log(messageId);
 		console.log(messageId);
 
 
 		let messageChildrenIds = history.messages[messageId].childrenIds;
 		let messageChildrenIds = history.messages[messageId].childrenIds;
@@ -86,33 +85,43 @@
 	};
 	};
 
 
 	const initHandler = async () => {
 	const initHandler = async () => {
+		console.log('multiresponse:initHandler');
 		await tick();
 		await tick();
-		currentMessageId = messages[messageIdx].id;
 
 
-		groupedMessages = parentMessage?.models.reduce((a, model, modelIdx) => {
+		currentMessageId = messageId;
+		parentMessage = history.messages[messageId].parentId
+			? history.messages[history.messages[messageId].parentId]
+			: null;
+
+		groupedMessageIds = parentMessage?.models.reduce((a, model, modelIdx) => {
 			// Find all messages that are children of the parent message and have the same model
 			// Find all messages that are children of the parent message and have the same model
-			let modelMessages = parentMessage?.childrenIds
+			let modelMessageIds = parentMessage?.childrenIds
 				.map((id) => history.messages[id])
 				.map((id) => history.messages[id])
-				.filter((m) => m?.modelIdx === modelIdx);
+				.filter((m) => m?.modelIdx === modelIdx)
+				.map((m) => m.id);
 
 
-			if (modelMessages.length === 0) {
-				modelMessages = parentMessage?.childrenIds
+			// Legacy support for messages that don't have a modelIdx
+			// Find all messages that are children of the parent message and have the same model
+			if (modelMessageIds.length === 0) {
+				let modelMessages = parentMessage?.childrenIds
 					.map((id) => history.messages[id])
 					.map((id) => history.messages[id])
 					.filter((m) => m?.model === model);
 					.filter((m) => m?.model === model);
 
 
 				modelMessages.forEach((m) => {
 				modelMessages.forEach((m) => {
 					m.modelIdx = modelIdx;
 					m.modelIdx = modelIdx;
 				});
 				});
+
+				modelMessageIds = modelMessages.map((m) => m.id);
 			}
 			}
 
 
 			return {
 			return {
 				...a,
 				...a,
-				[modelIdx]: { messages: modelMessages }
+				[modelIdx]: { messageIds: modelMessageIds }
 			};
 			};
 		}, {});
 		}, {});
 
 
-		groupedMessagesIdx = parentMessage?.models.reduce((a, model, modelIdx) => {
-			const idx = groupedMessages[modelIdx].messages.findIndex((m) => m.id === currentMessageId);
+		groupedMessageIdsIdx = parentMessage?.models.reduce((a, model, modelIdx) => {
+			const idx = groupedMessageIds[modelIdx].messageIds.findIndex((id) => id === messageId);
 			if (idx !== -1) {
 			if (idx !== -1) {
 				return {
 				return {
 					...a,
 					...a,
@@ -121,39 +130,53 @@
 			} else {
 			} else {
 				return {
 				return {
 					...a,
 					...a,
-					[modelIdx]: 0
+					[modelIdx]: groupedMessageIds[modelIdx].messageIds.length - 1
 				};
 				};
 			}
 			}
 		}, {});
 		}, {});
+
+		console.log(groupedMessageIds, groupedMessageIdsIdx);
+
+		await tick();
 	};
 	};
 
 
 	const mergeResponsesHandler = async () => {
 	const mergeResponsesHandler = async () => {
-		const responses = Object.keys(groupedMessages).map((modelIdx) => {
-			const { messages } = groupedMessages[modelIdx];
-			return messages[groupedMessagesIdx[modelIdx]].content;
+		const responses = Object.keys(groupedMessageIds).map((modelIdx) => {
+			const { messageIds } = groupedMessageIds[modelIdx];
+			const messageId = messageIds[groupedMessageIdsIdx[modelIdx]];
+
+			return history.messages[messageId].content;
 		});
 		});
-		mergeResponses(currentMessageId, responses, chatId);
+		mergeResponses(messageId, responses, chatId);
 	};
 	};
 
 
 	onMount(async () => {
 	onMount(async () => {
-		initHandler();
+		await initHandler();
+		await tick();
+
+		const messageElement = document.getElementById(`message-${messageId}`);
+		console.log(messageElement);
+		if (messageElement) {
+			messageElement.scrollIntoView({ behavior: 'smooth', block: 'center' });
+		}
 	});
 	});
 </script>
 </script>
 
 
-<div>
-	<div
-		class="flex snap-x snap-mandatory overflow-x-auto scrollbar-hidden"
-		id="responses-container-{chatId}-{parentMessage.id}"
-	>
-		{#key currentMessageId}
-			{#each Object.keys(groupedMessages) as modelIdx}
-				{#if groupedMessagesIdx[modelIdx] !== undefined && groupedMessages[modelIdx].messages.length > 0}
+{#if parentMessage}
+	<div>
+		<div
+			class="flex snap-x snap-mandatory overflow-x-auto scrollbar-hidden"
+			id="responses-container-{chatId}-{parentMessage.id}"
+		>
+			{#each Object.keys(groupedMessageIds) as modelIdx}
+				{#if groupedMessageIdsIdx[modelIdx] !== undefined && groupedMessageIds[modelIdx].messageIds.length > 0}
 					<!-- svelte-ignore a11y-no-static-element-interactions -->
 					<!-- svelte-ignore a11y-no-static-element-interactions -->
 					<!-- svelte-ignore a11y-click-events-have-key-events -->
 					<!-- svelte-ignore a11y-click-events-have-key-events -->
-					{@const message = groupedMessages[modelIdx].messages[groupedMessagesIdx[modelIdx]]}
+					{@const _messageId =
+						groupedMessageIds[modelIdx].messageIds[groupedMessageIdsIdx[modelIdx]]}
 
 
 					<div
 					<div
-						class=" snap-center w-full max-w-full m-1 border {history.messages[currentMessageId]
+						class=" snap-center w-full max-w-full m-1 border {history.messages[messageId]
 							?.modelIdx == modelIdx
 							?.modelIdx == modelIdx
 							? `border-gray-100 dark:border-gray-800 border-[1.5px] ${
 							? `border-gray-100 dark:border-gray-800 border-[1.5px] ${
 									$mobile ? 'min-w-full' : 'min-w-[32rem]'
 									$mobile ? 'min-w-full' : 'min-w-[32rem]'
@@ -162,17 +185,13 @@
 									$mobile ? 'min-w-full' : 'min-w-80'
 									$mobile ? 'min-w-full' : 'min-w-80'
 								}`} transition-all p-5 rounded-2xl"
 								}`} transition-all p-5 rounded-2xl"
 						on:click={() => {
 						on:click={() => {
-							if (currentMessageId != message.id) {
-								currentMessageId = message.id;
-								let messageId = message.id;
-								console.log(messageId);
-								//
-								let messageChildrenIds = history.messages[messageId].childrenIds;
+							if (messageId != _messageId) {
+								let messageChildrenIds = history.messages[_messageId].childrenIds;
 								while (messageChildrenIds.length !== 0) {
 								while (messageChildrenIds.length !== 0) {
 									messageId = messageChildrenIds.at(-1);
 									messageId = messageChildrenIds.at(-1);
-									messageChildrenIds = history.messages[messageId].childrenIds;
+									messageChildrenIds = history.messages[_messageId].childrenIds;
 								}
 								}
-								history.currentId = messageId;
+								history.currentId = _messageId;
 								dispatch('change');
 								dispatch('change');
 							}
 							}
 						}}
 						}}
@@ -180,95 +199,92 @@
 						{#key history.currentId}
 						{#key history.currentId}
 							{#if message}
 							{#if message}
 								<ResponseMessage
 								<ResponseMessage
-									{message}
-									siblings={groupedMessages[modelIdx].messages.map((m) => m.id)}
+									{history}
+									messageId={_messageId}
 									isLastMessage={true}
 									isLastMessage={true}
-									{updateChatMessages}
-									{confirmEditResponseMessage}
+									siblings={groupedMessageIds[modelIdx].messageIds}
 									showPreviousMessage={() => showPreviousMessage(modelIdx)}
 									showPreviousMessage={() => showPreviousMessage(modelIdx)}
 									showNextMessage={() => showNextMessage(modelIdx)}
 									showNextMessage={() => showNextMessage(modelIdx)}
-									{readOnly}
 									{rateMessage}
 									{rateMessage}
-									{copyToClipboard}
-									{continueGeneration}
+									{editMessage}
+									{continueResponse}
 									regenerateResponse={async (message) => {
 									regenerateResponse={async (message) => {
 										regenerateResponse(message);
 										regenerateResponse(message);
 										await tick();
 										await tick();
-										groupedMessagesIdx[modelIdx] = groupedMessages[modelIdx].messages.length - 1;
+										groupedMessageIdsIdx[modelIdx] =
+											groupedMessageIds[modelIdx].messageIds.length - 1;
 									}}
 									}}
 									on:action={async (e) => {
 									on:action={async (e) => {
 										dispatch('action', e.detail);
 										dispatch('action', e.detail);
 									}}
 									}}
+									on:update={async (e) => {
+										dispatch('update', e.detail);
+									}}
 									on:save={async (e) => {
 									on:save={async (e) => {
-										console.log('save', e);
-
-										const message = e.detail;
-										history.messages[message.id] = message;
-										await updateChatById(localStorage.token, chatId, {
-											messages: messages,
-											history: history
-										});
+										dispatch('save', e.detail);
 									}}
 									}}
+									{readOnly}
 								/>
 								/>
 							{/if}
 							{/if}
 						{/key}
 						{/key}
 					</div>
 					</div>
 				{/if}
 				{/if}
 			{/each}
 			{/each}
-		{/key}
-	</div>
-
-	{#if !readOnly && isLastMessage}
-		{#if !Object.keys(groupedMessages).find((modelIdx) => {
-			const { messages } = groupedMessages[modelIdx];
-			return !messages[groupedMessagesIdx[modelIdx]]?.done ?? false;
-		})}
-			<div class="flex justify-end">
-				<div class="w-full">
-					{#if history.messages[currentMessageId]?.merged?.status}
-						{@const message = history.messages[currentMessageId]?.merged}
-
-						<div class="w-full rounded-xl pl-5 pr-2 py-2">
-							<Name>
-								Merged Response
-
-								{#if message.timestamp}
-									<span
-										class=" self-center invisible group-hover:visible text-gray-400 text-xs font-medium uppercase ml-0.5 -mt-0.5"
-									>
-										{dayjs(message.timestamp * 1000).format($i18n.t('h:mm a'))}
-									</span>
-								{/if}
-							</Name>
-
-							<div class="mt-1 markdown-prose w-full min-w-full">
-								{#if (message?.content ?? '') === ''}
-									<Skeleton />
-								{:else}
-									<Markdown id={`merged`} content={message.content ?? ''} />
-								{/if}
+		</div>
+
+		{#if !readOnly && isLastMessage}
+			{#if !Object.keys(groupedMessageIds).find((modelIdx) => {
+				const { messageIds } = groupedMessageIds[modelIdx];
+				const _messageId = messageIds[groupedMessageIdsIdx[modelIdx]];
+				return !history.messages[_messageId]?.done ?? false;
+			})}
+				<div class="flex justify-end">
+					<div class="w-full">
+						{#if history.messages[messageId]?.merged?.status}
+							{@const message = history.messages[messageId]?.merged}
+
+							<div class="w-full rounded-xl pl-5 pr-2 py-2">
+								<Name>
+									Merged Response
+
+									{#if message.timestamp}
+										<span
+											class=" self-center invisible group-hover:visible text-gray-400 text-xs font-medium uppercase ml-0.5 -mt-0.5"
+										>
+											{dayjs(message.timestamp * 1000).format($i18n.t('h:mm a'))}
+										</span>
+									{/if}
+								</Name>
+
+								<div class="mt-1 markdown-prose w-full min-w-full">
+									{#if (message?.content ?? '') === ''}
+										<Skeleton />
+									{:else}
+										<Markdown id={`merged`} content={message.content ?? ''} />
+									{/if}
+								</div>
 							</div>
 							</div>
-						</div>
-					{/if}
-				</div>
+						{/if}
+					</div>
 
 
-				<div class=" flex-shrink-0 text-gray-600 dark:text-gray-500 mt-1">
-					<Tooltip content={$i18n.t('Merge Responses')} placement="bottom">
-						<button
-							type="button"
-							id="merge-response-button"
-							class="{true
-								? 'visible'
-								: 'invisible group-hover:visible'} p-1 hover:bg-black/5 dark:hover:bg-white/5 rounded-lg dark:hover:text-white hover:text-black transition regenerate-response-button"
-							on:click={() => {
-								mergeResponsesHandler();
-							}}
-						>
-							<Merge className=" size-5 " />
-						</button>
-					</Tooltip>
+					<div class=" flex-shrink-0 text-gray-600 dark:text-gray-500 mt-1">
+						<Tooltip content={$i18n.t('Merge Responses')} placement="bottom">
+							<button
+								type="button"
+								id="merge-response-button"
+								class="{true
+									? 'visible'
+									: 'invisible group-hover:visible'} p-1 hover:bg-black/5 dark:hover:bg-white/5 rounded-lg dark:hover:text-white hover:text-black transition regenerate-response-button"
+								on:click={() => {
+									mergeResponsesHandler();
+								}}
+							>
+								<Merge className=" size-5 " />
+							</button>
+						</Tooltip>
+					</div>
 				</div>
 				</div>
-			</div>
+			{/if}
 		{/if}
 		{/if}
-	{/if}
-</div>
+	</div>
+{/if}

+ 31 - 21
src/lib/components/chat/Messages/ResponseMessage.svelte

@@ -13,6 +13,7 @@
 	import { synthesizeOpenAISpeech } from '$lib/apis/audio';
 	import { synthesizeOpenAISpeech } from '$lib/apis/audio';
 	import { imageGenerations } from '$lib/apis/images';
 	import { imageGenerations } from '$lib/apis/images';
 	import {
 	import {
+		copyToClipboard as _copyToClipboard,
 		approximateToHumanReadable,
 		approximateToHumanReadable,
 		extractParagraphsForAudio,
 		extractParagraphsForAudio,
 		extractSentencesForAudio,
 		extractSentencesForAudio,
@@ -76,25 +77,30 @@
 		annotation?: { type: string; rating: number };
 		annotation?: { type: string; rating: number };
 	}
 	}
 
 
-	export let message: MessageType;
-	export let siblings;
-
-	export let isLastMessage = true;
+	export let history;
+	export let messageId;
 
 
-	export let readOnly = false;
+	let message: MessageType = JSON.parse(JSON.stringify(history.messages[messageId]));
+	$: if (history.messages) {
+		if (JSON.stringify(message) !== JSON.stringify(history.messages[messageId])) {
+			message = JSON.parse(JSON.stringify(history.messages[messageId]));
+		}
+	}
 
 
-	export let updateChatMessages: Function;
-	export let confirmEditResponseMessage: Function;
-	export let saveNewResponseMessage: Function = () => {};
+	export let siblings;
 
 
 	export let showPreviousMessage: Function;
 	export let showPreviousMessage: Function;
 	export let showNextMessage: Function;
 	export let showNextMessage: Function;
+
+	export let editMessage: Function;
 	export let rateMessage: Function;
 	export let rateMessage: Function;
 
 
-	export let copyToClipboard: Function;
-	export let continueGeneration: Function;
+	export let continueResponse: Function;
 	export let regenerateResponse: Function;
 	export let regenerateResponse: Function;
 
 
+	export let isLastMessage = true;
+	export let readOnly = false;
+
 	let model = null;
 	let model = null;
 	$: model = $models.find((m) => m.id === message.model);
 	$: model = $models.find((m) => m.id === message.model);
 
 
@@ -111,6 +117,13 @@
 
 
 	let showRateComment = false;
 	let showRateComment = false;
 
 
+	const copyToClipboard = async (text) => {
+		const res = await _copyToClipboard(text);
+		if (res) {
+			toast.success($i18n.t('Copying to clipboard was successful!'));
+		}
+	};
+
 	const playAudio = (idx: number) => {
 	const playAudio = (idx: number) => {
 		return new Promise<void>((res) => {
 		return new Promise<void>((res) => {
 			speakingIdx = idx;
 			speakingIdx = idx;
@@ -260,11 +273,7 @@
 	};
 	};
 
 
 	const editMessageConfirmHandler = async () => {
 	const editMessageConfirmHandler = async () => {
-		if (editedContent === '') {
-			editedContent = ' ';
-		}
-
-		confirmEditResponseMessage(message.id, editedContent);
+		editMessage(message.id, editedContent ? editedContent : '', false);
 
 
 		edit = false;
 		edit = false;
 		editedContent = '';
 		editedContent = '';
@@ -272,8 +281,8 @@
 		await tick();
 		await tick();
 	};
 	};
 
 
-	const saveNewMessageHandler = async () => {
-		saveNewResponseMessage(message, editedContent);
+	const saveAsCopyHandler = async () => {
+		editMessage(message.id, editedContent ? editedContent : '');
 
 
 		edit = false;
 		edit = false;
 		editedContent = '';
 		editedContent = '';
@@ -313,6 +322,8 @@
 	}
 	}
 
 
 	onMount(async () => {
 	onMount(async () => {
+		console.log('ResponseMessage mounted');
+
 		await tick();
 		await tick();
 	});
 	});
 </script>
 </script>
@@ -424,7 +435,7 @@
 											id="save-new-message-button"
 											id="save-new-message-button"
 											class=" px-4 py-2 bg-gray-50 hover:bg-gray-100 dark:bg-gray-800 dark:hover:bg-gray-700 border dark:border-gray-700 text-gray-700 dark:text-gray-200 transition rounded-3xl"
 											class=" px-4 py-2 bg-gray-50 hover:bg-gray-100 dark:bg-gray-800 dark:hover:bg-gray-700 border dark:border-gray-700 text-gray-700 dark:text-gray-200 transition rounded-3xl"
 											on:click={() => {
 											on:click={() => {
-												saveNewMessageHandler();
+												saveAsCopyHandler();
 											}}
 											}}
 										>
 										>
 											{$i18n.t('Save As Copy')}
 											{$i18n.t('Save As Copy')}
@@ -909,7 +920,7 @@
 													? 'visible'
 													? 'visible'
 													: 'invisible group-hover:visible'} p-1.5 hover:bg-black/5 dark:hover:bg-white/5 rounded-lg dark:hover:text-white hover:text-black transition regenerate-response-button"
 													: 'invisible group-hover:visible'} p-1.5 hover:bg-black/5 dark:hover:bg-white/5 rounded-lg dark:hover:text-white hover:text-black transition regenerate-response-button"
 												on:click={() => {
 												on:click={() => {
-													continueGeneration();
+													continueResponse();
 
 
 													(model?.actions ?? [])
 													(model?.actions ?? [])
 														.filter((action) => action?.__webui__ ?? false)
 														.filter((action) => action?.__webui__ ?? false)
@@ -1028,8 +1039,7 @@
 							bind:show={showRateComment}
 							bind:show={showRateComment}
 							bind:message
 							bind:message
 							on:submit={(e) => {
 							on:submit={(e) => {
-								updateChatMessages();
-
+								dispatch('update');
 								(model?.actions ?? [])
 								(model?.actions ?? [])
 									.filter((action) => action?.__webui__ ?? false)
 									.filter((action) => action?.__webui__ ?? false)
 									.forEach((action) => {
 									.forEach((action) => {

+ 39 - 15
src/lib/components/chat/Messages/UserMessage.svelte

@@ -1,38 +1,58 @@
 <script lang="ts">
 <script lang="ts">
 	import dayjs from 'dayjs';
 	import dayjs from 'dayjs';
+	import { toast } from 'svelte-sonner';
+	import { tick, createEventDispatcher, getContext, onMount } from 'svelte';
+
+	import { models, settings } from '$lib/stores';
+	import { user as _user } from '$lib/stores';
+	import {
+		copyToClipboard as _copyToClipboard,
+		processResponseContent,
+		replaceTokens
+	} from '$lib/utils';
 
 
-	import { tick, createEventDispatcher, getContext } from 'svelte';
 	import Name from './Name.svelte';
 	import Name from './Name.svelte';
 	import ProfileImage from './ProfileImage.svelte';
 	import ProfileImage from './ProfileImage.svelte';
-	import { models, settings } from '$lib/stores';
 	import Tooltip from '$lib/components/common/Tooltip.svelte';
 	import Tooltip from '$lib/components/common/Tooltip.svelte';
-
-	import { user as _user } from '$lib/stores';
-	import { getFileContentById } from '$lib/apis/files';
 	import FileItem from '$lib/components/common/FileItem.svelte';
 	import FileItem from '$lib/components/common/FileItem.svelte';
-	import { marked } from 'marked';
-	import { processResponseContent, replaceTokens } from '$lib/utils';
-	import MarkdownTokens from './Markdown/MarkdownTokens.svelte';
 	import Markdown from './Markdown.svelte';
 	import Markdown from './Markdown.svelte';
 
 
 	const i18n = getContext('i18n');
 	const i18n = getContext('i18n');
 
 
 	const dispatch = createEventDispatcher();
 	const dispatch = createEventDispatcher();
-
 	export let user;
 	export let user;
-	export let message;
+
+	export let history;
+	export let messageId;
+
 	export let siblings;
 	export let siblings;
-	export let isFirstMessage: boolean;
-	export let readOnly: boolean;
 
 
-	export let confirmEditMessage: Function;
 	export let showPreviousMessage: Function;
 	export let showPreviousMessage: Function;
 	export let showNextMessage: Function;
 	export let showNextMessage: Function;
-	export let copyToClipboard: Function;
+
+	export let editMessage: Function;
+
+	export let isFirstMessage: boolean;
+	export let readOnly: boolean;
 
 
 	let edit = false;
 	let edit = false;
 	let editedContent = '';
 	let editedContent = '';
 	let messageEditTextAreaElement: HTMLTextAreaElement;
 	let messageEditTextAreaElement: HTMLTextAreaElement;
+
+	let message = JSON.parse(JSON.stringify(history.messages[messageId]));
+	$: if (history.messages) {
+		if (JSON.stringify(message) !== JSON.stringify(history.messages[messageId])) {
+			message = JSON.parse(JSON.stringify(history.messages[messageId]));
+		}
+	}
+
+	const copyToClipboard = async (text) => {
+		const res = await _copyToClipboard(text);
+		if (res) {
+			toast.success($i18n.t('Copying to clipboard was successful!'));
+		}
+	};
+
 	const editMessageHandler = async () => {
 	const editMessageHandler = async () => {
 		edit = true;
 		edit = true;
 		editedContent = message.content;
 		editedContent = message.content;
@@ -46,7 +66,7 @@
 	};
 	};
 
 
 	const editMessageConfirmHandler = async (submit = true) => {
 	const editMessageConfirmHandler = async (submit = true) => {
-		confirmEditMessage(message.id, editedContent, submit);
+		editMessage(message.id, editedContent, submit);
 
 
 		edit = false;
 		edit = false;
 		editedContent = '';
 		editedContent = '';
@@ -60,6 +80,10 @@
 	const deleteMessageHandler = async () => {
 	const deleteMessageHandler = async () => {
 		dispatch('delete', message.id);
 		dispatch('delete', message.id);
 	};
 	};
+
+	onMount(() => {
+		console.log('UserMessage mounted');
+	});
 </script>
 </script>
 
 
 <div class=" flex w-full user-message" dir={$settings.chatDirection} id="message-{message.id}">
 <div class=" flex w-full user-message" dir={$settings.chatDirection} id="message-{message.id}">

+ 24 - 5
src/lib/components/chat/Overview/Node.svelte

@@ -4,13 +4,14 @@
 
 
 	import ProfileImageBase from '../Messages/ProfileImageBase.svelte';
 	import ProfileImageBase from '../Messages/ProfileImageBase.svelte';
 	import Tooltip from '$lib/components/common/Tooltip.svelte';
 	import Tooltip from '$lib/components/common/Tooltip.svelte';
+	import Heart from '$lib/components/icons/Heart.svelte';
 
 
 	type $$Props = NodeProps;
 	type $$Props = NodeProps;
 	export let data: $$Props['data'];
 	export let data: $$Props['data'];
 </script>
 </script>
 
 
 <div
 <div
-	class="px-4 py-3 shadow-md rounded-xl dark:bg-black bg-white border dark:border-gray-900 w-60 h-20"
+	class="px-4 py-3 shadow-md rounded-xl dark:bg-black bg-white border dark:border-gray-900 w-60 h-20 group"
 >
 >
 	<Tooltip
 	<Tooltip
 		content={data?.message?.error ? data.message.error.content : data.message.content}
 		content={data?.message?.error ? data.message.error.content : data.message.content}
@@ -24,8 +25,10 @@
 					className={'size-5 -translate-y-[1px]'}
 					className={'size-5 -translate-y-[1px]'}
 				/>
 				/>
 				<div class="ml-2">
 				<div class="ml-2">
-					<div class="text-xs text-black dark:text-white font-medium">
-						{data?.user?.name ?? 'User'}
+					<div class=" flex justify-between items-center">
+						<div class="text-xs text-black dark:text-white font-medium line-clamp-1">
+							{data?.user?.name ?? 'User'}
+						</div>
 					</div>
 					</div>
 
 
 					{#if data?.message?.error}
 					{#if data?.message?.error}
@@ -43,8 +46,24 @@
 				/>
 				/>
 
 
 				<div class="ml-2">
 				<div class="ml-2">
-					<div class="text-xs text-black dark:text-white font-medium">
-						{data?.model?.name ?? data?.message?.model ?? 'Assistant'}
+					<div class=" flex justify-between items-center">
+						<div class="text-xs text-black dark:text-white font-medium line-clamp-1">
+							{data?.model?.name ?? data?.message?.model ?? 'Assistant'}
+						</div>
+
+						<button
+							class={data?.message?.favorite ? '' : 'invisible group-hover:visible'}
+							on:click={() => {
+								data.message.favorite = !(data?.message?.favorite ?? false);
+							}}
+						>
+							<Heart
+								className="size-3 {data?.message?.favorite
+									? 'fill-red-500 stroke-red-500'
+									: 'hover:fill-red-500 hover:stroke-red-500'} "
+								strokeWidth="2.5"
+							/>
+						</button>
 					</div>
 					</div>
 
 
 					{#if data?.message?.error}
 					{#if data?.message?.error}

+ 31 - 2
src/lib/components/chat/Settings/Advanced/AdvancedParams.svelte

@@ -10,6 +10,7 @@
 
 
 	export let params = {
 	export let params = {
 		// Advanced
 		// Advanced
+		stream_response: null, // Set stream responses for this model individually
 		seed: null,
 		seed: null,
 		stop: null,
 		stop: null,
 		temperature: null,
 		temperature: null,
@@ -42,6 +43,35 @@
 </script>
 </script>
 
 
 <div class=" space-y-1 text-xs pb-safe-bottom">
 <div class=" space-y-1 text-xs pb-safe-bottom">
+	<div>
+		<div class=" py-0.5 flex w-full justify-between">
+			<div class=" self-center text-xs font-medium">
+				{$i18n.t('Stream Chat Response')}
+			</div>
+
+			<button
+				class="p-1 px-3 text-xs flex rounded transition"
+				on:click={() => {
+					params.stream_response =
+						(params?.stream_response ?? null) === null
+							? true
+							: params.stream_response
+								? false
+								: null;
+				}}
+				type="button"
+			>
+				{#if params.stream_response === true}
+					<span class="ml-2 self-center">{$i18n.t('On')}</span>
+				{:else if params.stream_response === false}
+					<span class="ml-2 self-center">{$i18n.t('Off')}</span>
+				{:else}
+					<span class="ml-2 self-center">{$i18n.t('Default')}</span>
+				{/if}
+			</button>
+		</div>
+	</div>
+
 	<div class=" py-0.5 w-full justify-between">
 	<div class=" py-0.5 w-full justify-between">
 		<div class="flex w-full justify-between">
 		<div class="flex w-full justify-between">
 			<div class=" self-center text-xs font-medium">{$i18n.t('Seed')}</div>
 			<div class=" self-center text-xs font-medium">{$i18n.t('Seed')}</div>
@@ -734,7 +764,7 @@
 						id="steps-range"
 						id="steps-range"
 						type="range"
 						type="range"
 						min="-2"
 						min="-2"
-						max="16000"
+						max="131072"
 						step="1"
 						step="1"
 						bind:value={params.max_tokens}
 						bind:value={params.max_tokens}
 						class="w-full h-2 rounded-lg appearance-none cursor-pointer dark:bg-gray-700"
 						class="w-full h-2 rounded-lg appearance-none cursor-pointer dark:bg-gray-700"
@@ -746,7 +776,6 @@
 						type="number"
 						type="number"
 						class=" bg-transparent text-center w-14"
 						class=" bg-transparent text-center w-14"
 						min="-2"
 						min="-2"
-						max="16000"
 						step="1"
 						step="1"
 					/>
 					/>
 				</div>
 				</div>

+ 2 - 0
src/lib/components/chat/Settings/General.svelte

@@ -45,6 +45,7 @@
 
 
 	let params = {
 	let params = {
 		// Advanced
 		// Advanced
+		stream_response: null,
 		seed: null,
 		seed: null,
 		temperature: null,
 		temperature: null,
 		frequency_penalty: null,
 		frequency_penalty: null,
@@ -327,6 +328,7 @@
 				saveSettings({
 				saveSettings({
 					system: system !== '' ? system : undefined,
 					system: system !== '' ? system : undefined,
 					params: {
 					params: {
+						stream_response: params.stream_response !== null ? params.stream_response : undefined,
 						seed: (params.seed !== null ? params.seed : undefined) ?? undefined,
 						seed: (params.seed !== null ? params.seed : undefined) ?? undefined,
 						stop: params.stop ? params.stop.split(',').filter((e) => e) : undefined,
 						stop: params.stop ? params.stop.split(',').filter((e) => e) : undefined,
 						temperature: params.temperature !== null ? params.temperature : undefined,
 						temperature: params.temperature !== null ? params.temperature : undefined,

+ 0 - 30
src/lib/components/chat/Settings/Interface.svelte

@@ -36,18 +36,11 @@
 	let voiceInterruption = false;
 	let voiceInterruption = false;
 	let hapticFeedback = false;
 	let hapticFeedback = false;
 
 
-	let streamResponse = true;
-
 	const toggleSplitLargeChunks = async () => {
 	const toggleSplitLargeChunks = async () => {
 		splitLargeChunks = !splitLargeChunks;
 		splitLargeChunks = !splitLargeChunks;
 		saveSettings({ splitLargeChunks: splitLargeChunks });
 		saveSettings({ splitLargeChunks: splitLargeChunks });
 	};
 	};
 
 
-	const toggleStreamResponse = async () => {
-		streamResponse = !streamResponse;
-		saveSettings({ streamResponse: streamResponse });
-	};
-
 	const togglesScrollOnBranchChange = async () => {
 	const togglesScrollOnBranchChange = async () => {
 		scrollOnBranchChange = !scrollOnBranchChange;
 		scrollOnBranchChange = !scrollOnBranchChange;
 		saveSettings({ scrollOnBranchChange: scrollOnBranchChange });
 		saveSettings({ scrollOnBranchChange: scrollOnBranchChange });
@@ -165,7 +158,6 @@
 		userLocation = $settings.userLocation ?? false;
 		userLocation = $settings.userLocation ?? false;
 
 
 		hapticFeedback = $settings.hapticFeedback ?? false;
 		hapticFeedback = $settings.hapticFeedback ?? false;
-		streamResponse = $settings?.streamResponse ?? true;
 
 
 		defaultModelId = $settings?.models?.at(0) ?? '';
 		defaultModelId = $settings?.models?.at(0) ?? '';
 		if ($config?.default_models) {
 		if ($config?.default_models) {
@@ -319,28 +311,6 @@
 				</div>
 				</div>
 			</div>
 			</div>
 
 
-			<div>
-				<div class=" py-0.5 flex w-full justify-between">
-					<div class=" self-center text-xs">
-						{$i18n.t('Stream Chat Response')}
-					</div>
-
-					<button
-						class="p-1 px-3 text-xs flex rounded transition"
-						on:click={() => {
-							toggleStreamResponse();
-						}}
-						type="button"
-					>
-						{#if streamResponse === true}
-							<span class="ml-2 self-center">{$i18n.t('On')}</span>
-						{:else}
-							<span class="ml-2 self-center">{$i18n.t('Off')}</span>
-						{/if}
-					</button>
-				</div>
-			</div>
-
 			<div>
 			<div>
 				<div class=" py-0.5 flex w-full justify-between">
 				<div class=" py-0.5 flex w-full justify-between">
 					<div class=" self-center text-xs">
 					<div class=" self-center text-xs">

+ 19 - 3
src/lib/components/common/Loader.svelte

@@ -1,16 +1,24 @@
 <script lang="ts">
 <script lang="ts">
-	import { createEventDispatcher, onMount } from 'svelte';
+	import { createEventDispatcher, onDestroy, onMount } from 'svelte';
 	const dispatch = createEventDispatcher();
 	const dispatch = createEventDispatcher();
 
 
 	let loaderElement: HTMLElement;
 	let loaderElement: HTMLElement;
 
 
+	let observer;
+	let intervalId;
+
 	onMount(() => {
 	onMount(() => {
-		const observer = new IntersectionObserver(
+		observer = new IntersectionObserver(
 			(entries, observer) => {
 			(entries, observer) => {
 				entries.forEach((entry) => {
 				entries.forEach((entry) => {
 					if (entry.isIntersecting) {
 					if (entry.isIntersecting) {
-						dispatch('visible');
+						intervalId = setInterval(() => {
+							dispatch('visible');
+						}, 100);
+						// dispatch('visible');
 						// observer.unobserve(loaderElement); // Stop observing until content is loaded
 						// observer.unobserve(loaderElement); // Stop observing until content is loaded
+					} else {
+						clearInterval(intervalId);
 					}
 					}
 				});
 				});
 			},
 			},
@@ -23,6 +31,14 @@
 
 
 		observer.observe(loaderElement);
 		observer.observe(loaderElement);
 	});
 	});
+
+	onDestroy(() => {
+		observer.disconnect();
+
+		if (intervalId) {
+			clearInterval(intervalId);
+		}
+	});
 </script>
 </script>
 
 
 <div bind:this={loaderElement}>
 <div bind:this={loaderElement}>

+ 3 - 1
src/lib/components/common/Tooltip.svelte

@@ -13,6 +13,7 @@
 	export let className = 'flex';
 	export let className = 'flex';
 	export let theme = '';
 	export let theme = '';
 	export let allowHTML = true;
 	export let allowHTML = true;
+	export let tippyOptions = {};
 
 
 	let tooltipElement;
 	let tooltipElement;
 	let tooltipInstance;
 	let tooltipInstance;
@@ -28,7 +29,8 @@
 				touch: touch,
 				touch: touch,
 				...(theme !== '' ? { theme } : { theme: 'dark' }),
 				...(theme !== '' ? { theme } : { theme: 'dark' }),
 				arrow: false,
 				arrow: false,
-				offset: [0, 4]
+				offset: [0, 4],
+				...tippyOptions
 			});
 			});
 		}
 		}
 	} else if (tooltipInstance && content === '') {
 	} else if (tooltipInstance && content === '') {

+ 1 - 1
src/lib/components/layout/Sidebar.svelte

@@ -461,7 +461,7 @@
 				</div>
 				</div>
 			{/if}
 			{/if}
 
 
-			{#if $pinnedChats.length > 0}
+			{#if !search && $pinnedChats.length > 0}
 				<div class="pl-2 py-2 flex flex-col space-y-1">
 				<div class="pl-2 py-2 flex flex-col space-y-1">
 					<div class="">
 					<div class="">
 						<div class="w-full pl-2.5 text-xs text-gray-500 dark:text-gray-500 font-medium pb-1.5">
 						<div class="w-full pl-2.5 text-xs text-gray-500 dark:text-gray-500 font-medium pb-1.5">

+ 17 - 1
src/lib/components/layout/Sidebar/UserMenu.svelte

@@ -5,7 +5,7 @@
 	import { flyAndScale } from '$lib/utils/transitions';
 	import { flyAndScale } from '$lib/utils/transitions';
 	import { goto } from '$app/navigation';
 	import { goto } from '$app/navigation';
 	import ArchiveBox from '$lib/components/icons/ArchiveBox.svelte';
 	import ArchiveBox from '$lib/components/icons/ArchiveBox.svelte';
-	import { showSettings, activeUserCount, USAGE_POOL } from '$lib/stores';
+	import { showSettings, activeUserCount, USAGE_POOL, mobile, showSidebar } from '$lib/stores';
 	import { fade, slide } from 'svelte/transition';
 	import { fade, slide } from 'svelte/transition';
 	import Tooltip from '$lib/components/common/Tooltip.svelte';
 	import Tooltip from '$lib/components/common/Tooltip.svelte';
 
 
@@ -41,6 +41,10 @@
 				on:click={async () => {
 				on:click={async () => {
 					await showSettings.set(true);
 					await showSettings.set(true);
 					show = false;
 					show = false;
+
+					if ($mobile) {
+						showSidebar.set(false);
+					}
 				}}
 				}}
 			>
 			>
 				<div class=" self-center mr-3">
 				<div class=" self-center mr-3">
@@ -72,6 +76,10 @@
 				on:click={() => {
 				on:click={() => {
 					dispatch('show', 'archived-chat');
 					dispatch('show', 'archived-chat');
 					show = false;
 					show = false;
+
+					if ($mobile) {
+						showSidebar.set(false);
+					}
 				}}
 				}}
 			>
 			>
 				<div class=" self-center mr-3">
 				<div class=" self-center mr-3">
@@ -86,6 +94,10 @@
 					on:click={() => {
 					on:click={() => {
 						goto('/playground');
 						goto('/playground');
 						show = false;
 						show = false;
+
+						if ($mobile) {
+							showSidebar.set(false);
+						}
 					}}
 					}}
 				>
 				>
 					<div class=" self-center mr-3">
 					<div class=" self-center mr-3">
@@ -112,6 +124,10 @@
 					on:click={() => {
 					on:click={() => {
 						goto('/admin');
 						goto('/admin');
 						show = false;
 						show = false;
+
+						if ($mobile) {
+							showSidebar.set(false);
+						}
 					}}
 					}}
 				>
 				>
 					<div class=" self-center mr-3">
 					<div class=" self-center mr-3">

+ 44 - 0
src/lib/components/layout/UpdateInfoToast.svelte

@@ -0,0 +1,44 @@
+<script lang="ts">
+	import { getContext, createEventDispatcher } from 'svelte';
+
+	const dispatch = createEventDispatcher();
+	const i18n = getContext('i18n');
+
+	import { WEBUI_VERSION } from '$lib/constants';
+	import XMark from '../icons/XMark.svelte';
+
+	export let version = {
+		current: WEBUI_VERSION,
+		latest: WEBUI_VERSION
+	};
+</script>
+
+<div
+	class="flex items-start bg-[--info-bg] border border-[--info-border] text-[--info-text] rounded-lg px-3.5 py-3 text-xs"
+>
+	<div class="flex-1 font-medium">
+		{$i18n.t(`A new version (v{{LATEST_VERSION}}) is now available.`, {
+			LATEST_VERSION: version.latest
+		})}
+
+		<a
+			href="https://github.com/open-webui/open-webui/releases/tag/v{version.latest}"
+			target="_blank"
+			class="underline"
+		>
+			{$i18n.t('Update for the latest features and improvements.')}</a
+		>
+	</div>
+
+	<div class=" flex-shrink-0 pl-2">
+		<button
+			class=" hover:text-blue-900 dark:hover:text-blue-300 transition"
+			on:click={() => {
+				console.log('closeToast');
+				dispatch('closeToast');
+			}}
+		>
+			<XMark />
+		</button>
+	</div>
+</div>

+ 1 - 1
src/lib/components/workspace/Documents.svelte

@@ -55,7 +55,7 @@
 	const uploadDoc = async (file, tags?: object) => {
 	const uploadDoc = async (file, tags?: object) => {
 		console.log(file);
 		console.log(file);
 		// Check if the file is an audio file and transcribe/convert it to text file
 		// Check if the file is an audio file and transcribe/convert it to text file
-		if (['audio/mpeg', 'audio/wav', 'audio/ogg'].includes(file['type'])) {
+		if (['audio/mpeg', 'audio/wav', 'audio/ogg', 'audio/x-m4a'].includes(file['type'])) {
 			const transcribeRes = await transcribeAudio(localStorage.token, file).catch((error) => {
 			const transcribeRes = await transcribeAudio(localStorage.token, file).catch((error) => {
 				toast.error(error);
 				toast.error(error);
 				return null;
 				return null;

+ 17 - 3
src/lib/components/workspace/Models.svelte

@@ -1,4 +1,6 @@
 <script lang="ts">
 <script lang="ts">
+	import { marked } from 'marked';
+
 	import { toast } from 'svelte-sonner';
 	import { toast } from 'svelte-sonner';
 	import Sortable from 'sortablejs';
 	import Sortable from 'sortablejs';
 
 
@@ -389,9 +391,21 @@
 				<div
 				<div
 					class=" flex-1 self-center {(model?.info?.meta?.hidden ?? false) ? 'text-gray-500' : ''}"
 					class=" flex-1 self-center {(model?.info?.meta?.hidden ?? false) ? 'text-gray-500' : ''}"
 				>
 				>
-					<div class="  font-semibold line-clamp-1">{model.name}</div>
-					<div class=" text-xs overflow-hidden text-ellipsis line-clamp-1">
-						{!!model?.info?.meta?.description ? model?.info?.meta?.description : model.id}
+					<Tooltip
+						content={marked.parse(
+							model?.ollama?.digest
+								? `${model?.ollama?.digest} *(${model?.ollama?.modified_at})*`
+								: ''
+						)}
+						className=" w-fit"
+						placement="top-start"
+					>
+						<div class="  font-semibold line-clamp-1">{model.name}</div>
+					</Tooltip>
+					<div class=" text-xs overflow-hidden text-ellipsis line-clamp-1 text-gray-500">
+						{!!model?.info?.meta?.description
+							? model?.info?.meta?.description
+							: (model?.ollama?.digest ?? model.id)}
 					</div>
 					</div>
 				</div>
 				</div>
 			</a>
 			</a>

+ 3 - 1
src/lib/constants.ts

@@ -31,7 +31,9 @@ export const SUPPORTED_FILE_TYPE = [
 	'application/x-javascript',
 	'application/x-javascript',
 	'text/markdown',
 	'text/markdown',
 	'audio/mpeg',
 	'audio/mpeg',
-	'audio/wav'
+	'audio/wav',
+	'audio/ogg',
+	'audio/x-m4a'
 ];
 ];
 
 
 export const SUPPORTED_FILE_EXTENSIONS = [
 export const SUPPORTED_FILE_EXTENSIONS = [

+ 4 - 0
src/lib/i18n/locales/ar-BH/translation.json

@@ -9,6 +9,7 @@
 	"{{user}}'s Chats": "دردشات {{user}}",
 	"{{user}}'s Chats": "دردشات {{user}}",
 	"{{webUIName}} Backend Required": "{{webUIName}} مطلوب",
 	"{{webUIName}} Backend Required": "{{webUIName}} مطلوب",
 	"*Prompt node ID(s) are required for image generation": "",
 	"*Prompt node ID(s) are required for image generation": "",
+	"A new version (v{{LATEST_VERSION}}) is now available.": "",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "يتم استخدام نموذج المهمة عند تنفيذ مهام مثل إنشاء عناوين للدردشات واستعلامات بحث الويب",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "يتم استخدام نموذج المهمة عند تنفيذ مهام مثل إنشاء عناوين للدردشات واستعلامات بحث الويب",
 	"a user": "مستخدم",
 	"a user": "مستخدم",
 	"About": "عن",
 	"About": "عن",
@@ -465,6 +466,7 @@
 	"Oops! Looks like the URL is invalid. Please double-check and try again.": "خطاء! يبدو أن عنوان URL غير صالح. يرجى التحقق مرة أخرى والمحاولة مرة أخرى.",
 	"Oops! Looks like the URL is invalid. Please double-check and try again.": "خطاء! يبدو أن عنوان URL غير صالح. يرجى التحقق مرة أخرى والمحاولة مرة أخرى.",
 	"Oops! There was an error in the previous response. Please try again or contact admin.": "",
 	"Oops! There was an error in the previous response. Please try again or contact admin.": "",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "خطاء! أنت تستخدم طريقة غير مدعومة (الواجهة الأمامية فقط). يرجى تقديم واجهة WebUI من الواجهة الخلفية.",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "خطاء! أنت تستخدم طريقة غير مدعومة (الواجهة الأمامية فقط). يرجى تقديم واجهة WebUI من الواجهة الخلفية.",
+	"Open file": "",
 	"Open new chat": "فتح محادثة جديده",
 	"Open new chat": "فتح محادثة جديده",
 	"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "",
 	"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "",
 	"OpenAI": "OpenAI",
 	"OpenAI": "OpenAI",
@@ -476,6 +478,7 @@
 	"Other": "آخر",
 	"Other": "آخر",
 	"Output format": "",
 	"Output format": "",
 	"Overview": "",
 	"Overview": "",
+	"page": "",
 	"Password": "الباسورد",
 	"Password": "الباسورد",
 	"PDF document (.pdf)": "PDF ملف (.pdf)",
 	"PDF document (.pdf)": "PDF ملف (.pdf)",
 	"PDF Extract Images (OCR)": "PDF أستخرج الصور (OCR)",
 	"PDF Extract Images (OCR)": "PDF أستخرج الصور (OCR)",
@@ -703,6 +706,7 @@
 	"Unpin": "",
 	"Unpin": "",
 	"Update": "",
 	"Update": "",
 	"Update and Copy Link": "تحديث ونسخ الرابط",
 	"Update and Copy Link": "تحديث ونسخ الرابط",
+	"Update for the latest features and improvements.": "",
 	"Update password": "تحديث كلمة المرور",
 	"Update password": "تحديث كلمة المرور",
 	"Updated at": "",
 	"Updated at": "",
 	"Upload": "",
 	"Upload": "",

+ 4 - 0
src/lib/i18n/locales/bg-BG/translation.json

@@ -9,6 +9,7 @@
 	"{{user}}'s Chats": "{{user}}'s чатове",
 	"{{user}}'s Chats": "{{user}}'s чатове",
 	"{{webUIName}} Backend Required": "{{webUIName}} Изисква се Бекенд",
 	"{{webUIName}} Backend Required": "{{webUIName}} Изисква се Бекенд",
 	"*Prompt node ID(s) are required for image generation": "",
 	"*Prompt node ID(s) are required for image generation": "",
+	"A new version (v{{LATEST_VERSION}}) is now available.": "",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "Моделът на задачите се използва при изпълнение на задачи като генериране на заглавия за чатове и заявки за търсене в мрежата",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "Моделът на задачите се използва при изпълнение на задачи като генериране на заглавия за чатове и заявки за търсене в мрежата",
 	"a user": "потребител",
 	"a user": "потребител",
 	"About": "Относно",
 	"About": "Относно",
@@ -465,6 +466,7 @@
 	"Oops! Looks like the URL is invalid. Please double-check and try again.": "Упс! Изглежда URL адресът е невалиден. Моля, проверете отново и опитайте пак.",
 	"Oops! Looks like the URL is invalid. Please double-check and try again.": "Упс! Изглежда URL адресът е невалиден. Моля, проверете отново и опитайте пак.",
 	"Oops! There was an error in the previous response. Please try again or contact admin.": "",
 	"Oops! There was an error in the previous response. Please try again or contact admin.": "",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "Упс! Използвате неподдържан метод (само фронтенд). Моля, сервирайте WebUI от бекенда.",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "Упс! Използвате неподдържан метод (само фронтенд). Моля, сервирайте WebUI от бекенда.",
+	"Open file": "",
 	"Open new chat": "Отвори нов чат",
 	"Open new chat": "Отвори нов чат",
 	"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "",
 	"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "",
 	"OpenAI": "OpenAI",
 	"OpenAI": "OpenAI",
@@ -476,6 +478,7 @@
 	"Other": "Other",
 	"Other": "Other",
 	"Output format": "",
 	"Output format": "",
 	"Overview": "",
 	"Overview": "",
+	"page": "",
 	"Password": "Парола",
 	"Password": "Парола",
 	"PDF document (.pdf)": "PDF документ (.pdf)",
 	"PDF document (.pdf)": "PDF документ (.pdf)",
 	"PDF Extract Images (OCR)": "PDF Extract Images (OCR)",
 	"PDF Extract Images (OCR)": "PDF Extract Images (OCR)",
@@ -699,6 +702,7 @@
 	"Unpin": "",
 	"Unpin": "",
 	"Update": "",
 	"Update": "",
 	"Update and Copy Link": "Обнови и копирай връзка",
 	"Update and Copy Link": "Обнови и копирай връзка",
+	"Update for the latest features and improvements.": "",
 	"Update password": "Обновяване на парола",
 	"Update password": "Обновяване на парола",
 	"Updated at": "",
 	"Updated at": "",
 	"Upload": "",
 	"Upload": "",

+ 4 - 0
src/lib/i18n/locales/bn-BD/translation.json

@@ -9,6 +9,7 @@
 	"{{user}}'s Chats": "{{user}}র চ্যাটস",
 	"{{user}}'s Chats": "{{user}}র চ্যাটস",
 	"{{webUIName}} Backend Required": "{{webUIName}} ব্যাকএন্ড আবশ্যক",
 	"{{webUIName}} Backend Required": "{{webUIName}} ব্যাকএন্ড আবশ্যক",
 	"*Prompt node ID(s) are required for image generation": "",
 	"*Prompt node ID(s) are required for image generation": "",
+	"A new version (v{{LATEST_VERSION}}) is now available.": "",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "চ্যাট এবং ওয়েব অনুসন্ধান প্রশ্নের জন্য শিরোনাম তৈরি করার মতো কাজগুলি সম্পাদন করার সময় একটি টাস্ক মডেল ব্যবহার করা হয়",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "চ্যাট এবং ওয়েব অনুসন্ধান প্রশ্নের জন্য শিরোনাম তৈরি করার মতো কাজগুলি সম্পাদন করার সময় একটি টাস্ক মডেল ব্যবহার করা হয়",
 	"a user": "একজন ব্যাবহারকারী",
 	"a user": "একজন ব্যাবহারকারী",
 	"About": "সম্পর্কে",
 	"About": "সম্পর্কে",
@@ -465,6 +466,7 @@
 	"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 was an error in the previous response. Please try again or contact admin.": "",
 	"Oops! There was an error in the previous response. Please try again or contact admin.": "",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "আপনি একটা আনসাপোর্টেড পদ্ধতি (শুধু ফ্রন্টএন্ড) ব্যবহার করছেন। দয়া করে WebUI ব্যাকএন্ড থেকে চালনা করুন।",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "আপনি একটা আনসাপোর্টেড পদ্ধতি (শুধু ফ্রন্টএন্ড) ব্যবহার করছেন। দয়া করে WebUI ব্যাকএন্ড থেকে চালনা করুন।",
+	"Open file": "",
 	"Open new chat": "নতুন চ্যাট খুলুন",
 	"Open new chat": "নতুন চ্যাট খুলুন",
 	"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "",
 	"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "",
 	"OpenAI": "OpenAI",
 	"OpenAI": "OpenAI",
@@ -476,6 +478,7 @@
 	"Other": "অন্যান্য",
 	"Other": "অন্যান্য",
 	"Output format": "",
 	"Output format": "",
 	"Overview": "",
 	"Overview": "",
+	"page": "",
 	"Password": "পাসওয়ার্ড",
 	"Password": "পাসওয়ার্ড",
 	"PDF document (.pdf)": "PDF ডকুমেন্ট (.pdf)",
 	"PDF document (.pdf)": "PDF ডকুমেন্ট (.pdf)",
 	"PDF Extract Images (OCR)": "পিডিএফ এর ছবি থেকে লেখা বের করুন (OCR)",
 	"PDF Extract Images (OCR)": "পিডিএফ এর ছবি থেকে লেখা বের করুন (OCR)",
@@ -699,6 +702,7 @@
 	"Unpin": "",
 	"Unpin": "",
 	"Update": "",
 	"Update": "",
 	"Update and Copy Link": "আপডেট এবং লিংক কপি করুন",
 	"Update and Copy Link": "আপডেট এবং লিংক কপি করুন",
+	"Update for the latest features and improvements.": "",
 	"Update password": "পাসওয়ার্ড আপডেট করুন",
 	"Update password": "পাসওয়ার্ড আপডেট করুন",
 	"Updated at": "",
 	"Updated at": "",
 	"Upload": "",
 	"Upload": "",

+ 4 - 0
src/lib/i18n/locales/ca-ES/translation.json

@@ -9,6 +9,7 @@
 	"{{user}}'s Chats": "Els xats de {{user}}",
 	"{{user}}'s Chats": "Els xats de {{user}}",
 	"{{webUIName}} Backend Required": "El Backend de {{webUIName}} és necessari",
 	"{{webUIName}} Backend Required": "El Backend de {{webUIName}} és necessari",
 	"*Prompt node ID(s) are required for image generation": "*Els identificadors de nodes d'indicacions són necessaris per a la generació d'imatges",
 	"*Prompt node ID(s) are required for image generation": "*Els identificadors de nodes d'indicacions són necessaris per a la generació d'imatges",
+	"A new version (v{{LATEST_VERSION}}) is now available.": "",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "Un model de tasca s'utilitza quan es realitzen tasques com ara generar títols per a xats i consultes de cerca per a la web",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "Un model de tasca s'utilitza quan es realitzen tasques com ara generar títols per a xats i consultes de cerca per a la web",
 	"a user": "un usuari",
 	"a user": "un usuari",
 	"About": "Sobre",
 	"About": "Sobre",
@@ -465,6 +466,7 @@
 	"Oops! Looks like the URL is invalid. Please double-check and try again.": "Ui! Sembla que l'URL no és vàlida. Si us plau, revisa-la i torna-ho a provar.",
 	"Oops! Looks like the URL is invalid. Please double-check and try again.": "Ui! Sembla que l'URL no és vàlida. Si us plau, revisa-la i torna-ho a provar.",
 	"Oops! There was an error in the previous response. Please try again or contact admin.": "Ui! Hi ha hagut un error en la resposta anterior. Torna a provar-ho o contacta amb un administrador",
 	"Oops! There was an error in the previous response. Please try again or contact admin.": "Ui! Hi ha hagut un error en la resposta anterior. Torna a provar-ho o contacta amb un administrador",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "Ui! Estàs utilitzant un mètode no suportat (només frontend). Si us plau, serveix la WebUI des del backend.",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "Ui! Estàs utilitzant un mètode no suportat (només frontend). Si us plau, serveix la WebUI des del backend.",
+	"Open file": "",
 	"Open new chat": "Obre un xat nou",
 	"Open new chat": "Obre un xat nou",
 	"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}})",
 	"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": "OpenAI",
@@ -476,6 +478,7 @@
 	"Other": "Altres",
 	"Other": "Altres",
 	"Output format": "Format de sortida",
 	"Output format": "Format de sortida",
 	"Overview": "Vista general",
 	"Overview": "Vista general",
+	"page": "",
 	"Password": "Contrasenya",
 	"Password": "Contrasenya",
 	"PDF document (.pdf)": "Document PDF (.pdf)",
 	"PDF document (.pdf)": "Document PDF (.pdf)",
 	"PDF Extract Images (OCR)": "Extreu imatges del PDF (OCR)",
 	"PDF Extract Images (OCR)": "Extreu imatges del PDF (OCR)",
@@ -700,6 +703,7 @@
 	"Unpin": "Alliberar",
 	"Unpin": "Alliberar",
 	"Update": "Actualitzar",
 	"Update": "Actualitzar",
 	"Update and Copy Link": "Actualitzar i copiar l'enllaç",
 	"Update and Copy Link": "Actualitzar i copiar l'enllaç",
+	"Update for the latest features and improvements.": "",
 	"Update password": "Actualitzar la contrasenya",
 	"Update password": "Actualitzar la contrasenya",
 	"Updated at": "Actualitzat",
 	"Updated at": "Actualitzat",
 	"Upload": "Pujar",
 	"Upload": "Pujar",

+ 4 - 0
src/lib/i18n/locales/ceb-PH/translation.json

@@ -9,6 +9,7 @@
 	"{{user}}'s Chats": "",
 	"{{user}}'s Chats": "",
 	"{{webUIName}} Backend Required": "Backend {{webUIName}} gikinahanglan",
 	"{{webUIName}} Backend Required": "Backend {{webUIName}} gikinahanglan",
 	"*Prompt node ID(s) are required for image generation": "",
 	"*Prompt node ID(s) are required for image generation": "",
+	"A new version (v{{LATEST_VERSION}}) is now available.": "",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "",
 	"a user": "usa ka user",
 	"a user": "usa ka user",
 	"About": "Mahitungod sa",
 	"About": "Mahitungod sa",
@@ -465,6 +466,7 @@
 	"Oops! Looks like the URL is invalid. Please double-check and try again.": "Oops! ",
 	"Oops! Looks like the URL is invalid. Please double-check and try again.": "Oops! ",
 	"Oops! There was an error in the previous response. Please try again or contact admin.": "",
 	"Oops! There was an error in the previous response. Please try again or contact admin.": "",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "Oops! ",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "Oops! ",
+	"Open file": "",
 	"Open new chat": "Ablihi ang bag-ong diskusyon",
 	"Open new chat": "Ablihi ang bag-ong diskusyon",
 	"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "",
 	"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "",
 	"OpenAI": "",
 	"OpenAI": "",
@@ -476,6 +478,7 @@
 	"Other": "",
 	"Other": "",
 	"Output format": "",
 	"Output format": "",
 	"Overview": "",
 	"Overview": "",
+	"page": "",
 	"Password": "Password",
 	"Password": "Password",
 	"PDF document (.pdf)": "",
 	"PDF document (.pdf)": "",
 	"PDF Extract Images (OCR)": "PDF Image Extraction (OCR)",
 	"PDF Extract Images (OCR)": "PDF Image Extraction (OCR)",
@@ -699,6 +702,7 @@
 	"Unpin": "",
 	"Unpin": "",
 	"Update": "",
 	"Update": "",
 	"Update and Copy Link": "",
 	"Update and Copy Link": "",
+	"Update for the latest features and improvements.": "",
 	"Update password": "I-update ang password",
 	"Update password": "I-update ang password",
 	"Updated at": "",
 	"Updated at": "",
 	"Upload": "",
 	"Upload": "",

+ 4 - 0
src/lib/i18n/locales/de-DE/translation.json

@@ -9,6 +9,7 @@
 	"{{user}}'s Chats": "{{user}}s Unterhaltungen",
 	"{{user}}'s Chats": "{{user}}s Unterhaltungen",
 	"{{webUIName}} Backend Required": "{{webUIName}}-Backend erforderlich",
 	"{{webUIName}} Backend Required": "{{webUIName}}-Backend erforderlich",
 	"*Prompt node ID(s) are required for image generation": "",
 	"*Prompt node ID(s) are required for image generation": "",
+	"A new version (v{{LATEST_VERSION}}) is now available.": "",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "Aufgabenmodelle können Unterhaltungstitel oder Websuchanfragen generieren.",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "Aufgabenmodelle können Unterhaltungstitel oder Websuchanfragen generieren.",
 	"a user": "ein Benutzer",
 	"a user": "ein Benutzer",
 	"About": "Über",
 	"About": "Über",
@@ -465,6 +466,7 @@
 	"Oops! Looks like the URL is invalid. Please double-check and try again.": "Hoppla! Es scheint, dass die URL ungültig ist. Bitte überprüfen Sie diese und versuchen Sie es erneut.",
 	"Oops! Looks like the URL is invalid. Please double-check and try again.": "Hoppla! Es scheint, dass die URL ungültig ist. Bitte überprüfen Sie diese und versuchen Sie es erneut.",
 	"Oops! There was an error in the previous response. Please try again or contact admin.": "Hoppla! Es gab einen Fehler in der vorherigen Antwort. Bitte versuchen Sie es erneut oder kontaktieren Sie den Administrator.",
 	"Oops! There was an error in the previous response. Please try again or contact admin.": "Hoppla! Es gab einen Fehler in der vorherigen Antwort. Bitte versuchen Sie es erneut oder kontaktieren Sie den Administrator.",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "Hoppla! Sie verwenden eine nicht unterstützte Methode (nur Frontend). Bitte stellen Sie die WebUI vom Backend bereit.",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "Hoppla! Sie verwenden eine nicht unterstützte Methode (nur Frontend). Bitte stellen Sie die WebUI vom Backend bereit.",
+	"Open file": "Datei öffnen",
 	"Open new chat": "Neuen Chat öffnen",
 	"Open new chat": "Neuen Chat öffnen",
 	"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}})",
 	"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": "OpenAI",
@@ -476,6 +478,7 @@
 	"Other": "Andere",
 	"Other": "Andere",
 	"Output format": "",
 	"Output format": "",
 	"Overview": "",
 	"Overview": "",
+	"page": "Seite",
 	"Password": "Passwort",
 	"Password": "Passwort",
 	"PDF document (.pdf)": "PDF-Dokument (.pdf)",
 	"PDF document (.pdf)": "PDF-Dokument (.pdf)",
 	"PDF Extract Images (OCR)": "Text von Bildern aus PDFs extrahieren (OCR)",
 	"PDF Extract Images (OCR)": "Text von Bildern aus PDFs extrahieren (OCR)",
@@ -699,6 +702,7 @@
 	"Unpin": "Lösen",
 	"Unpin": "Lösen",
 	"Update": "Aktualisieren",
 	"Update": "Aktualisieren",
 	"Update and Copy Link": "Aktualisieren und Link kopieren",
 	"Update and Copy Link": "Aktualisieren und Link kopieren",
+	"Update for the latest features and improvements.": "",
 	"Update password": "Passwort aktualisieren",
 	"Update password": "Passwort aktualisieren",
 	"Updated at": "Aktualisiert am",
 	"Updated at": "Aktualisiert am",
 	"Upload": "Hochladen",
 	"Upload": "Hochladen",

+ 4 - 0
src/lib/i18n/locales/dg-DG/translation.json

@@ -9,6 +9,7 @@
 	"{{user}}'s Chats": "",
 	"{{user}}'s Chats": "",
 	"{{webUIName}} Backend Required": "{{webUIName}} Backend Much Required",
 	"{{webUIName}} Backend Required": "{{webUIName}} Backend Much Required",
 	"*Prompt node ID(s) are required for image generation": "",
 	"*Prompt node ID(s) are required for image generation": "",
+	"A new version (v{{LATEST_VERSION}}) is now available.": "",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "",
 	"a user": "such user",
 	"a user": "such user",
 	"About": "Much About",
 	"About": "Much About",
@@ -465,6 +466,7 @@
 	"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! 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 was an error in the previous response. Please try again or contact admin.": "",
 	"Oops! There was an error in the previous response. Please try again or contact admin.": "",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.",
+	"Open file": "",
 	"Open new chat": "Open new bark",
 	"Open new chat": "Open new bark",
 	"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "",
 	"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "",
 	"OpenAI": "",
 	"OpenAI": "",
@@ -476,6 +478,7 @@
 	"Other": "",
 	"Other": "",
 	"Output format": "",
 	"Output format": "",
 	"Overview": "",
 	"Overview": "",
+	"page": "",
 	"Password": "Barkword",
 	"Password": "Barkword",
 	"PDF document (.pdf)": "",
 	"PDF document (.pdf)": "",
 	"PDF Extract Images (OCR)": "PDF Extract Wowmages (OCR)",
 	"PDF Extract Images (OCR)": "PDF Extract Wowmages (OCR)",
@@ -701,6 +704,7 @@
 	"Unpin": "",
 	"Unpin": "",
 	"Update": "",
 	"Update": "",
 	"Update and Copy Link": "",
 	"Update and Copy Link": "",
+	"Update for the latest features and improvements.": "",
 	"Update password": "Update password much change",
 	"Update password": "Update password much change",
 	"Updated at": "",
 	"Updated at": "",
 	"Upload": "",
 	"Upload": "",

+ 4 - 0
src/lib/i18n/locales/en-GB/translation.json

@@ -9,6 +9,7 @@
 	"{{user}}'s Chats": "",
 	"{{user}}'s Chats": "",
 	"{{webUIName}} Backend Required": "",
 	"{{webUIName}} Backend Required": "",
 	"*Prompt node ID(s) are required for image generation": "",
 	"*Prompt node ID(s) are required for image generation": "",
+	"A new version (v{{LATEST_VERSION}}) is now available.": "",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "",
 	"a user": "",
 	"a user": "",
 	"About": "",
 	"About": "",
@@ -465,6 +466,7 @@
 	"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 was an error in the previous response. Please try again or contact admin.": "",
 	"Oops! There was an error in the previous response. Please try again or contact admin.": "",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "",
+	"Open file": "",
 	"Open new chat": "",
 	"Open new chat": "",
 	"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "",
 	"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "",
 	"OpenAI": "",
 	"OpenAI": "",
@@ -476,6 +478,7 @@
 	"Other": "",
 	"Other": "",
 	"Output format": "",
 	"Output format": "",
 	"Overview": "",
 	"Overview": "",
+	"page": "",
 	"Password": "",
 	"Password": "",
 	"PDF document (.pdf)": "",
 	"PDF document (.pdf)": "",
 	"PDF Extract Images (OCR)": "",
 	"PDF Extract Images (OCR)": "",
@@ -699,6 +702,7 @@
 	"Unpin": "",
 	"Unpin": "",
 	"Update": "",
 	"Update": "",
 	"Update and Copy Link": "",
 	"Update and Copy Link": "",
+	"Update for the latest features and improvements.": "",
 	"Update password": "",
 	"Update password": "",
 	"Updated at": "",
 	"Updated at": "",
 	"Upload": "",
 	"Upload": "",

+ 4 - 0
src/lib/i18n/locales/en-US/translation.json

@@ -9,6 +9,7 @@
 	"{{user}}'s Chats": "",
 	"{{user}}'s Chats": "",
 	"{{webUIName}} Backend Required": "",
 	"{{webUIName}} Backend Required": "",
 	"*Prompt node ID(s) are required for image generation": "",
 	"*Prompt node ID(s) are required for image generation": "",
+	"A new version (v{{LATEST_VERSION}}) is now available.": "",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "",
 	"a user": "",
 	"a user": "",
 	"About": "",
 	"About": "",
@@ -465,6 +466,7 @@
 	"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 was an error in the previous response. Please try again or contact admin.": "",
 	"Oops! There was an error in the previous response. Please try again or contact admin.": "",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "",
+	"Open file": "",
 	"Open new chat": "",
 	"Open new chat": "",
 	"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "",
 	"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "",
 	"OpenAI": "",
 	"OpenAI": "",
@@ -476,6 +478,7 @@
 	"Other": "",
 	"Other": "",
 	"Output format": "",
 	"Output format": "",
 	"Overview": "",
 	"Overview": "",
+	"page": "",
 	"Password": "",
 	"Password": "",
 	"PDF document (.pdf)": "",
 	"PDF document (.pdf)": "",
 	"PDF Extract Images (OCR)": "",
 	"PDF Extract Images (OCR)": "",
@@ -699,6 +702,7 @@
 	"Unpin": "",
 	"Unpin": "",
 	"Update": "",
 	"Update": "",
 	"Update and Copy Link": "",
 	"Update and Copy Link": "",
+	"Update for the latest features and improvements.": "",
 	"Update password": "",
 	"Update password": "",
 	"Updated at": "",
 	"Updated at": "",
 	"Upload": "",
 	"Upload": "",

+ 4 - 0
src/lib/i18n/locales/es-ES/translation.json

@@ -9,6 +9,7 @@
 	"{{user}}'s Chats": "{{user}}'s Chats",
 	"{{user}}'s Chats": "{{user}}'s Chats",
 	"{{webUIName}} Backend Required": "{{webUIName}} Servidor Requerido",
 	"{{webUIName}} Backend Required": "{{webUIName}} Servidor Requerido",
 	"*Prompt node ID(s) are required for image generation": "",
 	"*Prompt node ID(s) are required for image generation": "",
+	"A new version (v{{LATEST_VERSION}}) is now available.": "",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "Un modelo de tareas se utiliza cuando se realizan tareas como la generación de títulos para chats y consultas de búsqueda web",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "Un modelo de tareas se utiliza cuando se realizan tareas como la generación de títulos para chats y consultas de búsqueda web",
 	"a user": "un usuario",
 	"a user": "un usuario",
 	"About": "Sobre nosotros",
 	"About": "Sobre nosotros",
@@ -465,6 +466,7 @@
 	"Oops! Looks like the URL is invalid. Please double-check and try again.": "¡Ups! Parece que la URL no es válida. Vuelva a verificar e inténtelo nuevamente.",
 	"Oops! Looks like the URL is invalid. Please double-check and try again.": "¡Ups! Parece que la URL no es válida. Vuelva a verificar e inténtelo nuevamente.",
 	"Oops! There was an error in the previous response. Please try again or contact admin.": "¡Oops! Hubo un error en la respuesta anterior. Intente de nuevo o póngase en contacto con el administrador.",
 	"Oops! There was an error in the previous response. Please try again or contact admin.": "¡Oops! Hubo un error en la respuesta anterior. Intente de nuevo o póngase en contacto con el administrador.",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "¡Ups! Estás utilizando un método no compatible (solo frontend). Por favor ejecute la WebUI desde el backend.",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "¡Ups! Estás utilizando un método no compatible (solo frontend). Por favor ejecute la WebUI desde el backend.",
+	"Open file": "",
 	"Open new chat": "Abrir nuevo chat",
 	"Open new chat": "Abrir nuevo chat",
 	"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "",
 	"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "",
 	"OpenAI": "OpenAI",
 	"OpenAI": "OpenAI",
@@ -476,6 +478,7 @@
 	"Other": "Otro",
 	"Other": "Otro",
 	"Output format": "",
 	"Output format": "",
 	"Overview": "",
 	"Overview": "",
+	"page": "",
 	"Password": "Contraseña",
 	"Password": "Contraseña",
 	"PDF document (.pdf)": "PDF document (.pdf)",
 	"PDF document (.pdf)": "PDF document (.pdf)",
 	"PDF Extract Images (OCR)": "Extraer imágenes de PDF (OCR)",
 	"PDF Extract Images (OCR)": "Extraer imágenes de PDF (OCR)",
@@ -700,6 +703,7 @@
 	"Unpin": "",
 	"Unpin": "",
 	"Update": "Actualizar",
 	"Update": "Actualizar",
 	"Update and Copy Link": "Actualizar y copiar enlace",
 	"Update and Copy Link": "Actualizar y copiar enlace",
+	"Update for the latest features and improvements.": "",
 	"Update password": "Actualizar contraseña",
 	"Update password": "Actualizar contraseña",
 	"Updated at": "Actualizado en",
 	"Updated at": "Actualizado en",
 	"Upload": "Subir",
 	"Upload": "Subir",

+ 4 - 0
src/lib/i18n/locales/fa-IR/translation.json

@@ -9,6 +9,7 @@
 	"{{user}}'s Chats": "{{user}} چت ها",
 	"{{user}}'s Chats": "{{user}} چت ها",
 	"{{webUIName}} Backend Required": "بکند {{webUIName}} نیاز است.",
 	"{{webUIName}} Backend Required": "بکند {{webUIName}} نیاز است.",
 	"*Prompt node ID(s) are required for image generation": "",
 	"*Prompt node ID(s) are required for image generation": "",
+	"A new version (v{{LATEST_VERSION}}) is now available.": "",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "یک مدل وظیفه هنگام انجام وظایف مانند تولید عناوین برای چت ها و نمایش های جستجوی وب استفاده می شود.",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "یک مدل وظیفه هنگام انجام وظایف مانند تولید عناوین برای چت ها و نمایش های جستجوی وب استفاده می شود.",
 	"a user": "یک کاربر",
 	"a user": "یک کاربر",
 	"About": "درباره",
 	"About": "درباره",
@@ -465,6 +466,7 @@
 	"Oops! Looks like the URL is invalid. Please double-check and try again.": "اوه! به نظر می رسد URL نامعتبر است. لطفاً دوباره بررسی کنید و دوباره امتحان کنید.",
 	"Oops! Looks like the URL is invalid. Please double-check and try again.": "اوه! به نظر می رسد URL نامعتبر است. لطفاً دوباره بررسی کنید و دوباره امتحان کنید.",
 	"Oops! There was an error in the previous response. Please try again or contact admin.": "",
 	"Oops! There was an error in the previous response. Please try again or contact admin.": "",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "اوه! شما از یک روش پشتیبانی نشده (فقط frontend) استفاده می کنید. لطفاً WebUI را از بکند اجرا کنید.",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "اوه! شما از یک روش پشتیبانی نشده (فقط frontend) استفاده می کنید. لطفاً WebUI را از بکند اجرا کنید.",
+	"Open file": "",
 	"Open new chat": "باز کردن گپ جدید",
 	"Open new chat": "باز کردن گپ جدید",
 	"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "",
 	"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "",
 	"OpenAI": "OpenAI",
 	"OpenAI": "OpenAI",
@@ -476,6 +478,7 @@
 	"Other": "دیگر",
 	"Other": "دیگر",
 	"Output format": "",
 	"Output format": "",
 	"Overview": "",
 	"Overview": "",
+	"page": "",
 	"Password": "رمز عبور",
 	"Password": "رمز عبور",
 	"PDF document (.pdf)": "PDF سند (.pdf)",
 	"PDF document (.pdf)": "PDF سند (.pdf)",
 	"PDF Extract Images (OCR)": "استخراج تصاویر از PDF (OCR)",
 	"PDF Extract Images (OCR)": "استخراج تصاویر از PDF (OCR)",
@@ -699,6 +702,7 @@
 	"Unpin": "",
 	"Unpin": "",
 	"Update": "",
 	"Update": "",
 	"Update and Copy Link": "به روزرسانی و کپی لینک",
 	"Update and Copy Link": "به روزرسانی و کپی لینک",
+	"Update for the latest features and improvements.": "",
 	"Update password": "به روزرسانی رمزعبور",
 	"Update password": "به روزرسانی رمزعبور",
 	"Updated at": "",
 	"Updated at": "",
 	"Upload": "",
 	"Upload": "",

+ 4 - 0
src/lib/i18n/locales/fi-FI/translation.json

@@ -9,6 +9,7 @@
 	"{{user}}'s Chats": "{{user}}:n keskustelut",
 	"{{user}}'s Chats": "{{user}}:n keskustelut",
 	"{{webUIName}} Backend Required": "{{webUIName}} backend vaaditaan",
 	"{{webUIName}} Backend Required": "{{webUIName}} backend vaaditaan",
 	"*Prompt node ID(s) are required for image generation": "",
 	"*Prompt node ID(s) are required for image generation": "",
+	"A new version (v{{LATEST_VERSION}}) is now available.": "",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "Tehtävämallia käytetään tehtävien suorittamiseen, kuten otsikoiden luomiseen keskusteluille ja verkkohakukyselyille",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "Tehtävämallia käytetään tehtävien suorittamiseen, kuten otsikoiden luomiseen keskusteluille ja verkkohakukyselyille",
 	"a user": "käyttäjä",
 	"a user": "käyttäjä",
 	"About": "Tietoja",
 	"About": "Tietoja",
@@ -465,6 +466,7 @@
 	"Oops! Looks like the URL is invalid. Please double-check and try again.": "Hups! Näyttää siltä, että URL on virheellinen. Tarkista se ja yritä uudelleen.",
 	"Oops! Looks like the URL is invalid. Please double-check and try again.": "Hups! Näyttää siltä, että URL on virheellinen. Tarkista se ja yritä uudelleen.",
 	"Oops! There was an error in the previous response. Please try again or contact admin.": "",
 	"Oops! There was an error in the previous response. Please try again or contact admin.": "",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "Hupsista! Käytät ei-tuettua menetelmää. WebUI pitää palvella backendista.",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "Hupsista! Käytät ei-tuettua menetelmää. WebUI pitää palvella backendista.",
+	"Open file": "",
 	"Open new chat": "Avaa uusi keskustelu",
 	"Open new chat": "Avaa uusi keskustelu",
 	"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "",
 	"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "",
 	"OpenAI": "OpenAI",
 	"OpenAI": "OpenAI",
@@ -476,6 +478,7 @@
 	"Other": "Muu",
 	"Other": "Muu",
 	"Output format": "",
 	"Output format": "",
 	"Overview": "",
 	"Overview": "",
+	"page": "",
 	"Password": "Salasana",
 	"Password": "Salasana",
 	"PDF document (.pdf)": "PDF-tiedosto (.pdf)",
 	"PDF document (.pdf)": "PDF-tiedosto (.pdf)",
 	"PDF Extract Images (OCR)": "PDF-tiedoston kuvien erottelu (OCR)",
 	"PDF Extract Images (OCR)": "PDF-tiedoston kuvien erottelu (OCR)",
@@ -699,6 +702,7 @@
 	"Unpin": "",
 	"Unpin": "",
 	"Update": "",
 	"Update": "",
 	"Update and Copy Link": "Päivitä ja kopioi linkki",
 	"Update and Copy Link": "Päivitä ja kopioi linkki",
+	"Update for the latest features and improvements.": "",
 	"Update password": "Päivitä salasana",
 	"Update password": "Päivitä salasana",
 	"Updated at": "",
 	"Updated at": "",
 	"Upload": "",
 	"Upload": "",

+ 4 - 0
src/lib/i18n/locales/fr-CA/translation.json

@@ -9,6 +9,7 @@
 	"{{user}}'s Chats": "Discussions de {{user}}",
 	"{{user}}'s Chats": "Discussions de {{user}}",
 	"{{webUIName}} Backend Required": "Backend {{webUIName}} requis",
 	"{{webUIName}} Backend Required": "Backend {{webUIName}} requis",
 	"*Prompt node ID(s) are required for image generation": "",
 	"*Prompt node ID(s) are required for image generation": "",
+	"A new version (v{{LATEST_VERSION}}) is now available.": "",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "Un modèle de tâche est utilisé lors de l’exécution de tâches telles que la génération de titres pour les conversations et les requêtes de recherche sur le web.",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "Un modèle de tâche est utilisé lors de l’exécution de tâches telles que la génération de titres pour les conversations et les requêtes de recherche sur le web.",
 	"a user": "un utilisateur",
 	"a user": "un utilisateur",
 	"About": "À propos",
 	"About": "À propos",
@@ -465,6 +466,7 @@
 	"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! 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 was an error in the previous response. Please try again or contact admin.": "Oops ! Il y a eu une erreur dans la réponse précédente. Veuillez réessayer ou contacter l'administrateur.",
 	"Oops! There was an error in the previous response. Please try again or contact admin.": "Oops ! Il y a eu une erreur dans la réponse précédente. Veuillez réessayer ou contacter l'administrateur.",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "Oups\u00a0! Vous utilisez une méthode non prise en charge (frontend uniquement). Veuillez servir l'interface Web à partir du backend.",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "Oups\u00a0! Vous utilisez une méthode non prise en charge (frontend uniquement). Veuillez servir l'interface Web à partir du backend.",
+	"Open file": "",
 	"Open new chat": "Ouvrir une nouvelle discussion",
 	"Open new chat": "Ouvrir une nouvelle discussion",
 	"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "",
 	"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "",
 	"OpenAI": "OpenAI",
 	"OpenAI": "OpenAI",
@@ -476,6 +478,7 @@
 	"Other": "Autre",
 	"Other": "Autre",
 	"Output format": "",
 	"Output format": "",
 	"Overview": "",
 	"Overview": "",
+	"page": "",
 	"Password": "Mot de passe",
 	"Password": "Mot de passe",
 	"PDF document (.pdf)": "Document au format PDF  (.pdf)",
 	"PDF document (.pdf)": "Document au format PDF  (.pdf)",
 	"PDF Extract Images (OCR)": "Extraction d'images PDF (OCR)",
 	"PDF Extract Images (OCR)": "Extraction d'images PDF (OCR)",
@@ -700,6 +703,7 @@
 	"Unpin": "",
 	"Unpin": "",
 	"Update": "Mise à jour",
 	"Update": "Mise à jour",
 	"Update and Copy Link": "Mettre à jour et copier le lien",
 	"Update and Copy Link": "Mettre à jour et copier le lien",
+	"Update for the latest features and improvements.": "",
 	"Update password": "Mettre à jour le mot de passe",
 	"Update password": "Mettre à jour le mot de passe",
 	"Updated at": "Mise à jour le",
 	"Updated at": "Mise à jour le",
 	"Upload": "Télécharger",
 	"Upload": "Télécharger",

+ 4 - 0
src/lib/i18n/locales/fr-FR/translation.json

@@ -9,6 +9,7 @@
 	"{{user}}'s Chats": "Conversations de {{user}}",
 	"{{user}}'s Chats": "Conversations de {{user}}",
 	"{{webUIName}} Backend Required": "Backend {{webUIName}} requis",
 	"{{webUIName}} Backend Required": "Backend {{webUIName}} requis",
 	"*Prompt node ID(s) are required for image generation": "*Les ID de noeud du prompt sont nécessaires pour la génération d’images",
 	"*Prompt node ID(s) are required for image generation": "*Les ID de noeud du prompt sont nécessaires pour la génération d’images",
+	"A new version (v{{LATEST_VERSION}}) is now available.": "",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "Un modèle de tâche est utilisé lors de l’exécution de tâches telles que la génération de titres pour les conversations et les requêtes de recherche sur le web.",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "Un modèle de tâche est utilisé lors de l’exécution de tâches telles que la génération de titres pour les conversations et les requêtes de recherche sur le web.",
 	"a user": "un utilisateur",
 	"a user": "un utilisateur",
 	"About": "À propos",
 	"About": "À propos",
@@ -465,6 +466,7 @@
 	"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! 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 was an error in the previous response. Please try again or contact admin.": "Oops ! Il y a eu une erreur dans la réponse précédente. Veuillez réessayer ou contacter l'administrateur.",
 	"Oops! There was an error in the previous response. Please try again or contact admin.": "Oops ! Il y a eu une erreur dans la réponse précédente. Veuillez réessayer ou contacter l'administrateur.",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "Oups\u00a0! Vous utilisez une méthode non prise en charge (frontend uniquement). Veuillez servir l'interface Web à partir du backend.",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "Oups\u00a0! Vous utilisez une méthode non prise en charge (frontend uniquement). Veuillez servir l'interface Web à partir du backend.",
+	"Open file": "",
 	"Open new chat": "Ouvrir une nouvelle conversation",
 	"Open new chat": "Ouvrir une nouvelle conversation",
 	"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}})",
 	"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": "OpenAI",
@@ -476,6 +478,7 @@
 	"Other": "Autre",
 	"Other": "Autre",
 	"Output format": "",
 	"Output format": "",
 	"Overview": "",
 	"Overview": "",
+	"page": "",
 	"Password": "Mot de passe",
 	"Password": "Mot de passe",
 	"PDF document (.pdf)": "Document au format PDF  (.pdf)",
 	"PDF document (.pdf)": "Document au format PDF  (.pdf)",
 	"PDF Extract Images (OCR)": "Extraction d'images PDF (OCR)",
 	"PDF Extract Images (OCR)": "Extraction d'images PDF (OCR)",
@@ -700,6 +703,7 @@
 	"Unpin": "Désépingler",
 	"Unpin": "Désépingler",
 	"Update": "Mise à jour",
 	"Update": "Mise à jour",
 	"Update and Copy Link": "Mettre à jour et copier le lien",
 	"Update and Copy Link": "Mettre à jour et copier le lien",
+	"Update for the latest features and improvements.": "",
 	"Update password": "Mettre à jour le mot de passe",
 	"Update password": "Mettre à jour le mot de passe",
 	"Updated at": "Mise à jour le",
 	"Updated at": "Mise à jour le",
 	"Upload": "Télécharger",
 	"Upload": "Télécharger",

+ 4 - 0
src/lib/i18n/locales/he-IL/translation.json

@@ -9,6 +9,7 @@
 	"{{user}}'s Chats": "צ'אטים של {{user}}",
 	"{{user}}'s Chats": "צ'אטים של {{user}}",
 	"{{webUIName}} Backend Required": "נדרש Backend של {{webUIName}}",
 	"{{webUIName}} Backend Required": "נדרש Backend של {{webUIName}}",
 	"*Prompt node ID(s) are required for image generation": "",
 	"*Prompt node ID(s) are required for image generation": "",
+	"A new version (v{{LATEST_VERSION}}) is now available.": "",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "מודל משימה משמש בעת ביצוע משימות כגון יצירת כותרות עבור צ'אטים ושאילתות חיפוש באינטרנט",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "מודל משימה משמש בעת ביצוע משימות כגון יצירת כותרות עבור צ'אטים ושאילתות חיפוש באינטרנט",
 	"a user": "משתמש",
 	"a user": "משתמש",
 	"About": "אודות",
 	"About": "אודות",
@@ -465,6 +466,7 @@
 	"Oops! Looks like the URL is invalid. Please double-check and try again.": "אופס! נראה שהכתובת URL אינה תקינה. אנא בדוק שוב ונסה שנית.",
 	"Oops! Looks like the URL is invalid. Please double-check and try again.": "אופס! נראה שהכתובת URL אינה תקינה. אנא בדוק שוב ונסה שנית.",
 	"Oops! There was an error in the previous response. Please try again or contact admin.": "",
 	"Oops! There was an error in the previous response. Please try again or contact admin.": "",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "אופס! אתה משתמש בשיטה לא נתמכת (רק חזית). אנא שרת את ממשק המשתמש האינטרנטי מהשרת האחורי.",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "אופס! אתה משתמש בשיטה לא נתמכת (רק חזית). אנא שרת את ממשק המשתמש האינטרנטי מהשרת האחורי.",
+	"Open file": "",
 	"Open new chat": "פתח צ'אט חדש",
 	"Open new chat": "פתח צ'אט חדש",
 	"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "",
 	"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "",
 	"OpenAI": "OpenAI",
 	"OpenAI": "OpenAI",
@@ -476,6 +478,7 @@
 	"Other": "אחר",
 	"Other": "אחר",
 	"Output format": "",
 	"Output format": "",
 	"Overview": "",
 	"Overview": "",
+	"page": "",
 	"Password": "סיסמה",
 	"Password": "סיסמה",
 	"PDF document (.pdf)": "מסמך PDF (.pdf)",
 	"PDF document (.pdf)": "מסמך PDF (.pdf)",
 	"PDF Extract Images (OCR)": "חילוץ תמונות מ-PDF (OCR)",
 	"PDF Extract Images (OCR)": "חילוץ תמונות מ-PDF (OCR)",
@@ -700,6 +703,7 @@
 	"Unpin": "",
 	"Unpin": "",
 	"Update": "",
 	"Update": "",
 	"Update and Copy Link": "עדכן ושכפל קישור",
 	"Update and Copy Link": "עדכן ושכפל קישור",
+	"Update for the latest features and improvements.": "",
 	"Update password": "עדכן סיסמה",
 	"Update password": "עדכן סיסמה",
 	"Updated at": "",
 	"Updated at": "",
 	"Upload": "",
 	"Upload": "",

+ 4 - 0
src/lib/i18n/locales/hi-IN/translation.json

@@ -9,6 +9,7 @@
 	"{{user}}'s Chats": "{{user}} की चैट",
 	"{{user}}'s Chats": "{{user}} की चैट",
 	"{{webUIName}} Backend Required": "{{webUIName}} बैकएंड आवश्यक",
 	"{{webUIName}} Backend Required": "{{webUIName}} बैकएंड आवश्यक",
 	"*Prompt node ID(s) are required for image generation": "",
 	"*Prompt node ID(s) are required for image generation": "",
+	"A new version (v{{LATEST_VERSION}}) is now available.": "",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "चैट और वेब खोज क्वेरी के लिए शीर्षक उत्पन्न करने जैसे कार्य करते समय कार्य मॉडल का उपयोग किया जाता है",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "चैट और वेब खोज क्वेरी के लिए शीर्षक उत्पन्न करने जैसे कार्य करते समय कार्य मॉडल का उपयोग किया जाता है",
 	"a user": "एक उपयोगकर्ता",
 	"a user": "एक उपयोगकर्ता",
 	"About": "हमारे बारे में",
 	"About": "हमारे बारे में",
@@ -465,6 +466,7 @@
 	"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 was an error in the previous response. Please try again or contact admin.": "",
 	"Oops! There was an error in the previous response. Please try again or contact admin.": "",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "उफ़! आप एक असमर्थित विधि (केवल फ्रंटएंड) का उपयोग कर रहे हैं। कृपया बैकएंड से WebUI सर्वे करें।",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "उफ़! आप एक असमर्थित विधि (केवल फ्रंटएंड) का उपयोग कर रहे हैं। कृपया बैकएंड से WebUI सर्वे करें।",
+	"Open file": "",
 	"Open new chat": "नई चैट खोलें",
 	"Open new chat": "नई चैट खोलें",
 	"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "",
 	"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "",
 	"OpenAI": "OpenAI",
 	"OpenAI": "OpenAI",
@@ -476,6 +478,7 @@
 	"Other": "अन्य",
 	"Other": "अन्य",
 	"Output format": "",
 	"Output format": "",
 	"Overview": "",
 	"Overview": "",
+	"page": "",
 	"Password": "पासवर्ड",
 	"Password": "पासवर्ड",
 	"PDF document (.pdf)": "PDF दस्तावेज़ (.pdf)",
 	"PDF document (.pdf)": "PDF दस्तावेज़ (.pdf)",
 	"PDF Extract Images (OCR)": "PDF छवियाँ निकालें (OCR)",
 	"PDF Extract Images (OCR)": "PDF छवियाँ निकालें (OCR)",
@@ -699,6 +702,7 @@
 	"Unpin": "",
 	"Unpin": "",
 	"Update": "",
 	"Update": "",
 	"Update and Copy Link": "अपडेट करें और लिंक कॉपी करें",
 	"Update and Copy Link": "अपडेट करें और लिंक कॉपी करें",
+	"Update for the latest features and improvements.": "",
 	"Update password": "पासवर्ड अपडेट करें",
 	"Update password": "पासवर्ड अपडेट करें",
 	"Updated at": "",
 	"Updated at": "",
 	"Upload": "",
 	"Upload": "",

+ 4 - 0
src/lib/i18n/locales/hr-HR/translation.json

@@ -9,6 +9,7 @@
 	"{{user}}'s Chats": "Razgovori korisnika {{user}}",
 	"{{user}}'s Chats": "Razgovori korisnika {{user}}",
 	"{{webUIName}} Backend Required": "{{webUIName}} Backend je potreban",
 	"{{webUIName}} Backend Required": "{{webUIName}} Backend je potreban",
 	"*Prompt node ID(s) are required for image generation": "",
 	"*Prompt node ID(s) are required for image generation": "",
+	"A new version (v{{LATEST_VERSION}}) is now available.": "",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "Model zadatka koristi se pri izvođenju zadataka kao što su generiranje naslova za razgovore i upite za pretraživanje weba",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "Model zadatka koristi se pri izvođenju zadataka kao što su generiranje naslova za razgovore i upite za pretraživanje weba",
 	"a user": "korisnik",
 	"a user": "korisnik",
 	"About": "O aplikaciji",
 	"About": "O aplikaciji",
@@ -465,6 +466,7 @@
 	"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! 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 was an error in the previous response. Please try again or contact admin.": "",
 	"Oops! There was an error in the previous response. Please try again or contact admin.": "",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "Ups! Koristite nepodržanu metodu (samo frontend). Molimo poslužite WebUI s backend-a.",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "Ups! Koristite nepodržanu metodu (samo frontend). Molimo poslužite WebUI s backend-a.",
+	"Open file": "",
 	"Open new chat": "Otvorite novi razgovor",
 	"Open new chat": "Otvorite novi razgovor",
 	"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "",
 	"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "",
 	"OpenAI": "OpenAI",
 	"OpenAI": "OpenAI",
@@ -476,6 +478,7 @@
 	"Other": "Ostalo",
 	"Other": "Ostalo",
 	"Output format": "",
 	"Output format": "",
 	"Overview": "",
 	"Overview": "",
+	"page": "",
 	"Password": "Lozinka",
 	"Password": "Lozinka",
 	"PDF document (.pdf)": "PDF dokument (.pdf)",
 	"PDF document (.pdf)": "PDF dokument (.pdf)",
 	"PDF Extract Images (OCR)": "PDF izdvajanje slika (OCR)",
 	"PDF Extract Images (OCR)": "PDF izdvajanje slika (OCR)",
@@ -700,6 +703,7 @@
 	"Unpin": "",
 	"Unpin": "",
 	"Update": "",
 	"Update": "",
 	"Update and Copy Link": "Ažuriraj i kopiraj vezu",
 	"Update and Copy Link": "Ažuriraj i kopiraj vezu",
+	"Update for the latest features and improvements.": "",
 	"Update password": "Ažuriraj lozinku",
 	"Update password": "Ažuriraj lozinku",
 	"Updated at": "",
 	"Updated at": "",
 	"Upload": "",
 	"Upload": "",

+ 4 - 0
src/lib/i18n/locales/id-ID/translation.json

@@ -9,6 +9,7 @@
 	"{{user}}'s Chats": "Obrolan {{user}}",
 	"{{user}}'s Chats": "Obrolan {{user}}",
 	"{{webUIName}} Backend Required": "{{webUIName}} Diperlukan Backend",
 	"{{webUIName}} Backend Required": "{{webUIName}} Diperlukan Backend",
 	"*Prompt node ID(s) are required for image generation": "",
 	"*Prompt node ID(s) are required for image generation": "",
+	"A new version (v{{LATEST_VERSION}}) is now available.": "",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "Model tugas digunakan saat melakukan tugas seperti membuat judul untuk obrolan dan kueri penelusuran web",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "Model tugas digunakan saat melakukan tugas seperti membuat judul untuk obrolan dan kueri penelusuran web",
 	"a user": "seorang pengguna",
 	"a user": "seorang pengguna",
 	"About": "Tentang",
 	"About": "Tentang",
@@ -465,6 +466,7 @@
 	"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! 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 was an error in the previous response. Please try again or contact admin.": "Ups! Ada kesalahan pada respons sebelumnya. Silakan coba lagi atau hubungi admin.",
 	"Oops! There was an error in the previous response. Please try again or contact admin.": "Ups! Ada kesalahan pada respons sebelumnya. Silakan coba lagi atau hubungi admin.",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "Ups! Anda menggunakan metode yang tidak didukung (hanya untuk frontend). Silakan sajikan WebUI dari backend.",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "Ups! Anda menggunakan metode yang tidak didukung (hanya untuk frontend). Silakan sajikan WebUI dari backend.",
+	"Open file": "",
 	"Open new chat": "Buka obrolan baru",
 	"Open new chat": "Buka obrolan baru",
 	"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "",
 	"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "",
 	"OpenAI": "OpenAI",
 	"OpenAI": "OpenAI",
@@ -476,6 +478,7 @@
 	"Other": "Lainnya",
 	"Other": "Lainnya",
 	"Output format": "",
 	"Output format": "",
 	"Overview": "",
 	"Overview": "",
+	"page": "",
 	"Password": "Kata sandi",
 	"Password": "Kata sandi",
 	"PDF document (.pdf)": "Dokumen PDF (.pdf)",
 	"PDF document (.pdf)": "Dokumen PDF (.pdf)",
 	"PDF Extract Images (OCR)": "Ekstrak Gambar PDF (OCR)",
 	"PDF Extract Images (OCR)": "Ekstrak Gambar PDF (OCR)",
@@ -699,6 +702,7 @@
 	"Unpin": "",
 	"Unpin": "",
 	"Update": "Memperbarui",
 	"Update": "Memperbarui",
 	"Update and Copy Link": "Perbarui dan Salin Tautan",
 	"Update and Copy Link": "Perbarui dan Salin Tautan",
+	"Update for the latest features and improvements.": "",
 	"Update password": "Perbarui kata sandi",
 	"Update password": "Perbarui kata sandi",
 	"Updated at": "Diperbarui di",
 	"Updated at": "Diperbarui di",
 	"Upload": "Unggah",
 	"Upload": "Unggah",

+ 4 - 0
src/lib/i18n/locales/it-IT/translation.json

@@ -9,6 +9,7 @@
 	"{{user}}'s Chats": "{{user}} Chat",
 	"{{user}}'s Chats": "{{user}} Chat",
 	"{{webUIName}} Backend Required": "{{webUIName}} Backend richiesto",
 	"{{webUIName}} Backend Required": "{{webUIName}} Backend richiesto",
 	"*Prompt node ID(s) are required for image generation": "",
 	"*Prompt node ID(s) are required for image generation": "",
+	"A new version (v{{LATEST_VERSION}}) is now available.": "",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "Un modello di attività viene utilizzato durante l'esecuzione di attività come la generazione di titoli per chat e query di ricerca Web",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "Un modello di attività viene utilizzato durante l'esecuzione di attività come la generazione di titoli per chat e query di ricerca Web",
 	"a user": "un utente",
 	"a user": "un utente",
 	"About": "Informazioni",
 	"About": "Informazioni",
@@ -465,6 +466,7 @@
 	"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! 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 was an error in the previous response. Please try again or contact admin.": "",
 	"Oops! There was an error in the previous response. Please try again or contact admin.": "",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "Ops! Stai utilizzando un metodo non supportato (solo frontend). Si prega di servire la WebUI dal backend.",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "Ops! Stai utilizzando un metodo non supportato (solo frontend). Si prega di servire la WebUI dal backend.",
+	"Open file": "",
 	"Open new chat": "Apri nuova chat",
 	"Open new chat": "Apri nuova chat",
 	"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "",
 	"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "",
 	"OpenAI": "OpenAI",
 	"OpenAI": "OpenAI",
@@ -476,6 +478,7 @@
 	"Other": "Altro",
 	"Other": "Altro",
 	"Output format": "",
 	"Output format": "",
 	"Overview": "",
 	"Overview": "",
+	"page": "",
 	"Password": "Password",
 	"Password": "Password",
 	"PDF document (.pdf)": "Documento PDF (.pdf)",
 	"PDF document (.pdf)": "Documento PDF (.pdf)",
 	"PDF Extract Images (OCR)": "Estrazione immagini PDF (OCR)",
 	"PDF Extract Images (OCR)": "Estrazione immagini PDF (OCR)",
@@ -700,6 +703,7 @@
 	"Unpin": "",
 	"Unpin": "",
 	"Update": "",
 	"Update": "",
 	"Update and Copy Link": "Aggiorna e copia link",
 	"Update and Copy Link": "Aggiorna e copia link",
+	"Update for the latest features and improvements.": "",
 	"Update password": "Aggiorna password",
 	"Update password": "Aggiorna password",
 	"Updated at": "",
 	"Updated at": "",
 	"Upload": "",
 	"Upload": "",

+ 4 - 0
src/lib/i18n/locales/ja-JP/translation.json

@@ -9,6 +9,7 @@
 	"{{user}}'s Chats": "{{user}} のチャット",
 	"{{user}}'s Chats": "{{user}} のチャット",
 	"{{webUIName}} Backend Required": "{{webUIName}} バックエンドが必要です",
 	"{{webUIName}} Backend Required": "{{webUIName}} バックエンドが必要です",
 	"*Prompt node ID(s) are required for image generation": "",
 	"*Prompt node ID(s) are required for image generation": "",
+	"A new version (v{{LATEST_VERSION}}) is now available.": "",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "タスクモデルは、チャットやWeb検索クエリのタイトルの生成などのタスクを実行するときに使用されます",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "タスクモデルは、チャットやWeb検索クエリのタイトルの生成などのタスクを実行するときに使用されます",
 	"a user": "ユーザー",
 	"a user": "ユーザー",
 	"About": "概要",
 	"About": "概要",
@@ -465,6 +466,7 @@
 	"Oops! Looks like the URL is invalid. Please double-check and try again.": "おっと! URL が無効なようです。もう一度確認してやり直してください。",
 	"Oops! Looks like the URL is invalid. Please double-check and try again.": "おっと! URL が無効なようです。もう一度確認してやり直してください。",
 	"Oops! There was an error in the previous response. Please try again or contact admin.": "",
 	"Oops! There was an error in the previous response. Please try again or contact admin.": "",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "おっと! サポートされていない方法 (フロントエンドのみ) を使用しています。バックエンドから WebUI を提供してください。",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "おっと! サポートされていない方法 (フロントエンドのみ) を使用しています。バックエンドから WebUI を提供してください。",
+	"Open file": "",
 	"Open new chat": "新しいチャットを開く",
 	"Open new chat": "新しいチャットを開く",
 	"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "",
 	"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "",
 	"OpenAI": "OpenAI",
 	"OpenAI": "OpenAI",
@@ -476,6 +478,7 @@
 	"Other": "その他",
 	"Other": "その他",
 	"Output format": "",
 	"Output format": "",
 	"Overview": "",
 	"Overview": "",
+	"page": "",
 	"Password": "パスワード",
 	"Password": "パスワード",
 	"PDF document (.pdf)": "PDF ドキュメント (.pdf)",
 	"PDF document (.pdf)": "PDF ドキュメント (.pdf)",
 	"PDF Extract Images (OCR)": "PDF 画像抽出 (OCR)",
 	"PDF Extract Images (OCR)": "PDF 画像抽出 (OCR)",
@@ -698,6 +701,7 @@
 	"Unpin": "",
 	"Unpin": "",
 	"Update": "",
 	"Update": "",
 	"Update and Copy Link": "リンクの更新とコピー",
 	"Update and Copy Link": "リンクの更新とコピー",
+	"Update for the latest features and improvements.": "",
 	"Update password": "パスワードを更新",
 	"Update password": "パスワードを更新",
 	"Updated at": "",
 	"Updated at": "",
 	"Upload": "",
 	"Upload": "",

+ 4 - 0
src/lib/i18n/locales/ka-GE/translation.json

@@ -9,6 +9,7 @@
 	"{{user}}'s Chats": "{{user}}-ის ჩათები",
 	"{{user}}'s Chats": "{{user}}-ის ჩათები",
 	"{{webUIName}} Backend Required": "{{webUIName}} საჭიროა ბექენდი",
 	"{{webUIName}} Backend Required": "{{webUIName}} საჭიროა ბექენდი",
 	"*Prompt node ID(s) are required for image generation": "",
 	"*Prompt node ID(s) are required for image generation": "",
+	"A new version (v{{LATEST_VERSION}}) is now available.": "",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "დავალების მოდელი გამოიყენება ისეთი ამოცანების შესრულებისას, როგორიცაა ჩეთების სათაურების გენერირება და ვებ – ძიების მოთხოვნები",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "დავალების მოდელი გამოიყენება ისეთი ამოცანების შესრულებისას, როგორიცაა ჩეთების სათაურების გენერირება და ვებ – ძიების მოთხოვნები",
 	"a user": "მომხმარებელი",
 	"a user": "მომხმარებელი",
 	"About": "შესახებ",
 	"About": "შესახებ",
@@ -465,6 +466,7 @@
 	"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 was an error in the previous response. Please try again or contact admin.": "",
 	"Oops! There was an error in the previous response. Please try again or contact admin.": "",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "უპს! თქვენ იყენებთ მხარდაუჭერელ მეთოდს (მხოლოდ frontend). გთხოვთ, მოემსახუროთ WebUI-ს ბექენდიდან",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "უპს! თქვენ იყენებთ მხარდაუჭერელ მეთოდს (მხოლოდ frontend). გთხოვთ, მოემსახუროთ WebUI-ს ბექენდიდან",
+	"Open file": "",
 	"Open new chat": "ახალი მიმოწერის გახსნა",
 	"Open new chat": "ახალი მიმოწერის გახსნა",
 	"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "",
 	"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "",
 	"OpenAI": "OpenAI",
 	"OpenAI": "OpenAI",
@@ -476,6 +478,7 @@
 	"Other": "სხვა",
 	"Other": "სხვა",
 	"Output format": "",
 	"Output format": "",
 	"Overview": "",
 	"Overview": "",
+	"page": "",
 	"Password": "პაროლი",
 	"Password": "პაროლი",
 	"PDF document (.pdf)": "PDF დოკუმენტი (.pdf)",
 	"PDF document (.pdf)": "PDF დოკუმენტი (.pdf)",
 	"PDF Extract Images (OCR)": "PDF იდან ამოღებული სურათები (OCR)",
 	"PDF Extract Images (OCR)": "PDF იდან ამოღებული სურათები (OCR)",
@@ -699,6 +702,7 @@
 	"Unpin": "",
 	"Unpin": "",
 	"Update": "",
 	"Update": "",
 	"Update and Copy Link": "განახლება და ბმულის კოპირება",
 	"Update and Copy Link": "განახლება და ბმულის კოპირება",
+	"Update for the latest features and improvements.": "",
 	"Update password": "პაროლის განახლება",
 	"Update password": "პაროლის განახლება",
 	"Updated at": "",
 	"Updated at": "",
 	"Upload": "",
 	"Upload": "",

+ 4 - 0
src/lib/i18n/locales/ko-KR/translation.json

@@ -9,6 +9,7 @@
 	"{{user}}'s Chats": "{{user}}의 채팅",
 	"{{user}}'s Chats": "{{user}}의 채팅",
 	"{{webUIName}} Backend Required": "{{webUIName}} 백엔드가 필요합니다.",
 	"{{webUIName}} Backend Required": "{{webUIName}} 백엔드가 필요합니다.",
 	"*Prompt node ID(s) are required for image generation": "",
 	"*Prompt node ID(s) are required for image generation": "",
+	"A new version (v{{LATEST_VERSION}}) is now available.": "",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "작업 모델은 채팅 및 웹 검색 쿼리에 대한 제목 생성 등의 작업 수행 시 사용됩니다.",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "작업 모델은 채팅 및 웹 검색 쿼리에 대한 제목 생성 등의 작업 수행 시 사용됩니다.",
 	"a user": "사용자",
 	"a user": "사용자",
 	"About": "정보",
 	"About": "정보",
@@ -465,6 +466,7 @@
 	"Oops! Looks like the URL is invalid. Please double-check and try again.": "이런! URL이 잘못된 것 같습니다. 다시 한번 확인하고 다시 시도해주세요.",
 	"Oops! Looks like the URL is invalid. Please double-check and try again.": "이런! URL이 잘못된 것 같습니다. 다시 한번 확인하고 다시 시도해주세요.",
 	"Oops! There was an error in the previous response. Please try again or contact admin.": "",
 	"Oops! There was an error in the previous response. Please try again or contact admin.": "",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "이런! 지원되지 않는 방식(프론트엔드만)을 사용하고 계십니다. 백엔드에서 WebUI를 제공해주세요.",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "이런! 지원되지 않는 방식(프론트엔드만)을 사용하고 계십니다. 백엔드에서 WebUI를 제공해주세요.",
+	"Open file": "",
 	"Open new chat": "새 채팅 열기",
 	"Open new chat": "새 채팅 열기",
 	"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "",
 	"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "",
 	"OpenAI": "OpenAI",
 	"OpenAI": "OpenAI",
@@ -476,6 +478,7 @@
 	"Other": "기타",
 	"Other": "기타",
 	"Output format": "",
 	"Output format": "",
 	"Overview": "",
 	"Overview": "",
+	"page": "",
 	"Password": "비밀번호",
 	"Password": "비밀번호",
 	"PDF document (.pdf)": "PDF 문서(.pdf)",
 	"PDF document (.pdf)": "PDF 문서(.pdf)",
 	"PDF Extract Images (OCR)": "PDF 이미지 추출(OCR)",
 	"PDF Extract Images (OCR)": "PDF 이미지 추출(OCR)",
@@ -699,6 +702,7 @@
 	"Unpin": "",
 	"Unpin": "",
 	"Update": "업데이트",
 	"Update": "업데이트",
 	"Update and Copy Link": "링크 업데이트 및 복사",
 	"Update and Copy Link": "링크 업데이트 및 복사",
+	"Update for the latest features and improvements.": "",
 	"Update password": "비밀번호 업데이트",
 	"Update password": "비밀번호 업데이트",
 	"Updated at": "다음에 업데이트됨",
 	"Updated at": "다음에 업데이트됨",
 	"Upload": "업로드",
 	"Upload": "업로드",

+ 4 - 0
src/lib/i18n/locales/lt-LT/translation.json

@@ -9,6 +9,7 @@
 	"{{user}}'s Chats": "{{user}} susirašinėjimai",
 	"{{user}}'s Chats": "{{user}} susirašinėjimai",
 	"{{webUIName}} Backend Required": "{{webUIName}} būtinas serveris",
 	"{{webUIName}} Backend Required": "{{webUIName}} būtinas serveris",
 	"*Prompt node ID(s) are required for image generation": "",
 	"*Prompt node ID(s) are required for image generation": "",
+	"A new version (v{{LATEST_VERSION}}) is now available.": "",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "Užduočių modelis naudojamas pokalbių pavadinimų ir paieškos užklausų generavimui.",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "Užduočių modelis naudojamas pokalbių pavadinimų ir paieškos užklausų generavimui.",
 	"a user": "naudotojas",
 	"a user": "naudotojas",
 	"About": "Apie",
 	"About": "Apie",
@@ -465,6 +466,7 @@
 	"Oops! Looks like the URL is invalid. Please double-check and try again.": "Regis nuoroda nevalidi. Prašau patikrtinkite ir pabandykite iš naujo.",
 	"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 was an error in the previous response. Please try again or contact admin.": "Įvyko klaida. Pabandykite iš naujo arba susisiekite su administratoriumi.",
 	"Oops! There was an error in the previous response. Please try again or contact admin.": "Įvyko klaida. Pabandykite iš naujo arba susisiekite su administratoriumi.",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "Naudojate nepalaikomą (front-end) web ui rėžimą. Prašau serviruokite WebUI iš back-end",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "Naudojate nepalaikomą (front-end) web ui rėžimą. Prašau serviruokite WebUI iš back-end",
+	"Open file": "",
 	"Open new chat": "Atverti naują pokalbį",
 	"Open new chat": "Atverti naują pokalbį",
 	"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.",
 	"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": "OpenAI",
@@ -476,6 +478,7 @@
 	"Other": "Kita",
 	"Other": "Kita",
 	"Output format": "",
 	"Output format": "",
 	"Overview": "",
 	"Overview": "",
+	"page": "",
 	"Password": "Slaptažodis",
 	"Password": "Slaptažodis",
 	"PDF document (.pdf)": "PDF dokumentas (.pdf)",
 	"PDF document (.pdf)": "PDF dokumentas (.pdf)",
 	"PDF Extract Images (OCR)": "PDF paveikslėlių skaitymas (OCR)",
 	"PDF Extract Images (OCR)": "PDF paveikslėlių skaitymas (OCR)",
@@ -701,6 +704,7 @@
 	"Unpin": "Atsemigti",
 	"Unpin": "Atsemigti",
 	"Update": "Atnaujinti",
 	"Update": "Atnaujinti",
 	"Update and Copy Link": "Atnaujinti ir kopijuoti nuorodą",
 	"Update and Copy Link": "Atnaujinti ir kopijuoti nuorodą",
+	"Update for the latest features and improvements.": "",
 	"Update password": "Atnaujinti slaptažodį",
 	"Update password": "Atnaujinti slaptažodį",
 	"Updated at": "Atnaujinta",
 	"Updated at": "Atnaujinta",
 	"Upload": "Atnaujinti",
 	"Upload": "Atnaujinti",

+ 4 - 0
src/lib/i18n/locales/ms-MY/translation.json

@@ -9,6 +9,7 @@
 	"{{user}}'s Chats": "Perbualan {{user}}",
 	"{{user}}'s Chats": "Perbualan {{user}}",
 	"{{webUIName}} Backend Required": "{{webUIName}} Backend diperlukan",
 	"{{webUIName}} Backend Required": "{{webUIName}} Backend diperlukan",
 	"*Prompt node ID(s) are required for image generation": "",
 	"*Prompt node ID(s) are required for image generation": "",
+	"A new version (v{{LATEST_VERSION}}) is now available.": "",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "Model tugas digunakan semasa melaksanakan tugas seperti menjana tajuk untuk perbualan dan pertanyaan carian web.",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "Model tugas digunakan semasa melaksanakan tugas seperti menjana tajuk untuk perbualan dan pertanyaan carian web.",
 	"a user": "seorang pengguna",
 	"a user": "seorang pengguna",
 	"About": "Mengenai",
 	"About": "Mengenai",
@@ -465,6 +466,7 @@
 	"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! 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 was an error in the previous response. Please try again or contact admin.": "Maaf, terdapat ralat dalam respons sebelumnya. Sila cuba lagi atau hubungi pentadbir",
 	"Oops! There was an error in the previous response. Please try again or contact admin.": "Maaf, terdapat ralat dalam respons sebelumnya. Sila cuba lagi atau hubungi pentadbir",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "Maaf, Anda menggunakan kaedah yang tidak disokong (bahagian 'frontend' sahaja). Sila sediakan WebUI dari 'backend'.",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "Maaf, Anda menggunakan kaedah yang tidak disokong (bahagian 'frontend' sahaja). Sila sediakan WebUI dari 'backend'.",
+	"Open file": "",
 	"Open new chat": "Buka perbualan baru",
 	"Open new chat": "Buka perbualan baru",
 	"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}})",
 	"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": "OpenAI",
@@ -476,6 +478,7 @@
 	"Other": "Lain-lain",
 	"Other": "Lain-lain",
 	"Output format": "",
 	"Output format": "",
 	"Overview": "",
 	"Overview": "",
+	"page": "",
 	"Password": "Kata Laluan",
 	"Password": "Kata Laluan",
 	"PDF document (.pdf)": "Dokumen PDF (.pdf)",
 	"PDF document (.pdf)": "Dokumen PDF (.pdf)",
 	"PDF Extract Images (OCR)": "Imej Ekstrak PDF (OCR)",
 	"PDF Extract Images (OCR)": "Imej Ekstrak PDF (OCR)",
@@ -699,6 +702,7 @@
 	"Unpin": "Nyahsematkan",
 	"Unpin": "Nyahsematkan",
 	"Update": "Kemaskini",
 	"Update": "Kemaskini",
 	"Update and Copy Link": "Kemaskini dan salin pautan",
 	"Update and Copy Link": "Kemaskini dan salin pautan",
+	"Update for the latest features and improvements.": "",
 	"Update password": "Kemaskini Kata Laluan",
 	"Update password": "Kemaskini Kata Laluan",
 	"Updated at": "Dikemaskini pada",
 	"Updated at": "Dikemaskini pada",
 	"Upload": "Muatnaik",
 	"Upload": "Muatnaik",

+ 4 - 0
src/lib/i18n/locales/nb-NO/translation.json

@@ -9,6 +9,7 @@
 	"{{user}}'s Chats": "{{user}}s samtaler",
 	"{{user}}'s Chats": "{{user}}s samtaler",
 	"{{webUIName}} Backend Required": "{{webUIName}} Backend kreves",
 	"{{webUIName}} Backend Required": "{{webUIName}} Backend kreves",
 	"*Prompt node ID(s) are required for image generation": "",
 	"*Prompt node ID(s) are required for image generation": "",
+	"A new version (v{{LATEST_VERSION}}) is now available.": "",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "En oppgavemodell brukes når du utfører oppgaver som å generere titler for samtaler og websøkeforespørsler",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "En oppgavemodell brukes når du utfører oppgaver som å generere titler for samtaler og websøkeforespørsler",
 	"a user": "en bruker",
 	"a user": "en bruker",
 	"About": "Om",
 	"About": "Om",
@@ -465,6 +466,7 @@
 	"Oops! Looks like the URL is invalid. Please double-check and try again.": "Oops! Ser ut som URL-en er ugyldig. Vennligst dobbeltsjekk og prøv igjen.",
 	"Oops! Looks like the URL is invalid. Please double-check and try again.": "Oops! Ser ut som URL-en er ugyldig. Vennligst dobbeltsjekk og prøv igjen.",
 	"Oops! There was an error in the previous response. Please try again or contact admin.": "Oops! Det oppstod en feil i forrige svar. Prøv igjen eller kontakt administrator",
 	"Oops! There was an error in the previous response. Please try again or contact admin.": "Oops! Det oppstod en feil i forrige svar. Prøv igjen eller kontakt administrator",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "Oops! Du bruker en ikke-støttet metode (kun frontend). Vennligst server WebUI fra backend.",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "Oops! Du bruker en ikke-støttet metode (kun frontend). Vennligst server WebUI fra backend.",
+	"Open file": "",
 	"Open new chat": "Åpne ny chat",
 	"Open new chat": "Åpne ny chat",
 	"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "Open WebUI-versjon (v{{OPEN_WEBUI_VERSION}}) er lavere enn nødvendig versjon (v{{REQUIRED_VERSION}})",
 	"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "Open WebUI-versjon (v{{OPEN_WEBUI_VERSION}}) er lavere enn nødvendig versjon (v{{REQUIRED_VERSION}})",
 	"OpenAI": "OpenAI",
 	"OpenAI": "OpenAI",
@@ -476,6 +478,7 @@
 	"Other": "Annet",
 	"Other": "Annet",
 	"Output format": "",
 	"Output format": "",
 	"Overview": "",
 	"Overview": "",
+	"page": "",
 	"Password": "Passord",
 	"Password": "Passord",
 	"PDF document (.pdf)": "PDF-dokument (.pdf)",
 	"PDF document (.pdf)": "PDF-dokument (.pdf)",
 	"PDF Extract Images (OCR)": "PDF-ekstraktbilder (OCR)",
 	"PDF Extract Images (OCR)": "PDF-ekstraktbilder (OCR)",
@@ -699,6 +702,7 @@
 	"Unpin": "Løsne",
 	"Unpin": "Løsne",
 	"Update": "Oppdater",
 	"Update": "Oppdater",
 	"Update and Copy Link": "Oppdater og kopier lenke",
 	"Update and Copy Link": "Oppdater og kopier lenke",
+	"Update for the latest features and improvements.": "",
 	"Update password": "Oppdater passord",
 	"Update password": "Oppdater passord",
 	"Updated at": "Oppdatert",
 	"Updated at": "Oppdatert",
 	"Upload": "Last opp",
 	"Upload": "Last opp",

+ 4 - 0
src/lib/i18n/locales/nl-NL/translation.json

@@ -9,6 +9,7 @@
 	"{{user}}'s Chats": "{{user}}'s Chats",
 	"{{user}}'s Chats": "{{user}}'s Chats",
 	"{{webUIName}} Backend Required": "{{webUIName}} Backend Verlpicht",
 	"{{webUIName}} Backend Required": "{{webUIName}} Backend Verlpicht",
 	"*Prompt node ID(s) are required for image generation": "",
 	"*Prompt node ID(s) are required for image generation": "",
+	"A new version (v{{LATEST_VERSION}}) is now available.": "",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "Een taakmodel wordt gebruikt bij het uitvoeren van taken zoals het genereren van titels voor chats en zoekopdrachten op internet",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "Een taakmodel wordt gebruikt bij het uitvoeren van taken zoals het genereren van titels voor chats en zoekopdrachten op internet",
 	"a user": "een gebruiker",
 	"a user": "een gebruiker",
 	"About": "Over",
 	"About": "Over",
@@ -465,6 +466,7 @@
 	"Oops! Looks like the URL is invalid. Please double-check and try again.": "Oops! Het lijkt erop dat de URL ongeldig is. Controleer het nogmaals en probeer opnieuw.",
 	"Oops! Looks like the URL is invalid. Please double-check and try again.": "Oops! Het lijkt erop dat de URL ongeldig is. Controleer het nogmaals en probeer opnieuw.",
 	"Oops! There was an error in the previous response. Please try again or contact admin.": "",
 	"Oops! There was an error in the previous response. Please try again or contact admin.": "",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "Oops! Je gebruikt een niet-ondersteunde methode (alleen frontend). Serveer de WebUI vanuit de backend.",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "Oops! Je gebruikt een niet-ondersteunde methode (alleen frontend). Serveer de WebUI vanuit de backend.",
+	"Open file": "",
 	"Open new chat": "Open nieuwe chat",
 	"Open new chat": "Open nieuwe chat",
 	"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "",
 	"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "",
 	"OpenAI": "OpenAI",
 	"OpenAI": "OpenAI",
@@ -476,6 +478,7 @@
 	"Other": "Andere",
 	"Other": "Andere",
 	"Output format": "",
 	"Output format": "",
 	"Overview": "",
 	"Overview": "",
+	"page": "",
 	"Password": "Wachtwoord",
 	"Password": "Wachtwoord",
 	"PDF document (.pdf)": "PDF document (.pdf)",
 	"PDF document (.pdf)": "PDF document (.pdf)",
 	"PDF Extract Images (OCR)": "PDF Extract Afbeeldingen (OCR)",
 	"PDF Extract Images (OCR)": "PDF Extract Afbeeldingen (OCR)",
@@ -699,6 +702,7 @@
 	"Unpin": "",
 	"Unpin": "",
 	"Update": "",
 	"Update": "",
 	"Update and Copy Link": "Update en Kopieer Link",
 	"Update and Copy Link": "Update en Kopieer Link",
+	"Update for the latest features and improvements.": "",
 	"Update password": "Wijzig wachtwoord",
 	"Update password": "Wijzig wachtwoord",
 	"Updated at": "",
 	"Updated at": "",
 	"Upload": "",
 	"Upload": "",

+ 4 - 0
src/lib/i18n/locales/pa-IN/translation.json

@@ -9,6 +9,7 @@
 	"{{user}}'s Chats": "{{user}} ਦੀਆਂ ਗੱਲਾਂ",
 	"{{user}}'s Chats": "{{user}} ਦੀਆਂ ਗੱਲਾਂ",
 	"{{webUIName}} Backend Required": "{{webUIName}} ਬੈਕਐਂਡ ਲੋੜੀਂਦਾ ਹੈ",
 	"{{webUIName}} Backend Required": "{{webUIName}} ਬੈਕਐਂਡ ਲੋੜੀਂਦਾ ਹੈ",
 	"*Prompt node ID(s) are required for image generation": "",
 	"*Prompt node ID(s) are required for image generation": "",
+	"A new version (v{{LATEST_VERSION}}) is now available.": "",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "ਚੈਟਾਂ ਅਤੇ ਵੈੱਬ ਖੋਜ ਪੁੱਛਗਿੱਛਾਂ ਵਾਸਤੇ ਸਿਰਲੇਖ ਤਿਆਰ ਕਰਨ ਵਰਗੇ ਕਾਰਜ ਾਂ ਨੂੰ ਕਰਦੇ ਸਮੇਂ ਇੱਕ ਕਾਰਜ ਮਾਡਲ ਦੀ ਵਰਤੋਂ ਕੀਤੀ ਜਾਂਦੀ ਹੈ",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "ਚੈਟਾਂ ਅਤੇ ਵੈੱਬ ਖੋਜ ਪੁੱਛਗਿੱਛਾਂ ਵਾਸਤੇ ਸਿਰਲੇਖ ਤਿਆਰ ਕਰਨ ਵਰਗੇ ਕਾਰਜ ਾਂ ਨੂੰ ਕਰਦੇ ਸਮੇਂ ਇੱਕ ਕਾਰਜ ਮਾਡਲ ਦੀ ਵਰਤੋਂ ਕੀਤੀ ਜਾਂਦੀ ਹੈ",
 	"a user": "ਇੱਕ ਉਪਭੋਗਤਾ",
 	"a user": "ਇੱਕ ਉਪਭੋਗਤਾ",
 	"About": "ਬਾਰੇ",
 	"About": "ਬਾਰੇ",
@@ -465,6 +466,7 @@
 	"Oops! Looks like the URL is invalid. Please double-check and try again.": "ਓਹੋ! ਲੱਗਦਾ ਹੈ ਕਿ URL ਗਲਤ ਹੈ। ਕਿਰਪਾ ਕਰਕੇ ਦੁਬਾਰਾ ਜਾਂਚ ਕਰੋ ਅਤੇ ਮੁੜ ਕੋਸ਼ਿਸ਼ ਕਰੋ।",
 	"Oops! Looks like the URL is invalid. Please double-check and try again.": "ਓਹੋ! ਲੱਗਦਾ ਹੈ ਕਿ URL ਗਲਤ ਹੈ। ਕਿਰਪਾ ਕਰਕੇ ਦੁਬਾਰਾ ਜਾਂਚ ਕਰੋ ਅਤੇ ਮੁੜ ਕੋਸ਼ਿਸ਼ ਕਰੋ।",
 	"Oops! There was an error in the previous response. Please try again or contact admin.": "",
 	"Oops! There was an error in the previous response. Please try again or contact admin.": "",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "ਓਹੋ! ਤੁਸੀਂ ਇੱਕ ਅਣਸਮਰਥਿਤ ਢੰਗ ਵਰਤ ਰਹੇ ਹੋ (ਸਿਰਫ਼ ਫਰੰਟਐਂਡ)। ਕਿਰਪਾ ਕਰਕੇ ਵੈਬਯੂਆਈ ਨੂੰ ਬੈਕਐਂਡ ਤੋਂ ਸਰਵ ਕਰੋ।",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "ਓਹੋ! ਤੁਸੀਂ ਇੱਕ ਅਣਸਮਰਥਿਤ ਢੰਗ ਵਰਤ ਰਹੇ ਹੋ (ਸਿਰਫ਼ ਫਰੰਟਐਂਡ)। ਕਿਰਪਾ ਕਰਕੇ ਵੈਬਯੂਆਈ ਨੂੰ ਬੈਕਐਂਡ ਤੋਂ ਸਰਵ ਕਰੋ।",
+	"Open file": "",
 	"Open new chat": "ਨਵੀਂ ਗੱਲਬਾਤ ਖੋਲ੍ਹੋ",
 	"Open new chat": "ਨਵੀਂ ਗੱਲਬਾਤ ਖੋਲ੍ਹੋ",
 	"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "",
 	"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "",
 	"OpenAI": "ਓਪਨਏਆਈ",
 	"OpenAI": "ਓਪਨਏਆਈ",
@@ -476,6 +478,7 @@
 	"Other": "ਹੋਰ",
 	"Other": "ਹੋਰ",
 	"Output format": "",
 	"Output format": "",
 	"Overview": "",
 	"Overview": "",
+	"page": "",
 	"Password": "ਪਾਸਵਰਡ",
 	"Password": "ਪਾਸਵਰਡ",
 	"PDF document (.pdf)": "PDF ਡਾਕੂਮੈਂਟ (.pdf)",
 	"PDF document (.pdf)": "PDF ਡਾਕੂਮੈਂਟ (.pdf)",
 	"PDF Extract Images (OCR)": "PDF ਚਿੱਤਰ ਕੱਢੋ (OCR)",
 	"PDF Extract Images (OCR)": "PDF ਚਿੱਤਰ ਕੱਢੋ (OCR)",
@@ -699,6 +702,7 @@
 	"Unpin": "",
 	"Unpin": "",
 	"Update": "",
 	"Update": "",
 	"Update and Copy Link": "ਅੱਪਡੇਟ ਕਰੋ ਅਤੇ ਲਿੰਕ ਕਾਪੀ ਕਰੋ",
 	"Update and Copy Link": "ਅੱਪਡੇਟ ਕਰੋ ਅਤੇ ਲਿੰਕ ਕਾਪੀ ਕਰੋ",
+	"Update for the latest features and improvements.": "",
 	"Update password": "ਪਾਸਵਰਡ ਅੱਪਡੇਟ ਕਰੋ",
 	"Update password": "ਪਾਸਵਰਡ ਅੱਪਡੇਟ ਕਰੋ",
 	"Updated at": "",
 	"Updated at": "",
 	"Upload": "",
 	"Upload": "",

+ 4 - 0
src/lib/i18n/locales/pl-PL/translation.json

@@ -9,6 +9,7 @@
 	"{{user}}'s Chats": "{{user}} - czaty",
 	"{{user}}'s Chats": "{{user}} - czaty",
 	"{{webUIName}} Backend Required": "Backend {{webUIName}} wymagane",
 	"{{webUIName}} Backend Required": "Backend {{webUIName}} wymagane",
 	"*Prompt node ID(s) are required for image generation": "",
 	"*Prompt node ID(s) are required for image generation": "",
+	"A new version (v{{LATEST_VERSION}}) is now available.": "",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "Model zadań jest używany podczas wykonywania zadań, takich jak generowanie tytułów czatów i zapytań wyszukiwania w Internecie",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "Model zadań jest używany podczas wykonywania zadań, takich jak generowanie tytułów czatów i zapytań wyszukiwania w Internecie",
 	"a user": "użytkownik",
 	"a user": "użytkownik",
 	"About": "O nas",
 	"About": "O nas",
@@ -465,6 +466,7 @@
 	"Oops! Looks like the URL is invalid. Please double-check and try again.": "Ups! Wygląda na to, że URL jest nieprawidłowy. Sprawdź jeszcze raz i spróbuj ponownie.",
 	"Oops! Looks like the URL is invalid. Please double-check and try again.": "Ups! Wygląda na to, że URL jest nieprawidłowy. Sprawdź jeszcze raz i spróbuj ponownie.",
 	"Oops! There was an error in the previous response. Please try again or contact admin.": "",
 	"Oops! There was an error in the previous response. Please try again or contact admin.": "",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "Ups! Używasz nieobsługiwanej metody (tylko interfejs front-end). Proszę obsłużyć interfejs WebUI z poziomu backendu.",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "Ups! Używasz nieobsługiwanej metody (tylko interfejs front-end). Proszę obsłużyć interfejs WebUI z poziomu backendu.",
+	"Open file": "",
 	"Open new chat": "Otwórz nowy czat",
 	"Open new chat": "Otwórz nowy czat",
 	"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "",
 	"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "",
 	"OpenAI": "OpenAI",
 	"OpenAI": "OpenAI",
@@ -476,6 +478,7 @@
 	"Other": "Inne",
 	"Other": "Inne",
 	"Output format": "",
 	"Output format": "",
 	"Overview": "",
 	"Overview": "",
+	"page": "",
 	"Password": "Hasło",
 	"Password": "Hasło",
 	"PDF document (.pdf)": "Dokument PDF (.pdf)",
 	"PDF document (.pdf)": "Dokument PDF (.pdf)",
 	"PDF Extract Images (OCR)": "PDF Wyodrębnij obrazy (OCR)",
 	"PDF Extract Images (OCR)": "PDF Wyodrębnij obrazy (OCR)",
@@ -701,6 +704,7 @@
 	"Unpin": "",
 	"Unpin": "",
 	"Update": "",
 	"Update": "",
 	"Update and Copy Link": "Uaktualnij i skopiuj link",
 	"Update and Copy Link": "Uaktualnij i skopiuj link",
+	"Update for the latest features and improvements.": "",
 	"Update password": "Aktualizacja hasła",
 	"Update password": "Aktualizacja hasła",
 	"Updated at": "",
 	"Updated at": "",
 	"Upload": "",
 	"Upload": "",

+ 4 - 0
src/lib/i18n/locales/pt-BR/translation.json

@@ -9,6 +9,7 @@
 	"{{user}}'s Chats": "Chats de {{user}}",
 	"{{user}}'s Chats": "Chats de {{user}}",
 	"{{webUIName}} Backend Required": "Backend {{webUIName}} necessário",
 	"{{webUIName}} Backend Required": "Backend {{webUIName}} necessário",
 	"*Prompt node ID(s) are required for image generation": "",
 	"*Prompt node ID(s) are required for image generation": "",
+	"A new version (v{{LATEST_VERSION}}) is now available.": "",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "Um modelo de tarefa é usado ao realizar tarefas como gerar títulos para chats e consultas de pesquisa na web",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "Um modelo de tarefa é usado ao realizar tarefas como gerar títulos para chats e consultas de pesquisa na web",
 	"a user": "um usuário",
 	"a user": "um usuário",
 	"About": "Sobre",
 	"About": "Sobre",
@@ -465,6 +466,7 @@
 	"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! 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 was an error in the previous response. Please try again or contact admin.": "Ops! Houve um erro na resposta anterior. Por favor, tente novamente ou entre em contato com o administrador.",
 	"Oops! There was an error in the previous response. Please try again or contact admin.": "Ops! Houve um erro na resposta anterior. Por favor, tente novamente ou entre em contato com o administrador.",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "Ops! Você está usando um método não suportado (somente frontend). Por favor, sirva a WebUI a partir do backend.",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "Ops! Você está usando um método não suportado (somente frontend). Por favor, sirva a WebUI a partir do backend.",
+	"Open file": "",
 	"Open new chat": "Abrir novo chat",
 	"Open new chat": "Abrir novo chat",
 	"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}})",
 	"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": "OpenAI",
@@ -476,6 +478,7 @@
 	"Other": "Outro",
 	"Other": "Outro",
 	"Output format": "",
 	"Output format": "",
 	"Overview": "",
 	"Overview": "",
+	"page": "",
 	"Password": "Senha",
 	"Password": "Senha",
 	"PDF document (.pdf)": "Documento PDF (.pdf)",
 	"PDF document (.pdf)": "Documento PDF (.pdf)",
 	"PDF Extract Images (OCR)": "Extrair Imagens do PDF (OCR)",
 	"PDF Extract Images (OCR)": "Extrair Imagens do PDF (OCR)",
@@ -700,6 +703,7 @@
 	"Unpin": "Desfixar",
 	"Unpin": "Desfixar",
 	"Update": "Atualizar",
 	"Update": "Atualizar",
 	"Update and Copy Link": "Atualizar e Copiar Link",
 	"Update and Copy Link": "Atualizar e Copiar Link",
+	"Update for the latest features and improvements.": "",
 	"Update password": "Atualizar senha",
 	"Update password": "Atualizar senha",
 	"Updated at": "Atualizado em",
 	"Updated at": "Atualizado em",
 	"Upload": "Fazer upload",
 	"Upload": "Fazer upload",

+ 4 - 0
src/lib/i18n/locales/pt-PT/translation.json

@@ -9,6 +9,7 @@
 	"{{user}}'s Chats": "{{user}}'s Chats",
 	"{{user}}'s Chats": "{{user}}'s Chats",
 	"{{webUIName}} Backend Required": "{{webUIName}} Backend Necessário",
 	"{{webUIName}} Backend Required": "{{webUIName}} Backend Necessário",
 	"*Prompt node ID(s) are required for image generation": "",
 	"*Prompt node ID(s) are required for image generation": "",
+	"A new version (v{{LATEST_VERSION}}) is now available.": "",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "Um modelo de tarefa é usado ao executar tarefas como gerar títulos para bate-papos e consultas de pesquisa na Web",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "Um modelo de tarefa é usado ao executar tarefas como gerar títulos para bate-papos e consultas de pesquisa na Web",
 	"a user": "um utilizador",
 	"a user": "um utilizador",
 	"About": "Acerca de",
 	"About": "Acerca de",
@@ -465,6 +466,7 @@
 	"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! 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 was an error in the previous response. Please try again or contact admin.": "",
 	"Oops! There was an error in the previous response. Please try again or contact admin.": "",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "Epá! Você está a usar um método não suportado (somente frontend). Por favor, sirva o WebUI a partir do backend.",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "Epá! Você está a usar um método não suportado (somente frontend). Por favor, sirva o WebUI a partir do backend.",
+	"Open file": "",
 	"Open new chat": "Abrir nova conversa",
 	"Open new chat": "Abrir nova conversa",
 	"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "",
 	"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "",
 	"OpenAI": "OpenAI",
 	"OpenAI": "OpenAI",
@@ -476,6 +478,7 @@
 	"Other": "Outro",
 	"Other": "Outro",
 	"Output format": "",
 	"Output format": "",
 	"Overview": "",
 	"Overview": "",
+	"page": "",
 	"Password": "Senha",
 	"Password": "Senha",
 	"PDF document (.pdf)": "Documento PDF (.pdf)",
 	"PDF document (.pdf)": "Documento PDF (.pdf)",
 	"PDF Extract Images (OCR)": "Extrair Imagens de PDF (OCR)",
 	"PDF Extract Images (OCR)": "Extrair Imagens de PDF (OCR)",
@@ -700,6 +703,7 @@
 	"Unpin": "",
 	"Unpin": "",
 	"Update": "",
 	"Update": "",
 	"Update and Copy Link": "Atualizar e Copiar Link",
 	"Update and Copy Link": "Atualizar e Copiar Link",
+	"Update for the latest features and improvements.": "",
 	"Update password": "Atualizar senha",
 	"Update password": "Atualizar senha",
 	"Updated at": "",
 	"Updated at": "",
 	"Upload": "",
 	"Upload": "",

+ 4 - 0
src/lib/i18n/locales/ro-RO/translation.json

@@ -9,6 +9,7 @@
 	"{{user}}'s Chats": "Conversațiile lui {{user}}",
 	"{{user}}'s Chats": "Conversațiile lui {{user}}",
 	"{{webUIName}} Backend Required": "Este necesar backend-ul {{webUIName}}",
 	"{{webUIName}} Backend Required": "Este necesar backend-ul {{webUIName}}",
 	"*Prompt node ID(s) are required for image generation": "",
 	"*Prompt node ID(s) are required for image generation": "",
+	"A new version (v{{LATEST_VERSION}}) is now available.": "",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "Un model de sarcină este utilizat pentru realizarea unor sarcini precum generarea de titluri pentru conversații și interogări de căutare pe web",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "Un model de sarcină este utilizat pentru realizarea unor sarcini precum generarea de titluri pentru conversații și interogări de căutare pe web",
 	"a user": "un utilizator",
 	"a user": "un utilizator",
 	"About": "Despre",
 	"About": "Despre",
@@ -465,6 +466,7 @@
 	"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! 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 was an error in the previous response. Please try again or contact admin.": "Oops! A apărut o eroare în răspunsul anterior. Vă rugăm să încercați din nou sau să contactați administratorul.",
 	"Oops! There was an error in the previous response. Please try again or contact admin.": "Oops! A apărut o eroare în răspunsul anterior. Vă rugăm să încercați din nou sau să contactați administratorul.",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "Oops! Utilizați o metodă nesuportată (doar frontend). Vă rugăm să serviți WebUI din backend.",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "Oops! Utilizați o metodă nesuportată (doar frontend). Vă rugăm să serviți WebUI din backend.",
+	"Open file": "",
 	"Open new chat": "Deschide conversație nouă",
 	"Open new chat": "Deschide conversație nouă",
 	"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}})",
 	"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": "OpenAI",
@@ -476,6 +478,7 @@
 	"Other": "Altele",
 	"Other": "Altele",
 	"Output format": "",
 	"Output format": "",
 	"Overview": "",
 	"Overview": "",
+	"page": "",
 	"Password": "Parolă",
 	"Password": "Parolă",
 	"PDF document (.pdf)": "Document PDF (.pdf)",
 	"PDF document (.pdf)": "Document PDF (.pdf)",
 	"PDF Extract Images (OCR)": "Extrage Imagini PDF (OCR)",
 	"PDF Extract Images (OCR)": "Extrage Imagini PDF (OCR)",
@@ -700,6 +703,7 @@
 	"Unpin": "Anulează Fixarea",
 	"Unpin": "Anulează Fixarea",
 	"Update": "Actualizează",
 	"Update": "Actualizează",
 	"Update and Copy Link": "Actualizează și Copiază Link-ul",
 	"Update and Copy Link": "Actualizează și Copiază Link-ul",
+	"Update for the latest features and improvements.": "",
 	"Update password": "Actualizează parola",
 	"Update password": "Actualizează parola",
 	"Updated at": "Actualizat la",
 	"Updated at": "Actualizat la",
 	"Upload": "Încărcare",
 	"Upload": "Încărcare",

+ 4 - 0
src/lib/i18n/locales/ru-RU/translation.json

@@ -9,6 +9,7 @@
 	"{{user}}'s Chats": "Чаты {{user}}'а",
 	"{{user}}'s Chats": "Чаты {{user}}'а",
 	"{{webUIName}} Backend Required": "Необходимо подключение к серверу {{webUIName}}",
 	"{{webUIName}} Backend Required": "Необходимо подключение к серверу {{webUIName}}",
 	"*Prompt node ID(s) are required for image generation": "ID узлов промптов обязательны для генерации изображения",
 	"*Prompt node ID(s) are required for image generation": "ID узлов промптов обязательны для генерации изображения",
+	"A new version (v{{LATEST_VERSION}}) is now available.": "",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "Модель задач используется при выполнении таких задач, как генерация заголовков для чатов и поисковых запросов в Интернете",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "Модель задач используется при выполнении таких задач, как генерация заголовков для чатов и поисковых запросов в Интернете",
 	"a user": "пользователь",
 	"a user": "пользователь",
 	"About": "О программе",
 	"About": "О программе",
@@ -465,6 +466,7 @@
 	"Oops! Looks like the URL is invalid. Please double-check and try again.": "Упс! Похоже, что URL-адрес недействителен. Пожалуйста, перепроверьте и попробуйте еще раз.",
 	"Oops! Looks like the URL is invalid. Please double-check and try again.": "Упс! Похоже, что URL-адрес недействителен. Пожалуйста, перепроверьте и попробуйте еще раз.",
 	"Oops! There was an error in the previous response. Please try again or contact admin.": "Упс! В предыдущем ответе была ошибка. Пожалуйста, повторите попытку или свяжитесь с администратором.",
 	"Oops! There was an error in the previous response. Please try again or contact admin.": "Упс! В предыдущем ответе была ошибка. Пожалуйста, повторите попытку или свяжитесь с администратором.",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "Упс! Вы используете неподдерживаемый метод (только фронтенд). Пожалуйста, обслуживайте веб-интерфейс из бэкенда.",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "Упс! Вы используете неподдерживаемый метод (только фронтенд). Пожалуйста, обслуживайте веб-интерфейс из бэкенда.",
+	"Open file": "",
 	"Open new chat": "Открыть новый чат",
 	"Open new chat": "Открыть новый чат",
 	"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "Версия Open WebUI (v{{OPEN_WEBUI_VERSION}}) ниже требуемой версии (v{{REQUIRED_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": "Open AI",
@@ -476,6 +478,7 @@
 	"Other": "Прочее",
 	"Other": "Прочее",
 	"Output format": "",
 	"Output format": "",
 	"Overview": "",
 	"Overview": "",
+	"page": "",
 	"Password": "Пароль",
 	"Password": "Пароль",
 	"PDF document (.pdf)": "PDF-документ (.pdf)",
 	"PDF document (.pdf)": "PDF-документ (.pdf)",
 	"PDF Extract Images (OCR)": "Извлечение изображений из PDF (OCR)",
 	"PDF Extract Images (OCR)": "Извлечение изображений из PDF (OCR)",
@@ -701,6 +704,7 @@
 	"Unpin": "Открепить",
 	"Unpin": "Открепить",
 	"Update": "Обновить",
 	"Update": "Обновить",
 	"Update and Copy Link": "Обновить и скопировать ссылку",
 	"Update and Copy Link": "Обновить и скопировать ссылку",
+	"Update for the latest features and improvements.": "",
 	"Update password": "Обновить пароль",
 	"Update password": "Обновить пароль",
 	"Updated at": "Обновлено",
 	"Updated at": "Обновлено",
 	"Upload": "Загрузить",
 	"Upload": "Загрузить",

+ 4 - 0
src/lib/i18n/locales/sr-RS/translation.json

@@ -9,6 +9,7 @@
 	"{{user}}'s Chats": "Ћаскања корисника {{user}}",
 	"{{user}}'s Chats": "Ћаскања корисника {{user}}",
 	"{{webUIName}} Backend Required": "Захтева се {{webUIName}} позадинац",
 	"{{webUIName}} Backend Required": "Захтева се {{webUIName}} позадинац",
 	"*Prompt node ID(s) are required for image generation": "",
 	"*Prompt node ID(s) are required for image generation": "",
+	"A new version (v{{LATEST_VERSION}}) is now available.": "",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "Модел задатка се користи приликом извршавања задатака као што су генерисање наслова за ћаскања и упите за Веб претрагу",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "Модел задатка се користи приликом извршавања задатака као што су генерисање наслова за ћаскања и упите за Веб претрагу",
 	"a user": "корисник",
 	"a user": "корисник",
 	"About": "О нама",
 	"About": "О нама",
@@ -465,6 +466,7 @@
 	"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 was an error in the previous response. Please try again or contact admin.": "",
 	"Oops! There was an error in the previous response. Please try again or contact admin.": "",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "Упс! Користите неподржани метод (само фронтенд). Молимо вас да покренете WebUI са бекенда.",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "Упс! Користите неподржани метод (само фронтенд). Молимо вас да покренете WebUI са бекенда.",
+	"Open file": "",
 	"Open new chat": "Покрени ново ћаскање",
 	"Open new chat": "Покрени ново ћаскање",
 	"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "",
 	"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "",
 	"OpenAI": "OpenAI",
 	"OpenAI": "OpenAI",
@@ -476,6 +478,7 @@
 	"Other": "Остало",
 	"Other": "Остало",
 	"Output format": "",
 	"Output format": "",
 	"Overview": "",
 	"Overview": "",
+	"page": "",
 	"Password": "Лозинка",
 	"Password": "Лозинка",
 	"PDF document (.pdf)": "PDF документ (.pdf)",
 	"PDF document (.pdf)": "PDF документ (.pdf)",
 	"PDF Extract Images (OCR)": "Извлачење PDF слика (OCR)",
 	"PDF Extract Images (OCR)": "Извлачење PDF слика (OCR)",
@@ -700,6 +703,7 @@
 	"Unpin": "",
 	"Unpin": "",
 	"Update": "",
 	"Update": "",
 	"Update and Copy Link": "Ажурирај и копирај везу",
 	"Update and Copy Link": "Ажурирај и копирај везу",
+	"Update for the latest features and improvements.": "",
 	"Update password": "Ажурирај лозинку",
 	"Update password": "Ажурирај лозинку",
 	"Updated at": "",
 	"Updated at": "",
 	"Upload": "",
 	"Upload": "",

+ 4 - 0
src/lib/i18n/locales/sv-SE/translation.json

@@ -9,6 +9,7 @@
 	"{{user}}'s Chats": "{{user}}s Chats",
 	"{{user}}'s Chats": "{{user}}s Chats",
 	"{{webUIName}} Backend Required": "{{webUIName}} Backend krävs",
 	"{{webUIName}} Backend Required": "{{webUIName}} Backend krävs",
 	"*Prompt node ID(s) are required for image generation": "",
 	"*Prompt node ID(s) are required for image generation": "",
+	"A new version (v{{LATEST_VERSION}}) is now available.": "",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "En uppgiftsmodell används när du utför uppgifter som att generera titlar för chattar och webbsökningsfrågor",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "En uppgiftsmodell används när du utför uppgifter som att generera titlar för chattar och webbsökningsfrågor",
 	"a user": "en användare",
 	"a user": "en användare",
 	"About": "Om",
 	"About": "Om",
@@ -465,6 +466,7 @@
 	"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! 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 was an error in the previous response. Please try again or contact admin.": "",
 	"Oops! There was an error in the previous response. Please try again or contact admin.": "",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "Hoppsan! Du använder en ej stödd metod (endast frontend). Vänligen servera WebUI från backend.",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "Hoppsan! Du använder en ej stödd metod (endast frontend). Vänligen servera WebUI från backend.",
+	"Open file": "",
 	"Open new chat": "Öppna ny chatt",
 	"Open new chat": "Öppna ny chatt",
 	"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "",
 	"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "",
 	"OpenAI": "OpenAI",
 	"OpenAI": "OpenAI",
@@ -476,6 +478,7 @@
 	"Other": "Andra",
 	"Other": "Andra",
 	"Output format": "",
 	"Output format": "",
 	"Overview": "",
 	"Overview": "",
+	"page": "",
 	"Password": "Lösenord",
 	"Password": "Lösenord",
 	"PDF document (.pdf)": "PDF-dokument (.pdf)",
 	"PDF document (.pdf)": "PDF-dokument (.pdf)",
 	"PDF Extract Images (OCR)": "PDF Extrahera bilder (OCR)",
 	"PDF Extract Images (OCR)": "PDF Extrahera bilder (OCR)",
@@ -699,6 +702,7 @@
 	"Unpin": "",
 	"Unpin": "",
 	"Update": "",
 	"Update": "",
 	"Update and Copy Link": "Uppdatera och kopiera länk",
 	"Update and Copy Link": "Uppdatera och kopiera länk",
+	"Update for the latest features and improvements.": "",
 	"Update password": "Uppdatera lösenord",
 	"Update password": "Uppdatera lösenord",
 	"Updated at": "",
 	"Updated at": "",
 	"Upload": "",
 	"Upload": "",

+ 4 - 0
src/lib/i18n/locales/th-TH/translation.json

@@ -9,6 +9,7 @@
 	"{{user}}'s Chats": "การสนทนาของ {{user}}",
 	"{{user}}'s Chats": "การสนทนาของ {{user}}",
 	"{{webUIName}} Backend Required": "ต้องการ Backend ของ {{webUIName}}",
 	"{{webUIName}} Backend Required": "ต้องการ Backend ของ {{webUIName}}",
 	"*Prompt node ID(s) are required for image generation": "",
 	"*Prompt node ID(s) are required for image generation": "",
+	"A new version (v{{LATEST_VERSION}}) is now available.": "",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "ใช้โมเดลงานเมื่อทำงานเช่นการสร้างหัวข้อสำหรับการสนทนาและการค้นหาเว็บ",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "ใช้โมเดลงานเมื่อทำงานเช่นการสร้างหัวข้อสำหรับการสนทนาและการค้นหาเว็บ",
 	"a user": "ผู้ใช้",
 	"a user": "ผู้ใช้",
 	"About": "เกี่ยวกับ",
 	"About": "เกี่ยวกับ",
@@ -465,6 +466,7 @@
 	"Oops! Looks like the URL is invalid. Please double-check and try again.": "อุ๊บส์! ดูเหมือนว่า URL ไม่ถูกต้อง กรุณาตรวจสอบและลองใหม่อีกครั้ง",
 	"Oops! Looks like the URL is invalid. Please double-check and try again.": "อุ๊บส์! ดูเหมือนว่า URL ไม่ถูกต้อง กรุณาตรวจสอบและลองใหม่อีกครั้ง",
 	"Oops! There was an error in the previous response. Please try again or contact admin.": "อุ๊บส์! มีข้อผิดพลาดในคำตอบก่อนหน้า กรุณาลองใหม่อีกครั้งหรือติดต่อผู้ดูแลระบบ",
 	"Oops! There was an error in the previous response. Please try again or contact admin.": "อุ๊บส์! มีข้อผิดพลาดในคำตอบก่อนหน้า กรุณาลองใหม่อีกครั้งหรือติดต่อผู้ดูแลระบบ",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "อุ๊บส์! คุณกำลังใช้วิธีที่ไม่รองรับ (เฉพาะเว็บส่วนหน้า) กรุณาให้บริการ WebUI จากเว็บส่วนแบ็กเอนด์",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "อุ๊บส์! คุณกำลังใช้วิธีที่ไม่รองรับ (เฉพาะเว็บส่วนหน้า) กรุณาให้บริการ WebUI จากเว็บส่วนแบ็กเอนด์",
+	"Open file": "",
 	"Open new chat": "เปิดแชทใหม่",
 	"Open new chat": "เปิดแชทใหม่",
 	"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "เวอร์ชั่น Open WebUI (v{{OPEN_WEBUI_VERSION}}) ต่ำกว่าเวอร์ชั่นที่ต้องการ (v{{REQUIRED_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": "OpenAI",
@@ -476,6 +478,7 @@
 	"Other": "อื่น ๆ",
 	"Other": "อื่น ๆ",
 	"Output format": "",
 	"Output format": "",
 	"Overview": "",
 	"Overview": "",
+	"page": "",
 	"Password": "รหัสผ่าน",
 	"Password": "รหัสผ่าน",
 	"PDF document (.pdf)": "เอกสาร PDF (.pdf)",
 	"PDF document (.pdf)": "เอกสาร PDF (.pdf)",
 	"PDF Extract Images (OCR)": "การแยกรูปภาพจาก PDF (OCR)",
 	"PDF Extract Images (OCR)": "การแยกรูปภาพจาก PDF (OCR)",
@@ -699,6 +702,7 @@
 	"Unpin": "ยกเลิกการปักหมุด",
 	"Unpin": "ยกเลิกการปักหมุด",
 	"Update": "อัปเดต",
 	"Update": "อัปเดต",
 	"Update and Copy Link": "อัปเดตและคัดลอกลิงก์",
 	"Update and Copy Link": "อัปเดตและคัดลอกลิงก์",
+	"Update for the latest features and improvements.": "",
 	"Update password": "อัปเดตรหัสผ่าน",
 	"Update password": "อัปเดตรหัสผ่าน",
 	"Updated at": "อัปเดตเมื่อ",
 	"Updated at": "อัปเดตเมื่อ",
 	"Upload": "อัปโหลด",
 	"Upload": "อัปโหลด",

+ 4 - 0
src/lib/i18n/locales/tk-TW/translation.json

@@ -9,6 +9,7 @@
 	"{{user}}'s Chats": "",
 	"{{user}}'s Chats": "",
 	"{{webUIName}} Backend Required": "",
 	"{{webUIName}} Backend Required": "",
 	"*Prompt node ID(s) are required for image generation": "",
 	"*Prompt node ID(s) are required for image generation": "",
+	"A new version (v{{LATEST_VERSION}}) is now available.": "",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "",
 	"a user": "",
 	"a user": "",
 	"About": "",
 	"About": "",
@@ -465,6 +466,7 @@
 	"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 was an error in the previous response. Please try again or contact admin.": "",
 	"Oops! There was an error in the previous response. Please try again or contact admin.": "",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "",
+	"Open file": "",
 	"Open new chat": "",
 	"Open new chat": "",
 	"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "",
 	"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "",
 	"OpenAI": "",
 	"OpenAI": "",
@@ -476,6 +478,7 @@
 	"Other": "",
 	"Other": "",
 	"Output format": "",
 	"Output format": "",
 	"Overview": "",
 	"Overview": "",
+	"page": "",
 	"Password": "",
 	"Password": "",
 	"PDF document (.pdf)": "",
 	"PDF document (.pdf)": "",
 	"PDF Extract Images (OCR)": "",
 	"PDF Extract Images (OCR)": "",
@@ -699,6 +702,7 @@
 	"Unpin": "",
 	"Unpin": "",
 	"Update": "",
 	"Update": "",
 	"Update and Copy Link": "",
 	"Update and Copy Link": "",
+	"Update for the latest features and improvements.": "",
 	"Update password": "",
 	"Update password": "",
 	"Updated at": "",
 	"Updated at": "",
 	"Upload": "",
 	"Upload": "",

+ 119 - 115
src/lib/i18n/locales/tr-TR/translation.json

@@ -1,37 +1,38 @@
 {
 {
 	"'s', 'm', 'h', 'd', 'w' or '-1' for no expiration.": "'s', 'm', 'h', 'd', 'w' veya süresiz için '-1'.",
 	"'s', 'm', 'h', 'd', 'w' or '-1' for no expiration.": "'s', 'm', 'h', 'd', 'w' veya süresiz için '-1'.",
 	"(Beta)": "(Beta)",
 	"(Beta)": "(Beta)",
-	"(e.g. `sh webui.sh --api --api-auth username_password`)": "(e.g. `sh webui.sh --api --api-auth username_password`)",
+	"(e.g. `sh webui.sh --api --api-auth username_password`)": "(örn. `sh webui.sh --api --api-auth username_password`)",
 	"(e.g. `sh webui.sh --api`)": "(örn. `sh webui.sh --api`)",
 	"(e.g. `sh webui.sh --api`)": "(örn. `sh webui.sh --api`)",
 	"(latest)": "(en son)",
 	"(latest)": "(en son)",
 	"{{ models }}": "{{ models }}",
 	"{{ models }}": "{{ models }}",
 	"{{ owner }}: You cannot delete a base model": "{{ owner }}: Temel modeli silemezsiniz",
 	"{{ owner }}: You cannot delete a base model": "{{ owner }}: Temel modeli silemezsiniz",
-	"{{user}}'s Chats": "{{user}} Sohbetleri",
-	"{{webUIName}} Backend Required": "{{webUIName}} Arkayüz Gerekli",
-	"*Prompt node ID(s) are required for image generation": "",
+	"{{user}}'s Chats": "{{user}}'ın Sohbetleri",
+	"{{webUIName}} Backend Required": "{{webUIName}} Arka-uç Gerekli",
+	"*Prompt node ID(s) are required for image generation": "*Görüntü oluşturma için düğüm kimlikleri gereklidir",
+	"A new version (v{{LATEST_VERSION}}) is now available.": "",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "Bir görev modeli, sohbetler ve web arama sorguları için başlık oluşturma gibi görevleri yerine getirirken kullanılır",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "Bir görev modeli, sohbetler ve web arama sorguları için başlık oluşturma gibi görevleri yerine getirirken kullanılır",
 	"a user": "bir kullanıcı",
 	"a user": "bir kullanıcı",
 	"About": "Hakkında",
 	"About": "Hakkında",
 	"Account": "Hesap",
 	"Account": "Hesap",
 	"Account Activation Pending": "Hesap Aktivasyonu Bekleniyor",
 	"Account Activation Pending": "Hesap Aktivasyonu Bekleniyor",
 	"Accurate information": "Doğru bilgi",
 	"Accurate information": "Doğru bilgi",
-	"Actions": "",
+	"Actions": "Aksiyonlar",
 	"Active Users": "Aktif Kullanıcılar",
 	"Active Users": "Aktif Kullanıcılar",
 	"Add": "Ekle",
 	"Add": "Ekle",
-	"Add a model id": "Model id ekle",
-	"Add a short description about what this model does": "Bu modelin ne yaptığı hakkında kısa bir açıklama ekle",
+	"Add a model id": "Bir model id ekle",
+	"Add a short description about what this model does": "Bu modelin ne yaptığı hakkında kısa bir açıklama ekleyin",
 	"Add a short title for this prompt": "Bu prompt için kısa bir başlık ekleyin",
 	"Add a short title for this prompt": "Bu prompt için kısa bir başlık ekleyin",
 	"Add a tag": "Bir etiket ekleyin",
 	"Add a tag": "Bir etiket ekleyin",
-	"Add custom prompt": "Özel prompt ekle",
-	"Add Docs": "Dökümanlar Ekle",
+	"Add custom prompt": "Özel prompt ekleyin",
+	"Add Docs": "Belgeler Ekle",
 	"Add Files": "Dosyalar Ekle",
 	"Add Files": "Dosyalar Ekle",
 	"Add Memory": "Bellek Ekle",
 	"Add Memory": "Bellek Ekle",
-	"Add message": "Mesaj ekle",
+	"Add message": "Mesaj Ekle",
 	"Add Model": "Model Ekle",
 	"Add Model": "Model Ekle",
-	"Add Tag": "",
-	"Add Tags": "Etiketler ekle",
+	"Add Tag": "Etiket Ekle",
+	"Add Tags": "Etiketler Ekle",
 	"Add User": "Kullanıcı Ekle",
 	"Add User": "Kullanıcı Ekle",
-	"Adjusting these settings will apply changes universally to all users.": "Bu ayarları ayarlamak değişiklikleri tüm kullanıcılara evrensel olarak uygular.",
+	"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": "Yönetici",
 	"Admin": "Yönetici",
 	"Admin Panel": "Yönetici Paneli",
 	"Admin Panel": "Yönetici Paneli",
@@ -44,9 +45,9 @@
 	"All Users": "Tüm Kullanıcılar",
 	"All Users": "Tüm Kullanıcılar",
 	"Allow": "İzin ver",
 	"Allow": "İzin ver",
 	"Allow Chat Deletion": "Sohbet Silmeye İzin Ver",
 	"Allow Chat Deletion": "Sohbet Silmeye İzin Ver",
-	"Allow Chat Editing": "",
+	"Allow Chat Editing": "Soğbet Düzenlemeye İzin Ver",
 	"Allow non-local voices": "Yerel olmayan seslere izin verin",
 	"Allow non-local voices": "Yerel olmayan seslere izin verin",
-	"Allow Temporary Chat": "",
+	"Allow Temporary Chat": "Geçici Sohbetlere İzin Ver",
 	"Allow User Location": "Kullanıcı Konumuna İzin Ver",
 	"Allow User Location": "Kullanıcı Konumuna İzin Ver",
 	"Allow Voice Interruption in Call": "Aramada Ses Kesintisine İzin Ver",
 	"Allow Voice Interruption in Call": "Aramada Ses Kesintisine İzin Ver",
 	"alphanumeric characters and hyphens": "alfanumerik karakterler ve tireler",
 	"alphanumeric characters and hyphens": "alfanumerik karakterler ve tireler",
@@ -73,10 +74,10 @@
 	"AUTOMATIC1111 Api Auth String": "AUTOMATIC1111 API Kimlik Doğrulama Dizesi",
 	"AUTOMATIC1111 Api Auth String": "AUTOMATIC1111 API Kimlik Doğrulama Dizesi",
 	"AUTOMATIC1111 Base URL": "AUTOMATIC1111 Temel URL",
 	"AUTOMATIC1111 Base URL": "AUTOMATIC1111 Temel URL",
 	"AUTOMATIC1111 Base URL is required.": "AUTOMATIC1111 Temel URL gereklidir.",
 	"AUTOMATIC1111 Base URL is required.": "AUTOMATIC1111 Temel URL gereklidir.",
-	"Available list": "",
+	"Available list": "Mevcut liste",
 	"available!": "mevcut!",
 	"available!": "mevcut!",
-	"Azure AI Speech": "",
-	"Azure Region": "",
+	"Azure AI Speech": "Azure AI Konuşma",
+	"Azure Region": "Azure Bölgesi",
 	"Back": "Geri",
 	"Back": "Geri",
 	"Bad Response": "Kötü Yanıt",
 	"Bad Response": "Kötü Yanıt",
 	"Banners": "Afişler",
 	"Banners": "Afişler",
@@ -94,10 +95,10 @@
 	"Change Password": "Parola Değiştir",
 	"Change Password": "Parola Değiştir",
 	"Chat": "Sohbet",
 	"Chat": "Sohbet",
 	"Chat Background Image": "Sohbet Arka Plan Resmi",
 	"Chat Background Image": "Sohbet Arka Plan Resmi",
-	"Chat Bubble UI": "Sohbet Balonu UI",
-	"Chat Controls": "",
+	"Chat Bubble UI": "Sohbet Balonu Arayüzü",
+	"Chat Controls": "Sohbet Kontrolleri",
 	"Chat direction": "Sohbet Yönü",
 	"Chat direction": "Sohbet Yönü",
-	"Chat Overview": "",
+	"Chat Overview": "Sohbet Genel Bakış",
 	"Chats": "Sohbetler",
 	"Chats": "Sohbetler",
 	"Check Again": "Tekrar Kontrol Et",
 	"Check Again": "Tekrar Kontrol Et",
 	"Check for updates": "Güncellemeleri kontrol et",
 	"Check for updates": "Güncellemeleri kontrol et",
@@ -115,7 +116,7 @@
 	"Click here to select a csv file.": "Bir CSV dosyası seçmek için buraya tıklayın.",
 	"Click here to select a csv file.": "Bir CSV dosyası seçmek için buraya tıklayın.",
 	"Click here to select a py file.": "Bir py dosyası seçmek için buraya tıklayın.",
 	"Click here to select a py file.": "Bir py dosyası seçmek için buraya tıklayın.",
 	"Click here to select documents.": "Belgeleri seçmek için buraya tıklayın.",
 	"Click here to select documents.": "Belgeleri seçmek için buraya tıklayın.",
-	"Click here to upload a workflow.json file.": "",
+	"Click here to upload a workflow.json file.": "Bir workflow.json dosyası yüklemek için buraya tıklayın.",
 	"click here.": "buraya tıklayın.",
 	"click here.": "buraya tıklayın.",
 	"Click on the user role button to change a user's role.": "Bir kullanıcının rolünü değiştirmek için kullanıcı rolü düğmesine tıklayın.",
 	"Click on the user role button to change a user's role.": "Bir kullanıcının rolünü değiştirmek için kullanıcı rolü düğmesine tıklayın.",
 	"Clipboard write permission denied. Please check your browser settings to grant the necessary access.": "Panoya yazma izni reddedildi. Tarayıcı ayarlarını kontrol ederek gerekli izinleri sağlayabilirsiniz.",
 	"Clipboard write permission denied. Please check your browser settings to grant the necessary access.": "Panoya yazma izni reddedildi. Tarayıcı ayarlarını kontrol ederek gerekli izinleri sağlayabilirsiniz.",
@@ -126,8 +127,8 @@
 	"ComfyUI": "ComfyUI",
 	"ComfyUI": "ComfyUI",
 	"ComfyUI Base URL": "ComfyUI Temel URL",
 	"ComfyUI Base URL": "ComfyUI Temel URL",
 	"ComfyUI Base URL is required.": "ComfyUI Temel URL gerekli.",
 	"ComfyUI Base URL is required.": "ComfyUI Temel URL gerekli.",
-	"ComfyUI Workflow": "",
-	"ComfyUI Workflow Nodes": "",
+	"ComfyUI Workflow": "ComfyUI İş Akışı",
+	"ComfyUI Workflow Nodes": "ComfyUI İş Akışı Düğümleri",
 	"Command": "Komut",
 	"Command": "Komut",
 	"Concurrent Requests": "Eşzamanlı İstekler",
 	"Concurrent Requests": "Eşzamanlı İstekler",
 	"Confirm": "Onayla",
 	"Confirm": "Onayla",
@@ -136,17 +137,17 @@
 	"Connections": "Bağlantılar",
 	"Connections": "Bağlantılar",
 	"Contact Admin for WebUI Access": "WebUI Erişimi için Yöneticiyle İletişime Geçin",
 	"Contact Admin for WebUI Access": "WebUI Erişimi için Yöneticiyle İletişime Geçin",
 	"Content": "İçerik",
 	"Content": "İçerik",
-	"Content Extraction": "",
+	"Content Extraction": "İçerik Çıkarma",
 	"Context Length": "Bağlam Uzunluğu",
 	"Context Length": "Bağlam Uzunluğu",
 	"Continue Response": "Yanıta Devam Et",
 	"Continue Response": "Yanıta Devam Et",
 	"Continue with {{provider}}": "{{provider}} ile devam et",
 	"Continue with {{provider}}": "{{provider}} ile devam et",
-	"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.": "",
-	"Controls": "",
-	"Copied": "",
+	"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.": "Mesaj metninin TTS istekleri için nasıl bölüneceğini kontrol edin. 'Noktalama' cümlelere, 'paragraflar' paragraflara böler ve 'hiçbiri' mesajı tek bir dize olarak tutar.",
+	"Controls": "Kontroller",
+	"Copied": "Kopyalandı",
 	"Copied shared chat URL to clipboard!": "Paylaşılan sohbet URL'si panoya kopyalandı!",
 	"Copied shared chat URL to clipboard!": "Paylaşılan sohbet URL'si panoya kopyalandı!",
-	"Copied to clipboard": "",
+	"Copied to clipboard": "Panoya kopyalandı",
 	"Copy": "Kopyala",
 	"Copy": "Kopyala",
-	"Copy Code": "",
+	"Copy Code": "Kodu Kopyala",
 	"Copy last code block": "Son kod bloğunu kopyala",
 	"Copy last code block": "Son kod bloğunu kopyala",
 	"Copy last response": "Son yanıtı kopyala",
 	"Copy last response": "Son yanıtı kopyala",
 	"Copy Link": "Bağlantıyı Kopyala",
 	"Copy Link": "Bağlantıyı Kopyala",
@@ -181,7 +182,7 @@
 	"Delete chat": "Sohbeti sil",
 	"Delete chat": "Sohbeti sil",
 	"Delete Chat": "Sohbeti Sil",
 	"Delete Chat": "Sohbeti Sil",
 	"Delete chat?": "Sohbeti sil?",
 	"Delete chat?": "Sohbeti sil?",
-	"Delete Doc": "",
+	"Delete Doc": "Belgeyi Sil",
 	"Delete function?": "Fonksiyonu sil?",
 	"Delete function?": "Fonksiyonu sil?",
 	"Delete prompt?": "Promptu sil?",
 	"Delete prompt?": "Promptu sil?",
 	"delete this link": "bu bağlantıyı sil",
 	"delete this link": "bu bağlantıyı sil",
@@ -191,7 +192,7 @@
 	"Deleted {{name}}": "{{name}} silindi",
 	"Deleted {{name}}": "{{name}} silindi",
 	"Description": "Açıklama",
 	"Description": "Açıklama",
 	"Didn't fully follow instructions": "Talimatları tam olarak takip etmedi",
 	"Didn't fully follow instructions": "Talimatları tam olarak takip etmedi",
-	"Disabled": "",
+	"Disabled": "Devre Dışı",
 	"Discover a function": "Bir fonksiyon keşfedin",
 	"Discover a function": "Bir fonksiyon keşfedin",
 	"Discover a model": "Bir model keşfedin",
 	"Discover a model": "Bir model keşfedin",
 	"Discover a prompt": "Bir prompt keşfedin",
 	"Discover a prompt": "Bir prompt keşfedin",
@@ -203,16 +204,16 @@
 	"Dismissible": "Reddedilebilir",
 	"Dismissible": "Reddedilebilir",
 	"Display Emoji in Call": "Aramada Emoji Göster",
 	"Display Emoji in Call": "Aramada Emoji Göster",
 	"Display the username instead of You in the Chat": "Sohbet'te Siz yerine kullanıcı adını göster",
 	"Display the username instead of You in the Chat": "Sohbet'te Siz yerine kullanıcı adını göster",
-	"Do not install functions from sources you do not fully trust.": "",
-	"Do not install tools from sources you do not fully trust.": "",
+	"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.",
 	"Document": "Belge",
 	"Document": "Belge",
 	"Documentation": "Dökümantasyon",
 	"Documentation": "Dökümantasyon",
 	"Documents": "Belgeler",
 	"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.",
 	"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.",
 	"Don't Allow": "İzin Verme",
 	"Don't Allow": "İzin Verme",
 	"Don't have an account?": "Hesabınız yok mu?",
 	"Don't have an account?": "Hesabınız yok mu?",
-	"don't install random functions from sources you don't trust.": "",
-	"don't install random tools from sources you don't trust.": "",
+	"don't install random functions from sources you don't trust.": "Tanımadığınız kaynaklardan rastgele fonksiyonlar yüklemeyin.",
+	"don't install random tools from sources you don't trust.": "Tanımadığınız kaynaklardan rastgele araçlar yüklemeyin.",
 	"Don't like the style": "Tarzını beğenmedim",
 	"Don't like the style": "Tarzını beğenmedim",
 	"Done": "Tamamlandı",
 	"Done": "Tamamlandı",
 	"Download": "İndir",
 	"Download": "İndir",
@@ -231,18 +232,18 @@
 	"Embedding Model Engine": "Gömme Modeli Motoru",
 	"Embedding Model Engine": "Gömme Modeli Motoru",
 	"Embedding model set to \"{{embedding_model}}\"": "Gömme modeli \"{{embedding_model}}\" olarak ayarlandı",
 	"Embedding model set to \"{{embedding_model}}\"": "Gömme modeli \"{{embedding_model}}\" olarak ayarlandı",
 	"Enable Community Sharing": "Topluluk Paylaşımını Etkinleştir",
 	"Enable Community Sharing": "Topluluk Paylaşımını Etkinleştir",
-	"Enable Message Rating": "",
+	"Enable Message Rating": "Mesaj Değerlendirmeyi Etkinleştir",
 	"Enable New Sign Ups": "Yeni Kayıtları Etkinleştir",
 	"Enable New Sign Ups": "Yeni Kayıtları Etkinleştir",
 	"Enable Web Search": "Web Aramasını Etkinleştir",
 	"Enable Web Search": "Web Aramasını Etkinleştir",
-	"Enable Web Search Query Generation": "",
-	"Enabled": "",
-	"Engine": "",
+	"Enable Web Search Query Generation": "Web Arama Sorgusu Oluşturmayı Etkinleştir",
+	"Enabled": "Etkin",
+	"Engine": "Motor",
 	"Ensure your CSV file includes 4 columns in this order: Name, Email, Password, Role.": "CSV dosyanızın şu sırayla 4 sütun içerdiğinden emin olun: İsim, E-posta, Şifre, Rol.",
 	"Ensure your CSV file includes 4 columns in this order: Name, Email, Password, Role.": "CSV dosyanızın şu sırayla 4 sütun içerdiğinden emin olun: İsim, E-posta, Şifre, Rol.",
 	"Enter {{role}} message here": "Buraya {{role}} mesajını girin",
 	"Enter {{role}} message here": "Buraya {{role}} mesajını girin",
 	"Enter a detail about yourself for your LLMs to recall": "LLM'lerinizin hatırlaması için kendiniz hakkında bir bilgi girin",
 	"Enter a detail about yourself for your LLMs to recall": "LLM'lerinizin hatırlaması için kendiniz hakkında bir bilgi girin",
 	"Enter api auth string (e.g. username:password)": "Api auth dizesini girin (örn. kullanıcı adı:parola)",
 	"Enter api auth string (e.g. username:password)": "Api auth dizesini girin (örn. kullanıcı adı:parola)",
 	"Enter Brave Search API Key": "Brave Search API Anahtarını Girin",
 	"Enter Brave Search API Key": "Brave Search API Anahtarını Girin",
-	"Enter CFG Scale (e.g. 7.0)": "",
+	"Enter CFG Scale (e.g. 7.0)": "CFG Ölçeğini Girin (örn. 7.0)",
 	"Enter Chunk Overlap": "Chunk Örtüşmesini Girin",
 	"Enter Chunk Overlap": "Chunk Örtüşmesini Girin",
 	"Enter Chunk Size": "Chunk Boyutunu Girin",
 	"Enter Chunk Size": "Chunk Boyutunu Girin",
 	"Enter Github Raw URL": "Github Raw URL'sini girin",
 	"Enter Github Raw URL": "Github Raw URL'sini girin",
@@ -250,28 +251,28 @@
 	"Enter Google PSE Engine Id": "Google PSE Engine Id'sini Girin",
 	"Enter Google PSE Engine Id": "Google PSE Engine Id'sini Girin",
 	"Enter Image Size (e.g. 512x512)": "Görüntü Boyutunu Girin (örn. 512x512)",
 	"Enter Image Size (e.g. 512x512)": "Görüntü Boyutunu Girin (örn. 512x512)",
 	"Enter language codes": "Dil kodlarını girin",
 	"Enter language codes": "Dil kodlarını girin",
-	"Enter Model ID": "",
+	"Enter Model ID": "Model ID'sini Girin",
 	"Enter model tag (e.g. {{modelTag}})": "Model etiketini girin (örn. {{modelTag}})",
 	"Enter model tag (e.g. {{modelTag}})": "Model etiketini girin (örn. {{modelTag}})",
 	"Enter Number of Steps (e.g. 50)": "Adım Sayısını Girin (örn. 50)",
 	"Enter Number of Steps (e.g. 50)": "Adım Sayısını Girin (örn. 50)",
-	"Enter Sampler (e.g. Euler a)": "",
-	"Enter Scheduler (e.g. Karras)": "",
+	"Enter Sampler (e.g. Euler a)": "Örnekleyiciyi Girin (örn. Euler a)",
+	"Enter Scheduler (e.g. Karras)": "Zamanlayıcıyı Girin (örn. Karras)",
 	"Enter Score": "Skoru Girin",
 	"Enter Score": "Skoru Girin",
-	"Enter SearchApi API Key": "",
-	"Enter SearchApi Engine": "",
+	"Enter SearchApi API Key": "Arama-API Anahtarını Girin",
+	"Enter SearchApi Engine": "Arama-API Motorunu Girin",
 	"Enter Searxng Query URL": "Searxng Sorgu URL'sini girin",
 	"Enter Searxng Query URL": "Searxng Sorgu URL'sini girin",
 	"Enter Serper API Key": "Serper API Anahtarını Girin",
 	"Enter Serper API Key": "Serper API Anahtarını Girin",
 	"Enter Serply API Key": "Serply API Anahtarını Girin",
 	"Enter Serply API Key": "Serply API Anahtarını Girin",
 	"Enter Serpstack API Key": "Serpstack API Anahtarını Girin",
 	"Enter Serpstack API Key": "Serpstack API Anahtarını Girin",
 	"Enter stop sequence": "Durdurma dizisini girin",
 	"Enter stop sequence": "Durdurma dizisini girin",
-	"Enter system prompt": "",
+	"Enter system prompt": "Sistem promptunu girin",
 	"Enter Tavily API Key": "Tavily API Anahtarını Girin",
 	"Enter Tavily API Key": "Tavily API Anahtarını Girin",
-	"Enter Tika Server URL": "",
+	"Enter Tika Server URL": "Tika Sunucu URL'sini Girin",
 	"Enter Top K": "Top K'yı girin",
 	"Enter Top K": "Top K'yı girin",
 	"Enter URL (e.g. http://127.0.0.1:7860/)": "URL'yi Girin (örn. http://127.0.0.1:7860/)",
 	"Enter URL (e.g. http://127.0.0.1:7860/)": "URL'yi Girin (örn. http://127.0.0.1:7860/)",
 	"Enter URL (e.g. http://localhost:11434)": "URL'yi Girin (e.g. http://localhost:11434)",
 	"Enter URL (e.g. http://localhost:11434)": "URL'yi Girin (e.g. http://localhost:11434)",
 	"Enter Your Email": "E-postanızı Girin",
 	"Enter Your Email": "E-postanızı Girin",
 	"Enter Your Full Name": "Tam Adınızı Girin",
 	"Enter Your Full Name": "Tam Adınızı Girin",
-	"Enter your message": "",
+	"Enter your message": "Mesajınızı girin",
 	"Enter Your Password": "Parolanızı Girin",
 	"Enter Your Password": "Parolanızı Girin",
 	"Enter Your Role": "Rolünüzü Girin",
 	"Enter Your Role": "Rolünüzü Girin",
 	"Error": "Hata",
 	"Error": "Hata",
@@ -296,8 +297,8 @@
 	"File": "Dosya",
 	"File": "Dosya",
 	"File Mode": "Dosya Modu",
 	"File Mode": "Dosya Modu",
 	"File not found.": "Dosya bulunamadı.",
 	"File not found.": "Dosya bulunamadı.",
-	"File size should not exceed {{maxSize}} MB.": "",
-	"Files": "",
+	"File size should not exceed {{maxSize}} MB.": "Dosya boyutu {{maxSize}} MB'yi aşmamalıdır.",
+	"Files": "Dosyalar",
 	"Filter is now globally disabled": "Filtre artık global olarak devre dışı",
 	"Filter is now globally disabled": "Filtre artık global olarak devre dışı",
 	"Filter is now globally enabled": "Filtre artık global olarak devrede",
 	"Filter is now globally enabled": "Filtre artık global olarak devrede",
 	"Filters": "Filtreler",
 	"Filters": "Filtreler",
@@ -310,28 +311,28 @@
 	"Frequency Penalty": "Frekans Cezası",
 	"Frequency Penalty": "Frekans Cezası",
 	"Function created successfully": "Fonksiyon başarıyla oluşturuldu",
 	"Function created successfully": "Fonksiyon başarıyla oluşturuldu",
 	"Function deleted successfully": "Fonksiyon başarıyla silindi",
 	"Function deleted successfully": "Fonksiyon başarıyla silindi",
-	"Function Description (e.g. A filter to remove profanity from text)": "",
-	"Function ID (e.g. my_filter)": "",
-	"Function is now globally disabled": "",
-	"Function is now globally enabled": "",
-	"Function Name (e.g. My Filter)": "",
+	"Function Description (e.g. A filter to remove profanity from text)": "Fonksiyon Açıklaması (örn. Metinden küfürleri kaldıran bir filtre)",
+	"Function ID (e.g. my_filter)": "Fonksiyon ID'si (örn. my_filter)",
+	"Function is now globally disabled": "Fonksiyon artık global olarak devre dışı",
+	"Function is now globally enabled": "Fonksiyon artık global olarak aktif",
+	"Function Name (e.g. My Filter)": "Fonksiyon Adı (örn. Benim Filtrem)",
 	"Function updated successfully": "Fonksiyon başarıyla güncellendi",
 	"Function updated successfully": "Fonksiyon başarıyla güncellendi",
 	"Functions": "Fonksiyonlar",
 	"Functions": "Fonksiyonlar",
-	"Functions allow arbitrary code execution": "",
-	"Functions allow arbitrary code execution.": "",
+	"Functions allow arbitrary code execution": "Fonksiyonlar keyfi kod yürütülmesine izin verir",
+	"Functions allow arbitrary code execution.": "Fonksiyonlar keyfi kod yürütülmesine izin verir.",
 	"Functions imported successfully": "Fonksiyonlar başarıyla içe aktarıldı",
 	"Functions imported successfully": "Fonksiyonlar başarıyla içe aktarıldı",
 	"General": "Genel",
 	"General": "Genel",
 	"General Settings": "Genel Ayarlar",
 	"General Settings": "Genel Ayarlar",
 	"Generate Image": "Görsel Üret",
 	"Generate Image": "Görsel Üret",
 	"Generating search query": "Arama sorgusu oluşturma",
 	"Generating search query": "Arama sorgusu oluşturma",
 	"Generation Info": "Üretim Bilgisi",
 	"Generation Info": "Üretim Bilgisi",
-	"Get up and running with": "",
-	"Global": "Global",
+	"Get up and running with": "ile çalışmaya başlayın",
+	"Global": "Evrensel",
 	"Good Response": "İyi Yanıt",
 	"Good Response": "İyi Yanıt",
 	"Google PSE API Key": "Google PSE API Anahtarı",
 	"Google PSE API Key": "Google PSE API Anahtarı",
 	"Google PSE Engine Id": "Google PSE Engine Id",
 	"Google PSE Engine Id": "Google PSE Engine Id",
 	"h:mm a": "h:mm a",
 	"h:mm a": "h:mm a",
-	"Haptic Feedback": "",
+	"Haptic Feedback": "Dokunsal Geri Bildirim",
 	"has no conversations.": "hiç konuşması yok.",
 	"has no conversations.": "hiç konuşması yok.",
 	"Hello, {{name}}": "Merhaba, {{name}}",
 	"Hello, {{name}}": "Merhaba, {{name}}",
 	"Help": "Yardım",
 	"Help": "Yardım",
@@ -339,7 +340,7 @@
 	"Hide Model": "Modeli Gizle",
 	"Hide Model": "Modeli Gizle",
 	"How can I help you today?": "Bugün size nasıl yardımcı olabilirim?",
 	"How can I help you today?": "Bugün size nasıl yardımcı olabilirim?",
 	"Hybrid Search": "Karma Arama",
 	"Hybrid Search": "Karma Arama",
-	"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.": "",
+	"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.": "Eylemimin sonuçlarını okuduğumu ve anladığımı kabul ediyorum. Rastgele kod çalıştırmayla ilgili risklerin farkındayım ve kaynağın güvenilirliğini doğruladım.",
 	"Image Generation (Experimental)": "Görüntü Oluşturma (Deneysel)",
 	"Image Generation (Experimental)": "Görüntü Oluşturma (Deneysel)",
 	"Image Generation Engine": "Görüntü Oluşturma Motoru",
 	"Image Generation Engine": "Görüntü Oluşturma Motoru",
 	"Image Settings": "Görüntü Ayarları",
 	"Image Settings": "Görüntü Ayarları",
@@ -371,27 +372,27 @@
 	"Keyboard shortcuts": "Klavye kısayolları",
 	"Keyboard shortcuts": "Klavye kısayolları",
 	"Knowledge": "Bilgi",
 	"Knowledge": "Bilgi",
 	"Language": "Dil",
 	"Language": "Dil",
-	"large language models, locally.": "",
+	"large language models, locally.": "büyük dil modelleri, yerel olarak.",
 	"Last Active": "Son Aktivite",
 	"Last Active": "Son Aktivite",
 	"Last Modified": "Son Düzenleme",
 	"Last Modified": "Son Düzenleme",
 	"Leave empty for unlimited": "",
 	"Leave empty for unlimited": "",
-	"Leave empty to use the default prompt, or enter a custom prompt": "",
+	"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",
 	"Light": "Açık",
 	"Light": "Açık",
 	"Listening...": "Dinleniyor...",
 	"Listening...": "Dinleniyor...",
 	"LLMs can make mistakes. Verify important information.": "LLM'ler hata yapabilir. Önemli bilgileri doğrulayın.",
 	"LLMs can make mistakes. Verify important information.": "LLM'ler hata yapabilir. Önemli bilgileri doğrulayın.",
 	"Local Models": "Yerel Modeller",
 	"Local Models": "Yerel Modeller",
-	"LTR": "LTR",
+	"LTR": "Soldan Sağa",
 	"Made by OpenWebUI Community": "OpenWebUI Topluluğu tarafından yapılmıştır",
 	"Made by OpenWebUI Community": "OpenWebUI Topluluğu tarafından yapılmıştır",
 	"Make sure to enclose them with": "Değişkenlerinizi şu şekilde biçimlendirin:",
 	"Make sure to enclose them with": "Değişkenlerinizi şu şekilde biçimlendirin:",
-	"Make sure to export a workflow.json file as API format from ComfyUI.": "",
+	"Make sure to export a workflow.json file as API format from ComfyUI.": "ComfyUI'dan API formatında bir workflow.json dosyası olarak dışa aktardığınızdan emin olun.",
 	"Manage": "Yönet",
 	"Manage": "Yönet",
 	"Manage Models": "Modelleri Yönet",
 	"Manage Models": "Modelleri Yönet",
 	"Manage Ollama Models": "Ollama Modellerini Yönet",
 	"Manage Ollama Models": "Ollama Modellerini Yönet",
 	"Manage Pipelines": "Pipelineları Yönet",
 	"Manage Pipelines": "Pipelineları Yönet",
 	"March": "Mart",
 	"March": "Mart",
 	"Max Tokens (num_predict)": "Maksimum Token (num_predict)",
 	"Max Tokens (num_predict)": "Maksimum Token (num_predict)",
-	"Max Upload Count": "",
-	"Max Upload Size": "",
+	"Max Upload Count": "Maksimum Yükleme Sayısı",
+	"Max Upload Size": "Maksimum Yükleme Boyutu",
 	"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.",
 	"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",
 	"May": "Mayıs",
 	"Memories accessible by LLMs will be shown here.": "LLM'ler tarafından erişilebilen bellekler burada gösterilecektir.",
 	"Memories accessible by LLMs will be shown here.": "LLM'ler tarafından erişilebilen bellekler burada gösterilecektir.",
@@ -400,9 +401,9 @@
 	"Memory cleared successfully": "Bellek başarıyle temizlendi",
 	"Memory cleared successfully": "Bellek başarıyle temizlendi",
 	"Memory deleted successfully": "Bellek başarıyla silindi",
 	"Memory deleted successfully": "Bellek başarıyla silindi",
 	"Memory updated successfully": "Bellek başarıyla güncellendi",
 	"Memory updated successfully": "Bellek başarıyla güncellendi",
-	"Merge Responses": "",
+	"Merge Responses": "Yanıtları Birleştir",
 	"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.",
 	"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.",
-	"Min P": "",
+	"Min P": "Min P",
 	"Minimum Score": "Minimum Skor",
 	"Minimum Score": "Minimum Skor",
 	"Mirostat": "Mirostat",
 	"Mirostat": "Mirostat",
 	"Mirostat Eta": "Mirostat Eta",
 	"Mirostat Eta": "Mirostat Eta",
@@ -415,8 +416,8 @@
 	"Model {{modelId}} not found": "{{modelId}} bulunamadı",
 	"Model {{modelId}} not found": "{{modelId}} bulunamadı",
 	"Model {{modelName}} is not vision capable": "Model {{modelName}} görüntü yeteneğine sahip değil",
 	"Model {{modelName}} is not vision capable": "Model {{modelName}} görüntü yeteneğine sahip değil",
 	"Model {{name}} is now {{status}}": "{{name}} modeli artık {{status}}",
 	"Model {{name}} is now {{status}}": "{{name}} modeli artık {{status}}",
-	"Model {{name}} is now at the top": "",
-	"Model accepts image inputs": "",
+	"Model {{name}} is now at the top": "{{name}} modeli artık en üstte",
+	"Model accepts image inputs": "Model görüntü girdilerini kabul eder",
 	"Model created successfully!": "Model başarıyla oluşturuldu!",
 	"Model created successfully!": "Model başarıyla oluşturuldu!",
 	"Model filesystem path detected. Model shortname is required for update, cannot continue.": "Model dosya sistemi yolu algılandı. Güncelleme için model kısa adı gerekli, devam edilemiyor.",
 	"Model filesystem path detected. Model shortname is required for update, cannot continue.": "Model dosya sistemi yolu algılandı. Güncelleme için model kısa adı gerekli, devam edilemiyor.",
 	"Model ID": "Model ID",
 	"Model ID": "Model ID",
@@ -428,7 +429,7 @@
 	"Modelfile Content": "Model Dosyası İçeriği",
 	"Modelfile Content": "Model Dosyası İçeriği",
 	"Models": "Modeller",
 	"Models": "Modeller",
 	"More": "Daha Fazla",
 	"More": "Daha Fazla",
-	"Move to Top": "",
+	"Move to Top": "En Üste Taşı",
 	"Name": "Ad",
 	"Name": "Ad",
 	"Name Tag": "Ad Etiketi",
 	"Name Tag": "Ad Etiketi",
 	"Name your model": "Modelinizi Adlandırın",
 	"Name your model": "Modelinizi Adlandırın",
@@ -465,8 +466,9 @@
 	"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! 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 was an error in the previous response. Please try again or contact admin.": "Hop! Önceki yanıtta bir hata oluştu. Lütfen tekrar deneyin veya yönetici ile iletişime geçin.",
 	"Oops! There was an error in the previous response. Please try again or contact admin.": "Hop! Önceki yanıtta bir hata oluştu. Lütfen tekrar deneyin veya yönetici ile iletişime geçin.",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "Hop! Desteklenmeyen bir yöntem kullanıyorsunuz (yalnızca önyüz). Lütfen WebUI'yi arkayüzden sunun.",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "Hop! Desteklenmeyen bir yöntem kullanıyorsunuz (yalnızca önyüz). Lütfen WebUI'yi arkayüzden sunun.",
+	"Open file": "",
 	"Open new chat": "Yeni sohbet aç",
 	"Open new chat": "Yeni sohbet aç",
-	"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_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": "OpenAI",
 	"OpenAI API": "OpenAI API",
 	"OpenAI API": "OpenAI API",
 	"OpenAI API Config": "OpenAI API Konfigürasyonu",
 	"OpenAI API Config": "OpenAI API Konfigürasyonu",
@@ -474,8 +476,9 @@
 	"OpenAI URL/Key required.": "OpenAI URL/Anahtar gereklidir.",
 	"OpenAI URL/Key required.": "OpenAI URL/Anahtar gereklidir.",
 	"or": "veya",
 	"or": "veya",
 	"Other": "Diğer",
 	"Other": "Diğer",
-	"Output format": "",
-	"Overview": "",
+	"Output format": "Çıktı formatı",
+	"Overview": "Genel Bakış",
+	"page": "",
 	"Password": "Parola",
 	"Password": "Parola",
 	"PDF document (.pdf)": "PDF belgesi (.pdf)",
 	"PDF document (.pdf)": "PDF belgesi (.pdf)",
 	"PDF Extract Images (OCR)": "PDF Görüntülerini Çıkart (OCR)",
 	"PDF Extract Images (OCR)": "PDF Görüntülerini Çıkart (OCR)",
@@ -484,8 +487,8 @@
 	"Permission denied when accessing microphone": "Mikrofona erişim izni reddedildi",
 	"Permission denied when accessing microphone": "Mikrofona erişim izni reddedildi",
 	"Permission denied when accessing microphone: {{error}}": "Mikrofona erişim izni reddedildi: {{error}}",
 	"Permission denied when accessing microphone: {{error}}": "Mikrofona erişim izni reddedildi: {{error}}",
 	"Personalization": "Kişiselleştirme",
 	"Personalization": "Kişiselleştirme",
-	"Pin": "",
-	"Pinned": "",
+	"Pin": "Sabitle",
+	"Pinned": "Sabitlenmiş",
 	"Pipeline deleted successfully": "Pipeline başarıyla silindi",
 	"Pipeline deleted successfully": "Pipeline başarıyla silindi",
 	"Pipeline downloaded successfully": "Pipeline başarıyla güncellendi",
 	"Pipeline downloaded successfully": "Pipeline başarıyla güncellendi",
 	"Pipelines": "Pipelinelar",
 	"Pipelines": "Pipelinelar",
@@ -493,7 +496,7 @@
 	"Pipelines Valves": "Pipeline Valvleri",
 	"Pipelines Valves": "Pipeline Valvleri",
 	"Plain text (.txt)": "Düz metin (.txt)",
 	"Plain text (.txt)": "Düz metin (.txt)",
 	"Playground": "Oyun Alanı",
 	"Playground": "Oyun Alanı",
-	"Please carefully review the following warnings:": "",
+	"Please carefully review the following warnings:": "Lütfen aşağıdaki uyarıları dikkatlice inceleyin:",
 	"Positive attitude": "Olumlu yaklaşım",
 	"Positive attitude": "Olumlu yaklaşım",
 	"Previous 30 days": "Önceki 30 gün",
 	"Previous 30 days": "Önceki 30 gün",
 	"Previous 7 days": "Önceki 7 gün",
 	"Previous 7 days": "Önceki 7 gün",
@@ -527,24 +530,24 @@
 	"Reset Vector Storage": "Vektör Depolamayı Sıfırla",
 	"Reset Vector Storage": "Vektör Depolamayı Sıfırla",
 	"Response AutoCopy to Clipboard": "Yanıtı Panoya Otomatik Kopyala",
 	"Response AutoCopy to Clipboard": "Yanıtı Panoya Otomatik Kopyala",
 	"Response notifications cannot be activated as the website permissions have been denied. Please visit your browser settings to grant the necessary access.": "Web sitesi izinleri reddedildiğinden yanıt bildirimleri etkinleştirilemiyor. Gerekli erişimi sağlamak için lütfen tarayıcı ayarlarınızı ziyaret edin.",
 	"Response notifications cannot be activated as the website permissions have been denied. Please visit your browser settings to grant the necessary access.": "Web sitesi izinleri reddedildiğinden yanıt bildirimleri etkinleştirilemiyor. Gerekli erişimi sağlamak için lütfen tarayıcı ayarlarınızı ziyaret edin.",
-	"Response splitting": "",
+	"Response splitting": "Yanıt bölme",
 	"Role": "Rol",
 	"Role": "Rol",
 	"Rosé Pine": "Rosé Pine",
 	"Rosé Pine": "Rosé Pine",
 	"Rosé Pine Dawn": "Rosé Pine Dawn",
 	"Rosé Pine Dawn": "Rosé Pine Dawn",
-	"RTL": "RTL",
-	"Run": "",
-	"Run Llama 2, Code Llama, and other models. Customize and create your own.": "",
+	"RTL": "Sağdan Sola",
+	"Run": "Çalıştır",
+	"Run Llama 2, Code Llama, and other models. Customize and create your own.": "Llama 2, Code Llama ve diğer modelleri çalıştırın. Kendinize özgü hale getirin ve kendi modelinizi oluşturun.",
 	"Running": "Çalışıyor",
 	"Running": "Çalışıyor",
 	"Save": "Kaydet",
 	"Save": "Kaydet",
 	"Save & Create": "Kaydet ve Oluştur",
 	"Save & Create": "Kaydet ve Oluştur",
 	"Save & Update": "Kaydet ve Güncelle",
 	"Save & Update": "Kaydet ve Güncelle",
-	"Save As Copy": "",
-	"Save Tag": "",
+	"Save As Copy": "Kopya Olarak Kaydet",
+	"Save Tag": "Etiketi Kaydet",
 	"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": "Sohbet kayıtlarının doğrudan tarayıcınızın depolama alanına kaydedilmesi artık desteklenmemektedir. Lütfen aşağıdaki butona tıklayarak sohbet kayıtlarınızı indirmek ve silmek için bir dakikanızı ayırın. Endişelenmeyin, sohbet günlüklerinizi arkayüze kolayca yeniden aktarabilirsiniz:",
 	"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": "Sohbet kayıtlarının doğrudan tarayıcınızın depolama alanına kaydedilmesi artık desteklenmemektedir. Lütfen aşağıdaki butona tıklayarak sohbet kayıtlarınızı indirmek ve silmek için bir dakikanızı ayırın. Endişelenmeyin, sohbet günlüklerinizi arkayüze kolayca yeniden aktarabilirsiniz:",
 	"Scan": "Tarama",
 	"Scan": "Tarama",
 	"Scan complete!": "Tarama tamamlandı!",
 	"Scan complete!": "Tarama tamamlandı!",
 	"Scan for documents from {{path}}": "{{path}} dizininden belgeleri tarayın",
 	"Scan for documents from {{path}}": "{{path}} dizininden belgeleri tarayın",
-	"Scroll to bottom when switching between branches": "",
+	"Scroll to bottom when switching between branches": "Dallar arasında geçiş yaparken en alta kaydır",
 	"Search": "Ara",
 	"Search": "Ara",
 	"Search a model": "Bir model ara",
 	"Search a model": "Bir model ara",
 	"Search Chats": "Sohbetleri Ara",
 	"Search Chats": "Sohbetleri Ara",
@@ -555,12 +558,12 @@
 	"Search Query Generation Prompt": "Arama Sorgusu Üretme Promptu",
 	"Search Query Generation Prompt": "Arama Sorgusu Üretme Promptu",
 	"Search Result Count": "Arama Sonucu Sayısı",
 	"Search Result Count": "Arama Sonucu Sayısı",
 	"Search Tools": "Arama Araçları",
 	"Search Tools": "Arama Araçları",
-	"SearchApi API Key": "",
-	"SearchApi Engine": "",
+	"SearchApi API Key": "Arama-API API Anahtarı",
+	"SearchApi Engine": "Arama-API Motoru",
 	"Searched {{count}} sites_one": "Arandı {{count}} sites_one",
 	"Searched {{count}} sites_one": "Arandı {{count}} sites_one",
 	"Searched {{count}} sites_other": "Arandı {{count}} sites_other",
 	"Searched {{count}} sites_other": "Arandı {{count}} sites_other",
 	"Searching \"{{searchQuery}}\"": "\"{{searchQuery}}\" aranıyor",
 	"Searching \"{{searchQuery}}\"": "\"{{searchQuery}}\" aranıyor",
-	"Searching Knowledge for \"{{searchQuery}}\"": "",
+	"Searching Knowledge for \"{{searchQuery}}\"": "\"{{searchQuery}}\" için Bilgi aranıyor",
 	"Searxng Query URL": "Searxng Sorgu URL'si",
 	"Searxng Query URL": "Searxng Sorgu URL'si",
 	"See readme.md for instructions": "Yönergeler için readme.md dosyasına bakın",
 	"See readme.md for instructions": "Yönergeler için readme.md dosyasına bakın",
 	"See what's new": "Yeniliklere göz atın",
 	"See what's new": "Yeniliklere göz atın",
@@ -574,27 +577,27 @@
 	"Select a tool": "Bir araç seç",
 	"Select a tool": "Bir araç seç",
 	"Select an Ollama instance": "Bir Ollama örneği seçin",
 	"Select an Ollama instance": "Bir Ollama örneği seçin",
 	"Select Documents": "Bir Doküman Seç",
 	"Select Documents": "Bir Doküman Seç",
-	"Select Engine": "",
+	"Select Engine": "Motor Seç",
 	"Select model": "Model seç",
 	"Select model": "Model seç",
 	"Select only one model to call": "Arama için sadece bir model seç",
 	"Select only one model to call": "Arama için sadece bir model seç",
 	"Selected model(s) do not support image inputs": "Seçilen model(ler) görüntü girişlerini desteklemiyor",
 	"Selected model(s) do not support image inputs": "Seçilen model(ler) görüntü girişlerini desteklemiyor",
 	"Send": "Gönder",
 	"Send": "Gönder",
 	"Send a Message": "Bir Mesaj Gönder",
 	"Send a Message": "Bir Mesaj Gönder",
 	"Send message": "Mesaj gönder",
 	"Send message": "Mesaj gönder",
-	"Sends `stream_options: { include_usage: true }` in the request.\nSupported providers will return token usage information in the response when set.": "",
+	"Sends `stream_options: { include_usage: true }` in the request.\nSupported providers will return token usage information in the response when set.": "İsteğe `stream_options: { include_usage: true }` gönderir.\nDesteklenen sağlayıcılar, ayarlandığında yanıtta token kullanım bilgilerini döndürecektir.",
 	"September": "Eylül",
 	"September": "Eylül",
 	"Serper API Key": "Serper API Anahtarı",
 	"Serper API Key": "Serper API Anahtarı",
 	"Serply API Key": "Serply API Anahtarı",
 	"Serply API Key": "Serply API Anahtarı",
 	"Serpstack API Key": "Serpstack API Anahtarı",
 	"Serpstack API Key": "Serpstack API Anahtarı",
 	"Server connection verified": "Sunucu bağlantısı doğrulandı",
 	"Server connection verified": "Sunucu bağlantısı doğrulandı",
 	"Set as default": "Varsayılan olarak ayarla",
 	"Set as default": "Varsayılan olarak ayarla",
-	"Set CFG Scale": "",
+	"Set CFG Scale": "CFG Ölçeğini Ayarla",
 	"Set Default Model": "Varsayılan Modeli Ayarla",
 	"Set Default Model": "Varsayılan Modeli Ayarla",
 	"Set embedding model (e.g. {{model}})": "Gömme modelini ayarlayın (örn. {{model}})",
 	"Set embedding model (e.g. {{model}})": "Gömme modelini ayarlayın (örn. {{model}})",
 	"Set Image Size": "Görüntü Boyutunu Ayarla",
 	"Set Image Size": "Görüntü Boyutunu Ayarla",
 	"Set reranking model (e.g. {{model}})": "Yeniden sıralama modelini ayarlayın (örn. {{model}})",
 	"Set reranking model (e.g. {{model}})": "Yeniden sıralama modelini ayarlayın (örn. {{model}})",
-	"Set Sampler": "",
-	"Set Scheduler": "",
+	"Set Sampler": "Örnekleyiciyi Ayarla",
+	"Set Scheduler": "Zamanlayıcıyı Ayarla",
 	"Set Steps": "Adımları Ayarla",
 	"Set Steps": "Adımları Ayarla",
 	"Set Task Model": "Görev Modeli Ayarla",
 	"Set Task Model": "Görev Modeli Ayarla",
 	"Set Voice": "Ses Ayarla",
 	"Set Voice": "Ses Ayarla",
@@ -615,7 +618,7 @@
 	"Sign up": "Kaydol",
 	"Sign up": "Kaydol",
 	"Signing in": "Oturum açma",
 	"Signing in": "Oturum açma",
 	"Source": "Kaynak",
 	"Source": "Kaynak",
-	"Speech Playback Speed": "",
+	"Speech Playback Speed": "Konuşma Oynatma Hızı",
 	"Speech recognition error: {{error}}": "Konuşma tanıma hatası: {{error}}",
 	"Speech recognition error: {{error}}": "Konuşma tanıma hatası: {{error}}",
 	"Speech-to-Text Engine": "Konuşmadan Metne Motoru",
 	"Speech-to-Text Engine": "Konuşmadan Metne Motoru",
 	"Stop Sequence": "Diziyi Durdur",
 	"Stop Sequence": "Diziyi Durdur",
@@ -627,8 +630,8 @@
 	"Success": "Başarılı",
 	"Success": "Başarılı",
 	"Successfully updated.": "Başarıyla güncellendi.",
 	"Successfully updated.": "Başarıyla güncellendi.",
 	"Suggested": "Önerilen",
 	"Suggested": "Önerilen",
-	"Support": "",
-	"Support this plugin:": "",
+	"Support": "Destek",
+	"Support this plugin:": "Bu eklentiyi destekleyin:",
 	"System": "Sistem",
 	"System": "Sistem",
 	"System Prompt": "Sistem Promptu",
 	"System Prompt": "Sistem Promptu",
 	"Tags": "Etiketler",
 	"Tags": "Etiketler",
@@ -637,14 +640,14 @@
 	"Tell us more:": "Bize daha fazlasını anlat:",
 	"Tell us more:": "Bize daha fazlasını anlat:",
 	"Temperature": "Temperature",
 	"Temperature": "Temperature",
 	"Template": "Şablon",
 	"Template": "Şablon",
-	"Temporary Chat": "",
+	"Temporary Chat": "Geçici Sohbet",
 	"Text Completion": "Metin Tamamlama",
 	"Text Completion": "Metin Tamamlama",
 	"Text-to-Speech Engine": "Metinden Sese Motoru",
 	"Text-to-Speech Engine": "Metinden Sese Motoru",
 	"Tfs Z": "Tfs Z",
 	"Tfs Z": "Tfs Z",
 	"Thanks for your feedback!": "Geri bildiriminiz için teşekkürler!",
 	"Thanks for your feedback!": "Geri bildiriminiz için teşekkürler!",
-	"The developers behind this plugin are passionate volunteers from the community. If you find this plugin helpful, please consider contributing to its development.": "",
-	"The maximum file size in MB. If the file size exceeds this limit, the file will not be uploaded.": "",
-	"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.": "",
+	"The developers behind this plugin are passionate volunteers from the community. If you find this plugin helpful, please consider contributing to its development.": "Bu eklentinin arkasındaki geliştiriciler topluluktan tutkulu gönüllülerdir. Bu eklentinin yararlı olduğunu düşünüyorsanız, gelişimine katkıda bulunmayı düşünün.",
+	"The maximum file size in MB. If the file size exceeds this limit, the file will not be uploaded.": "MB cinsinden maksimum dosya boyutu. Dosya boyutu bu sınırı aşarsa, dosya yüklenmeyecektir.",
+	"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.": "Sohbette aynı anda kullanılabilecek maksimum dosya sayısı. Dosya sayısı bu sınırı aşarsa, dosyalar yüklenmeyecektir.",
 	"The score should be a value between 0.0 (0%) and 1.0 (100%).": "Puan 0.0 (%0) ile 1.0 (%100) arasında bir değer olmalıdır.",
 	"The score should be a value between 0.0 (0%) and 1.0 (100%).": "Puan 0.0 (%0) ile 1.0 (%100) arasında bir değer olmalıdır.",
 	"Theme": "Tema",
 	"Theme": "Tema",
 	"Thinking...": "Düşünüyor...",
 	"Thinking...": "Düşünüyor...",
@@ -654,7 +657,7 @@
 	"This will delete": "Bu silinecek",
 	"This will delete": "Bu silinecek",
 	"Thorough explanation": "Kapsamlı açıklama",
 	"Thorough explanation": "Kapsamlı açıklama",
 	"Tika": "",
 	"Tika": "",
-	"Tika Server URL required.": "",
+	"Tika Server URL required.": "Tika Sunucu URL'si gereklidir.",
 	"Tip: Update multiple variable slots consecutively by pressing the tab key in the chat input after each replacement.": "İpucu: Her değiştirmeden sonra sohbet girişinde tab tuşuna basarak birden fazla değişken yuvasını art arda güncelleyin.",
 	"Tip: Update multiple variable slots consecutively by pressing the tab key in the chat input after each replacement.": "İpucu: Her değiştirmeden sonra sohbet girişinde tab tuşuna basarak birden fazla değişken yuvasını art arda güncelleyin.",
 	"Title": "Başlık",
 	"Title": "Başlık",
 	"Title (e.g. Tell me a fun fact)": "Başlık (e.g. Bana ilginç bir bilgi ver)",
 	"Title (e.g. Tell me a fun fact)": "Başlık (e.g. Bana ilginç bir bilgi ver)",
@@ -667,7 +670,7 @@
 	"To access the WebUI, please reach out to the administrator. Admins can manage user statuses from the Admin Panel.": "WebUI'ye erişmek için lütfen yöneticiyle iletişime geçin. Yöneticiler kullanıcı durumlarını Yönetici Panelinden yönetebilir.",
 	"To access the WebUI, please reach out to the administrator. Admins can manage user statuses from the Admin Panel.": "WebUI'ye erişmek için lütfen yöneticiyle iletişime geçin. Yöneticiler kullanıcı durumlarını Yönetici Panelinden yönetebilir.",
 	"To add documents here, upload them to the \"Documents\" workspace first.": "Buraya belge eklemek için öncelikle bunları \"Belgeler\" çalışma alanına yükleyin.",
 	"To add documents here, upload them to the \"Documents\" workspace first.": "Buraya belge eklemek için öncelikle bunları \"Belgeler\" çalışma alanına yükleyin.",
 	"to chat input.": "sohbet girişine.",
 	"to chat input.": "sohbet girişine.",
-	"To select actions here, add them to the \"Functions\" workspace first.": "",
+	"To select actions here, add them to the \"Functions\" workspace first.": "Burada eylemleri seçmek için öncelikle bunları \"İşlevler\" çalışma alanına ekleyin.",
 	"To select filters here, add them to the \"Functions\" workspace first.": "Filtreleri burada seçmek için öncelikle bunları \"İşlevler\" çalışma alanına ekleyin.",
 	"To select filters here, add them to the \"Functions\" workspace first.": "Filtreleri burada seçmek için öncelikle bunları \"İşlevler\" çalışma alanına ekleyin.",
 	"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.",
 	"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.",
 	"Today": "Bugün",
 	"Today": "Bugün",
@@ -678,13 +681,13 @@
 	"Tool deleted successfully": "Araç başarıyla silindi",
 	"Tool deleted successfully": "Araç başarıyla silindi",
 	"Tool imported successfully": "Araç başarıyla içe aktarıldı",
 	"Tool imported successfully": "Araç başarıyla içe aktarıldı",
 	"Tool updated successfully": "Araç başarıyla güncellendi",
 	"Tool updated successfully": "Araç başarıyla güncellendi",
-	"Toolkit Description (e.g. A toolkit for performing various operations)": "",
-	"Toolkit ID (e.g. my_toolkit)": "",
-	"Toolkit Name (e.g. My ToolKit)": "",
+	"Toolkit Description (e.g. A toolkit for performing various operations)": "Toolkit Açıklaması (örn. Çeşitli işlemleri gerçekleştirmek için bir toolkit)",
+	"Toolkit ID (e.g. my_toolkit)": "Toolkit ID'si (örn. my_toolkit)",
+	"Toolkit Name (e.g. My ToolKit)": "Toolkit Adı (örn. Benim Toolkitim)",
 	"Tools": "Araçlar",
 	"Tools": "Araçlar",
-	"Tools are a function calling system with arbitrary code execution": "",
-	"Tools have a function calling system that allows arbitrary code execution": "",
-	"Tools have a function calling system that allows arbitrary code execution.": "",
+	"Tools are a function calling system with arbitrary code execution": "Araçlar, keyfi kod yürütme ile bir fonksiyon çağırma sistemine sahiptir",
+	"Tools have a function calling system that allows arbitrary code execution": "Araçlar, keyfi kod yürütme izni veren bir fonksiyon çağırma sistemine sahiptir",
+	"Tools have a function calling system that allows arbitrary code execution.": "Araçlar, keyfi kod yürütme izni veren bir fonksiyon çağırma sistemine sahiptir.",
 	"Top K": "Top K",
 	"Top K": "Top K",
 	"Top P": "Top P",
 	"Top P": "Top P",
 	"Trouble accessing Ollama?": "Ollama'ya erişmede sorun mu yaşıyorsunuz?",
 	"Trouble accessing Ollama?": "Ollama'ya erişmede sorun mu yaşıyorsunuz?",
@@ -692,13 +695,14 @@
 	"TTS Settings": "TTS Ayarları",
 	"TTS Settings": "TTS Ayarları",
 	"TTS Voice": "TTS Sesi",
 	"TTS Voice": "TTS Sesi",
 	"Type": "Tür",
 	"Type": "Tür",
-	"Type Hugging Face Resolve (Download) URL": "Hugging Face Resolve (Download) URL'sini Yazın",
+	"Type Hugging Face Resolve (Download) URL": "HuggingFace Çözümleme (İndirme) URL'sini Yazın",
 	"Uh-oh! There was an issue connecting to {{provider}}.": "Ah! {{provider}}'a bağlanırken bir sorun oluştu.",
 	"Uh-oh! There was an issue connecting to {{provider}}.": "Ah! {{provider}}'a bağlanırken bir sorun oluştu.",
-	"UI": "UI",
+	"UI": "Arayüz",
 	"Unknown file type '{{file_type}}'. Proceeding with the file upload anyway.": "Bilinmeyen dosya türü '{{file_type}}'. Yine de dosya yükleme işlemine devam ediliyor.",
 	"Unknown file type '{{file_type}}'. Proceeding with the file upload anyway.": "Bilinmeyen dosya türü '{{file_type}}'. Yine de dosya yükleme işlemine devam ediliyor.",
-	"Unpin": "",
+	"Unpin": "Sabitlemeyi Kaldır",
 	"Update": "Güncelle",
 	"Update": "Güncelle",
 	"Update and Copy Link": "Güncelle ve Bağlantıyı Kopyala",
 	"Update and Copy Link": "Güncelle ve Bağlantıyı Kopyala",
+	"Update for the latest features and improvements.": "",
 	"Update password": "Parolayı Güncelle",
 	"Update password": "Parolayı Güncelle",
 	"Updated at": "Şu tarihte güncellendi:",
 	"Updated at": "Şu tarihte güncellendi:",
 	"Upload": "Yükle",
 	"Upload": "Yükle",
@@ -726,7 +730,7 @@
 	"Version": "Sürüm",
 	"Version": "Sürüm",
 	"Voice": "Ses",
 	"Voice": "Ses",
 	"Warning": "Uyarı",
 	"Warning": "Uyarı",
-	"Warning:": "",
+	"Warning:": "Uyarı:",
 	"Warning: If you update or change your embedding model, you will need to re-import all documents.": "Uyarı: Gömme modelinizi günceller veya değiştirirseniz, tüm belgeleri yeniden içe aktarmanız gerekecektir.",
 	"Warning: If you update or change your embedding model, you will need to re-import all documents.": "Uyarı: Gömme modelinizi günceller veya değiştirirseniz, tüm belgeleri yeniden içe aktarmanız gerekecektir.",
 	"Web": "Web",
 	"Web": "Web",
 	"Web API": "Web API",
 	"Web API": "Web API",
@@ -744,7 +748,7 @@
 	"Write a summary in 50 words that summarizes [topic or keyword].": "[Konuyu veya anahtar kelimeyi] özetleyen 50 kelimelik bir özet yazın.",
 	"Write a summary in 50 words that summarizes [topic or keyword].": "[Konuyu veya anahtar kelimeyi] özetleyen 50 kelimelik bir özet yazın.",
 	"Yesterday": "Dün",
 	"Yesterday": "Dün",
 	"You": "Sen",
 	"You": "Sen",
-	"You can only chat with a maximum of {{maxCount}} file(s) at a time.": "",
+	"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 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 clone a base model": "Bir temel modeli klonlayamazsınız",
 	"You cannot clone a base model": "Bir temel modeli klonlayamazsınız",
 	"You have no archived conversations.": "Arşivlenmiş sohbetleriniz yok.",
 	"You have no archived conversations.": "Arşivlenmiş sohbetleriniz yok.",
@@ -752,7 +756,7 @@
 	"You're a helpful assistant.": "Sen yardımsever bir asistansın.",
 	"You're a helpful assistant.": "Sen yardımsever bir asistansın.",
 	"You're now logged in.": "Şimdi giriş yaptınız.",
 	"You're now logged in.": "Şimdi giriş yaptınız.",
 	"Your account status is currently pending activation.": "Hesap durumunuz şu anda etkinleştirilmeyi bekliyor.",
 	"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.": "",
+	"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.",
 	"Youtube": "Youtube",
 	"Youtube": "Youtube",
 	"Youtube Loader Settings": "Youtube Yükleyici Ayarları"
 	"Youtube Loader Settings": "Youtube Yükleyici Ayarları"
 }
 }

+ 4 - 0
src/lib/i18n/locales/uk-UA/translation.json

@@ -9,6 +9,7 @@
 	"{{user}}'s Chats": "Чати {{user}}а",
 	"{{user}}'s Chats": "Чати {{user}}а",
 	"{{webUIName}} Backend Required": "Необхідно підключення бекенду {{webUIName}}",
 	"{{webUIName}} Backend Required": "Необхідно підключення бекенду {{webUIName}}",
 	"*Prompt node ID(s) are required for image generation": "*Для генерації зображення потрібно вказати ідентифікатор(и) вузла(ів)",
 	"*Prompt node ID(s) are required for image generation": "*Для генерації зображення потрібно вказати ідентифікатор(и) вузла(ів)",
+	"A new version (v{{LATEST_VERSION}}) is now available.": "",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "Модель задач використовується при виконанні таких завдань, як генерація заголовків для чатів та пошукових запитів в Інтернеті",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "Модель задач використовується при виконанні таких завдань, як генерація заголовків для чатів та пошукових запитів в Інтернеті",
 	"a user": "користувача",
 	"a user": "користувача",
 	"About": "Про програму",
 	"About": "Про програму",
@@ -465,6 +466,7 @@
 	"Oops! Looks like the URL is invalid. Please double-check and try again.": "Упс! Схоже, що URL-адреса невірна. Будь ласка, перевірте ще раз та спробуйте ще раз.",
 	"Oops! Looks like the URL is invalid. Please double-check and try again.": "Упс! Схоже, що URL-адреса невірна. Будь ласка, перевірте ще раз та спробуйте ще раз.",
 	"Oops! There was an error in the previous response. Please try again or contact admin.": "Упс! У попередній відповіді сталася помилка. Будь ласка, спробуйте ще раз або зверніться до адміністратора.",
 	"Oops! There was an error in the previous response. Please try again or contact admin.": "Упс! У попередній відповіді сталася помилка. Будь ласка, спробуйте ще раз або зверніться до адміністратора.",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "Упс! Ви використовуєте непідтримуваний метод (тільки для фронтенду). Будь ласка, обслуговуйте WebUI з бекенду.",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "Упс! Ви використовуєте непідтримуваний метод (тільки для фронтенду). Будь ласка, обслуговуйте WebUI з бекенду.",
+	"Open file": "",
 	"Open new chat": "Відкрити новий чат",
 	"Open new chat": "Відкрити новий чат",
 	"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "Open WebUI версія (v{{OPEN_WEBUI_VERSION}}) нижча за необхідну версію (v{{REQUIRED_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": "OpenAI",
@@ -476,6 +478,7 @@
 	"Other": "Інше",
 	"Other": "Інше",
 	"Output format": "",
 	"Output format": "",
 	"Overview": "",
 	"Overview": "",
+	"page": "",
 	"Password": "Пароль",
 	"Password": "Пароль",
 	"PDF document (.pdf)": "PDF документ (.pdf)",
 	"PDF document (.pdf)": "PDF документ (.pdf)",
 	"PDF Extract Images (OCR)": "Розпізнавання зображень з PDF (OCR)",
 	"PDF Extract Images (OCR)": "Розпізнавання зображень з PDF (OCR)",
@@ -701,6 +704,7 @@
 	"Unpin": "Відчепити",
 	"Unpin": "Відчепити",
 	"Update": "Оновлення",
 	"Update": "Оновлення",
 	"Update and Copy Link": "Оновлення та копіювання посилання",
 	"Update and Copy Link": "Оновлення та копіювання посилання",
+	"Update for the latest features and improvements.": "",
 	"Update password": "Оновити пароль",
 	"Update password": "Оновити пароль",
 	"Updated at": "Оновлено на",
 	"Updated at": "Оновлено на",
 	"Upload": "Завантажити",
 	"Upload": "Завантажити",

+ 4 - 0
src/lib/i18n/locales/vi-VN/translation.json

@@ -9,6 +9,7 @@
 	"{{user}}'s Chats": "{{user}}'s Chats",
 	"{{user}}'s Chats": "{{user}}'s Chats",
 	"{{webUIName}} Backend Required": "{{webUIName}} Yêu cầu Backend",
 	"{{webUIName}} Backend Required": "{{webUIName}} Yêu cầu Backend",
 	"*Prompt node ID(s) are required for image generation": "",
 	"*Prompt node ID(s) are required for image generation": "",
+	"A new version (v{{LATEST_VERSION}}) is now available.": "",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "Mô hình tác vụ được sử dụng khi thực hiện các tác vụ như tạo tiêu đề cho cuộc trò chuyện và truy vấn tìm kiếm trên web",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "Mô hình tác vụ được sử dụng khi thực hiện các tác vụ như tạo tiêu đề cho cuộc trò chuyện và truy vấn tìm kiếm trên web",
 	"a user": "người sử dụng",
 	"a user": "người sử dụng",
 	"About": "Giới thiệu",
 	"About": "Giới thiệu",
@@ -465,6 +466,7 @@
 	"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! 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 was an error in the previous response. Please try again or contact admin.": "Rất tiếc! Đã xảy ra lỗi trong phản hồi trước đó. Vui lòng thử lại hoặc liên hệ với quản trị viên.",
 	"Oops! There was an error in the previous response. Please try again or contact admin.": "Rất tiếc! Đã xảy ra lỗi trong phản hồi trước đó. Vui lòng thử lại hoặc liên hệ với quản trị viên.",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "Rất tiếc! Bạn đang sử dụng một phương thức không được hỗ trợ (chỉ dành cho frontend). Vui lòng cung cấp phương thức cho WebUI từ phía backend.",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "Rất tiếc! Bạn đang sử dụng một phương thức không được hỗ trợ (chỉ dành cho frontend). Vui lòng cung cấp phương thức cho WebUI từ phía backend.",
+	"Open file": "",
 	"Open new chat": "Mở nội dung chat mới",
 	"Open new chat": "Mở nội dung chat mới",
 	"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}})",
 	"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": "OpenAI",
@@ -476,6 +478,7 @@
 	"Other": "Khác",
 	"Other": "Khác",
 	"Output format": "",
 	"Output format": "",
 	"Overview": "",
 	"Overview": "",
+	"page": "",
 	"Password": "Mật khẩu",
 	"Password": "Mật khẩu",
 	"PDF document (.pdf)": "Tập tin PDF (.pdf)",
 	"PDF document (.pdf)": "Tập tin PDF (.pdf)",
 	"PDF Extract Images (OCR)": "Trích xuất ảnh từ PDF (OCR)",
 	"PDF Extract Images (OCR)": "Trích xuất ảnh từ PDF (OCR)",
@@ -698,6 +701,7 @@
 	"Unpin": "Bỏ ghim",
 	"Unpin": "Bỏ ghim",
 	"Update": "Cập nhật",
 	"Update": "Cập nhật",
 	"Update and Copy Link": "Cập nhật và sao chép link",
 	"Update and Copy Link": "Cập nhật và sao chép link",
+	"Update for the latest features and improvements.": "",
 	"Update password": "Cập nhật mật khẩu",
 	"Update password": "Cập nhật mật khẩu",
 	"Updated at": "Cập nhật lúc",
 	"Updated at": "Cập nhật lúc",
 	"Upload": "",
 	"Upload": "",

+ 5 - 1
src/lib/i18n/locales/zh-CN/translation.json

@@ -9,6 +9,7 @@
 	"{{user}}'s Chats": "{{user}} 的对话记录",
 	"{{user}}'s Chats": "{{user}} 的对话记录",
 	"{{webUIName}} Backend Required": "需要 {{webUIName}} 后端",
 	"{{webUIName}} Backend Required": "需要 {{webUIName}} 后端",
 	"*Prompt node ID(s) are required for image generation": "*图片生成需要 Prompt node ID",
 	"*Prompt node ID(s) are required for image generation": "*图片生成需要 Prompt node ID",
+	"A new version (v{{LATEST_VERSION}}) is now available.": "",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "任务模型用于执行生成对话标题和联网搜索查询等任务",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "任务模型用于执行生成对话标题和联网搜索查询等任务",
 	"a user": "用户",
 	"a user": "用户",
 	"About": "关于",
 	"About": "关于",
@@ -465,6 +466,7 @@
 	"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 was an error in the previous response. Please try again or contact admin.": "糟糕!之前的回复出现了错误。请重试或联系管理员。",
 	"Oops! There was an error in the previous response. Please try again or contact admin.": "糟糕!之前的回复出现了错误。请重试或联系管理员。",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "糟糕!你正在使用不被支持的方法(仅前端)。请从后端提供 WebUI 服务。",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "糟糕!你正在使用不被支持的方法(仅前端)。请从后端提供 WebUI 服务。",
+	"Open file": "",
 	"Open new chat": "打开新对话",
 	"Open new chat": "打开新对话",
 	"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "当前 Open WebUI 版本 (v{{OPEN_WEBUI_VERSION}}) 低于所需的版本 (v{{REQUIRED_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": "OpenAI",
@@ -476,6 +478,7 @@
 	"Other": "其他",
 	"Other": "其他",
 	"Output format": "输出格式",
 	"Output format": "输出格式",
 	"Overview": "概述",
 	"Overview": "概述",
+	"page": "",
 	"Password": "密码",
 	"Password": "密码",
 	"PDF document (.pdf)": "PDF 文档 (.pdf)",
 	"PDF document (.pdf)": "PDF 文档 (.pdf)",
 	"PDF Extract Images (OCR)": "PDF 图像处理 (使用 OCR)",
 	"PDF Extract Images (OCR)": "PDF 图像处理 (使用 OCR)",
@@ -614,7 +617,7 @@
 	"Sign up": "注册",
 	"Sign up": "注册",
 	"Signing in": "正在登录",
 	"Signing in": "正在登录",
 	"Source": "来源",
 	"Source": "来源",
-	"Speech Playback Speed": "",
+	"Speech Playback Speed": "语音播放速度",
 	"Speech recognition error: {{error}}": "语音识别错误:{{error}}",
 	"Speech recognition error: {{error}}": "语音识别错误:{{error}}",
 	"Speech-to-Text Engine": "语音转文本引擎",
 	"Speech-to-Text Engine": "语音转文本引擎",
 	"Stop Sequence": "停止序列 (Stop Sequence)",
 	"Stop Sequence": "停止序列 (Stop Sequence)",
@@ -698,6 +701,7 @@
 	"Unpin": "取消置顶",
 	"Unpin": "取消置顶",
 	"Update": "更新",
 	"Update": "更新",
 	"Update and Copy Link": "更新和复制链接",
 	"Update and Copy Link": "更新和复制链接",
+	"Update for the latest features and improvements.": "",
 	"Update password": "更新密码",
 	"Update password": "更新密码",
 	"Updated at": "更新于",
 	"Updated at": "更新于",
 	"Upload": "上传",
 	"Upload": "上传",

+ 5 - 1
src/lib/i18n/locales/zh-TW/translation.json

@@ -9,6 +9,7 @@
 	"{{user}}'s Chats": "{{user}} 的對話",
 	"{{user}}'s Chats": "{{user}} 的對話",
 	"{{webUIName}} Backend Required": "需要 {{webUIName}} 後端",
 	"{{webUIName}} Backend Required": "需要 {{webUIName}} 後端",
 	"*Prompt node ID(s) are required for image generation": "",
 	"*Prompt node ID(s) are required for image generation": "",
+	"A new version (v{{LATEST_VERSION}}) is now available.": "",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "執行產生對話標題和網頁搜尋查詢等任務時會使用任務模型",
 	"A task model is used when performing tasks such as generating titles for chats and web search queries": "執行產生對話標題和網頁搜尋查詢等任務時會使用任務模型",
 	"a user": "一位使用者",
 	"a user": "一位使用者",
 	"About": "關於",
 	"About": "關於",
@@ -465,6 +466,7 @@
 	"Oops! Looks like the URL is invalid. Please double-check and try again.": "哎呀!這個 URL 似乎無效。請仔細檢查並再試一次。",
 	"Oops! Looks like the URL is invalid. Please double-check and try again.": "哎呀!這個 URL 似乎無效。請仔細檢查並再試一次。",
 	"Oops! There was an error in the previous response. Please try again or contact admin.": "哎呀!先前的回應發生錯誤。請重試或聯絡管理員。",
 	"Oops! There was an error in the previous response. Please try again or contact admin.": "哎呀!先前的回應發生錯誤。請重試或聯絡管理員。",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "哎呀!您使用了不支援的方法(僅限前端)。請從後端提供 WebUI。",
 	"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "哎呀!您使用了不支援的方法(僅限前端)。請從後端提供 WebUI。",
+	"Open file": "",
 	"Open new chat": "開啟新的對話",
 	"Open new chat": "開啟新的對話",
 	"Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "Open WebUI 版本 (v{{OPEN_WEBUI_VERSION}}) 低於所需版本 (v{{REQUIRED_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": "OpenAI",
@@ -476,6 +478,7 @@
 	"Other": "其他",
 	"Other": "其他",
 	"Output format": "",
 	"Output format": "",
 	"Overview": "",
 	"Overview": "",
+	"page": "",
 	"Password": "密碼",
 	"Password": "密碼",
 	"PDF document (.pdf)": "PDF 文件 (.pdf)",
 	"PDF document (.pdf)": "PDF 文件 (.pdf)",
 	"PDF Extract Images (OCR)": "PDF 影像擷取(OCR 光學文字辨識)",
 	"PDF Extract Images (OCR)": "PDF 影像擷取(OCR 光學文字辨識)",
@@ -615,7 +618,7 @@
 	"Sign up": "註冊",
 	"Sign up": "註冊",
 	"Signing in": "正在登入",
 	"Signing in": "正在登入",
 	"Source": "來源",
 	"Source": "來源",
-	"Speech Playback Speed": "",
+	"Speech Playback Speed": "語音播放速度",
 	"Speech recognition error: {{error}}": "語音辨識錯誤:{{error}}",
 	"Speech recognition error: {{error}}": "語音辨識錯誤:{{error}}",
 	"Speech-to-Text Engine": "語音轉文字 (STT) 引擎",
 	"Speech-to-Text Engine": "語音轉文字 (STT) 引擎",
 	"Stop Sequence": "停止序列",
 	"Stop Sequence": "停止序列",
@@ -699,6 +702,7 @@
 	"Unpin": "取消釘選",
 	"Unpin": "取消釘選",
 	"Update": "更新",
 	"Update": "更新",
 	"Update and Copy Link": "更新並複製連結",
 	"Update and Copy Link": "更新並複製連結",
+	"Update for the latest features and improvements.": "",
 	"Update password": "更新密碼",
 	"Update password": "更新密碼",
 	"Updated at": "更新於",
 	"Updated at": "更新於",
 	"Upload": "上傳",
 	"Upload": "上傳",

+ 47 - 1
src/lib/utils/index.ts

@@ -664,6 +664,15 @@ export const promptTemplate = (
 		hour12: true
 		hour12: true
 	});
 	});
 
 
+	// Get the current weekday
+	const currentWeekday = getWeekday();
+
+	// Get the user's timezone
+	const currentTimezone = getUserTimezone();
+
+	// Get the user's language
+	const userLanguage = localStorage.getItem('locale') || 'en-US';
+
 	// Replace {{CURRENT_DATETIME}} in the template with the formatted datetime
 	// Replace {{CURRENT_DATETIME}} in the template with the formatted datetime
 	template = template.replace('{{CURRENT_DATETIME}}', `${formattedDate} ${currentTime}`);
 	template = template.replace('{{CURRENT_DATETIME}}', `${formattedDate} ${currentTime}`);
 
 
@@ -673,6 +682,15 @@ export const promptTemplate = (
 	// Replace {{CURRENT_TIME}} in the template with the formatted time
 	// Replace {{CURRENT_TIME}} in the template with the formatted time
 	template = template.replace('{{CURRENT_TIME}}', currentTime);
 	template = template.replace('{{CURRENT_TIME}}', currentTime);
 
 
+	// Replace {{CURRENT_WEEKDAY}} in the template with the current weekday
+	template = template.replace('{{CURRENT_WEEKDAY}}', currentWeekday);
+
+	// Replace {{CURRENT_TIMEZONE}} in the template with the user's timezone
+	template = template.replace('{{CURRENT_TIMEZONE}}', currentTimezone);
+
+	// Replace {{USER_LANGUAGE}} in the template with the user's language
+	template = template.replace('{{USER_LANGUAGE}}', userLanguage);
+
 	if (user_name) {
 	if (user_name) {
 		// Replace {{USER_NAME}} in the template with the user's name
 		// Replace {{USER_NAME}} in the template with the user's name
 		template = template.replace('{{USER_NAME}}', user_name);
 		template = template.replace('{{USER_NAME}}', user_name);
@@ -829,6 +847,34 @@ export const bestMatchingLanguage = (supportedLanguages, preferredLanguages, def
 		.map((prefLang) => languages.find((lang) => lang.startsWith(prefLang)))
 		.map((prefLang) => languages.find((lang) => lang.startsWith(prefLang)))
 		.find(Boolean);
 		.find(Boolean);
 
 
-	console.log(languages, preferredLanguages, match, defaultLocale);
 	return match || defaultLocale;
 	return match || defaultLocale;
 };
 };
+
+// Get the date in the format YYYY-MM-DD
+export const getFormattedDate = () => {
+	const date = new Date();
+	return date.toISOString().split('T')[0];
+};
+
+// Get the time in the format HH:MM:SS
+export const getFormattedTime = () => {
+	const date = new Date();
+	return date.toTimeString().split(' ')[0];
+};
+
+// Get the current date and time in the format YYYY-MM-DD HH:MM:SS
+export const getCurrentDateTime = () => {
+	return `${getFormattedDate()} ${getFormattedTime()}`;
+};
+
+// Get the user's timezone
+export const getUserTimezone = () => {
+	return Intl.DateTimeFormat().resolvedOptions().timeZone;
+};
+
+// Get the weekday
+export const getWeekday = () => {
+	const date = new Date();
+	const weekdays = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
+	return weekdays[date.getDay()];
+};

+ 28 - 1
src/routes/(app)/+layout.svelte

@@ -9,7 +9,7 @@
 
 
 	import { goto } from '$app/navigation';
 	import { goto } from '$app/navigation';
 
 
-	import { getModels as _getModels } from '$lib/apis';
+	import { getModels as _getModels, getVersionUpdates } from '$lib/apis';
 	import { getAllChatTags } from '$lib/apis/chats';
 	import { getAllChatTags } from '$lib/apis/chats';
 
 
 	import { getPrompts } from '$lib/apis/prompts';
 	import { getPrompts } from '$lib/apis/prompts';
@@ -42,6 +42,10 @@
 	import AccountPending from '$lib/components/layout/Overlay/AccountPending.svelte';
 	import AccountPending from '$lib/components/layout/Overlay/AccountPending.svelte';
 	import { getFunctions } from '$lib/apis/functions';
 	import { getFunctions } from '$lib/apis/functions';
 	import { page } from '$app/stores';
 	import { page } from '$app/stores';
+	import { WEBUI_VERSION } from '$lib/constants';
+	import { compareVersion } from '$lib/utils';
+
+	import UpdateInfoToast from '$lib/components/layout/UpdateInfoToast.svelte';
 
 
 	const i18n = getContext('i18n');
 	const i18n = getContext('i18n');
 
 
@@ -191,11 +195,34 @@
 				temporaryChatEnabled.set(true);
 				temporaryChatEnabled.set(true);
 			}
 			}
 
 
+			if ($user.role === 'admin') {
+				checkForVersionUpdates();
+			}
+
 			await tick();
 			await tick();
 		}
 		}
 
 
 		loaded = true;
 		loaded = true;
 	});
 	});
+
+	const checkForVersionUpdates = async () => {
+		const version = await getVersionUpdates(localStorage.token).catch((error) => {
+			return {
+				current: WEBUI_VERSION,
+				latest: WEBUI_VERSION
+			};
+		});
+
+		if (compareVersion(version.latest, version.current)) {
+			toast.custom(UpdateInfoToast, {
+				duration: Number.POSITIVE_INFINITY,
+				position: 'bottom-right',
+				componentProps: {
+					version
+				}
+			});
+		}
+	};
 </script>
 </script>
 
 
 <SettingsModal bind:show={$showSettings} />
 <SettingsModal bind:show={$showSettings} />

+ 11 - 1
src/routes/+layout.svelte

@@ -209,4 +209,14 @@
 	<slot />
 	<slot />
 {/if}
 {/if}
 
 
-<Toaster richColors position="top-center" />
+<Toaster
+	theme={$theme.includes('dark')
+		? 'dark'
+		: $theme === 'system'
+			? window.matchMedia('(prefers-color-scheme: dark)').matches
+				? 'dark'
+				: 'light'
+			: 'light'}
+	richColors
+	position="top-center"
+/>

+ 1 - 1
src/routes/s/[id]/+page.svelte

@@ -155,7 +155,7 @@
 							bind:autoScroll
 							bind:autoScroll
 							bottomPadding={files.length > 0}
 							bottomPadding={files.length > 0}
 							sendPrompt={() => {}}
 							sendPrompt={() => {}}
-							continueGeneration={() => {}}
+							continueResponse={() => {}}
 							regenerateResponse={() => {}}
 							regenerateResponse={() => {}}
 						/>
 						/>
 					</div>
 					</div>