Browse Source

Merge pull request #9480 from open-webui/dev

0.5.11
Timothy Jaeryang Baek 4 months ago
parent
commit
4d667e447d
100 changed files with 4565 additions and 1599 deletions
  1. 28 0
      CHANGELOG.md
  2. 1 1
      README.md
  3. 74 3
      backend/open_webui/config.py
  4. 1 0
      backend/open_webui/env.py
  5. 88 14
      backend/open_webui/main.py
  6. 1 1
      backend/open_webui/models/chats.py
  7. 18 0
      backend/open_webui/models/users.py
  8. 28 0
      backend/open_webui/retrieval/vector/dbs/opensearch.py
  9. 65 0
      backend/open_webui/retrieval/web/bocha.py
  10. 34 15
      backend/open_webui/retrieval/web/google_pse.py
  11. 13 4
      backend/open_webui/retrieval/web/jina_search.py
  12. 68 0
      backend/open_webui/routers/audio.py
  13. 92 0
      backend/open_webui/routers/configs.py
  14. 16 20
      backend/open_webui/routers/files.py
  15. 46 69
      backend/open_webui/routers/images.py
  16. 73 46
      backend/open_webui/routers/ollama.py
  17. 6 6
      backend/open_webui/routers/openai.py
  18. 24 0
      backend/open_webui/routers/retrieval.py
  19. 54 8
      backend/open_webui/routers/tasks.py
  20. 1 1
      backend/open_webui/routers/users.py
  21. 4 4
      backend/open_webui/socket/main.py
  22. 21 7
      backend/open_webui/storage/provider.py
  23. 237 180
      backend/open_webui/utils/chat.py
  24. 148 0
      backend/open_webui/utils/code_interpreter.py
  25. 99 0
      backend/open_webui/utils/filter.py
  26. 1 1
      backend/open_webui/utils/images/comfyui.py
  27. 144 122
      backend/open_webui/utils/middleware.py
  28. 13 5
      backend/open_webui/utils/misc.py
  29. 46 11
      backend/open_webui/utils/oauth.py
  30. 6 6
      backend/open_webui/utils/payload.py
  31. 7 5
      backend/open_webui/utils/pdf_generator.py
  32. 27 13
      backend/open_webui/utils/response.py
  33. 5 3
      backend/requirements.txt
  34. 188 122
      package-lock.json
  35. 5 3
      package.json
  36. 6 3
      pyproject.toml
  37. 114 0
      src/lib/apis/configs/index.ts
  38. 111 1
      src/lib/apis/index.ts
  39. 78 22
      src/lib/apis/openai/index.ts
  40. 7 3
      src/lib/components/AddConnectionModal.svelte
  41. 2 2
      src/lib/components/admin/Evaluations/Feedbacks.svelte
  42. 3 1
      src/lib/components/admin/Evaluations/Leaderboard.svelte
  43. 34 8
      src/lib/components/admin/Functions.svelte
  44. 36 0
      src/lib/components/admin/Settings.svelte
  45. 41 3
      src/lib/components/admin/Settings/Audio.svelte
  46. 166 0
      src/lib/components/admin/Settings/CodeInterpreter.svelte
  47. 78 17
      src/lib/components/admin/Settings/Connections.svelte
  48. 1 1
      src/lib/components/admin/Settings/Connections/OllamaConnection.svelte
  49. 2 1
      src/lib/components/admin/Settings/Connections/OpenAIConnection.svelte
  50. 39 19
      src/lib/components/admin/Settings/Evaluations.svelte
  51. 1 1
      src/lib/components/admin/Settings/General.svelte
  52. 20 4
      src/lib/components/admin/Settings/Models.svelte
  53. 25 5
      src/lib/components/admin/Settings/Models/Manage/ManageOllama.svelte
  54. 25 5
      src/lib/components/admin/Settings/Pipelines.svelte
  55. 42 0
      src/lib/components/admin/Settings/WebSearch.svelte
  56. 15 9
      src/lib/components/chat/Chat.svelte
  57. 19 7
      src/lib/components/chat/MessageInput.svelte
  58. 17 2
      src/lib/components/chat/MessageInput/CallOverlay.svelte
  59. 22 12
      src/lib/components/chat/Messages/Citations.svelte
  60. 17 2
      src/lib/components/chat/Messages/CodeBlock.svelte
  61. 16 9
      src/lib/components/chat/Messages/Markdown/Source.svelte
  62. 117 63
      src/lib/components/chat/Messages/ResponseMessage.svelte
  63. 207 201
      src/lib/components/chat/Messages/UserMessage.svelte
  64. 33 3
      src/lib/components/chat/ModelSelector/Selector.svelte
  65. 2 2
      src/lib/components/chat/Navbar.svelte
  66. 8 2
      src/lib/components/chat/Settings/Account.svelte
  67. 162 16
      src/lib/components/chat/Settings/Audio.svelte
  68. 156 0
      src/lib/components/chat/Settings/Connections.svelte
  69. 83 0
      src/lib/components/chat/Settings/Connections/Connection.svelte
  70. 5 0
      src/lib/components/chat/Settings/General.svelte
  71. 44 2
      src/lib/components/chat/SettingsModal.svelte
  72. 2 2
      src/lib/components/chat/ShareChatModal.svelte
  73. 11 4
      src/lib/components/common/Collapsible.svelte
  74. 1 0
      src/lib/components/common/SensitiveInput.svelte
  75. 28 6
      src/lib/components/workspace/Models.svelte
  76. 2 2
      src/lib/components/workspace/Prompts.svelte
  77. 2 2
      src/lib/components/workspace/Tools.svelte
  78. 29 3
      src/lib/i18n/locales/ar-BH/translation.json
  79. 29 3
      src/lib/i18n/locales/bg-BG/translation.json
  80. 29 3
      src/lib/i18n/locales/bn-BD/translation.json
  81. 48 22
      src/lib/i18n/locales/ca-ES/translation.json
  82. 29 3
      src/lib/i18n/locales/ceb-PH/translation.json
  83. 29 3
      src/lib/i18n/locales/cs-CZ/translation.json
  84. 29 3
      src/lib/i18n/locales/da-DK/translation.json
  85. 130 104
      src/lib/i18n/locales/de-DE/translation.json
  86. 29 3
      src/lib/i18n/locales/dg-DG/translation.json
  87. 29 3
      src/lib/i18n/locales/el-GR/translation.json
  88. 29 3
      src/lib/i18n/locales/en-GB/translation.json
  89. 29 3
      src/lib/i18n/locales/en-US/translation.json
  90. 325 301
      src/lib/i18n/locales/es-ES/translation.json
  91. 29 3
      src/lib/i18n/locales/eu-ES/translation.json
  92. 29 3
      src/lib/i18n/locales/fa-IR/translation.json
  93. 29 3
      src/lib/i18n/locales/fi-FI/translation.json
  94. 29 3
      src/lib/i18n/locales/fr-CA/translation.json
  95. 29 3
      src/lib/i18n/locales/fr-FR/translation.json
  96. 29 3
      src/lib/i18n/locales/he-IL/translation.json
  97. 29 3
      src/lib/i18n/locales/hi-IN/translation.json
  98. 29 3
      src/lib/i18n/locales/hr-HR/translation.json
  99. 29 3
      src/lib/i18n/locales/hu-HU/translation.json
  100. 29 3
      src/lib/i18n/locales/id-ID/translation.json

+ 28 - 0
CHANGELOG.md

@@ -5,6 +5,34 @@ 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.5.11] - 2025-02-13
+
+### Added
+
+- **🎤 Kokoro-JS TTS Support**: A new on-device, high-quality text-to-speech engine has been integrated, vastly improving voice generation quality—everything runs directly in your browser.
+- **🐍 Jupyter Notebook Support in Code Interpreter**: Now, you can configure Code Interpreter to run Python code not only via Pyodide but also through Jupyter, offering a more robust coding environment for AI-driven computations and analysis.
+- **🔗 Direct API Connections for Private & Local Inference**: You can now connect Open WebUI to your private or localhost API inference endpoints. CORS must be enabled, but this unlocks direct, on-device AI infrastructure support.
+- **🔍 Advanced Domain Filtering for Web Search**: You can now specify which domains should be included or excluded from web searches, refining results for more relevant information retrieval.
+- **🚀 Improved Image Generation Metadata Handling**: Generated images now retain metadata for better organization and future retrieval.
+- **📂 S3 Key Prefix Support**: Fine-grained control over S3 storage file structuring with configurable key prefixes.
+- **📸 Support for Image-Only Messages**: Send messages containing only images, facilitating more visual-centric interactions.
+- **🌍 Updated Translations**: German, Spanish, Traditional Chinese, and Catalan translations updated for better multilingual support.
+
+### Fixed
+
+- **🔧 OAuth Debug Logs & Username Claim Fixes**: Debug logs have been added for OAuth role and group management, with fixes ensuring proper OAuth username retrieval and claim handling.
+- **📌 Citations Formatting & Toggle Fixes**: Inline citation toggles now function correctly, and citations with more than three sources are now fully visible when expanded.
+- **📸 ComfyUI Maximum Seed Value Constraint Fixed**: The maximum allowed seed value for ComfyUI has been corrected, preventing unintended behavior.
+- **🔑 Connection Settings Stability**: Addressed connection settings issues that were causing instability when saving configurations.
+- **📂 GGUF Model Upload Stability**: Fixed upload inconsistencies for GGUF models, ensuring reliable local model handling.
+- **🔧 Web Search Configuration Bug**: Fixed issues where web search filters and settings weren't correctly applied.
+- **💾 User Settings Persistence Fix**: Ensured user-specific settings are correctly saved and applied across sessions.
+- **🔄 OpenID Username Retrieval Enhancement**: Usernames are now correctly picked up and assigned for OpenID Connect (OIDC) logins.
+
+### Changed
+
+- **🔗 Improved Direct Connections Integration**: Simplified the configuration process for setting up direct API connections, making it easier to integrate custom inference endpoints.
+
 ## [0.5.10] - 2025-02-05
 ## [0.5.10] - 2025-02-05
 
 
 ### Fixed
 ### Fixed

+ 1 - 1
README.md

@@ -174,7 +174,7 @@ docker run --rm --volume /var/run/docker.sock:/var/run/docker.sock containrrr/wa
 
 
 In the last part of the command, replace `open-webui` with your container name if it is different.
 In the last part of the command, replace `open-webui` with your container name if it is different.
 
 
-Check our Migration Guide available in our [Open WebUI Documentation](https://docs.openwebui.com/tutorials/migration/).
+Check our Updating Guide available in our [Open WebUI Documentation](https://docs.openwebui.com/getting-started/updating).
 
 
 ### Using the Dev Branch 🌙
 ### Using the Dev Branch 🌙
 
 

+ 74 - 3
backend/open_webui/config.py

@@ -660,6 +660,7 @@ S3_ACCESS_KEY_ID = os.environ.get("S3_ACCESS_KEY_ID", None)
 S3_SECRET_ACCESS_KEY = os.environ.get("S3_SECRET_ACCESS_KEY", None)
 S3_SECRET_ACCESS_KEY = os.environ.get("S3_SECRET_ACCESS_KEY", None)
 S3_REGION_NAME = os.environ.get("S3_REGION_NAME", None)
 S3_REGION_NAME = os.environ.get("S3_REGION_NAME", None)
 S3_BUCKET_NAME = os.environ.get("S3_BUCKET_NAME", None)
 S3_BUCKET_NAME = os.environ.get("S3_BUCKET_NAME", None)
+S3_KEY_PREFIX = os.environ.get("S3_KEY_PREFIX", None)
 S3_ENDPOINT_URL = os.environ.get("S3_ENDPOINT_URL", None)
 S3_ENDPOINT_URL = os.environ.get("S3_ENDPOINT_URL", None)
 
 
 GCS_BUCKET_NAME = os.environ.get("GCS_BUCKET_NAME", None)
 GCS_BUCKET_NAME = os.environ.get("GCS_BUCKET_NAME", None)
@@ -682,6 +683,17 @@ Path(UPLOAD_DIR).mkdir(parents=True, exist_ok=True)
 CACHE_DIR = f"{DATA_DIR}/cache"
 CACHE_DIR = f"{DATA_DIR}/cache"
 Path(CACHE_DIR).mkdir(parents=True, exist_ok=True)
 Path(CACHE_DIR).mkdir(parents=True, exist_ok=True)
 
 
+
+####################################
+# DIRECT CONNECTIONS
+####################################
+
+ENABLE_DIRECT_CONNECTIONS = PersistentConfig(
+    "ENABLE_DIRECT_CONNECTIONS",
+    "direct.enable",
+    os.environ.get("ENABLE_DIRECT_CONNECTIONS", "True").lower() == "true",
+)
+
 ####################################
 ####################################
 # OLLAMA_BASE_URL
 # OLLAMA_BASE_URL
 ####################################
 ####################################
@@ -1325,6 +1337,54 @@ Your task is to synthesize these responses into a single, high-quality response.
 Responses from models: {{responses}}"""
 Responses from models: {{responses}}"""
 
 
 
 
+####################################
+# Code Interpreter
+####################################
+
+ENABLE_CODE_INTERPRETER = PersistentConfig(
+    "ENABLE_CODE_INTERPRETER",
+    "code_interpreter.enable",
+    os.environ.get("ENABLE_CODE_INTERPRETER", "True").lower() == "true",
+)
+
+CODE_INTERPRETER_ENGINE = PersistentConfig(
+    "CODE_INTERPRETER_ENGINE",
+    "code_interpreter.engine",
+    os.environ.get("CODE_INTERPRETER_ENGINE", "pyodide"),
+)
+
+CODE_INTERPRETER_PROMPT_TEMPLATE = PersistentConfig(
+    "CODE_INTERPRETER_PROMPT_TEMPLATE",
+    "code_interpreter.prompt_template",
+    os.environ.get("CODE_INTERPRETER_PROMPT_TEMPLATE", ""),
+)
+
+CODE_INTERPRETER_JUPYTER_URL = PersistentConfig(
+    "CODE_INTERPRETER_JUPYTER_URL",
+    "code_interpreter.jupyter.url",
+    os.environ.get("CODE_INTERPRETER_JUPYTER_URL", ""),
+)
+
+CODE_INTERPRETER_JUPYTER_AUTH = PersistentConfig(
+    "CODE_INTERPRETER_JUPYTER_AUTH",
+    "code_interpreter.jupyter.auth",
+    os.environ.get("CODE_INTERPRETER_JUPYTER_AUTH", ""),
+)
+
+CODE_INTERPRETER_JUPYTER_AUTH_TOKEN = PersistentConfig(
+    "CODE_INTERPRETER_JUPYTER_AUTH_TOKEN",
+    "code_interpreter.jupyter.auth_token",
+    os.environ.get("CODE_INTERPRETER_JUPYTER_AUTH_TOKEN", ""),
+)
+
+
+CODE_INTERPRETER_JUPYTER_AUTH_PASSWORD = PersistentConfig(
+    "CODE_INTERPRETER_JUPYTER_AUTH_PASSWORD",
+    "code_interpreter.jupyter.auth_password",
+    os.environ.get("CODE_INTERPRETER_JUPYTER_AUTH_PASSWORD", ""),
+)
+
+
 DEFAULT_CODE_INTERPRETER_PROMPT = """
 DEFAULT_CODE_INTERPRETER_PROMPT = """
 #### Tools Available
 #### Tools Available
 
 
@@ -1335,9 +1395,8 @@ DEFAULT_CODE_INTERPRETER_PROMPT = """
    - When coding, **always aim to print meaningful outputs** (e.g., results, tables, summaries, or visuals) to better interpret and verify the findings. Avoid relying on implicit outputs; prioritize explicit and clear print statements so the results are effectively communicated to the user.  
    - When coding, **always aim to print meaningful outputs** (e.g., results, tables, summaries, or visuals) to better interpret and verify the findings. Avoid relying on implicit outputs; prioritize explicit and clear print statements so the results are effectively communicated to the user.  
    - After obtaining the printed output, **always provide a concise analysis, interpretation, or next steps to help the user understand the findings or refine the outcome further.**  
    - After obtaining the printed output, **always provide a concise analysis, interpretation, or next steps to help the user understand the findings or refine the outcome further.**  
    - If the results are unclear, unexpected, or require validation, refine the code and execute it again as needed. Always aim to deliver meaningful insights from the results, iterating if necessary.  
    - If the results are unclear, unexpected, or require validation, refine the code and execute it again as needed. Always aim to deliver meaningful insights from the results, iterating if necessary.  
-   - If a link is provided for an image, audio, or any file, include it in the response exactly as given to ensure the user has access to the original resource.  
+   - **If a link to an image, audio, or any file is provided in markdown format in the output, ALWAYS regurgitate word for word, explicitly display it as part of the response to ensure the user can access it easily, do NOT change the link.**
    - All responses should be communicated in the chat's primary language, ensuring seamless understanding. If the chat is multilingual, default to English for clarity.
    - All responses should be communicated in the chat's primary language, ensuring seamless understanding. If the chat is multilingual, default to English for clarity.
-   - **If a link to an image, audio, or any file is provided in markdown format, ALWAYS regurgitate explicitly display it as part of the response to ensure the user can access it easily, do NOT change the link.**
 
 
 Ensure that the tools are effectively utilized to achieve the highest-quality analysis for the user."""
 Ensure that the tools are effectively utilized to achieve the highest-quality analysis for the user."""
 
 
@@ -1645,7 +1704,7 @@ RAG_WEB_SEARCH_ENGINE = PersistentConfig(
 # This ensures the highest level of safety and reliability of the information sources.
 # This ensures the highest level of safety and reliability of the information sources.
 RAG_WEB_SEARCH_DOMAIN_FILTER_LIST = PersistentConfig(
 RAG_WEB_SEARCH_DOMAIN_FILTER_LIST = PersistentConfig(
     "RAG_WEB_SEARCH_DOMAIN_FILTER_LIST",
     "RAG_WEB_SEARCH_DOMAIN_FILTER_LIST",
-    "rag.rag.web.search.domain.filter_list",
+    "rag.web.search.domain.filter_list",
     [
     [
         # "wikipedia.com",
         # "wikipedia.com",
         # "wikimedia.org",
         # "wikimedia.org",
@@ -1690,6 +1749,12 @@ MOJEEK_SEARCH_API_KEY = PersistentConfig(
     os.getenv("MOJEEK_SEARCH_API_KEY", ""),
     os.getenv("MOJEEK_SEARCH_API_KEY", ""),
 )
 )
 
 
+BOCHA_SEARCH_API_KEY = PersistentConfig(
+    "BOCHA_SEARCH_API_KEY",
+    "rag.web.search.bocha_search_api_key",
+    os.getenv("BOCHA_SEARCH_API_KEY", ""),
+)
+
 SERPSTACK_API_KEY = PersistentConfig(
 SERPSTACK_API_KEY = PersistentConfig(
     "SERPSTACK_API_KEY",
     "SERPSTACK_API_KEY",
     "rag.web.search.serpstack_api_key",
     "rag.web.search.serpstack_api_key",
@@ -2012,6 +2077,12 @@ WHISPER_MODEL_AUTO_UPDATE = (
     and os.environ.get("WHISPER_MODEL_AUTO_UPDATE", "").lower() == "true"
     and os.environ.get("WHISPER_MODEL_AUTO_UPDATE", "").lower() == "true"
 )
 )
 
 
+# Add Deepgram configuration
+DEEPGRAM_API_KEY = PersistentConfig(
+    "DEEPGRAM_API_KEY",
+    "audio.stt.deepgram.api_key",
+    os.getenv("DEEPGRAM_API_KEY", ""),
+)
 
 
 AUDIO_STT_OPENAI_API_BASE_URL = PersistentConfig(
 AUDIO_STT_OPENAI_API_BASE_URL = PersistentConfig(
     "AUDIO_STT_OPENAI_API_BASE_URL",
     "AUDIO_STT_OPENAI_API_BASE_URL",

+ 1 - 0
backend/open_webui/env.py

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

+ 88 - 14
backend/open_webui/main.py

@@ -97,6 +97,16 @@ from open_webui.config import (
     OPENAI_API_BASE_URLS,
     OPENAI_API_BASE_URLS,
     OPENAI_API_KEYS,
     OPENAI_API_KEYS,
     OPENAI_API_CONFIGS,
     OPENAI_API_CONFIGS,
+    # Direct Connections
+    ENABLE_DIRECT_CONNECTIONS,
+    # Code Interpreter
+    ENABLE_CODE_INTERPRETER,
+    CODE_INTERPRETER_ENGINE,
+    CODE_INTERPRETER_PROMPT_TEMPLATE,
+    CODE_INTERPRETER_JUPYTER_URL,
+    CODE_INTERPRETER_JUPYTER_AUTH,
+    CODE_INTERPRETER_JUPYTER_AUTH_TOKEN,
+    CODE_INTERPRETER_JUPYTER_AUTH_PASSWORD,
     # Image
     # Image
     AUTOMATIC1111_API_AUTH,
     AUTOMATIC1111_API_AUTH,
     AUTOMATIC1111_BASE_URL,
     AUTOMATIC1111_BASE_URL,
@@ -130,6 +140,7 @@ from open_webui.config import (
     AUDIO_TTS_AZURE_SPEECH_REGION,
     AUDIO_TTS_AZURE_SPEECH_REGION,
     AUDIO_TTS_AZURE_SPEECH_OUTPUT_FORMAT,
     AUDIO_TTS_AZURE_SPEECH_OUTPUT_FORMAT,
     WHISPER_MODEL,
     WHISPER_MODEL,
+    DEEPGRAM_API_KEY,
     WHISPER_MODEL_AUTO_UPDATE,
     WHISPER_MODEL_AUTO_UPDATE,
     WHISPER_MODEL_DIR,
     WHISPER_MODEL_DIR,
     # Retrieval
     # Retrieval
@@ -180,6 +191,7 @@ from open_webui.config import (
     EXA_API_KEY,
     EXA_API_KEY,
     KAGI_SEARCH_API_KEY,
     KAGI_SEARCH_API_KEY,
     MOJEEK_SEARCH_API_KEY,
     MOJEEK_SEARCH_API_KEY,
+    BOCHA_SEARCH_API_KEY,
     GOOGLE_PSE_API_KEY,
     GOOGLE_PSE_API_KEY,
     GOOGLE_PSE_ENGINE_ID,
     GOOGLE_PSE_ENGINE_ID,
     GOOGLE_DRIVE_CLIENT_ID,
     GOOGLE_DRIVE_CLIENT_ID,
@@ -322,7 +334,11 @@ class SPAStaticFiles(StaticFiles):
             return await super().get_response(path, scope)
             return await super().get_response(path, scope)
         except (HTTPException, StarletteHTTPException) as ex:
         except (HTTPException, StarletteHTTPException) as ex:
             if ex.status_code == 404:
             if ex.status_code == 404:
-                return await super().get_response("index.html", scope)
+                if path.endswith(".js"):
+                    # Return 404 for javascript files
+                    raise ex
+                else:
+                    return await super().get_response("index.html", scope)
             else:
             else:
                 raise ex
                 raise ex
 
 
@@ -389,6 +405,14 @@ app.state.config.OPENAI_API_CONFIGS = OPENAI_API_CONFIGS
 
 
 app.state.OPENAI_MODELS = {}
 app.state.OPENAI_MODELS = {}
 
 
+########################################
+#
+# DIRECT CONNECTIONS
+#
+########################################
+
+app.state.config.ENABLE_DIRECT_CONNECTIONS = ENABLE_DIRECT_CONNECTIONS
+
 ########################################
 ########################################
 #
 #
 # WEBUI
 # WEBUI
@@ -514,6 +538,7 @@ app.state.config.GOOGLE_PSE_ENGINE_ID = GOOGLE_PSE_ENGINE_ID
 app.state.config.BRAVE_SEARCH_API_KEY = BRAVE_SEARCH_API_KEY
 app.state.config.BRAVE_SEARCH_API_KEY = BRAVE_SEARCH_API_KEY
 app.state.config.KAGI_SEARCH_API_KEY = KAGI_SEARCH_API_KEY
 app.state.config.KAGI_SEARCH_API_KEY = KAGI_SEARCH_API_KEY
 app.state.config.MOJEEK_SEARCH_API_KEY = MOJEEK_SEARCH_API_KEY
 app.state.config.MOJEEK_SEARCH_API_KEY = MOJEEK_SEARCH_API_KEY
+app.state.config.BOCHA_SEARCH_API_KEY = BOCHA_SEARCH_API_KEY
 app.state.config.SERPSTACK_API_KEY = SERPSTACK_API_KEY
 app.state.config.SERPSTACK_API_KEY = SERPSTACK_API_KEY
 app.state.config.SERPSTACK_HTTPS = SERPSTACK_HTTPS
 app.state.config.SERPSTACK_HTTPS = SERPSTACK_HTTPS
 app.state.config.SERPER_API_KEY = SERPER_API_KEY
 app.state.config.SERPER_API_KEY = SERPER_API_KEY
@@ -569,6 +594,24 @@ app.state.EMBEDDING_FUNCTION = get_embedding_function(
     app.state.config.RAG_EMBEDDING_BATCH_SIZE,
     app.state.config.RAG_EMBEDDING_BATCH_SIZE,
 )
 )
 
 
+########################################
+#
+# CODE INTERPRETER
+#
+########################################
+
+app.state.config.ENABLE_CODE_INTERPRETER = ENABLE_CODE_INTERPRETER
+app.state.config.CODE_INTERPRETER_ENGINE = CODE_INTERPRETER_ENGINE
+app.state.config.CODE_INTERPRETER_PROMPT_TEMPLATE = CODE_INTERPRETER_PROMPT_TEMPLATE
+
+app.state.config.CODE_INTERPRETER_JUPYTER_URL = CODE_INTERPRETER_JUPYTER_URL
+app.state.config.CODE_INTERPRETER_JUPYTER_AUTH = CODE_INTERPRETER_JUPYTER_AUTH
+app.state.config.CODE_INTERPRETER_JUPYTER_AUTH_TOKEN = (
+    CODE_INTERPRETER_JUPYTER_AUTH_TOKEN
+)
+app.state.config.CODE_INTERPRETER_JUPYTER_AUTH_PASSWORD = (
+    CODE_INTERPRETER_JUPYTER_AUTH_PASSWORD
+)
 
 
 ########################################
 ########################################
 #
 #
@@ -611,6 +654,7 @@ app.state.config.STT_ENGINE = AUDIO_STT_ENGINE
 app.state.config.STT_MODEL = AUDIO_STT_MODEL
 app.state.config.STT_MODEL = AUDIO_STT_MODEL
 
 
 app.state.config.WHISPER_MODEL = WHISPER_MODEL
 app.state.config.WHISPER_MODEL = WHISPER_MODEL
+app.state.config.DEEPGRAM_API_KEY = DEEPGRAM_API_KEY
 
 
 app.state.config.TTS_OPENAI_API_BASE_URL = AUDIO_TTS_OPENAI_API_BASE_URL
 app.state.config.TTS_OPENAI_API_BASE_URL = AUDIO_TTS_OPENAI_API_BASE_URL
 app.state.config.TTS_OPENAI_API_KEY = AUDIO_TTS_OPENAI_API_KEY
 app.state.config.TTS_OPENAI_API_KEY = AUDIO_TTS_OPENAI_API_KEY
@@ -753,6 +797,7 @@ app.include_router(openai.router, prefix="/openai", tags=["openai"])
 app.include_router(pipelines.router, prefix="/api/v1/pipelines", tags=["pipelines"])
 app.include_router(pipelines.router, prefix="/api/v1/pipelines", tags=["pipelines"])
 app.include_router(tasks.router, prefix="/api/v1/tasks", tags=["tasks"])
 app.include_router(tasks.router, prefix="/api/v1/tasks", tags=["tasks"])
 app.include_router(images.router, prefix="/api/v1/images", tags=["images"])
 app.include_router(images.router, prefix="/api/v1/images", tags=["images"])
+
 app.include_router(audio.router, prefix="/api/v1/audio", tags=["audio"])
 app.include_router(audio.router, prefix="/api/v1/audio", tags=["audio"])
 app.include_router(retrieval.router, prefix="/api/v1/retrieval", tags=["retrieval"])
 app.include_router(retrieval.router, prefix="/api/v1/retrieval", tags=["retrieval"])
 
 
@@ -855,20 +900,30 @@ async def chat_completion(
     if not request.app.state.MODELS:
     if not request.app.state.MODELS:
         await get_all_models(request)
         await get_all_models(request)
 
 
+    model_item = form_data.pop("model_item", {})
     tasks = form_data.pop("background_tasks", None)
     tasks = form_data.pop("background_tasks", None)
+
     try:
     try:
-        model_id = form_data.get("model", None)
-        if model_id not in request.app.state.MODELS:
-            raise Exception("Model not found")
-        model = request.app.state.MODELS[model_id]
-        model_info = Models.get_model_by_id(model_id)
-
-        # Check if user has access to the model
-        if not BYPASS_MODEL_ACCESS_CONTROL and user.role == "user":
-            try:
-                check_model_access(user, model)
-            except Exception as e:
-                raise e
+        if not model_item.get("direct", False):
+            model_id = form_data.get("model", None)
+            if model_id not in request.app.state.MODELS:
+                raise Exception("Model not found")
+
+            model = request.app.state.MODELS[model_id]
+            model_info = Models.get_model_by_id(model_id)
+
+            # Check if user has access to the model
+            if not BYPASS_MODEL_ACCESS_CONTROL and user.role == "user":
+                try:
+                    check_model_access(user, model)
+                except Exception as e:
+                    raise e
+        else:
+            model = model_item
+            model_info = None
+
+            request.state.direct = True
+            request.state.model = model
 
 
         metadata = {
         metadata = {
             "user_id": user.id,
             "user_id": user.id,
@@ -880,6 +935,7 @@ async def chat_completion(
             "features": form_data.get("features", None),
             "features": form_data.get("features", None),
             "variables": form_data.get("variables", None),
             "variables": form_data.get("variables", None),
             "model": model_info,
             "model": model_info,
+            "direct": model_item.get("direct", False),
             **(
             **(
                 {"function_calling": "native"}
                 {"function_calling": "native"}
                 if form_data.get("params", {}).get("function_calling") == "native"
                 if form_data.get("params", {}).get("function_calling") == "native"
@@ -891,6 +947,8 @@ async def chat_completion(
                 else {}
                 else {}
             ),
             ),
         }
         }
+
+        request.state.metadata = metadata
         form_data["metadata"] = metadata
         form_data["metadata"] = metadata
 
 
         form_data, metadata, events = await process_chat_payload(
         form_data, metadata, events = await process_chat_payload(
@@ -898,6 +956,7 @@ async def chat_completion(
         )
         )
 
 
     except Exception as e:
     except Exception as e:
+        log.debug(f"Error processing chat payload: {e}")
         raise HTTPException(
         raise HTTPException(
             status_code=status.HTTP_400_BAD_REQUEST,
             status_code=status.HTTP_400_BAD_REQUEST,
             detail=str(e),
             detail=str(e),
@@ -926,6 +985,12 @@ async def chat_completed(
     request: Request, form_data: dict, user=Depends(get_verified_user)
     request: Request, form_data: dict, user=Depends(get_verified_user)
 ):
 ):
     try:
     try:
+        model_item = form_data.pop("model_item", {})
+
+        if model_item.get("direct", False):
+            request.state.direct = True
+            request.state.model = model_item
+
         return await chat_completed_handler(request, form_data, user)
         return await chat_completed_handler(request, form_data, user)
     except Exception as e:
     except Exception as e:
         raise HTTPException(
         raise HTTPException(
@@ -939,6 +1004,12 @@ async def chat_action(
     request: Request, action_id: str, form_data: dict, user=Depends(get_verified_user)
     request: Request, action_id: str, form_data: dict, user=Depends(get_verified_user)
 ):
 ):
     try:
     try:
+        model_item = form_data.pop("model_item", {})
+
+        if model_item.get("direct", False):
+            request.state.direct = True
+            request.state.model = model_item
+
         return await chat_action_handler(request, action_id, form_data, user)
         return await chat_action_handler(request, action_id, form_data, user)
     except Exception as e:
     except Exception as e:
         raise HTTPException(
         raise HTTPException(
@@ -1011,14 +1082,17 @@ async def get_app_config(request: Request):
             "enable_websocket": ENABLE_WEBSOCKET_SUPPORT,
             "enable_websocket": ENABLE_WEBSOCKET_SUPPORT,
             **(
             **(
                 {
                 {
+                    "enable_direct_connections": app.state.config.ENABLE_DIRECT_CONNECTIONS,
                     "enable_channels": app.state.config.ENABLE_CHANNELS,
                     "enable_channels": app.state.config.ENABLE_CHANNELS,
                     "enable_web_search": app.state.config.ENABLE_RAG_WEB_SEARCH,
                     "enable_web_search": app.state.config.ENABLE_RAG_WEB_SEARCH,
-                    "enable_google_drive_integration": app.state.config.ENABLE_GOOGLE_DRIVE_INTEGRATION,
+                    "enable_code_interpreter": app.state.config.ENABLE_CODE_INTERPRETER,
                     "enable_image_generation": app.state.config.ENABLE_IMAGE_GENERATION,
                     "enable_image_generation": app.state.config.ENABLE_IMAGE_GENERATION,
+                    "enable_autocomplete_generation": app.state.config.ENABLE_AUTOCOMPLETE_GENERATION,
                     "enable_community_sharing": app.state.config.ENABLE_COMMUNITY_SHARING,
                     "enable_community_sharing": app.state.config.ENABLE_COMMUNITY_SHARING,
                     "enable_message_rating": app.state.config.ENABLE_MESSAGE_RATING,
                     "enable_message_rating": app.state.config.ENABLE_MESSAGE_RATING,
                     "enable_admin_export": ENABLE_ADMIN_EXPORT,
                     "enable_admin_export": ENABLE_ADMIN_EXPORT,
                     "enable_admin_chat_access": ENABLE_ADMIN_CHAT_ACCESS,
                     "enable_admin_chat_access": ENABLE_ADMIN_CHAT_ACCESS,
+                    "enable_google_drive_integration": app.state.config.ENABLE_GOOGLE_DRIVE_INTEGRATION,
                 }
                 }
                 if user is not None
                 if user is not None
                 else {}
                 else {}

+ 1 - 1
backend/open_webui/models/chats.py

@@ -470,7 +470,7 @@ class ChatTable:
         try:
         try:
             with get_db() as db:
             with get_db() as db:
                 # it is possible that the shared link was deleted. hence,
                 # it is possible that the shared link was deleted. hence,
-                # we check if the chat is still shared by checkng if a chat with the share_id exists
+                # we check if the chat is still shared by checking if a chat with the share_id exists
                 chat = db.query(Chat).filter_by(share_id=id).first()
                 chat = db.query(Chat).filter_by(share_id=id).first()
 
 
                 if chat:
                 if chat:

+ 18 - 0
backend/open_webui/models/users.py

@@ -271,6 +271,24 @@ class UsersTable:
         except Exception:
         except Exception:
             return None
             return None
 
 
+    def update_user_settings_by_id(self, id: str, updated: dict) -> Optional[UserModel]:
+        try:
+            with get_db() as db:
+                user_settings = db.query(User).filter_by(id=id).first().settings
+
+                if user_settings is None:
+                    user_settings = {}
+
+                user_settings.update(updated)
+
+                db.query(User).filter_by(id=id).update({"settings": user_settings})
+                db.commit()
+
+                user = db.query(User).filter_by(id=id).first()
+                return UserModel.model_validate(user)
+        except Exception:
+            return None
+
     def delete_user_by_id(self, id: str) -> bool:
     def delete_user_by_id(self, id: str) -> bool:
         try:
         try:
             # Remove User from Groups
             # Remove User from Groups

+ 28 - 0
backend/open_webui/retrieval/vector/dbs/opensearch.py

@@ -113,6 +113,34 @@ class OpenSearchClient:
 
 
         return self._result_to_search_result(result)
         return self._result_to_search_result(result)
 
 
+    def query(
+        self, collection_name: str, filter: dict, limit: Optional[int] = None
+    ) -> Optional[GetResult]:
+        if not self.has_collection(collection_name):
+            return None
+
+        query_body = {
+            "query": {"bool": {"filter": []}},
+            "_source": ["text", "metadata"],
+        }
+
+        for field, value in filter.items():
+            query_body["query"]["bool"]["filter"].append({"term": {field: value}})
+
+        size = limit if limit else 10
+
+        try:
+            result = self.client.search(
+                index=f"{self.index_prefix}_{collection_name}",
+                body=query_body,
+                size=size,
+            )
+
+            return self._result_to_get_result(result)
+
+        except Exception as e:
+            return None
+
     def get_or_create_index(self, index_name: str, dimension: int):
     def get_or_create_index(self, index_name: str, dimension: int):
         if not self.has_index(index_name):
         if not self.has_index(index_name):
             self._create_index(index_name, dimension)
             self._create_index(index_name, dimension)

+ 65 - 0
backend/open_webui/retrieval/web/bocha.py

@@ -0,0 +1,65 @@
+import logging
+from typing import Optional
+
+import requests
+import json
+from open_webui.retrieval.web.main import SearchResult, get_filtered_results
+from open_webui.env import SRC_LOG_LEVELS
+
+log = logging.getLogger(__name__)
+log.setLevel(SRC_LOG_LEVELS["RAG"])
+
+
+def _parse_response(response):
+    result = {}
+    if "data" in response:
+        data = response["data"]
+        if "webPages" in data:
+            webPages = data["webPages"]
+            if "value" in webPages:
+                result["webpage"] = [
+                    {
+                        "id": item.get("id", ""),
+                        "name": item.get("name", ""),
+                        "url": item.get("url", ""),
+                        "snippet": item.get("snippet", ""),
+                        "summary": item.get("summary", ""),
+                        "siteName": item.get("siteName", ""),
+                        "siteIcon": item.get("siteIcon", ""),
+                        "datePublished": item.get("datePublished", "")
+                        or item.get("dateLastCrawled", ""),
+                    }
+                    for item in webPages["value"]
+                ]
+    return result
+
+
+def search_bocha(
+    api_key: str, query: str, count: int, filter_list: Optional[list[str]] = None
+) -> list[SearchResult]:
+    """Search using Bocha's Search API and return the results as a list of SearchResult objects.
+
+    Args:
+        api_key (str): A Bocha Search API key
+        query (str): The query to search for
+    """
+    url = "https://api.bochaai.com/v1/web-search?utm_source=ollama"
+    headers = {"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"}
+
+    payload = json.dumps(
+        {"query": query, "summary": True, "freshness": "noLimit", "count": count}
+    )
+
+    response = requests.post(url, headers=headers, data=payload, timeout=5)
+    response.raise_for_status()
+    results = _parse_response(response.json())
+    print(results)
+    if filter_list:
+        results = get_filtered_results(results, filter_list)
+
+    return [
+        SearchResult(
+            link=result["url"], title=result.get("name"), snippet=result.get("summary")
+        )
+        for result in results.get("webpage", [])[:count]
+    ]

+ 34 - 15
backend/open_webui/retrieval/web/google_pse.py

@@ -17,34 +17,53 @@ def search_google_pse(
     filter_list: Optional[list[str]] = None,
     filter_list: Optional[list[str]] = None,
 ) -> list[SearchResult]:
 ) -> list[SearchResult]:
     """Search using Google's Programmable Search Engine API and return the results as a list of SearchResult objects.
     """Search using Google's Programmable Search Engine API and return the results as a list of SearchResult objects.
+    Handles pagination for counts greater than 10.
 
 
     Args:
     Args:
         api_key (str): A Programmable Search Engine API key
         api_key (str): A Programmable Search Engine API key
         search_engine_id (str): A Programmable Search Engine ID
         search_engine_id (str): A Programmable Search Engine ID
         query (str): The query to search for
         query (str): The query to search for
+        count (int): The number of results to return (max 100, as PSE max results per query is 10 and max page is 10)
+        filter_list (Optional[list[str]], optional): A list of keywords to filter out from results. Defaults to None.
+
+    Returns:
+        list[SearchResult]: A list of SearchResult objects.
     """
     """
     url = "https://www.googleapis.com/customsearch/v1"
     url = "https://www.googleapis.com/customsearch/v1"
-
     headers = {"Content-Type": "application/json"}
     headers = {"Content-Type": "application/json"}
-    params = {
-        "cx": search_engine_id,
-        "q": query,
-        "key": api_key,
-        "num": count,
-    }
-
-    response = requests.request("GET", url, headers=headers, params=params)
-    response.raise_for_status()
-
-    json_response = response.json()
-    results = json_response.get("items", [])
+    all_results = []
+    start_index = 1  # Google PSE start parameter is 1-based
+
+    while count > 0:
+        num_results_this_page = min(count, 10)  # Google PSE max results per page is 10
+        params = {
+            "cx": search_engine_id,
+            "q": query,
+            "key": api_key,
+            "num": num_results_this_page,
+            "start": start_index,
+        }
+        response = requests.request("GET", url, headers=headers, params=params)
+        response.raise_for_status()
+        json_response = response.json()
+        results = json_response.get("items", [])
+        if results:  # check if results are returned. If not, no more pages to fetch.
+            all_results.extend(results)
+            count -= len(
+                results
+            )  # Decrement count by the number of results fetched in this page.
+            start_index += 10  # Increment start index for the next page
+        else:
+            break  # No more results from Google PSE, break the loop
+
     if filter_list:
     if filter_list:
-        results = get_filtered_results(results, filter_list)
+        all_results = get_filtered_results(all_results, filter_list)
+
     return [
     return [
         SearchResult(
         SearchResult(
             link=result["link"],
             link=result["link"],
             title=result.get("title"),
             title=result.get("title"),
             snippet=result.get("snippet"),
             snippet=result.get("snippet"),
         )
         )
-        for result in results
+        for result in all_results
     ]
     ]

+ 13 - 4
backend/open_webui/retrieval/web/jina_search.py

@@ -20,14 +20,23 @@ def search_jina(api_key: str, query: str, count: int) -> list[SearchResult]:
         list[SearchResult]: A list of search results
         list[SearchResult]: A list of search results
     """
     """
     jina_search_endpoint = "https://s.jina.ai/"
     jina_search_endpoint = "https://s.jina.ai/"
-    headers = {"Accept": "application/json", "Authorization": f"Bearer {api_key}"}
-    url = str(URL(jina_search_endpoint + query))
-    response = requests.get(url, headers=headers)
+
+    headers = {
+        "Accept": "application/json",
+        "Content-Type": "application/json",
+        "Authorization": api_key,
+        "X-Retain-Images": "none",
+    }
+
+    payload = {"q": query, "count": count if count <= 10 else 10}
+
+    url = str(URL(jina_search_endpoint))
+    response = requests.post(url, headers=headers, json=payload)
     response.raise_for_status()
     response.raise_for_status()
     data = response.json()
     data = response.json()
 
 
     results = []
     results = []
-    for result in data["data"][:count]:
+    for result in data["data"]:
         results.append(
         results.append(
             SearchResult(
             SearchResult(
                 link=result["url"],
                 link=result["url"],

+ 68 - 0
backend/open_webui/routers/audio.py

@@ -11,6 +11,7 @@ from pydub.silence import split_on_silence
 import aiohttp
 import aiohttp
 import aiofiles
 import aiofiles
 import requests
 import requests
+import mimetypes
 
 
 from fastapi import (
 from fastapi import (
     Depends,
     Depends,
@@ -138,6 +139,7 @@ class STTConfigForm(BaseModel):
     ENGINE: str
     ENGINE: str
     MODEL: str
     MODEL: str
     WHISPER_MODEL: str
     WHISPER_MODEL: str
+    DEEPGRAM_API_KEY: str
 
 
 
 
 class AudioConfigUpdateForm(BaseModel):
 class AudioConfigUpdateForm(BaseModel):
@@ -165,6 +167,7 @@ async def get_audio_config(request: Request, user=Depends(get_admin_user)):
             "ENGINE": request.app.state.config.STT_ENGINE,
             "ENGINE": request.app.state.config.STT_ENGINE,
             "MODEL": request.app.state.config.STT_MODEL,
             "MODEL": request.app.state.config.STT_MODEL,
             "WHISPER_MODEL": request.app.state.config.WHISPER_MODEL,
             "WHISPER_MODEL": request.app.state.config.WHISPER_MODEL,
+            "DEEPGRAM_API_KEY": request.app.state.config.DEEPGRAM_API_KEY,
         },
         },
     }
     }
 
 
@@ -190,6 +193,7 @@ async def update_audio_config(
     request.app.state.config.STT_ENGINE = form_data.stt.ENGINE
     request.app.state.config.STT_ENGINE = form_data.stt.ENGINE
     request.app.state.config.STT_MODEL = form_data.stt.MODEL
     request.app.state.config.STT_MODEL = form_data.stt.MODEL
     request.app.state.config.WHISPER_MODEL = form_data.stt.WHISPER_MODEL
     request.app.state.config.WHISPER_MODEL = form_data.stt.WHISPER_MODEL
+    request.app.state.config.DEEPGRAM_API_KEY = form_data.stt.DEEPGRAM_API_KEY
 
 
     if request.app.state.config.STT_ENGINE == "":
     if request.app.state.config.STT_ENGINE == "":
         request.app.state.faster_whisper_model = set_faster_whisper_model(
         request.app.state.faster_whisper_model = set_faster_whisper_model(
@@ -214,6 +218,7 @@ async def update_audio_config(
             "ENGINE": request.app.state.config.STT_ENGINE,
             "ENGINE": request.app.state.config.STT_ENGINE,
             "MODEL": request.app.state.config.STT_MODEL,
             "MODEL": request.app.state.config.STT_MODEL,
             "WHISPER_MODEL": request.app.state.config.WHISPER_MODEL,
             "WHISPER_MODEL": request.app.state.config.WHISPER_MODEL,
+            "DEEPGRAM_API_KEY": request.app.state.config.DEEPGRAM_API_KEY,
         },
         },
     }
     }
 
 
@@ -521,6 +526,69 @@ def transcribe(request: Request, file_path):
 
 
             raise Exception(detail if detail else "Open WebUI: Server Connection Error")
             raise Exception(detail if detail else "Open WebUI: Server Connection Error")
 
 
+    elif request.app.state.config.STT_ENGINE == "deepgram":
+        try:
+            # Determine the MIME type of the file
+            mime, _ = mimetypes.guess_type(file_path)
+            if not mime:
+                mime = "audio/wav"  # fallback to wav if undetectable
+
+            # Read the audio file
+            with open(file_path, "rb") as f:
+                file_data = f.read()
+
+            # Build headers and parameters
+            headers = {
+                "Authorization": f"Token {request.app.state.config.DEEPGRAM_API_KEY}",
+                "Content-Type": mime,
+            }
+
+            # Add model if specified
+            params = {}
+            if request.app.state.config.STT_MODEL:
+                params["model"] = request.app.state.config.STT_MODEL
+
+            # Make request to Deepgram API
+            r = requests.post(
+                "https://api.deepgram.com/v1/listen",
+                headers=headers,
+                params=params,
+                data=file_data,
+            )
+            r.raise_for_status()
+            response_data = r.json()
+
+            # Extract transcript from Deepgram response
+            try:
+                transcript = response_data["results"]["channels"][0]["alternatives"][
+                    0
+                ].get("transcript", "")
+            except (KeyError, IndexError) as e:
+                log.error(f"Malformed response from Deepgram: {str(e)}")
+                raise Exception(
+                    "Failed to parse Deepgram response - unexpected response format"
+                )
+            data = {"text": transcript.strip()}
+
+            # Save transcript
+            transcript_file = f"{file_dir}/{id}.json"
+            with open(transcript_file, "w") as f:
+                json.dump(data, f)
+
+            return data
+
+        except Exception as e:
+            log.exception(e)
+            detail = None
+            if r is not None:
+                try:
+                    res = r.json()
+                    if "error" in res:
+                        detail = f"External: {res['error'].get('message', '')}"
+                except Exception:
+                    detail = f"External: {e}"
+            raise Exception(detail if detail else "Open WebUI: Server Connection Error")
+
 
 
 def compress_audio(file_path):
 def compress_audio(file_path):
     if os.path.getsize(file_path) > MAX_FILE_SIZE:
     if os.path.getsize(file_path) > MAX_FILE_SIZE:

+ 92 - 0
backend/open_webui/routers/configs.py

@@ -36,6 +36,98 @@ async def export_config(user=Depends(get_admin_user)):
     return get_config()
     return get_config()
 
 
 
 
+############################
+# Direct Connections Config
+############################
+
+
+class DirectConnectionsConfigForm(BaseModel):
+    ENABLE_DIRECT_CONNECTIONS: bool
+
+
+@router.get("/direct_connections", response_model=DirectConnectionsConfigForm)
+async def get_direct_connections_config(request: Request, user=Depends(get_admin_user)):
+    return {
+        "ENABLE_DIRECT_CONNECTIONS": request.app.state.config.ENABLE_DIRECT_CONNECTIONS,
+    }
+
+
+@router.post("/direct_connections", response_model=DirectConnectionsConfigForm)
+async def set_direct_connections_config(
+    request: Request,
+    form_data: DirectConnectionsConfigForm,
+    user=Depends(get_admin_user),
+):
+    request.app.state.config.ENABLE_DIRECT_CONNECTIONS = (
+        form_data.ENABLE_DIRECT_CONNECTIONS
+    )
+    return {
+        "ENABLE_DIRECT_CONNECTIONS": request.app.state.config.ENABLE_DIRECT_CONNECTIONS,
+    }
+
+
+############################
+# CodeInterpreterConfig
+############################
+class CodeInterpreterConfigForm(BaseModel):
+    ENABLE_CODE_INTERPRETER: bool
+    CODE_INTERPRETER_ENGINE: str
+    CODE_INTERPRETER_PROMPT_TEMPLATE: Optional[str]
+    CODE_INTERPRETER_JUPYTER_URL: Optional[str]
+    CODE_INTERPRETER_JUPYTER_AUTH: Optional[str]
+    CODE_INTERPRETER_JUPYTER_AUTH_TOKEN: Optional[str]
+    CODE_INTERPRETER_JUPYTER_AUTH_PASSWORD: Optional[str]
+
+
+@router.get("/code_interpreter", response_model=CodeInterpreterConfigForm)
+async def get_code_interpreter_config(request: Request, user=Depends(get_admin_user)):
+    return {
+        "ENABLE_CODE_INTERPRETER": request.app.state.config.ENABLE_CODE_INTERPRETER,
+        "CODE_INTERPRETER_ENGINE": request.app.state.config.CODE_INTERPRETER_ENGINE,
+        "CODE_INTERPRETER_PROMPT_TEMPLATE": request.app.state.config.CODE_INTERPRETER_PROMPT_TEMPLATE,
+        "CODE_INTERPRETER_JUPYTER_URL": request.app.state.config.CODE_INTERPRETER_JUPYTER_URL,
+        "CODE_INTERPRETER_JUPYTER_AUTH": request.app.state.config.CODE_INTERPRETER_JUPYTER_AUTH,
+        "CODE_INTERPRETER_JUPYTER_AUTH_TOKEN": request.app.state.config.CODE_INTERPRETER_JUPYTER_AUTH_TOKEN,
+        "CODE_INTERPRETER_JUPYTER_AUTH_PASSWORD": request.app.state.config.CODE_INTERPRETER_JUPYTER_AUTH_PASSWORD,
+    }
+
+
+@router.post("/code_interpreter", response_model=CodeInterpreterConfigForm)
+async def set_code_interpreter_config(
+    request: Request, form_data: CodeInterpreterConfigForm, user=Depends(get_admin_user)
+):
+    request.app.state.config.ENABLE_CODE_INTERPRETER = form_data.ENABLE_CODE_INTERPRETER
+    request.app.state.config.CODE_INTERPRETER_ENGINE = form_data.CODE_INTERPRETER_ENGINE
+    request.app.state.config.CODE_INTERPRETER_PROMPT_TEMPLATE = (
+        form_data.CODE_INTERPRETER_PROMPT_TEMPLATE
+    )
+
+    request.app.state.config.CODE_INTERPRETER_JUPYTER_URL = (
+        form_data.CODE_INTERPRETER_JUPYTER_URL
+    )
+
+    request.app.state.config.CODE_INTERPRETER_JUPYTER_AUTH = (
+        form_data.CODE_INTERPRETER_JUPYTER_AUTH
+    )
+
+    request.app.state.config.CODE_INTERPRETER_JUPYTER_AUTH_TOKEN = (
+        form_data.CODE_INTERPRETER_JUPYTER_AUTH_TOKEN
+    )
+    request.app.state.config.CODE_INTERPRETER_JUPYTER_AUTH_PASSWORD = (
+        form_data.CODE_INTERPRETER_JUPYTER_AUTH_PASSWORD
+    )
+
+    return {
+        "ENABLE_CODE_INTERPRETER": request.app.state.config.ENABLE_CODE_INTERPRETER,
+        "CODE_INTERPRETER_ENGINE": request.app.state.config.CODE_INTERPRETER_ENGINE,
+        "CODE_INTERPRETER_PROMPT_TEMPLATE": request.app.state.config.CODE_INTERPRETER_PROMPT_TEMPLATE,
+        "CODE_INTERPRETER_JUPYTER_URL": request.app.state.config.CODE_INTERPRETER_JUPYTER_URL,
+        "CODE_INTERPRETER_JUPYTER_AUTH": request.app.state.config.CODE_INTERPRETER_JUPYTER_AUTH,
+        "CODE_INTERPRETER_JUPYTER_AUTH_TOKEN": request.app.state.config.CODE_INTERPRETER_JUPYTER_AUTH_TOKEN,
+        "CODE_INTERPRETER_JUPYTER_AUTH_PASSWORD": request.app.state.config.CODE_INTERPRETER_JUPYTER_AUTH_PASSWORD,
+    }
+
+
 ############################
 ############################
 # SetDefaultModels
 # SetDefaultModels
 ############################
 ############################

+ 16 - 20
backend/open_webui/routers/files.py

@@ -3,30 +3,22 @@ import os
 import uuid
 import uuid
 from pathlib import Path
 from pathlib import Path
 from typing import Optional
 from typing import Optional
-from pydantic import BaseModel
-import mimetypes
 from urllib.parse import quote
 from urllib.parse import quote
 
 
-from open_webui.storage.provider import Storage
-
+from fastapi import APIRouter, Depends, File, HTTPException, Request, UploadFile, status
+from fastapi.responses import FileResponse, StreamingResponse
+from open_webui.constants import ERROR_MESSAGES
+from open_webui.env import SRC_LOG_LEVELS
 from open_webui.models.files import (
 from open_webui.models.files import (
     FileForm,
     FileForm,
     FileModel,
     FileModel,
     FileModelResponse,
     FileModelResponse,
     Files,
     Files,
 )
 )
-from open_webui.routers.retrieval import process_file, ProcessFileForm
-
-from open_webui.config import UPLOAD_DIR
-from open_webui.env import SRC_LOG_LEVELS
-from open_webui.constants import ERROR_MESSAGES
-
-
-from fastapi import APIRouter, Depends, File, HTTPException, UploadFile, status, Request
-from fastapi.responses import FileResponse, StreamingResponse
-
-
+from open_webui.routers.retrieval import ProcessFileForm, process_file
+from open_webui.storage.provider import Storage
 from open_webui.utils.auth import get_admin_user, get_verified_user
 from open_webui.utils.auth import get_admin_user, get_verified_user
+from pydantic import BaseModel
 
 
 log = logging.getLogger(__name__)
 log = logging.getLogger(__name__)
 log.setLevel(SRC_LOG_LEVELS["MODELS"])
 log.setLevel(SRC_LOG_LEVELS["MODELS"])
@@ -41,7 +33,10 @@ router = APIRouter()
 
 
 @router.post("/", response_model=FileModelResponse)
 @router.post("/", response_model=FileModelResponse)
 def upload_file(
 def upload_file(
-    request: Request, file: UploadFile = File(...), user=Depends(get_verified_user)
+    request: Request,
+    file: UploadFile = File(...),
+    user=Depends(get_verified_user),
+    file_metadata: dict = {},
 ):
 ):
     log.info(f"file.content_type: {file.content_type}")
     log.info(f"file.content_type: {file.content_type}")
     try:
     try:
@@ -65,6 +60,7 @@ def upload_file(
                         "name": name,
                         "name": name,
                         "content_type": file.content_type,
                         "content_type": file.content_type,
                         "size": len(contents),
                         "size": len(contents),
+                        "data": file_metadata,
                     },
                     },
                 }
                 }
             ),
             ),
@@ -126,7 +122,7 @@ async def delete_all_files(user=Depends(get_admin_user)):
             Storage.delete_all_files()
             Storage.delete_all_files()
         except Exception as e:
         except Exception as e:
             log.exception(e)
             log.exception(e)
-            log.error(f"Error deleting files")
+            log.error("Error deleting files")
             raise HTTPException(
             raise HTTPException(
                 status_code=status.HTTP_400_BAD_REQUEST,
                 status_code=status.HTTP_400_BAD_REQUEST,
                 detail=ERROR_MESSAGES.DEFAULT("Error deleting files"),
                 detail=ERROR_MESSAGES.DEFAULT("Error deleting files"),
@@ -248,7 +244,7 @@ async def get_file_content_by_id(id: str, user=Depends(get_verified_user)):
                 )
                 )
         except Exception as e:
         except Exception as e:
             log.exception(e)
             log.exception(e)
-            log.error(f"Error getting file content")
+            log.error("Error getting file content")
             raise HTTPException(
             raise HTTPException(
                 status_code=status.HTTP_400_BAD_REQUEST,
                 status_code=status.HTTP_400_BAD_REQUEST,
                 detail=ERROR_MESSAGES.DEFAULT("Error getting file content"),
                 detail=ERROR_MESSAGES.DEFAULT("Error getting file content"),
@@ -279,7 +275,7 @@ async def get_html_file_content_by_id(id: str, user=Depends(get_verified_user)):
                 )
                 )
         except Exception as e:
         except Exception as e:
             log.exception(e)
             log.exception(e)
-            log.error(f"Error getting file content")
+            log.error("Error getting file content")
             raise HTTPException(
             raise HTTPException(
                 status_code=status.HTTP_400_BAD_REQUEST,
                 status_code=status.HTTP_400_BAD_REQUEST,
                 detail=ERROR_MESSAGES.DEFAULT("Error getting file content"),
                 detail=ERROR_MESSAGES.DEFAULT("Error getting file content"),
@@ -355,7 +351,7 @@ async def delete_file_by_id(id: str, user=Depends(get_verified_user)):
                 Storage.delete_file(file.path)
                 Storage.delete_file(file.path)
             except Exception as e:
             except Exception as e:
                 log.exception(e)
                 log.exception(e)
-                log.error(f"Error deleting files")
+                log.error("Error deleting files")
                 raise HTTPException(
                 raise HTTPException(
                     status_code=status.HTTP_400_BAD_REQUEST,
                     status_code=status.HTTP_400_BAD_REQUEST,
                     detail=ERROR_MESSAGES.DEFAULT("Error deleting files"),
                     detail=ERROR_MESSAGES.DEFAULT("Error deleting files"),

+ 46 - 69
backend/open_webui/routers/images.py

@@ -1,32 +1,26 @@
 import asyncio
 import asyncio
 import base64
 import base64
+import io
 import json
 import json
 import logging
 import logging
 import mimetypes
 import mimetypes
 import re
 import re
-import uuid
 from pathlib import Path
 from pathlib import Path
 from typing import Optional
 from typing import Optional
 
 
 import requests
 import requests
-
-
-from fastapi import Depends, FastAPI, HTTPException, Request, APIRouter
-from fastapi.middleware.cors import CORSMiddleware
-from pydantic import BaseModel
-
-
+from fastapi import APIRouter, Depends, HTTPException, Request, UploadFile
 from open_webui.config import CACHE_DIR
 from open_webui.config import CACHE_DIR
 from open_webui.constants import ERROR_MESSAGES
 from open_webui.constants import ERROR_MESSAGES
-from open_webui.env import ENV, SRC_LOG_LEVELS, ENABLE_FORWARD_USER_INFO_HEADERS
-
+from open_webui.env import ENABLE_FORWARD_USER_INFO_HEADERS, SRC_LOG_LEVELS
+from open_webui.routers.files import upload_file
 from open_webui.utils.auth import get_admin_user, get_verified_user
 from open_webui.utils.auth import get_admin_user, get_verified_user
 from open_webui.utils.images.comfyui import (
 from open_webui.utils.images.comfyui import (
     ComfyUIGenerateImageForm,
     ComfyUIGenerateImageForm,
     ComfyUIWorkflow,
     ComfyUIWorkflow,
     comfyui_generate_image,
     comfyui_generate_image,
 )
 )
-
+from pydantic import BaseModel
 
 
 log = logging.getLogger(__name__)
 log = logging.getLogger(__name__)
 log.setLevel(SRC_LOG_LEVELS["IMAGES"])
 log.setLevel(SRC_LOG_LEVELS["IMAGES"])
@@ -271,7 +265,6 @@ async def get_image_config(request: Request, user=Depends(get_admin_user)):
 async def update_image_config(
 async def update_image_config(
     request: Request, form_data: ImageConfigForm, user=Depends(get_admin_user)
     request: Request, form_data: ImageConfigForm, user=Depends(get_admin_user)
 ):
 ):
-
     set_image_model(request, form_data.MODEL)
     set_image_model(request, form_data.MODEL)
 
 
     pattern = r"^\d+x\d+$"
     pattern = r"^\d+x\d+$"
@@ -383,40 +376,22 @@ class GenerateImageForm(BaseModel):
     negative_prompt: Optional[str] = None
     negative_prompt: Optional[str] = None
 
 
 
 
-def save_b64_image(b64_str):
+def load_b64_image_data(b64_str):
     try:
     try:
-        image_id = str(uuid.uuid4())
-
         if "," in b64_str:
         if "," in b64_str:
             header, encoded = b64_str.split(",", 1)
             header, encoded = b64_str.split(",", 1)
             mime_type = header.split(";")[0]
             mime_type = header.split(";")[0]
-
             img_data = base64.b64decode(encoded)
             img_data = base64.b64decode(encoded)
-            image_format = mimetypes.guess_extension(mime_type)
-
-            image_filename = f"{image_id}{image_format}"
-            file_path = IMAGE_CACHE_DIR / f"{image_filename}"
-            with open(file_path, "wb") as f:
-                f.write(img_data)
-            return image_filename
         else:
         else:
-            image_filename = f"{image_id}.png"
-            file_path = IMAGE_CACHE_DIR.joinpath(image_filename)
-
+            mime_type = "image/png"
             img_data = base64.b64decode(b64_str)
             img_data = base64.b64decode(b64_str)
-
-            # Write the image data to a file
-            with open(file_path, "wb") as f:
-                f.write(img_data)
-            return image_filename
-
+        return img_data, mime_type
     except Exception as e:
     except Exception as e:
-        log.exception(f"Error saving image: {e}")
+        log.exception(f"Error loading image data: {e}")
         return None
         return None
 
 
 
 
-def save_url_image(url, headers=None):
-    image_id = str(uuid.uuid4())
+def load_url_image_data(url, headers=None):
     try:
     try:
         if headers:
         if headers:
             r = requests.get(url, headers=headers)
             r = requests.get(url, headers=headers)
@@ -426,18 +401,7 @@ def save_url_image(url, headers=None):
         r.raise_for_status()
         r.raise_for_status()
         if r.headers["content-type"].split("/")[0] == "image":
         if r.headers["content-type"].split("/")[0] == "image":
             mime_type = r.headers["content-type"]
             mime_type = r.headers["content-type"]
-            image_format = mimetypes.guess_extension(mime_type)
-
-            if not image_format:
-                raise ValueError("Could not determine image type from MIME type")
-
-            image_filename = f"{image_id}{image_format}"
-
-            file_path = IMAGE_CACHE_DIR.joinpath(f"{image_filename}")
-            with open(file_path, "wb") as image_file:
-                for chunk in r.iter_content(chunk_size=8192):
-                    image_file.write(chunk)
-            return image_filename
+            return r.content, mime_type
         else:
         else:
             log.error("Url does not point to an image.")
             log.error("Url does not point to an image.")
             return None
             return None
@@ -447,6 +411,20 @@ def save_url_image(url, headers=None):
         return None
         return None
 
 
 
 
+def upload_image(request, image_metadata, image_data, content_type, user):
+    image_format = mimetypes.guess_extension(content_type)
+    file = UploadFile(
+        file=io.BytesIO(image_data),
+        filename=f"generated-image{image_format}",  # will be converted to a unique ID on upload_file
+        headers={
+            "content-type": content_type,
+        },
+    )
+    file_item = upload_file(request, file, user, file_metadata=image_metadata)
+    url = request.app.url_path_for("get_file_content_by_id", id=file_item.id)
+    return url
+
+
 @router.post("/generations")
 @router.post("/generations")
 async def image_generations(
 async def image_generations(
     request: Request,
     request: Request,
@@ -500,13 +478,9 @@ async def image_generations(
             images = []
             images = []
 
 
             for image in res["data"]:
             for image in res["data"]:
-                image_filename = save_b64_image(image["b64_json"])
-                images.append({"url": f"/cache/image/generations/{image_filename}"})
-                file_body_path = IMAGE_CACHE_DIR.joinpath(f"{image_filename}.json")
-
-                with open(file_body_path, "w") as f:
-                    json.dump(data, f)
-
+                image_data, content_type = load_b64_image_data(image["b64_json"])
+                url = upload_image(request, data, image_data, content_type, user)
+                images.append({"url": url})
             return images
             return images
 
 
         elif request.app.state.config.IMAGE_GENERATION_ENGINE == "comfyui":
         elif request.app.state.config.IMAGE_GENERATION_ENGINE == "comfyui":
@@ -552,14 +526,15 @@ async def image_generations(
                         "Authorization": f"Bearer {request.app.state.config.COMFYUI_API_KEY}"
                         "Authorization": f"Bearer {request.app.state.config.COMFYUI_API_KEY}"
                     }
                     }
 
 
-                image_filename = save_url_image(image["url"], headers)
-                images.append({"url": f"/cache/image/generations/{image_filename}"})
-                file_body_path = IMAGE_CACHE_DIR.joinpath(f"{image_filename}.json")
-
-                with open(file_body_path, "w") as f:
-                    json.dump(form_data.model_dump(exclude_none=True), f)
-
-            log.debug(f"images: {images}")
+                image_data, content_type = load_url_image_data(image["url"], headers)
+                url = upload_image(
+                    request,
+                    form_data.model_dump(exclude_none=True),
+                    image_data,
+                    content_type,
+                    user,
+                )
+                images.append({"url": url})
             return images
             return images
         elif (
         elif (
             request.app.state.config.IMAGE_GENERATION_ENGINE == "automatic1111"
             request.app.state.config.IMAGE_GENERATION_ENGINE == "automatic1111"
@@ -604,13 +579,15 @@ async def image_generations(
             images = []
             images = []
 
 
             for image in res["images"]:
             for image in res["images"]:
-                image_filename = save_b64_image(image)
-                images.append({"url": f"/cache/image/generations/{image_filename}"})
-                file_body_path = IMAGE_CACHE_DIR.joinpath(f"{image_filename}.json")
-
-                with open(file_body_path, "w") as f:
-                    json.dump({**data, "info": res["info"]}, f)
-
+                image_data, content_type = load_b64_image_data(image)
+                url = upload_image(
+                    request,
+                    {**data, "info": res["info"]},
+                    image_data,
+                    content_type,
+                    user,
+                )
+                images.append({"url": url})
             return images
             return images
     except Exception as e:
     except Exception as e:
         error = e
         error = e

+ 73 - 46
backend/open_webui/routers/ollama.py

@@ -11,10 +11,8 @@ import re
 import time
 import time
 from typing import Optional, Union
 from typing import Optional, Union
 from urllib.parse import urlparse
 from urllib.parse import urlparse
-
 import aiohttp
 import aiohttp
 from aiocache import cached
 from aiocache import cached
-
 import requests
 import requests
 
 
 from fastapi import (
 from fastapi import (
@@ -990,6 +988,8 @@ async def generate_chat_completion(
         )
         )
 
 
     payload = {**form_data.model_dump(exclude_none=True)}
     payload = {**form_data.model_dump(exclude_none=True)}
+    if "metadata" in payload:
+        del payload["metadata"]
 
 
     model_id = payload["model"]
     model_id = payload["model"]
     model_info = Models.get_model_by_id(model_id)
     model_info = Models.get_model_by_id(model_id)
@@ -1408,9 +1408,10 @@ async def download_model(
         return None
         return None
 
 
 
 
+# TODO: Progress bar does not reflect size & duration of upload.
 @router.post("/models/upload")
 @router.post("/models/upload")
 @router.post("/models/upload/{url_idx}")
 @router.post("/models/upload/{url_idx}")
-def upload_model(
+async def upload_model(
     request: Request,
     request: Request,
     file: UploadFile = File(...),
     file: UploadFile = File(...),
     url_idx: Optional[int] = None,
     url_idx: Optional[int] = None,
@@ -1419,59 +1420,85 @@ def upload_model(
     if url_idx is None:
     if url_idx is None:
         url_idx = 0
         url_idx = 0
     ollama_url = request.app.state.config.OLLAMA_BASE_URLS[url_idx]
     ollama_url = request.app.state.config.OLLAMA_BASE_URLS[url_idx]
-
-    file_path = f"{UPLOAD_DIR}/{file.filename}"
-
-    # Save file in chunks
-    with open(file_path, "wb+") as f:
-        for chunk in file.file:
-            f.write(chunk)
-
-    def file_process_stream():
+    file_path = os.path.join(UPLOAD_DIR, file.filename)
+    os.makedirs(UPLOAD_DIR, exist_ok=True)
+
+    # --- P1: save file locally ---
+    chunk_size = 1024 * 1024 * 2  # 2 MB chunks
+    with open(file_path, "wb") as out_f:
+        while True:
+            chunk = file.file.read(chunk_size)
+            # log.info(f"Chunk: {str(chunk)}") # DEBUG
+            if not chunk:
+                break
+            out_f.write(chunk)
+
+    async def file_process_stream():
         nonlocal ollama_url
         nonlocal ollama_url
         total_size = os.path.getsize(file_path)
         total_size = os.path.getsize(file_path)
-        chunk_size = 1024 * 1024
+        log.info(f"Total Model Size: {str(total_size)}")  # DEBUG
+
+        # --- P2: SSE progress + calculate sha256 hash ---
+        file_hash = calculate_sha256(file_path, chunk_size)
+        log.info(f"Model Hash: {str(file_hash)}")  # DEBUG
         try:
         try:
             with open(file_path, "rb") as f:
             with open(file_path, "rb") as f:
-                total = 0
-                done = False
-
-                while not done:
-                    chunk = f.read(chunk_size)
-                    if not chunk:
-                        done = True
-                        continue
-
-                    total += len(chunk)
-                    progress = round((total / total_size) * 100, 2)
-
-                    res = {
+                bytes_read = 0
+                while chunk := f.read(chunk_size):
+                    bytes_read += len(chunk)
+                    progress = round(bytes_read / total_size * 100, 2)
+                    data_msg = {
                         "progress": progress,
                         "progress": progress,
                         "total": total_size,
                         "total": total_size,
-                        "completed": total,
+                        "completed": bytes_read,
                     }
                     }
-                    yield f"data: {json.dumps(res)}\n\n"
+                    yield f"data: {json.dumps(data_msg)}\n\n"
 
 
-                if done:
-                    f.seek(0)
-                    hashed = calculate_sha256(f)
-                    f.seek(0)
+            # --- P3: Upload to ollama /api/blobs ---
+            with open(file_path, "rb") as f:
+                url = f"{ollama_url}/api/blobs/sha256:{file_hash}"
+                response = requests.post(url, data=f)
+
+            if response.ok:
+                log.info(f"Uploaded to /api/blobs")  # DEBUG
+                # Remove local file
+                os.remove(file_path)
+
+                # Create model in ollama
+                model_name, ext = os.path.splitext(file.filename)
+                log.info(f"Created Model: {model_name}")  # DEBUG
+
+                create_payload = {
+                    "model": model_name,
+                    # Reference the file by its original name => the uploaded blob's digest
+                    "files": {file.filename: f"sha256:{file_hash}"},
+                }
+                log.info(f"Model Payload: {create_payload}")  # DEBUG
+
+                # Call ollama /api/create
+                # https://github.com/ollama/ollama/blob/main/docs/api.md#create-a-model
+                create_resp = requests.post(
+                    url=f"{ollama_url}/api/create",
+                    headers={"Content-Type": "application/json"},
+                    data=json.dumps(create_payload),
+                )
 
 
-                    url = f"{ollama_url}/api/blobs/sha256:{hashed}"
-                    response = requests.post(url, data=f)
+                if create_resp.ok:
+                    log.info(f"API SUCCESS!")  # DEBUG
+                    done_msg = {
+                        "done": True,
+                        "blob": f"sha256:{file_hash}",
+                        "name": file.filename,
+                        "model_created": model_name,
+                    }
+                    yield f"data: {json.dumps(done_msg)}\n\n"
+                else:
+                    raise Exception(
+                        f"Failed to create model in Ollama. {create_resp.text}"
+                    )
 
 
-                    if response.ok:
-                        res = {
-                            "done": done,
-                            "blob": f"sha256:{hashed}",
-                            "name": file.filename,
-                        }
-                        os.remove(file_path)
-                        yield f"data: {json.dumps(res)}\n\n"
-                    else:
-                        raise Exception(
-                            "Ollama: Could not create blob, Please try again."
-                        )
+            else:
+                raise Exception("Ollama: Could not create blob, Please try again.")
 
 
         except Exception as e:
         except Exception as e:
             res = {"error": str(e)}
             res = {"error": str(e)}

+ 6 - 6
backend/open_webui/routers/openai.py

@@ -75,9 +75,9 @@ async def cleanup_response(
         await session.close()
         await session.close()
 
 
 
 
-def openai_o1_handler(payload):
+def openai_o1_o3_handler(payload):
     """
     """
-    Handle O1 specific parameters
+    Handle o1, o3 specific parameters
     """
     """
     if "max_tokens" in payload:
     if "max_tokens" in payload:
         # Remove "max_tokens" from the payload
         # Remove "max_tokens" from the payload
@@ -621,10 +621,10 @@ async def generate_chat_completion(
     url = request.app.state.config.OPENAI_API_BASE_URLS[idx]
     url = request.app.state.config.OPENAI_API_BASE_URLS[idx]
     key = request.app.state.config.OPENAI_API_KEYS[idx]
     key = request.app.state.config.OPENAI_API_KEYS[idx]
 
 
-    # Fix: O1 does not support the "max_tokens" parameter, Modify "max_tokens" to "max_completion_tokens"
-    is_o1 = payload["model"].lower().startswith("o1-")
-    if is_o1:
-        payload = openai_o1_handler(payload)
+    # Fix: o1,o3 does not support the "max_tokens" parameter, Modify "max_tokens" to "max_completion_tokens"
+    is_o1_o3 = payload["model"].lower().startswith(("o1", "o3-"))
+    if is_o1_o3:
+        payload = openai_o1_o3_handler(payload)
     elif "api.openai.com" not in url:
     elif "api.openai.com" not in url:
         # Remove "max_completion_tokens" from the payload for backward compatibility
         # Remove "max_completion_tokens" from the payload for backward compatibility
         if "max_completion_tokens" in payload:
         if "max_completion_tokens" in payload:

+ 24 - 0
backend/open_webui/routers/retrieval.py

@@ -45,6 +45,7 @@ from open_webui.retrieval.web.utils import get_web_loader
 from open_webui.retrieval.web.brave import search_brave
 from open_webui.retrieval.web.brave import search_brave
 from open_webui.retrieval.web.kagi import search_kagi
 from open_webui.retrieval.web.kagi import search_kagi
 from open_webui.retrieval.web.mojeek import search_mojeek
 from open_webui.retrieval.web.mojeek import search_mojeek
+from open_webui.retrieval.web.bocha import search_bocha
 from open_webui.retrieval.web.duckduckgo import search_duckduckgo
 from open_webui.retrieval.web.duckduckgo import search_duckduckgo
 from open_webui.retrieval.web.google_pse import search_google_pse
 from open_webui.retrieval.web.google_pse import search_google_pse
 from open_webui.retrieval.web.jina_search import search_jina
 from open_webui.retrieval.web.jina_search import search_jina
@@ -379,6 +380,7 @@ async def get_rag_config(request: Request, user=Depends(get_admin_user)):
                 "brave_search_api_key": request.app.state.config.BRAVE_SEARCH_API_KEY,
                 "brave_search_api_key": request.app.state.config.BRAVE_SEARCH_API_KEY,
                 "kagi_search_api_key": request.app.state.config.KAGI_SEARCH_API_KEY,
                 "kagi_search_api_key": request.app.state.config.KAGI_SEARCH_API_KEY,
                 "mojeek_search_api_key": request.app.state.config.MOJEEK_SEARCH_API_KEY,
                 "mojeek_search_api_key": request.app.state.config.MOJEEK_SEARCH_API_KEY,
+                "bocha_search_api_key": request.app.state.config.BOCHA_SEARCH_API_KEY,
                 "serpstack_api_key": request.app.state.config.SERPSTACK_API_KEY,
                 "serpstack_api_key": request.app.state.config.SERPSTACK_API_KEY,
                 "serpstack_https": request.app.state.config.SERPSTACK_HTTPS,
                 "serpstack_https": request.app.state.config.SERPSTACK_HTTPS,
                 "serper_api_key": request.app.state.config.SERPER_API_KEY,
                 "serper_api_key": request.app.state.config.SERPER_API_KEY,
@@ -392,6 +394,7 @@ async def get_rag_config(request: Request, user=Depends(get_admin_user)):
                 "exa_api_key": request.app.state.config.EXA_API_KEY,
                 "exa_api_key": request.app.state.config.EXA_API_KEY,
                 "result_count": request.app.state.config.RAG_WEB_SEARCH_RESULT_COUNT,
                 "result_count": request.app.state.config.RAG_WEB_SEARCH_RESULT_COUNT,
                 "concurrent_requests": request.app.state.config.RAG_WEB_SEARCH_CONCURRENT_REQUESTS,
                 "concurrent_requests": request.app.state.config.RAG_WEB_SEARCH_CONCURRENT_REQUESTS,
+                "domain_filter_list": request.app.state.config.RAG_WEB_SEARCH_DOMAIN_FILTER_LIST,
             },
             },
         },
         },
     }
     }
@@ -428,6 +431,7 @@ class WebSearchConfig(BaseModel):
     brave_search_api_key: Optional[str] = None
     brave_search_api_key: Optional[str] = None
     kagi_search_api_key: Optional[str] = None
     kagi_search_api_key: Optional[str] = None
     mojeek_search_api_key: Optional[str] = None
     mojeek_search_api_key: Optional[str] = None
+    bocha_search_api_key: Optional[str] = None
     serpstack_api_key: Optional[str] = None
     serpstack_api_key: Optional[str] = None
     serpstack_https: Optional[bool] = None
     serpstack_https: Optional[bool] = None
     serper_api_key: Optional[str] = None
     serper_api_key: Optional[str] = None
@@ -441,6 +445,7 @@ class WebSearchConfig(BaseModel):
     exa_api_key: Optional[str] = None
     exa_api_key: Optional[str] = None
     result_count: Optional[int] = None
     result_count: Optional[int] = None
     concurrent_requests: Optional[int] = None
     concurrent_requests: Optional[int] = None
+    domain_filter_list: Optional[List[str]] = []
 
 
 
 
 class WebConfig(BaseModel):
 class WebConfig(BaseModel):
@@ -523,6 +528,9 @@ async def update_rag_config(
         request.app.state.config.MOJEEK_SEARCH_API_KEY = (
         request.app.state.config.MOJEEK_SEARCH_API_KEY = (
             form_data.web.search.mojeek_search_api_key
             form_data.web.search.mojeek_search_api_key
         )
         )
+        request.app.state.config.BOCHA_SEARCH_API_KEY = (
+            form_data.web.search.bocha_search_api_key
+        )
         request.app.state.config.SERPSTACK_API_KEY = (
         request.app.state.config.SERPSTACK_API_KEY = (
             form_data.web.search.serpstack_api_key
             form_data.web.search.serpstack_api_key
         )
         )
@@ -553,6 +561,9 @@ async def update_rag_config(
         request.app.state.config.RAG_WEB_SEARCH_CONCURRENT_REQUESTS = (
         request.app.state.config.RAG_WEB_SEARCH_CONCURRENT_REQUESTS = (
             form_data.web.search.concurrent_requests
             form_data.web.search.concurrent_requests
         )
         )
+        request.app.state.config.RAG_WEB_SEARCH_DOMAIN_FILTER_LIST = (
+            form_data.web.search.domain_filter_list
+        )
 
 
     return {
     return {
         "status": True,
         "status": True,
@@ -586,6 +597,7 @@ async def update_rag_config(
                 "brave_search_api_key": request.app.state.config.BRAVE_SEARCH_API_KEY,
                 "brave_search_api_key": request.app.state.config.BRAVE_SEARCH_API_KEY,
                 "kagi_search_api_key": request.app.state.config.KAGI_SEARCH_API_KEY,
                 "kagi_search_api_key": request.app.state.config.KAGI_SEARCH_API_KEY,
                 "mojeek_search_api_key": request.app.state.config.MOJEEK_SEARCH_API_KEY,
                 "mojeek_search_api_key": request.app.state.config.MOJEEK_SEARCH_API_KEY,
+                "bocha_search_api_key": request.app.state.config.BOCHA_SEARCH_API_KEY,
                 "serpstack_api_key": request.app.state.config.SERPSTACK_API_KEY,
                 "serpstack_api_key": request.app.state.config.SERPSTACK_API_KEY,
                 "serpstack_https": request.app.state.config.SERPSTACK_HTTPS,
                 "serpstack_https": request.app.state.config.SERPSTACK_HTTPS,
                 "serper_api_key": request.app.state.config.SERPER_API_KEY,
                 "serper_api_key": request.app.state.config.SERPER_API_KEY,
@@ -599,6 +611,7 @@ async def update_rag_config(
                 "exa_api_key": request.app.state.config.EXA_API_KEY,
                 "exa_api_key": request.app.state.config.EXA_API_KEY,
                 "result_count": request.app.state.config.RAG_WEB_SEARCH_RESULT_COUNT,
                 "result_count": request.app.state.config.RAG_WEB_SEARCH_RESULT_COUNT,
                 "concurrent_requests": request.app.state.config.RAG_WEB_SEARCH_CONCURRENT_REQUESTS,
                 "concurrent_requests": request.app.state.config.RAG_WEB_SEARCH_CONCURRENT_REQUESTS,
+                "domain_filter_list": request.app.state.config.RAG_WEB_SEARCH_DOMAIN_FILTER_LIST,
             },
             },
         },
         },
     }
     }
@@ -1107,6 +1120,7 @@ def search_web(request: Request, engine: str, query: str) -> list[SearchResult]:
     - BRAVE_SEARCH_API_KEY
     - BRAVE_SEARCH_API_KEY
     - KAGI_SEARCH_API_KEY
     - KAGI_SEARCH_API_KEY
     - MOJEEK_SEARCH_API_KEY
     - MOJEEK_SEARCH_API_KEY
+    - BOCHA_SEARCH_API_KEY
     - SERPSTACK_API_KEY
     - SERPSTACK_API_KEY
     - SERPER_API_KEY
     - SERPER_API_KEY
     - SERPLY_API_KEY
     - SERPLY_API_KEY
@@ -1174,6 +1188,16 @@ def search_web(request: Request, engine: str, query: str) -> list[SearchResult]:
             )
             )
         else:
         else:
             raise Exception("No MOJEEK_SEARCH_API_KEY found in environment variables")
             raise Exception("No MOJEEK_SEARCH_API_KEY found in environment variables")
+    elif engine == "bocha":
+        if request.app.state.config.BOCHA_SEARCH_API_KEY:
+            return search_bocha(
+                request.app.state.config.BOCHA_SEARCH_API_KEY,
+                query,
+                request.app.state.config.RAG_WEB_SEARCH_RESULT_COUNT,
+                request.app.state.config.RAG_WEB_SEARCH_DOMAIN_FILTER_LIST,
+            )
+        else:
+            raise Exception("No BOCHA_SEARCH_API_KEY found in environment variables")
     elif engine == "serpstack":
     elif engine == "serpstack":
         if request.app.state.config.SERPSTACK_API_KEY:
         if request.app.state.config.SERPSTACK_API_KEY:
             return search_serpstack(
             return search_serpstack(

+ 54 - 8
backend/open_webui/routers/tasks.py

@@ -139,7 +139,12 @@ async def update_task_config(
 async def generate_title(
 async def generate_title(
     request: Request, form_data: dict, user=Depends(get_verified_user)
     request: Request, form_data: dict, user=Depends(get_verified_user)
 ):
 ):
-    models = request.app.state.MODELS
+    if getattr(request.state, "direct", False) and hasattr(request.state, "model"):
+        models = {
+            request.state.model["id"]: request.state.model,
+        }
+    else:
+        models = request.app.state.MODELS
 
 
     model_id = form_data["model"]
     model_id = form_data["model"]
     if model_id not in models:
     if model_id not in models:
@@ -198,6 +203,7 @@ async def generate_title(
             }
             }
         ),
         ),
         "metadata": {
         "metadata": {
+            **(request.state.metadata if hasattr(request.state, "metadata") else {}),
             "task": str(TASKS.TITLE_GENERATION),
             "task": str(TASKS.TITLE_GENERATION),
             "task_body": form_data,
             "task_body": form_data,
             "chat_id": form_data.get("chat_id", None),
             "chat_id": form_data.get("chat_id", None),
@@ -225,7 +231,12 @@ async def generate_chat_tags(
             content={"detail": "Tags generation is disabled"},
             content={"detail": "Tags generation is disabled"},
         )
         )
 
 
-    models = request.app.state.MODELS
+    if getattr(request.state, "direct", False) and hasattr(request.state, "model"):
+        models = {
+            request.state.model["id"]: request.state.model,
+        }
+    else:
+        models = request.app.state.MODELS
 
 
     model_id = form_data["model"]
     model_id = form_data["model"]
     if model_id not in models:
     if model_id not in models:
@@ -261,6 +272,7 @@ async def generate_chat_tags(
         "messages": [{"role": "user", "content": content}],
         "messages": [{"role": "user", "content": content}],
         "stream": False,
         "stream": False,
         "metadata": {
         "metadata": {
+            **(request.state.metadata if hasattr(request.state, "metadata") else {}),
             "task": str(TASKS.TAGS_GENERATION),
             "task": str(TASKS.TAGS_GENERATION),
             "task_body": form_data,
             "task_body": form_data,
             "chat_id": form_data.get("chat_id", None),
             "chat_id": form_data.get("chat_id", None),
@@ -281,7 +293,12 @@ async def generate_chat_tags(
 async def generate_image_prompt(
 async def generate_image_prompt(
     request: Request, form_data: dict, user=Depends(get_verified_user)
     request: Request, form_data: dict, user=Depends(get_verified_user)
 ):
 ):
-    models = request.app.state.MODELS
+    if getattr(request.state, "direct", False) and hasattr(request.state, "model"):
+        models = {
+            request.state.model["id"]: request.state.model,
+        }
+    else:
+        models = request.app.state.MODELS
 
 
     model_id = form_data["model"]
     model_id = form_data["model"]
     if model_id not in models:
     if model_id not in models:
@@ -321,6 +338,7 @@ async def generate_image_prompt(
         "messages": [{"role": "user", "content": content}],
         "messages": [{"role": "user", "content": content}],
         "stream": False,
         "stream": False,
         "metadata": {
         "metadata": {
+            **(request.state.metadata if hasattr(request.state, "metadata") else {}),
             "task": str(TASKS.IMAGE_PROMPT_GENERATION),
             "task": str(TASKS.IMAGE_PROMPT_GENERATION),
             "task_body": form_data,
             "task_body": form_data,
             "chat_id": form_data.get("chat_id", None),
             "chat_id": form_data.get("chat_id", None),
@@ -356,7 +374,12 @@ async def generate_queries(
                 detail=f"Query generation is disabled",
                 detail=f"Query generation is disabled",
             )
             )
 
 
-    models = request.app.state.MODELS
+    if getattr(request.state, "direct", False) and hasattr(request.state, "model"):
+        models = {
+            request.state.model["id"]: request.state.model,
+        }
+    else:
+        models = request.app.state.MODELS
 
 
     model_id = form_data["model"]
     model_id = form_data["model"]
     if model_id not in models:
     if model_id not in models:
@@ -392,6 +415,7 @@ async def generate_queries(
         "messages": [{"role": "user", "content": content}],
         "messages": [{"role": "user", "content": content}],
         "stream": False,
         "stream": False,
         "metadata": {
         "metadata": {
+            **(request.state.metadata if hasattr(request.state, "metadata") else {}),
             "task": str(TASKS.QUERY_GENERATION),
             "task": str(TASKS.QUERY_GENERATION),
             "task_body": form_data,
             "task_body": form_data,
             "chat_id": form_data.get("chat_id", None),
             "chat_id": form_data.get("chat_id", None),
@@ -431,7 +455,12 @@ async def generate_autocompletion(
                 detail=f"Input prompt exceeds maximum length of {request.app.state.config.AUTOCOMPLETE_GENERATION_INPUT_MAX_LENGTH}",
                 detail=f"Input prompt exceeds maximum length of {request.app.state.config.AUTOCOMPLETE_GENERATION_INPUT_MAX_LENGTH}",
             )
             )
 
 
-    models = request.app.state.MODELS
+    if getattr(request.state, "direct", False) and hasattr(request.state, "model"):
+        models = {
+            request.state.model["id"]: request.state.model,
+        }
+    else:
+        models = request.app.state.MODELS
 
 
     model_id = form_data["model"]
     model_id = form_data["model"]
     if model_id not in models:
     if model_id not in models:
@@ -467,6 +496,7 @@ async def generate_autocompletion(
         "messages": [{"role": "user", "content": content}],
         "messages": [{"role": "user", "content": content}],
         "stream": False,
         "stream": False,
         "metadata": {
         "metadata": {
+            **(request.state.metadata if hasattr(request.state, "metadata") else {}),
             "task": str(TASKS.AUTOCOMPLETE_GENERATION),
             "task": str(TASKS.AUTOCOMPLETE_GENERATION),
             "task_body": form_data,
             "task_body": form_data,
             "chat_id": form_data.get("chat_id", None),
             "chat_id": form_data.get("chat_id", None),
@@ -488,7 +518,12 @@ async def generate_emoji(
     request: Request, form_data: dict, user=Depends(get_verified_user)
     request: Request, form_data: dict, user=Depends(get_verified_user)
 ):
 ):
 
 
-    models = request.app.state.MODELS
+    if getattr(request.state, "direct", False) and hasattr(request.state, "model"):
+        models = {
+            request.state.model["id"]: request.state.model,
+        }
+    else:
+        models = request.app.state.MODELS
 
 
     model_id = form_data["model"]
     model_id = form_data["model"]
     if model_id not in models:
     if model_id not in models:
@@ -531,7 +566,11 @@ async def generate_emoji(
             }
             }
         ),
         ),
         "chat_id": form_data.get("chat_id", None),
         "chat_id": form_data.get("chat_id", None),
-        "metadata": {"task": str(TASKS.EMOJI_GENERATION), "task_body": form_data},
+        "metadata": {
+            **(request.state.metadata if hasattr(request.state, "metadata") else {}),
+            "task": str(TASKS.EMOJI_GENERATION),
+            "task_body": form_data,
+        },
     }
     }
 
 
     try:
     try:
@@ -548,7 +587,13 @@ async def generate_moa_response(
     request: Request, form_data: dict, user=Depends(get_verified_user)
     request: Request, form_data: dict, user=Depends(get_verified_user)
 ):
 ):
 
 
-    models = request.app.state.MODELS
+    if getattr(request.state, "direct", False) and hasattr(request.state, "model"):
+        models = {
+            request.state.model["id"]: request.state.model,
+        }
+    else:
+        models = request.app.state.MODELS
+
     model_id = form_data["model"]
     model_id = form_data["model"]
 
 
     if model_id not in models:
     if model_id not in models:
@@ -581,6 +626,7 @@ async def generate_moa_response(
         "messages": [{"role": "user", "content": content}],
         "messages": [{"role": "user", "content": content}],
         "stream": form_data.get("stream", False),
         "stream": form_data.get("stream", False),
         "metadata": {
         "metadata": {
+            **(request.state.metadata if hasattr(request.state, "metadata") else {}),
             "chat_id": form_data.get("chat_id", None),
             "chat_id": form_data.get("chat_id", None),
             "task": str(TASKS.MOA_RESPONSE_GENERATION),
             "task": str(TASKS.MOA_RESPONSE_GENERATION),
             "task_body": form_data,
             "task_body": form_data,

+ 1 - 1
backend/open_webui/routers/users.py

@@ -153,7 +153,7 @@ async def get_user_settings_by_session_user(user=Depends(get_verified_user)):
 async def update_user_settings_by_session_user(
 async def update_user_settings_by_session_user(
     form_data: UserSettings, user=Depends(get_verified_user)
     form_data: UserSettings, user=Depends(get_verified_user)
 ):
 ):
-    user = Users.update_user_by_id(user.id, {"settings": form_data.model_dump()})
+    user = Users.update_user_settings_by_id(user.id, form_data.model_dump())
     if user:
     if user:
         return user.settings
         return user.settings
     else:
     else:

+ 4 - 4
backend/open_webui/socket/main.py

@@ -279,8 +279,8 @@ def get_event_emitter(request_info):
             await sio.emit(
             await sio.emit(
                 "chat-events",
                 "chat-events",
                 {
                 {
-                    "chat_id": request_info["chat_id"],
-                    "message_id": request_info["message_id"],
+                    "chat_id": request_info.get("chat_id", None),
+                    "message_id": request_info.get("message_id", None),
                     "data": event_data,
                     "data": event_data,
                 },
                 },
                 to=session_id,
                 to=session_id,
@@ -329,8 +329,8 @@ def get_event_call(request_info):
         response = await sio.call(
         response = await sio.call(
             "chat-events",
             "chat-events",
             {
             {
-                "chat_id": request_info["chat_id"],
-                "message_id": request_info["message_id"],
+                "chat_id": request_info.get("chat_id", None),
+                "message_id": request_info.get("message_id", None),
                 "data": event_data,
                 "data": event_data,
             },
             },
             to=request_info["session_id"],
             to=request_info["session_id"],

+ 21 - 7
backend/open_webui/storage/provider.py

@@ -10,6 +10,7 @@ from open_webui.config import (
     S3_ACCESS_KEY_ID,
     S3_ACCESS_KEY_ID,
     S3_BUCKET_NAME,
     S3_BUCKET_NAME,
     S3_ENDPOINT_URL,
     S3_ENDPOINT_URL,
+    S3_KEY_PREFIX,
     S3_REGION_NAME,
     S3_REGION_NAME,
     S3_SECRET_ACCESS_KEY,
     S3_SECRET_ACCESS_KEY,
     GCS_BUCKET_NAME,
     GCS_BUCKET_NAME,
@@ -93,15 +94,17 @@ class S3StorageProvider(StorageProvider):
             aws_secret_access_key=S3_SECRET_ACCESS_KEY,
             aws_secret_access_key=S3_SECRET_ACCESS_KEY,
         )
         )
         self.bucket_name = S3_BUCKET_NAME
         self.bucket_name = S3_BUCKET_NAME
+        self.key_prefix = S3_KEY_PREFIX if S3_KEY_PREFIX else ""
 
 
     def upload_file(self, file: BinaryIO, filename: str) -> Tuple[bytes, str]:
     def upload_file(self, file: BinaryIO, filename: str) -> Tuple[bytes, str]:
         """Handles uploading of the file to S3 storage."""
         """Handles uploading of the file to S3 storage."""
         _, file_path = LocalStorageProvider.upload_file(file, filename)
         _, file_path = LocalStorageProvider.upload_file(file, filename)
         try:
         try:
-            self.s3_client.upload_file(file_path, self.bucket_name, filename)
+            s3_key = os.path.join(self.key_prefix, filename)
+            self.s3_client.upload_file(file_path, self.bucket_name, s3_key)
             return (
             return (
                 open(file_path, "rb").read(),
                 open(file_path, "rb").read(),
-                "s3://" + self.bucket_name + "/" + filename,
+                "s3://" + self.bucket_name + "/" + s3_key,
             )
             )
         except ClientError as e:
         except ClientError as e:
             raise RuntimeError(f"Error uploading file to S3: {e}")
             raise RuntimeError(f"Error uploading file to S3: {e}")
@@ -109,18 +112,18 @@ class S3StorageProvider(StorageProvider):
     def get_file(self, file_path: str) -> str:
     def get_file(self, file_path: str) -> str:
         """Handles downloading of the file from S3 storage."""
         """Handles downloading of the file from S3 storage."""
         try:
         try:
-            bucket_name, key = file_path.split("//")[1].split("/")
-            local_file_path = f"{UPLOAD_DIR}/{key}"
-            self.s3_client.download_file(bucket_name, key, local_file_path)
+            s3_key = self._extract_s3_key(file_path)
+            local_file_path = self._get_local_file_path(s3_key)
+            self.s3_client.download_file(self.bucket_name, s3_key, local_file_path)
             return local_file_path
             return local_file_path
         except ClientError as e:
         except ClientError as e:
             raise RuntimeError(f"Error downloading file from S3: {e}")
             raise RuntimeError(f"Error downloading file from S3: {e}")
 
 
     def delete_file(self, file_path: str) -> None:
     def delete_file(self, file_path: str) -> None:
         """Handles deletion of the file from S3 storage."""
         """Handles deletion of the file from S3 storage."""
-        filename = file_path.split("/")[-1]
         try:
         try:
-            self.s3_client.delete_object(Bucket=self.bucket_name, Key=filename)
+            s3_key = self._extract_s3_key(file_path)
+            self.s3_client.delete_object(Bucket=self.bucket_name, Key=s3_key)
         except ClientError as e:
         except ClientError as e:
             raise RuntimeError(f"Error deleting file from S3: {e}")
             raise RuntimeError(f"Error deleting file from S3: {e}")
 
 
@@ -133,6 +136,10 @@ class S3StorageProvider(StorageProvider):
             response = self.s3_client.list_objects_v2(Bucket=self.bucket_name)
             response = self.s3_client.list_objects_v2(Bucket=self.bucket_name)
             if "Contents" in response:
             if "Contents" in response:
                 for content in response["Contents"]:
                 for content in response["Contents"]:
+                    # Skip objects that were not uploaded from open-webui in the first place
+                    if not content["Key"].startswith(self.key_prefix):
+                        continue
+
                     self.s3_client.delete_object(
                     self.s3_client.delete_object(
                         Bucket=self.bucket_name, Key=content["Key"]
                         Bucket=self.bucket_name, Key=content["Key"]
                     )
                     )
@@ -142,6 +149,13 @@ class S3StorageProvider(StorageProvider):
         # Always delete from local storage
         # Always delete from local storage
         LocalStorageProvider.delete_all_files()
         LocalStorageProvider.delete_all_files()
 
 
+    # The s3 key is the name assigned to an object. It excludes the bucket name, but includes the internal path and the file name.
+    def _extract_s3_key(self, full_file_path: str) -> str:
+        return "/".join(full_file_path.split("//")[1].split("/")[1:])
+
+    def _get_local_file_path(self, s3_key: str) -> str:
+        return f"{UPLOAD_DIR}/{s3_key.split('/')[-1]}"
+
 
 
 class GCSStorageProvider(StorageProvider):
 class GCSStorageProvider(StorageProvider):
     def __init__(self):
     def __init__(self):

+ 237 - 180
backend/open_webui/utils/chat.py

@@ -7,14 +7,17 @@ from typing import Any, Optional
 import random
 import random
 import json
 import json
 import inspect
 import inspect
+import uuid
+import asyncio
 
 
-from fastapi import Request
-from starlette.responses import Response, StreamingResponse
+from fastapi import Request, status
+from starlette.responses import Response, StreamingResponse, JSONResponse
 
 
 
 
 from open_webui.models.users import UserModel
 from open_webui.models.users import UserModel
 
 
 from open_webui.socket.main import (
 from open_webui.socket.main import (
+    sio,
     get_event_call,
     get_event_call,
     get_event_emitter,
     get_event_emitter,
 )
 )
@@ -44,6 +47,10 @@ from open_webui.utils.response import (
     convert_response_ollama_to_openai,
     convert_response_ollama_to_openai,
     convert_streaming_response_ollama_to_openai,
     convert_streaming_response_ollama_to_openai,
 )
 )
+from open_webui.utils.filter import (
+    get_sorted_filter_ids,
+    process_filter_functions,
+)
 
 
 from open_webui.env import SRC_LOG_LEVELS, GLOBAL_LOG_LEVEL, BYPASS_MODEL_ACCESS_CONTROL
 from open_webui.env import SRC_LOG_LEVELS, GLOBAL_LOG_LEVEL, BYPASS_MODEL_ACCESS_CONTROL
 
 
@@ -53,6 +60,101 @@ log = logging.getLogger(__name__)
 log.setLevel(SRC_LOG_LEVELS["MAIN"])
 log.setLevel(SRC_LOG_LEVELS["MAIN"])
 
 
 
 
+async def generate_direct_chat_completion(
+    request: Request,
+    form_data: dict,
+    user: Any,
+    models: dict,
+):
+    print("generate_direct_chat_completion")
+
+    metadata = form_data.pop("metadata", {})
+
+    user_id = metadata.get("user_id")
+    session_id = metadata.get("session_id")
+    request_id = str(uuid.uuid4())  # Generate a unique request ID
+
+    event_caller = get_event_call(metadata)
+
+    channel = f"{user_id}:{session_id}:{request_id}"
+
+    if form_data.get("stream"):
+        q = asyncio.Queue()
+
+        async def message_listener(sid, data):
+            """
+            Handle received socket messages and push them into the queue.
+            """
+            await q.put(data)
+
+        # Register the listener
+        sio.on(channel, message_listener)
+
+        # Start processing chat completion in background
+        res = await event_caller(
+            {
+                "type": "request:chat:completion",
+                "data": {
+                    "form_data": form_data,
+                    "model": models[form_data["model"]],
+                    "channel": channel,
+                    "session_id": session_id,
+                },
+            }
+        )
+
+        print("res", res)
+
+        if res.get("status", False):
+            # Define a generator to stream responses
+            async def event_generator():
+                nonlocal q
+                try:
+                    while True:
+                        data = await q.get()  # Wait for new messages
+                        if isinstance(data, dict):
+                            if "done" in data and data["done"]:
+                                break  # Stop streaming when 'done' is received
+
+                            yield f"data: {json.dumps(data)}\n\n"
+                        elif isinstance(data, str):
+                            yield data
+                except Exception as e:
+                    log.debug(f"Error in event generator: {e}")
+                    pass
+
+            # Define a background task to run the event generator
+            async def background():
+                try:
+                    del sio.handlers["/"][channel]
+                except Exception as e:
+                    pass
+
+            # Return the streaming response
+            return StreamingResponse(
+                event_generator(), media_type="text/event-stream", background=background
+            )
+        else:
+            raise Exception(str(res))
+    else:
+        res = await event_caller(
+            {
+                "type": "request:chat:completion",
+                "data": {
+                    "form_data": form_data,
+                    "model": models[form_data["model"]],
+                    "channel": channel,
+                    "session_id": session_id,
+                },
+            }
+        )
+
+        if "error" in res:
+            raise Exception(res["error"])
+
+        return res
+
+
 async def generate_chat_completion(
 async def generate_chat_completion(
     request: Request,
     request: Request,
     form_data: dict,
     form_data: dict,
@@ -62,7 +164,16 @@ async def generate_chat_completion(
     if BYPASS_MODEL_ACCESS_CONTROL:
     if BYPASS_MODEL_ACCESS_CONTROL:
         bypass_filter = True
         bypass_filter = True
 
 
-    models = request.app.state.MODELS
+    if hasattr(request.state, "metadata"):
+        form_data["metadata"] = request.state.metadata
+
+    if getattr(request.state, "direct", False) and hasattr(request.state, "model"):
+        models = {
+            request.state.model["id"]: request.state.model,
+        }
+        log.debug(f"direct connection to model: {models}")
+    else:
+        models = request.app.state.MODELS
 
 
     model_id = form_data["model"]
     model_id = form_data["model"]
     if model_id not in models:
     if model_id not in models:
@@ -83,78 +194,90 @@ async def generate_chat_completion(
         except Exception as e:
         except Exception as e:
             raise e
             raise e
 
 
-    if model["owned_by"] == "arena":
-        model_ids = model.get("info", {}).get("meta", {}).get("model_ids")
-        filter_mode = model.get("info", {}).get("meta", {}).get("filter_mode")
-        if model_ids and filter_mode == "exclude":
-            model_ids = [
-                model["id"]
-                for model in list(request.app.state.MODELS.values())
-                if model.get("owned_by") != "arena" and model["id"] not in model_ids
-            ]
-
-        selected_model_id = None
-        if isinstance(model_ids, list) and model_ids:
-            selected_model_id = random.choice(model_ids)
-        else:
-            model_ids = [
-                model["id"]
-                for model in list(request.app.state.MODELS.values())
-                if model.get("owned_by") != "arena"
-            ]
-            selected_model_id = random.choice(model_ids)
-
-        form_data["model"] = selected_model_id
-
-        if form_data.get("stream") == True:
+    if getattr(request.state, "direct", False):
+        return await generate_direct_chat_completion(
+            request, form_data, user=user, models=models
+        )
 
 
-            async def stream_wrapper(stream):
-                yield f"data: {json.dumps({'selected_model_id': selected_model_id})}\n\n"
-                async for chunk in stream:
-                    yield chunk
+    else:
+        if model["owned_by"] == "arena":
+            model_ids = model.get("info", {}).get("meta", {}).get("model_ids")
+            filter_mode = model.get("info", {}).get("meta", {}).get("filter_mode")
+            if model_ids and filter_mode == "exclude":
+                model_ids = [
+                    model["id"]
+                    for model in list(request.app.state.MODELS.values())
+                    if model.get("owned_by") != "arena" and model["id"] not in model_ids
+                ]
+
+            selected_model_id = None
+            if isinstance(model_ids, list) and model_ids:
+                selected_model_id = random.choice(model_ids)
+            else:
+                model_ids = [
+                    model["id"]
+                    for model in list(request.app.state.MODELS.values())
+                    if model.get("owned_by") != "arena"
+                ]
+                selected_model_id = random.choice(model_ids)
+
+            form_data["model"] = selected_model_id
+
+            if form_data.get("stream") == True:
+
+                async def stream_wrapper(stream):
+                    yield f"data: {json.dumps({'selected_model_id': selected_model_id})}\n\n"
+                    async for chunk in stream:
+                        yield chunk
+
+                response = await generate_chat_completion(
+                    request, form_data, user, bypass_filter=True
+                )
+                return StreamingResponse(
+                    stream_wrapper(response.body_iterator),
+                    media_type="text/event-stream",
+                    background=response.background,
+                )
+            else:
+                return {
+                    **(
+                        await generate_chat_completion(
+                            request, form_data, user, bypass_filter=True
+                        )
+                    ),
+                    "selected_model_id": selected_model_id,
+                }
 
 
-            response = await generate_chat_completion(
-                request, form_data, user, bypass_filter=True
+        if model.get("pipe"):
+            # Below does not require bypass_filter because this is the only route the uses this function and it is already bypassing the filter
+            return await generate_function_chat_completion(
+                request, form_data, user=user, models=models
             )
             )
-            return StreamingResponse(
-                stream_wrapper(response.body_iterator),
-                media_type="text/event-stream",
-                background=response.background,
+        if model["owned_by"] == "ollama":
+            # Using /ollama/api/chat endpoint
+            form_data = convert_payload_openai_to_ollama(form_data)
+            response = await generate_ollama_chat_completion(
+                request=request,
+                form_data=form_data,
+                user=user,
+                bypass_filter=bypass_filter,
             )
             )
+            if form_data.get("stream"):
+                response.headers["content-type"] = "text/event-stream"
+                return StreamingResponse(
+                    convert_streaming_response_ollama_to_openai(response),
+                    headers=dict(response.headers),
+                    background=response.background,
+                )
+            else:
+                return convert_response_ollama_to_openai(response)
         else:
         else:
-            return {
-                **(
-                    await generate_chat_completion(
-                        request, form_data, user, bypass_filter=True
-                    )
-                ),
-                "selected_model_id": selected_model_id,
-            }
-
-    if model.get("pipe"):
-        # Below does not require bypass_filter because this is the only route the uses this function and it is already bypassing the filter
-        return await generate_function_chat_completion(
-            request, form_data, user=user, models=models
-        )
-    if model["owned_by"] == "ollama":
-        # Using /ollama/api/chat endpoint
-        form_data = convert_payload_openai_to_ollama(form_data)
-        response = await generate_ollama_chat_completion(
-            request=request, form_data=form_data, user=user, bypass_filter=bypass_filter
-        )
-        if form_data.get("stream"):
-            response.headers["content-type"] = "text/event-stream"
-            return StreamingResponse(
-                convert_streaming_response_ollama_to_openai(response),
-                headers=dict(response.headers),
-                background=response.background,
+            return await generate_openai_chat_completion(
+                request=request,
+                form_data=form_data,
+                user=user,
+                bypass_filter=bypass_filter,
             )
             )
-        else:
-            return convert_response_ollama_to_openai(response)
-    else:
-        return await generate_openai_chat_completion(
-            request=request, form_data=form_data, user=user, bypass_filter=bypass_filter
-        )
 
 
 
 
 chat_completion = generate_chat_completion
 chat_completion = generate_chat_completion
@@ -163,7 +286,13 @@ chat_completion = generate_chat_completion
 async def chat_completed(request: Request, form_data: dict, user: Any):
 async def chat_completed(request: Request, form_data: dict, user: Any):
     if not request.app.state.MODELS:
     if not request.app.state.MODELS:
         await get_all_models(request)
         await get_all_models(request)
-    models = request.app.state.MODELS
+
+    if getattr(request.state, "direct", False) and hasattr(request.state, "model"):
+        models = {
+            request.state.model["id"]: request.state.model,
+        }
+    else:
+        models = request.app.state.MODELS
 
 
     data = form_data
     data = form_data
     model_id = data["model"]
     model_id = data["model"]
@@ -177,116 +306,38 @@ async def chat_completed(request: Request, form_data: dict, user: Any):
     except Exception as e:
     except Exception as e:
         return Exception(f"Error: {e}")
         return Exception(f"Error: {e}")
 
 
-    __event_emitter__ = get_event_emitter(
-        {
-            "chat_id": data["chat_id"],
-            "message_id": data["id"],
-            "session_id": data["session_id"],
-            "user_id": user.id,
-        }
-    )
-
-    __event_call__ = get_event_call(
-        {
-            "chat_id": data["chat_id"],
-            "message_id": data["id"],
-            "session_id": data["session_id"],
-            "user_id": user.id,
-        }
-    )
-
-    def get_priority(function_id):
-        function = Functions.get_function_by_id(function_id)
-        if function is not None and hasattr(function, "valves"):
-            # TODO: Fix FunctionModel to include vavles
-            return (function.valves if function.valves else {}).get("priority", 0)
-        return 0
-
-    filter_ids = [function.id for function in Functions.get_global_filter_functions()]
-    if "info" in model and "meta" in model["info"]:
-        filter_ids.extend(model["info"]["meta"].get("filterIds", []))
-        filter_ids = list(set(filter_ids))
-
-    enabled_filter_ids = [
-        function.id
-        for function in Functions.get_functions_by_type("filter", active_only=True)
-    ]
-    filter_ids = [
-        filter_id for filter_id in filter_ids if filter_id in enabled_filter_ids
-    ]
-
-    # Sort filter_ids by priority, using the get_priority function
-    filter_ids.sort(key=get_priority)
-
-    for filter_id in filter_ids:
-        filter = Functions.get_function_by_id(filter_id)
-        if not filter:
-            continue
-
-        if filter_id in request.app.state.FUNCTIONS:
-            function_module = request.app.state.FUNCTIONS[filter_id]
-        else:
-            function_module, _, _ = load_function_module_by_id(filter_id)
-            request.app.state.FUNCTIONS[filter_id] = function_module
-
-        if hasattr(function_module, "valves") and hasattr(function_module, "Valves"):
-            valves = Functions.get_function_valves_by_id(filter_id)
-            function_module.valves = function_module.Valves(
-                **(valves if valves else {})
-            )
-
-        if not hasattr(function_module, "outlet"):
-            continue
-        try:
-            outlet = function_module.outlet
-
-            # Get the signature of the function
-            sig = inspect.signature(outlet)
-            params = {"body": data}
-
-            # Extra parameters to be passed to the function
-            extra_params = {
-                "__model__": model,
-                "__id__": filter_id,
-                "__event_emitter__": __event_emitter__,
-                "__event_call__": __event_call__,
-                "__request__": request,
-            }
-
-            # Add extra params in contained in function signature
-            for key, value in extra_params.items():
-                if key in sig.parameters:
-                    params[key] = value
+    metadata = {
+        "chat_id": data["chat_id"],
+        "message_id": data["id"],
+        "session_id": data["session_id"],
+        "user_id": user.id,
+    }
+
+    extra_params = {
+        "__event_emitter__": get_event_emitter(metadata),
+        "__event_call__": get_event_call(metadata),
+        "__user__": {
+            "id": user.id,
+            "email": user.email,
+            "name": user.name,
+            "role": user.role,
+        },
+        "__metadata__": metadata,
+        "__request__": request,
+        "__model__": model,
+    }
 
 
-            if "__user__" in sig.parameters:
-                __user__ = {
-                    "id": user.id,
-                    "email": user.email,
-                    "name": user.name,
-                    "role": user.role,
-                }
-
-                try:
-                    if hasattr(function_module, "UserValves"):
-                        __user__["valves"] = function_module.UserValves(
-                            **Functions.get_user_valves_by_id_and_user_id(
-                                filter_id, user.id
-                            )
-                        )
-                except Exception as e:
-                    print(e)
-
-                params = {**params, "__user__": __user__}
-
-            if inspect.iscoroutinefunction(outlet):
-                data = await outlet(**params)
-            else:
-                data = outlet(**params)
-
-        except Exception as e:
-            return Exception(f"Error: {e}")
-
-    return data
+    try:
+        result, _ = await process_filter_functions(
+            request=request,
+            filter_ids=get_sorted_filter_ids(model),
+            filter_type="outlet",
+            form_data=data,
+            extra_params=extra_params,
+        )
+        return result
+    except Exception as e:
+        return Exception(f"Error: {e}")
 
 
 
 
 async def chat_action(request: Request, action_id: str, form_data: dict, user: Any):
 async def chat_action(request: Request, action_id: str, form_data: dict, user: Any):
@@ -301,7 +352,13 @@ async def chat_action(request: Request, action_id: str, form_data: dict, user: A
 
 
     if not request.app.state.MODELS:
     if not request.app.state.MODELS:
         await get_all_models(request)
         await get_all_models(request)
-    models = request.app.state.MODELS
+
+    if getattr(request.state, "direct", False) and hasattr(request.state, "model"):
+        models = {
+            request.state.model["id"]: request.state.model,
+        }
+    else:
+        models = request.app.state.MODELS
 
 
     data = form_data
     data = form_data
     model_id = data["model"]
     model_id = data["model"]

+ 148 - 0
backend/open_webui/utils/code_interpreter.py

@@ -0,0 +1,148 @@
+import asyncio
+import json
+import uuid
+import websockets
+import requests
+from urllib.parse import urljoin
+
+
+async def execute_code_jupyter(
+    jupyter_url, code, token=None, password=None, timeout=10
+):
+    """
+    Executes Python code in a Jupyter kernel.
+    Supports authentication with a token or password.
+    :param jupyter_url: Jupyter server URL (e.g., "http://localhost:8888")
+    :param code: Code to execute
+    :param token: Jupyter authentication token (optional)
+    :param password: Jupyter password (optional)
+    :param timeout: WebSocket timeout in seconds (default: 10s)
+    :return: Dictionary with stdout, stderr, and result
+             - Images are prefixed with "base64:image/png," and separated by newlines if multiple.
+    """
+    session = requests.Session()  # Maintain cookies
+    headers = {}  # Headers for requests
+
+    # Authenticate using password
+    if password and not token:
+        try:
+            login_url = urljoin(jupyter_url, "/login")
+            response = session.get(login_url)
+            response.raise_for_status()
+            xsrf_token = session.cookies.get("_xsrf")
+            if not xsrf_token:
+                raise ValueError("Failed to fetch _xsrf token")
+
+            login_data = {"_xsrf": xsrf_token, "password": password}
+            login_response = session.post(
+                login_url, data=login_data, cookies=session.cookies
+            )
+            login_response.raise_for_status()
+            headers["X-XSRFToken"] = xsrf_token
+        except Exception as e:
+            return {
+                "stdout": "",
+                "stderr": f"Authentication Error: {str(e)}",
+                "result": "",
+            }
+
+    # Construct API URLs with authentication token if provided
+    params = f"?token={token}" if token else ""
+    kernel_url = urljoin(jupyter_url, f"/api/kernels{params}")
+
+    try:
+        response = session.post(kernel_url, headers=headers, cookies=session.cookies)
+        response.raise_for_status()
+        kernel_id = response.json()["id"]
+
+        websocket_url = urljoin(
+            jupyter_url.replace("http", "ws"),
+            f"/api/kernels/{kernel_id}/channels{params}",
+        )
+
+        ws_headers = {}
+        if password and not token:
+            ws_headers["X-XSRFToken"] = session.cookies.get("_xsrf")
+            cookies = {name: value for name, value in session.cookies.items()}
+            ws_headers["Cookie"] = "; ".join(
+                [f"{name}={value}" for name, value in cookies.items()]
+            )
+
+        async with websockets.connect(
+            websocket_url, additional_headers=ws_headers
+        ) as ws:
+            msg_id = str(uuid.uuid4())
+            execute_request = {
+                "header": {
+                    "msg_id": msg_id,
+                    "msg_type": "execute_request",
+                    "username": "user",
+                    "session": str(uuid.uuid4()),
+                    "date": "",
+                    "version": "5.3",
+                },
+                "parent_header": {},
+                "metadata": {},
+                "content": {
+                    "code": code,
+                    "silent": False,
+                    "store_history": True,
+                    "user_expressions": {},
+                    "allow_stdin": False,
+                    "stop_on_error": True,
+                },
+                "channel": "shell",
+            }
+            await ws.send(json.dumps(execute_request))
+
+            stdout, stderr, result = "", "", []
+
+            while True:
+                try:
+                    message = await asyncio.wait_for(ws.recv(), timeout)
+                    message_data = json.loads(message)
+                    if message_data.get("parent_header", {}).get("msg_id") == msg_id:
+                        msg_type = message_data.get("msg_type")
+
+                        if msg_type == "stream":
+                            if message_data["content"]["name"] == "stdout":
+                                stdout += message_data["content"]["text"]
+                            elif message_data["content"]["name"] == "stderr":
+                                stderr += message_data["content"]["text"]
+
+                        elif msg_type in ("execute_result", "display_data"):
+                            data = message_data["content"]["data"]
+                            if "image/png" in data:
+                                result.append(
+                                    f"data:image/png;base64,{data['image/png']}"
+                                )
+                            elif "text/plain" in data:
+                                result.append(data["text/plain"])
+
+                        elif msg_type == "error":
+                            stderr += "\n".join(message_data["content"]["traceback"])
+
+                        elif (
+                            msg_type == "status"
+                            and message_data["content"]["execution_state"] == "idle"
+                        ):
+                            break
+
+                except asyncio.TimeoutError:
+                    stderr += "\nExecution timed out."
+                    break
+
+    except Exception as e:
+        return {"stdout": "", "stderr": f"Error: {str(e)}", "result": ""}
+
+    finally:
+        if kernel_id:
+            requests.delete(
+                f"{kernel_url}/{kernel_id}", headers=headers, cookies=session.cookies
+            )
+
+    return {
+        "stdout": stdout.strip(),
+        "stderr": stderr.strip(),
+        "result": "\n".join(result).strip() if result else "",
+    }

+ 99 - 0
backend/open_webui/utils/filter.py

@@ -0,0 +1,99 @@
+import inspect
+from open_webui.utils.plugin import load_function_module_by_id
+from open_webui.models.functions import Functions
+
+
+def get_sorted_filter_ids(model):
+    def get_priority(function_id):
+        function = Functions.get_function_by_id(function_id)
+        if function is not None and hasattr(function, "valves"):
+            # TODO: Fix FunctionModel to include vavles
+            return (function.valves if function.valves else {}).get("priority", 0)
+        return 0
+
+    filter_ids = [function.id for function in Functions.get_global_filter_functions()]
+    if "info" in model and "meta" in model["info"]:
+        filter_ids.extend(model["info"]["meta"].get("filterIds", []))
+        filter_ids = list(set(filter_ids))
+
+    enabled_filter_ids = [
+        function.id
+        for function in Functions.get_functions_by_type("filter", active_only=True)
+    ]
+
+    filter_ids = [fid for fid in filter_ids if fid in enabled_filter_ids]
+    filter_ids.sort(key=get_priority)
+    return filter_ids
+
+
+async def process_filter_functions(
+    request, filter_ids, filter_type, form_data, extra_params
+):
+    skip_files = None
+
+    for filter_id in filter_ids:
+        filter = Functions.get_function_by_id(filter_id)
+        if not filter:
+            continue
+
+        if filter_id in request.app.state.FUNCTIONS:
+            function_module = request.app.state.FUNCTIONS[filter_id]
+        else:
+            function_module, _, _ = load_function_module_by_id(filter_id)
+            request.app.state.FUNCTIONS[filter_id] = function_module
+
+        # Check if the function has a file_handler variable
+        if filter_type == "inlet" and hasattr(function_module, "file_handler"):
+            skip_files = function_module.file_handler
+
+        # Apply valves to the function
+        if hasattr(function_module, "valves") and hasattr(function_module, "Valves"):
+            valves = Functions.get_function_valves_by_id(filter_id)
+            function_module.valves = function_module.Valves(
+                **(valves if valves else {})
+            )
+
+        # Prepare handler function
+        handler = getattr(function_module, filter_type, None)
+        if not handler:
+            continue
+
+        try:
+            # Prepare parameters
+            sig = inspect.signature(handler)
+            params = {"body": form_data} | {
+                k: v
+                for k, v in {
+                    **extra_params,
+                    "__id__": filter_id,
+                }.items()
+                if k in sig.parameters
+            }
+
+            # Handle user parameters
+            if "__user__" in sig.parameters:
+                if hasattr(function_module, "UserValves"):
+                    try:
+                        params["__user__"]["valves"] = function_module.UserValves(
+                            **Functions.get_user_valves_by_id_and_user_id(
+                                filter_id, params["__user__"]["id"]
+                            )
+                        )
+                    except Exception as e:
+                        print(e)
+
+            # Execute handler
+            if inspect.iscoroutinefunction(handler):
+                form_data = await handler(**params)
+            else:
+                form_data = handler(**params)
+
+        except Exception as e:
+            print(f"Error in {filter_type} handler {filter_id}: {e}")
+            raise e
+
+    # Handle file cleanup for inlet
+    if skip_files and "files" in form_data.get("metadata", {}):
+        del form_data["metadata"]["files"]
+
+    return form_data, {}

+ 1 - 1
backend/open_webui/utils/images/comfyui.py

@@ -161,7 +161,7 @@ async def comfyui_generate_image(
                 seed = (
                 seed = (
                     payload.seed
                     payload.seed
                     if payload.seed
                     if payload.seed
-                    else random.randint(0, 18446744073709551614)
+                    else random.randint(0, 1125899906842624)
                 )
                 )
                 for node_id in node.node_ids:
                 for node_id in node.node_ids:
                     workflow[node_id]["inputs"][node.key] = seed
                     workflow[node_id]["inputs"][node.key] = seed

+ 144 - 122
backend/open_webui/utils/middleware.py

@@ -68,7 +68,11 @@ from open_webui.utils.misc import (
 )
 )
 from open_webui.utils.tools import get_tools
 from open_webui.utils.tools import get_tools
 from open_webui.utils.plugin import load_function_module_by_id
 from open_webui.utils.plugin import load_function_module_by_id
-
+from open_webui.utils.filter import (
+    get_sorted_filter_ids,
+    process_filter_functions,
+)
+from open_webui.utils.code_interpreter import execute_code_jupyter
 
 
 from open_webui.tasks import create_task
 from open_webui.tasks import create_task
 
 
@@ -91,99 +95,6 @@ log = logging.getLogger(__name__)
 log.setLevel(SRC_LOG_LEVELS["MAIN"])
 log.setLevel(SRC_LOG_LEVELS["MAIN"])
 
 
 
 
-async def chat_completion_filter_functions_handler(request, body, model, extra_params):
-    skip_files = None
-
-    def get_filter_function_ids(model):
-        def get_priority(function_id):
-            function = Functions.get_function_by_id(function_id)
-            if function is not None and hasattr(function, "valves"):
-                # TODO: Fix FunctionModel
-                return (function.valves if function.valves else {}).get("priority", 0)
-            return 0
-
-        filter_ids = [
-            function.id for function in Functions.get_global_filter_functions()
-        ]
-        if "info" in model and "meta" in model["info"]:
-            filter_ids.extend(model["info"]["meta"].get("filterIds", []))
-            filter_ids = list(set(filter_ids))
-
-        enabled_filter_ids = [
-            function.id
-            for function in Functions.get_functions_by_type("filter", active_only=True)
-        ]
-
-        filter_ids = [
-            filter_id for filter_id in filter_ids if filter_id in enabled_filter_ids
-        ]
-
-        filter_ids.sort(key=get_priority)
-        return filter_ids
-
-    filter_ids = get_filter_function_ids(model)
-    for filter_id in filter_ids:
-        filter = Functions.get_function_by_id(filter_id)
-        if not filter:
-            continue
-
-        if filter_id in request.app.state.FUNCTIONS:
-            function_module = request.app.state.FUNCTIONS[filter_id]
-        else:
-            function_module, _, _ = load_function_module_by_id(filter_id)
-            request.app.state.FUNCTIONS[filter_id] = function_module
-
-        # Check if the function has a file_handler variable
-        if hasattr(function_module, "file_handler"):
-            skip_files = function_module.file_handler
-
-        # Apply valves to the function
-        if hasattr(function_module, "valves") and hasattr(function_module, "Valves"):
-            valves = Functions.get_function_valves_by_id(filter_id)
-            function_module.valves = function_module.Valves(
-                **(valves if valves else {})
-            )
-
-        if hasattr(function_module, "inlet"):
-            try:
-                inlet = function_module.inlet
-
-                # Create a dictionary of parameters to be passed to the function
-                params = {"body": body} | {
-                    k: v
-                    for k, v in {
-                        **extra_params,
-                        "__model__": model,
-                        "__id__": filter_id,
-                    }.items()
-                    if k in inspect.signature(inlet).parameters
-                }
-
-                if "__user__" in params and hasattr(function_module, "UserValves"):
-                    try:
-                        params["__user__"]["valves"] = function_module.UserValves(
-                            **Functions.get_user_valves_by_id_and_user_id(
-                                filter_id, params["__user__"]["id"]
-                            )
-                        )
-                    except Exception as e:
-                        print(e)
-
-                if inspect.iscoroutinefunction(inlet):
-                    body = await inlet(**params)
-                else:
-                    body = inlet(**params)
-
-            except Exception as e:
-                print(f"Error: {e}")
-                raise e
-
-    if skip_files and "files" in body.get("metadata", {}):
-        del body["metadata"]["files"]
-
-    return body, {}
-
-
 async def chat_completion_tools_handler(
 async def chat_completion_tools_handler(
     request: Request, body: dict, user: UserModel, models, tools
     request: Request, body: dict, user: UserModel, models, tools
 ) -> tuple[dict, dict]:
 ) -> tuple[dict, dict]:
@@ -572,13 +483,13 @@ async def chat_image_generation_handler(
             {
             {
                 "type": "status",
                 "type": "status",
                 "data": {
                 "data": {
-                    "description": f"An error occured while generating an image",
+                    "description": f"An error occurred while generating an image",
                     "done": True,
                     "done": True,
                 },
                 },
             }
             }
         )
         )
 
 
-        system_message_content = "<context>Unable to generate an image, tell the user that an error occured</context>"
+        system_message_content = "<context>Unable to generate an image, tell the user that an error occurred</context>"
 
 
     if system_message_content:
     if system_message_content:
         form_data["messages"] = add_or_update_system_message(
         form_data["messages"] = add_or_update_system_message(
@@ -706,11 +617,18 @@ async def process_chat_payload(request, form_data, metadata, user, model):
         },
         },
         "__metadata__": metadata,
         "__metadata__": metadata,
         "__request__": request,
         "__request__": request,
+        "__model__": model,
     }
     }
 
 
     # Initialize events to store additional event to be sent to the client
     # Initialize events to store additional event to be sent to the client
     # Initialize contexts and citation
     # Initialize contexts and citation
-    models = request.app.state.MODELS
+    if getattr(request.state, "direct", False) and hasattr(request.state, "model"):
+        models = {
+            request.state.model["id"]: request.state.model,
+        }
+    else:
+        models = request.app.state.MODELS
+
     task_model_id = get_task_model_id(
     task_model_id = get_task_model_id(
         form_data["model"],
         form_data["model"],
         request.app.state.config.TASK_MODEL,
         request.app.state.config.TASK_MODEL,
@@ -778,12 +696,21 @@ async def process_chat_payload(request, form_data, metadata, user, model):
 
 
         if "code_interpreter" in features and features["code_interpreter"]:
         if "code_interpreter" in features and features["code_interpreter"]:
             form_data["messages"] = add_or_update_user_message(
             form_data["messages"] = add_or_update_user_message(
-                DEFAULT_CODE_INTERPRETER_PROMPT, form_data["messages"]
+                (
+                    request.app.state.config.CODE_INTERPRETER_PROMPT_TEMPLATE
+                    if request.app.state.config.CODE_INTERPRETER_PROMPT_TEMPLATE != ""
+                    else DEFAULT_CODE_INTERPRETER_PROMPT
+                ),
+                form_data["messages"],
             )
             )
 
 
     try:
     try:
-        form_data, flags = await chat_completion_filter_functions_handler(
-            request, form_data, model, extra_params
+        form_data, flags = await process_filter_functions(
+            request=request,
+            filter_ids=get_sorted_filter_ids(model),
+            filter_type="inlet",
+            form_data=form_data,
+            extra_params=extra_params,
         )
         )
     except Exception as e:
     except Exception as e:
         raise Exception(f"Error: {e}")
         raise Exception(f"Error: {e}")
@@ -851,17 +778,7 @@ async def process_chat_payload(request, form_data, metadata, user, model):
 
 
             if "document" in source:
             if "document" in source:
                 for doc_idx, doc_context in enumerate(source["document"]):
                 for doc_idx, doc_context in enumerate(source["document"]):
-                    doc_metadata = source.get("metadata")
-                    doc_source_id = None
-
-                    if doc_metadata:
-                        doc_source_id = doc_metadata[doc_idx].get("source", source_id)
-
-                    if source_id:
-                        context_string += f"<source><source_id>{doc_source_id if doc_source_id is not None else source_id}</source_id><source_context>{doc_context}</source_context></source>\n"
-                    else:
-                        # If there is no source_id, then do not include the source_id tag
-                        context_string += f"<source><source_context>{doc_context}</source_context></source>\n"
+                    context_string += f"<source><source_id>{doc_idx}</source_id><source_context>{doc_context}</source_context></source>\n"
 
 
         context_string = context_string.strip()
         context_string = context_string.strip()
         prompt = get_last_user_message(form_data["messages"])
         prompt = get_last_user_message(form_data["messages"])
@@ -1122,6 +1039,20 @@ async def process_chat_response(
             },
             },
         )
         )
 
 
+        def split_content_and_whitespace(content):
+            content_stripped = content.rstrip()
+            original_whitespace = (
+                content[len(content_stripped) :]
+                if len(content) > len(content_stripped)
+                else ""
+            )
+            return content_stripped, original_whitespace
+
+        def is_opening_code_block(content):
+            backtick_segments = content.split("```")
+            # Even number of segments means the last backticks are opening a new block
+            return len(backtick_segments) > 1 and len(backtick_segments) % 2 == 0
+
         # Handle as a background task
         # Handle as a background task
         async def post_response_handler(response, events):
         async def post_response_handler(response, events):
             def serialize_content_blocks(content_blocks, raw=False):
             def serialize_content_blocks(content_blocks, raw=False):
@@ -1188,6 +1119,19 @@ async def process_chat_response(
                         output = block.get("output", None)
                         output = block.get("output", None)
                         lang = attributes.get("lang", "")
                         lang = attributes.get("lang", "")
 
 
+                        content_stripped, original_whitespace = (
+                            split_content_and_whitespace(content)
+                        )
+                        if is_opening_code_block(content_stripped):
+                            # Remove trailing backticks that would open a new block
+                            content = (
+                                content_stripped.rstrip("`").rstrip()
+                                + original_whitespace
+                            )
+                        else:
+                            # Keep content as is - either closing backticks or no backticks
+                            content = content_stripped + original_whitespace
+
                         if output:
                         if output:
                             output = html.escape(json.dumps(output))
                             output = html.escape(json.dumps(output))
 
 
@@ -1242,10 +1186,10 @@ async def process_chat_response(
                                 match.end() :
                                 match.end() :
                             ]  # Content after opening tag
                             ]  # Content after opening tag
 
 
-                            # Remove the start tag from the currently handling text block
+                            # Remove the start tag and after from the currently handling text block
                             content_blocks[-1]["content"] = content_blocks[-1][
                             content_blocks[-1]["content"] = content_blocks[-1][
                                 "content"
                                 "content"
-                            ].replace(match.group(0), "")
+                            ].replace(match.group(0) + after_tag, "")
 
 
                             if before_tag:
                             if before_tag:
                                 content_blocks[-1]["content"] = before_tag
                                 content_blocks[-1]["content"] = before_tag
@@ -1702,26 +1646,70 @@ async def process_chat_response(
                         content_blocks[-1]["type"] == "code_interpreter"
                         content_blocks[-1]["type"] == "code_interpreter"
                         and retries < MAX_RETRIES
                         and retries < MAX_RETRIES
                     ):
                     ):
+                        await event_emitter(
+                            {
+                                "type": "chat:completion",
+                                "data": {
+                                    "content": serialize_content_blocks(content_blocks),
+                                },
+                            }
+                        )
+
                         retries += 1
                         retries += 1
                         log.debug(f"Attempt count: {retries}")
                         log.debug(f"Attempt count: {retries}")
 
 
                         output = ""
                         output = ""
                         try:
                         try:
                             if content_blocks[-1]["attributes"].get("type") == "code":
                             if content_blocks[-1]["attributes"].get("type") == "code":
-                                output = await event_caller(
-                                    {
-                                        "type": "execute:python",
-                                        "data": {
-                                            "id": str(uuid4()),
-                                            "code": content_blocks[-1]["content"],
-                                        },
+                                code = content_blocks[-1]["content"]
+
+                                if (
+                                    request.app.state.config.CODE_INTERPRETER_ENGINE
+                                    == "pyodide"
+                                ):
+                                    output = await event_caller(
+                                        {
+                                            "type": "execute:python",
+                                            "data": {
+                                                "id": str(uuid4()),
+                                                "code": code,
+                                                "session_id": metadata.get(
+                                                    "session_id", None
+                                                ),
+                                            },
+                                        }
+                                    )
+                                elif (
+                                    request.app.state.config.CODE_INTERPRETER_ENGINE
+                                    == "jupyter"
+                                ):
+                                    output = await execute_code_jupyter(
+                                        request.app.state.config.CODE_INTERPRETER_JUPYTER_URL,
+                                        code,
+                                        (
+                                            request.app.state.config.CODE_INTERPRETER_JUPYTER_AUTH_TOKEN
+                                            if request.app.state.config.CODE_INTERPRETER_JUPYTER_AUTH
+                                            == "token"
+                                            else None
+                                        ),
+                                        (
+                                            request.app.state.config.CODE_INTERPRETER_JUPYTER_AUTH_PASSWORD
+                                            if request.app.state.config.CODE_INTERPRETER_JUPYTER_AUTH
+                                            == "password"
+                                            else None
+                                        ),
+                                    )
+                                else:
+                                    output = {
+                                        "stdout": "Code interpreter engine not configured."
                                     }
                                     }
-                                )
+
+                                log.debug(f"Code interpreter output: {output}")
 
 
                                 if isinstance(output, dict):
                                 if isinstance(output, dict):
                                     stdout = output.get("stdout", "")
                                     stdout = output.get("stdout", "")
 
 
-                                    if stdout:
+                                    if isinstance(stdout, str):
                                         stdoutLines = stdout.split("\n")
                                         stdoutLines = stdout.split("\n")
                                         for idx, line in enumerate(stdoutLines):
                                         for idx, line in enumerate(stdoutLines):
                                             if "data:image/png;base64" in line:
                                             if "data:image/png;base64" in line:
@@ -1750,6 +1738,38 @@ async def process_chat_response(
                                                 )
                                                 )
 
 
                                         output["stdout"] = "\n".join(stdoutLines)
                                         output["stdout"] = "\n".join(stdoutLines)
+
+                                    result = output.get("result", "")
+
+                                    if isinstance(result, str):
+                                        resultLines = result.split("\n")
+                                        for idx, line in enumerate(resultLines):
+                                            if "data:image/png;base64" in line:
+                                                id = str(uuid4())
+
+                                                # ensure the path exists
+                                                os.makedirs(
+                                                    os.path.join(CACHE_DIR, "images"),
+                                                    exist_ok=True,
+                                                )
+
+                                                image_path = os.path.join(
+                                                    CACHE_DIR,
+                                                    f"images/{id}.png",
+                                                )
+
+                                                with open(image_path, "wb") as f:
+                                                    f.write(
+                                                        base64.b64decode(
+                                                            line.split(",")[1]
+                                                        )
+                                                    )
+
+                                                resultLines[idx] = (
+                                                    f"![Output Image {idx}](/cache/images/{id}.png)"
+                                                )
+
+                                        output["result"] = "\n".join(resultLines)
                         except Exception as e:
                         except Exception as e:
                             output = str(e)
                             output = str(e)
 
 
@@ -1771,6 +1791,8 @@ async def process_chat_response(
                             }
                             }
                         )
                         )
 
 
+                        print(content_blocks, serialize_content_blocks(content_blocks))
+
                         try:
                         try:
                             res = await generate_chat_completion(
                             res = await generate_chat_completion(
                                 request,
                                 request,

+ 13 - 5
backend/open_webui/utils/misc.py

@@ -217,12 +217,19 @@ def openai_chat_chunk_message_template(
 
 
 
 
 def openai_chat_completion_message_template(
 def openai_chat_completion_message_template(
-    model: str, message: Optional[str] = None, usage: Optional[dict] = None
+    model: str,
+    message: Optional[str] = None,
+    tool_calls: Optional[list[dict]] = None,
+    usage: Optional[dict] = None,
 ) -> dict:
 ) -> dict:
     template = openai_chat_message_template(model)
     template = openai_chat_message_template(model)
     template["object"] = "chat.completion"
     template["object"] = "chat.completion"
     if message is not None:
     if message is not None:
         template["choices"][0]["message"] = {"content": message, "role": "assistant"}
         template["choices"][0]["message"] = {"content": message, "role": "assistant"}
+
+    if tool_calls:
+        template["choices"][0]["tool_calls"] = tool_calls
+
     template["choices"][0]["finish_reason"] = "stop"
     template["choices"][0]["finish_reason"] = "stop"
 
 
     if usage:
     if usage:
@@ -244,11 +251,12 @@ def get_gravatar_url(email):
     return f"https://www.gravatar.com/avatar/{hash_hex}?d=mp"
     return f"https://www.gravatar.com/avatar/{hash_hex}?d=mp"
 
 
 
 
-def calculate_sha256(file):
+def calculate_sha256(file_path, chunk_size):
+    # Compute SHA-256 hash of a file efficiently in chunks
     sha256 = hashlib.sha256()
     sha256 = hashlib.sha256()
-    # Read the file in chunks to efficiently handle large files
-    for chunk in iter(lambda: file.read(8192), b""):
-        sha256.update(chunk)
+    with open(file_path, "rb") as f:
+        while chunk := f.read(chunk_size):
+            sha256.update(chunk)
     return sha256.hexdigest()
     return sha256.hexdigest()
 
 
 
 

+ 46 - 11
backend/open_webui/utils/oauth.py

@@ -1,6 +1,7 @@
 import base64
 import base64
 import logging
 import logging
 import mimetypes
 import mimetypes
+import sys
 import uuid
 import uuid
 
 
 import aiohttp
 import aiohttp
@@ -40,7 +41,11 @@ from open_webui.utils.misc import parse_duration
 from open_webui.utils.auth import get_password_hash, create_token
 from open_webui.utils.auth import get_password_hash, create_token
 from open_webui.utils.webhook import post_webhook
 from open_webui.utils.webhook import post_webhook
 
 
+from open_webui.env import SRC_LOG_LEVELS, GLOBAL_LOG_LEVEL
+
+logging.basicConfig(stream=sys.stdout, level=GLOBAL_LOG_LEVEL)
 log = logging.getLogger(__name__)
 log = logging.getLogger(__name__)
+log.setLevel(SRC_LOG_LEVELS["OAUTH"])
 
 
 auth_manager_config = AppConfig()
 auth_manager_config = AppConfig()
 auth_manager_config.DEFAULT_USER_ROLE = DEFAULT_USER_ROLE
 auth_manager_config.DEFAULT_USER_ROLE = DEFAULT_USER_ROLE
@@ -72,12 +77,15 @@ class OAuthManager:
     def get_user_role(self, user, user_data):
     def get_user_role(self, user, user_data):
         if user and Users.get_num_users() == 1:
         if user and Users.get_num_users() == 1:
             # If the user is the only user, assign the role "admin" - actually repairs role for single user on login
             # If the user is the only user, assign the role "admin" - actually repairs role for single user on login
+            log.debug("Assigning the only user the admin role")
             return "admin"
             return "admin"
         if not user and Users.get_num_users() == 0:
         if not user and Users.get_num_users() == 0:
             # If there are no users, assign the role "admin", as the first user will be an admin
             # If there are no users, assign the role "admin", as the first user will be an admin
+            log.debug("Assigning the first user the admin role")
             return "admin"
             return "admin"
 
 
         if auth_manager_config.ENABLE_OAUTH_ROLE_MANAGEMENT:
         if auth_manager_config.ENABLE_OAUTH_ROLE_MANAGEMENT:
+            log.debug("Running OAUTH Role management")
             oauth_claim = auth_manager_config.OAUTH_ROLES_CLAIM
             oauth_claim = auth_manager_config.OAUTH_ROLES_CLAIM
             oauth_allowed_roles = auth_manager_config.OAUTH_ALLOWED_ROLES
             oauth_allowed_roles = auth_manager_config.OAUTH_ALLOWED_ROLES
             oauth_admin_roles = auth_manager_config.OAUTH_ADMIN_ROLES
             oauth_admin_roles = auth_manager_config.OAUTH_ADMIN_ROLES
@@ -93,17 +101,24 @@ class OAuthManager:
                     claim_data = claim_data.get(nested_claim, {})
                     claim_data = claim_data.get(nested_claim, {})
                 oauth_roles = claim_data if isinstance(claim_data, list) else None
                 oauth_roles = claim_data if isinstance(claim_data, list) else None
 
 
+            log.debug(f"Oauth Roles claim: {oauth_claim}")
+            log.debug(f"User roles from oauth: {oauth_roles}")
+            log.debug(f"Accepted user roles: {oauth_allowed_roles}")
+            log.debug(f"Accepted admin roles: {oauth_admin_roles}")
+
             # If any roles are found, check if they match the allowed or admin roles
             # If any roles are found, check if they match the allowed or admin roles
             if oauth_roles:
             if oauth_roles:
                 # If role management is enabled, and matching roles are provided, use the roles
                 # If role management is enabled, and matching roles are provided, use the roles
                 for allowed_role in oauth_allowed_roles:
                 for allowed_role in oauth_allowed_roles:
                     # If the user has any of the allowed roles, assign the role "user"
                     # If the user has any of the allowed roles, assign the role "user"
                     if allowed_role in oauth_roles:
                     if allowed_role in oauth_roles:
+                        log.debug("Assigned user the user role")
                         role = "user"
                         role = "user"
                         break
                         break
                 for admin_role in oauth_admin_roles:
                 for admin_role in oauth_admin_roles:
                     # If the user has any of the admin roles, assign the role "admin"
                     # If the user has any of the admin roles, assign the role "admin"
                     if admin_role in oauth_roles:
                     if admin_role in oauth_roles:
+                        log.debug("Assigned user the admin role")
                         role = "admin"
                         role = "admin"
                         break
                         break
         else:
         else:
@@ -117,16 +132,27 @@ class OAuthManager:
         return role
         return role
 
 
     def update_user_groups(self, user, user_data, default_permissions):
     def update_user_groups(self, user, user_data, default_permissions):
+        log.debug("Running OAUTH Group management")
         oauth_claim = auth_manager_config.OAUTH_GROUPS_CLAIM
         oauth_claim = auth_manager_config.OAUTH_GROUPS_CLAIM
 
 
         user_oauth_groups: list[str] = user_data.get(oauth_claim, list())
         user_oauth_groups: list[str] = user_data.get(oauth_claim, list())
         user_current_groups: list[GroupModel] = Groups.get_groups_by_member_id(user.id)
         user_current_groups: list[GroupModel] = Groups.get_groups_by_member_id(user.id)
         all_available_groups: list[GroupModel] = Groups.get_groups()
         all_available_groups: list[GroupModel] = Groups.get_groups()
 
 
+        log.debug(f"Oauth Groups claim: {oauth_claim}")
+        log.debug(f"User oauth groups: {user_oauth_groups}")
+        log.debug(f"User's current groups: {[g.name for g in user_current_groups]}")
+        log.debug(
+            f"All groups available in OpenWebUI: {[g.name for g in all_available_groups]}"
+        )
+
         # Remove groups that user is no longer a part of
         # Remove groups that user is no longer a part of
         for group_model in user_current_groups:
         for group_model in user_current_groups:
             if group_model.name not in user_oauth_groups:
             if group_model.name not in user_oauth_groups:
                 # Remove group from user
                 # Remove group from user
+                log.debug(
+                    f"Removing user from group {group_model.name} as it is no longer in their oauth groups"
+                )
 
 
                 user_ids = group_model.user_ids
                 user_ids = group_model.user_ids
                 user_ids = [i for i in user_ids if i != user.id]
                 user_ids = [i for i in user_ids if i != user.id]
@@ -152,6 +178,9 @@ class OAuthManager:
                 gm.name == group_model.name for gm in user_current_groups
                 gm.name == group_model.name for gm in user_current_groups
             ):
             ):
                 # Add user to group
                 # Add user to group
+                log.debug(
+                    f"Adding user to group {group_model.name} as it was found in their oauth groups"
+                )
 
 
                 user_ids = group_model.user_ids
                 user_ids = group_model.user_ids
                 user_ids.append(user.id)
                 user_ids.append(user.id)
@@ -193,7 +222,7 @@ class OAuthManager:
             log.warning(f"OAuth callback error: {e}")
             log.warning(f"OAuth callback error: {e}")
             raise HTTPException(400, detail=ERROR_MESSAGES.INVALID_CRED)
             raise HTTPException(400, detail=ERROR_MESSAGES.INVALID_CRED)
         user_data: UserInfo = token.get("userinfo")
         user_data: UserInfo = token.get("userinfo")
-        if not user_data:
+        if not user_data or "email" not in user_data:
             user_data: UserInfo = await client.userinfo(token=token)
             user_data: UserInfo = await client.userinfo(token=token)
         if not user_data:
         if not user_data:
             log.warning(f"OAuth callback failed, user data is missing: {token}")
             log.warning(f"OAuth callback failed, user data is missing: {token}")
@@ -261,15 +290,20 @@ class OAuthManager:
                             }
                             }
                         async with aiohttp.ClientSession() as session:
                         async with aiohttp.ClientSession() as session:
                             async with session.get(picture_url, **get_kwargs) as resp:
                             async with session.get(picture_url, **get_kwargs) as resp:
-                                picture = await resp.read()
-                                base64_encoded_picture = base64.b64encode(
-                                    picture
-                                ).decode("utf-8")
-                                guessed_mime_type = mimetypes.guess_type(picture_url)[0]
-                                if guessed_mime_type is None:
-                                    # assume JPG, browsers are tolerant enough of image formats
-                                    guessed_mime_type = "image/jpeg"
-                                picture_url = f"data:{guessed_mime_type};base64,{base64_encoded_picture}"
+                                if resp.ok:
+                                    picture = await resp.read()
+                                    base64_encoded_picture = base64.b64encode(
+                                        picture
+                                    ).decode("utf-8")
+                                    guessed_mime_type = mimetypes.guess_type(
+                                        picture_url
+                                    )[0]
+                                    if guessed_mime_type is None:
+                                        # assume JPG, browsers are tolerant enough of image formats
+                                        guessed_mime_type = "image/jpeg"
+                                    picture_url = f"data:{guessed_mime_type};base64,{base64_encoded_picture}"
+                                else:
+                                    picture_url = "/user.png"
                     except Exception as e:
                     except Exception as e:
                         log.error(
                         log.error(
                             f"Error downloading profile image '{picture_url}': {e}"
                             f"Error downloading profile image '{picture_url}': {e}"
@@ -281,7 +315,8 @@ class OAuthManager:
                 username_claim = auth_manager_config.OAUTH_USERNAME_CLAIM
                 username_claim = auth_manager_config.OAUTH_USERNAME_CLAIM
 
 
                 name = user_data.get(username_claim)
                 name = user_data.get(username_claim)
-                if not isinstance(user, str):
+                if not name:
+                    log.warning("Username claim is missing, using email as name")
                     name = email
                     name = email
 
 
                 role = self.get_user_role(None, user_data)
                 role = self.get_user_role(None, user_data)

+ 6 - 6
backend/open_webui/utils/payload.py

@@ -14,6 +14,12 @@ def apply_model_system_prompt_to_body(
     if not system:
     if not system:
         return form_data
         return form_data
 
 
+    # Metadata (WebUI Usage)
+    if metadata:
+        variables = metadata.get("variables", {})
+        if variables:
+            system = prompt_variables_template(system, variables)
+
     # Legacy (API Usage)
     # Legacy (API Usage)
     if user:
     if user:
         template_params = {
         template_params = {
@@ -25,12 +31,6 @@ def apply_model_system_prompt_to_body(
 
 
     system = prompt_template(system, **template_params)
     system = prompt_template(system, **template_params)
 
 
-    # Metadata (WebUI Usage)
-    if metadata:
-        variables = metadata.get("variables", {})
-        if variables:
-            system = prompt_variables_template(system, variables)
-
     form_data["messages"] = add_or_update_system_message(
     form_data["messages"] = add_or_update_system_message(
         system, form_data.get("messages", [])
         system, form_data.get("messages", [])
     )
     )

+ 7 - 5
backend/open_webui/utils/pdf_generator.py

@@ -2,6 +2,7 @@ from datetime import datetime
 from io import BytesIO
 from io import BytesIO
 from pathlib import Path
 from pathlib import Path
 from typing import Dict, Any, List
 from typing import Dict, Any, List
+from html import escape
 
 
 from markdown import markdown
 from markdown import markdown
 
 
@@ -41,13 +42,13 @@ class PDFGenerator:
 
 
     def _build_html_message(self, message: Dict[str, Any]) -> str:
     def _build_html_message(self, message: Dict[str, Any]) -> str:
         """Build HTML for a single message."""
         """Build HTML for a single message."""
-        role = message.get("role", "user")
-        content = message.get("content", "")
+        role = escape(message.get("role", "user"))
+        content = escape(message.get("content", ""))
         timestamp = message.get("timestamp")
         timestamp = message.get("timestamp")
 
 
-        model = message.get("model") if role == "assistant" else ""
+        model = escape(message.get("model") if role == "assistant" else "")
 
 
-        date_str = self.format_timestamp(timestamp) if timestamp else ""
+        date_str = escape(self.format_timestamp(timestamp) if timestamp else "")
 
 
         # extends pymdownx extension to convert markdown to html.
         # extends pymdownx extension to convert markdown to html.
         # - https://facelessuser.github.io/pymdown-extensions/usage_notes/
         # - https://facelessuser.github.io/pymdown-extensions/usage_notes/
@@ -76,6 +77,7 @@ class PDFGenerator:
 
 
     def _generate_html_body(self) -> str:
     def _generate_html_body(self) -> str:
         """Generate the full HTML body for the PDF."""
         """Generate the full HTML body for the PDF."""
+        escaped_title = escape(self.form_data.title)
         return f"""
         return f"""
         <html>
         <html>
             <head>
             <head>
@@ -84,7 +86,7 @@ class PDFGenerator:
             <body>
             <body>
             <div>
             <div>
                 <div>
                 <div>
-                    <h2>{self.form_data.title}</h2>
+                    <h2>{escaped_title}</h2>
                     {self.messages_html}
                     {self.messages_html}
                 </div>
                 </div>
             </div>
             </div>

+ 27 - 13
backend/open_webui/utils/response.py

@@ -6,9 +6,32 @@ from open_webui.utils.misc import (
 )
 )
 
 
 
 
+def convert_ollama_tool_call_to_openai(tool_calls: dict) -> dict:
+    openai_tool_calls = []
+    for tool_call in tool_calls:
+        openai_tool_call = {
+            "index": tool_call.get("index", 0),
+            "id": tool_call.get("id", f"call_{str(uuid4())}"),
+            "type": "function",
+            "function": {
+                "name": tool_call.get("function", {}).get("name", ""),
+                "arguments": json.dumps(
+                    tool_call.get("function", {}).get("arguments", {})
+                ),
+            },
+        }
+        openai_tool_calls.append(openai_tool_call)
+    return openai_tool_calls
+
+
 def convert_response_ollama_to_openai(ollama_response: dict) -> dict:
 def convert_response_ollama_to_openai(ollama_response: dict) -> dict:
     model = ollama_response.get("model", "ollama")
     model = ollama_response.get("model", "ollama")
     message_content = ollama_response.get("message", {}).get("content", "")
     message_content = ollama_response.get("message", {}).get("content", "")
+    tool_calls = ollama_response.get("message", {}).get("tool_calls", None)
+    openai_tool_calls = None
+
+    if tool_calls:
+        openai_tool_calls = convert_ollama_tool_call_to_openai(tool_calls)
 
 
     data = ollama_response
     data = ollama_response
     usage = {
     usage = {
@@ -51,7 +74,9 @@ def convert_response_ollama_to_openai(ollama_response: dict) -> dict:
         ),
         ),
     }
     }
 
 
-    response = openai_chat_completion_message_template(model, message_content, usage)
+    response = openai_chat_completion_message_template(
+        model, message_content, openai_tool_calls, usage
+    )
     return response
     return response
 
 
 
 
@@ -65,18 +90,7 @@ async def convert_streaming_response_ollama_to_openai(ollama_streaming_response)
         openai_tool_calls = None
         openai_tool_calls = None
 
 
         if tool_calls:
         if tool_calls:
-            openai_tool_calls = []
-            for tool_call in tool_calls:
-                openai_tool_call = {
-                    "index": tool_call.get("index", 0),
-                    "id": tool_call.get("id", f"call_{str(uuid4())}"),
-                    "type": "function",
-                    "function": {
-                        "name": tool_call.get("function", {}).get("name", ""),
-                        "arguments": f"{tool_call.get('function', {}).get('arguments', {})}",
-                    },
-                }
-                openai_tool_calls.append(openai_tool_call)
+            openai_tool_calls = convert_ollama_tool_call_to_openai(tool_calls)
 
 
         done = data.get("done", False)
         done = data.get("done", False)
 
 

+ 5 - 3
backend/requirements.txt

@@ -32,6 +32,8 @@ boto3==1.35.53
 argon2-cffi==23.1.0
 argon2-cffi==23.1.0
 APScheduler==3.10.4
 APScheduler==3.10.4
 
 
+RestrictedPython==8.0
+
 # AI libraries
 # AI libraries
 openai
 openai
 anthropic
 anthropic
@@ -45,7 +47,7 @@ fake-useragent==1.5.1
 chromadb==0.6.2
 chromadb==0.6.2
 pymilvus==2.5.0
 pymilvus==2.5.0
 qdrant-client~=1.12.0
 qdrant-client~=1.12.0
-opensearch-py==2.7.1
+opensearch-py==2.8.0
 
 
 
 
 transformers
 transformers
@@ -77,7 +79,7 @@ opencv-python-headless==4.11.0.86
 rapidocr-onnxruntime==1.3.24
 rapidocr-onnxruntime==1.3.24
 rank-bm25==0.2.2
 rank-bm25==0.2.2
 
 
-faster-whisper==1.0.3
+faster-whisper==1.1.1
 
 
 PyJWT[crypto]==2.10.1
 PyJWT[crypto]==2.10.1
 authlib==1.4.1
 authlib==1.4.1
@@ -89,7 +91,7 @@ pytube==15.0.0
 
 
 extract_msg
 extract_msg
 pydub
 pydub
-duckduckgo-search~=7.3.0
+duckduckgo-search~=7.3.2
 
 
 ## Google Drive
 ## Google Drive
 google-api-python-client
 google-api-python-client

+ 188 - 122
package-lock.json

@@ -1,12 +1,12 @@
 {
 {
 	"name": "open-webui",
 	"name": "open-webui",
-	"version": "0.5.10",
+	"version": "0.5.11",
 	"lockfileVersion": 3,
 	"lockfileVersion": 3,
 	"requires": true,
 	"requires": true,
 	"packages": {
 	"packages": {
 		"": {
 		"": {
 			"name": "open-webui",
 			"name": "open-webui",
-			"version": "0.5.10",
+			"version": "0.5.11",
 			"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",
@@ -42,6 +42,7 @@
 				"idb": "^7.1.1",
 				"idb": "^7.1.1",
 				"js-sha256": "^0.10.1",
 				"js-sha256": "^0.10.1",
 				"katex": "^0.16.21",
 				"katex": "^0.16.21",
+				"kokoro-js": "^1.1.1",
 				"marked": "^9.1.0",
 				"marked": "^9.1.0",
 				"mermaid": "^10.9.3",
 				"mermaid": "^10.9.3",
 				"paneforge": "^0.0.6",
 				"paneforge": "^0.0.6",
@@ -62,7 +63,8 @@
 				"svelte-sonner": "^0.3.19",
 				"svelte-sonner": "^0.3.19",
 				"tippy.js": "^6.3.7",
 				"tippy.js": "^6.3.7",
 				"turndown": "^7.2.0",
 				"turndown": "^7.2.0",
-				"uuid": "^9.0.1"
+				"uuid": "^9.0.1",
+				"vite-plugin-static-copy": "^2.2.0"
 			},
 			},
 			"devDependencies": {
 			"devDependencies": {
 				"@sveltejs/adapter-auto": "3.2.2",
 				"@sveltejs/adapter-auto": "3.2.2",
@@ -91,7 +93,7 @@
 				"tslib": "^2.4.1",
 				"tslib": "^2.4.1",
 				"typescript": "^5.5.4",
 				"typescript": "^5.5.4",
 				"vite": "^5.4.14",
 				"vite": "^5.4.14",
-				"vitest": "^1.6.0"
+				"vitest": "^1.6.1"
 			},
 			},
 			"engines": {
 			"engines": {
 				"node": ">=18.13.0 <=22.x.x",
 				"node": ">=18.13.0 <=22.x.x",
@@ -1078,21 +1080,23 @@
 			}
 			}
 		},
 		},
 		"node_modules/@huggingface/jinja": {
 		"node_modules/@huggingface/jinja": {
-			"version": "0.3.1",
-			"resolved": "https://registry.npmjs.org/@huggingface/jinja/-/jinja-0.3.1.tgz",
-			"integrity": "sha512-SbcBWUKDQ76lzlVYOloscUk0SJjuL1LcbZsfQv/Bxxc7dwJMYuS+DAQ+HhVw6ZkTFXArejaX5HQRuCuleYwYdA==",
+			"version": "0.3.3",
+			"resolved": "https://registry.npmjs.org/@huggingface/jinja/-/jinja-0.3.3.tgz",
+			"integrity": "sha512-vQQr2JyWvVFba3Lj9es4q9vCl1sAc74fdgnEMoX8qHrXtswap9ge9uO3ONDzQB0cQ0PUyaKY2N6HaVbTBvSXvw==",
+			"license": "MIT",
 			"engines": {
 			"engines": {
 				"node": ">=18"
 				"node": ">=18"
 			}
 			}
 		},
 		},
 		"node_modules/@huggingface/transformers": {
 		"node_modules/@huggingface/transformers": {
-			"version": "3.0.0",
-			"resolved": "https://registry.npmjs.org/@huggingface/transformers/-/transformers-3.0.0.tgz",
-			"integrity": "sha512-OWIPnTijAw4DQ+IFHBOrej2SDdYyykYlTtpTLCEt5MZq/e9Cb65RS2YVhdGcgbaW/6JAL3i8ZA5UhDeWGm4iRQ==",
+			"version": "3.3.3",
+			"resolved": "https://registry.npmjs.org/@huggingface/transformers/-/transformers-3.3.3.tgz",
+			"integrity": "sha512-OcMubhBjW6u1xnp0zSt5SvCxdGHuhP2k+w2Vlm3i0vNcTJhJTZWxxYQmPBfcb7PX+Q6c43lGSzWD6tsJFwka4Q==",
+			"license": "Apache-2.0",
 			"dependencies": {
 			"dependencies": {
-				"@huggingface/jinja": "^0.3.0",
-				"onnxruntime-node": "1.19.2",
-				"onnxruntime-web": "1.20.0-dev.20241016-2b8fc5529b",
+				"@huggingface/jinja": "^0.3.3",
+				"onnxruntime-node": "1.20.1",
+				"onnxruntime-web": "1.21.0-dev.20250206-d981b153d3",
 				"sharp": "^0.33.5"
 				"sharp": "^0.33.5"
 			}
 			}
 		},
 		},
@@ -1546,6 +1550,7 @@
 			"version": "4.0.1",
 			"version": "4.0.1",
 			"resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz",
 			"resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz",
 			"integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==",
 			"integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==",
+			"license": "ISC",
 			"dependencies": {
 			"dependencies": {
 				"minipass": "^7.0.4"
 				"minipass": "^7.0.4"
 			},
 			},
@@ -1558,6 +1563,7 @@
 			"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz",
 			"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz",
 			"integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==",
 			"integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==",
 			"dev": true,
 			"dev": true,
+			"license": "MIT",
 			"dependencies": {
 			"dependencies": {
 				"@sinclair/typebox": "^0.27.8"
 				"@sinclair/typebox": "^0.27.8"
 			},
 			},
@@ -1798,7 +1804,6 @@
 			"version": "2.1.5",
 			"version": "2.1.5",
 			"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
 			"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
 			"integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
 			"integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
-			"dev": true,
 			"dependencies": {
 			"dependencies": {
 				"@nodelib/fs.stat": "2.0.5",
 				"@nodelib/fs.stat": "2.0.5",
 				"run-parallel": "^1.1.9"
 				"run-parallel": "^1.1.9"
@@ -1811,7 +1816,6 @@
 			"version": "2.0.5",
 			"version": "2.0.5",
 			"resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
 			"resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
 			"integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
 			"integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
-			"dev": true,
 			"engines": {
 			"engines": {
 				"node": ">= 8"
 				"node": ">= 8"
 			}
 			}
@@ -1820,7 +1824,6 @@
 			"version": "1.2.8",
 			"version": "1.2.8",
 			"resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
 			"resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
 			"integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
 			"integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
-			"dev": true,
 			"dependencies": {
 			"dependencies": {
 				"@nodelib/fs.scandir": "2.1.5",
 				"@nodelib/fs.scandir": "2.1.5",
 				"fastq": "^1.6.0"
 				"fastq": "^1.6.0"
@@ -1856,27 +1859,32 @@
 		"node_modules/@protobufjs/aspromise": {
 		"node_modules/@protobufjs/aspromise": {
 			"version": "1.1.2",
 			"version": "1.1.2",
 			"resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
 			"resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
-			"integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ=="
+			"integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==",
+			"license": "BSD-3-Clause"
 		},
 		},
 		"node_modules/@protobufjs/base64": {
 		"node_modules/@protobufjs/base64": {
 			"version": "1.1.2",
 			"version": "1.1.2",
 			"resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz",
 			"resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz",
-			"integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg=="
+			"integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==",
+			"license": "BSD-3-Clause"
 		},
 		},
 		"node_modules/@protobufjs/codegen": {
 		"node_modules/@protobufjs/codegen": {
 			"version": "2.0.4",
 			"version": "2.0.4",
 			"resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz",
 			"resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz",
-			"integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg=="
+			"integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==",
+			"license": "BSD-3-Clause"
 		},
 		},
 		"node_modules/@protobufjs/eventemitter": {
 		"node_modules/@protobufjs/eventemitter": {
 			"version": "1.1.0",
 			"version": "1.1.0",
 			"resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz",
 			"resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz",
-			"integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q=="
+			"integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==",
+			"license": "BSD-3-Clause"
 		},
 		},
 		"node_modules/@protobufjs/fetch": {
 		"node_modules/@protobufjs/fetch": {
 			"version": "1.1.0",
 			"version": "1.1.0",
 			"resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz",
 			"resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz",
 			"integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==",
 			"integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==",
+			"license": "BSD-3-Clause",
 			"dependencies": {
 			"dependencies": {
 				"@protobufjs/aspromise": "^1.1.1",
 				"@protobufjs/aspromise": "^1.1.1",
 				"@protobufjs/inquire": "^1.1.0"
 				"@protobufjs/inquire": "^1.1.0"
@@ -1885,27 +1893,32 @@
 		"node_modules/@protobufjs/float": {
 		"node_modules/@protobufjs/float": {
 			"version": "1.0.2",
 			"version": "1.0.2",
 			"resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz",
 			"resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz",
-			"integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ=="
+			"integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==",
+			"license": "BSD-3-Clause"
 		},
 		},
 		"node_modules/@protobufjs/inquire": {
 		"node_modules/@protobufjs/inquire": {
 			"version": "1.1.0",
 			"version": "1.1.0",
 			"resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz",
 			"resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz",
-			"integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q=="
+			"integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==",
+			"license": "BSD-3-Clause"
 		},
 		},
 		"node_modules/@protobufjs/path": {
 		"node_modules/@protobufjs/path": {
 			"version": "1.1.2",
 			"version": "1.1.2",
 			"resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz",
 			"resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz",
-			"integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA=="
+			"integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==",
+			"license": "BSD-3-Clause"
 		},
 		},
 		"node_modules/@protobufjs/pool": {
 		"node_modules/@protobufjs/pool": {
 			"version": "1.1.0",
 			"version": "1.1.0",
 			"resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz",
 			"resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz",
-			"integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw=="
+			"integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==",
+			"license": "BSD-3-Clause"
 		},
 		},
 		"node_modules/@protobufjs/utf8": {
 		"node_modules/@protobufjs/utf8": {
 			"version": "1.1.0",
 			"version": "1.1.0",
 			"resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz",
 			"resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz",
-			"integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="
+			"integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==",
+			"license": "BSD-3-Clause"
 		},
 		},
 		"node_modules/@pyscript/core": {
 		"node_modules/@pyscript/core": {
 			"version": "0.4.32",
 			"version": "0.4.32",
@@ -2210,7 +2223,8 @@
 			"version": "0.27.8",
 			"version": "0.27.8",
 			"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz",
 			"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz",
 			"integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==",
 			"integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==",
-			"dev": true
+			"dev": true,
+			"license": "MIT"
 		},
 		},
 		"node_modules/@socket.io/component-emitter": {
 		"node_modules/@socket.io/component-emitter": {
 			"version": "3.1.2",
 			"version": "3.1.2",
@@ -3146,13 +3160,14 @@
 			"integrity": "sha512-g7f0IkJdPW2xhY7H4iE72DAsIyfuwEFc6JWc2tYFwKDMWWAF699vGjrM348cwQuOXgHpe1gWFe+Eiyjx/ewvvw=="
 			"integrity": "sha512-g7f0IkJdPW2xhY7H4iE72DAsIyfuwEFc6JWc2tYFwKDMWWAF699vGjrM348cwQuOXgHpe1gWFe+Eiyjx/ewvvw=="
 		},
 		},
 		"node_modules/@vitest/expect": {
 		"node_modules/@vitest/expect": {
-			"version": "1.6.0",
-			"resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.6.0.tgz",
-			"integrity": "sha512-ixEvFVQjycy/oNgHjqsL6AZCDduC+tflRluaHIzKIsdbzkLn2U/iBnVeJwB6HsIjQBdfMR8Z0tRxKUsvFJEeWQ==",
+			"version": "1.6.1",
+			"resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.6.1.tgz",
+			"integrity": "sha512-jXL+9+ZNIJKruofqXuuTClf44eSpcHlgj3CiuNihUF3Ioujtmc0zIa3UJOW5RjDK1YLBJZnWBlPuqhYycLioog==",
 			"dev": true,
 			"dev": true,
+			"license": "MIT",
 			"dependencies": {
 			"dependencies": {
-				"@vitest/spy": "1.6.0",
-				"@vitest/utils": "1.6.0",
+				"@vitest/spy": "1.6.1",
+				"@vitest/utils": "1.6.1",
 				"chai": "^4.3.10"
 				"chai": "^4.3.10"
 			},
 			},
 			"funding": {
 			"funding": {
@@ -3160,12 +3175,13 @@
 			}
 			}
 		},
 		},
 		"node_modules/@vitest/runner": {
 		"node_modules/@vitest/runner": {
-			"version": "1.6.0",
-			"resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.6.0.tgz",
-			"integrity": "sha512-P4xgwPjwesuBiHisAVz/LSSZtDjOTPYZVmNAnpHHSR6ONrf8eCJOFRvUwdHn30F5M1fxhqtl7QZQUk2dprIXAg==",
+			"version": "1.6.1",
+			"resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.6.1.tgz",
+			"integrity": "sha512-3nSnYXkVkf3mXFfE7vVyPmi3Sazhb/2cfZGGs0JRzFsPFvAMBEcrweV1V1GsrstdXeKCTXlJbvnQwGWgEIHmOA==",
 			"dev": true,
 			"dev": true,
+			"license": "MIT",
 			"dependencies": {
 			"dependencies": {
-				"@vitest/utils": "1.6.0",
+				"@vitest/utils": "1.6.1",
 				"p-limit": "^5.0.0",
 				"p-limit": "^5.0.0",
 				"pathe": "^1.1.1"
 				"pathe": "^1.1.1"
 			},
 			},
@@ -3178,6 +3194,7 @@
 			"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-5.0.0.tgz",
 			"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-5.0.0.tgz",
 			"integrity": "sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==",
 			"integrity": "sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==",
 			"dev": true,
 			"dev": true,
+			"license": "MIT",
 			"dependencies": {
 			"dependencies": {
 				"yocto-queue": "^1.0.0"
 				"yocto-queue": "^1.0.0"
 			},
 			},
@@ -3189,10 +3206,11 @@
 			}
 			}
 		},
 		},
 		"node_modules/@vitest/runner/node_modules/yocto-queue": {
 		"node_modules/@vitest/runner/node_modules/yocto-queue": {
-			"version": "1.0.0",
-			"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz",
-			"integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==",
+			"version": "1.1.1",
+			"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.1.1.tgz",
+			"integrity": "sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g==",
 			"dev": true,
 			"dev": true,
+			"license": "MIT",
 			"engines": {
 			"engines": {
 				"node": ">=12.20"
 				"node": ">=12.20"
 			},
 			},
@@ -3201,10 +3219,11 @@
 			}
 			}
 		},
 		},
 		"node_modules/@vitest/snapshot": {
 		"node_modules/@vitest/snapshot": {
-			"version": "1.6.0",
-			"resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.6.0.tgz",
-			"integrity": "sha512-+Hx43f8Chus+DCmygqqfetcAZrDJwvTj0ymqjQq4CvmpKFSTVteEOBzCusu1x2tt4OJcvBflyHUE0DZSLgEMtQ==",
+			"version": "1.6.1",
+			"resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.6.1.tgz",
+			"integrity": "sha512-WvidQuWAzU2p95u8GAKlRMqMyN1yOJkGHnx3M1PL9Raf7AQ1kwLKg04ADlCa3+OXUZE7BceOhVZiuWAbzCKcUQ==",
 			"dev": true,
 			"dev": true,
+			"license": "MIT",
 			"dependencies": {
 			"dependencies": {
 				"magic-string": "^0.30.5",
 				"magic-string": "^0.30.5",
 				"pathe": "^1.1.1",
 				"pathe": "^1.1.1",
@@ -3215,10 +3234,11 @@
 			}
 			}
 		},
 		},
 		"node_modules/@vitest/spy": {
 		"node_modules/@vitest/spy": {
-			"version": "1.6.0",
-			"resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.6.0.tgz",
-			"integrity": "sha512-leUTap6B/cqi/bQkXUu6bQV5TZPx7pmMBKBQiI0rJA8c3pB56ZsaTbREnF7CJfmvAS4V2cXIBAh/3rVwrrCYgw==",
+			"version": "1.6.1",
+			"resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.6.1.tgz",
+			"integrity": "sha512-MGcMmpGkZebsMZhbQKkAf9CX5zGvjkBTqf8Zx3ApYWXr3wG+QvEu2eXWfnIIWYSJExIp4V9FCKDEeygzkYrXMw==",
 			"dev": true,
 			"dev": true,
+			"license": "MIT",
 			"dependencies": {
 			"dependencies": {
 				"tinyspy": "^2.2.0"
 				"tinyspy": "^2.2.0"
 			},
 			},
@@ -3227,10 +3247,11 @@
 			}
 			}
 		},
 		},
 		"node_modules/@vitest/utils": {
 		"node_modules/@vitest/utils": {
-			"version": "1.6.0",
-			"resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.6.0.tgz",
-			"integrity": "sha512-21cPiuGMoMZwiOHa2i4LXkMkMkCGzA+MVFV70jRwHo95dL4x/ts5GZhML1QWuy7yfp3WzK3lRvZi3JnXTYqrBw==",
+			"version": "1.6.1",
+			"resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.6.1.tgz",
+			"integrity": "sha512-jOrrUvXM4Av9ZWiG1EajNto0u96kWAhJ1LmPmJhXXQx/32MecEKd10pOLYgS2BQx1TgkGhloPU1ArDW2vvaY6g==",
 			"dev": true,
 			"dev": true,
+			"license": "MIT",
 			"dependencies": {
 			"dependencies": {
 				"diff-sequences": "^29.6.3",
 				"diff-sequences": "^29.6.3",
 				"estree-walker": "^3.0.3",
 				"estree-walker": "^3.0.3",
@@ -3246,6 +3267,7 @@
 			"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
 			"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
 			"integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
 			"integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
 			"dev": true,
 			"dev": true,
+			"license": "MIT",
 			"dependencies": {
 			"dependencies": {
 				"@types/estree": "^1.0.0"
 				"@types/estree": "^1.0.0"
 			}
 			}
@@ -3416,7 +3438,6 @@
 			"version": "3.1.3",
 			"version": "3.1.3",
 			"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
 			"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
 			"integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
 			"integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
-			"dev": true,
 			"dependencies": {
 			"dependencies": {
 				"normalize-path": "^3.0.0",
 				"normalize-path": "^3.0.0",
 				"picomatch": "^2.0.4"
 				"picomatch": "^2.0.4"
@@ -3496,6 +3517,7 @@
 			"resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz",
 			"resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz",
 			"integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==",
 			"integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==",
 			"dev": true,
 			"dev": true,
+			"license": "MIT",
 			"engines": {
 			"engines": {
 				"node": "*"
 				"node": "*"
 			}
 			}
@@ -3644,7 +3666,6 @@
 			"version": "2.3.0",
 			"version": "2.3.0",
 			"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
 			"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
 			"integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
 			"integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
-			"dev": true,
 			"engines": {
 			"engines": {
 				"node": ">=8"
 				"node": ">=8"
 			},
 			},
@@ -3720,7 +3741,6 @@
 			"version": "3.0.3",
 			"version": "3.0.3",
 			"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
 			"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
 			"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
 			"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
-			"dev": true,
 			"dependencies": {
 			"dependencies": {
 				"fill-range": "^7.1.1"
 				"fill-range": "^7.1.1"
 			},
 			},
@@ -3895,6 +3915,7 @@
 			"resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz",
 			"resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz",
 			"integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==",
 			"integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==",
 			"dev": true,
 			"dev": true,
+			"license": "MIT",
 			"engines": {
 			"engines": {
 				"node": ">=8"
 				"node": ">=8"
 			}
 			}
@@ -3972,10 +3993,11 @@
 			"dev": true
 			"dev": true
 		},
 		},
 		"node_modules/chai": {
 		"node_modules/chai": {
-			"version": "4.4.1",
-			"resolved": "https://registry.npmjs.org/chai/-/chai-4.4.1.tgz",
-			"integrity": "sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==",
+			"version": "4.5.0",
+			"resolved": "https://registry.npmjs.org/chai/-/chai-4.5.0.tgz",
+			"integrity": "sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==",
 			"dev": true,
 			"dev": true,
+			"license": "MIT",
 			"dependencies": {
 			"dependencies": {
 				"assertion-error": "^1.1.0",
 				"assertion-error": "^1.1.0",
 				"check-error": "^1.0.3",
 				"check-error": "^1.0.3",
@@ -3983,7 +4005,7 @@
 				"get-func-name": "^2.0.2",
 				"get-func-name": "^2.0.2",
 				"loupe": "^2.3.6",
 				"loupe": "^2.3.6",
 				"pathval": "^1.1.1",
 				"pathval": "^1.1.1",
-				"type-detect": "^4.0.8"
+				"type-detect": "^4.1.0"
 			},
 			},
 			"engines": {
 			"engines": {
 				"node": ">=4"
 				"node": ">=4"
@@ -4019,6 +4041,7 @@
 			"resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz",
 			"resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz",
 			"integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==",
 			"integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==",
 			"dev": true,
 			"dev": true,
+			"license": "MIT",
 			"dependencies": {
 			"dependencies": {
 				"get-func-name": "^2.0.2"
 				"get-func-name": "^2.0.2"
 			},
 			},
@@ -4077,7 +4100,6 @@
 			"version": "3.6.0",
 			"version": "3.6.0",
 			"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
 			"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
 			"integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
 			"integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
-			"dev": true,
 			"dependencies": {
 			"dependencies": {
 				"anymatch": "~3.1.2",
 				"anymatch": "~3.1.2",
 				"braces": "~3.0.2",
 				"braces": "~3.0.2",
@@ -4101,7 +4123,6 @@
 			"version": "5.1.2",
 			"version": "5.1.2",
 			"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
 			"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
 			"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
 			"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
-			"dev": true,
 			"dependencies": {
 			"dependencies": {
 				"is-glob": "^4.0.1"
 				"is-glob": "^4.0.1"
 			},
 			},
@@ -4113,6 +4134,7 @@
 			"version": "3.0.0",
 			"version": "3.0.0",
 			"resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz",
 			"resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz",
 			"integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==",
 			"integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==",
+			"license": "BlueOak-1.0.0",
 			"engines": {
 			"engines": {
 				"node": ">=18"
 				"node": ">=18"
 			}
 			}
@@ -5135,10 +5157,11 @@
 			}
 			}
 		},
 		},
 		"node_modules/deep-eql": {
 		"node_modules/deep-eql": {
-			"version": "4.1.3",
-			"resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz",
-			"integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==",
+			"version": "4.1.4",
+			"resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz",
+			"integrity": "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==",
 			"dev": true,
 			"dev": true,
+			"license": "MIT",
 			"dependencies": {
 			"dependencies": {
 				"type-detect": "^4.0.0"
 				"type-detect": "^4.0.0"
 			},
 			},
@@ -5257,6 +5280,7 @@
 			"resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz",
 			"resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz",
 			"integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==",
 			"integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==",
 			"dev": true,
 			"dev": true,
+			"license": "MIT",
 			"engines": {
 			"engines": {
 				"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
 				"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
 			}
 			}
@@ -5899,7 +5923,6 @@
 			"version": "3.3.2",
 			"version": "3.3.2",
 			"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
 			"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
 			"integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==",
 			"integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==",
-			"dev": true,
 			"dependencies": {
 			"dependencies": {
 				"@nodelib/fs.stat": "^2.0.2",
 				"@nodelib/fs.stat": "^2.0.2",
 				"@nodelib/fs.walk": "^1.2.3",
 				"@nodelib/fs.walk": "^1.2.3",
@@ -5915,7 +5938,6 @@
 			"version": "5.1.2",
 			"version": "5.1.2",
 			"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
 			"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
 			"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
 			"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
-			"dev": true,
 			"dependencies": {
 			"dependencies": {
 				"is-glob": "^4.0.1"
 				"is-glob": "^4.0.1"
 			},
 			},
@@ -5939,7 +5961,6 @@
 			"version": "1.17.1",
 			"version": "1.17.1",
 			"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz",
 			"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz",
 			"integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==",
 			"integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==",
-			"dev": true,
 			"dependencies": {
 			"dependencies": {
 				"reusify": "^1.0.4"
 				"reusify": "^1.0.4"
 			}
 			}
@@ -5998,7 +6019,6 @@
 			"version": "7.1.1",
 			"version": "7.1.1",
 			"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
 			"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
 			"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
 			"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
-			"dev": true,
 			"dependencies": {
 			"dependencies": {
 				"to-regex-range": "^5.0.1"
 				"to-regex-range": "^5.0.1"
 			},
 			},
@@ -6037,9 +6057,10 @@
 			}
 			}
 		},
 		},
 		"node_modules/flatbuffers": {
 		"node_modules/flatbuffers": {
-			"version": "1.12.0",
-			"resolved": "https://registry.npmjs.org/flatbuffers/-/flatbuffers-1.12.0.tgz",
-			"integrity": "sha512-c7CZADjRcl6j0PlvFy0ZqXQ67qSEZfrVPynmnL+2zPc+NtMvrF8Y0QceMo7QqnSPc7+uWjUIAbvCQ5WIKlMVdQ=="
+			"version": "25.1.24",
+			"resolved": "https://registry.npmjs.org/flatbuffers/-/flatbuffers-25.1.24.tgz",
+			"integrity": "sha512-Ni+KCqYquU30UEgGkrrwpbYtUcUmNuLFcQ5Xdy9DK7WUaji+AAov+Bf12FEYmu0eI15y31oD38utnBexe0cAYA==",
+			"license": "Apache-2.0"
 		},
 		},
 		"node_modules/flatted": {
 		"node_modules/flatted": {
 			"version": "3.3.1",
 			"version": "3.3.1",
@@ -6110,7 +6131,6 @@
 			"version": "11.2.0",
 			"version": "11.2.0",
 			"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz",
 			"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz",
 			"integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==",
 			"integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==",
-			"dev": true,
 			"dependencies": {
 			"dependencies": {
 				"graceful-fs": "^4.2.0",
 				"graceful-fs": "^4.2.0",
 				"jsonfile": "^6.0.1",
 				"jsonfile": "^6.0.1",
@@ -6238,6 +6258,7 @@
 			"resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz",
 			"resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz",
 			"integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==",
 			"integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==",
 			"dev": true,
 			"dev": true,
+			"license": "MIT",
 			"engines": {
 			"engines": {
 				"node": "*"
 				"node": "*"
 			}
 			}
@@ -6429,8 +6450,7 @@
 		"node_modules/graceful-fs": {
 		"node_modules/graceful-fs": {
 			"version": "4.2.11",
 			"version": "4.2.11",
 			"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
 			"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
-			"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
-			"dev": true
+			"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="
 		},
 		},
 		"node_modules/graphemer": {
 		"node_modules/graphemer": {
 			"version": "1.4.0",
 			"version": "1.4.0",
@@ -6441,7 +6461,8 @@
 		"node_modules/guid-typescript": {
 		"node_modules/guid-typescript": {
 			"version": "1.0.9",
 			"version": "1.0.9",
 			"resolved": "https://registry.npmjs.org/guid-typescript/-/guid-typescript-1.0.9.tgz",
 			"resolved": "https://registry.npmjs.org/guid-typescript/-/guid-typescript-1.0.9.tgz",
-			"integrity": "sha512-Y8T4vYhEfwJOTbouREvG+3XDsjr8E3kIr7uf+JZ0BYloFsttiHU0WfvANVsR7TxNUJa/WpCnw/Ino/p+DeBhBQ=="
+			"integrity": "sha512-Y8T4vYhEfwJOTbouREvG+3XDsjr8E3kIr7uf+JZ0BYloFsttiHU0WfvANVsR7TxNUJa/WpCnw/Ino/p+DeBhBQ==",
+			"license": "ISC"
 		},
 		},
 		"node_modules/gulp-sort": {
 		"node_modules/gulp-sort": {
 			"version": "2.0.0",
 			"version": "2.0.0",
@@ -6809,7 +6830,6 @@
 			"version": "2.1.0",
 			"version": "2.1.0",
 			"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
 			"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
 			"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
 			"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
-			"dev": true,
 			"dependencies": {
 			"dependencies": {
 				"binary-extensions": "^2.0.0"
 				"binary-extensions": "^2.0.0"
 			},
 			},
@@ -6858,7 +6878,6 @@
 			"version": "2.1.1",
 			"version": "2.1.1",
 			"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
 			"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
 			"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
 			"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
-			"dev": true,
 			"engines": {
 			"engines": {
 				"node": ">=0.10.0"
 				"node": ">=0.10.0"
 			}
 			}
@@ -6875,7 +6894,6 @@
 			"version": "4.0.3",
 			"version": "4.0.3",
 			"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
 			"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
 			"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
 			"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
-			"dev": true,
 			"dependencies": {
 			"dependencies": {
 				"is-extglob": "^2.1.1"
 				"is-extglob": "^2.1.1"
 			},
 			},
@@ -6917,7 +6935,6 @@
 			"version": "7.0.0",
 			"version": "7.0.0",
 			"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
 			"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
 			"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
 			"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
-			"dev": true,
 			"engines": {
 			"engines": {
 				"node": ">=0.12.0"
 				"node": ">=0.12.0"
 			}
 			}
@@ -7097,7 +7114,6 @@
 			"version": "6.1.0",
 			"version": "6.1.0",
 			"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
 			"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
 			"integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
 			"integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
-			"dev": true,
 			"dependencies": {
 			"dependencies": {
 				"universalify": "^2.0.0"
 				"universalify": "^2.0.0"
 			},
 			},
@@ -7172,6 +7188,16 @@
 			"integrity": "sha512-tBECoUqNFbyAY4RrbqsBQqDFpGXAEbdD5QKr8kACx3+rnArmuuR22nKQWKazvp07N9yjTyDZaw/20UIH8tL9DQ==",
 			"integrity": "sha512-tBECoUqNFbyAY4RrbqsBQqDFpGXAEbdD5QKr8kACx3+rnArmuuR22nKQWKazvp07N9yjTyDZaw/20UIH8tL9DQ==",
 			"dev": true
 			"dev": true
 		},
 		},
+		"node_modules/kokoro-js": {
+			"version": "1.1.1",
+			"resolved": "https://registry.npmjs.org/kokoro-js/-/kokoro-js-1.1.1.tgz",
+			"integrity": "sha512-cyLO34iI8nBJXPnd3fI4fGeQGS+a6Uatg7eXNL6QS8TLSxaa30WD6Fj7/XoIZYaHg8q6d+TCrui/f74MTY2g1g==",
+			"license": "Apache-2.0",
+			"dependencies": {
+				"@huggingface/transformers": "^3.3.3",
+				"phonemizer": "^1.2.1"
+			}
+		},
 		"node_modules/layout-base": {
 		"node_modules/layout-base": {
 			"version": "1.0.2",
 			"version": "1.0.2",
 			"resolved": "https://registry.npmjs.org/layout-base/-/layout-base-1.0.2.tgz",
 			"resolved": "https://registry.npmjs.org/layout-base/-/layout-base-1.0.2.tgz",
@@ -7455,15 +7481,17 @@
 			}
 			}
 		},
 		},
 		"node_modules/long": {
 		"node_modules/long": {
-			"version": "5.2.3",
-			"resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz",
-			"integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q=="
+			"version": "5.2.4",
+			"resolved": "https://registry.npmjs.org/long/-/long-5.2.4.tgz",
+			"integrity": "sha512-qtzLbJE8hq7VabR3mISmVGtoXP8KGc2Z/AT8OuqlYD7JTR3oqrgwdjnk07wpj1twXxYmgDXgoKVWUG/fReSzHg==",
+			"license": "Apache-2.0"
 		},
 		},
 		"node_modules/loupe": {
 		"node_modules/loupe": {
 			"version": "2.3.7",
 			"version": "2.3.7",
 			"resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz",
 			"resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz",
 			"integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==",
 			"integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==",
 			"dev": true,
 			"dev": true,
+			"license": "MIT",
 			"dependencies": {
 			"dependencies": {
 				"get-func-name": "^2.0.1"
 				"get-func-name": "^2.0.1"
 			}
 			}
@@ -7609,7 +7637,6 @@
 			"version": "1.4.1",
 			"version": "1.4.1",
 			"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
 			"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
 			"integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
 			"integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
-			"dev": true,
 			"engines": {
 			"engines": {
 				"node": ">= 8"
 				"node": ">= 8"
 			}
 			}
@@ -8066,7 +8093,6 @@
 			"version": "4.0.8",
 			"version": "4.0.8",
 			"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
 			"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
 			"integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
 			"integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
-			"dev": true,
 			"dependencies": {
 			"dependencies": {
 				"braces": "^3.0.3",
 				"braces": "^3.0.3",
 				"picomatch": "^2.3.1"
 				"picomatch": "^2.3.1"
@@ -8150,6 +8176,7 @@
 			"version": "3.0.1",
 			"version": "3.0.1",
 			"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.0.1.tgz",
 			"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.0.1.tgz",
 			"integrity": "sha512-umcy022ILvb5/3Djuu8LWeqUa8D68JaBzlttKeMWen48SjabqS3iY5w/vzeMzMUNhLDifyhbOwKDSznB1vvrwg==",
 			"integrity": "sha512-umcy022ILvb5/3Djuu8LWeqUa8D68JaBzlttKeMWen48SjabqS3iY5w/vzeMzMUNhLDifyhbOwKDSznB1vvrwg==",
+			"license": "MIT",
 			"dependencies": {
 			"dependencies": {
 				"minipass": "^7.0.4",
 				"minipass": "^7.0.4",
 				"rimraf": "^5.0.5"
 				"rimraf": "^5.0.5"
@@ -8162,6 +8189,7 @@
 			"version": "10.4.5",
 			"version": "10.4.5",
 			"resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
 			"resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
 			"integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
 			"integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
+			"license": "ISC",
 			"dependencies": {
 			"dependencies": {
 				"foreground-child": "^3.1.0",
 				"foreground-child": "^3.1.0",
 				"jackspeak": "^3.1.2",
 				"jackspeak": "^3.1.2",
@@ -8181,6 +8209,7 @@
 			"version": "3.4.3",
 			"version": "3.4.3",
 			"resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz",
 			"resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz",
 			"integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==",
 			"integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==",
+			"license": "BlueOak-1.0.0",
 			"dependencies": {
 			"dependencies": {
 				"@isaacs/cliui": "^8.0.2"
 				"@isaacs/cliui": "^8.0.2"
 			},
 			},
@@ -8195,6 +8224,7 @@
 			"version": "9.0.5",
 			"version": "9.0.5",
 			"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
 			"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
 			"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
 			"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
+			"license": "ISC",
 			"dependencies": {
 			"dependencies": {
 				"brace-expansion": "^2.0.1"
 				"brace-expansion": "^2.0.1"
 			},
 			},
@@ -8209,6 +8239,7 @@
 			"version": "5.0.10",
 			"version": "5.0.10",
 			"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz",
 			"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz",
 			"integrity": "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==",
 			"integrity": "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==",
+			"license": "ISC",
 			"dependencies": {
 			"dependencies": {
 				"glob": "^10.3.7"
 				"glob": "^10.3.7"
 			},
 			},
@@ -8329,7 +8360,6 @@
 			"version": "3.0.0",
 			"version": "3.0.0",
 			"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
 			"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
 			"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
 			"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
-			"dev": true,
 			"engines": {
 			"engines": {
 				"node": ">=0.10.0"
 				"node": ">=0.10.0"
 			}
 			}
@@ -8433,42 +8463,46 @@
 			}
 			}
 		},
 		},
 		"node_modules/onnxruntime-common": {
 		"node_modules/onnxruntime-common": {
-			"version": "1.19.2",
-			"resolved": "https://registry.npmjs.org/onnxruntime-common/-/onnxruntime-common-1.19.2.tgz",
-			"integrity": "sha512-a4R7wYEVFbZBlp0BfhpbFWqe4opCor3KM+5Wm22Az3NGDcQMiU2hfG/0MfnBs+1ZrlSGmlgWeMcXQkDk1UFb8Q=="
+			"version": "1.20.1",
+			"resolved": "https://registry.npmjs.org/onnxruntime-common/-/onnxruntime-common-1.20.1.tgz",
+			"integrity": "sha512-YiU0s0IzYYC+gWvqD1HzLc46Du1sXpSiwzKb63PACIJr6LfL27VsXSXQvt68EzD3V0D5Bc0vyJTjmMxp0ylQiw==",
+			"license": "MIT"
 		},
 		},
 		"node_modules/onnxruntime-node": {
 		"node_modules/onnxruntime-node": {
-			"version": "1.19.2",
-			"resolved": "https://registry.npmjs.org/onnxruntime-node/-/onnxruntime-node-1.19.2.tgz",
-			"integrity": "sha512-9eHMP/HKbbeUcqte1JYzaaRC8JPn7ojWeCeoyShO86TOR97OCyIyAIOGX3V95ErjslVhJRXY8Em/caIUc0hm1Q==",
+			"version": "1.20.1",
+			"resolved": "https://registry.npmjs.org/onnxruntime-node/-/onnxruntime-node-1.20.1.tgz",
+			"integrity": "sha512-di/I4HDXRw+FLgq+TyHmQEDd3cEp9iFFZm0r4uJ1Wd7b/WE1VXtKWo8yemex347c6GNF/3Pv86ZfPhIWxORr0w==",
 			"hasInstallScript": true,
 			"hasInstallScript": true,
+			"license": "MIT",
 			"os": [
 			"os": [
 				"win32",
 				"win32",
 				"darwin",
 				"darwin",
 				"linux"
 				"linux"
 			],
 			],
 			"dependencies": {
 			"dependencies": {
-				"onnxruntime-common": "1.19.2",
+				"onnxruntime-common": "1.20.1",
 				"tar": "^7.0.1"
 				"tar": "^7.0.1"
 			}
 			}
 		},
 		},
 		"node_modules/onnxruntime-web": {
 		"node_modules/onnxruntime-web": {
-			"version": "1.20.0-dev.20241016-2b8fc5529b",
-			"resolved": "https://registry.npmjs.org/onnxruntime-web/-/onnxruntime-web-1.20.0-dev.20241016-2b8fc5529b.tgz",
-			"integrity": "sha512-1XovqtgqeEFtupuyzdDQo7Tqj4GRyNHzOoXjapCEo4rfH3JrXok5VtqucWfRXHPsOI5qoNxMQ9VE+drDIp6woQ==",
+			"version": "1.21.0-dev.20250206-d981b153d3",
+			"resolved": "https://registry.npmjs.org/onnxruntime-web/-/onnxruntime-web-1.21.0-dev.20250206-d981b153d3.tgz",
+			"integrity": "sha512-esDVQdRic6J44VBMFLumYvcGfioMh80ceLmzF1yheJyuLKq/Th8VT2aj42XWQst+2bcWnAhw4IKmRQaqzU8ugg==",
+			"license": "MIT",
 			"dependencies": {
 			"dependencies": {
-				"flatbuffers": "^1.12.0",
+				"flatbuffers": "^25.1.24",
 				"guid-typescript": "^1.0.9",
 				"guid-typescript": "^1.0.9",
 				"long": "^5.2.3",
 				"long": "^5.2.3",
-				"onnxruntime-common": "1.20.0-dev.20241016-2b8fc5529b",
+				"onnxruntime-common": "1.21.0-dev.20250206-d981b153d3",
 				"platform": "^1.3.6",
 				"platform": "^1.3.6",
 				"protobufjs": "^7.2.4"
 				"protobufjs": "^7.2.4"
 			}
 			}
 		},
 		},
 		"node_modules/onnxruntime-web/node_modules/onnxruntime-common": {
 		"node_modules/onnxruntime-web/node_modules/onnxruntime-common": {
-			"version": "1.20.0-dev.20241016-2b8fc5529b",
-			"resolved": "https://registry.npmjs.org/onnxruntime-common/-/onnxruntime-common-1.20.0-dev.20241016-2b8fc5529b.tgz",
-			"integrity": "sha512-KZK8b6zCYGZFjd4ANze0pqBnqnFTS3GIVeclQpa2qseDpXrCQJfkWBixRcrZShNhm3LpFOZ8qJYFC5/qsJK9WQ=="
+			"version": "1.21.0-dev.20250206-d981b153d3",
+			"resolved": "https://registry.npmjs.org/onnxruntime-common/-/onnxruntime-common-1.21.0-dev.20250206-d981b153d3.tgz",
+			"integrity": "sha512-TwaE51xV9q2y8pM61q73rbywJnusw9ivTEHAJ39GVWNZqxCoDBpe/tQkh/w9S+o/g+zS7YeeL0I/2mEWd+dgyA==",
+			"license": "MIT"
 		},
 		},
 		"node_modules/optionator": {
 		"node_modules/optionator": {
 			"version": "0.9.3",
 			"version": "0.9.3",
@@ -8546,7 +8580,8 @@
 		"node_modules/package-json-from-dist": {
 		"node_modules/package-json-from-dist": {
 			"version": "1.0.1",
 			"version": "1.0.1",
 			"resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
 			"resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
-			"integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="
+			"integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==",
+			"license": "BlueOak-1.0.0"
 		},
 		},
 		"node_modules/paneforge": {
 		"node_modules/paneforge": {
 			"version": "0.0.6",
 			"version": "0.0.6",
@@ -8686,6 +8721,7 @@
 			"resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz",
 			"resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz",
 			"integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==",
 			"integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==",
 			"dev": true,
 			"dev": true,
+			"license": "MIT",
 			"engines": {
 			"engines": {
 				"node": "*"
 				"node": "*"
 			}
 			}
@@ -8728,6 +8764,12 @@
 				"@types/estree": "*"
 				"@types/estree": "*"
 			}
 			}
 		},
 		},
+		"node_modules/phonemizer": {
+			"version": "1.2.1",
+			"resolved": "https://registry.npmjs.org/phonemizer/-/phonemizer-1.2.1.tgz",
+			"integrity": "sha512-v0KJ4mi2T4Q7eJQ0W15Xd4G9k4kICSXE8bpDeJ8jisL4RyJhNWsweKTOi88QXFc4r4LZlz5jVL5lCHhkpdT71A==",
+			"license": "Apache-2.0"
+		},
 		"node_modules/picocolors": {
 		"node_modules/picocolors": {
 			"version": "1.1.0",
 			"version": "1.1.0",
 			"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz",
 			"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz",
@@ -8781,7 +8823,8 @@
 		"node_modules/platform": {
 		"node_modules/platform": {
 			"version": "1.3.6",
 			"version": "1.3.6",
 			"resolved": "https://registry.npmjs.org/platform/-/platform-1.3.6.tgz",
 			"resolved": "https://registry.npmjs.org/platform/-/platform-1.3.6.tgz",
-			"integrity": "sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg=="
+			"integrity": "sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==",
+			"license": "MIT"
 		},
 		},
 		"node_modules/polyscript": {
 		"node_modules/polyscript": {
 			"version": "0.12.8",
 			"version": "0.12.8",
@@ -9064,6 +9107,7 @@
 			"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz",
 			"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz",
 			"integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==",
 			"integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==",
 			"dev": true,
 			"dev": true,
+			"license": "MIT",
 			"dependencies": {
 			"dependencies": {
 				"@jest/schemas": "^29.6.3",
 				"@jest/schemas": "^29.6.3",
 				"ansi-styles": "^5.0.0",
 				"ansi-styles": "^5.0.0",
@@ -9078,6 +9122,7 @@
 			"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
 			"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
 			"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
 			"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
 			"dev": true,
 			"dev": true,
+			"license": "MIT",
 			"engines": {
 			"engines": {
 				"node": ">=10"
 				"node": ">=10"
 			},
 			},
@@ -9314,6 +9359,7 @@
 			"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.4.0.tgz",
 			"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.4.0.tgz",
 			"integrity": "sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw==",
 			"integrity": "sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw==",
 			"hasInstallScript": true,
 			"hasInstallScript": true,
+			"license": "BSD-3-Clause",
 			"dependencies": {
 			"dependencies": {
 				"@protobufjs/aspromise": "^1.1.2",
 				"@protobufjs/aspromise": "^1.1.2",
 				"@protobufjs/base64": "^1.1.2",
 				"@protobufjs/base64": "^1.1.2",
@@ -9413,7 +9459,6 @@
 			"version": "1.2.3",
 			"version": "1.2.3",
 			"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
 			"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
 			"integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
 			"integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
-			"dev": true,
 			"funding": [
 			"funding": [
 				{
 				{
 					"type": "github",
 					"type": "github",
@@ -9504,7 +9549,8 @@
 			"version": "18.3.1",
 			"version": "18.3.1",
 			"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz",
 			"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz",
 			"integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==",
 			"integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==",
-			"dev": true
+			"dev": true,
+			"license": "MIT"
 		},
 		},
 		"node_modules/read-cache": {
 		"node_modules/read-cache": {
 			"version": "1.0.0",
 			"version": "1.0.0",
@@ -9534,7 +9580,6 @@
 			"version": "3.6.0",
 			"version": "3.6.0",
 			"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
 			"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
 			"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
 			"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
-			"dev": true,
 			"dependencies": {
 			"dependencies": {
 				"picomatch": "^2.2.1"
 				"picomatch": "^2.2.1"
 			},
 			},
@@ -9637,7 +9682,6 @@
 			"version": "1.0.4",
 			"version": "1.0.4",
 			"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
 			"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
 			"integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
 			"integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
-			"dev": true,
 			"engines": {
 			"engines": {
 				"iojs": ">=1.0.0",
 				"iojs": ">=1.0.0",
 				"node": ">=0.10.0"
 				"node": ">=0.10.0"
@@ -9763,7 +9807,6 @@
 			"version": "1.2.0",
 			"version": "1.2.0",
 			"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
 			"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
 			"integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
 			"integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
-			"dev": true,
 			"funding": [
 			"funding": [
 				{
 				{
 					"type": "github",
 					"type": "github",
@@ -11131,6 +11174,7 @@
 			"version": "7.4.3",
 			"version": "7.4.3",
 			"resolved": "https://registry.npmjs.org/tar/-/tar-7.4.3.tgz",
 			"resolved": "https://registry.npmjs.org/tar/-/tar-7.4.3.tgz",
 			"integrity": "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==",
 			"integrity": "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==",
+			"license": "ISC",
 			"dependencies": {
 			"dependencies": {
 				"@isaacs/fs-minipass": "^4.0.0",
 				"@isaacs/fs-minipass": "^4.0.0",
 				"chownr": "^3.0.0",
 				"chownr": "^3.0.0",
@@ -11147,6 +11191,7 @@
 			"version": "3.0.1",
 			"version": "3.0.1",
 			"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz",
 			"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz",
 			"integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==",
 			"integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==",
+			"license": "MIT",
 			"bin": {
 			"bin": {
 				"mkdirp": "dist/cjs/src/bin.js"
 				"mkdirp": "dist/cjs/src/bin.js"
 			},
 			},
@@ -11247,6 +11292,7 @@
 			"resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.2.1.tgz",
 			"resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.2.1.tgz",
 			"integrity": "sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==",
 			"integrity": "sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==",
 			"dev": true,
 			"dev": true,
+			"license": "MIT",
 			"engines": {
 			"engines": {
 				"node": ">=14.0.0"
 				"node": ">=14.0.0"
 			}
 			}
@@ -11277,7 +11323,6 @@
 			"version": "5.0.1",
 			"version": "5.0.1",
 			"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
 			"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
 			"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
 			"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
-			"dev": true,
 			"dependencies": {
 			"dependencies": {
 				"is-number": "^7.0.0"
 				"is-number": "^7.0.0"
 			},
 			},
@@ -11406,10 +11451,11 @@
 			"integrity": "sha512-fLIydlJy7IG9XL4wjRwEcKhxx/ekLXiWiMvcGo01cOMF+TN+5ZqajM1mRNRz2bNNi1bzou2yofhjZEQi7kgl9A=="
 			"integrity": "sha512-fLIydlJy7IG9XL4wjRwEcKhxx/ekLXiWiMvcGo01cOMF+TN+5ZqajM1mRNRz2bNNi1bzou2yofhjZEQi7kgl9A=="
 		},
 		},
 		"node_modules/type-detect": {
 		"node_modules/type-detect": {
-			"version": "4.0.8",
-			"resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
-			"integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==",
+			"version": "4.1.0",
+			"resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz",
+			"integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==",
 			"dev": true,
 			"dev": true,
+			"license": "MIT",
 			"engines": {
 			"engines": {
 				"node": ">=4"
 				"node": ">=4"
 			}
 			}
@@ -11484,7 +11530,6 @@
 			"version": "2.0.1",
 			"version": "2.0.1",
 			"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz",
 			"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz",
 			"integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==",
 			"integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==",
-			"dev": true,
 			"engines": {
 			"engines": {
 				"node": ">= 10.0.0"
 				"node": ">= 10.0.0"
 			}
 			}
@@ -11749,10 +11794,11 @@
 			}
 			}
 		},
 		},
 		"node_modules/vite-node": {
 		"node_modules/vite-node": {
-			"version": "1.6.0",
-			"resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.6.0.tgz",
-			"integrity": "sha512-de6HJgzC+TFzOu0NTC4RAIsyf/DY/ibWDYQUcuEA84EMHhcefTUGkjFHKKEJhQN4A+6I0u++kr3l36ZF2d7XRw==",
+			"version": "1.6.1",
+			"resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.6.1.tgz",
+			"integrity": "sha512-YAXkfvGtuTzwWbDSACdJSg4A4DZiAqckWe90Zapc/sEX3XvHcw1NdurM/6od8J207tSDqNbSsgdCacBgvJKFuA==",
 			"dev": true,
 			"dev": true,
+			"license": "MIT",
 			"dependencies": {
 			"dependencies": {
 				"cac": "^6.7.14",
 				"cac": "^6.7.14",
 				"debug": "^4.3.4",
 				"debug": "^4.3.4",
@@ -11770,6 +11816,24 @@
 				"url": "https://opencollective.com/vitest"
 				"url": "https://opencollective.com/vitest"
 			}
 			}
 		},
 		},
+		"node_modules/vite-plugin-static-copy": {
+			"version": "2.2.0",
+			"resolved": "https://registry.npmjs.org/vite-plugin-static-copy/-/vite-plugin-static-copy-2.2.0.tgz",
+			"integrity": "sha512-ytMrKdR9iWEYHbUxs6x53m+MRl4SJsOSoMu1U1+Pfg0DjPeMlsRVx3RR5jvoonineDquIue83Oq69JvNsFSU5w==",
+			"license": "MIT",
+			"dependencies": {
+				"chokidar": "^3.5.3",
+				"fast-glob": "^3.2.11",
+				"fs-extra": "^11.1.0",
+				"picocolors": "^1.0.0"
+			},
+			"engines": {
+				"node": "^18.0.0 || >=20.0.0"
+			},
+			"peerDependencies": {
+				"vite": "^5.0.0 || ^6.0.0"
+			}
+		},
 		"node_modules/vite/node_modules/@esbuild/aix-ppc64": {
 		"node_modules/vite/node_modules/@esbuild/aix-ppc64": {
 			"version": "0.21.5",
 			"version": "0.21.5",
 			"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
 			"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
@@ -12166,16 +12230,17 @@
 			}
 			}
 		},
 		},
 		"node_modules/vitest": {
 		"node_modules/vitest": {
-			"version": "1.6.0",
-			"resolved": "https://registry.npmjs.org/vitest/-/vitest-1.6.0.tgz",
-			"integrity": "sha512-H5r/dN06swuFnzNFhq/dnz37bPXnq8xB2xB5JOVk8K09rUtoeNN+LHWkoQ0A/i3hvbUKKcCei9KpbxqHMLhLLA==",
+			"version": "1.6.1",
+			"resolved": "https://registry.npmjs.org/vitest/-/vitest-1.6.1.tgz",
+			"integrity": "sha512-Ljb1cnSJSivGN0LqXd/zmDbWEM0RNNg2t1QW/XUhYl/qPqyu7CsqeWtqQXHVaJsecLPuDoak2oJcZN2QoRIOag==",
 			"dev": true,
 			"dev": true,
+			"license": "MIT",
 			"dependencies": {
 			"dependencies": {
-				"@vitest/expect": "1.6.0",
-				"@vitest/runner": "1.6.0",
-				"@vitest/snapshot": "1.6.0",
-				"@vitest/spy": "1.6.0",
-				"@vitest/utils": "1.6.0",
+				"@vitest/expect": "1.6.1",
+				"@vitest/runner": "1.6.1",
+				"@vitest/snapshot": "1.6.1",
+				"@vitest/spy": "1.6.1",
+				"@vitest/utils": "1.6.1",
 				"acorn-walk": "^8.3.2",
 				"acorn-walk": "^8.3.2",
 				"chai": "^4.3.10",
 				"chai": "^4.3.10",
 				"debug": "^4.3.4",
 				"debug": "^4.3.4",
@@ -12189,7 +12254,7 @@
 				"tinybench": "^2.5.1",
 				"tinybench": "^2.5.1",
 				"tinypool": "^0.8.3",
 				"tinypool": "^0.8.3",
 				"vite": "^5.0.0",
 				"vite": "^5.0.0",
-				"vite-node": "1.6.0",
+				"vite-node": "1.6.1",
 				"why-is-node-running": "^2.2.2"
 				"why-is-node-running": "^2.2.2"
 			},
 			},
 			"bin": {
 			"bin": {
@@ -12204,8 +12269,8 @@
 			"peerDependencies": {
 			"peerDependencies": {
 				"@edge-runtime/vm": "*",
 				"@edge-runtime/vm": "*",
 				"@types/node": "^18.0.0 || >=20.0.0",
 				"@types/node": "^18.0.0 || >=20.0.0",
-				"@vitest/browser": "1.6.0",
-				"@vitest/ui": "1.6.0",
+				"@vitest/browser": "1.6.1",
+				"@vitest/ui": "1.6.1",
 				"happy-dom": "*",
 				"happy-dom": "*",
 				"jsdom": "*"
 				"jsdom": "*"
 			},
 			},
@@ -12567,6 +12632,7 @@
 			"version": "5.0.0",
 			"version": "5.0.0",
 			"resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz",
 			"resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz",
 			"integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==",
 			"integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==",
+			"license": "BlueOak-1.0.0",
 			"engines": {
 			"engines": {
 				"node": ">=18"
 				"node": ">=18"
 			}
 			}

+ 5 - 3
package.json

@@ -1,6 +1,6 @@
 {
 {
 	"name": "open-webui",
 	"name": "open-webui",
-	"version": "0.5.10",
+	"version": "0.5.11",
 	"private": true,
 	"private": true,
 	"scripts": {
 	"scripts": {
 		"dev": "npm run pyodide:fetch && vite dev --host",
 		"dev": "npm run pyodide:fetch && vite dev --host",
@@ -47,7 +47,7 @@
 		"tslib": "^2.4.1",
 		"tslib": "^2.4.1",
 		"typescript": "^5.5.4",
 		"typescript": "^5.5.4",
 		"vite": "^5.4.14",
 		"vite": "^5.4.14",
-		"vitest": "^1.6.0"
+		"vitest": "^1.6.1"
 	},
 	},
 	"type": "module",
 	"type": "module",
 	"dependencies": {
 	"dependencies": {
@@ -85,6 +85,7 @@
 		"idb": "^7.1.1",
 		"idb": "^7.1.1",
 		"js-sha256": "^0.10.1",
 		"js-sha256": "^0.10.1",
 		"katex": "^0.16.21",
 		"katex": "^0.16.21",
+		"kokoro-js": "^1.1.1",
 		"marked": "^9.1.0",
 		"marked": "^9.1.0",
 		"mermaid": "^10.9.3",
 		"mermaid": "^10.9.3",
 		"paneforge": "^0.0.6",
 		"paneforge": "^0.0.6",
@@ -105,7 +106,8 @@
 		"svelte-sonner": "^0.3.19",
 		"svelte-sonner": "^0.3.19",
 		"tippy.js": "^6.3.7",
 		"tippy.js": "^6.3.7",
 		"turndown": "^7.2.0",
 		"turndown": "^7.2.0",
-		"uuid": "^9.0.1"
+		"uuid": "^9.0.1",
+		"vite-plugin-static-copy": "^2.2.0"
 	},
 	},
 	"engines": {
 	"engines": {
 		"node": ">=18.13.0 <=22.x.x",
 		"node": ">=18.13.0 <=22.x.x",

+ 6 - 3
pyproject.toml

@@ -40,6 +40,9 @@ dependencies = [
     "argon2-cffi==23.1.0",
     "argon2-cffi==23.1.0",
     "APScheduler==3.10.4",
     "APScheduler==3.10.4",
 
 
+
+    "RestrictedPython==8.0",
+
     "openai",
     "openai",
     "anthropic",
     "anthropic",
     "google-generativeai==0.7.2",
     "google-generativeai==0.7.2",
@@ -52,7 +55,7 @@ dependencies = [
     "chromadb==0.6.2",
     "chromadb==0.6.2",
     "pymilvus==2.5.0",
     "pymilvus==2.5.0",
     "qdrant-client~=1.12.0",
     "qdrant-client~=1.12.0",
-    "opensearch-py==2.7.1",
+    "opensearch-py==2.8.0",
 
 
     "transformers",
     "transformers",
     "sentence-transformers==3.3.1",
     "sentence-transformers==3.3.1",
@@ -82,7 +85,7 @@ dependencies = [
     "rapidocr-onnxruntime==1.3.24",
     "rapidocr-onnxruntime==1.3.24",
     "rank-bm25==0.2.2",
     "rank-bm25==0.2.2",
 
 
-    "faster-whisper==1.0.3",
+    "faster-whisper==1.1.1",
 
 
     "PyJWT[crypto]==2.10.1",
     "PyJWT[crypto]==2.10.1",
     "authlib==1.4.1",
     "authlib==1.4.1",
@@ -94,7 +97,7 @@ dependencies = [
 
 
     "extract_msg",
     "extract_msg",
     "pydub",
     "pydub",
-    "duckduckgo-search~=7.3.0",
+    "duckduckgo-search~=7.3.2",
 
 
     "google-api-python-client",
     "google-api-python-client",
     "google-auth-httplib2",
     "google-auth-httplib2",

+ 114 - 0
src/lib/apis/configs/index.ts

@@ -58,6 +58,120 @@ export const exportConfig = async (token: string) => {
 	return res;
 	return res;
 };
 };
 
 
+export const getDirectConnectionsConfig = async (token: string) => {
+	let error = null;
+
+	const res = await fetch(`${WEBUI_API_BASE_URL}/configs/direct_connections`, {
+		method: 'GET',
+		headers: {
+			'Content-Type': 'application/json',
+			Authorization: `Bearer ${token}`
+		}
+	})
+		.then(async (res) => {
+			if (!res.ok) throw await res.json();
+			return res.json();
+		})
+		.catch((err) => {
+			console.log(err);
+			error = err.detail;
+			return null;
+		});
+
+	if (error) {
+		throw error;
+	}
+
+	return res;
+};
+
+export const setDirectConnectionsConfig = async (token: string, config: object) => {
+	let error = null;
+
+	const res = await fetch(`${WEBUI_API_BASE_URL}/configs/direct_connections`, {
+		method: 'POST',
+		headers: {
+			'Content-Type': 'application/json',
+			Authorization: `Bearer ${token}`
+		},
+		body: JSON.stringify({
+			...config
+		})
+	})
+		.then(async (res) => {
+			if (!res.ok) throw await res.json();
+			return res.json();
+		})
+		.catch((err) => {
+			console.log(err);
+			error = err.detail;
+			return null;
+		});
+
+	if (error) {
+		throw error;
+	}
+
+	return res;
+};
+
+export const getCodeInterpreterConfig = async (token: string) => {
+	let error = null;
+
+	const res = await fetch(`${WEBUI_API_BASE_URL}/configs/code_interpreter`, {
+		method: 'GET',
+		headers: {
+			'Content-Type': 'application/json',
+			Authorization: `Bearer ${token}`
+		}
+	})
+		.then(async (res) => {
+			if (!res.ok) throw await res.json();
+			return res.json();
+		})
+		.catch((err) => {
+			console.log(err);
+			error = err.detail;
+			return null;
+		});
+
+	if (error) {
+		throw error;
+	}
+
+	return res;
+};
+
+export const setCodeInterpreterConfig = async (token: string, config: object) => {
+	let error = null;
+
+	const res = await fetch(`${WEBUI_API_BASE_URL}/configs/code_interpreter`, {
+		method: 'POST',
+		headers: {
+			'Content-Type': 'application/json',
+			Authorization: `Bearer ${token}`
+		},
+		body: JSON.stringify({
+			...config
+		})
+	})
+		.then(async (res) => {
+			if (!res.ok) throw await res.json();
+			return res.json();
+		})
+		.catch((err) => {
+			console.log(err);
+			error = err.detail;
+			return null;
+		});
+
+	if (error) {
+		throw error;
+	}
+
+	return res;
+};
+
 export const getModelsConfig = async (token: string) => {
 export const getModelsConfig = async (token: string) => {
 	let error = null;
 	let error = null;
 
 

+ 111 - 1
src/lib/apis/index.ts

@@ -1,6 +1,11 @@
 import { WEBUI_API_BASE_URL, WEBUI_BASE_URL } from '$lib/constants';
 import { WEBUI_API_BASE_URL, WEBUI_BASE_URL } from '$lib/constants';
+import { getOpenAIModelsDirect } from './openai';
 
 
-export const getModels = async (token: string = '', base: boolean = false) => {
+export const getModels = async (
+	token: string = '',
+	connections: object | null = null,
+	base: boolean = false
+) => {
 	let error = null;
 	let error = null;
 	const res = await fetch(`${WEBUI_BASE_URL}/api/models${base ? '/base' : ''}`, {
 	const res = await fetch(`${WEBUI_BASE_URL}/api/models${base ? '/base' : ''}`, {
 		method: 'GET',
 		method: 'GET',
@@ -25,6 +30,111 @@ export const getModels = async (token: string = '', base: boolean = false) => {
 	}
 	}
 
 
 	let models = res?.data ?? [];
 	let models = res?.data ?? [];
+
+	if (connections && !base) {
+		let localModels = [];
+
+		if (connections) {
+			const OPENAI_API_BASE_URLS = connections.OPENAI_API_BASE_URLS;
+			const OPENAI_API_KEYS = connections.OPENAI_API_KEYS;
+			const OPENAI_API_CONFIGS = connections.OPENAI_API_CONFIGS;
+
+			const requests = [];
+			for (const idx in OPENAI_API_BASE_URLS) {
+				const url = OPENAI_API_BASE_URLS[idx];
+
+				if (idx.toString() in OPENAI_API_CONFIGS) {
+					const apiConfig = OPENAI_API_CONFIGS[idx.toString()] ?? {};
+
+					const enable = apiConfig?.enable ?? true;
+					const modelIds = apiConfig?.model_ids ?? [];
+
+					if (enable) {
+						if (modelIds.length > 0) {
+							const modelList = {
+								object: 'list',
+								data: modelIds.map((modelId) => ({
+									id: modelId,
+									name: modelId,
+									owned_by: 'openai',
+									openai: { id: modelId },
+									urlIdx: idx
+								}))
+							};
+
+							requests.push(
+								(async () => {
+									return modelList;
+								})()
+							);
+						} else {
+							requests.push(
+								(async () => {
+									return await getOpenAIModelsDirect(url, OPENAI_API_KEYS[idx])
+										.then((res) => {
+											return res;
+										})
+										.catch((err) => {
+											return {
+												object: 'list',
+												data: [],
+												urlIdx: idx
+											};
+										});
+								})()
+							);
+						}
+					} else {
+						requests.push(
+							(async () => {
+								return {
+									object: 'list',
+									data: [],
+									urlIdx: idx
+								};
+							})()
+						);
+					}
+				}
+			}
+
+			const responses = await Promise.all(requests);
+
+			for (const idx in responses) {
+				const response = responses[idx];
+				const apiConfig = OPENAI_API_CONFIGS[idx.toString()] ?? {};
+
+				let models = Array.isArray(response) ? response : (response?.data ?? []);
+				models = models.map((model) => ({ ...model, openai: { id: model.id }, urlIdx: idx }));
+
+				const prefixId = apiConfig.prefix_id;
+				if (prefixId) {
+					for (const model of models) {
+						model.id = `${prefixId}.${model.id}`;
+					}
+				}
+
+				localModels = localModels.concat(models);
+			}
+		}
+
+		models = models.concat(
+			localModels.map((model) => ({
+				...model,
+				name: model?.name ?? model?.id,
+				direct: true
+			}))
+		);
+
+		// Remove duplicates
+		const modelsMap = {};
+		for (const model of models) {
+			modelsMap[model.id] = model;
+		}
+
+		models = Object.values(modelsMap);
+	}
+
 	return models;
 	return models;
 };
 };
 
 

+ 78 - 22
src/lib/apis/openai/index.ts

@@ -208,6 +208,33 @@ export const updateOpenAIKeys = async (token: string = '', keys: string[]) => {
 	return res.OPENAI_API_KEYS;
 	return res.OPENAI_API_KEYS;
 };
 };
 
 
+export const getOpenAIModelsDirect = async (url: string, key: string) => {
+	let error = null;
+
+	const res = await fetch(`${url}/models`, {
+		method: 'GET',
+		headers: {
+			Accept: 'application/json',
+			'Content-Type': 'application/json',
+			...(key && { authorization: `Bearer ${key}` })
+		}
+	})
+		.then(async (res) => {
+			if (!res.ok) throw await res.json();
+			return res.json();
+		})
+		.catch((err) => {
+			error = `OpenAI: ${err?.error?.message ?? 'Network Problem'}`;
+			return [];
+		});
+
+	if (error) {
+		throw error;
+	}
+
+	return res;
+};
+
 export const getOpenAIModels = async (token: string, urlIdx?: number) => {
 export const getOpenAIModels = async (token: string, urlIdx?: number) => {
 	let error = null;
 	let error = null;
 
 
@@ -241,33 +268,62 @@ export const getOpenAIModels = async (token: string, urlIdx?: number) => {
 export const verifyOpenAIConnection = async (
 export const verifyOpenAIConnection = async (
 	token: string = '',
 	token: string = '',
 	url: string = 'https://api.openai.com/v1',
 	url: string = 'https://api.openai.com/v1',
-	key: string = ''
+	key: string = '',
+	direct: boolean = false
 ) => {
 ) => {
+	if (!url) {
+		throw 'OpenAI: URL is required';
+	}
+
 	let error = null;
 	let error = null;
+	let res = null;
 
 
-	const res = await fetch(`${OPENAI_API_BASE_URL}/verify`, {
-		method: 'POST',
-		headers: {
-			Accept: 'application/json',
-			Authorization: `Bearer ${token}`,
-			'Content-Type': 'application/json'
-		},
-		body: JSON.stringify({
-			url,
-			key
+	if (direct) {
+		res = await fetch(`${url}/models`, {
+			method: 'GET',
+			headers: {
+				Accept: 'application/json',
+				Authorization: `Bearer ${key}`,
+				'Content-Type': 'application/json'
+			}
 		})
 		})
-	})
-		.then(async (res) => {
-			if (!res.ok) throw await res.json();
-			return res.json();
+			.then(async (res) => {
+				if (!res.ok) throw await res.json();
+				return res.json();
+			})
+			.catch((err) => {
+				error = `OpenAI: ${err?.error?.message ?? 'Network Problem'}`;
+				return [];
+			});
+
+		if (error) {
+			throw error;
+		}
+	} else {
+		res = await fetch(`${OPENAI_API_BASE_URL}/verify`, {
+			method: 'POST',
+			headers: {
+				Accept: 'application/json',
+				Authorization: `Bearer ${token}`,
+				'Content-Type': 'application/json'
+			},
+			body: JSON.stringify({
+				url,
+				key
+			})
 		})
 		})
-		.catch((err) => {
-			error = `OpenAI: ${err?.error?.message ?? 'Network Problem'}`;
-			return [];
-		});
-
-	if (error) {
-		throw error;
+			.then(async (res) => {
+				if (!res.ok) throw await res.json();
+				return res.json();
+			})
+			.catch((err) => {
+				error = `OpenAI: ${err?.error?.message ?? 'Network Problem'}`;
+				return [];
+			});
+
+		if (error) {
+			throw error;
+		}
 	}
 	}
 
 
 	return res;
 	return res;

+ 7 - 3
src/lib/components/admin/Settings/Connections/AddConnectionModal.svelte → src/lib/components/AddConnectionModal.svelte

@@ -20,7 +20,9 @@
 
 
 	export let show = false;
 	export let show = false;
 	export let edit = false;
 	export let edit = false;
+
 	export let ollama = false;
 	export let ollama = false;
+	export let direct = false;
 
 
 	export let connection = null;
 	export let connection = null;
 
 
@@ -46,9 +48,11 @@
 	};
 	};
 
 
 	const verifyOpenAIHandler = async () => {
 	const verifyOpenAIHandler = async () => {
-		const res = await verifyOpenAIConnection(localStorage.token, url, key).catch((error) => {
-			toast.error(`${error}`);
-		});
+		const res = await verifyOpenAIConnection(localStorage.token, url, key, direct).catch(
+			(error) => {
+				toast.error(`${error}`);
+			}
+		);
 
 
 		if (res) {
 		if (res) {
 			toast.success($i18n.t('Server connection verified'));
 			toast.success($i18n.t('Server connection verified'));

+ 2 - 2
src/lib/components/admin/Evaluations/Feedbacks.svelte

@@ -65,7 +65,7 @@
 	};
 	};
 
 
 	const shareHandler = async () => {
 	const shareHandler = async () => {
-		toast.success($i18n.t('Redirecting you to OpenWebUI Community'));
+		toast.success($i18n.t('Redirecting you to Open WebUI Community'));
 
 
 		// remove snapshot from feedbacks
 		// remove snapshot from feedbacks
 		const feedbacksToShare = feedbacks.map((f) => {
 		const feedbacksToShare = feedbacks.map((f) => {
@@ -266,7 +266,7 @@
 					}}
 					}}
 				>
 				>
 					<div class=" self-center mr-2 font-medium line-clamp-1">
 					<div class=" self-center mr-2 font-medium line-clamp-1">
-						{$i18n.t('Share to OpenWebUI Community')}
+						{$i18n.t('Share to Open WebUI Community')}
 					</div>
 					</div>
 
 
 					<div class=" self-center">
 					<div class=" self-center">

+ 3 - 1
src/lib/components/admin/Evaluations/Leaderboard.svelte

@@ -1,6 +1,8 @@
 <script lang="ts">
 <script lang="ts">
 	import * as ort from 'onnxruntime-web';
 	import * as ort from 'onnxruntime-web';
-	import { AutoModel, AutoTokenizer } from '@huggingface/transformers';
+	import { env, AutoModel, AutoTokenizer } from '@huggingface/transformers';
+
+	env.backends.onnx.wasm.wasmPaths = '/wasm/';
 
 
 	import { onMount, getContext } from 'svelte';
 	import { onMount, getContext } from 'svelte';
 	import { models } from '$lib/stores';
 	import { models } from '$lib/stores';

+ 34 - 8
src/lib/components/admin/Functions.svelte

@@ -3,7 +3,7 @@
 	import fileSaver from 'file-saver';
 	import fileSaver from 'file-saver';
 	const { saveAs } = fileSaver;
 	const { saveAs } = fileSaver;
 
 
-	import { WEBUI_NAME, config, functions, models } from '$lib/stores';
+	import { WEBUI_NAME, config, functions, models, settings } from '$lib/stores';
 	import { onMount, getContext, tick } from 'svelte';
 	import { onMount, getContext, tick } from 'svelte';
 
 
 	import { goto } from '$app/navigation';
 	import { goto } from '$app/navigation';
@@ -65,7 +65,7 @@
 			return null;
 			return null;
 		});
 		});
 
 
-		toast.success($i18n.t('Redirecting you to OpenWebUI Community'));
+		toast.success($i18n.t('Redirecting you to Open WebUI Community'));
 
 
 		const url = 'https://openwebui.com';
 		const url = 'https://openwebui.com';
 
 
@@ -126,7 +126,12 @@
 			toast.success($i18n.t('Function deleted successfully'));
 			toast.success($i18n.t('Function deleted successfully'));
 
 
 			functions.set(await getFunctions(localStorage.token));
 			functions.set(await getFunctions(localStorage.token));
-			models.set(await getModels(localStorage.token));
+			models.set(
+				await getModels(
+					localStorage.token,
+					$config?.features?.enable_direct_connections && ($settings?.directConnections ?? null)
+				)
+			);
 		}
 		}
 	};
 	};
 
 
@@ -147,7 +152,12 @@
 			}
 			}
 
 
 			functions.set(await getFunctions(localStorage.token));
 			functions.set(await getFunctions(localStorage.token));
-			models.set(await getModels(localStorage.token));
+			models.set(
+				await getModels(
+					localStorage.token,
+					$config?.features?.enable_direct_connections && ($settings?.directConnections ?? null)
+				)
+			);
 		}
 		}
 	};
 	};
 
 
@@ -359,7 +369,13 @@
 							bind:state={func.is_active}
 							bind:state={func.is_active}
 							on:change={async (e) => {
 							on:change={async (e) => {
 								toggleFunctionById(localStorage.token, func.id);
 								toggleFunctionById(localStorage.token, func.id);
-								models.set(await getModels(localStorage.token));
+								models.set(
+									await getModels(
+										localStorage.token,
+										$config?.features?.enable_direct_connections &&
+											($settings?.directConnections ?? null)
+									)
+								);
 							}}
 							}}
 						/>
 						/>
 					</Tooltip>
 					</Tooltip>
@@ -453,7 +469,7 @@
 {#if $config?.features.enable_community_sharing}
 {#if $config?.features.enable_community_sharing}
 	<div class=" my-16">
 	<div class=" my-16">
 		<div class=" text-xl font-medium mb-1 line-clamp-1">
 		<div class=" text-xl font-medium mb-1 line-clamp-1">
-			{$i18n.t('Made by OpenWebUI Community')}
+			{$i18n.t('Made by Open WebUI Community')}
 		</div>
 		</div>
 
 
 		<a
 		<a
@@ -496,7 +512,12 @@
 	id={selectedFunction?.id ?? null}
 	id={selectedFunction?.id ?? null}
 	on:save={async () => {
 	on:save={async () => {
 		await tick();
 		await tick();
-		models.set(await getModels(localStorage.token));
+		models.set(
+			await getModels(
+				localStorage.token,
+				$config?.features?.enable_direct_connections && ($settings?.directConnections ?? null)
+			)
+		);
 	}}
 	}}
 />
 />
 
 
@@ -517,7 +538,12 @@
 
 
 			toast.success($i18n.t('Functions imported successfully'));
 			toast.success($i18n.t('Functions imported successfully'));
 			functions.set(await getFunctions(localStorage.token));
 			functions.set(await getFunctions(localStorage.token));
-			models.set(await getModels(localStorage.token));
+			models.set(
+				await getModels(
+					localStorage.token,
+					$config?.features?.enable_direct_connections && ($settings?.directConnections ?? null)
+				)
+			);
 		};
 		};
 
 
 		reader.readAsText(importFiles[0]);
 		reader.readAsText(importFiles[0]);

+ 36 - 0
src/lib/components/admin/Settings.svelte

@@ -19,6 +19,7 @@
 	import ChartBar from '../icons/ChartBar.svelte';
 	import ChartBar from '../icons/ChartBar.svelte';
 	import DocumentChartBar from '../icons/DocumentChartBar.svelte';
 	import DocumentChartBar from '../icons/DocumentChartBar.svelte';
 	import Evaluations from './Settings/Evaluations.svelte';
 	import Evaluations from './Settings/Evaluations.svelte';
+	import CodeInterpreter from './Settings/CodeInterpreter.svelte';
 
 
 	const i18n = getContext('i18n');
 	const i18n = getContext('i18n');
 
 
@@ -188,6 +189,32 @@
 			<div class=" self-center">{$i18n.t('Web Search')}</div>
 			<div class=" self-center">{$i18n.t('Web Search')}</div>
 		</button>
 		</button>
 
 
+		<button
+			class="px-0.5 py-1 min-w-fit rounded-lg flex-1 md:flex-none flex text-right transition {selectedTab ===
+			'code-interpreter'
+				? ''
+				: ' text-gray-300 dark:text-gray-600 hover:text-gray-700 dark:hover:text-white'}"
+			on:click={() => {
+				selectedTab = 'code-interpreter';
+			}}
+		>
+			<div class=" self-center mr-2">
+				<svg
+					xmlns="http://www.w3.org/2000/svg"
+					viewBox="0 0 16 16"
+					fill="currentColor"
+					class="size-4"
+				>
+					<path
+						fill-rule="evenodd"
+						d="M2 4a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V4Zm2.22 1.97a.75.75 0 0 0 0 1.06l.97.97-.97.97a.75.75 0 1 0 1.06 1.06l1.5-1.5a.75.75 0 0 0 0-1.06l-1.5-1.5a.75.75 0 0 0-1.06 0ZM8.75 8.5a.75.75 0 0 0 0 1.5h2.5a.75.75 0 0 0 0-1.5h-2.5Z"
+						clip-rule="evenodd"
+					/>
+				</svg>
+			</div>
+			<div class=" self-center">{$i18n.t('Code Interpreter')}</div>
+		</button>
+
 		<button
 		<button
 			class="px-0.5 py-1 min-w-fit rounded-lg flex-1 md:flex-none flex text-right transition {selectedTab ===
 			class="px-0.5 py-1 min-w-fit rounded-lg flex-1 md:flex-none flex text-right transition {selectedTab ===
 			'interface'
 			'interface'
@@ -364,6 +391,15 @@
 					await config.set(await getBackendConfig());
 					await config.set(await getBackendConfig());
 				}}
 				}}
 			/>
 			/>
+		{:else if selectedTab === 'code-interpreter'}
+			<CodeInterpreter
+				saveHandler={async () => {
+					toast.success($i18n.t('Settings saved successfully!'));
+
+					await tick();
+					await config.set(await getBackendConfig());
+				}}
+			/>
 		{:else if selectedTab === 'interface'}
 		{:else if selectedTab === 'interface'}
 			<Interface
 			<Interface
 				on:save={() => {
 				on:save={() => {

+ 41 - 3
src/lib/components/admin/Settings/Audio.svelte

@@ -10,7 +10,7 @@
 		getModels as _getModels,
 		getModels as _getModels,
 		getVoices as _getVoices
 		getVoices as _getVoices
 	} from '$lib/apis/audio';
 	} from '$lib/apis/audio';
-	import { config } from '$lib/stores';
+	import { config, settings } from '$lib/stores';
 
 
 	import SensitiveInput from '$lib/components/common/SensitiveInput.svelte';
 	import SensitiveInput from '$lib/components/common/SensitiveInput.svelte';
 
 
@@ -39,6 +39,7 @@
 	let STT_ENGINE = '';
 	let STT_ENGINE = '';
 	let STT_MODEL = '';
 	let STT_MODEL = '';
 	let STT_WHISPER_MODEL = '';
 	let STT_WHISPER_MODEL = '';
+	let STT_DEEPGRAM_API_KEY = '';
 
 
 	let STT_WHISPER_MODEL_LOADING = false;
 	let STT_WHISPER_MODEL_LOADING = false;
 
 
@@ -50,7 +51,10 @@
 		if (TTS_ENGINE === '') {
 		if (TTS_ENGINE === '') {
 			models = [];
 			models = [];
 		} else {
 		} else {
-			const res = await _getModels(localStorage.token).catch((e) => {
+			const res = await _getModels(
+				localStorage.token,
+				$config?.features?.enable_direct_connections && ($settings?.directConnections ?? null)
+			).catch((e) => {
 				toast.error(`${e}`);
 				toast.error(`${e}`);
 			});
 			});
 
 
@@ -103,7 +107,8 @@
 				OPENAI_API_KEY: STT_OPENAI_API_KEY,
 				OPENAI_API_KEY: STT_OPENAI_API_KEY,
 				ENGINE: STT_ENGINE,
 				ENGINE: STT_ENGINE,
 				MODEL: STT_MODEL,
 				MODEL: STT_MODEL,
-				WHISPER_MODEL: STT_WHISPER_MODEL
+				WHISPER_MODEL: STT_WHISPER_MODEL,
+				DEEPGRAM_API_KEY: STT_DEEPGRAM_API_KEY
 			}
 			}
 		});
 		});
 
 
@@ -143,6 +148,7 @@
 			STT_ENGINE = res.stt.ENGINE;
 			STT_ENGINE = res.stt.ENGINE;
 			STT_MODEL = res.stt.MODEL;
 			STT_MODEL = res.stt.MODEL;
 			STT_WHISPER_MODEL = res.stt.WHISPER_MODEL;
 			STT_WHISPER_MODEL = res.stt.WHISPER_MODEL;
+			STT_DEEPGRAM_API_KEY = res.stt.DEEPGRAM_API_KEY;
 		}
 		}
 
 
 		await getVoices();
 		await getVoices();
@@ -173,6 +179,7 @@
 							<option value="">{$i18n.t('Whisper (Local)')}</option>
 							<option value="">{$i18n.t('Whisper (Local)')}</option>
 							<option value="openai">OpenAI</option>
 							<option value="openai">OpenAI</option>
 							<option value="web">{$i18n.t('Web API')}</option>
 							<option value="web">{$i18n.t('Web API')}</option>
+							<option value="deepgram">Deepgram</option>
 						</select>
 						</select>
 					</div>
 					</div>
 				</div>
 				</div>
@@ -210,6 +217,37 @@
 							</div>
 							</div>
 						</div>
 						</div>
 					</div>
 					</div>
+				{:else if STT_ENGINE === 'deepgram'}
+					<div>
+						<div class="mt-1 flex gap-2 mb-1">
+							<SensitiveInput placeholder={$i18n.t('API Key')} bind:value={STT_DEEPGRAM_API_KEY} />
+						</div>
+					</div>
+
+					<hr class=" dark:border-gray-850 my-2" />
+
+					<div>
+						<div class=" mb-1.5 text-sm font-medium">{$i18n.t('STT Model')}</div>
+						<div class="flex w-full">
+							<div class="flex-1">
+								<input
+									class="w-full rounded-lg py-2 px-4 text-sm bg-gray-50 dark:text-gray-300 dark:bg-gray-850 outline-none"
+									bind:value={STT_MODEL}
+									placeholder="Select a model (optional)"
+								/>
+							</div>
+						</div>
+						<div class="mt-2 mb-1 text-xs text-gray-400 dark:text-gray-500">
+							{$i18n.t('Leave model field empty to use the default model.')}
+							<a
+								class=" hover:underline dark:text-gray-200 text-gray-800"
+								href="https://developers.deepgram.com/docs/models"
+								target="_blank"
+							>
+								{$i18n.t('Click here to see available models.')}
+							</a>
+						</div>
+					</div>
 				{:else if STT_ENGINE === ''}
 				{:else if STT_ENGINE === ''}
 					<div>
 					<div>
 						<div class=" mb-1.5 text-sm font-medium">{$i18n.t('STT Model')}</div>
 						<div class=" mb-1.5 text-sm font-medium">{$i18n.t('STT Model')}</div>

+ 166 - 0
src/lib/components/admin/Settings/CodeInterpreter.svelte

@@ -0,0 +1,166 @@
+<script lang="ts">
+	import { toast } from 'svelte-sonner';
+	import { onMount, getContext } from 'svelte';
+	import { getCodeInterpreterConfig, setCodeInterpreterConfig } from '$lib/apis/configs';
+
+	import SensitiveInput from '$lib/components/common/SensitiveInput.svelte';
+
+	import Tooltip from '$lib/components/common/Tooltip.svelte';
+	import Textarea from '$lib/components/common/Textarea.svelte';
+	import Switch from '$lib/components/common/Switch.svelte';
+
+	const i18n = getContext('i18n');
+
+	export let saveHandler: Function;
+
+	let config = null;
+
+	let engines = ['pyodide', 'jupyter'];
+
+	const submitHandler = async () => {
+		const res = await setCodeInterpreterConfig(localStorage.token, config);
+	};
+
+	onMount(async () => {
+		const res = await getCodeInterpreterConfig(localStorage.token);
+
+		if (res) {
+			config = res;
+		}
+	});
+</script>
+
+<form
+	class="flex flex-col h-full justify-between space-y-3 text-sm"
+	on:submit|preventDefault={async () => {
+		await submitHandler();
+		saveHandler();
+	}}
+>
+	<div class=" space-y-3 overflow-y-scroll scrollbar-hidden h-full">
+		{#if config}
+			<div>
+				<div class=" mb-1 text-sm font-medium">
+					{$i18n.t('Code Interpreter')}
+				</div>
+
+				<div>
+					<div class=" py-0.5 flex w-full justify-between">
+						<div class=" self-center text-xs font-medium">
+							{$i18n.t('Enable Code Interpreter')}
+						</div>
+
+						<Switch bind:state={config.ENABLE_CODE_INTERPRETER} />
+					</div>
+				</div>
+
+				<div class=" py-0.5 flex w-full justify-between">
+					<div class=" self-center text-xs font-medium">{$i18n.t('Code Interpreter Engine')}</div>
+					<div class="flex items-center relative">
+						<select
+							class="dark:bg-gray-900 w-fit pr-8 rounded px-2 p-1 text-xs bg-transparent outline-none text-right"
+							bind:value={config.CODE_INTERPRETER_ENGINE}
+							placeholder={$i18n.t('Select a engine')}
+							required
+						>
+							<option disabled selected value="">{$i18n.t('Select a engine')}</option>
+							{#each engines as engine}
+								<option value={engine}>{engine}</option>
+							{/each}
+						</select>
+					</div>
+				</div>
+
+				{#if config.CODE_INTERPRETER_ENGINE === 'jupyter'}
+					<div class="mt-1 flex flex-col gap-1.5 mb-1 w-full">
+						<div class="text-xs font-medium">
+							{$i18n.t('Jupyter URL')}
+						</div>
+
+						<div class="flex w-full">
+							<div class="flex-1">
+								<input
+									class="w-full text-sm py-0.5 placeholder:text-gray-300 dark:placeholder:text-gray-700 bg-transparent outline-none"
+									type="text"
+									placeholder={$i18n.t('Enter Jupyter URL')}
+									bind:value={config.CODE_INTERPRETER_JUPYTER_URL}
+									autocomplete="off"
+								/>
+							</div>
+						</div>
+					</div>
+
+					<div class="mt-1 flex gap-2 mb-1 w-full items-center justify-between">
+						<div class="text-xs font-medium">
+							{$i18n.t('Jupyter Auth')}
+						</div>
+
+						<div>
+							<select
+								class="dark:bg-gray-900 w-fit pr-8 rounded px-2 p-1 text-xs bg-transparent outline-none text-left"
+								bind:value={config.CODE_INTERPRETER_JUPYTER_AUTH}
+								placeholder={$i18n.t('Select an auth method')}
+							>
+								<option selected value="">{$i18n.t('None')}</option>
+								<option value="token">{$i18n.t('Token')}</option>
+								<option value="password">{$i18n.t('Password')}</option>
+							</select>
+						</div>
+					</div>
+
+					{#if config.CODE_INTERPRETER_JUPYTER_AUTH}
+						<div class="flex w-full gap-2">
+							<div class="flex-1">
+								{#if config.CODE_INTERPRETER_JUPYTER_AUTH === 'password'}
+									<SensitiveInput
+										type="text"
+										placeholder={$i18n.t('Enter Jupyter Password')}
+										bind:value={config.CODE_INTERPRETER_JUPYTER_AUTH_PASSWORD}
+										autocomplete="off"
+									/>
+								{:else}
+									<SensitiveInput
+										type="text"
+										placeholder={$i18n.t('Enter Jupyter Token')}
+										bind:value={config.CODE_INTERPRETER_JUPYTER_AUTH_TOKEN}
+										autocomplete="off"
+									/>
+								{/if}
+							</div>
+						</div>
+					{/if}
+				{/if}
+			</div>
+
+			<hr class=" dark:border-gray-850 my-2" />
+
+			<div>
+				<div class="py-0.5 w-full">
+					<div class=" mb-2.5 text-xs font-medium">
+						{$i18n.t('Code Interpreter Prompt Template')}
+					</div>
+
+					<Tooltip
+						content={$i18n.t('Leave empty to use the default prompt, or enter a custom prompt')}
+						placement="top-start"
+					>
+						<Textarea
+							bind:value={config.CODE_INTERPRETER_PROMPT_TEMPLATE}
+							placeholder={$i18n.t(
+								'Leave empty to use the default prompt, or enter a custom prompt'
+							)}
+						/>
+					</Tooltip>
+				</div>
+			</div>
+		{/if}
+	</div>
+	<div class="flex justify-end pt-3 text-sm font-medium">
+		<button
+			class="px-3.5 py-1.5 text-sm font-medium bg-black hover:bg-gray-900 text-white dark:bg-white dark:text-black dark:hover:bg-gray-100 transition rounded-full"
+			type="submit"
+		>
+			{$i18n.t('Save')}
+		</button>
+	</div>
+</form>

+ 78 - 17
src/lib/components/admin/Settings/Connections.svelte

@@ -7,8 +7,9 @@
 	import { getOllamaConfig, updateOllamaConfig } from '$lib/apis/ollama';
 	import { getOllamaConfig, updateOllamaConfig } from '$lib/apis/ollama';
 	import { getOpenAIConfig, updateOpenAIConfig, getOpenAIModels } from '$lib/apis/openai';
 	import { getOpenAIConfig, updateOpenAIConfig, getOpenAIModels } from '$lib/apis/openai';
 	import { getModels as _getModels } from '$lib/apis';
 	import { getModels as _getModels } from '$lib/apis';
+	import { getDirectConnectionsConfig, setDirectConnectionsConfig } from '$lib/apis/configs';
 
 
-	import { models, user } from '$lib/stores';
+	import { config, models, settings, user } from '$lib/stores';
 
 
 	import Switch from '$lib/components/common/Switch.svelte';
 	import Switch from '$lib/components/common/Switch.svelte';
 	import Spinner from '$lib/components/common/Spinner.svelte';
 	import Spinner from '$lib/components/common/Spinner.svelte';
@@ -16,13 +17,16 @@
 	import Plus from '$lib/components/icons/Plus.svelte';
 	import Plus from '$lib/components/icons/Plus.svelte';
 
 
 	import OpenAIConnection from './Connections/OpenAIConnection.svelte';
 	import OpenAIConnection from './Connections/OpenAIConnection.svelte';
-	import AddConnectionModal from './Connections/AddConnectionModal.svelte';
+	import AddConnectionModal from '$lib/components/AddConnectionModal.svelte';
 	import OllamaConnection from './Connections/OllamaConnection.svelte';
 	import OllamaConnection from './Connections/OllamaConnection.svelte';
 
 
 	const i18n = getContext('i18n');
 	const i18n = getContext('i18n');
 
 
 	const getModels = async () => {
 	const getModels = async () => {
-		const models = await _getModels(localStorage.token);
+		const models = await _getModels(
+			localStorage.token,
+			$config?.features?.enable_direct_connections && ($settings?.directConnections ?? null)
+		);
 		return models;
 		return models;
 	};
 	};
 
 
@@ -37,6 +41,8 @@
 	let ENABLE_OPENAI_API: null | boolean = null;
 	let ENABLE_OPENAI_API: null | boolean = null;
 	let ENABLE_OLLAMA_API: null | boolean = null;
 	let ENABLE_OLLAMA_API: null | boolean = null;
 
 
+	let directConnectionsConfig = null;
+
 	let pipelineUrls = {};
 	let pipelineUrls = {};
 	let showAddOpenAIConnectionModal = false;
 	let showAddOpenAIConnectionModal = false;
 	let showAddOllamaConnectionModal = false;
 	let showAddOllamaConnectionModal = false;
@@ -98,17 +104,33 @@
 		}
 		}
 	};
 	};
 
 
+	const updateDirectConnectionsHandler = async () => {
+		const res = await setDirectConnectionsConfig(localStorage.token, directConnectionsConfig).catch(
+			(error) => {
+				toast.error(`${error}`);
+			}
+		);
+
+		if (res) {
+			toast.success($i18n.t('Direct Connections settings updated'));
+			await models.set(await getModels());
+		}
+	};
+
 	const addOpenAIConnectionHandler = async (connection) => {
 	const addOpenAIConnectionHandler = async (connection) => {
 		OPENAI_API_BASE_URLS = [...OPENAI_API_BASE_URLS, connection.url];
 		OPENAI_API_BASE_URLS = [...OPENAI_API_BASE_URLS, connection.url];
 		OPENAI_API_KEYS = [...OPENAI_API_KEYS, connection.key];
 		OPENAI_API_KEYS = [...OPENAI_API_KEYS, connection.key];
-		OPENAI_API_CONFIGS[OPENAI_API_BASE_URLS.length] = connection.config;
+		OPENAI_API_CONFIGS[OPENAI_API_BASE_URLS.length - 1] = connection.config;
 
 
 		await updateOpenAIHandler();
 		await updateOpenAIHandler();
 	};
 	};
 
 
 	const addOllamaConnectionHandler = async (connection) => {
 	const addOllamaConnectionHandler = async (connection) => {
 		OLLAMA_BASE_URLS = [...OLLAMA_BASE_URLS, connection.url];
 		OLLAMA_BASE_URLS = [...OLLAMA_BASE_URLS, connection.url];
-		OLLAMA_API_CONFIGS[OLLAMA_BASE_URLS.length] = connection.config;
+		OLLAMA_API_CONFIGS[OLLAMA_BASE_URLS.length - 1] = {
+			...connection.config,
+			key: connection.key
+		};
 
 
 		await updateOllamaHandler();
 		await updateOllamaHandler();
 	};
 	};
@@ -124,6 +146,9 @@
 				})(),
 				})(),
 				(async () => {
 				(async () => {
 					openaiConfig = await getOpenAIConfig(localStorage.token);
 					openaiConfig = await getOpenAIConfig(localStorage.token);
+				})(),
+				(async () => {
+					directConnectionsConfig = await getDirectConnectionsConfig(localStorage.token);
 				})()
 				})()
 			]);
 			]);
 
 
@@ -167,6 +192,14 @@
 			}
 			}
 		}
 		}
 	});
 	});
+
+	const submitHandler = async () => {
+		updateOpenAIHandler();
+		updateOllamaHandler();
+		updateDirectConnectionsHandler();
+
+		dispatch('save');
+	};
 </script>
 </script>
 
 
 <AddConnectionModal
 <AddConnectionModal
@@ -180,17 +213,9 @@
 	onSubmit={addOllamaConnectionHandler}
 	onSubmit={addOllamaConnectionHandler}
 />
 />
 
 
-<form
-	class="flex flex-col h-full justify-between text-sm"
-	on:submit|preventDefault={() => {
-		updateOpenAIHandler();
-		updateOllamaHandler();
-
-		dispatch('save');
-	}}
->
+<form class="flex flex-col h-full justify-between text-sm" on:submit|preventDefault={submitHandler}>
 	<div class=" overflow-y-scroll scrollbar-hidden h-full">
 	<div class=" overflow-y-scroll scrollbar-hidden h-full">
-		{#if ENABLE_OPENAI_API !== null && ENABLE_OLLAMA_API !== null}
+		{#if ENABLE_OPENAI_API !== null && ENABLE_OLLAMA_API !== null && directConnectionsConfig !== null}
 			<div class="my-2">
 			<div class="my-2">
 				<div class="mt-2 space-y-2 pr-1.5">
 				<div class="mt-2 space-y-2 pr-1.5">
 					<div class="flex justify-between items-center text-sm">
 					<div class="flex justify-between items-center text-sm">
@@ -244,7 +269,11 @@
 											);
 											);
 											OPENAI_API_KEYS = OPENAI_API_KEYS.filter((key, keyIdx) => idx !== keyIdx);
 											OPENAI_API_KEYS = OPENAI_API_KEYS.filter((key, keyIdx) => idx !== keyIdx);
 
 
-											delete OPENAI_API_CONFIGS[idx];
+											let newConfig = {};
+											OPENAI_API_BASE_URLS.forEach((url, newIdx) => {
+												newConfig[newIdx] = OPENAI_API_CONFIGS[newIdx < idx ? newIdx : newIdx + 1];
+											});
+											OPENAI_API_CONFIGS = newConfig;
 										}}
 										}}
 									/>
 									/>
 								{/each}
 								{/each}
@@ -302,7 +331,12 @@
 										}}
 										}}
 										onDelete={() => {
 										onDelete={() => {
 											OLLAMA_BASE_URLS = OLLAMA_BASE_URLS.filter((url, urlIdx) => idx !== urlIdx);
 											OLLAMA_BASE_URLS = OLLAMA_BASE_URLS.filter((url, urlIdx) => idx !== urlIdx);
-											delete OLLAMA_API_CONFIGS[idx];
+
+											let newConfig = {};
+											OLLAMA_BASE_URLS.forEach((url, newIdx) => {
+												newConfig[newIdx] = OLLAMA_API_CONFIGS[newIdx < idx ? newIdx : newIdx + 1];
+											});
+											OLLAMA_API_CONFIGS = newConfig;
 										}}
 										}}
 									/>
 									/>
 								{/each}
 								{/each}
@@ -322,6 +356,33 @@
 					</div>
 					</div>
 				{/if}
 				{/if}
 			</div>
 			</div>
+
+			<hr class=" border-gray-50 dark:border-gray-850" />
+
+			<div class="pr-1.5 my-2">
+				<div class="flex justify-between items-center text-sm">
+					<div class="  font-medium">{$i18n.t('Direct Connections')}</div>
+
+					<div class="flex items-center">
+						<div class="">
+							<Switch
+								bind:state={directConnectionsConfig.ENABLE_DIRECT_CONNECTIONS}
+								on:change={async () => {
+									updateDirectConnectionsHandler();
+								}}
+							/>
+						</div>
+					</div>
+				</div>
+
+				<div class="mt-1.5">
+					<div class="text-xs text-gray-500">
+						{$i18n.t(
+							'Direct Connections allow users to connect to their own OpenAI compatible API endpoints.'
+						)}
+					</div>
+				</div>
+			</div>
 		{:else}
 		{:else}
 			<div class="flex h-full justify-center">
 			<div class="flex h-full justify-center">
 				<div class="my-auto">
 				<div class="my-auto">

+ 1 - 1
src/lib/components/admin/Settings/Connections/OllamaConnection.svelte

@@ -4,7 +4,7 @@
 
 
 	import Tooltip from '$lib/components/common/Tooltip.svelte';
 	import Tooltip from '$lib/components/common/Tooltip.svelte';
 	import SensitiveInput from '$lib/components/common/SensitiveInput.svelte';
 	import SensitiveInput from '$lib/components/common/SensitiveInput.svelte';
-	import AddConnectionModal from './AddConnectionModal.svelte';
+	import AddConnectionModal from '$lib/components/AddConnectionModal.svelte';
 
 
 	import Cog6 from '$lib/components/icons/Cog6.svelte';
 	import Cog6 from '$lib/components/icons/Cog6.svelte';
 	import Wrench from '$lib/components/icons/Wrench.svelte';
 	import Wrench from '$lib/components/icons/Wrench.svelte';

+ 2 - 1
src/lib/components/admin/Settings/Connections/OpenAIConnection.svelte

@@ -5,7 +5,8 @@
 	import Tooltip from '$lib/components/common/Tooltip.svelte';
 	import Tooltip from '$lib/components/common/Tooltip.svelte';
 	import SensitiveInput from '$lib/components/common/SensitiveInput.svelte';
 	import SensitiveInput from '$lib/components/common/SensitiveInput.svelte';
 	import Cog6 from '$lib/components/icons/Cog6.svelte';
 	import Cog6 from '$lib/components/icons/Cog6.svelte';
-	import AddConnectionModal from './AddConnectionModal.svelte';
+	import AddConnectionModal from '$lib/components/AddConnectionModal.svelte';
+
 	import { connect } from 'socket.io-client';
 	import { connect } from 'socket.io-client';
 
 
 	export let onDelete = () => {};
 	export let onDelete = () => {};

+ 39 - 19
src/lib/components/admin/Settings/Evaluations.svelte

@@ -1,6 +1,6 @@
 <script lang="ts">
 <script lang="ts">
 	import { toast } from 'svelte-sonner';
 	import { toast } from 'svelte-sonner';
-	import { models, user } from '$lib/stores';
+	import { models, settings, user, config } from '$lib/stores';
 	import { createEventDispatcher, onMount, getContext, tick } from 'svelte';
 	import { createEventDispatcher, onMount, getContext, tick } from 'svelte';
 
 
 	const dispatch = createEventDispatcher();
 	const dispatch = createEventDispatcher();
@@ -16,49 +16,69 @@
 
 
 	const i18n = getContext('i18n');
 	const i18n = getContext('i18n');
 
 
-	let config = null;
+	let evaluationConfig = null;
 	let showAddModel = false;
 	let showAddModel = false;
 
 
 	const submitHandler = async () => {
 	const submitHandler = async () => {
-		config = await updateConfig(localStorage.token, config).catch((err) => {
+		evaluationConfig = await updateConfig(localStorage.token, evaluationConfig).catch((err) => {
 			toast.error(err);
 			toast.error(err);
 			return null;
 			return null;
 		});
 		});
 
 
-		if (config) {
+		if (evaluationConfig) {
 			toast.success('Settings saved successfully');
 			toast.success('Settings saved successfully');
-			models.set(await getModels(localStorage.token));
+			models.set(
+				await getModels(
+					localStorage.token,
+					$config?.features?.enable_direct_connections && ($settings?.directConnections ?? null)
+				)
+			);
 		}
 		}
 	};
 	};
 
 
 	const addModelHandler = async (model) => {
 	const addModelHandler = async (model) => {
-		config.EVALUATION_ARENA_MODELS.push(model);
-		config.EVALUATION_ARENA_MODELS = [...config.EVALUATION_ARENA_MODELS];
+		evaluationConfig.EVALUATION_ARENA_MODELS.push(model);
+		evaluationConfig.EVALUATION_ARENA_MODELS = [...evaluationConfig.EVALUATION_ARENA_MODELS];
 
 
 		await submitHandler();
 		await submitHandler();
-		models.set(await getModels(localStorage.token));
+		models.set(
+			await getModels(
+				localStorage.token,
+				$config?.features?.enable_direct_connections && ($settings?.directConnections ?? null)
+			)
+		);
 	};
 	};
 
 
 	const editModelHandler = async (model, modelIdx) => {
 	const editModelHandler = async (model, modelIdx) => {
-		config.EVALUATION_ARENA_MODELS[modelIdx] = model;
-		config.EVALUATION_ARENA_MODELS = [...config.EVALUATION_ARENA_MODELS];
+		evaluationConfig.EVALUATION_ARENA_MODELS[modelIdx] = model;
+		evaluationConfig.EVALUATION_ARENA_MODELS = [...evaluationConfig.EVALUATION_ARENA_MODELS];
 
 
 		await submitHandler();
 		await submitHandler();
-		models.set(await getModels(localStorage.token));
+		models.set(
+			await getModels(
+				localStorage.token,
+				$config?.features?.enable_direct_connections && ($settings?.directConnections ?? null)
+			)
+		);
 	};
 	};
 
 
 	const deleteModelHandler = async (modelIdx) => {
 	const deleteModelHandler = async (modelIdx) => {
-		config.EVALUATION_ARENA_MODELS = config.EVALUATION_ARENA_MODELS.filter(
+		evaluationConfig.EVALUATION_ARENA_MODELS = evaluationConfig.EVALUATION_ARENA_MODELS.filter(
 			(m, mIdx) => mIdx !== modelIdx
 			(m, mIdx) => mIdx !== modelIdx
 		);
 		);
 
 
 		await submitHandler();
 		await submitHandler();
-		models.set(await getModels(localStorage.token));
+		models.set(
+			await getModels(
+				localStorage.token,
+				$config?.features?.enable_direct_connections && ($settings?.directConnections ?? null)
+			)
+		);
 	};
 	};
 
 
 	onMount(async () => {
 	onMount(async () => {
 		if ($user.role === 'admin') {
 		if ($user.role === 'admin') {
-			config = await getConfig(localStorage.token).catch((err) => {
+			evaluationConfig = await getConfig(localStorage.token).catch((err) => {
 				toast.error(err);
 				toast.error(err);
 				return null;
 				return null;
 			});
 			});
@@ -81,7 +101,7 @@
 	}}
 	}}
 >
 >
 	<div class="overflow-y-scroll scrollbar-hidden h-full">
 	<div class="overflow-y-scroll scrollbar-hidden h-full">
-		{#if config !== null}
+		{#if evaluationConfig !== null}
 			<div class="">
 			<div class="">
 				<div class="text-sm font-medium mb-2">{$i18n.t('General Settings')}</div>
 				<div class="text-sm font-medium mb-2">{$i18n.t('General Settings')}</div>
 
 
@@ -90,12 +110,12 @@
 						<div class=" text-xs font-medium">{$i18n.t('Arena Models')}</div>
 						<div class=" text-xs font-medium">{$i18n.t('Arena Models')}</div>
 
 
 						<Tooltip content={$i18n.t(`Message rating should be enabled to use this feature`)}>
 						<Tooltip content={$i18n.t(`Message rating should be enabled to use this feature`)}>
-							<Switch bind:state={config.ENABLE_EVALUATION_ARENA_MODELS} />
+							<Switch bind:state={evaluationConfig.ENABLE_EVALUATION_ARENA_MODELS} />
 						</Tooltip>
 						</Tooltip>
 					</div>
 					</div>
 				</div>
 				</div>
 
 
-				{#if config.ENABLE_EVALUATION_ARENA_MODELS}
+				{#if evaluationConfig.ENABLE_EVALUATION_ARENA_MODELS}
 					<hr class=" border-gray-50 dark:border-gray-700/10 my-2" />
 					<hr class=" border-gray-50 dark:border-gray-700/10 my-2" />
 
 
 					<div class="flex justify-between items-center mb-2">
 					<div class="flex justify-between items-center mb-2">
@@ -117,8 +137,8 @@
 					</div>
 					</div>
 
 
 					<div class="flex flex-col gap-2">
 					<div class="flex flex-col gap-2">
-						{#if (config?.EVALUATION_ARENA_MODELS ?? []).length > 0}
-							{#each config.EVALUATION_ARENA_MODELS as model, index}
+						{#if (evaluationConfig?.EVALUATION_ARENA_MODELS ?? []).length > 0}
+							{#each evaluationConfig.EVALUATION_ARENA_MODELS as model, index}
 								<Model
 								<Model
 									{model}
 									{model}
 									on:edit={(e) => {
 									on:edit={(e) => {

+ 1 - 1
src/lib/components/admin/Settings/General.svelte

@@ -144,7 +144,7 @@
 							<div class="mt-2 text-xs text-gray-400 dark:text-gray-500">
 							<div class="mt-2 text-xs text-gray-400 dark:text-gray-500">
 								<!-- https://docs.openwebui.com/getting-started/advanced-topics/api-endpoints -->
 								<!-- https://docs.openwebui.com/getting-started/advanced-topics/api-endpoints -->
 								<a
 								<a
-									href="https://docs.openwebui.com/getting-started/advanced-topics/api-endpoints"
+									href="https://docs.openwebui.com/getting-started/api-endpoints"
 									target="_blank"
 									target="_blank"
 									class=" text-gray-300 font-medium underline"
 									class=" text-gray-300 font-medium underline"
 								>
 								>

+ 20 - 4
src/lib/components/admin/Settings/Models.svelte

@@ -68,7 +68,7 @@
 
 
 	const init = async () => {
 	const init = async () => {
 		workspaceModels = await getBaseModels(localStorage.token);
 		workspaceModels = await getBaseModels(localStorage.token);
-		baseModels = await getModels(localStorage.token, true);
+		baseModels = await getModels(localStorage.token, null, true);
 
 
 		models = baseModels.map((m) => {
 		models = baseModels.map((m) => {
 			const workspaceModel = workspaceModels.find((wm) => wm.id === m.id);
 			const workspaceModel = workspaceModels.find((wm) => wm.id === m.id);
@@ -111,7 +111,12 @@
 			}
 			}
 		}
 		}
 
 
-		_models.set(await getModels(localStorage.token));
+		_models.set(
+			await getModels(
+				localStorage.token,
+				$config?.features?.enable_direct_connections && ($settings?.directConnections ?? null)
+			)
+		);
 		await init();
 		await init();
 	};
 	};
 
 
@@ -133,7 +138,12 @@
 		}
 		}
 
 
 		// await init();
 		// await init();
-		_models.set(await getModels(localStorage.token));
+		_models.set(
+			await getModels(
+				localStorage.token,
+				$config?.features?.enable_direct_connections && ($settings?.directConnections ?? null)
+			)
+		);
 	};
 	};
 
 
 	onMount(async () => {
 	onMount(async () => {
@@ -330,7 +340,13 @@
 									}
 									}
 								}
 								}
 
 
-								await _models.set(await getModels(localStorage.token));
+								await _models.set(
+									await getModels(
+										localStorage.token,
+										$config?.features?.enable_direct_connections &&
+											($settings?.directConnections ?? null)
+									)
+								);
 								init();
 								init();
 							};
 							};
 
 

+ 25 - 5
src/lib/components/admin/Settings/Models/Manage/ManageOllama.svelte

@@ -3,7 +3,7 @@
 	import { getContext, onMount } from 'svelte';
 	import { getContext, onMount } from 'svelte';
 	const i18n = getContext('i18n');
 	const i18n = getContext('i18n');
 
 
-	import { WEBUI_NAME, models, MODEL_DOWNLOAD_POOL, user, config } from '$lib/stores';
+	import { WEBUI_NAME, models, MODEL_DOWNLOAD_POOL, user, config, settings } from '$lib/stores';
 	import { splitStream } from '$lib/utils';
 	import { splitStream } from '$lib/utils';
 
 
 	import {
 	import {
@@ -235,7 +235,12 @@
 					})
 					})
 				);
 				);
 
 
-				models.set(await getModels(localStorage.token));
+				models.set(
+					await getModels(
+						localStorage.token,
+						$config?.features?.enable_direct_connections && ($settings?.directConnections ?? null)
+					)
+				);
 			} else {
 			} else {
 				toast.error($i18n.t('Download canceled'));
 				toast.error($i18n.t('Download canceled'));
 			}
 			}
@@ -394,7 +399,12 @@
 		modelTransferring = false;
 		modelTransferring = false;
 		uploadProgress = null;
 		uploadProgress = null;
 
 
-		models.set(await getModels(localStorage.token));
+		models.set(
+			await getModels(
+				localStorage.token,
+				$config?.features?.enable_direct_connections && ($settings?.directConnections ?? null)
+			)
+		);
 	};
 	};
 
 
 	const deleteModelHandler = async () => {
 	const deleteModelHandler = async () => {
@@ -407,7 +417,12 @@
 		}
 		}
 
 
 		deleteModelTag = '';
 		deleteModelTag = '';
-		models.set(await getModels(localStorage.token));
+		models.set(
+			await getModels(
+				localStorage.token,
+				$config?.features?.enable_direct_connections && ($settings?.directConnections ?? null)
+			)
+		);
 	};
 	};
 
 
 	const cancelModelPullHandler = async (model: string) => {
 	const cancelModelPullHandler = async (model: string) => {
@@ -506,7 +521,12 @@
 			}
 			}
 		}
 		}
 
 
-		models.set(await getModels(localStorage.token));
+		models.set(
+			await getModels(
+				localStorage.token,
+				$config?.features?.enable_direct_connections && ($settings?.directConnections ?? null)
+			)
+		);
 
 
 		createModelLoading = false;
 		createModelLoading = false;
 
 

+ 25 - 5
src/lib/components/admin/Settings/Pipelines.svelte

@@ -2,7 +2,7 @@
 	import { v4 as uuidv4 } from 'uuid';
 	import { v4 as uuidv4 } from 'uuid';
 
 
 	import { toast } from 'svelte-sonner';
 	import { toast } from 'svelte-sonner';
-	import { models } from '$lib/stores';
+	import { config, models, settings } from '$lib/stores';
 	import { getContext, onMount, tick } from 'svelte';
 	import { getContext, onMount, tick } from 'svelte';
 	import type { Writable } from 'svelte/store';
 	import type { Writable } from 'svelte/store';
 	import type { i18n as i18nType } from 'i18next';
 	import type { i18n as i18nType } from 'i18next';
@@ -63,7 +63,12 @@
 			if (res) {
 			if (res) {
 				toast.success($i18n.t('Valves updated successfully'));
 				toast.success($i18n.t('Valves updated successfully'));
 				setPipelines();
 				setPipelines();
-				models.set(await getModels(localStorage.token));
+				models.set(
+					await getModels(
+						localStorage.token,
+						$config?.features?.enable_direct_connections && ($settings?.directConnections ?? null)
+					)
+				);
 				saveHandler();
 				saveHandler();
 			}
 			}
 		} else {
 		} else {
@@ -125,7 +130,12 @@
 		if (res) {
 		if (res) {
 			toast.success($i18n.t('Pipeline downloaded successfully'));
 			toast.success($i18n.t('Pipeline downloaded successfully'));
 			setPipelines();
 			setPipelines();
-			models.set(await getModels(localStorage.token));
+			models.set(
+				await getModels(
+					localStorage.token,
+					$config?.features?.enable_direct_connections && ($settings?.directConnections ?? null)
+				)
+			);
 		}
 		}
 
 
 		downloading = false;
 		downloading = false;
@@ -150,7 +160,12 @@
 			if (res) {
 			if (res) {
 				toast.success($i18n.t('Pipeline downloaded successfully'));
 				toast.success($i18n.t('Pipeline downloaded successfully'));
 				setPipelines();
 				setPipelines();
-				models.set(await getModels(localStorage.token));
+				models.set(
+					await getModels(
+						localStorage.token,
+						$config?.features?.enable_direct_connections && ($settings?.directConnections ?? null)
+					)
+				);
 			}
 			}
 		} else {
 		} else {
 			toast.error($i18n.t('No file selected'));
 			toast.error($i18n.t('No file selected'));
@@ -179,7 +194,12 @@
 		if (res) {
 		if (res) {
 			toast.success($i18n.t('Pipeline deleted successfully'));
 			toast.success($i18n.t('Pipeline deleted successfully'));
 			setPipelines();
 			setPipelines();
-			models.set(await getModels(localStorage.token));
+			models.set(
+				await getModels(
+					localStorage.token,
+					$config?.features?.enable_direct_connections && ($settings?.directConnections ?? null)
+				)
+			);
 		}
 		}
 	};
 	};
 
 

+ 42 - 0
src/lib/components/admin/Settings/WebSearch.svelte

@@ -18,6 +18,7 @@
 		'brave',
 		'brave',
 		'kagi',
 		'kagi',
 		'mojeek',
 		'mojeek',
+		'bocha',
 		'serpstack',
 		'serpstack',
 		'serper',
 		'serper',
 		'serply',
 		'serply',
@@ -34,6 +35,16 @@
 	let youtubeProxyUrl = '';
 	let youtubeProxyUrl = '';
 
 
 	const submitHandler = async () => {
 	const submitHandler = async () => {
+		// Convert domain filter string to array before sending
+		if (webConfig.search.domain_filter_list) {
+			webConfig.search.domain_filter_list = webConfig.search.domain_filter_list
+				.split(',')
+				.map((domain) => domain.trim())
+				.filter((domain) => domain.length > 0);
+		} else {
+			webConfig.search.domain_filter_list = [];
+		}
+
 		const res = await updateRAGConfig(localStorage.token, {
 		const res = await updateRAGConfig(localStorage.token, {
 			web: webConfig,
 			web: webConfig,
 			youtube: {
 			youtube: {
@@ -42,6 +53,8 @@
 				proxy_url: youtubeProxyUrl
 				proxy_url: youtubeProxyUrl
 			}
 			}
 		});
 		});
+
+		webConfig.search.domain_filter_list = webConfig.search.domain_filter_list.join(', ');
 	};
 	};
 
 
 	onMount(async () => {
 	onMount(async () => {
@@ -49,6 +62,10 @@
 
 
 		if (res) {
 		if (res) {
 			webConfig = res.web;
 			webConfig = res.web;
+			// Convert array back to comma-separated string for display
+			if (webConfig?.search?.domain_filter_list) {
+				webConfig.search.domain_filter_list = webConfig.search.domain_filter_list.join(', ');
+			}
 
 
 			youtubeLanguage = res.youtube.language.join(',');
 			youtubeLanguage = res.youtube.language.join(',');
 			youtubeTranslation = res.youtube.translation;
 			youtubeTranslation = res.youtube.translation;
@@ -179,6 +196,17 @@
 									bind:value={webConfig.search.mojeek_search_api_key}
 									bind:value={webConfig.search.mojeek_search_api_key}
 								/>
 								/>
 							</div>
 							</div>
+						{:else if webConfig.search.engine === 'bocha'}
+							<div>
+								<div class=" self-center text-xs font-medium mb-1">
+									{$i18n.t('Bocha Search API Key')}
+								</div>
+
+								<SensitiveInput
+									placeholder={$i18n.t('Enter Bocha Search API Key')}
+									bind:value={webConfig.search.bocha_search_api_key}
+								/>
+							</div>
 						{:else if webConfig.search.engine === 'serpstack'}
 						{:else if webConfig.search.engine === 'serpstack'}
 							<div>
 							<div>
 								<div class=" self-center text-xs font-medium mb-1">
 								<div class=" self-center text-xs font-medium mb-1">
@@ -334,6 +362,20 @@
 							/>
 							/>
 						</div>
 						</div>
 					</div>
 					</div>
+
+					<div class="mt-2">
+						<div class=" self-center text-xs font-medium mb-1">
+							{$i18n.t('Domain Filter List')}
+						</div>
+
+						<input
+							class="w-full rounded-lg py-2 px-4 text-sm bg-gray-50 dark:text-gray-300 dark:bg-gray-850 outline-none"
+							placeholder={$i18n.t(
+								'Enter domains separated by commas (e.g., example.com,site.org)'
+							)}
+							bind:value={webConfig.search.domain_filter_list}
+						/>
+					</div>
 				{/if}
 				{/if}
 			</div>
 			</div>
 
 

+ 15 - 9
src/lib/components/chat/Chat.svelte

@@ -838,6 +838,7 @@
 				timestamp: m.timestamp,
 				timestamp: m.timestamp,
 				...(m.sources ? { sources: m.sources } : {})
 				...(m.sources ? { sources: m.sources } : {})
 			})),
 			})),
+			model_item: $models.find((m) => m.id === modelId),
 			chat_id: chatId,
 			chat_id: chatId,
 			session_id: $socket?.id,
 			session_id: $socket?.id,
 			id: responseMessageId
 			id: responseMessageId
@@ -896,6 +897,7 @@
 				...(m.sources ? { sources: m.sources } : {})
 				...(m.sources ? { sources: m.sources } : {})
 			})),
 			})),
 			...(event ? { event: event } : {}),
 			...(event ? { event: event } : {}),
+			model_item: $models.find((m) => m.id === modelId),
 			chat_id: chatId,
 			chat_id: chatId,
 			session_id: $socket?.id,
 			session_id: $socket?.id,
 			id: responseMessageId
 			id: responseMessageId
@@ -1226,7 +1228,7 @@
 			selectedModels = _selectedModels;
 			selectedModels = _selectedModels;
 		}
 		}
 
 
-		if (userPrompt === '') {
+		if (userPrompt === '' && files.length === 0) {
 			toast.error($i18n.t('Please enter a prompt'));
 			toast.error($i18n.t('Please enter a prompt'));
 			return;
 			return;
 		}
 		}
@@ -1478,7 +1480,7 @@
 			params?.stream_response ??
 			params?.stream_response ??
 			true;
 			true;
 
 
-		const messages = [
+		let messages = [
 			params?.system || $settings.system || (responseMessage?.userContext ?? null)
 			params?.system || $settings.system || (responseMessage?.userContext ?? null)
 				? {
 				? {
 						role: 'system',
 						role: 'system',
@@ -1499,8 +1501,9 @@
 				...message,
 				...message,
 				content: removeDetails(message.content, ['reasoning', 'code_interpreter'])
 				content: removeDetails(message.content, ['reasoning', 'code_interpreter'])
 			}))
 			}))
-		]
-			.filter((message) => message?.content?.trim())
+		].filter((message) => message);
+
+		messages = messages
 			.map((message, idx, arr) => ({
 			.map((message, idx, arr) => ({
 				role: message.role,
 				role: message.role,
 				...((message.files?.filter((file) => file.type === 'image').length > 0 ?? false) &&
 				...((message.files?.filter((file) => file.type === 'image').length > 0 ?? false) &&
@@ -1524,7 +1527,8 @@
 					: {
 					: {
 							content: message?.merged?.content ?? message.content
 							content: message?.merged?.content ?? message.content
 						})
 						})
-			}));
+			}))
+			.filter((message) => message?.role === 'user' || message?.content?.trim());
 
 
 		const res = await generateOpenAIChatCompletion(
 		const res = await generateOpenAIChatCompletion(
 			localStorage.token,
 			localStorage.token,
@@ -1556,7 +1560,8 @@
 							? imageGenerationEnabled
 							? imageGenerationEnabled
 							: false,
 							: false,
 					code_interpreter:
 					code_interpreter:
-						$user.role === 'admin' || $user?.permissions?.features?.code_interpreter
+						$config?.features?.enable_code_interpreter &&
+						($user.role === 'admin' || $user?.permissions?.features?.code_interpreter)
 							? codeInterpreterEnabled
 							? codeInterpreterEnabled
 							: false,
 							: false,
 					web_search:
 					web_search:
@@ -1571,6 +1576,7 @@
 						$settings?.userLocation ? await getAndUpdateUserLocation(localStorage.token) : undefined
 						$settings?.userLocation ? await getAndUpdateUserLocation(localStorage.token) : undefined
 					)
 					)
 				},
 				},
+				model_item: $models.find((m) => m.id === model.id),
 
 
 				session_id: $socket?.id,
 				session_id: $socket?.id,
 				chat_id: $chatId,
 				chat_id: $chatId,
@@ -1581,7 +1587,7 @@
 					(messages.length == 2 &&
 					(messages.length == 2 &&
 						messages.at(0)?.role === 'system' &&
 						messages.at(0)?.role === 'system' &&
 						messages.at(1)?.role === 'user')) &&
 						messages.at(1)?.role === 'user')) &&
-				selectedModels[0] === model.id
+				(selectedModels[0] === model.id || atSelectedModel !== undefined)
 					? {
 					? {
 							background_tasks: {
 							background_tasks: {
 								title_generation: $settings?.title?.auto ?? true,
 								title_generation: $settings?.title?.auto ?? true,
@@ -2006,7 +2012,7 @@
 									}
 									}
 								}}
 								}}
 								on:submit={async (e) => {
 								on:submit={async (e) => {
-									if (e.detail) {
+									if (e.detail || files.length > 0) {
 										await tick();
 										await tick();
 										submitPrompt(
 										submitPrompt(
 											($settings?.richTextInput ?? true)
 											($settings?.richTextInput ?? true)
@@ -2049,7 +2055,7 @@
 									}
 									}
 								}}
 								}}
 								on:submit={async (e) => {
 								on:submit={async (e) => {
-									if (e.detail) {
+									if (e.detail || files.length > 0) {
 										await tick();
 										await tick();
 										submitPrompt(
 										submitPrompt(
 											($settings?.richTextInput ?? true)
 											($settings?.richTextInput ?? true)

+ 19 - 7
src/lib/components/chat/MessageInput.svelte

@@ -16,7 +16,8 @@
 		showCallOverlay,
 		showCallOverlay,
 		tools,
 		tools,
 		user as _user,
 		user as _user,
-		showControls
+		showControls,
+		TTSWorker
 	} from '$lib/stores';
 	} from '$lib/stores';
 
 
 	import { blobToFile, compressImage, createMessagesList, findWordIndices } from '$lib/utils';
 	import { blobToFile, compressImage, createMessagesList, findWordIndices } from '$lib/utils';
@@ -43,6 +44,7 @@
 	import PhotoSolid from '../icons/PhotoSolid.svelte';
 	import PhotoSolid from '../icons/PhotoSolid.svelte';
 	import Photo from '../icons/Photo.svelte';
 	import Photo from '../icons/Photo.svelte';
 	import CommandLine from '../icons/CommandLine.svelte';
 	import CommandLine from '../icons/CommandLine.svelte';
+	import { KokoroWorker } from '$lib/workers/KokoroWorker';
 
 
 	const i18n = getContext('i18n');
 	const i18n = getContext('i18n');
 
 
@@ -638,7 +640,7 @@
 																xmlns="http://www.w3.org/2000/svg"
 																xmlns="http://www.w3.org/2000/svg"
 																viewBox="0 0 20 20"
 																viewBox="0 0 20 20"
 																fill="currentColor"
 																fill="currentColor"
-																class="w-4 h-4"
+																class="size-4"
 															>
 															>
 																<path
 																<path
 																	d="M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z"
 																	d="M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z"
@@ -695,7 +697,7 @@
 													)}
 													)}
 												placeholder={placeholder ? placeholder : $i18n.t('Send a Message')}
 												placeholder={placeholder ? placeholder : $i18n.t('Send a Message')}
 												largeTextAsFile={$settings?.largeTextAsFile ?? false}
 												largeTextAsFile={$settings?.largeTextAsFile ?? false}
-												autocomplete={true}
+												autocomplete={$config?.features.enable_autocomplete_generation}
 												generateAutoCompletion={async (text) => {
 												generateAutoCompletion={async (text) => {
 													if (selectedModelIds.length === 0 || !selectedModelIds.at(0)) {
 													if (selectedModelIds.length === 0 || !selectedModelIds.at(0)) {
 														toast.error($i18n.t('Please select a model first.'));
 														toast.error($i18n.t('Please select a model first.'));
@@ -1169,7 +1171,7 @@
 													</Tooltip>
 													</Tooltip>
 												{/if}
 												{/if}
 
 
-												{#if $_user.role === 'admin' || $_user?.permissions?.features?.code_interpreter}
+												{#if $config?.features?.enable_code_interpreter && ($_user.role === 'admin' || $_user?.permissions?.features?.code_interpreter)}
 													<Tooltip content={$i18n.t('Execute code for analysis')} placement="top">
 													<Tooltip content={$i18n.t('Execute code for analysis')} placement="top">
 														<button
 														<button
 															on:click|preventDefault={() =>
 															on:click|preventDefault={() =>
@@ -1242,7 +1244,7 @@
 										{/if}
 										{/if}
 
 
 										{#if !history.currentId || history.messages[history.currentId]?.done == true}
 										{#if !history.currentId || history.messages[history.currentId]?.done == true}
-											{#if prompt === ''}
+											{#if prompt === '' && files.length === 0}
 												<div class=" flex items-center">
 												<div class=" flex items-center">
 													<Tooltip content={$i18n.t('Call')}>
 													<Tooltip content={$i18n.t('Call')}>
 														<button
 														<button
@@ -1281,6 +1283,16 @@
 
 
 																	stream = null;
 																	stream = null;
 
 
+																	if (!$TTSWorker) {
+																		await TTSWorker.set(
+																			new KokoroWorker({
+																				dtype: $settings.audio?.tts?.engineConfig?.dtype ?? 'fp32'
+																			})
+																		);
+
+																		await $TTSWorker.init();
+																	}
+
 																	showCallOverlay.set(true);
 																	showCallOverlay.set(true);
 																	showControls.set(true);
 																	showControls.set(true);
 																} catch (err) {
 																} catch (err) {
@@ -1301,13 +1313,13 @@
 													<Tooltip content={$i18n.t('Send message')}>
 													<Tooltip content={$i18n.t('Send message')}>
 														<button
 														<button
 															id="send-message-button"
 															id="send-message-button"
-															class="{prompt !== ''
+															class="{!(prompt === '' && files.length === 0)
 																? webSearchEnabled || ($settings?.webSearch ?? false) === 'always'
 																? webSearchEnabled || ($settings?.webSearch ?? false) === 'always'
 																	? 'bg-blue-500 text-white hover:bg-blue-400 '
 																	? 'bg-blue-500 text-white hover:bg-blue-400 '
 																	: 'bg-black text-white hover:bg-gray-900 dark:bg-white dark:text-black dark:hover:bg-gray-100 '
 																	: 'bg-black text-white hover:bg-gray-900 dark:bg-white dark:text-black dark:hover:bg-gray-100 '
 																: 'text-white bg-gray-200 dark:text-gray-900 dark:bg-gray-700 disabled'} transition rounded-full p-1.5 self-center"
 																: 'text-white bg-gray-200 dark:text-gray-900 dark:bg-gray-700 disabled'} transition rounded-full p-1.5 self-center"
 															type="submit"
 															type="submit"
-															disabled={prompt === ''}
+															disabled={prompt === '' && files.length === 0}
 														>
 														>
 															<svg
 															<svg
 																xmlns="http://www.w3.org/2000/svg"
 																xmlns="http://www.w3.org/2000/svg"

+ 17 - 2
src/lib/components/chat/MessageInput/CallOverlay.svelte

@@ -1,5 +1,5 @@
 <script lang="ts">
 <script lang="ts">
-	import { config, models, settings, showCallOverlay } from '$lib/stores';
+	import { config, models, settings, showCallOverlay, TTSWorker } from '$lib/stores';
 	import { onMount, tick, getContext, onDestroy, createEventDispatcher } from 'svelte';
 	import { onMount, tick, getContext, onDestroy, createEventDispatcher } from 'svelte';
 
 
 	const dispatch = createEventDispatcher();
 	const dispatch = createEventDispatcher();
@@ -12,6 +12,7 @@
 
 
 	import Tooltip from '$lib/components/common/Tooltip.svelte';
 	import Tooltip from '$lib/components/common/Tooltip.svelte';
 	import VideoInputMenu from './CallOverlay/VideoInputMenu.svelte';
 	import VideoInputMenu from './CallOverlay/VideoInputMenu.svelte';
+	import { KokoroWorker } from '$lib/workers/KokoroWorker';
 
 
 	const i18n = getContext('i18n');
 	const i18n = getContext('i18n');
 
 
@@ -459,7 +460,21 @@
 					}
 					}
 				}
 				}
 
 
-				if ($config.audio.tts.engine !== '') {
+				if ($settings.audio?.tts?.engine === 'browser-kokoro') {
+					const blob = await $TTSWorker
+						.generate({
+							text: content,
+							voice: $settings?.audio?.tts?.voice ?? $config?.audio?.tts?.voice
+						})
+						.catch((error) => {
+							console.error(error);
+							toast.error(`${error}`);
+						});
+
+					if (blob) {
+						audioCache.set(content, new Audio(blob));
+					}
+				} else if ($config.audio.tts.engine !== '') {
 					const res = await synthesizeOpenAISpeech(
 					const res = await synthesizeOpenAISpeech(
 						localStorage.token,
 						localStorage.token,
 						$settings?.audio?.tts?.defaultVoice === $config.audio.tts.voice
 						$settings?.audio?.tts?.defaultVoice === $config.audio.tts.voice

+ 22 - 12
src/lib/components/chat/Messages/Citations.svelte

@@ -97,10 +97,10 @@
 {#if citations.length > 0}
 {#if citations.length > 0}
 	<div class=" py-0.5 -mx-0.5 w-full flex gap-1 items-center flex-wrap">
 	<div class=" py-0.5 -mx-0.5 w-full flex gap-1 items-center flex-wrap">
 		{#if citations.length <= 3}
 		{#if citations.length <= 3}
-			<div class="flex text-xs font-medium">
+			<div class="flex text-xs font-medium flex-wrap">
 				{#each citations as citation, idx}
 				{#each citations as citation, idx}
 					<button
 					<button
-						id={`source-${citation.source.name}`}
+						id={`source-${idx}`}
 						class="no-toggle outline-none flex dark:text-gray-300 p-1 bg-white dark:bg-gray-900 rounded-xl max-w-96"
 						class="no-toggle outline-none flex dark:text-gray-300 p-1 bg-white dark:bg-gray-900 rounded-xl max-w-96"
 						on:click={() => {
 						on:click={() => {
 							showCitationModal = true;
 							showCitationModal = true;
@@ -113,7 +113,7 @@
 							</div>
 							</div>
 						{/if}
 						{/if}
 						<div
 						<div
-							class="flex-1 mx-1 line-clamp-1 text-black/60 hover:text-black dark:text-white/60 dark:hover:text-white transition"
+							class="flex-1 mx-1 truncate text-black/60 hover:text-black dark:text-white/60 dark:hover:text-white transition"
 						>
 						>
 							{citation.source.name}
 							{citation.source.name}
 						</div>
 						</div>
@@ -121,13 +121,22 @@
 				{/each}
 				{/each}
 			</div>
 			</div>
 		{:else}
 		{:else}
-			<Collapsible bind:open={isCollapsibleOpen} className="w-full">
+			<Collapsible
+				id="collapsible-sources"
+				bind:open={isCollapsibleOpen}
+				className="w-full max-w-full "
+				buttonClassName="w-fit max-w-full"
+			>
 				<div
 				<div
-					class="flex items-center gap-2 text-gray-500 hover:text-gray-600 dark:hover:text-gray-400 transition cursor-pointer"
+					class="flex w-full overflow-auto items-center gap-2 text-gray-500 hover:text-gray-600 dark:hover:text-gray-400 transition cursor-pointer"
 				>
 				>
-					<div class="flex-grow flex items-center gap-1 overflow-hidden">
-						<span class="whitespace-nowrap hidden sm:inline">{$i18n.t('References from')}</span>
-						<div class="flex items-center">
+					<div
+						class="flex-1 flex items-center gap-1 overflow-auto scrollbar-none w-full max-w-full"
+					>
+						<span class="whitespace-nowrap hidden sm:inline flex-shrink-0"
+							>{$i18n.t('References from')}</span
+						>
+						<div class="flex items-center overflow-auto scrollbar-none w-full max-w-full flex-1">
 							<div class="flex text-xs font-medium items-center">
 							<div class="flex text-xs font-medium items-center">
 								{#each citations.slice(0, 2) as citation, idx}
 								{#each citations.slice(0, 2) as citation, idx}
 									<button
 									<button
@@ -145,14 +154,14 @@
 												{idx + 1}
 												{idx + 1}
 											</div>
 											</div>
 										{/if}
 										{/if}
-										<div class="flex-1 mx-1 line-clamp-1 truncate">
+										<div class="flex-1 mx-1 truncate">
 											{citation.source.name}
 											{citation.source.name}
 										</div>
 										</div>
 									</button>
 									</button>
 								{/each}
 								{/each}
 							</div>
 							</div>
 						</div>
 						</div>
-						<div class="flex items-center gap-1 whitespace-nowrap">
+						<div class="flex items-center gap-1 whitespace-nowrap flex-shrink-0">
 							<span class="hidden sm:inline">{$i18n.t('and')}</span>
 							<span class="hidden sm:inline">{$i18n.t('and')}</span>
 							{citations.length - 2}
 							{citations.length - 2}
 							<span>{$i18n.t('more')}</span>
 							<span>{$i18n.t('more')}</span>
@@ -167,9 +176,10 @@
 					</div>
 					</div>
 				</div>
 				</div>
 				<div slot="content">
 				<div slot="content">
-					<div class="flex text-xs font-medium">
+					<div class="flex text-xs font-medium flex-wrap">
 						{#each citations as citation, idx}
 						{#each citations as citation, idx}
 							<button
 							<button
+								id={`source-${idx}`}
 								class="no-toggle outline-none flex dark:text-gray-300 p-1 bg-gray-50 hover:bg-gray-100 dark:bg-gray-900 dark:hover:bg-gray-850 transition rounded-xl max-w-96"
 								class="no-toggle outline-none flex dark:text-gray-300 p-1 bg-gray-50 hover:bg-gray-100 dark:bg-gray-900 dark:hover:bg-gray-850 transition rounded-xl max-w-96"
 								on:click={() => {
 								on:click={() => {
 									showCitationModal = true;
 									showCitationModal = true;
@@ -181,7 +191,7 @@
 										{idx + 1}
 										{idx + 1}
 									</div>
 									</div>
 								{/if}
 								{/if}
-								<div class="flex-1 mx-1 line-clamp-1 truncate">
+								<div class="flex-1 mx-1 truncate">
 									{citation.source.name}
 									{citation.source.name}
 								</div>
 								</div>
 							</button>
 							</button>

+ 17 - 2
src/lib/components/chat/Messages/CodeBlock.svelte

@@ -5,7 +5,14 @@
 
 
 	import { v4 as uuidv4 } from 'uuid';
 	import { v4 as uuidv4 } from 'uuid';
 
 
-	import { getContext, getAllContexts, onMount, tick, createEventDispatcher } from 'svelte';
+	import {
+		getContext,
+		getAllContexts,
+		onMount,
+		tick,
+		createEventDispatcher,
+		onDestroy
+	} from 'svelte';
 	import { copyToClipboard } from '$lib/utils';
 	import { copyToClipboard } from '$lib/utils';
 
 
 	import 'highlight.js/styles/github-dark.min.css';
 	import 'highlight.js/styles/github-dark.min.css';
@@ -31,6 +38,8 @@
 	export let editorClassName = '';
 	export let editorClassName = '';
 	export let stickyButtonsClassName = 'top-8';
 	export let stickyButtonsClassName = 'top-8';
 
 
+	let pyodideWorker = null;
+
 	let _code = '';
 	let _code = '';
 	$: if (code) {
 	$: if (code) {
 		updateCode();
 		updateCode();
@@ -138,7 +147,7 @@
 
 
 		console.log(packages);
 		console.log(packages);
 
 
-		const pyodideWorker = new PyodideWorker();
+		pyodideWorker = new PyodideWorker();
 
 
 		pyodideWorker.postMessage({
 		pyodideWorker.postMessage({
 			id: id,
 			id: id,
@@ -280,6 +289,12 @@
 			});
 			});
 		}
 		}
 	});
 	});
+
+	onDestroy(() => {
+		if (pyodideWorker) {
+			pyodideWorker.terminate();
+		}
+	});
 </script>
 </script>
 
 
 <div>
 <div>

+ 16 - 9
src/lib/components/chat/Messages/Markdown/Source.svelte

@@ -2,24 +2,31 @@
 	export let token;
 	export let token;
 	export let onClick: Function = () => {};
 	export let onClick: Function = () => {};
 
 
-	let id = '';
-	function extractDataAttribute(input) {
-		// Use a regular expression to extract the value of the `data` attribute
-		const match = input.match(/data="([^"]*)"/);
-		// Check if a match was found and return the first captured group
-		return match ? match[1] : null;
+	let attributes: Record<string, string> = {};
+
+	function extractAttributes(input: string): Record<string, string> {
+		const regex = /(\w+)="([^"]*)"/g;
+		let match;
+		let attrs: Record<string, string> = {};
+
+		// Loop through all matches and populate the attributes object
+		while ((match = regex.exec(input)) !== null) {
+			attrs[match[1]] = match[2];
+		}
+
+		return attrs;
 	}
 	}
 
 
-	$: id = extractDataAttribute(token.text);
+	$: attributes = extractAttributes(token.text);
 </script>
 </script>
 
 
 <button
 <button
 	class="text-xs font-medium w-fit translate-y-[2px] px-2 py-0.5 dark:bg-white/5 dark:text-white/60 dark:hover:text-white bg-gray-50 text-black/60 hover:text-black transition rounded-lg"
 	class="text-xs font-medium w-fit translate-y-[2px] px-2 py-0.5 dark:bg-white/5 dark:text-white/60 dark:hover:text-white bg-gray-50 text-black/60 hover:text-black transition rounded-lg"
 	on:click={() => {
 	on:click={() => {
-		onClick(id);
+		onClick(attributes.data);
 	}}
 	}}
 >
 >
 	<span class="line-clamp-1">
 	<span class="line-clamp-1">
-		{id}
+		{attributes.title}
 	</span>
 	</span>
 </button>
 </button>

+ 117 - 63
src/lib/components/chat/Messages/ResponseMessage.svelte

@@ -4,12 +4,18 @@
 
 
 	import { createEventDispatcher } from 'svelte';
 	import { createEventDispatcher } from 'svelte';
 	import { onMount, tick, getContext } from 'svelte';
 	import { onMount, tick, getContext } from 'svelte';
+	import type { Writable } from 'svelte/store';
+	import type { i18n as i18nType } from 'i18next';
 
 
 	const i18n = getContext<Writable<i18nType>>('i18n');
 	const i18n = getContext<Writable<i18nType>>('i18n');
 
 
 	const dispatch = createEventDispatcher();
 	const dispatch = createEventDispatcher();
 
 
-	import { config, models, settings, user } from '$lib/stores';
+	import { createNewFeedback, getFeedbackById, updateFeedbackById } from '$lib/apis/evaluations';
+	import { getChatById } from '$lib/apis/chats';
+	import { generateTags } from '$lib/apis';
+
+	import { config, models, settings, TTSWorker, user } from '$lib/stores';
 	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 {
@@ -34,13 +40,8 @@
 	import Error from './Error.svelte';
 	import Error from './Error.svelte';
 	import Citations from './Citations.svelte';
 	import Citations from './Citations.svelte';
 	import CodeExecutions from './CodeExecutions.svelte';
 	import CodeExecutions from './CodeExecutions.svelte';
-
-	import type { Writable } from 'svelte/store';
-	import type { i18n as i18nType } from 'i18next';
 	import ContentRenderer from './ContentRenderer.svelte';
 	import ContentRenderer from './ContentRenderer.svelte';
-	import { createNewFeedback, getFeedbackById, updateFeedbackById } from '$lib/apis/evaluations';
-	import { getChatById } from '$lib/apis/chats';
-	import { generateTags } from '$lib/apis';
+	import { KokoroWorker } from '$lib/workers/KokoroWorker';
 
 
 	interface MessageType {
 	interface MessageType {
 		id: string;
 		id: string;
@@ -193,7 +194,42 @@
 
 
 		speaking = true;
 		speaking = true;
 
 
-		if ($config.audio.tts.engine !== '') {
+		if ($config.audio.tts.engine === '') {
+			let voices = [];
+			const getVoicesLoop = setInterval(() => {
+				voices = speechSynthesis.getVoices();
+				if (voices.length > 0) {
+					clearInterval(getVoicesLoop);
+
+					const voice =
+						voices
+							?.filter(
+								(v) => v.voiceURI === ($settings?.audio?.tts?.voice ?? $config?.audio?.tts?.voice)
+							)
+							?.at(0) ?? undefined;
+
+					console.log(voice);
+
+					const speak = new SpeechSynthesisUtterance(message.content);
+					speak.rate = $settings.audio?.tts?.playbackRate ?? 1;
+
+					console.log(speak);
+
+					speak.onend = () => {
+						speaking = false;
+						if ($settings.conversationMode) {
+							document.getElementById('voice-input-button')?.click();
+						}
+					};
+
+					if (voice) {
+						speak.voice = voice;
+					}
+
+					speechSynthesis.speak(speak);
+				}
+			}, 100);
+		} else {
 			loadingSpeech = true;
 			loadingSpeech = true;
 
 
 			const messageContentParts: string[] = getMessageContentParts(
 			const messageContentParts: string[] = getMessageContentParts(
@@ -222,67 +258,68 @@
 
 
 			let lastPlayedAudioPromise = Promise.resolve(); // Initialize a promise that resolves immediately
 			let lastPlayedAudioPromise = Promise.resolve(); // Initialize a promise that resolves immediately
 
 
-			for (const [idx, sentence] of messageContentParts.entries()) {
-				const res = await synthesizeOpenAISpeech(
-					localStorage.token,
-					$settings?.audio?.tts?.defaultVoice === $config.audio.tts.voice
-						? ($settings?.audio?.tts?.voice ?? $config?.audio?.tts?.voice)
-						: $config?.audio?.tts?.voice,
-					sentence
-				).catch((error) => {
-					console.error(error);
-					toast.error(`${error}`);
+			if ($settings.audio?.tts?.engine === 'browser-kokoro') {
+				if (!$TTSWorker) {
+					await TTSWorker.set(
+						new KokoroWorker({
+							dtype: $settings.audio?.tts?.engineConfig?.dtype ?? 'fp32'
+						})
+					);
 
 
-					speaking = false;
-					loadingSpeech = false;
-				});
-
-				if (res) {
-					const blob = await res.blob();
-					const blobUrl = URL.createObjectURL(blob);
-					const audio = new Audio(blobUrl);
-					audio.playbackRate = $settings.audio?.tts?.playbackRate ?? 1;
-
-					audioParts[idx] = audio;
-					loadingSpeech = false;
-					lastPlayedAudioPromise = lastPlayedAudioPromise.then(() => playAudio(idx));
+					await $TTSWorker.init();
 				}
 				}
-			}
-		} else {
-			let voices = [];
-			const getVoicesLoop = setInterval(() => {
-				voices = speechSynthesis.getVoices();
-				if (voices.length > 0) {
-					clearInterval(getVoicesLoop);
 
 
-					const voice =
-						voices
-							?.filter(
-								(v) => v.voiceURI === ($settings?.audio?.tts?.voice ?? $config?.audio?.tts?.voice)
-							)
-							?.at(0) ?? undefined;
-
-					console.log(voice);
-
-					const speak = new SpeechSynthesisUtterance(message.content);
-					speak.rate = $settings.audio?.tts?.playbackRate ?? 1;
-
-					console.log(speak);
+				for (const [idx, sentence] of messageContentParts.entries()) {
+					const blob = await $TTSWorker
+						.generate({
+							text: sentence,
+							voice: $settings?.audio?.tts?.voice ?? $config?.audio?.tts?.voice
+						})
+						.catch((error) => {
+							console.error(error);
+							toast.error(`${error}`);
+
+							speaking = false;
+							loadingSpeech = false;
+						});
+
+					if (blob) {
+						const audio = new Audio(blob);
+						audio.playbackRate = $settings.audio?.tts?.playbackRate ?? 1;
+
+						audioParts[idx] = audio;
+						loadingSpeech = false;
+						lastPlayedAudioPromise = lastPlayedAudioPromise.then(() => playAudio(idx));
+					}
+				}
+			} else {
+				for (const [idx, sentence] of messageContentParts.entries()) {
+					const res = await synthesizeOpenAISpeech(
+						localStorage.token,
+						$settings?.audio?.tts?.defaultVoice === $config.audio.tts.voice
+							? ($settings?.audio?.tts?.voice ?? $config?.audio?.tts?.voice)
+							: $config?.audio?.tts?.voice,
+						sentence
+					).catch((error) => {
+						console.error(error);
+						toast.error(`${error}`);
 
 
-					speak.onend = () => {
 						speaking = false;
 						speaking = false;
-						if ($settings.conversationMode) {
-							document.getElementById('voice-input-button')?.click();
-						}
-					};
+						loadingSpeech = false;
+					});
 
 
-					if (voice) {
-						speak.voice = voice;
-					}
+					if (res) {
+						const blob = await res.blob();
+						const blobUrl = URL.createObjectURL(blob);
+						const audio = new Audio(blobUrl);
+						audio.playbackRate = $settings.audio?.tts?.playbackRate ?? 1;
 
 
-					speechSynthesis.speak(speak);
+						audioParts[idx] = audio;
+						loadingSpeech = false;
+						lastPlayedAudioPromise = lastPlayedAudioPromise.then(() => playAudio(idx));
+					}
 				}
 				}
-			}, 100);
+			}
 		}
 		}
 	};
 	};
 
 
@@ -679,12 +716,29 @@
 										floatingButtons={message?.done}
 										floatingButtons={message?.done}
 										save={!readOnly}
 										save={!readOnly}
 										{model}
 										{model}
-										onSourceClick={(e) => {
+										onSourceClick={async (e) => {
 											console.log(e);
 											console.log(e);
-											const sourceButton = document.getElementById(`source-${e}`);
+											let sourceButton = document.getElementById(`source-${e}`);
+											const sourcesCollapsible = document.getElementById(`collapsible-sources`);
 
 
 											if (sourceButton) {
 											if (sourceButton) {
 												sourceButton.click();
 												sourceButton.click();
+											} else if (sourcesCollapsible) {
+												// Open sources collapsible so we can click the source button
+												sourcesCollapsible
+													.querySelector('div:first-child')
+													.dispatchEvent(new PointerEvent('pointerup', {}));
+
+												// Wait for next frame to ensure DOM updates
+												await new Promise((resolve) => {
+													requestAnimationFrame(() => {
+														requestAnimationFrame(resolve);
+													});
+												});
+
+												// Try clicking the source button again
+												sourceButton = document.getElementById(`source-${e}`);
+												sourceButton && sourceButton.click();
 											}
 											}
 										}}
 										}}
 										onAddMessages={({ modelId, parentId, messages }) => {
 										onAddMessages={({ modelId, parentId, messages }) => {

+ 207 - 201
src/lib/components/chat/Messages/UserMessage.svelte

@@ -145,274 +145,280 @@
 				</div>
 				</div>
 			{/if}
 			{/if}
 
 
-			{#if edit === true}
-				<div class=" w-full bg-gray-50 dark:bg-gray-800 rounded-3xl px-5 py-3 mb-2">
-					<div class="max-h-96 overflow-auto">
-						<textarea
-							id="message-edit-{message.id}"
-							bind:this={messageEditTextAreaElement}
-							class=" bg-transparent outline-none w-full resize-none"
-							bind:value={editedContent}
-							on:input={(e) => {
-								e.target.style.height = '';
-								e.target.style.height = `${e.target.scrollHeight}px`;
-							}}
-							on:keydown={(e) => {
-								if (e.key === 'Escape') {
-									document.getElementById('close-edit-message-button')?.click();
-								}
-
-								const isCmdOrCtrlPressed = e.metaKey || e.ctrlKey;
-								const isEnterPressed = e.key === 'Enter';
-
-								if (isCmdOrCtrlPressed && isEnterPressed) {
-									document.getElementById('confirm-edit-message-button')?.click();
-								}
-							}}
-						/>
-					</div>
+			{#if message.content !== ''}
+				{#if edit === true}
+					<div class=" w-full bg-gray-50 dark:bg-gray-800 rounded-3xl px-5 py-3 mb-2">
+						<div class="max-h-96 overflow-auto">
+							<textarea
+								id="message-edit-{message.id}"
+								bind:this={messageEditTextAreaElement}
+								class=" bg-transparent outline-none w-full resize-none"
+								bind:value={editedContent}
+								on:input={(e) => {
+									e.target.style.height = '';
+									e.target.style.height = `${e.target.scrollHeight}px`;
+								}}
+								on:keydown={(e) => {
+									if (e.key === 'Escape') {
+										document.getElementById('close-edit-message-button')?.click();
+									}
 
 
-					<div class=" mt-2 mb-1 flex justify-between text-sm font-medium">
-						<div>
-							<button
-								id="save-edit-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"
-								on:click={() => {
-									editMessageConfirmHandler(false);
+									const isCmdOrCtrlPressed = e.metaKey || e.ctrlKey;
+									const isEnterPressed = e.key === 'Enter';
+
+									if (isCmdOrCtrlPressed && isEnterPressed) {
+										document.getElementById('confirm-edit-message-button')?.click();
+									}
 								}}
 								}}
-							>
-								{$i18n.t('Save')}
-							</button>
+							/>
 						</div>
 						</div>
 
 
-						<div class="flex space-x-1.5">
-							<button
-								id="close-edit-message-button"
-								class="px-4 py-2 bg-white dark:bg-gray-900 hover:bg-gray-100 text-gray-800 dark:text-gray-100 transition rounded-3xl"
-								on:click={() => {
-									cancelEditMessage();
-								}}
-							>
-								{$i18n.t('Cancel')}
-							</button>
-
-							<button
-								id="confirm-edit-message-button"
-								class=" px-4 py-2 bg-gray-900 dark:bg-white hover:bg-gray-850 text-gray-100 dark:text-gray-800 transition rounded-3xl"
-								on:click={() => {
-									editMessageConfirmHandler();
-								}}
-							>
-								{$i18n.t('Send')}
-							</button>
+						<div class=" mt-2 mb-1 flex justify-between text-sm font-medium">
+							<div>
+								<button
+									id="save-edit-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"
+									on:click={() => {
+										editMessageConfirmHandler(false);
+									}}
+								>
+									{$i18n.t('Save')}
+								</button>
+							</div>
+
+							<div class="flex space-x-1.5">
+								<button
+									id="close-edit-message-button"
+									class="px-4 py-2 bg-white dark:bg-gray-900 hover:bg-gray-100 text-gray-800 dark:text-gray-100 transition rounded-3xl"
+									on:click={() => {
+										cancelEditMessage();
+									}}
+								>
+									{$i18n.t('Cancel')}
+								</button>
+
+								<button
+									id="confirm-edit-message-button"
+									class=" px-4 py-2 bg-gray-900 dark:bg-white hover:bg-gray-850 text-gray-100 dark:text-gray-800 transition rounded-3xl"
+									on:click={() => {
+										editMessageConfirmHandler();
+									}}
+								>
+									{$i18n.t('Send')}
+								</button>
+							</div>
 						</div>
 						</div>
 					</div>
 					</div>
-				</div>
-			{:else}
-				<div class="w-full">
-					<div class="flex {($settings?.chatBubble ?? true) ? 'justify-end pb-1' : 'w-full'}">
-						<div
-							class="rounded-3xl {($settings?.chatBubble ?? true)
-								? `max-w-[90%] px-5 py-2  bg-gray-50 dark:bg-gray-850 ${
-										message.files ? 'rounded-tr-lg' : ''
-									}`
-								: ' w-full'}"
-						>
-							{#if message.content}
-								<Markdown id={message.id} content={message.content} />
-							{/if}
+				{:else}
+					<div class="w-full">
+						<div class="flex {($settings?.chatBubble ?? true) ? 'justify-end pb-1' : 'w-full'}">
+							<div
+								class="rounded-3xl {($settings?.chatBubble ?? true)
+									? `max-w-[90%] px-5 py-2  bg-gray-50 dark:bg-gray-850 ${
+											message.files ? 'rounded-tr-lg' : ''
+										}`
+									: ' w-full'}"
+							>
+								{#if message.content}
+									<Markdown id={message.id} content={message.content} />
+								{/if}
+							</div>
 						</div>
 						</div>
-					</div>
 
 
-					<div
-						class=" flex {($settings?.chatBubble ?? true)
-							? 'justify-end'
-							: ''}  text-gray-600 dark:text-gray-500"
-					>
-						{#if !($settings?.chatBubble ?? true)}
-							{#if siblings.length > 1}
-								<div class="flex self-center" dir="ltr">
-									<button
-										class="self-center p-1 hover:bg-black/5 dark:hover:bg-white/5 dark:hover:text-white hover:text-black rounded-md transition"
-										on:click={() => {
-											showPreviousMessage(message);
-										}}
-									>
-										<svg
-											xmlns="http://www.w3.org/2000/svg"
-											fill="none"
-											viewBox="0 0 24 24"
-											stroke="currentColor"
-											stroke-width="2.5"
-											class="size-3.5"
+						<div
+							class=" flex {($settings?.chatBubble ?? true)
+								? 'justify-end'
+								: ''}  text-gray-600 dark:text-gray-500"
+						>
+							{#if !($settings?.chatBubble ?? true)}
+								{#if siblings.length > 1}
+									<div class="flex self-center" dir="ltr">
+										<button
+											class="self-center p-1 hover:bg-black/5 dark:hover:bg-white/5 dark:hover:text-white hover:text-black rounded-md transition"
+											on:click={() => {
+												showPreviousMessage(message);
+											}}
 										>
 										>
-											<path
-												stroke-linecap="round"
-												stroke-linejoin="round"
-												d="M15.75 19.5 8.25 12l7.5-7.5"
-											/>
-										</svg>
-									</button>
-
-									<div class="text-sm tracking-widest font-semibold self-center dark:text-gray-100">
-										{siblings.indexOf(message.id) + 1}/{siblings.length}
+											<svg
+												xmlns="http://www.w3.org/2000/svg"
+												fill="none"
+												viewBox="0 0 24 24"
+												stroke="currentColor"
+												stroke-width="2.5"
+												class="size-3.5"
+											>
+												<path
+													stroke-linecap="round"
+													stroke-linejoin="round"
+													d="M15.75 19.5 8.25 12l7.5-7.5"
+												/>
+											</svg>
+										</button>
+
+										<div
+											class="text-sm tracking-widest font-semibold self-center dark:text-gray-100"
+										>
+											{siblings.indexOf(message.id) + 1}/{siblings.length}
+										</div>
+
+										<button
+											class="self-center p-1 hover:bg-black/5 dark:hover:bg-white/5 dark:hover:text-white hover:text-black rounded-md transition"
+											on:click={() => {
+												showNextMessage(message);
+											}}
+										>
+											<svg
+												xmlns="http://www.w3.org/2000/svg"
+												fill="none"
+												viewBox="0 0 24 24"
+												stroke="currentColor"
+												stroke-width="2.5"
+												class="size-3.5"
+											>
+												<path
+													stroke-linecap="round"
+													stroke-linejoin="round"
+													d="m8.25 4.5 7.5 7.5-7.5 7.5"
+												/>
+											</svg>
+										</button>
 									</div>
 									</div>
-
+								{/if}
+							{/if}
+							{#if !readOnly}
+								<Tooltip content={$i18n.t('Edit')} placement="bottom">
 									<button
 									<button
-										class="self-center p-1 hover:bg-black/5 dark:hover:bg-white/5 dark:hover:text-white hover:text-black rounded-md transition"
+										class="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 edit-user-message-button"
 										on:click={() => {
 										on:click={() => {
-											showNextMessage(message);
+											editMessageHandler();
 										}}
 										}}
 									>
 									>
 										<svg
 										<svg
 											xmlns="http://www.w3.org/2000/svg"
 											xmlns="http://www.w3.org/2000/svg"
 											fill="none"
 											fill="none"
 											viewBox="0 0 24 24"
 											viewBox="0 0 24 24"
+											stroke-width="2.3"
 											stroke="currentColor"
 											stroke="currentColor"
-											stroke-width="2.5"
-											class="size-3.5"
+											class="w-4 h-4"
 										>
 										>
 											<path
 											<path
 												stroke-linecap="round"
 												stroke-linecap="round"
 												stroke-linejoin="round"
 												stroke-linejoin="round"
-												d="m8.25 4.5 7.5 7.5-7.5 7.5"
+												d="M16.862 4.487l1.687-1.688a1.875 1.875 0 112.652 2.652L6.832 19.82a4.5 4.5 0 01-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 011.13-1.897L16.863 4.487zm0 0L19.5 7.125"
 											/>
 											/>
 										</svg>
 										</svg>
 									</button>
 									</button>
-								</div>
+								</Tooltip>
 							{/if}
 							{/if}
-						{/if}
-						{#if !readOnly}
-							<Tooltip content={$i18n.t('Edit')} placement="bottom">
-								<button
-									class="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 edit-user-message-button"
-									on:click={() => {
-										editMessageHandler();
-									}}
-								>
-									<svg
-										xmlns="http://www.w3.org/2000/svg"
-										fill="none"
-										viewBox="0 0 24 24"
-										stroke-width="2.3"
-										stroke="currentColor"
-										class="w-4 h-4"
-									>
-										<path
-											stroke-linecap="round"
-											stroke-linejoin="round"
-											d="M16.862 4.487l1.687-1.688a1.875 1.875 0 112.652 2.652L6.832 19.82a4.5 4.5 0 01-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 011.13-1.897L16.863 4.487zm0 0L19.5 7.125"
-										/>
-									</svg>
-								</button>
-							</Tooltip>
-						{/if}
 
 
-						<Tooltip content={$i18n.t('Copy')} placement="bottom">
-							<button
-								class="invisible group-hover:visible p-1.5 hover:bg-black/5 dark:hover:bg-white/5 rounded-lg dark:hover:text-white hover:text-black transition"
-								on:click={() => {
-									copyToClipboard(message.content);
-								}}
-							>
-								<svg
-									xmlns="http://www.w3.org/2000/svg"
-									fill="none"
-									viewBox="0 0 24 24"
-									stroke-width="2.3"
-									stroke="currentColor"
-									class="w-4 h-4"
-								>
-									<path
-										stroke-linecap="round"
-										stroke-linejoin="round"
-										d="M15.666 3.888A2.25 2.25 0 0013.5 2.25h-3c-1.03 0-1.9.693-2.166 1.638m7.332 0c.055.194.084.4.084.612v0a.75.75 0 01-.75.75H9a.75.75 0 01-.75-.75v0c0-.212.03-.418.084-.612m7.332 0c.646.049 1.288.11 1.927.184 1.1.128 1.907 1.077 1.907 2.185V19.5a2.25 2.25 0 01-2.25 2.25H6.75A2.25 2.25 0 014.5 19.5V6.257c0-1.108.806-2.057 1.907-2.185a48.208 48.208 0 011.927-.184"
-									/>
-								</svg>
-							</button>
-						</Tooltip>
-
-						{#if !isFirstMessage && !readOnly}
-							<Tooltip content={$i18n.t('Delete')} placement="bottom">
+							<Tooltip content={$i18n.t('Copy')} placement="bottom">
 								<button
 								<button
-									class="invisible group-hover:visible p-1 rounded dark:hover:text-white hover:text-black transition"
+									class="invisible group-hover:visible p-1.5 hover:bg-black/5 dark:hover:bg-white/5 rounded-lg dark:hover:text-white hover:text-black transition"
 									on:click={() => {
 									on:click={() => {
-										deleteMessageHandler();
+										copyToClipboard(message.content);
 									}}
 									}}
 								>
 								>
 									<svg
 									<svg
 										xmlns="http://www.w3.org/2000/svg"
 										xmlns="http://www.w3.org/2000/svg"
 										fill="none"
 										fill="none"
 										viewBox="0 0 24 24"
 										viewBox="0 0 24 24"
-										stroke-width="2"
+										stroke-width="2.3"
 										stroke="currentColor"
 										stroke="currentColor"
 										class="w-4 h-4"
 										class="w-4 h-4"
 									>
 									>
 										<path
 										<path
 											stroke-linecap="round"
 											stroke-linecap="round"
 											stroke-linejoin="round"
 											stroke-linejoin="round"
-											d="m14.74 9-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 0 1-2.244 2.077H8.084a2.25 2.25 0 0 1-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 0 0-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 0 1 3.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 0 0-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 0 0-7.5 0"
+											d="M15.666 3.888A2.25 2.25 0 0013.5 2.25h-3c-1.03 0-1.9.693-2.166 1.638m7.332 0c.055.194.084.4.084.612v0a.75.75 0 01-.75.75H9a.75.75 0 01-.75-.75v0c0-.212.03-.418.084-.612m7.332 0c.646.049 1.288.11 1.927.184 1.1.128 1.907 1.077 1.907 2.185V19.5a2.25 2.25 0 01-2.25 2.25H6.75A2.25 2.25 0 014.5 19.5V6.257c0-1.108.806-2.057 1.907-2.185a48.208 48.208 0 011.927-.184"
 										/>
 										/>
 									</svg>
 									</svg>
 								</button>
 								</button>
 							</Tooltip>
 							</Tooltip>
-						{/if}
 
 
-						{#if $settings?.chatBubble ?? true}
-							{#if siblings.length > 1}
-								<div class="flex self-center" dir="ltr">
+							{#if !isFirstMessage && !readOnly}
+								<Tooltip content={$i18n.t('Delete')} placement="bottom">
 									<button
 									<button
-										class="self-center p-1 hover:bg-black/5 dark:hover:bg-white/5 dark:hover:text-white hover:text-black rounded-md transition"
+										class="invisible group-hover:visible p-1 rounded dark:hover:text-white hover:text-black transition"
 										on:click={() => {
 										on:click={() => {
-											showPreviousMessage(message);
+											deleteMessageHandler();
 										}}
 										}}
 									>
 									>
 										<svg
 										<svg
 											xmlns="http://www.w3.org/2000/svg"
 											xmlns="http://www.w3.org/2000/svg"
 											fill="none"
 											fill="none"
 											viewBox="0 0 24 24"
 											viewBox="0 0 24 24"
+											stroke-width="2"
 											stroke="currentColor"
 											stroke="currentColor"
-											stroke-width="2.5"
-											class="size-3.5"
+											class="w-4 h-4"
 										>
 										>
 											<path
 											<path
 												stroke-linecap="round"
 												stroke-linecap="round"
 												stroke-linejoin="round"
 												stroke-linejoin="round"
-												d="M15.75 19.5 8.25 12l7.5-7.5"
+												d="m14.74 9-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 0 1-2.244 2.077H8.084a2.25 2.25 0 0 1-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 0 0-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 0 1 3.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 0 0-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 0 0-7.5 0"
 											/>
 											/>
 										</svg>
 										</svg>
 									</button>
 									</button>
+								</Tooltip>
+							{/if}
 
 
-									<div class="text-sm tracking-widest font-semibold self-center dark:text-gray-100">
-										{siblings.indexOf(message.id) + 1}/{siblings.length}
-									</div>
-
-									<button
-										class="self-center p-1 hover:bg-black/5 dark:hover:bg-white/5 dark:hover:text-white hover:text-black rounded-md transition"
-										on:click={() => {
-											showNextMessage(message);
-										}}
-									>
-										<svg
-											xmlns="http://www.w3.org/2000/svg"
-											fill="none"
-											viewBox="0 0 24 24"
-											stroke="currentColor"
-											stroke-width="2.5"
-											class="size-3.5"
+							{#if $settings?.chatBubble ?? true}
+								{#if siblings.length > 1}
+									<div class="flex self-center" dir="ltr">
+										<button
+											class="self-center p-1 hover:bg-black/5 dark:hover:bg-white/5 dark:hover:text-white hover:text-black rounded-md transition"
+											on:click={() => {
+												showPreviousMessage(message);
+											}}
 										>
 										>
-											<path
-												stroke-linecap="round"
-												stroke-linejoin="round"
-												d="m8.25 4.5 7.5 7.5-7.5 7.5"
-											/>
-										</svg>
-									</button>
-								</div>
+											<svg
+												xmlns="http://www.w3.org/2000/svg"
+												fill="none"
+												viewBox="0 0 24 24"
+												stroke="currentColor"
+												stroke-width="2.5"
+												class="size-3.5"
+											>
+												<path
+													stroke-linecap="round"
+													stroke-linejoin="round"
+													d="M15.75 19.5 8.25 12l7.5-7.5"
+												/>
+											</svg>
+										</button>
+
+										<div
+											class="text-sm tracking-widest font-semibold self-center dark:text-gray-100"
+										>
+											{siblings.indexOf(message.id) + 1}/{siblings.length}
+										</div>
+
+										<button
+											class="self-center p-1 hover:bg-black/5 dark:hover:bg-white/5 dark:hover:text-white hover:text-black rounded-md transition"
+											on:click={() => {
+												showNextMessage(message);
+											}}
+										>
+											<svg
+												xmlns="http://www.w3.org/2000/svg"
+												fill="none"
+												viewBox="0 0 24 24"
+												stroke="currentColor"
+												stroke-width="2.5"
+												class="size-3.5"
+											>
+												<path
+													stroke-linecap="round"
+													stroke-linejoin="round"
+													d="m8.25 4.5 7.5 7.5-7.5 7.5"
+												/>
+											</svg>
+										</button>
+									</div>
+								{/if}
 							{/if}
 							{/if}
-						{/if}
+						</div>
 					</div>
 					</div>
-				</div>
+				{/if}
 			{/if}
 			{/if}
 		</div>
 		</div>
 	</div>
 	</div>

+ 33 - 3
src/lib/components/chat/ModelSelector/Selector.svelte

@@ -12,7 +12,15 @@
 
 
 	import { deleteModel, getOllamaVersion, pullModel } from '$lib/apis/ollama';
 	import { deleteModel, getOllamaVersion, pullModel } from '$lib/apis/ollama';
 
 
-	import { user, MODEL_DOWNLOAD_POOL, models, mobile, temporaryChatEnabled } from '$lib/stores';
+	import {
+		user,
+		MODEL_DOWNLOAD_POOL,
+		models,
+		mobile,
+		temporaryChatEnabled,
+		settings,
+		config
+	} from '$lib/stores';
 	import { toast } from 'svelte-sonner';
 	import { toast } from 'svelte-sonner';
 	import { capitalizeFirstLetter, sanitizeResponseContent, splitStream } from '$lib/utils';
 	import { capitalizeFirstLetter, sanitizeResponseContent, splitStream } from '$lib/utils';
 	import { getModels } from '$lib/apis';
 	import { getModels } from '$lib/apis';
@@ -186,7 +194,12 @@
 					})
 					})
 				);
 				);
 
 
-				models.set(await getModels(localStorage.token));
+				models.set(
+					await getModels(
+						localStorage.token,
+						$config?.features?.enable_direct_connections && ($settings?.directConnections ?? null)
+					)
+				);
 			} else {
 			} else {
 				toast.error($i18n.t('Download canceled'));
 				toast.error($i18n.t('Download canceled'));
 			}
 			}
@@ -358,7 +371,24 @@
 
 
 								<!-- {JSON.stringify(item.info)} -->
 								<!-- {JSON.stringify(item.info)} -->
 
 
-								{#if item.model.owned_by === 'openai'}
+								{#if item.model?.direct}
+									<Tooltip content={`${'Direct'}`}>
+										<div class="translate-y-[1px]">
+											<svg
+												xmlns="http://www.w3.org/2000/svg"
+												viewBox="0 0 16 16"
+												fill="currentColor"
+												class="size-3"
+											>
+												<path
+													fill-rule="evenodd"
+													d="M2 2.75A.75.75 0 0 1 2.75 2C8.963 2 14 7.037 14 13.25a.75.75 0 0 1-1.5 0c0-5.385-4.365-9.75-9.75-9.75A.75.75 0 0 1 2 2.75Zm0 4.5a.75.75 0 0 1 .75-.75 6.75 6.75 0 0 1 6.75 6.75.75.75 0 0 1-1.5 0C8 10.35 5.65 8 2.75 8A.75.75 0 0 1 2 7.25ZM3.5 11a1.5 1.5 0 1 0 0 3 1.5 1.5 0 0 0 0-3Z"
+													clip-rule="evenodd"
+												/>
+											</svg>
+										</div>
+									</Tooltip>
+								{:else if item.model.owned_by === 'openai'}
 									<Tooltip content={`${'External'}`}>
 									<Tooltip content={`${'External'}`}>
 										<div class="translate-y-[1px]">
 										<div class="translate-y-[1px]">
 											<svg
 											<svg

+ 2 - 2
src/lib/components/chat/Navbar.svelte

@@ -114,7 +114,7 @@
 							</div>
 							</div>
 						</button>
 						</button>
 					</Menu>
 					</Menu>
-				{:else if $mobile && ($user.role === 'admin' || $user?.permissions.chat?.controls)}
+				{:else if $mobile && ($user.role === 'admin' || $user?.permissions?.chat?.controls)}
 					<Tooltip content={$i18n.t('Controls')}>
 					<Tooltip content={$i18n.t('Controls')}>
 						<button
 						<button
 							class=" flex cursor-pointer px-2 py-2 rounded-xl hover:bg-gray-50 dark:hover:bg-gray-850 transition"
 							class=" flex cursor-pointer px-2 py-2 rounded-xl hover:bg-gray-50 dark:hover:bg-gray-850 transition"
@@ -130,7 +130,7 @@
 					</Tooltip>
 					</Tooltip>
 				{/if}
 				{/if}
 
 
-				{#if !$mobile && ($user.role === 'admin' || $user?.permissions.chat?.controls)}
+				{#if !$mobile && ($user.role === 'admin' || $user?.permissions?.chat?.controls)}
 					<Tooltip content={$i18n.t('Controls')}>
 					<Tooltip content={$i18n.t('Controls')}>
 						<button
 						<button
 							class=" flex cursor-pointer px-2 py-2 rounded-xl hover:bg-gray-50 dark:hover:bg-gray-850 transition"
 							class=" flex cursor-pointer px-2 py-2 rounded-xl hover:bg-gray-50 dark:hover:bg-gray-850 transition"

+ 8 - 2
src/lib/components/chat/Settings/Account.svelte

@@ -3,7 +3,7 @@
 	import { onMount, getContext } from 'svelte';
 	import { onMount, getContext } from 'svelte';
 
 
 	import { user, config, settings } from '$lib/stores';
 	import { user, config, settings } from '$lib/stores';
-	import { updateUserProfile, createAPIKey, getAPIKey } from '$lib/apis/auths';
+	import { updateUserProfile, createAPIKey, getAPIKey, getSessionUser } from '$lib/apis/auths';
 
 
 	import UpdatePassword from './Account/UpdatePassword.svelte';
 	import UpdatePassword from './Account/UpdatePassword.svelte';
 	import { getGravatarUrl } from '$lib/apis/utils';
 	import { getGravatarUrl } from '$lib/apis/utils';
@@ -53,7 +53,13 @@
 		);
 		);
 
 
 		if (updatedUser) {
 		if (updatedUser) {
-			await user.set(updatedUser);
+			// Get Session User Info
+			const sessionUser = await getSessionUser(localStorage.token).catch((error) => {
+				toast.error(`${error}`);
+				return null;
+			});
+
+			await user.set(sessionUser);
 			return true;
 			return true;
 		}
 		}
 		return false;
 		return false;

+ 162 - 16
src/lib/components/chat/Settings/Audio.svelte

@@ -1,11 +1,14 @@
 <script lang="ts">
 <script lang="ts">
 	import { toast } from 'svelte-sonner';
 	import { toast } from 'svelte-sonner';
 	import { createEventDispatcher, onMount, getContext } from 'svelte';
 	import { createEventDispatcher, onMount, getContext } from 'svelte';
+	import { KokoroTTS } from 'kokoro-js';
 
 
 	import { user, settings, config } from '$lib/stores';
 	import { user, settings, config } from '$lib/stores';
 	import { getVoices as _getVoices } from '$lib/apis/audio';
 	import { getVoices as _getVoices } from '$lib/apis/audio';
 
 
 	import Switch from '$lib/components/common/Switch.svelte';
 	import Switch from '$lib/components/common/Switch.svelte';
+	import { round } from '@huggingface/transformers';
+	import Spinner from '$lib/components/common/Spinner.svelte';
 	const dispatch = createEventDispatcher();
 	const dispatch = createEventDispatcher();
 
 
 	const i18n = getContext('i18n');
 	const i18n = getContext('i18n');
@@ -20,6 +23,13 @@
 
 
 	let STTEngine = '';
 	let STTEngine = '';
 
 
+	let TTSEngine = '';
+	let TTSEngineConfig = {};
+
+	let TTSModel = null;
+	let TTSModelProgress = null;
+	let TTSModelLoading = false;
+
 	let voices = [];
 	let voices = [];
 	let voice = '';
 	let voice = '';
 
 
@@ -28,23 +38,37 @@
 	const speedOptions = [2, 1.75, 1.5, 1.25, 1, 0.75, 0.5];
 	const speedOptions = [2, 1.75, 1.5, 1.25, 1, 0.75, 0.5];
 
 
 	const getVoices = async () => {
 	const getVoices = async () => {
-		if ($config.audio.tts.engine === '') {
-			const getVoicesLoop = setInterval(async () => {
-				voices = await speechSynthesis.getVoices();
+		if (TTSEngine === 'browser-kokoro') {
+			if (!TTSModel) {
+				await loadKokoro();
+			}
 
 
-				// do your loop
-				if (voices.length > 0) {
-					clearInterval(getVoicesLoop);
-				}
-			}, 100);
-		} else {
-			const res = await _getVoices(localStorage.token).catch((e) => {
-				toast.error(`${e}`);
+			voices = Object.entries(TTSModel.voices).map(([key, value]) => {
+				return {
+					id: key,
+					name: value.name,
+					localService: false
+				};
 			});
 			});
-
-			if (res) {
-				console.log(res);
-				voices = res.voices;
+		} else {
+			if ($config.audio.tts.engine === '') {
+				const getVoicesLoop = setInterval(async () => {
+					voices = await speechSynthesis.getVoices();
+
+					// do your loop
+					if (voices.length > 0) {
+						clearInterval(getVoicesLoop);
+					}
+				}, 100);
+			} else {
+				const res = await _getVoices(localStorage.token).catch((e) => {
+					toast.error(`${e}`);
+				});
+
+				if (res) {
+					console.log(res);
+					voices = res.voices;
+				}
 			}
 			}
 		}
 		}
 	};
 	};
@@ -67,6 +91,9 @@
 
 
 		STTEngine = $settings?.audio?.stt?.engine ?? '';
 		STTEngine = $settings?.audio?.stt?.engine ?? '';
 
 
+		TTSEngine = $settings?.audio?.tts?.engine ?? '';
+		TTSEngineConfig = $settings?.audio?.tts?.engineConfig ?? {};
+
 		if ($settings?.audio?.tts?.defaultVoice === $config.audio.tts.voice) {
 		if ($settings?.audio?.tts?.defaultVoice === $config.audio.tts.voice) {
 			voice = $settings?.audio?.tts?.voice ?? $config.audio.tts.voice ?? '';
 			voice = $settings?.audio?.tts?.voice ?? $config.audio.tts.voice ?? '';
 		} else {
 		} else {
@@ -77,6 +104,51 @@
 
 
 		await getVoices();
 		await getVoices();
 	});
 	});
+
+	$: if (TTSEngine && TTSEngineConfig) {
+		onTTSEngineChange();
+	}
+
+	const onTTSEngineChange = async () => {
+		if (TTSEngine === 'browser-kokoro') {
+			await loadKokoro();
+		}
+	};
+
+	const loadKokoro = async () => {
+		if (TTSEngine === 'browser-kokoro') {
+			voices = [];
+
+			if (TTSEngineConfig?.dtype) {
+				TTSModel = null;
+				TTSModelProgress = null;
+				TTSModelLoading = true;
+
+				const model_id = 'onnx-community/Kokoro-82M-v1.0-ONNX';
+
+				TTSModel = await KokoroTTS.from_pretrained(model_id, {
+					dtype: TTSEngineConfig.dtype, // Options: "fp32", "fp16", "q8", "q4", "q4f16"
+					device: !!navigator?.gpu ? 'webgpu' : 'wasm', // Detect WebGPU
+					progress_callback: (e) => {
+						TTSModelProgress = e;
+						console.log(e);
+					}
+				});
+
+				await getVoices();
+
+				// const rawAudio = await tts.generate(inputText, {
+				// 	// Use `tts.list_voices()` to list all available voices
+				// 	voice: voice
+				// });
+
+				// const blobUrl = URL.createObjectURL(await rawAudio.toBlob());
+				// const audio = new Audio(blobUrl);
+
+				// audio.play();
+			}
+		}
+	};
 </script>
 </script>
 
 
 <form
 <form
@@ -88,6 +160,8 @@
 					engine: STTEngine !== '' ? STTEngine : undefined
 					engine: STTEngine !== '' ? STTEngine : undefined
 				},
 				},
 				tts: {
 				tts: {
+					engine: TTSEngine !== '' ? TTSEngine : undefined,
+					engineConfig: TTSEngineConfig,
 					playbackRate: playbackRate,
 					playbackRate: playbackRate,
 					voice: voice !== '' ? voice : undefined,
 					voice: voice !== '' ? voice : undefined,
 					defaultVoice: $config?.audio?.tts?.voice ?? '',
 					defaultVoice: $config?.audio?.tts?.voice ?? '',
@@ -142,6 +216,39 @@
 		<div>
 		<div>
 			<div class=" mb-1 text-sm font-medium">{$i18n.t('TTS Settings')}</div>
 			<div class=" mb-1 text-sm font-medium">{$i18n.t('TTS Settings')}</div>
 
 
+			<div class=" py-0.5 flex w-full justify-between">
+				<div class=" self-center text-xs font-medium">{$i18n.t('Text-to-Speech Engine')}</div>
+				<div class="flex items-center relative">
+					<select
+						class="dark:bg-gray-900 w-fit pr-8 rounded px-2 p-1 text-xs bg-transparent outline-none text-right"
+						bind:value={TTSEngine}
+						placeholder="Select an engine"
+					>
+						<option value="">{$i18n.t('Default')}</option>
+						<option value="browser-kokoro">{$i18n.t('Kokoro.js (Browser)')}</option>
+					</select>
+				</div>
+			</div>
+
+			{#if TTSEngine === 'browser-kokoro'}
+				<div class=" py-0.5 flex w-full justify-between">
+					<div class=" self-center text-xs font-medium">{$i18n.t('Kokoro.js Dtype')}</div>
+					<div class="flex items-center relative">
+						<select
+							class="dark:bg-gray-900 w-fit pr-8 rounded px-2 p-1 text-xs bg-transparent outline-none text-right"
+							bind:value={TTSEngineConfig.dtype}
+							placeholder="Select dtype"
+						>
+							<option value="" disabled selected>Select dtype</option>
+							<option value="fp32">fp32</option>
+							<option value="fp16">fp16</option>
+							<option value="q8">q8</option>
+							<option value="q4">q4</option>
+						</select>
+					</div>
+				</div>
+			{/if}
+
 			<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 font-medium">{$i18n.t('Auto-playback response')}</div>
 				<div class=" self-center text-xs font-medium">{$i18n.t('Auto-playback response')}</div>
 
 
@@ -178,7 +285,46 @@
 
 
 		<hr class=" dark:border-gray-850" />
 		<hr class=" dark:border-gray-850" />
 
 
-		{#if $config.audio.tts.engine === ''}
+		{#if TTSEngine === 'browser-kokoro'}
+			{#if TTSModel}
+				<div>
+					<div class=" mb-2.5 text-sm font-medium">{$i18n.t('Set Voice')}</div>
+					<div class="flex w-full">
+						<div class="flex-1">
+							<input
+								list="voice-list"
+								class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
+								bind:value={voice}
+								placeholder="Select a voice"
+							/>
+
+							<datalist id="voice-list">
+								{#each voices as voice}
+									<option value={voice.id}>{voice.name}</option>
+								{/each}
+							</datalist>
+						</div>
+					</div>
+				</div>
+			{:else}
+				<div>
+					<div class=" mb-2.5 text-sm font-medium flex gap-2 items-center">
+						<Spinner className="size-4" />
+
+						<div class=" text-sm font-medium shimmer">
+							{$i18n.t('Loading Kokoro.js...')}
+							{TTSModelProgress && TTSModelProgress.status === 'progress'
+								? `(${Math.round(TTSModelProgress.progress * 10) / 10}%)`
+								: ''}
+						</div>
+					</div>
+
+					<div class="text-xs text-gray-500">
+						{$i18n.t('Please do not close the settings page while loading the model.')}
+					</div>
+				</div>
+			{/if}
+		{:else if $config.audio.tts.engine === ''}
 			<div>
 			<div>
 				<div class=" mb-2.5 text-sm font-medium">{$i18n.t('Set Voice')}</div>
 				<div class=" mb-2.5 text-sm font-medium">{$i18n.t('Set Voice')}</div>
 				<div class="flex w-full">
 				<div class="flex w-full">

+ 156 - 0
src/lib/components/chat/Settings/Connections.svelte

@@ -0,0 +1,156 @@
+<script lang="ts">
+	import { toast } from 'svelte-sonner';
+	import { createEventDispatcher, onMount, getContext, tick } from 'svelte';
+	import { getModels as _getModels } from '$lib/apis';
+
+	const dispatch = createEventDispatcher();
+	const i18n = getContext('i18n');
+
+	import { models, settings, user } from '$lib/stores';
+
+	import Switch from '$lib/components/common/Switch.svelte';
+	import Spinner from '$lib/components/common/Spinner.svelte';
+	import Tooltip from '$lib/components/common/Tooltip.svelte';
+	import Plus from '$lib/components/icons/Plus.svelte';
+	import Connection from './Connections/Connection.svelte';
+
+	import AddConnectionModal from '$lib/components/AddConnectionModal.svelte';
+
+	export let saveSettings: Function;
+
+	let config = null;
+
+	let showConnectionModal = false;
+
+	const addConnectionHandler = async (connection) => {
+		config.OPENAI_API_BASE_URLS.push(connection.url);
+		config.OPENAI_API_KEYS.push(connection.key);
+		config.OPENAI_API_CONFIGS[config.OPENAI_API_BASE_URLS.length - 1] = connection.config;
+
+		await updateHandler();
+	};
+
+	const updateHandler = async () => {
+		// Remove trailing slashes
+		config.OPENAI_API_BASE_URLS = config.OPENAI_API_BASE_URLS.map((url) => url.replace(/\/$/, ''));
+
+		// Check if API KEYS length is same than API URLS length
+		if (config.OPENAI_API_KEYS.length !== config.OPENAI_API_BASE_URLS.length) {
+			// if there are more keys than urls, remove the extra keys
+			if (config.OPENAI_API_KEYS.length > config.OPENAI_API_BASE_URLS.length) {
+				config.OPENAI_API_KEYS = config.OPENAI_API_KEYS.slice(
+					0,
+					config.OPENAI_API_BASE_URLS.length
+				);
+			}
+
+			// if there are more urls than keys, add empty keys
+			if (config.OPENAI_API_KEYS.length < config.OPENAI_API_BASE_URLS.length) {
+				const diff = config.OPENAI_API_BASE_URLS.length - config.OPENAI_API_KEYS.length;
+				for (let i = 0; i < diff; i++) {
+					config.OPENAI_API_KEYS.push('');
+				}
+			}
+		}
+
+		await saveSettings({
+			directConnections: config
+		});
+	};
+
+	onMount(async () => {
+		config = $settings?.directConnections ?? {
+			OPENAI_API_BASE_URLS: [],
+			OPENAI_API_KEYS: [],
+			OPENAI_API_CONFIGS: {}
+		};
+	});
+</script>
+
+<AddConnectionModal direct bind:show={showConnectionModal} onSubmit={addConnectionHandler} />
+
+<form
+	class="flex flex-col h-full justify-between text-sm"
+	on:submit|preventDefault={() => {
+		updateHandler();
+	}}
+>
+	<div class=" overflow-y-scroll scrollbar-hidden h-full">
+		{#if config !== null}
+			<div class="">
+				<div class="pr-1.5">
+					<div class="">
+						<div class="flex justify-between items-center mb-0.5">
+							<div class="font-medium">{$i18n.t('Manage Direct Connections')}</div>
+
+							<Tooltip content={$i18n.t(`Add Connection`)}>
+								<button
+									class="px-1"
+									on:click={() => {
+										showConnectionModal = true;
+									}}
+									type="button"
+								>
+									<Plus />
+								</button>
+							</Tooltip>
+						</div>
+
+						<div class="flex flex-col gap-1.5">
+							{#each config?.OPENAI_API_BASE_URLS ?? [] as url, idx}
+								<Connection
+									bind:url
+									bind:key={config.OPENAI_API_KEYS[idx]}
+									bind:config={config.OPENAI_API_CONFIGS[idx]}
+									onSubmit={() => {
+										updateHandler();
+									}}
+									onDelete={() => {
+										config.OPENAI_API_BASE_URLS = config.OPENAI_API_BASE_URLS.filter(
+											(url, urlIdx) => idx !== urlIdx
+										);
+										config.OPENAI_API_KEYS = config.OPENAI_API_KEYS.filter(
+											(key, keyIdx) => idx !== keyIdx
+										);
+
+										let newConfig = {};
+										config.OPENAI_API_BASE_URLS.forEach((url, newIdx) => {
+											newConfig[newIdx] =
+												config.OPENAI_API_CONFIGS[newIdx < idx ? newIdx : newIdx + 1];
+										});
+										config.OPENAI_API_CONFIGS = newConfig;
+									}}
+								/>
+							{/each}
+						</div>
+					</div>
+
+					<div class="my-1.5">
+						<div class="text-xs text-gray-500">
+							{$i18n.t('Connect to your own OpenAI compatible API endpoints.')}
+							<br />
+							{$i18n.t(
+								'CORS must be properly configured by the provider to allow requests from Open WebUI.'
+							)}
+						</div>
+					</div>
+				</div>
+			</div>
+		{:else}
+			<div class="flex h-full justify-center">
+				<div class="my-auto">
+					<Spinner className="size-6" />
+				</div>
+			</div>
+		{/if}
+	</div>
+
+	<div class="flex justify-end pt-3 text-sm font-medium">
+		<button
+			class="px-3.5 py-1.5 text-sm font-medium bg-black hover:bg-gray-900 text-white dark:bg-white dark:text-black dark:hover:bg-gray-100 transition rounded-full"
+			type="submit"
+		>
+			{$i18n.t('Save')}
+		</button>
+	</div>
+</form>

+ 83 - 0
src/lib/components/chat/Settings/Connections/Connection.svelte

@@ -0,0 +1,83 @@
+<script lang="ts">
+	import { getContext, tick } from 'svelte';
+	const i18n = getContext('i18n');
+
+	import Tooltip from '$lib/components/common/Tooltip.svelte';
+	import SensitiveInput from '$lib/components/common/SensitiveInput.svelte';
+	import Cog6 from '$lib/components/icons/Cog6.svelte';
+	import AddConnectionModal from '$lib/components/AddConnectionModal.svelte';
+
+	export let onDelete = () => {};
+	export let onSubmit = () => {};
+
+	export let pipeline = false;
+
+	export let url = '';
+	export let key = '';
+	export let config = {};
+
+	let showConfigModal = false;
+</script>
+
+<AddConnectionModal
+	edit
+	bind:show={showConfigModal}
+	connection={{
+		url,
+		key,
+		config
+	}}
+	{onDelete}
+	onSubmit={(connection) => {
+		url = connection.url;
+		key = connection.key;
+		config = connection.config;
+		onSubmit(connection);
+	}}
+/>
+
+<div class="flex w-full gap-2 items-center">
+	<Tooltip
+		className="w-full relative"
+		content={$i18n.t(`WebUI will make requests to "{{url}}/chat/completions"`, {
+			url
+		})}
+		placement="top-start"
+	>
+		{#if !(config?.enable ?? true)}
+			<div
+				class="absolute top-0 bottom-0 left-0 right-0 opacity-60 bg-white dark:bg-gray-900 z-10"
+			></div>
+		{/if}
+		<div class="flex w-full">
+			<div class="flex-1 relative">
+				<input
+					class=" outline-none w-full bg-transparent {pipeline ? 'pr-8' : ''}"
+					placeholder={$i18n.t('API Base URL')}
+					bind:value={url}
+					autocomplete="off"
+				/>
+			</div>
+
+			<SensitiveInput
+				inputClassName=" outline-none bg-transparent w-full"
+				placeholder={$i18n.t('API Key')}
+				bind:value={key}
+			/>
+		</div>
+	</Tooltip>
+
+	<div class="flex gap-1">
+		<Tooltip content={$i18n.t('Configure')} className="self-start">
+			<button
+				class="self-center p-1 bg-transparent hover:bg-gray-100 dark:bg-gray-900 dark:hover:bg-gray-850 rounded-lg transition"
+				on:click={() => {
+					showConfigModal = true;
+				}}
+				type="button"
+			>
+				<Cog6 />
+			</button>
+		</Tooltip>
+	</div>
+</div>

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

@@ -49,6 +49,7 @@
 		function_calling: null,
 		function_calling: null,
 		seed: null,
 		seed: null,
 		temperature: null,
 		temperature: null,
+		reasoning_effort: null,
 		frequency_penalty: null,
 		frequency_penalty: null,
 		repeat_last_n: null,
 		repeat_last_n: null,
 		mirostat: null,
 		mirostat: null,
@@ -333,9 +334,13 @@
 					system: system !== '' ? system : undefined,
 					system: system !== '' ? system : undefined,
 					params: {
 					params: {
 						stream_response: params.stream_response !== null ? params.stream_response : undefined,
 						stream_response: params.stream_response !== null ? params.stream_response : undefined,
+						function_calling:
+							params.function_calling !== null ? params.function_calling : 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,
+						reasoning_effort:
+							params.reasoning_effort !== null ? params.reasoning_effort : undefined,
 						frequency_penalty:
 						frequency_penalty:
 							params.frequency_penalty !== null ? params.frequency_penalty : undefined,
 							params.frequency_penalty !== null ? params.frequency_penalty : undefined,
 						repeat_last_n: params.repeat_last_n !== null ? params.repeat_last_n : undefined,
 						repeat_last_n: params.repeat_last_n !== null ? params.repeat_last_n : undefined,

+ 44 - 2
src/lib/components/chat/SettingsModal.svelte

@@ -1,7 +1,7 @@
 <script lang="ts">
 <script lang="ts">
 	import { getContext, tick } from 'svelte';
 	import { getContext, tick } from 'svelte';
 	import { toast } from 'svelte-sonner';
 	import { toast } from 'svelte-sonner';
-	import { models, settings, user } from '$lib/stores';
+	import { config, models, settings, user } from '$lib/stores';
 	import { updateUserSettings } from '$lib/apis/users';
 	import { updateUserSettings } from '$lib/apis/users';
 	import { getModels as _getModels } from '$lib/apis';
 	import { getModels as _getModels } from '$lib/apis';
 	import { goto } from '$app/navigation';
 	import { goto } from '$app/navigation';
@@ -17,6 +17,7 @@
 	import Personalization from './Settings/Personalization.svelte';
 	import Personalization from './Settings/Personalization.svelte';
 	import SearchInput from '../layout/Sidebar/SearchInput.svelte';
 	import SearchInput from '../layout/Sidebar/SearchInput.svelte';
 	import Search from '../icons/Search.svelte';
 	import Search from '../icons/Search.svelte';
+	import Connections from './Settings/Connections.svelte';
 
 
 	const i18n = getContext('i18n');
 	const i18n = getContext('i18n');
 
 
@@ -122,6 +123,11 @@
 				'alwaysonwebsearch'
 				'alwaysonwebsearch'
 			]
 			]
 		},
 		},
+		{
+			id: 'connections',
+			title: 'Connections',
+			keywords: []
+		},
 		{
 		{
 			id: 'personalization',
 			id: 'personalization',
 			title: 'Personalization',
 			title: 'Personalization',
@@ -316,7 +322,10 @@
 	};
 	};
 
 
 	const getModels = async () => {
 	const getModels = async () => {
-		return await _getModels(localStorage.token);
+		return await _getModels(
+			localStorage.token,
+			$config?.features?.enable_direct_connections && ($settings?.directConnections ?? null)
+		);
 	};
 	};
 
 
 	let selectedTab = 'general';
 	let selectedTab = 'general';
@@ -447,6 +456,32 @@
 								</div>
 								</div>
 								<div class=" self-center">{$i18n.t('Interface')}</div>
 								<div class=" self-center">{$i18n.t('Interface')}</div>
 							</button>
 							</button>
+						{:else if tabId === 'connections'}
+							{#if $user.role === 'admin' || ($user.role === 'user' && $config?.features?.enable_direct_connections)}
+								<button
+									class="px-0.5 py-1 min-w-fit rounded-lg flex-1 md:flex-none flex text-right transition {selectedTab ===
+									'connections'
+										? ''
+										: ' text-gray-300 dark:text-gray-600 hover:text-gray-700 dark:hover:text-white'}"
+									on:click={() => {
+										selectedTab = 'connections';
+									}}
+								>
+									<div class=" self-center mr-2">
+										<svg
+											xmlns="http://www.w3.org/2000/svg"
+											viewBox="0 0 16 16"
+											fill="currentColor"
+											class="w-4 h-4"
+										>
+											<path
+												d="M1 9.5A3.5 3.5 0 0 0 4.5 13H12a3 3 0 0 0 .917-5.857 2.503 2.503 0 0 0-3.198-3.019 3.5 3.5 0 0 0-6.628 2.171A3.5 3.5 0 0 0 1 9.5Z"
+											/>
+										</svg>
+									</div>
+									<div class=" self-center">{$i18n.t('Connections')}</div>
+								</button>
+							{/if}
 						{:else if tabId === 'personalization'}
 						{:else if tabId === 'personalization'}
 							<button
 							<button
 								class="px-0.5 py-1 min-w-fit rounded-lg flex-1 md:flex-none flex text-left transition {selectedTab ===
 								class="px-0.5 py-1 min-w-fit rounded-lg flex-1 md:flex-none flex text-left transition {selectedTab ===
@@ -620,6 +655,13 @@
 							toast.success($i18n.t('Settings saved successfully!'));
 							toast.success($i18n.t('Settings saved successfully!'));
 						}}
 						}}
 					/>
 					/>
+				{:else if selectedTab === 'connections'}
+					<Connections
+						saveSettings={async (updated) => {
+							await saveSettings(updated);
+							toast.success($i18n.t('Settings saved successfully!'));
+						}}
+					/>
 				{:else if selectedTab === 'personalization'}
 				{:else if selectedTab === 'personalization'}
 					<Personalization
 					<Personalization
 						{saveSettings}
 						{saveSettings}

+ 2 - 2
src/lib/components/chat/ShareChatModal.svelte

@@ -30,7 +30,7 @@
 		const _chat = chat.chat;
 		const _chat = chat.chat;
 		console.log('share', _chat);
 		console.log('share', _chat);
 
 
-		toast.success($i18n.t('Redirecting you to OpenWebUI Community'));
+		toast.success($i18n.t('Redirecting you to Open WebUI Community'));
 		const url = 'https://openwebui.com';
 		const url = 'https://openwebui.com';
 		// const url = 'http://localhost:5173';
 		// const url = 'http://localhost:5173';
 
 
@@ -143,7 +143,7 @@
 										show = false;
 										show = false;
 									}}
 									}}
 								>
 								>
-									{$i18n.t('Share to OpenWebUI Community')}
+									{$i18n.t('Share to Open WebUI Community')}
 								</button>
 								</button>
 							{/if}
 							{/if}
 
 

+ 11 - 4
src/lib/components/common/Collapsible.svelte

@@ -34,6 +34,7 @@
 	import Spinner from './Spinner.svelte';
 	import Spinner from './Spinner.svelte';
 
 
 	export let open = false;
 	export let open = false;
+	export let id = '';
 	export let className = '';
 	export let className = '';
 	export let buttonClassName =
 	export let buttonClassName =
 		'w-fit text-gray-500 hover:text-gray-700 dark:hover:text-gray-300 transition';
 		'w-fit text-gray-500 hover:text-gray-700 dark:hover:text-gray-300 transition';
@@ -46,7 +47,7 @@
 	export let hide = false;
 	export let hide = false;
 </script>
 </script>
 
 
-<div class={className}>
+<div {id} class={className}>
 	{#if title !== null}
 	{#if title !== null}
 		<!-- 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 -->
@@ -74,9 +75,15 @@
 				<div class="">
 				<div class="">
 					{#if attributes?.type === 'reasoning'}
 					{#if attributes?.type === 'reasoning'}
 						{#if attributes?.done === 'true' && attributes?.duration}
 						{#if attributes?.done === 'true' && attributes?.duration}
-							{$i18n.t('Thought for {{DURATION}}', {
-								DURATION: dayjs.duration(attributes.duration, 'seconds').humanize()
-							})}
+							{#if attributes.duration < 60}
+								{$i18n.t('Thought for {{DURATION}} seconds', {
+									DURATION: attributes.duration
+								})}
+							{:else}
+								{$i18n.t('Thought for {{DURATION}}', {
+									DURATION: dayjs.duration(attributes.duration, 'seconds').humanize()
+								})}
+							{/if}
 						{:else}
 						{:else}
 							{$i18n.t('Thinking...')}
 							{$i18n.t('Thinking...')}
 						{/if}
 						{/if}

+ 1 - 0
src/lib/components/common/SensitiveInput.svelte

@@ -23,6 +23,7 @@
 	/>
 	/>
 	<button
 	<button
 		class={showButtonClassName}
 		class={showButtonClassName}
+		type="button"
 		on:click={(e) => {
 		on:click={(e) => {
 			e.preventDefault();
 			e.preventDefault();
 			show = !show;
 			show = !show;

+ 28 - 6
src/lib/components/workspace/Models.svelte

@@ -68,7 +68,12 @@
 			toast.success($i18n.t(`Deleted {{name}}`, { name: model.id }));
 			toast.success($i18n.t(`Deleted {{name}}`, { name: model.id }));
 		}
 		}
 
 
-		await _models.set(await getModels(localStorage.token));
+		await _models.set(
+			await getModels(
+				localStorage.token,
+				$config?.features?.enable_direct_connections && ($settings?.directConnections ?? null)
+			)
+		);
 		models = await getWorkspaceModels(localStorage.token);
 		models = await getWorkspaceModels(localStorage.token);
 	};
 	};
 
 
@@ -82,7 +87,7 @@
 	};
 	};
 
 
 	const shareModelHandler = async (model) => {
 	const shareModelHandler = async (model) => {
-		toast.success($i18n.t('Redirecting you to OpenWebUI Community'));
+		toast.success($i18n.t('Redirecting you to Open WebUI Community'));
 
 
 		const url = 'https://openwebui.com';
 		const url = 'https://openwebui.com';
 
 
@@ -134,7 +139,12 @@
 			);
 			);
 		}
 		}
 
 
-		await _models.set(await getModels(localStorage.token));
+		await _models.set(
+			await getModels(
+				localStorage.token,
+				$config?.features?.enable_direct_connections && ($settings?.directConnections ?? null)
+			)
+		);
 		models = await getWorkspaceModels(localStorage.token);
 		models = await getWorkspaceModels(localStorage.token);
 	};
 	};
 
 
@@ -371,7 +381,13 @@
 										bind:state={model.is_active}
 										bind:state={model.is_active}
 										on:change={async (e) => {
 										on:change={async (e) => {
 											toggleModelById(localStorage.token, model.id);
 											toggleModelById(localStorage.token, model.id);
-											_models.set(await getModels(localStorage.token));
+											_models.set(
+												await getModels(
+													localStorage.token,
+													$config?.features?.enable_direct_connections &&
+														($settings?.directConnections ?? null)
+												)
+											);
 										}}
 										}}
 									/>
 									/>
 								</Tooltip>
 								</Tooltip>
@@ -417,7 +433,13 @@
 								}
 								}
 							}
 							}
 
 
-							await _models.set(await getModels(localStorage.token));
+							await _models.set(
+								await getModels(
+									localStorage.token,
+									$config?.features?.enable_direct_connections &&
+										($settings?.directConnections ?? null)
+								)
+							);
 							models = await getWorkspaceModels(localStorage.token);
 							models = await getWorkspaceModels(localStorage.token);
 						};
 						};
 
 
@@ -479,7 +501,7 @@
 	{#if $config?.features.enable_community_sharing}
 	{#if $config?.features.enable_community_sharing}
 		<div class=" my-16">
 		<div class=" my-16">
 			<div class=" text-xl font-medium mb-1 line-clamp-1">
 			<div class=" text-xl font-medium mb-1 line-clamp-1">
-				{$i18n.t('Made by OpenWebUI Community')}
+				{$i18n.t('Made by Open WebUI Community')}
 			</div>
 			</div>
 
 
 			<a
 			<a

+ 2 - 2
src/lib/components/workspace/Prompts.svelte

@@ -40,7 +40,7 @@
 	$: filteredItems = prompts.filter((p) => query === '' || p.command.includes(query));
 	$: filteredItems = prompts.filter((p) => query === '' || p.command.includes(query));
 
 
 	const shareHandler = async (prompt) => {
 	const shareHandler = async (prompt) => {
-		toast.success($i18n.t('Redirecting you to OpenWebUI Community'));
+		toast.success($i18n.t('Redirecting you to Open WebUI Community'));
 
 
 		const url = 'https://openwebui.com';
 		const url = 'https://openwebui.com';
 
 
@@ -319,7 +319,7 @@
 	{#if $config?.features.enable_community_sharing}
 	{#if $config?.features.enable_community_sharing}
 		<div class=" my-16">
 		<div class=" my-16">
 			<div class=" text-xl font-medium mb-1 line-clamp-1">
 			<div class=" text-xl font-medium mb-1 line-clamp-1">
-				{$i18n.t('Made by OpenWebUI Community')}
+				{$i18n.t('Made by Open WebUI Community')}
 			</div>
 			</div>
 
 
 			<a
 			<a

+ 2 - 2
src/lib/components/workspace/Tools.svelte

@@ -65,7 +65,7 @@
 			return null;
 			return null;
 		});
 		});
 
 
-		toast.success($i18n.t('Redirecting you to OpenWebUI Community'));
+		toast.success($i18n.t('Redirecting you to Open WebUI Community'));
 
 
 		const url = 'https://openwebui.com';
 		const url = 'https://openwebui.com';
 
 
@@ -438,7 +438,7 @@
 	{#if $config?.features.enable_community_sharing}
 	{#if $config?.features.enable_community_sharing}
 		<div class=" my-16">
 		<div class=" my-16">
 			<div class=" text-xl font-medium mb-1 line-clamp-1">
 			<div class=" text-xl font-medium mb-1 line-clamp-1">
-				{$i18n.t('Made by OpenWebUI Community')}
+				{$i18n.t('Made by Open WebUI Community')}
 			</div>
 			</div>
 
 
 			<a
 			<a

+ 29 - 3
src/lib/i18n/locales/ar-BH/translation.json

@@ -122,6 +122,7 @@
 	"Beta": "",
 	"Beta": "",
 	"Bing Search V7 Endpoint": "",
 	"Bing Search V7 Endpoint": "",
 	"Bing Search V7 Subscription Key": "",
 	"Bing Search V7 Subscription Key": "",
+	"Bocha Search API Key": "",
 	"Brave Search API Key": "مفتاح واجهة برمجة تطبيقات البحث الشجاع",
 	"Brave Search API Key": "مفتاح واجهة برمجة تطبيقات البحث الشجاع",
 	"By {{name}}": "",
 	"By {{name}}": "",
 	"Bypass SSL verification for Websites": "تجاوز التحقق من SSL للموقع",
 	"Bypass SSL verification for Websites": "تجاوز التحقق من SSL للموقع",
@@ -163,6 +164,7 @@
 	"Click here to": "أضغط هنا الانتقال",
 	"Click here to": "أضغط هنا الانتقال",
 	"Click here to download user import template file.": "",
 	"Click here to download user import template file.": "",
 	"Click here to learn more about faster-whisper and see the available models.": "",
 	"Click here to learn more about faster-whisper and see the available models.": "",
+	"Click here to see available models.": "",
 	"Click here to select": "أضغط هنا للاختيار",
 	"Click here to select": "أضغط هنا للاختيار",
 	"Click here to select a csv file.": "أضغط هنا للاختيار ملف csv",
 	"Click here to select a csv file.": "أضغط هنا للاختيار ملف csv",
 	"Click here to select a py file.": "",
 	"Click here to select a py file.": "",
@@ -177,6 +179,8 @@
 	"Code execution": "",
 	"Code execution": "",
 	"Code formatted successfully": "",
 	"Code formatted successfully": "",
 	"Code Interpreter": "",
 	"Code Interpreter": "",
+	"Code Interpreter Engine": "",
+	"Code Interpreter Prompt Template": "",
 	"Collection": "مجموعة",
 	"Collection": "مجموعة",
 	"Color": "",
 	"Color": "",
 	"ComfyUI": "ComfyUI",
 	"ComfyUI": "ComfyUI",
@@ -193,6 +197,7 @@
 	"Confirm Password": "تأكيد كلمة المرور",
 	"Confirm Password": "تأكيد كلمة المرور",
 	"Confirm your action": "",
 	"Confirm your action": "",
 	"Confirm your new password": "",
 	"Confirm your new password": "",
+	"Connect to your own OpenAI compatible API endpoints.": "",
 	"Connections": "اتصالات",
 	"Connections": "اتصالات",
 	"Constrains effort on reasoning for reasoning models. Only applicable to reasoning models from specific providers that support reasoning effort. (Default: medium)": "",
 	"Constrains effort on reasoning for reasoning models. Only applicable to reasoning models from specific providers that support reasoning effort. (Default: medium)": "",
 	"Contact Admin for WebUI Access": "",
 	"Contact Admin for WebUI Access": "",
@@ -215,6 +220,7 @@
 	"Copy Link": "أنسخ الرابط",
 	"Copy Link": "أنسخ الرابط",
 	"Copy to clipboard": "",
 	"Copy to clipboard": "",
 	"Copying to clipboard was successful!": "تم النسخ إلى الحافظة بنجاح",
 	"Copying to clipboard was successful!": "تم النسخ إلى الحافظة بنجاح",
+	"CORS must be properly configured by the provider to allow requests from Open WebUI.": "",
 	"Create": "",
 	"Create": "",
 	"Create a knowledge base": "",
 	"Create a knowledge base": "",
 	"Create a model": "إنشاء نموذج",
 	"Create a model": "إنشاء نموذج",
@@ -268,6 +274,9 @@
 	"Describe your knowledge base and objectives": "",
 	"Describe your knowledge base and objectives": "",
 	"Description": "وصف",
 	"Description": "وصف",
 	"Didn't fully follow instructions": "لم أتبع التعليمات بشكل كامل",
 	"Didn't fully follow instructions": "لم أتبع التعليمات بشكل كامل",
+	"Direct Connections": "",
+	"Direct Connections allow users to connect to their own OpenAI compatible API endpoints.": "",
+	"Direct Connections settings updated": "",
 	"Disabled": "",
 	"Disabled": "",
 	"Discover a function": "",
 	"Discover a function": "",
 	"Discover a model": "اكتشف نموذجا",
 	"Discover a model": "اكتشف نموذجا",
@@ -290,6 +299,7 @@
 	"Documentation": "",
 	"Documentation": "",
 	"Documents": "مستندات",
 	"Documents": "مستندات",
 	"does not make any external connections, and your data stays securely on your locally hosted server.": "لا يجري أي اتصالات خارجية، وتظل بياناتك آمنة على الخادم المستضاف محليًا.",
 	"does not make any external connections, and your data stays securely on your locally hosted server.": "لا يجري أي اتصالات خارجية، وتظل بياناتك آمنة على الخادم المستضاف محليًا.",
+	"Domain Filter List": "",
 	"Don't have an account?": "ليس لديك حساب؟",
 	"Don't have an account?": "ليس لديك حساب؟",
 	"don't install random functions from sources you don't trust.": "",
 	"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 tools from sources you don't trust.": "",
@@ -325,6 +335,7 @@
 	"Embedding model set to \"{{embedding_model}}\"": "تم تعيين نموذج التضمين على \"{{embedding_model}}\"",
 	"Embedding model set to \"{{embedding_model}}\"": "تم تعيين نموذج التضمين على \"{{embedding_model}}\"",
 	"Enable API Key": "",
 	"Enable API Key": "",
 	"Enable autocomplete generation for chat messages": "",
 	"Enable autocomplete generation for chat messages": "",
+	"Enable Code Interpreter": "",
 	"Enable Community Sharing": "تمكين مشاركة المجتمع",
 	"Enable Community Sharing": "تمكين مشاركة المجتمع",
 	"Enable Google Drive": "",
 	"Enable Google Drive": "",
 	"Enable Memory Locking (mlock) to prevent model data from being swapped out of RAM. This option locks the model's working set of pages into RAM, ensuring that they will not be swapped out to disk. This can help maintain performance by avoiding page faults and ensuring fast data access.": "",
 	"Enable Memory Locking (mlock) to prevent model data from being swapped out of RAM. This option locks the model's working set of pages into RAM, ensuring that they will not be swapped out to disk. This can help maintain performance by avoiding page faults and ensuring fast data access.": "",
@@ -343,18 +354,23 @@
 	"Enter Application DN Password": "",
 	"Enter Application DN Password": "",
 	"Enter Bing Search V7 Endpoint": "",
 	"Enter Bing Search V7 Endpoint": "",
 	"Enter Bing Search V7 Subscription Key": "",
 	"Enter Bing Search V7 Subscription Key": "",
+	"Enter Bocha Search API Key": "",
 	"Enter Brave Search API Key": "أدخل مفتاح واجهة برمجة تطبيقات البحث الشجاع",
 	"Enter Brave Search API Key": "أدخل مفتاح واجهة برمجة تطبيقات البحث الشجاع",
 	"Enter certificate path": "",
 	"Enter certificate path": "",
 	"Enter CFG Scale (e.g. 7.0)": "",
 	"Enter CFG Scale (e.g. 7.0)": "",
 	"Enter Chunk Overlap": "أدخل الChunk Overlap",
 	"Enter Chunk Overlap": "أدخل الChunk Overlap",
 	"Enter Chunk Size": "أدخل Chunk الحجم",
 	"Enter Chunk Size": "أدخل Chunk الحجم",
 	"Enter description": "",
 	"Enter description": "",
+	"Enter domains separated by commas (e.g., example.com,site.org)": "",
 	"Enter Exa API Key": "",
 	"Enter Exa API Key": "",
 	"Enter Github Raw URL": "أدخل عنوان URL ل Github Raw",
 	"Enter Github Raw URL": "أدخل عنوان URL ل Github Raw",
 	"Enter Google PSE API Key": "أدخل مفتاح واجهة برمجة تطبيقات PSE من Google",
 	"Enter Google PSE API Key": "أدخل مفتاح واجهة برمجة تطبيقات PSE من Google",
 	"Enter Google PSE Engine Id": "أدخل معرف محرك PSE من Google",
 	"Enter Google PSE Engine Id": "أدخل معرف محرك PSE من Google",
 	"Enter Image Size (e.g. 512x512)": "(e.g. 512x512) أدخل حجم الصورة ",
 	"Enter Image Size (e.g. 512x512)": "(e.g. 512x512) أدخل حجم الصورة ",
 	"Enter Jina API Key": "",
 	"Enter Jina API Key": "",
+	"Enter Jupyter Password": "",
+	"Enter Jupyter Token": "",
+	"Enter Jupyter URL": "",
 	"Enter Kagi Search API Key": "",
 	"Enter Kagi Search API Key": "",
 	"Enter language codes": "أدخل كود اللغة",
 	"Enter language codes": "أدخل كود اللغة",
 	"Enter Model ID": "",
 	"Enter Model ID": "",
@@ -540,6 +556,8 @@
 	"JSON Preview": "معاينة JSON",
 	"JSON Preview": "معاينة JSON",
 	"July": "يوليو",
 	"July": "يوليو",
 	"June": "يونيو",
 	"June": "يونيو",
+	"Jupyter Auth": "",
+	"Jupyter URL": "",
 	"JWT Expiration": "JWT تجريبي",
 	"JWT Expiration": "JWT تجريبي",
 	"JWT Token": "JWT Token",
 	"JWT Token": "JWT Token",
 	"Kagi Search API Key": "",
 	"Kagi Search API Key": "",
@@ -552,6 +570,8 @@
 	"Knowledge deleted successfully.": "",
 	"Knowledge deleted successfully.": "",
 	"Knowledge reset successfully.": "",
 	"Knowledge reset successfully.": "",
 	"Knowledge updated successfully": "",
 	"Knowledge updated successfully": "",
+	"Kokoro.js (Browser)": "",
+	"Kokoro.js Dtype": "",
 	"Label": "",
 	"Label": "",
 	"Landing Page Mode": "",
 	"Landing Page Mode": "",
 	"Language": "اللغة",
 	"Language": "اللغة",
@@ -566,19 +586,22 @@
 	"Leave empty to include all models from \"{{URL}}/models\" endpoint": "",
 	"Leave empty to include all models from \"{{URL}}/models\" endpoint": "",
 	"Leave empty to include all models or select specific models": "",
 	"Leave empty to include all models or select specific models": "",
 	"Leave empty to use the default prompt, or enter a custom prompt": "",
 	"Leave empty to use the default prompt, or enter a custom prompt": "",
+	"Leave model field empty to use the default model.": "",
 	"Light": "فاتح",
 	"Light": "فاتح",
 	"Listening...": "",
 	"Listening...": "",
 	"Llama.cpp": "",
 	"Llama.cpp": "",
 	"LLMs can make mistakes. Verify important information.": "يمكن أن تصدر بعض الأخطاء. لذلك يجب التحقق من المعلومات المهمة",
 	"LLMs can make mistakes. Verify important information.": "يمكن أن تصدر بعض الأخطاء. لذلك يجب التحقق من المعلومات المهمة",
+	"Loading Kokoro.js...": "",
 	"Local": "",
 	"Local": "",
 	"Local Models": "",
 	"Local Models": "",
 	"Lost": "",
 	"Lost": "",
 	"LTR": "من جهة اليسار إلى اليمين",
 	"LTR": "من جهة اليسار إلى اليمين",
-	"Made by OpenWebUI Community": "OpenWebUI تم إنشاؤه بواسطة مجتمع ",
+	"Made by Open WebUI Community": "OpenWebUI تم إنشاؤه بواسطة مجتمع ",
 	"Make sure to enclose them with": "تأكد من إرفاقها",
 	"Make sure to enclose them with": "تأكد من إرفاقها",
 	"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.": "",
 	"Manage": "",
 	"Manage": "",
 	"Manage Arena Models": "",
 	"Manage Arena Models": "",
+	"Manage Direct Connections": "",
 	"Manage Models": "",
 	"Manage Models": "",
 	"Manage Ollama": "",
 	"Manage Ollama": "",
 	"Manage Ollama API Connections": "",
 	"Manage Ollama API Connections": "",
@@ -722,6 +745,7 @@
 	"Plain text (.txt)": "نص عادي (.txt)",
 	"Plain text (.txt)": "نص عادي (.txt)",
 	"Playground": "مكان التجربة",
 	"Playground": "مكان التجربة",
 	"Please carefully review the following warnings:": "",
 	"Please carefully review the following warnings:": "",
+	"Please do not close the settings page while loading the model.": "",
 	"Please enter a prompt": "",
 	"Please enter a prompt": "",
 	"Please fill in all fields.": "",
 	"Please fill in all fields.": "",
 	"Please select a model first.": "",
 	"Please select a model first.": "",
@@ -754,7 +778,7 @@
 	"Read Aloud": "أقراء لي",
 	"Read Aloud": "أقراء لي",
 	"Reasoning Effort": "",
 	"Reasoning Effort": "",
 	"Record voice": "سجل صوت",
 	"Record voice": "سجل صوت",
-	"Redirecting you to OpenWebUI Community": "OpenWebUI إعادة توجيهك إلى مجتمع ",
+	"Redirecting you to Open WebUI Community": "OpenWebUI إعادة توجيهك إلى مجتمع ",
 	"Reduces the probability of generating nonsense. A higher value (e.g. 100) will give more diverse answers, while a lower value (e.g. 10) will be more conservative. (Default: 40)": "",
 	"Reduces the probability of generating nonsense. A higher value (e.g. 100) will give more diverse answers, while a lower value (e.g. 10) will be more conservative. (Default: 40)": "",
 	"Refer to yourself as \"User\" (e.g., \"User is learning Spanish\")": "",
 	"Refer to yourself as \"User\" (e.g., \"User is learning Spanish\")": "",
 	"References from": "",
 	"References from": "",
@@ -829,6 +853,7 @@
 	"Select a pipeline": "حدد مسارا",
 	"Select a pipeline": "حدد مسارا",
 	"Select a pipeline url": "حدد عنوان URL لخط الأنابيب",
 	"Select a pipeline url": "حدد عنوان URL لخط الأنابيب",
 	"Select a tool": "",
 	"Select a tool": "",
+	"Select an auth method": "",
 	"Select an Ollama instance": "",
 	"Select an Ollama instance": "",
 	"Select Engine": "",
 	"Select Engine": "",
 	"Select Knowledge": "",
 	"Select Knowledge": "",
@@ -869,7 +894,7 @@
 	"Settings saved successfully!": "تم حفظ الاعدادات بنجاح",
 	"Settings saved successfully!": "تم حفظ الاعدادات بنجاح",
 	"Share": "كشاركة",
 	"Share": "كشاركة",
 	"Share Chat": "مشاركة الدردشة",
 	"Share Chat": "مشاركة الدردشة",
-	"Share to OpenWebUI Community": "OpenWebUI شارك في مجتمع",
+	"Share to Open WebUI Community": "OpenWebUI شارك في مجتمع",
 	"Show": "عرض",
 	"Show": "عرض",
 	"Show \"What's New\" modal on login": "",
 	"Show \"What's New\" modal on login": "",
 	"Show Admin Details in Account Pending Overlay": "",
 	"Show Admin Details in Account Pending Overlay": "",
@@ -944,6 +969,7 @@
 	"This will reset the knowledge base and sync all files. Do you wish to continue?": "",
 	"This will reset the knowledge base and sync all files. Do you wish to continue?": "",
 	"Thorough explanation": "شرح شامل",
 	"Thorough explanation": "شرح شامل",
 	"Thought for {{DURATION}}": "",
 	"Thought for {{DURATION}}": "",
+	"Thought for {{DURATION}} seconds": "",
 	"Tika": "",
 	"Tika": "",
 	"Tika Server URL required.": "",
 	"Tika Server URL required.": "",
 	"Tiktoken": "",
 	"Tiktoken": "",

+ 29 - 3
src/lib/i18n/locales/bg-BG/translation.json

@@ -122,6 +122,7 @@
 	"Beta": "",
 	"Beta": "",
 	"Bing Search V7 Endpoint": "",
 	"Bing Search V7 Endpoint": "",
 	"Bing Search V7 Subscription Key": "",
 	"Bing Search V7 Subscription Key": "",
+	"Bocha Search API Key": "",
 	"Brave Search API Key": "Смел ключ за API за търсене",
 	"Brave Search API Key": "Смел ключ за API за търсене",
 	"By {{name}}": "",
 	"By {{name}}": "",
 	"Bypass SSL verification for Websites": "Изключване на SSL проверката за сайтове",
 	"Bypass SSL verification for Websites": "Изключване на SSL проверката за сайтове",
@@ -163,6 +164,7 @@
 	"Click here to": "Натиснете тук за",
 	"Click here to": "Натиснете тук за",
 	"Click here to download user import template file.": "",
 	"Click here to download user import template file.": "",
 	"Click here to learn more about faster-whisper and see the available models.": "",
 	"Click here to learn more about faster-whisper and see the available models.": "",
+	"Click here to see available models.": "",
 	"Click here to select": "Натиснете тук, за да изберете",
 	"Click here to select": "Натиснете тук, за да изберете",
 	"Click here to select a csv file.": "Натиснете тук, за да изберете csv файл.",
 	"Click here to select a csv file.": "Натиснете тук, за да изберете csv файл.",
 	"Click here to select a py file.": "",
 	"Click here to select a py file.": "",
@@ -177,6 +179,8 @@
 	"Code execution": "",
 	"Code execution": "",
 	"Code formatted successfully": "",
 	"Code formatted successfully": "",
 	"Code Interpreter": "",
 	"Code Interpreter": "",
+	"Code Interpreter Engine": "",
+	"Code Interpreter Prompt Template": "",
 	"Collection": "Колекция",
 	"Collection": "Колекция",
 	"Color": "",
 	"Color": "",
 	"ComfyUI": "ComfyUI",
 	"ComfyUI": "ComfyUI",
@@ -193,6 +197,7 @@
 	"Confirm Password": "Потвърди Парола",
 	"Confirm Password": "Потвърди Парола",
 	"Confirm your action": "",
 	"Confirm your action": "",
 	"Confirm your new password": "",
 	"Confirm your new password": "",
+	"Connect to your own OpenAI compatible API endpoints.": "",
 	"Connections": "Връзки",
 	"Connections": "Връзки",
 	"Constrains effort on reasoning for reasoning models. Only applicable to reasoning models from specific providers that support reasoning effort. (Default: medium)": "",
 	"Constrains effort on reasoning for reasoning models. Only applicable to reasoning models from specific providers that support reasoning effort. (Default: medium)": "",
 	"Contact Admin for WebUI Access": "",
 	"Contact Admin for WebUI Access": "",
@@ -215,6 +220,7 @@
 	"Copy Link": "Копиране на връзка",
 	"Copy Link": "Копиране на връзка",
 	"Copy to clipboard": "",
 	"Copy to clipboard": "",
 	"Copying to clipboard was successful!": "Копирането в клипборда беше успешно!",
 	"Copying to clipboard was successful!": "Копирането в клипборда беше успешно!",
+	"CORS must be properly configured by the provider to allow requests from Open WebUI.": "",
 	"Create": "",
 	"Create": "",
 	"Create a knowledge base": "",
 	"Create a knowledge base": "",
 	"Create a model": "Създаване на модел",
 	"Create a model": "Създаване на модел",
@@ -268,6 +274,9 @@
 	"Describe your knowledge base and objectives": "",
 	"Describe your knowledge base and objectives": "",
 	"Description": "Описание",
 	"Description": "Описание",
 	"Didn't fully follow instructions": "Не следва инструкциите",
 	"Didn't fully follow instructions": "Не следва инструкциите",
+	"Direct Connections": "",
+	"Direct Connections allow users to connect to their own OpenAI compatible API endpoints.": "",
+	"Direct Connections settings updated": "",
 	"Disabled": "",
 	"Disabled": "",
 	"Discover a function": "",
 	"Discover a function": "",
 	"Discover a model": "Открийте модел",
 	"Discover a model": "Открийте модел",
@@ -290,6 +299,7 @@
 	"Documentation": "",
 	"Documentation": "",
 	"Documents": "Документи",
 	"Documents": "Документи",
 	"does not make any external connections, and your data stays securely on your locally hosted server.": "няма външни връзки, и вашите данни остават сигурни на локално назначен сървър.",
 	"does not make any external connections, and your data stays securely on your locally hosted server.": "няма външни връзки, и вашите данни остават сигурни на локално назначен сървър.",
+	"Domain Filter List": "",
 	"Don't have an account?": "Нямате акаунт?",
 	"Don't have an account?": "Нямате акаунт?",
 	"don't install random functions from sources you don't trust.": "",
 	"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 tools from sources you don't trust.": "",
@@ -325,6 +335,7 @@
 	"Embedding model set to \"{{embedding_model}}\"": "Модел за вграждане е настроен на \"{{embedding_model}}\"",
 	"Embedding model set to \"{{embedding_model}}\"": "Модел за вграждане е настроен на \"{{embedding_model}}\"",
 	"Enable API Key": "",
 	"Enable API Key": "",
 	"Enable autocomplete generation for chat messages": "",
 	"Enable autocomplete generation for chat messages": "",
+	"Enable Code Interpreter": "",
 	"Enable Community Sharing": "Разрешаване на споделяне в общност",
 	"Enable Community Sharing": "Разрешаване на споделяне в общност",
 	"Enable Google Drive": "",
 	"Enable Google Drive": "",
 	"Enable Memory Locking (mlock) to prevent model data from being swapped out of RAM. This option locks the model's working set of pages into RAM, ensuring that they will not be swapped out to disk. This can help maintain performance by avoiding page faults and ensuring fast data access.": "",
 	"Enable Memory Locking (mlock) to prevent model data from being swapped out of RAM. This option locks the model's working set of pages into RAM, ensuring that they will not be swapped out to disk. This can help maintain performance by avoiding page faults and ensuring fast data access.": "",
@@ -343,18 +354,23 @@
 	"Enter Application DN Password": "",
 	"Enter Application DN Password": "",
 	"Enter Bing Search V7 Endpoint": "",
 	"Enter Bing Search V7 Endpoint": "",
 	"Enter Bing Search V7 Subscription Key": "",
 	"Enter Bing Search V7 Subscription Key": "",
+	"Enter Bocha Search API Key": "",
 	"Enter Brave Search API Key": "Въведете Brave Search API ключ",
 	"Enter Brave Search API Key": "Въведете Brave Search API ключ",
 	"Enter certificate path": "",
 	"Enter certificate path": "",
 	"Enter CFG Scale (e.g. 7.0)": "",
 	"Enter CFG Scale (e.g. 7.0)": "",
 	"Enter Chunk Overlap": "Въведете Chunk Overlap",
 	"Enter Chunk Overlap": "Въведете Chunk Overlap",
 	"Enter Chunk Size": "Въведете Chunk Size",
 	"Enter Chunk Size": "Въведете Chunk Size",
 	"Enter description": "",
 	"Enter description": "",
+	"Enter domains separated by commas (e.g., example.com,site.org)": "",
 	"Enter Exa API Key": "",
 	"Enter Exa API Key": "",
 	"Enter Github Raw URL": "Въведете URL адреса на Github Raw",
 	"Enter Github Raw URL": "Въведете URL адреса на Github Raw",
 	"Enter Google PSE API Key": "Въведете Google PSE API ключ",
 	"Enter Google PSE API Key": "Въведете Google PSE API ключ",
 	"Enter Google PSE Engine Id": "Въведете идентификатор на двигателя на Google PSE",
 	"Enter Google PSE Engine Id": "Въведете идентификатор на двигателя на Google PSE",
 	"Enter Image Size (e.g. 512x512)": "Въведете размер на изображението (напр. 512x512)",
 	"Enter Image Size (e.g. 512x512)": "Въведете размер на изображението (напр. 512x512)",
 	"Enter Jina API Key": "",
 	"Enter Jina API Key": "",
+	"Enter Jupyter Password": "",
+	"Enter Jupyter Token": "",
+	"Enter Jupyter URL": "",
 	"Enter Kagi Search API Key": "",
 	"Enter Kagi Search API Key": "",
 	"Enter language codes": "Въведете кодове на езика",
 	"Enter language codes": "Въведете кодове на езика",
 	"Enter Model ID": "",
 	"Enter Model ID": "",
@@ -540,6 +556,8 @@
 	"JSON Preview": "JSON Преглед",
 	"JSON Preview": "JSON Преглед",
 	"July": "Июл",
 	"July": "Июл",
 	"June": "Июн",
 	"June": "Июн",
+	"Jupyter Auth": "",
+	"Jupyter URL": "",
 	"JWT Expiration": "JWT Expiration",
 	"JWT Expiration": "JWT Expiration",
 	"JWT Token": "JWT Token",
 	"JWT Token": "JWT Token",
 	"Kagi Search API Key": "",
 	"Kagi Search API Key": "",
@@ -552,6 +570,8 @@
 	"Knowledge deleted successfully.": "",
 	"Knowledge deleted successfully.": "",
 	"Knowledge reset successfully.": "",
 	"Knowledge reset successfully.": "",
 	"Knowledge updated successfully": "",
 	"Knowledge updated successfully": "",
+	"Kokoro.js (Browser)": "",
+	"Kokoro.js Dtype": "",
 	"Label": "",
 	"Label": "",
 	"Landing Page Mode": "",
 	"Landing Page Mode": "",
 	"Language": "Език",
 	"Language": "Език",
@@ -566,19 +586,22 @@
 	"Leave empty to include all models from \"{{URL}}/models\" endpoint": "",
 	"Leave empty to include all models from \"{{URL}}/models\" endpoint": "",
 	"Leave empty to include all models or select specific models": "",
 	"Leave empty to include all models or select specific models": "",
 	"Leave empty to use the default prompt, or enter a custom prompt": "",
 	"Leave empty to use the default prompt, or enter a custom prompt": "",
+	"Leave model field empty to use the default model.": "",
 	"Light": "Светъл",
 	"Light": "Светъл",
 	"Listening...": "",
 	"Listening...": "",
 	"Llama.cpp": "",
 	"Llama.cpp": "",
 	"LLMs can make mistakes. Verify important information.": "LLMs могат да правят грешки. Проверете важните данни.",
 	"LLMs can make mistakes. Verify important information.": "LLMs могат да правят грешки. Проверете важните данни.",
+	"Loading Kokoro.js...": "",
 	"Local": "",
 	"Local": "",
 	"Local Models": "",
 	"Local Models": "",
 	"Lost": "",
 	"Lost": "",
 	"LTR": "LTR",
 	"LTR": "LTR",
-	"Made by OpenWebUI Community": "Направено от OpenWebUI общността",
+	"Made by Open WebUI Community": "Направено от OpenWebUI общността",
 	"Make sure to enclose them with": "Уверете се, че са заключени с",
 	"Make sure to enclose them with": "Уверете се, че са заключени с",
 	"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.": "",
 	"Manage": "",
 	"Manage": "",
 	"Manage Arena Models": "",
 	"Manage Arena Models": "",
+	"Manage Direct Connections": "",
 	"Manage Models": "",
 	"Manage Models": "",
 	"Manage Ollama": "",
 	"Manage Ollama": "",
 	"Manage Ollama API Connections": "",
 	"Manage Ollama API Connections": "",
@@ -722,6 +745,7 @@
 	"Plain text (.txt)": "Plain text (.txt)",
 	"Plain text (.txt)": "Plain text (.txt)",
 	"Playground": "Плейграунд",
 	"Playground": "Плейграунд",
 	"Please carefully review the following warnings:": "",
 	"Please carefully review the following warnings:": "",
+	"Please do not close the settings page while loading the model.": "",
 	"Please enter a prompt": "",
 	"Please enter a prompt": "",
 	"Please fill in all fields.": "",
 	"Please fill in all fields.": "",
 	"Please select a model first.": "",
 	"Please select a model first.": "",
@@ -754,7 +778,7 @@
 	"Read Aloud": "Прочети на Голос",
 	"Read Aloud": "Прочети на Голос",
 	"Reasoning Effort": "",
 	"Reasoning Effort": "",
 	"Record voice": "Записване на глас",
 	"Record voice": "Записване на глас",
-	"Redirecting you to OpenWebUI Community": "Пренасочване към OpenWebUI общността",
+	"Redirecting you to Open WebUI Community": "Пренасочване към OpenWebUI общността",
 	"Reduces the probability of generating nonsense. A higher value (e.g. 100) will give more diverse answers, while a lower value (e.g. 10) will be more conservative. (Default: 40)": "",
 	"Reduces the probability of generating nonsense. A higher value (e.g. 100) will give more diverse answers, while a lower value (e.g. 10) will be more conservative. (Default: 40)": "",
 	"Refer to yourself as \"User\" (e.g., \"User is learning Spanish\")": "",
 	"Refer to yourself as \"User\" (e.g., \"User is learning Spanish\")": "",
 	"References from": "",
 	"References from": "",
@@ -829,6 +853,7 @@
 	"Select a pipeline": "Изберете тръбопровод",
 	"Select a pipeline": "Изберете тръбопровод",
 	"Select a pipeline url": "Избор на URL адрес на канал",
 	"Select a pipeline url": "Избор на URL адрес на канал",
 	"Select a tool": "",
 	"Select a tool": "",
+	"Select an auth method": "",
 	"Select an Ollama instance": "",
 	"Select an Ollama instance": "",
 	"Select Engine": "",
 	"Select Engine": "",
 	"Select Knowledge": "",
 	"Select Knowledge": "",
@@ -869,7 +894,7 @@
 	"Settings saved successfully!": "Настройките са запазени успешно!",
 	"Settings saved successfully!": "Настройките са запазени успешно!",
 	"Share": "Подели",
 	"Share": "Подели",
 	"Share Chat": "Подели Чат",
 	"Share Chat": "Подели Чат",
-	"Share to OpenWebUI Community": "Споделите с OpenWebUI Общността",
+	"Share to Open WebUI Community": "Споделите с OpenWebUI Общността",
 	"Show": "Покажи",
 	"Show": "Покажи",
 	"Show \"What's New\" modal on login": "",
 	"Show \"What's New\" modal on login": "",
 	"Show Admin Details in Account Pending Overlay": "",
 	"Show Admin Details in Account Pending Overlay": "",
@@ -944,6 +969,7 @@
 	"This will reset the knowledge base and sync all files. Do you wish to continue?": "",
 	"This will reset the knowledge base and sync all files. Do you wish to continue?": "",
 	"Thorough explanation": "Това е подробно описание.",
 	"Thorough explanation": "Това е подробно описание.",
 	"Thought for {{DURATION}}": "",
 	"Thought for {{DURATION}}": "",
+	"Thought for {{DURATION}} seconds": "",
 	"Tika": "",
 	"Tika": "",
 	"Tika Server URL required.": "",
 	"Tika Server URL required.": "",
 	"Tiktoken": "",
 	"Tiktoken": "",

+ 29 - 3
src/lib/i18n/locales/bn-BD/translation.json

@@ -122,6 +122,7 @@
 	"Beta": "",
 	"Beta": "",
 	"Bing Search V7 Endpoint": "",
 	"Bing Search V7 Endpoint": "",
 	"Bing Search V7 Subscription Key": "",
 	"Bing Search V7 Subscription Key": "",
+	"Bocha Search API Key": "",
 	"Brave Search API Key": "সাহসী অনুসন্ধান API কী",
 	"Brave Search API Key": "সাহসী অনুসন্ধান API কী",
 	"By {{name}}": "",
 	"By {{name}}": "",
 	"Bypass SSL verification for Websites": "ওয়েবসাইটের জন্য SSL যাচাই বাতিল করুন",
 	"Bypass SSL verification for Websites": "ওয়েবসাইটের জন্য SSL যাচাই বাতিল করুন",
@@ -163,6 +164,7 @@
 	"Click here to": "এখানে ক্লিক করুন",
 	"Click here to": "এখানে ক্লিক করুন",
 	"Click here to download user import template file.": "",
 	"Click here to download user import template file.": "",
 	"Click here to learn more about faster-whisper and see the available models.": "",
 	"Click here to learn more about faster-whisper and see the available models.": "",
+	"Click here to see available models.": "",
 	"Click here to select": "নির্বাচন করার জন্য এখানে ক্লিক করুন",
 	"Click here to select": "নির্বাচন করার জন্য এখানে ক্লিক করুন",
 	"Click here to select a csv file.": "একটি csv ফাইল নির্বাচন করার জন্য এখানে ক্লিক করুন",
 	"Click here to select a csv file.": "একটি csv ফাইল নির্বাচন করার জন্য এখানে ক্লিক করুন",
 	"Click here to select a py file.": "",
 	"Click here to select a py file.": "",
@@ -177,6 +179,8 @@
 	"Code execution": "",
 	"Code execution": "",
 	"Code formatted successfully": "",
 	"Code formatted successfully": "",
 	"Code Interpreter": "",
 	"Code Interpreter": "",
+	"Code Interpreter Engine": "",
+	"Code Interpreter Prompt Template": "",
 	"Collection": "সংগ্রহ",
 	"Collection": "সংগ্রহ",
 	"Color": "",
 	"Color": "",
 	"ComfyUI": "ComfyUI",
 	"ComfyUI": "ComfyUI",
@@ -193,6 +197,7 @@
 	"Confirm Password": "পাসওয়ার্ড নিশ্চিত করুন",
 	"Confirm Password": "পাসওয়ার্ড নিশ্চিত করুন",
 	"Confirm your action": "",
 	"Confirm your action": "",
 	"Confirm your new password": "",
 	"Confirm your new password": "",
+	"Connect to your own OpenAI compatible API endpoints.": "",
 	"Connections": "কানেকশনগুলো",
 	"Connections": "কানেকশনগুলো",
 	"Constrains effort on reasoning for reasoning models. Only applicable to reasoning models from specific providers that support reasoning effort. (Default: medium)": "",
 	"Constrains effort on reasoning for reasoning models. Only applicable to reasoning models from specific providers that support reasoning effort. (Default: medium)": "",
 	"Contact Admin for WebUI Access": "",
 	"Contact Admin for WebUI Access": "",
@@ -215,6 +220,7 @@
 	"Copy Link": "লিংক কপি করুন",
 	"Copy Link": "লিংক কপি করুন",
 	"Copy to clipboard": "",
 	"Copy to clipboard": "",
 	"Copying to clipboard was successful!": "ক্লিপবোর্ডে কপি করা সফল হয়েছে",
 	"Copying to clipboard was successful!": "ক্লিপবোর্ডে কপি করা সফল হয়েছে",
+	"CORS must be properly configured by the provider to allow requests from Open WebUI.": "",
 	"Create": "",
 	"Create": "",
 	"Create a knowledge base": "",
 	"Create a knowledge base": "",
 	"Create a model": "একটি মডেল তৈরি করুন",
 	"Create a model": "একটি মডেল তৈরি করুন",
@@ -268,6 +274,9 @@
 	"Describe your knowledge base and objectives": "",
 	"Describe your knowledge base and objectives": "",
 	"Description": "বিবরণ",
 	"Description": "বিবরণ",
 	"Didn't fully follow instructions": "ইনস্ট্রাকশন সম্পূর্ণ অনুসরণ করা হয়নি",
 	"Didn't fully follow instructions": "ইনস্ট্রাকশন সম্পূর্ণ অনুসরণ করা হয়নি",
+	"Direct Connections": "",
+	"Direct Connections allow users to connect to their own OpenAI compatible API endpoints.": "",
+	"Direct Connections settings updated": "",
 	"Disabled": "",
 	"Disabled": "",
 	"Discover a function": "",
 	"Discover a function": "",
 	"Discover a model": "একটি মডেল আবিষ্কার করুন",
 	"Discover a model": "একটি মডেল আবিষ্কার করুন",
@@ -290,6 +299,7 @@
 	"Documentation": "",
 	"Documentation": "",
 	"Documents": "ডকুমেন্টসমূহ",
 	"Documents": "ডকুমেন্টসমূহ",
 	"does not make any external connections, and your data stays securely on your locally hosted server.": "কোন এক্সটার্নাল কানেকশন তৈরি করে না, এবং আপনার ডেটা আর লোকালি হোস্টেড সার্ভারেই নিরাপদে থাকে।",
 	"does not make any external connections, and your data stays securely on your locally hosted server.": "কোন এক্সটার্নাল কানেকশন তৈরি করে না, এবং আপনার ডেটা আর লোকালি হোস্টেড সার্ভারেই নিরাপদে থাকে।",
+	"Domain Filter List": "",
 	"Don't have an account?": "একাউন্ট নেই?",
 	"Don't have an account?": "একাউন্ট নেই?",
 	"don't install random functions from sources you don't trust.": "",
 	"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 tools from sources you don't trust.": "",
@@ -325,6 +335,7 @@
 	"Embedding model set to \"{{embedding_model}}\"": "ইমেজ ইমেবডিং মডেল সেট করা হয়েছে - \"{{embedding_model}}\"",
 	"Embedding model set to \"{{embedding_model}}\"": "ইমেজ ইমেবডিং মডেল সেট করা হয়েছে - \"{{embedding_model}}\"",
 	"Enable API Key": "",
 	"Enable API Key": "",
 	"Enable autocomplete generation for chat messages": "",
 	"Enable autocomplete generation for chat messages": "",
+	"Enable Code Interpreter": "",
 	"Enable Community Sharing": "সম্প্রদায় শেয়ারকরণ সক্ষম করুন",
 	"Enable Community Sharing": "সম্প্রদায় শেয়ারকরণ সক্ষম করুন",
 	"Enable Google Drive": "",
 	"Enable Google Drive": "",
 	"Enable Memory Locking (mlock) to prevent model data from being swapped out of RAM. This option locks the model's working set of pages into RAM, ensuring that they will not be swapped out to disk. This can help maintain performance by avoiding page faults and ensuring fast data access.": "",
 	"Enable Memory Locking (mlock) to prevent model data from being swapped out of RAM. This option locks the model's working set of pages into RAM, ensuring that they will not be swapped out to disk. This can help maintain performance by avoiding page faults and ensuring fast data access.": "",
@@ -343,18 +354,23 @@
 	"Enter Application DN Password": "",
 	"Enter Application DN Password": "",
 	"Enter Bing Search V7 Endpoint": "",
 	"Enter Bing Search V7 Endpoint": "",
 	"Enter Bing Search V7 Subscription Key": "",
 	"Enter Bing Search V7 Subscription Key": "",
+	"Enter Bocha Search API Key": "",
 	"Enter Brave Search API Key": "সাহসী অনুসন্ধান API কী লিখুন",
 	"Enter Brave Search API Key": "সাহসী অনুসন্ধান API কী লিখুন",
 	"Enter certificate path": "",
 	"Enter certificate path": "",
 	"Enter CFG Scale (e.g. 7.0)": "",
 	"Enter CFG Scale (e.g. 7.0)": "",
 	"Enter Chunk Overlap": "চাঙ্ক ওভারল্যাপ লিখুন",
 	"Enter Chunk Overlap": "চাঙ্ক ওভারল্যাপ লিখুন",
 	"Enter Chunk Size": "চাংক সাইজ লিখুন",
 	"Enter Chunk Size": "চাংক সাইজ লিখুন",
 	"Enter description": "",
 	"Enter description": "",
+	"Enter domains separated by commas (e.g., example.com,site.org)": "",
 	"Enter Exa API Key": "",
 	"Enter Exa API Key": "",
 	"Enter Github Raw URL": "গিটহাব কাঁচা URL লিখুন",
 	"Enter Github Raw URL": "গিটহাব কাঁচা URL লিখুন",
 	"Enter Google PSE API Key": "গুগল পিএসই এপিআই কী লিখুন",
 	"Enter Google PSE API Key": "গুগল পিএসই এপিআই কী লিখুন",
 	"Enter Google PSE Engine Id": "গুগল পিএসই ইঞ্জিন আইডি লিখুন",
 	"Enter Google PSE Engine Id": "গুগল পিএসই ইঞ্জিন আইডি লিখুন",
 	"Enter Image Size (e.g. 512x512)": "ছবির মাপ লিখুন (যেমন 512x512)",
 	"Enter Image Size (e.g. 512x512)": "ছবির মাপ লিখুন (যেমন 512x512)",
 	"Enter Jina API Key": "",
 	"Enter Jina API Key": "",
+	"Enter Jupyter Password": "",
+	"Enter Jupyter Token": "",
+	"Enter Jupyter URL": "",
 	"Enter Kagi Search API Key": "",
 	"Enter Kagi Search API Key": "",
 	"Enter language codes": "ল্যাঙ্গুয়েজ কোড লিখুন",
 	"Enter language codes": "ল্যাঙ্গুয়েজ কোড লিখুন",
 	"Enter Model ID": "",
 	"Enter Model ID": "",
@@ -540,6 +556,8 @@
 	"JSON Preview": "JSON প্রিভিউ",
 	"JSON Preview": "JSON প্রিভিউ",
 	"July": "জুলাই",
 	"July": "জুলাই",
 	"June": "জুন",
 	"June": "জুন",
+	"Jupyter Auth": "",
+	"Jupyter URL": "",
 	"JWT Expiration": "JWT-র মেয়াদ",
 	"JWT Expiration": "JWT-র মেয়াদ",
 	"JWT Token": "JWT টোকেন",
 	"JWT Token": "JWT টোকেন",
 	"Kagi Search API Key": "",
 	"Kagi Search API Key": "",
@@ -552,6 +570,8 @@
 	"Knowledge deleted successfully.": "",
 	"Knowledge deleted successfully.": "",
 	"Knowledge reset successfully.": "",
 	"Knowledge reset successfully.": "",
 	"Knowledge updated successfully": "",
 	"Knowledge updated successfully": "",
+	"Kokoro.js (Browser)": "",
+	"Kokoro.js Dtype": "",
 	"Label": "",
 	"Label": "",
 	"Landing Page Mode": "",
 	"Landing Page Mode": "",
 	"Language": "ভাষা",
 	"Language": "ভাষা",
@@ -566,19 +586,22 @@
 	"Leave empty to include all models from \"{{URL}}/models\" endpoint": "",
 	"Leave empty to include all models from \"{{URL}}/models\" endpoint": "",
 	"Leave empty to include all models or select specific models": "",
 	"Leave empty to include all models or select specific models": "",
 	"Leave empty to use the default prompt, or enter a custom prompt": "",
 	"Leave empty to use the default prompt, or enter a custom prompt": "",
+	"Leave model field empty to use the default model.": "",
 	"Light": "লাইট",
 	"Light": "লাইট",
 	"Listening...": "",
 	"Listening...": "",
 	"Llama.cpp": "",
 	"Llama.cpp": "",
 	"LLMs can make mistakes. Verify important information.": "LLM ভুল করতে পারে। গুরুত্বপূর্ণ তথ্য যাচাই করে নিন।",
 	"LLMs can make mistakes. Verify important information.": "LLM ভুল করতে পারে। গুরুত্বপূর্ণ তথ্য যাচাই করে নিন।",
+	"Loading Kokoro.js...": "",
 	"Local": "",
 	"Local": "",
 	"Local Models": "",
 	"Local Models": "",
 	"Lost": "",
 	"Lost": "",
 	"LTR": "LTR",
 	"LTR": "LTR",
-	"Made by OpenWebUI Community": "OpenWebUI কমিউনিটিকর্তৃক নির্মিত",
+	"Made by Open WebUI Community": "OpenWebUI কমিউনিটিকর্তৃক নির্মিত",
 	"Make sure to enclose them with": "এটা দিয়ে বন্ধনী দিতে ভুলবেন না",
 	"Make sure to enclose them with": "এটা দিয়ে বন্ধনী দিতে ভুলবেন না",
 	"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.": "",
 	"Manage": "",
 	"Manage": "",
 	"Manage Arena Models": "",
 	"Manage Arena Models": "",
+	"Manage Direct Connections": "",
 	"Manage Models": "",
 	"Manage Models": "",
 	"Manage Ollama": "",
 	"Manage Ollama": "",
 	"Manage Ollama API Connections": "",
 	"Manage Ollama API Connections": "",
@@ -722,6 +745,7 @@
 	"Plain text (.txt)": "প্লায়েন টেক্সট (.txt)",
 	"Plain text (.txt)": "প্লায়েন টেক্সট (.txt)",
 	"Playground": "খেলাঘর",
 	"Playground": "খেলাঘর",
 	"Please carefully review the following warnings:": "",
 	"Please carefully review the following warnings:": "",
+	"Please do not close the settings page while loading the model.": "",
 	"Please enter a prompt": "",
 	"Please enter a prompt": "",
 	"Please fill in all fields.": "",
 	"Please fill in all fields.": "",
 	"Please select a model first.": "",
 	"Please select a model first.": "",
@@ -754,7 +778,7 @@
 	"Read Aloud": "পড়াশোনা করুন",
 	"Read Aloud": "পড়াশোনা করুন",
 	"Reasoning Effort": "",
 	"Reasoning Effort": "",
 	"Record voice": "ভয়েস রেকর্ড করুন",
 	"Record voice": "ভয়েস রেকর্ড করুন",
-	"Redirecting you to OpenWebUI Community": "আপনাকে OpenWebUI কমিউনিটিতে পাঠানো হচ্ছে",
+	"Redirecting you to Open WebUI Community": "আপনাকে OpenWebUI কমিউনিটিতে পাঠানো হচ্ছে",
 	"Reduces the probability of generating nonsense. A higher value (e.g. 100) will give more diverse answers, while a lower value (e.g. 10) will be more conservative. (Default: 40)": "",
 	"Reduces the probability of generating nonsense. A higher value (e.g. 100) will give more diverse answers, while a lower value (e.g. 10) will be more conservative. (Default: 40)": "",
 	"Refer to yourself as \"User\" (e.g., \"User is learning Spanish\")": "",
 	"Refer to yourself as \"User\" (e.g., \"User is learning Spanish\")": "",
 	"References from": "",
 	"References from": "",
@@ -829,6 +853,7 @@
 	"Select a pipeline": "একটি পাইপলাইন নির্বাচন করুন",
 	"Select a pipeline": "একটি পাইপলাইন নির্বাচন করুন",
 	"Select a pipeline url": "একটি পাইপলাইন URL নির্বাচন করুন",
 	"Select a pipeline url": "একটি পাইপলাইন URL নির্বাচন করুন",
 	"Select a tool": "",
 	"Select a tool": "",
+	"Select an auth method": "",
 	"Select an Ollama instance": "",
 	"Select an Ollama instance": "",
 	"Select Engine": "",
 	"Select Engine": "",
 	"Select Knowledge": "",
 	"Select Knowledge": "",
@@ -869,7 +894,7 @@
 	"Settings saved successfully!": "সেটিংগুলো সফলভাবে সংরক্ষিত হয়েছে",
 	"Settings saved successfully!": "সেটিংগুলো সফলভাবে সংরক্ষিত হয়েছে",
 	"Share": "শেয়ার করুন",
 	"Share": "শেয়ার করুন",
 	"Share Chat": "চ্যাট শেয়ার করুন",
 	"Share Chat": "চ্যাট শেয়ার করুন",
-	"Share to OpenWebUI Community": "OpenWebUI কমিউনিটিতে শেয়ার করুন",
+	"Share to Open WebUI Community": "OpenWebUI কমিউনিটিতে শেয়ার করুন",
 	"Show": "দেখান",
 	"Show": "দেখান",
 	"Show \"What's New\" modal on login": "",
 	"Show \"What's New\" modal on login": "",
 	"Show Admin Details in Account Pending Overlay": "",
 	"Show Admin Details in Account Pending Overlay": "",
@@ -944,6 +969,7 @@
 	"This will reset the knowledge base and sync all files. Do you wish to continue?": "",
 	"This will reset the knowledge base and sync all files. Do you wish to continue?": "",
 	"Thorough explanation": "পুঙ্খানুপুঙ্খ ব্যাখ্যা",
 	"Thorough explanation": "পুঙ্খানুপুঙ্খ ব্যাখ্যা",
 	"Thought for {{DURATION}}": "",
 	"Thought for {{DURATION}}": "",
+	"Thought for {{DURATION}} seconds": "",
 	"Tika": "",
 	"Tika": "",
 	"Tika Server URL required.": "",
 	"Tika Server URL required.": "",
 	"Tiktoken": "",
 	"Tiktoken": "",

+ 48 - 22
src/lib/i18n/locales/ca-ES/translation.json

@@ -63,11 +63,11 @@
 	"Allowed Endpoints": "Punts d'accés permesos",
 	"Allowed Endpoints": "Punts d'accés permesos",
 	"Already have an account?": "Ja tens un compte?",
 	"Already have an account?": "Ja tens un compte?",
 	"Alternative to the top_p, and aims to ensure a balance of quality and variety. The parameter p represents the minimum probability for a token to be considered, relative to the probability of the most likely token. For example, with p=0.05 and the most likely token having a probability of 0.9, logits with a value less than 0.045 are filtered out. (Default: 0.0)": "Alternativa al top_p, i pretén garantir un equilibri de qualitat i varietat. El paràmetre p representa la probabilitat mínima que es consideri un token, en relació amb la probabilitat del token més probable. Per exemple, amb p=0,05 i el token més probable amb una probabilitat de 0,9, es filtren els logits amb un valor inferior a 0,045. (Per defecte: 0.0)",
 	"Alternative to the top_p, and aims to ensure a balance of quality and variety. The parameter p represents the minimum probability for a token to be considered, relative to the probability of the most likely token. For example, with p=0.05 and the most likely token having a probability of 0.9, logits with a value less than 0.045 are filtered out. (Default: 0.0)": "Alternativa al top_p, i pretén garantir un equilibri de qualitat i varietat. El paràmetre p representa la probabilitat mínima que es consideri un token, en relació amb la probabilitat del token més probable. Per exemple, amb p=0,05 i el token més probable amb una probabilitat de 0,9, es filtren els logits amb un valor inferior a 0,045. (Per defecte: 0.0)",
-	"Always": "",
+	"Always": "Sempre",
 	"Amazing": "Al·lucinant",
 	"Amazing": "Al·lucinant",
 	"an assistant": "un assistent",
 	"an assistant": "un assistent",
-	"Analyzed": "",
-	"Analyzing...": "",
+	"Analyzed": "Analitzat",
+	"Analyzing...": "Analitzant...",
 	"and": "i",
 	"and": "i",
 	"and {{COUNT}} more": "i {{COUNT}} més",
 	"and {{COUNT}} more": "i {{COUNT}} més",
 	"and create a new shared link.": "i crear un nou enllaç compartit.",
 	"and create a new shared link.": "i crear un nou enllaç compartit.",
@@ -122,6 +122,7 @@
 	"Beta": "Beta",
 	"Beta": "Beta",
 	"Bing Search V7 Endpoint": "Punt de connexió a Bing Search V7",
 	"Bing Search V7 Endpoint": "Punt de connexió a Bing Search V7",
 	"Bing Search V7 Subscription Key": "Clau de subscripció a Bing Search V7",
 	"Bing Search V7 Subscription Key": "Clau de subscripció a Bing Search V7",
+	"Bocha Search API Key": "",
 	"Brave Search API Key": "Clau API de Brave Search",
 	"Brave Search API Key": "Clau API de Brave Search",
 	"By {{name}}": "Per {{name}}",
 	"By {{name}}": "Per {{name}}",
 	"Bypass SSL verification for Websites": "Desactivar la verificació SSL per a l'accés a Internet",
 	"Bypass SSL verification for Websites": "Desactivar la verificació SSL per a l'accés a Internet",
@@ -163,6 +164,7 @@
 	"Click here to": "Clic aquí per",
 	"Click here to": "Clic aquí per",
 	"Click here to download user import template file.": "Fes clic aquí per descarregar l'arxiu de plantilla d'importació d'usuaris",
 	"Click here to download user import template file.": "Fes clic aquí per descarregar l'arxiu de plantilla d'importació d'usuaris",
 	"Click here to learn more about faster-whisper and see the available models.": "Clica aquí per obtenir més informació sobre faster-whisper i veure els models disponibles.",
 	"Click here to learn more about faster-whisper and see the available models.": "Clica aquí per obtenir més informació sobre faster-whisper i veure els models disponibles.",
+	"Click here to see available models.": "Clica aquí per veure els models disponibles.",
 	"Click here to select": "Clica aquí per seleccionar",
 	"Click here to select": "Clica aquí per seleccionar",
 	"Click here to select a csv file.": "Clica aquí per seleccionar un fitxer csv.",
 	"Click here to select a csv file.": "Clica aquí per seleccionar un fitxer csv.",
 	"Click here to select a py file.": "Clica aquí per seleccionar un fitxer py.",
 	"Click here to select a py file.": "Clica aquí per seleccionar un fitxer py.",
@@ -172,11 +174,13 @@
 	"Clipboard write permission denied. Please check your browser settings to grant the necessary access.": "Permís d'escriptura al porta-retalls denegat. Comprova els ajustos de navegador per donar l'accés necessari.",
 	"Clipboard write permission denied. Please check your browser settings to grant the necessary access.": "Permís d'escriptura al porta-retalls denegat. Comprova els ajustos de navegador per donar l'accés necessari.",
 	"Clone": "Clonar",
 	"Clone": "Clonar",
 	"Clone Chat": "Clonar el xat",
 	"Clone Chat": "Clonar el xat",
-	"Clone of {{TITLE}}": "",
+	"Clone of {{TITLE}}": "Clon de {{TITLE}}",
 	"Close": "Tancar",
 	"Close": "Tancar",
 	"Code execution": "Execució de codi",
 	"Code execution": "Execució de codi",
 	"Code formatted successfully": "Codi formatat correctament",
 	"Code formatted successfully": "Codi formatat correctament",
-	"Code Interpreter": "",
+	"Code Interpreter": "Intèrpret de codi",
+	"Code Interpreter Engine": "",
+	"Code Interpreter Prompt Template": "",
 	"Collection": "Col·lecció",
 	"Collection": "Col·lecció",
 	"Color": "Color",
 	"Color": "Color",
 	"ComfyUI": "ComfyUI",
 	"ComfyUI": "ComfyUI",
@@ -193,6 +197,7 @@
 	"Confirm Password": "Confirmar la contrasenya",
 	"Confirm Password": "Confirmar la contrasenya",
 	"Confirm your action": "Confirma la teva acció",
 	"Confirm your action": "Confirma la teva acció",
 	"Confirm your new password": "Confirma la teva nova contrasenya",
 	"Confirm your new password": "Confirma la teva nova contrasenya",
+	"Connect to your own OpenAI compatible API endpoints.": "",
 	"Connections": "Connexions",
 	"Connections": "Connexions",
 	"Constrains effort on reasoning for reasoning models. Only applicable to reasoning models from specific providers that support reasoning effort. (Default: medium)": "Restringeix l'esforç de raonament dels models de raonament. Només aplicable a models de raonament de proveïdors específics que donen suport a l'esforç de raonament. (Per defecte: mitjà)",
 	"Constrains effort on reasoning for reasoning models. Only applicable to reasoning models from specific providers that support reasoning effort. (Default: medium)": "Restringeix l'esforç de raonament dels models de raonament. Només aplicable a models de raonament de proveïdors específics que donen suport a l'esforç de raonament. (Per defecte: mitjà)",
 	"Contact Admin for WebUI Access": "Posat en contacte amb l'administrador per accedir a WebUI",
 	"Contact Admin for WebUI Access": "Posat en contacte amb l'administrador per accedir a WebUI",
@@ -215,6 +220,7 @@
 	"Copy Link": "Copiar l'enllaç",
 	"Copy Link": "Copiar l'enllaç",
 	"Copy to clipboard": "Copiar al porta-retalls",
 	"Copy to clipboard": "Copiar al porta-retalls",
 	"Copying to clipboard was successful!": "La còpia al porta-retalls s'ha realitzat correctament",
 	"Copying to clipboard was successful!": "La còpia al porta-retalls s'ha realitzat correctament",
+	"CORS must be properly configured by the provider to allow requests from Open WebUI.": "",
 	"Create": "Crear",
 	"Create": "Crear",
 	"Create a knowledge base": "Crear una base de coneixement",
 	"Create a knowledge base": "Crear una base de coneixement",
 	"Create a model": "Crear un model",
 	"Create a model": "Crear un model",
@@ -238,7 +244,7 @@
 	"Default": "Per defecte",
 	"Default": "Per defecte",
 	"Default (Open AI)": "Per defecte (Open AI)",
 	"Default (Open AI)": "Per defecte (Open AI)",
 	"Default (SentenceTransformers)": "Per defecte (SentenceTransformers)",
 	"Default (SentenceTransformers)": "Per defecte (SentenceTransformers)",
-	"Default mode works with a wider range of models by calling tools once before execution. Native mode leverages the model’s built-in tool-calling capabilities, but requires the model to inherently support this feature.": "",
+	"Default mode works with a wider range of models by calling tools once before execution. Native mode leverages the model’s built-in tool-calling capabilities, but requires the model to inherently support this feature.": "El mode predeterminat funciona amb una gamma més àmplia de models cridant a les eines una vegada abans de l'execució. El mode natiu aprofita les capacitats de crida d'eines integrades del model, però requereix que el model admeti aquesta funció de manera inherent.",
 	"Default Model": "Model per defecte",
 	"Default Model": "Model per defecte",
 	"Default model updated": "Model per defecte actualitzat",
 	"Default model updated": "Model per defecte actualitzat",
 	"Default Models": "Models per defecte",
 	"Default Models": "Models per defecte",
@@ -268,6 +274,9 @@
 	"Describe your knowledge base and objectives": "Descriu la teva base de coneixement i objectius",
 	"Describe your knowledge base and objectives": "Descriu la teva base de coneixement i objectius",
 	"Description": "Descripció",
 	"Description": "Descripció",
 	"Didn't fully follow instructions": "No s'han seguit les instruccions completament",
 	"Didn't fully follow instructions": "No s'han seguit les instruccions completament",
+	"Direct Connections": "",
+	"Direct Connections allow users to connect to their own OpenAI compatible API endpoints.": "",
+	"Direct Connections settings updated": "",
 	"Disabled": "Deshabilitat",
 	"Disabled": "Deshabilitat",
 	"Discover a function": "Descobrir una funció",
 	"Discover a function": "Descobrir una funció",
 	"Discover a model": "Descobrir un model",
 	"Discover a model": "Descobrir un model",
@@ -290,6 +299,7 @@
 	"Documentation": "Documentació",
 	"Documentation": "Documentació",
 	"Documents": "Documents",
 	"Documents": "Documents",
 	"does not make any external connections, and your data stays securely on your locally hosted server.": "no realitza connexions externes, i les teves dades romanen segures al teu servidor allotjat localment.",
 	"does not make any external connections, and your data stays securely on your locally hosted server.": "no realitza connexions externes, i les teves dades romanen segures al teu servidor allotjat localment.",
+	"Domain Filter List": "Llista de filtre de dominis",
 	"Don't have an account?": "No tens un compte?",
 	"Don't have an account?": "No tens un compte?",
 	"don't install random functions from sources you don't trust.": "no instal·lis funcions aleatòries de fonts en què no confiïs.",
 	"don't install random functions from sources you don't trust.": "no instal·lis funcions aleatòries de fonts en què no confiïs.",
 	"don't install random tools from sources you don't trust.": "no instal·lis eines aleatòries de fonts en què no confiïs.",
 	"don't install random tools from sources you don't trust.": "no instal·lis eines aleatòries de fonts en què no confiïs.",
@@ -325,6 +335,7 @@
 	"Embedding model set to \"{{embedding_model}}\"": "Model d'incrustació configurat a \"{{embedding_model}}\"",
 	"Embedding model set to \"{{embedding_model}}\"": "Model d'incrustació configurat a \"{{embedding_model}}\"",
 	"Enable API Key": "Activar la Clau API",
 	"Enable API Key": "Activar la Clau API",
 	"Enable autocomplete generation for chat messages": "Activar la generació automàtica per als missatges del xat",
 	"Enable autocomplete generation for chat messages": "Activar la generació automàtica per als missatges del xat",
+	"Enable Code Interpreter": "",
 	"Enable Community Sharing": "Activar l'ús compartit amb la comunitat",
 	"Enable Community Sharing": "Activar l'ús compartit amb la comunitat",
 	"Enable Google Drive": "Activar Google Drive",
 	"Enable Google Drive": "Activar Google Drive",
 	"Enable Memory Locking (mlock) to prevent model data from being swapped out of RAM. This option locks the model's working set of pages into RAM, ensuring that they will not be swapped out to disk. This can help maintain performance by avoiding page faults and ensuring fast data access.": "Activar el bloqueig de memòria (mlock) per evitar que les dades del model s'intercanviïn fora de la memòria RAM. Aquesta opció bloqueja el conjunt de pàgines de treball del model a la memòria RAM, assegurant-se que no s'intercanviaran al disc. Això pot ajudar a mantenir el rendiment evitant errors de pàgina i garantint un accés ràpid a les dades.",
 	"Enable Memory Locking (mlock) to prevent model data from being swapped out of RAM. This option locks the model's working set of pages into RAM, ensuring that they will not be swapped out to disk. This can help maintain performance by avoiding page faults and ensuring fast data access.": "Activar el bloqueig de memòria (mlock) per evitar que les dades del model s'intercanviïn fora de la memòria RAM. Aquesta opció bloqueja el conjunt de pàgines de treball del model a la memòria RAM, assegurant-se que no s'intercanviaran al disc. Això pot ajudar a mantenir el rendiment evitant errors de pàgina i garantint un accés ràpid a les dades.",
@@ -343,18 +354,23 @@
 	"Enter Application DN Password": "Introdueix la contrasenya del DN d'aplicació",
 	"Enter Application DN Password": "Introdueix la contrasenya del DN d'aplicació",
 	"Enter Bing Search V7 Endpoint": "Introdueix el punt de connexió de Bing Search V7",
 	"Enter Bing Search V7 Endpoint": "Introdueix el punt de connexió de Bing Search V7",
 	"Enter Bing Search V7 Subscription Key": "Introdueix la clau de subscripció de Bing Search V7",
 	"Enter Bing Search V7 Subscription Key": "Introdueix la clau de subscripció de Bing Search V7",
+	"Enter Bocha Search API Key": "",
 	"Enter Brave Search API Key": "Introdueix la clau API de Brave Search",
 	"Enter Brave Search API Key": "Introdueix la clau API de Brave Search",
 	"Enter certificate path": "Introdueix el camí del certificat",
 	"Enter certificate path": "Introdueix el camí del certificat",
 	"Enter CFG Scale (e.g. 7.0)": "Entra l'escala CFG (p.ex. 7.0)",
 	"Enter CFG Scale (e.g. 7.0)": "Entra l'escala CFG (p.ex. 7.0)",
 	"Enter Chunk Overlap": "Introdueix la mida de solapament de blocs",
 	"Enter Chunk Overlap": "Introdueix la mida de solapament de blocs",
 	"Enter Chunk Size": "Introdueix la mida del bloc",
 	"Enter Chunk Size": "Introdueix la mida del bloc",
 	"Enter description": "Introdueix la descripció",
 	"Enter description": "Introdueix la descripció",
-	"Enter Exa API Key": "",
+	"Enter domains separated by commas (e.g., example.com,site.org)": "Introdueix els dominis separats per comes (p. ex. example.com,site.org)",
+	"Enter Exa API Key": "Introdueix la clau API de d'EXA",
 	"Enter Github Raw URL": "Introdueix l'URL en brut de Github",
 	"Enter Github Raw URL": "Introdueix l'URL en brut de Github",
 	"Enter Google PSE API Key": "Introdueix la clau API de Google PSE",
 	"Enter Google PSE API Key": "Introdueix la clau API de Google PSE",
 	"Enter Google PSE Engine Id": "Introdueix l'identificador del motor PSE de Google",
 	"Enter Google PSE Engine Id": "Introdueix l'identificador del motor PSE de Google",
 	"Enter Image Size (e.g. 512x512)": "Introdueix la mida de la imatge (p. ex. 512x512)",
 	"Enter Image Size (e.g. 512x512)": "Introdueix la mida de la imatge (p. ex. 512x512)",
 	"Enter Jina API Key": "Introdueix la clau API de Jina",
 	"Enter Jina API Key": "Introdueix la clau API de Jina",
+	"Enter Jupyter Password": "",
+	"Enter Jupyter Token": "",
+	"Enter Jupyter URL": "",
 	"Enter Kagi Search API Key": "Introdueix la clau API de Kagi Search",
 	"Enter Kagi Search API Key": "Introdueix la clau API de Kagi Search",
 	"Enter language codes": "Introdueix els codis de llenguatge",
 	"Enter language codes": "Introdueix els codis de llenguatge",
 	"Enter Model ID": "Introdueix l'identificador del model",
 	"Enter Model ID": "Introdueix l'identificador del model",
@@ -398,14 +414,14 @@
 	"Error accessing Google Drive: {{error}}": "Error en accedir a Google Drive: {{error}}",
 	"Error accessing Google Drive: {{error}}": "Error en accedir a Google Drive: {{error}}",
 	"Error uploading file: {{error}}": "Error en pujar l'arxiu: {{error}}",
 	"Error uploading file: {{error}}": "Error en pujar l'arxiu: {{error}}",
 	"Evaluations": "Avaluacions",
 	"Evaluations": "Avaluacions",
-	"Exa API Key": "",
+	"Exa API Key": "Clau API d'EXA",
 	"Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Exemple: (&(objectClass=inetOrgPerson)(uid=%s))",
 	"Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Exemple: (&(objectClass=inetOrgPerson)(uid=%s))",
 	"Example: ALL": "Exemple: TOTS",
 	"Example: ALL": "Exemple: TOTS",
 	"Example: mail": "Exemple: mail",
 	"Example: mail": "Exemple: mail",
 	"Example: ou=users,dc=foo,dc=example": "Exemple: ou=users,dc=foo,dc=example",
 	"Example: ou=users,dc=foo,dc=example": "Exemple: ou=users,dc=foo,dc=example",
 	"Example: sAMAccountName or uid or userPrincipalName": "Exemple: sAMAccountName o uid o userPrincipalName",
 	"Example: sAMAccountName or uid or userPrincipalName": "Exemple: sAMAccountName o uid o userPrincipalName",
 	"Exclude": "Excloure",
 	"Exclude": "Excloure",
-	"Execute code for analysis": "",
+	"Execute code for analysis": "Executa el codi per analitzar-lo",
 	"Experimental": "Experimental",
 	"Experimental": "Experimental",
 	"Explore the cosmos": "Explorar el cosmos",
 	"Explore the cosmos": "Explorar el cosmos",
 	"Export": "Exportar",
 	"Export": "Exportar",
@@ -458,7 +474,7 @@
 	"Format your variables using brackets like this:": "Formata les teves variables utilitzant claudàtors així:",
 	"Format your variables using brackets like this:": "Formata les teves variables utilitzant claudàtors així:",
 	"Frequency Penalty": "Penalització per freqüència",
 	"Frequency Penalty": "Penalització per freqüència",
 	"Function": "Funció",
 	"Function": "Funció",
-	"Function Calling": "",
+	"Function Calling": "Crida a funcions",
 	"Function created successfully": "La funció s'ha creat correctament",
 	"Function created successfully": "La funció s'ha creat correctament",
 	"Function deleted successfully": "La funció s'ha eliminat correctament",
 	"Function deleted successfully": "La funció s'ha eliminat correctament",
 	"Function Description": "Descripció de la funció",
 	"Function Description": "Descripció de la funció",
@@ -473,7 +489,7 @@
 	"Functions imported successfully": "Les funcions s'han importat correctament",
 	"Functions imported successfully": "Les funcions s'han importat correctament",
 	"General": "General",
 	"General": "General",
 	"General Settings": "Preferències generals",
 	"General Settings": "Preferències generals",
-	"Generate an image": "",
+	"Generate an image": "Generar una imatge",
 	"Generate Image": "Generar imatge",
 	"Generate Image": "Generar imatge",
 	"Generating search query": "Generant consulta",
 	"Generating search query": "Generant consulta",
 	"Get started": "Començar",
 	"Get started": "Començar",
@@ -540,6 +556,8 @@
 	"JSON Preview": "Vista prèvia del document JSON",
 	"JSON Preview": "Vista prèvia del document JSON",
 	"July": "Juliol",
 	"July": "Juliol",
 	"June": "Juny",
 	"June": "Juny",
+	"Jupyter Auth": "",
+	"Jupyter URL": "",
 	"JWT Expiration": "Caducitat del JWT",
 	"JWT Expiration": "Caducitat del JWT",
 	"JWT Token": "Token JWT",
 	"JWT Token": "Token JWT",
 	"Kagi Search API Key": "Clau API de Kagi Search",
 	"Kagi Search API Key": "Clau API de Kagi Search",
@@ -552,6 +570,8 @@
 	"Knowledge deleted successfully.": "Coneixement eliminat correctament.",
 	"Knowledge deleted successfully.": "Coneixement eliminat correctament.",
 	"Knowledge reset successfully.": "Coneixement restablert correctament.",
 	"Knowledge reset successfully.": "Coneixement restablert correctament.",
 	"Knowledge updated successfully": "Coneixement actualitzat correctament.",
 	"Knowledge updated successfully": "Coneixement actualitzat correctament.",
+	"Kokoro.js (Browser)": "Kokoro.js (Navegador)",
+	"Kokoro.js Dtype": "Kokoro.js Dtype",
 	"Label": "Etiqueta",
 	"Label": "Etiqueta",
 	"Landing Page Mode": "Mode de la pàgina d'entrada",
 	"Landing Page Mode": "Mode de la pàgina d'entrada",
 	"Language": "Idioma",
 	"Language": "Idioma",
@@ -566,19 +586,22 @@
 	"Leave empty to include all models from \"{{URL}}/models\" endpoint": "Deixar-ho buit per incloure tots els models del punt de connexió \"{{URL}}/models\"",
 	"Leave empty to include all models from \"{{URL}}/models\" endpoint": "Deixar-ho buit per incloure tots els models del punt de connexió \"{{URL}}/models\"",
 	"Leave empty to include all models or select specific models": "Deixa-ho en blanc per incloure tots els models o selecciona models específics",
 	"Leave empty to include all models or select specific models": "Deixa-ho en blanc per incloure tots els models o selecciona models específics",
 	"Leave empty to use the default prompt, or enter a custom prompt": "Deixa-ho en blanc per utilitzar la indicació predeterminada o introdueix una indicació personalitzada",
 	"Leave empty to use the default prompt, or enter a custom prompt": "Deixa-ho en blanc per utilitzar la indicació predeterminada o introdueix una indicació personalitzada",
+	"Leave model field empty to use the default model.": "Deixa el camp de model buit per utilitzar el model per defecte.",
 	"Light": "Clar",
 	"Light": "Clar",
 	"Listening...": "Escoltant...",
 	"Listening...": "Escoltant...",
 	"Llama.cpp": "Llama.cpp",
 	"Llama.cpp": "Llama.cpp",
 	"LLMs can make mistakes. Verify important information.": "Els models de llenguatge poden cometre errors. Verifica la informació important.",
 	"LLMs can make mistakes. Verify important information.": "Els models de llenguatge poden cometre errors. Verifica la informació important.",
+	"Loading Kokoro.js...": "",
 	"Local": "Local",
 	"Local": "Local",
 	"Local Models": "Models locals",
 	"Local Models": "Models locals",
 	"Lost": "Perdut",
 	"Lost": "Perdut",
 	"LTR": "LTR",
 	"LTR": "LTR",
-	"Made by OpenWebUI Community": "Creat per la Comunitat OpenWebUI",
+	"Made by Open WebUI Community": "Creat per la Comunitat OpenWebUI",
 	"Make sure to enclose them with": "Assegura't d'envoltar-los amb",
 	"Make sure to enclose them with": "Assegura't d'envoltar-los amb",
 	"Make sure to export a workflow.json file as API format from ComfyUI.": "Assegura't d'exportar un fitxer workflow.json com a format API des de ComfyUI.",
 	"Make sure to export a workflow.json file as API format from ComfyUI.": "Assegura't d'exportar un fitxer workflow.json com a format API des de ComfyUI.",
 	"Manage": "Gestionar",
 	"Manage": "Gestionar",
 	"Manage Arena Models": "Gestionar els models de l'Arena",
 	"Manage Arena Models": "Gestionar els models de l'Arena",
+	"Manage Direct Connections": "",
 	"Manage Models": "Gestionar els models",
 	"Manage Models": "Gestionar els models",
 	"Manage Ollama": "Gestionar Ollama",
 	"Manage Ollama": "Gestionar Ollama",
 	"Manage Ollama API Connections": "Gestionar les connexions a l'API d'Ollama",
 	"Manage Ollama API Connections": "Gestionar les connexions a l'API d'Ollama",
@@ -630,7 +653,7 @@
 	"More": "Més",
 	"More": "Més",
 	"Name": "Nom",
 	"Name": "Nom",
 	"Name your knowledge base": "Anomena la teva base de coneixement",
 	"Name your knowledge base": "Anomena la teva base de coneixement",
-	"Native": "",
+	"Native": "Natiu",
 	"New Chat": "Nou xat",
 	"New Chat": "Nou xat",
 	"New Folder": "Nova carpeta",
 	"New Folder": "Nova carpeta",
 	"New Password": "Nova contrasenya",
 	"New Password": "Nova contrasenya",
@@ -722,10 +745,11 @@
 	"Plain text (.txt)": "Text pla (.txt)",
 	"Plain text (.txt)": "Text pla (.txt)",
 	"Playground": "Zona de jocs",
 	"Playground": "Zona de jocs",
 	"Please carefully review the following warnings:": "Si us plau, revisa els següents avisos amb cura:",
 	"Please carefully review the following warnings:": "Si us plau, revisa els següents avisos amb cura:",
+	"Please do not close the settings page while loading the model.": "",
 	"Please enter a prompt": "Si us plau, entra una indicació",
 	"Please enter a prompt": "Si us plau, entra una indicació",
 	"Please fill in all fields.": "Emplena tots els camps, si us plau.",
 	"Please fill in all fields.": "Emplena tots els camps, si us plau.",
 	"Please select a model first.": "Si us plau, selecciona un model primer",
 	"Please select a model first.": "Si us plau, selecciona un model primer",
-	"Please select a model.": "",
+	"Please select a model.": "Si us plau, selecciona un model.",
 	"Please select a reason": "Si us plau, selecciona una raó",
 	"Please select a reason": "Si us plau, selecciona una raó",
 	"Port": "Port",
 	"Port": "Port",
 	"Positive attitude": "Actitud positiva",
 	"Positive attitude": "Actitud positiva",
@@ -734,7 +758,7 @@
 	"Previous 30 days": "30 dies anteriors",
 	"Previous 30 days": "30 dies anteriors",
 	"Previous 7 days": "7 dies anteriors",
 	"Previous 7 days": "7 dies anteriors",
 	"Profile Image": "Imatge de perfil",
 	"Profile Image": "Imatge de perfil",
-	"Prompt": "",
+	"Prompt": "Indicació",
 	"Prompt (e.g. Tell me a fun fact about the Roman Empire)": "Indicació (p.ex. Digues-me quelcom divertit sobre l'Imperi Romà)",
 	"Prompt (e.g. Tell me a fun fact about the Roman Empire)": "Indicació (p.ex. Digues-me quelcom divertit sobre l'Imperi Romà)",
 	"Prompt Content": "Contingut de la indicació",
 	"Prompt Content": "Contingut de la indicació",
 	"Prompt created successfully": "Indicació creada correctament",
 	"Prompt created successfully": "Indicació creada correctament",
@@ -754,7 +778,7 @@
 	"Read Aloud": "Llegir en veu alta",
 	"Read Aloud": "Llegir en veu alta",
 	"Reasoning Effort": "Esforç de raonament",
 	"Reasoning Effort": "Esforç de raonament",
 	"Record voice": "Enregistrar la veu",
 	"Record voice": "Enregistrar la veu",
-	"Redirecting you to OpenWebUI Community": "Redirigint-te a la comunitat OpenWebUI",
+	"Redirecting you to Open WebUI Community": "Redirigint-te a la comunitat OpenWebUI",
 	"Reduces the probability of generating nonsense. A higher value (e.g. 100) will give more diverse answers, while a lower value (e.g. 10) will be more conservative. (Default: 40)": "Redueix la probabilitat de generar ximpleries. Un valor més alt (p. ex. 100) donarà respostes més diverses, mentre que un valor més baix (p. ex. 10) serà més conservador. (Per defecte: 40)",
 	"Reduces the probability of generating nonsense. A higher value (e.g. 100) will give more diverse answers, while a lower value (e.g. 10) will be more conservative. (Default: 40)": "Redueix la probabilitat de generar ximpleries. Un valor més alt (p. ex. 100) donarà respostes més diverses, mentre que un valor més baix (p. ex. 10) serà més conservador. (Per defecte: 40)",
 	"Refer to yourself as \"User\" (e.g., \"User is learning Spanish\")": "Fes referència a tu mateix com a \"Usuari\" (p. ex., \"L'usuari està aprenent espanyol\")",
 	"Refer to yourself as \"User\" (e.g., \"User is learning Spanish\")": "Fes referència a tu mateix com a \"Usuari\" (p. ex., \"L'usuari està aprenent espanyol\")",
 	"References from": "Referències de",
 	"References from": "Referències de",
@@ -810,7 +834,7 @@
 	"Search options": "Opcions de cerca",
 	"Search options": "Opcions de cerca",
 	"Search Prompts": "Cercar indicacions",
 	"Search Prompts": "Cercar indicacions",
 	"Search Result Count": "Recompte de resultats de cerca",
 	"Search Result Count": "Recompte de resultats de cerca",
-	"Search the internet": "",
+	"Search the internet": "Cerca a internet",
 	"Search Tools": "Cercar eines",
 	"Search Tools": "Cercar eines",
 	"SearchApi API Key": "Clau API de SearchApi",
 	"SearchApi API Key": "Clau API de SearchApi",
 	"SearchApi Engine": "Motor de SearchApi",
 	"SearchApi Engine": "Motor de SearchApi",
@@ -829,6 +853,7 @@
 	"Select a pipeline": "Seleccionar una Pipeline",
 	"Select a pipeline": "Seleccionar una Pipeline",
 	"Select a pipeline url": "Seleccionar l'URL d'una Pipeline",
 	"Select a pipeline url": "Seleccionar l'URL d'una Pipeline",
 	"Select a tool": "Seleccionar una eina",
 	"Select a tool": "Seleccionar una eina",
+	"Select an auth method": "",
 	"Select an Ollama instance": "Seleccionar una instància d'Ollama",
 	"Select an Ollama instance": "Seleccionar una instància d'Ollama",
 	"Select Engine": "Seleccionar el motor",
 	"Select Engine": "Seleccionar el motor",
 	"Select Knowledge": "Seleccionar coneixement",
 	"Select Knowledge": "Seleccionar coneixement",
@@ -869,7 +894,7 @@
 	"Settings saved successfully!": "Les preferències s'han desat correctament",
 	"Settings saved successfully!": "Les preferències s'han desat correctament",
 	"Share": "Compartir",
 	"Share": "Compartir",
 	"Share Chat": "Compartir el xat",
 	"Share Chat": "Compartir el xat",
-	"Share to OpenWebUI Community": "Compartir amb la comunitat OpenWebUI",
+	"Share to Open WebUI Community": "Compartir amb la comunitat OpenWebUI",
 	"Show": "Mostrar",
 	"Show": "Mostrar",
 	"Show \"What's New\" modal on login": "Veure 'Què hi ha de nou' a l'entrada",
 	"Show \"What's New\" modal on login": "Veure 'Què hi ha de nou' a l'entrada",
 	"Show Admin Details in Account Pending Overlay": "Mostrar els detalls de l'administrador a la superposició del compte pendent",
 	"Show Admin Details in Account Pending Overlay": "Mostrar els detalls de l'administrador a la superposició del compte pendent",
@@ -943,7 +968,8 @@
 	"This will delete all models including custom models and cannot be undone.": "Això eliminarà tots els models incloent els personalitzats i no es pot desfer",
 	"This will delete all models including custom models and cannot be undone.": "Això eliminarà tots els models incloent els personalitzats i no es pot desfer",
 	"This will reset the knowledge base and sync all files. Do you wish to continue?": "Això restablirà la base de coneixement i sincronitzarà tots els fitxers. Vols continuar?",
 	"This will reset the knowledge base and sync all files. Do you wish to continue?": "Això restablirà la base de coneixement i sincronitzarà tots els fitxers. Vols continuar?",
 	"Thorough explanation": "Explicació en detall",
 	"Thorough explanation": "Explicació en detall",
-	"Thought for {{DURATION}}": "",
+	"Thought for {{DURATION}}": "He pensat durant {{DURATION}}",
+	"Thought for {{DURATION}} seconds": "He pensat durant {{DURATION}} segons",
 	"Tika": "Tika",
 	"Tika": "Tika",
 	"Tika Server URL required.": "La URL del servidor Tika és obligatòria.",
 	"Tika Server URL required.": "La URL del servidor Tika és obligatòria.",
 	"Tiktoken": "Tiktoken",
 	"Tiktoken": "Tiktoken",
@@ -980,7 +1006,7 @@
 	"Tools": "Eines",
 	"Tools": "Eines",
 	"Tools Access": "Accés a les eines",
 	"Tools Access": "Accés a les eines",
 	"Tools are a function calling system with arbitrary code execution": "Les eines són un sistema de crida a funcions amb execució de codi arbitrari",
 	"Tools are a function calling system with arbitrary code execution": "Les eines són un sistema de crida a funcions amb execució de codi arbitrari",
-	"Tools Function Calling Prompt": "",
+	"Tools Function Calling Prompt": "Indicació per a la crida de funcions",
 	"Tools have a function calling system that allows arbitrary code execution": "Les eines disposen d'un sistema de crida a funcions que permet execució de codi arbitrari",
 	"Tools have a function calling system that allows arbitrary code execution": "Les eines disposen d'un sistema de crida a funcions que permet execució de codi arbitrari",
 	"Tools have a function calling system that allows arbitrary code execution.": "Les eines disposen d'un sistema de crida a funcions que permet execució de codi arbitrari.",
 	"Tools have a function calling system that allows arbitrary code execution.": "Les eines disposen d'un sistema de crida a funcions que permet execució de codi arbitrari.",
 	"Top K": "Top K",
 	"Top K": "Top K",
@@ -1051,7 +1077,7 @@
 	"Web Loader Settings": "Preferències del carregador web",
 	"Web Loader Settings": "Preferències del carregador web",
 	"Web Search": "Cerca la web",
 	"Web Search": "Cerca la web",
 	"Web Search Engine": "Motor de cerca de la web",
 	"Web Search Engine": "Motor de cerca de la web",
-	"Web Search in Chat": "",
+	"Web Search in Chat": "Cerca a internet al xat",
 	"Web Search Query Generation": "Generació de consultes per a la cerca de la web",
 	"Web Search Query Generation": "Generació de consultes per a la cerca de la web",
 	"Webhook URL": "URL del webhook",
 	"Webhook URL": "URL del webhook",
 	"WebUI Settings": "Preferències de WebUI",
 	"WebUI Settings": "Preferències de WebUI",
@@ -1081,7 +1107,7 @@
 	"You can personalize your interactions with LLMs by adding memories through the 'Manage' button below, making them more helpful and tailored to you.": "Pots personalitzar les teves interaccions amb els models de llenguatge afegint memòries mitjançant el botó 'Gestiona' que hi ha a continuació, fent-les més útils i adaptades a tu.",
 	"You can personalize your interactions with LLMs by adding memories through the 'Manage' button below, making them more helpful and tailored to you.": "Pots personalitzar les teves interaccions amb els models de llenguatge afegint memòries mitjançant el botó 'Gestiona' que hi ha a continuació, fent-les més útils i adaptades a tu.",
 	"You cannot upload an empty file.": "No es pot pujar un ariux buit.",
 	"You cannot upload an empty file.": "No es pot pujar un ariux buit.",
 	"You do not have permission to access this feature.": "No tens permís per accedir a aquesta funcionalitat",
 	"You do not have permission to access this feature.": "No tens permís per accedir a aquesta funcionalitat",
-	"You do not have permission to upload files": "",
+	"You do not have permission to upload files": "No tens permisos per pujar arxius",
 	"You do not have permission to upload files.": "No tens permisos per pujar arxius.",
 	"You do not have permission to upload files.": "No tens permisos per pujar arxius.",
 	"You have no archived conversations.": "No tens converses arxivades.",
 	"You have no archived conversations.": "No tens converses arxivades.",
 	"You have shared this chat": "Has compartit aquest xat",
 	"You have shared this chat": "Has compartit aquest xat",

+ 29 - 3
src/lib/i18n/locales/ceb-PH/translation.json

@@ -122,6 +122,7 @@
 	"Beta": "",
 	"Beta": "",
 	"Bing Search V7 Endpoint": "",
 	"Bing Search V7 Endpoint": "",
 	"Bing Search V7 Subscription Key": "",
 	"Bing Search V7 Subscription Key": "",
+	"Bocha Search API Key": "",
 	"Brave Search API Key": "",
 	"Brave Search API Key": "",
 	"By {{name}}": "",
 	"By {{name}}": "",
 	"Bypass SSL verification for Websites": "",
 	"Bypass SSL verification for Websites": "",
@@ -163,6 +164,7 @@
 	"Click here to": "",
 	"Click here to": "",
 	"Click here to download user import template file.": "",
 	"Click here to download user import template file.": "",
 	"Click here to learn more about faster-whisper and see the available models.": "",
 	"Click here to learn more about faster-whisper and see the available models.": "",
+	"Click here to see available models.": "",
 	"Click here to select": "I-klik dinhi aron makapili",
 	"Click here to select": "I-klik dinhi aron makapili",
 	"Click here to select a csv file.": "",
 	"Click here to select a csv file.": "",
 	"Click here to select a py file.": "",
 	"Click here to select a py file.": "",
@@ -177,6 +179,8 @@
 	"Code execution": "",
 	"Code execution": "",
 	"Code formatted successfully": "",
 	"Code formatted successfully": "",
 	"Code Interpreter": "",
 	"Code Interpreter": "",
+	"Code Interpreter Engine": "",
+	"Code Interpreter Prompt Template": "",
 	"Collection": "Koleksyon",
 	"Collection": "Koleksyon",
 	"Color": "",
 	"Color": "",
 	"ComfyUI": "",
 	"ComfyUI": "",
@@ -193,6 +197,7 @@
 	"Confirm Password": "Kumpirma ang password",
 	"Confirm Password": "Kumpirma ang password",
 	"Confirm your action": "",
 	"Confirm your action": "",
 	"Confirm your new password": "",
 	"Confirm your new password": "",
+	"Connect to your own OpenAI compatible API endpoints.": "",
 	"Connections": "Mga koneksyon",
 	"Connections": "Mga koneksyon",
 	"Constrains effort on reasoning for reasoning models. Only applicable to reasoning models from specific providers that support reasoning effort. (Default: medium)": "",
 	"Constrains effort on reasoning for reasoning models. Only applicable to reasoning models from specific providers that support reasoning effort. (Default: medium)": "",
 	"Contact Admin for WebUI Access": "",
 	"Contact Admin for WebUI Access": "",
@@ -215,6 +220,7 @@
 	"Copy Link": "",
 	"Copy Link": "",
 	"Copy to clipboard": "",
 	"Copy to clipboard": "",
 	"Copying to clipboard was successful!": "Ang pagkopya sa clipboard malampuson!",
 	"Copying to clipboard was successful!": "Ang pagkopya sa clipboard malampuson!",
+	"CORS must be properly configured by the provider to allow requests from Open WebUI.": "",
 	"Create": "",
 	"Create": "",
 	"Create a knowledge base": "",
 	"Create a knowledge base": "",
 	"Create a model": "",
 	"Create a model": "",
@@ -268,6 +274,9 @@
 	"Describe your knowledge base and objectives": "",
 	"Describe your knowledge base and objectives": "",
 	"Description": "Deskripsyon",
 	"Description": "Deskripsyon",
 	"Didn't fully follow instructions": "",
 	"Didn't fully follow instructions": "",
+	"Direct Connections": "",
+	"Direct Connections allow users to connect to their own OpenAI compatible API endpoints.": "",
+	"Direct Connections settings updated": "",
 	"Disabled": "",
 	"Disabled": "",
 	"Discover a function": "",
 	"Discover a function": "",
 	"Discover a model": "",
 	"Discover a model": "",
@@ -290,6 +299,7 @@
 	"Documentation": "",
 	"Documentation": "",
 	"Documents": "Mga dokumento",
 	"Documents": "Mga dokumento",
 	"does not make any external connections, and your data stays securely on your locally hosted server.": "wala maghimo ug eksternal nga koneksyon, ug ang imong data nagpabiling luwas sa imong lokal nga host server.",
 	"does not make any external connections, and your data stays securely on your locally hosted server.": "wala maghimo ug eksternal nga koneksyon, ug ang imong data nagpabiling luwas sa imong lokal nga host server.",
+	"Domain Filter List": "",
 	"Don't have an account?": "Wala kay account ?",
 	"Don't have an account?": "Wala kay account ?",
 	"don't install random functions from sources you don't trust.": "",
 	"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 tools from sources you don't trust.": "",
@@ -325,6 +335,7 @@
 	"Embedding model set to \"{{embedding_model}}\"": "",
 	"Embedding model set to \"{{embedding_model}}\"": "",
 	"Enable API Key": "",
 	"Enable API Key": "",
 	"Enable autocomplete generation for chat messages": "",
 	"Enable autocomplete generation for chat messages": "",
+	"Enable Code Interpreter": "",
 	"Enable Community Sharing": "",
 	"Enable Community Sharing": "",
 	"Enable Google Drive": "",
 	"Enable Google Drive": "",
 	"Enable Memory Locking (mlock) to prevent model data from being swapped out of RAM. This option locks the model's working set of pages into RAM, ensuring that they will not be swapped out to disk. This can help maintain performance by avoiding page faults and ensuring fast data access.": "",
 	"Enable Memory Locking (mlock) to prevent model data from being swapped out of RAM. This option locks the model's working set of pages into RAM, ensuring that they will not be swapped out to disk. This can help maintain performance by avoiding page faults and ensuring fast data access.": "",
@@ -343,18 +354,23 @@
 	"Enter Application DN Password": "",
 	"Enter Application DN Password": "",
 	"Enter Bing Search V7 Endpoint": "",
 	"Enter Bing Search V7 Endpoint": "",
 	"Enter Bing Search V7 Subscription Key": "",
 	"Enter Bing Search V7 Subscription Key": "",
+	"Enter Bocha Search API Key": "",
 	"Enter Brave Search API Key": "",
 	"Enter Brave Search API Key": "",
 	"Enter certificate path": "",
 	"Enter certificate path": "",
 	"Enter CFG Scale (e.g. 7.0)": "",
 	"Enter CFG Scale (e.g. 7.0)": "",
 	"Enter Chunk Overlap": "Pagsulod sa block overlap",
 	"Enter Chunk Overlap": "Pagsulod sa block overlap",
 	"Enter Chunk Size": "Isulod ang block size",
 	"Enter Chunk Size": "Isulod ang block size",
 	"Enter description": "",
 	"Enter description": "",
+	"Enter domains separated by commas (e.g., example.com,site.org)": "",
 	"Enter Exa API Key": "",
 	"Enter Exa API Key": "",
 	"Enter Github Raw URL": "",
 	"Enter Github Raw URL": "",
 	"Enter Google PSE API Key": "",
 	"Enter Google PSE API Key": "",
 	"Enter Google PSE Engine Id": "",
 	"Enter Google PSE Engine Id": "",
 	"Enter Image Size (e.g. 512x512)": "Pagsulod sa gidak-on sa hulagway (pananglitan 512x512)",
 	"Enter Image Size (e.g. 512x512)": "Pagsulod sa gidak-on sa hulagway (pananglitan 512x512)",
 	"Enter Jina API Key": "",
 	"Enter Jina API Key": "",
+	"Enter Jupyter Password": "",
+	"Enter Jupyter Token": "",
+	"Enter Jupyter URL": "",
 	"Enter Kagi Search API Key": "",
 	"Enter Kagi Search API Key": "",
 	"Enter language codes": "",
 	"Enter language codes": "",
 	"Enter Model ID": "",
 	"Enter Model ID": "",
@@ -540,6 +556,8 @@
 	"JSON Preview": "",
 	"JSON Preview": "",
 	"July": "",
 	"July": "",
 	"June": "",
 	"June": "",
+	"Jupyter Auth": "",
+	"Jupyter URL": "",
 	"JWT Expiration": "Pag-expire sa JWT",
 	"JWT Expiration": "Pag-expire sa JWT",
 	"JWT Token": "JWT token",
 	"JWT Token": "JWT token",
 	"Kagi Search API Key": "",
 	"Kagi Search API Key": "",
@@ -552,6 +570,8 @@
 	"Knowledge deleted successfully.": "",
 	"Knowledge deleted successfully.": "",
 	"Knowledge reset successfully.": "",
 	"Knowledge reset successfully.": "",
 	"Knowledge updated successfully": "",
 	"Knowledge updated successfully": "",
+	"Kokoro.js (Browser)": "",
+	"Kokoro.js Dtype": "",
 	"Label": "",
 	"Label": "",
 	"Landing Page Mode": "",
 	"Landing Page Mode": "",
 	"Language": "Pinulongan",
 	"Language": "Pinulongan",
@@ -566,19 +586,22 @@
 	"Leave empty to include all models from \"{{URL}}/models\" endpoint": "",
 	"Leave empty to include all models from \"{{URL}}/models\" endpoint": "",
 	"Leave empty to include all models or select specific models": "",
 	"Leave empty to include all models or select specific models": "",
 	"Leave empty to use the default prompt, or enter a custom prompt": "",
 	"Leave empty to use the default prompt, or enter a custom prompt": "",
+	"Leave model field empty to use the default model.": "",
 	"Light": "Kahayag",
 	"Light": "Kahayag",
 	"Listening...": "",
 	"Listening...": "",
 	"Llama.cpp": "",
 	"Llama.cpp": "",
 	"LLMs can make mistakes. Verify important information.": "Ang mga LLM mahimong masayop. ",
 	"LLMs can make mistakes. Verify important information.": "Ang mga LLM mahimong masayop. ",
+	"Loading Kokoro.js...": "",
 	"Local": "",
 	"Local": "",
 	"Local Models": "",
 	"Local Models": "",
 	"Lost": "",
 	"Lost": "",
 	"LTR": "",
 	"LTR": "",
-	"Made by OpenWebUI Community": "Gihimo sa komunidad sa OpenWebUI",
+	"Made by Open WebUI Community": "Gihimo sa komunidad sa OpenWebUI",
 	"Make sure to enclose them with": "Siguruha nga palibutan sila",
 	"Make sure to enclose them with": "Siguruha nga palibutan sila",
 	"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.": "",
 	"Manage": "",
 	"Manage": "",
 	"Manage Arena Models": "",
 	"Manage Arena Models": "",
+	"Manage Direct Connections": "",
 	"Manage Models": "",
 	"Manage Models": "",
 	"Manage Ollama": "",
 	"Manage Ollama": "",
 	"Manage Ollama API Connections": "",
 	"Manage Ollama API Connections": "",
@@ -722,6 +745,7 @@
 	"Plain text (.txt)": "",
 	"Plain text (.txt)": "",
 	"Playground": "Dulaanan",
 	"Playground": "Dulaanan",
 	"Please carefully review the following warnings:": "",
 	"Please carefully review the following warnings:": "",
+	"Please do not close the settings page while loading the model.": "",
 	"Please enter a prompt": "",
 	"Please enter a prompt": "",
 	"Please fill in all fields.": "",
 	"Please fill in all fields.": "",
 	"Please select a model first.": "",
 	"Please select a model first.": "",
@@ -754,7 +778,7 @@
 	"Read Aloud": "",
 	"Read Aloud": "",
 	"Reasoning Effort": "",
 	"Reasoning Effort": "",
 	"Record voice": "Irekord ang tingog",
 	"Record voice": "Irekord ang tingog",
-	"Redirecting you to OpenWebUI Community": "Gi-redirect ka sa komunidad sa OpenWebUI",
+	"Redirecting you to Open WebUI Community": "Gi-redirect ka sa komunidad sa OpenWebUI",
 	"Reduces the probability of generating nonsense. A higher value (e.g. 100) will give more diverse answers, while a lower value (e.g. 10) will be more conservative. (Default: 40)": "",
 	"Reduces the probability of generating nonsense. A higher value (e.g. 100) will give more diverse answers, while a lower value (e.g. 10) will be more conservative. (Default: 40)": "",
 	"Refer to yourself as \"User\" (e.g., \"User is learning Spanish\")": "",
 	"Refer to yourself as \"User\" (e.g., \"User is learning Spanish\")": "",
 	"References from": "",
 	"References from": "",
@@ -829,6 +853,7 @@
 	"Select a pipeline": "",
 	"Select a pipeline": "",
 	"Select a pipeline url": "",
 	"Select a pipeline url": "",
 	"Select a tool": "",
 	"Select a tool": "",
+	"Select an auth method": "",
 	"Select an Ollama instance": "",
 	"Select an Ollama instance": "",
 	"Select Engine": "",
 	"Select Engine": "",
 	"Select Knowledge": "",
 	"Select Knowledge": "",
@@ -869,7 +894,7 @@
 	"Settings saved successfully!": "Malampuson nga na-save ang mga setting!",
 	"Settings saved successfully!": "Malampuson nga na-save ang mga setting!",
 	"Share": "",
 	"Share": "",
 	"Share Chat": "",
 	"Share Chat": "",
-	"Share to OpenWebUI Community": "Ipakigbahin sa komunidad sa OpenWebUI",
+	"Share to Open WebUI Community": "Ipakigbahin sa komunidad sa OpenWebUI",
 	"Show": "Pagpakita",
 	"Show": "Pagpakita",
 	"Show \"What's New\" modal on login": "",
 	"Show \"What's New\" modal on login": "",
 	"Show Admin Details in Account Pending Overlay": "",
 	"Show Admin Details in Account Pending Overlay": "",
@@ -944,6 +969,7 @@
 	"This will reset the knowledge base and sync all files. Do you wish to continue?": "",
 	"This will reset the knowledge base and sync all files. Do you wish to continue?": "",
 	"Thorough explanation": "",
 	"Thorough explanation": "",
 	"Thought for {{DURATION}}": "",
 	"Thought for {{DURATION}}": "",
+	"Thought for {{DURATION}} seconds": "",
 	"Tika": "",
 	"Tika": "",
 	"Tika Server URL required.": "",
 	"Tika Server URL required.": "",
 	"Tiktoken": "",
 	"Tiktoken": "",

+ 29 - 3
src/lib/i18n/locales/cs-CZ/translation.json

@@ -122,6 +122,7 @@
 	"Beta": "",
 	"Beta": "",
 	"Bing Search V7 Endpoint": "",
 	"Bing Search V7 Endpoint": "",
 	"Bing Search V7 Subscription Key": "",
 	"Bing Search V7 Subscription Key": "",
+	"Bocha Search API Key": "",
 	"Brave Search API Key": "Klíč API pro Brave Search",
 	"Brave Search API Key": "Klíč API pro Brave Search",
 	"By {{name}}": "",
 	"By {{name}}": "",
 	"Bypass SSL verification for Websites": "Obcházení ověření SSL pro webové stránky",
 	"Bypass SSL verification for Websites": "Obcházení ověření SSL pro webové stránky",
@@ -163,6 +164,7 @@
 	"Click here to": "Klikněte sem pro",
 	"Click here to": "Klikněte sem pro",
 	"Click here to download user import template file.": "Klikněte zde pro stažení šablony souboru pro import uživatelů.",
 	"Click here to download user import template file.": "Klikněte zde pro stažení šablony souboru pro import uživatelů.",
 	"Click here to learn more about faster-whisper and see the available models.": "Klikněte sem a zjistěte více o faster-whisper a podívejte se na dostupné modely.",
 	"Click here to learn more about faster-whisper and see the available models.": "Klikněte sem a zjistěte více o faster-whisper a podívejte se na dostupné modely.",
+	"Click here to see available models.": "",
 	"Click here to select": "Klikněte sem pro výběr",
 	"Click here to select": "Klikněte sem pro výběr",
 	"Click here to select a csv file.": "Klikněte zde pro výběr souboru typu csv.",
 	"Click here to select a csv file.": "Klikněte zde pro výběr souboru typu csv.",
 	"Click here to select a py file.": "Klikněte sem pro výběr {{py}} souboru.",
 	"Click here to select a py file.": "Klikněte sem pro výběr {{py}} souboru.",
@@ -177,6 +179,8 @@
 	"Code execution": "Provádění kódu",
 	"Code execution": "Provádění kódu",
 	"Code formatted successfully": "Kód byl úspěšně naformátován.",
 	"Code formatted successfully": "Kód byl úspěšně naformátován.",
 	"Code Interpreter": "",
 	"Code Interpreter": "",
+	"Code Interpreter Engine": "",
+	"Code Interpreter Prompt Template": "",
 	"Collection": "",
 	"Collection": "",
 	"Color": "Barva",
 	"Color": "Barva",
 	"ComfyUI": "ComfyUI.",
 	"ComfyUI": "ComfyUI.",
@@ -193,6 +197,7 @@
 	"Confirm Password": "Potvrzení hesla",
 	"Confirm Password": "Potvrzení hesla",
 	"Confirm your action": "Potvrďte svoji akci",
 	"Confirm your action": "Potvrďte svoji akci",
 	"Confirm your new password": "",
 	"Confirm your new password": "",
+	"Connect to your own OpenAI compatible API endpoints.": "",
 	"Connections": "Připojení",
 	"Connections": "Připojení",
 	"Constrains effort on reasoning for reasoning models. Only applicable to reasoning models from specific providers that support reasoning effort. (Default: medium)": "",
 	"Constrains effort on reasoning for reasoning models. Only applicable to reasoning models from specific providers that support reasoning effort. (Default: medium)": "",
 	"Contact Admin for WebUI Access": "Kontaktujte administrátora pro přístup k webovému rozhraní.",
 	"Contact Admin for WebUI Access": "Kontaktujte administrátora pro přístup k webovému rozhraní.",
@@ -215,6 +220,7 @@
 	"Copy Link": "Kopírovat odkaz",
 	"Copy Link": "Kopírovat odkaz",
 	"Copy to clipboard": "Kopírovat do schránky",
 	"Copy to clipboard": "Kopírovat do schránky",
 	"Copying to clipboard was successful!": "Kopírování do schránky bylo úspěšné!",
 	"Copying to clipboard was successful!": "Kopírování do schránky bylo úspěšné!",
+	"CORS must be properly configured by the provider to allow requests from Open WebUI.": "",
 	"Create": "Vytvořit",
 	"Create": "Vytvořit",
 	"Create a knowledge base": "Vytvořit knowledge base",
 	"Create a knowledge base": "Vytvořit knowledge base",
 	"Create a model": "Vytvořte model",
 	"Create a model": "Vytvořte model",
@@ -268,6 +274,9 @@
 	"Describe your knowledge base and objectives": "",
 	"Describe your knowledge base and objectives": "",
 	"Description": "Popis",
 	"Description": "Popis",
 	"Didn't fully follow instructions": "Nenásledovali jste přesně všechny instrukce.",
 	"Didn't fully follow instructions": "Nenásledovali jste přesně všechny instrukce.",
+	"Direct Connections": "",
+	"Direct Connections allow users to connect to their own OpenAI compatible API endpoints.": "",
+	"Direct Connections settings updated": "",
 	"Disabled": "Zakázáno",
 	"Disabled": "Zakázáno",
 	"Discover a function": "Objevit funkci",
 	"Discover a function": "Objevit funkci",
 	"Discover a model": "Objevte model",
 	"Discover a model": "Objevte model",
@@ -290,6 +299,7 @@
 	"Documentation": "Dokumentace",
 	"Documentation": "Dokumentace",
 	"Documents": "Dokumenty",
 	"Documents": "Dokumenty",
 	"does not make any external connections, and your data stays securely on your locally hosted server.": "nevytváří žádná externí připojení a vaše data zůstávají bezpečně na vašem lokálním serveru.",
 	"does not make any external connections, and your data stays securely on your locally hosted server.": "nevytváří žádná externí připojení a vaše data zůstávají bezpečně na vašem lokálním serveru.",
+	"Domain Filter List": "",
 	"Don't have an account?": "Nemáte účet?",
 	"Don't have an account?": "Nemáte účet?",
 	"don't install random functions from sources you don't trust.": "Neinstalujte náhodné funkce ze zdrojů, kterým nedůvěřujete.",
 	"don't install random functions from sources you don't trust.": "Neinstalujte náhodné funkce ze zdrojů, kterým nedůvěřujete.",
 	"don't install random tools from sources you don't trust.": "Neinstalujte náhodné nástroje ze zdrojů, kterým nedůvěřujete.",
 	"don't install random tools from sources you don't trust.": "Neinstalujte náhodné nástroje ze zdrojů, kterým nedůvěřujete.",
@@ -325,6 +335,7 @@
 	"Embedding model set to \"{{embedding_model}}\"": "Model vkládání nastaven na \"{{embedding_model}}\"",
 	"Embedding model set to \"{{embedding_model}}\"": "Model vkládání nastaven na \"{{embedding_model}}\"",
 	"Enable API Key": "",
 	"Enable API Key": "",
 	"Enable autocomplete generation for chat messages": "",
 	"Enable autocomplete generation for chat messages": "",
+	"Enable Code Interpreter": "",
 	"Enable Community Sharing": "Povolit sdílení komunity",
 	"Enable Community Sharing": "Povolit sdílení komunity",
 	"Enable Google Drive": "",
 	"Enable Google Drive": "",
 	"Enable Memory Locking (mlock) to prevent model data from being swapped out of RAM. This option locks the model's working set of pages into RAM, ensuring that they will not be swapped out to disk. This can help maintain performance by avoiding page faults and ensuring fast data access.": "",
 	"Enable Memory Locking (mlock) to prevent model data from being swapped out of RAM. This option locks the model's working set of pages into RAM, ensuring that they will not be swapped out to disk. This can help maintain performance by avoiding page faults and ensuring fast data access.": "",
@@ -343,18 +354,23 @@
 	"Enter Application DN Password": "",
 	"Enter Application DN Password": "",
 	"Enter Bing Search V7 Endpoint": "",
 	"Enter Bing Search V7 Endpoint": "",
 	"Enter Bing Search V7 Subscription Key": "",
 	"Enter Bing Search V7 Subscription Key": "",
+	"Enter Bocha Search API Key": "",
 	"Enter Brave Search API Key": "Zadejte API klíč pro Brave Search",
 	"Enter Brave Search API Key": "Zadejte API klíč pro Brave Search",
 	"Enter certificate path": "",
 	"Enter certificate path": "",
 	"Enter CFG Scale (e.g. 7.0)": "Zadejte měřítko CFG (např. 7.0)",
 	"Enter CFG Scale (e.g. 7.0)": "Zadejte měřítko CFG (např. 7.0)",
 	"Enter Chunk Overlap": "Zadejte překryv části",
 	"Enter Chunk Overlap": "Zadejte překryv části",
 	"Enter Chunk Size": "Zadejte velikost bloku",
 	"Enter Chunk Size": "Zadejte velikost bloku",
 	"Enter description": "Zadejte popis",
 	"Enter description": "Zadejte popis",
+	"Enter domains separated by commas (e.g., example.com,site.org)": "",
 	"Enter Exa API Key": "",
 	"Enter Exa API Key": "",
 	"Enter Github Raw URL": "Zadejte URL adresu Github Raw",
 	"Enter Github Raw URL": "Zadejte URL adresu Github Raw",
 	"Enter Google PSE API Key": "Zadejte klíč rozhraní API Google PSE",
 	"Enter Google PSE API Key": "Zadejte klíč rozhraní API Google PSE",
 	"Enter Google PSE Engine Id": "Zadejte ID vyhledávacího mechanismu Google PSE",
 	"Enter Google PSE Engine Id": "Zadejte ID vyhledávacího mechanismu Google PSE",
 	"Enter Image Size (e.g. 512x512)": "Zadejte velikost obrázku (např. 512x512)",
 	"Enter Image Size (e.g. 512x512)": "Zadejte velikost obrázku (např. 512x512)",
 	"Enter Jina API Key": "",
 	"Enter Jina API Key": "",
+	"Enter Jupyter Password": "",
+	"Enter Jupyter Token": "",
+	"Enter Jupyter URL": "",
 	"Enter Kagi Search API Key": "",
 	"Enter Kagi Search API Key": "",
 	"Enter language codes": "Zadejte kódy jazyků",
 	"Enter language codes": "Zadejte kódy jazyků",
 	"Enter Model ID": "Zadejte ID modelu",
 	"Enter Model ID": "Zadejte ID modelu",
@@ -540,6 +556,8 @@
 	"JSON Preview": "Náhled JSON",
 	"JSON Preview": "Náhled JSON",
 	"July": "Červenec",
 	"July": "Červenec",
 	"June": "červen",
 	"June": "červen",
+	"Jupyter Auth": "",
+	"Jupyter URL": "",
 	"JWT Expiration": "Vypršení JWT",
 	"JWT Expiration": "Vypršení JWT",
 	"JWT Token": "JWT Token (JSON Web Token)",
 	"JWT Token": "JWT Token (JSON Web Token)",
 	"Kagi Search API Key": "",
 	"Kagi Search API Key": "",
@@ -552,6 +570,8 @@
 	"Knowledge deleted successfully.": "Znalosti byly úspěšně odstraněny.",
 	"Knowledge deleted successfully.": "Znalosti byly úspěšně odstraněny.",
 	"Knowledge reset successfully.": "Úspěšné obnovení znalostí.",
 	"Knowledge reset successfully.": "Úspěšné obnovení znalostí.",
 	"Knowledge updated successfully": "Znalosti úspěšně aktualizovány",
 	"Knowledge updated successfully": "Znalosti úspěšně aktualizovány",
+	"Kokoro.js (Browser)": "",
+	"Kokoro.js Dtype": "",
 	"Label": "",
 	"Label": "",
 	"Landing Page Mode": "Režim vstupní stránky",
 	"Landing Page Mode": "Režim vstupní stránky",
 	"Language": "Jazyk",
 	"Language": "Jazyk",
@@ -566,19 +586,22 @@
 	"Leave empty to include all models from \"{{URL}}/models\" endpoint": "",
 	"Leave empty to include all models from \"{{URL}}/models\" endpoint": "",
 	"Leave empty to include all models or select specific models": "Nechte prázdné pro zahrnutí všech modelů nebo vyberte konkrétní modely.",
 	"Leave empty to include all models or select specific models": "Nechte prázdné pro zahrnutí všech modelů nebo vyberte konkrétní modely.",
 	"Leave empty to use the default prompt, or enter a custom prompt": "Nechte prázdné pro použití výchozího podnětu, nebo zadejte vlastní podnět.",
 	"Leave empty to use the default prompt, or enter a custom prompt": "Nechte prázdné pro použití výchozího podnětu, nebo zadejte vlastní podnět.",
+	"Leave model field empty to use the default model.": "",
 	"Light": "Světlo",
 	"Light": "Světlo",
 	"Listening...": "Poslouchání...",
 	"Listening...": "Poslouchání...",
 	"Llama.cpp": "",
 	"Llama.cpp": "",
 	"LLMs can make mistakes. Verify important information.": "LLM mohou dělat chyby. Ověřte si důležité informace.",
 	"LLMs can make mistakes. Verify important information.": "LLM mohou dělat chyby. Ověřte si důležité informace.",
+	"Loading Kokoro.js...": "",
 	"Local": "",
 	"Local": "",
 	"Local Models": "Lokální modely",
 	"Local Models": "Lokální modely",
 	"Lost": "Ztracený",
 	"Lost": "Ztracený",
 	"LTR": "LTR",
 	"LTR": "LTR",
-	"Made by OpenWebUI Community": "Vytvořeno komunitou OpenWebUI",
+	"Made by Open WebUI Community": "Vytvořeno komunitou OpenWebUI",
 	"Make sure to enclose them with": "Ujistěte se, že jsou uzavřeny pomocí",
 	"Make sure to enclose them with": "Ujistěte se, že jsou uzavřeny pomocí",
 	"Make sure to export a workflow.json file as API format from ComfyUI.": "Ujistěte se, že exportujete soubor workflow.json ve formátu API z ComfyUI.",
 	"Make sure to export a workflow.json file as API format from ComfyUI.": "Ujistěte se, že exportujete soubor workflow.json ve formátu API z ComfyUI.",
 	"Manage": "Spravovat",
 	"Manage": "Spravovat",
 	"Manage Arena Models": "Správa modelů v Arena",
 	"Manage Arena Models": "Správa modelů v Arena",
+	"Manage Direct Connections": "",
 	"Manage Models": "",
 	"Manage Models": "",
 	"Manage Ollama": "",
 	"Manage Ollama": "",
 	"Manage Ollama API Connections": "",
 	"Manage Ollama API Connections": "",
@@ -722,6 +745,7 @@
 	"Plain text (.txt)": "Čistý text (.txt)",
 	"Plain text (.txt)": "Čistý text (.txt)",
 	"Playground": "",
 	"Playground": "",
 	"Please carefully review the following warnings:": "Prosím, pečlivě si přečtěte následující upozornění:",
 	"Please carefully review the following warnings:": "Prosím, pečlivě si přečtěte následující upozornění:",
+	"Please do not close the settings page while loading the model.": "",
 	"Please enter a prompt": "Prosím, zadejte zadání.",
 	"Please enter a prompt": "Prosím, zadejte zadání.",
 	"Please fill in all fields.": "Prosím, vyplňte všechna pole.",
 	"Please fill in all fields.": "Prosím, vyplňte všechna pole.",
 	"Please select a model first.": "",
 	"Please select a model first.": "",
@@ -754,7 +778,7 @@
 	"Read Aloud": "Číst nahlas",
 	"Read Aloud": "Číst nahlas",
 	"Reasoning Effort": "",
 	"Reasoning Effort": "",
 	"Record voice": "Nahrát hlas",
 	"Record voice": "Nahrát hlas",
-	"Redirecting you to OpenWebUI Community": "Přesměrování na komunitu OpenWebUI",
+	"Redirecting you to Open WebUI Community": "Přesměrování na komunitu OpenWebUI",
 	"Reduces the probability of generating nonsense. A higher value (e.g. 100) will give more diverse answers, while a lower value (e.g. 10) will be more conservative. (Default: 40)": "",
 	"Reduces the probability of generating nonsense. A higher value (e.g. 100) will give more diverse answers, while a lower value (e.g. 10) will be more conservative. (Default: 40)": "",
 	"Refer to yourself as \"User\" (e.g., \"User is learning Spanish\")": "Odkazujte na sebe jako na \"uživatele\" (např. \"Uživatel se učí španělsky\").",
 	"Refer to yourself as \"User\" (e.g., \"User is learning Spanish\")": "Odkazujte na sebe jako na \"uživatele\" (např. \"Uživatel se učí španělsky\").",
 	"References from": "Reference z",
 	"References from": "Reference z",
@@ -829,6 +853,7 @@
 	"Select a pipeline": "Vyberte pipeline",
 	"Select a pipeline": "Vyberte pipeline",
 	"Select a pipeline url": "Vyberte URL adresu kanálu",
 	"Select a pipeline url": "Vyberte URL adresu kanálu",
 	"Select a tool": "Vyberte nástroj",
 	"Select a tool": "Vyberte nástroj",
+	"Select an auth method": "",
 	"Select an Ollama instance": "",
 	"Select an Ollama instance": "",
 	"Select Engine": "Vyberte engine",
 	"Select Engine": "Vyberte engine",
 	"Select Knowledge": "Vybrat znalosti",
 	"Select Knowledge": "Vybrat znalosti",
@@ -869,7 +894,7 @@
 	"Settings saved successfully!": "Nastavení byla úspěšně uložena!",
 	"Settings saved successfully!": "Nastavení byla úspěšně uložena!",
 	"Share": "Sdílet",
 	"Share": "Sdílet",
 	"Share Chat": "Sdílet chat",
 	"Share Chat": "Sdílet chat",
-	"Share to OpenWebUI Community": "Sdílet s komunitou OpenWebUI",
+	"Share to Open WebUI Community": "Sdílet s komunitou OpenWebUI",
 	"Show": "Zobrazit",
 	"Show": "Zobrazit",
 	"Show \"What's New\" modal on login": "",
 	"Show \"What's New\" modal on login": "",
 	"Show Admin Details in Account Pending Overlay": "Zobrazit podrobnosti administrátora v překryvném okně s čekajícím účtem",
 	"Show Admin Details in Account Pending Overlay": "Zobrazit podrobnosti administrátora v překryvném okně s čekajícím účtem",
@@ -944,6 +969,7 @@
 	"This will reset the knowledge base and sync all files. Do you wish to continue?": "Toto obnoví znalostní databázi a synchronizuje všechny soubory. Přejete si pokračovat?",
 	"This will reset the knowledge base and sync all files. Do you wish to continue?": "Toto obnoví znalostní databázi a synchronizuje všechny soubory. Přejete si pokračovat?",
 	"Thorough explanation": "Obsáhlé vysvětlení",
 	"Thorough explanation": "Obsáhlé vysvětlení",
 	"Thought for {{DURATION}}": "",
 	"Thought for {{DURATION}}": "",
+	"Thought for {{DURATION}} seconds": "",
 	"Tika": "Tika",
 	"Tika": "Tika",
 	"Tika Server URL required.": "Je vyžadována URL adresa serveru Tika.",
 	"Tika Server URL required.": "Je vyžadována URL adresa serveru Tika.",
 	"Tiktoken": "Tiktoken",
 	"Tiktoken": "Tiktoken",

+ 29 - 3
src/lib/i18n/locales/da-DK/translation.json

@@ -122,6 +122,7 @@
 	"Beta": "",
 	"Beta": "",
 	"Bing Search V7 Endpoint": "",
 	"Bing Search V7 Endpoint": "",
 	"Bing Search V7 Subscription Key": "",
 	"Bing Search V7 Subscription Key": "",
+	"Bocha Search API Key": "",
 	"Brave Search API Key": "Brave Search API nøgle",
 	"Brave Search API Key": "Brave Search API nøgle",
 	"By {{name}}": "",
 	"By {{name}}": "",
 	"Bypass SSL verification for Websites": "Forbigå SSL verifikation på websider",
 	"Bypass SSL verification for Websites": "Forbigå SSL verifikation på websider",
@@ -163,6 +164,7 @@
 	"Click here to": "Klik her for at",
 	"Click here to": "Klik her for at",
 	"Click here to download user import template file.": "Klik her for at downloade bruger import template fil.",
 	"Click here to download user import template file.": "Klik her for at downloade bruger import template fil.",
 	"Click here to learn more about faster-whisper and see the available models.": "",
 	"Click here to learn more about faster-whisper and see the available models.": "",
+	"Click here to see available models.": "",
 	"Click here to select": "Klik her for at vælge",
 	"Click here to select": "Klik her for at vælge",
 	"Click here to select a csv file.": "Klik her for at vælge en csv fil",
 	"Click here to select a csv file.": "Klik her for at vælge en csv fil",
 	"Click here to select a py file.": "Klik her for at vælge en py fil",
 	"Click here to select a py file.": "Klik her for at vælge en py fil",
@@ -177,6 +179,8 @@
 	"Code execution": "",
 	"Code execution": "",
 	"Code formatted successfully": "Kode formateret korrekt",
 	"Code formatted successfully": "Kode formateret korrekt",
 	"Code Interpreter": "",
 	"Code Interpreter": "",
+	"Code Interpreter Engine": "",
+	"Code Interpreter Prompt Template": "",
 	"Collection": "Samling",
 	"Collection": "Samling",
 	"Color": "",
 	"Color": "",
 	"ComfyUI": "ComfyUI",
 	"ComfyUI": "ComfyUI",
@@ -193,6 +197,7 @@
 	"Confirm Password": "Bekræft password",
 	"Confirm Password": "Bekræft password",
 	"Confirm your action": "Bekræft din handling",
 	"Confirm your action": "Bekræft din handling",
 	"Confirm your new password": "",
 	"Confirm your new password": "",
+	"Connect to your own OpenAI compatible API endpoints.": "",
 	"Connections": "Forbindelser",
 	"Connections": "Forbindelser",
 	"Constrains effort on reasoning for reasoning models. Only applicable to reasoning models from specific providers that support reasoning effort. (Default: medium)": "",
 	"Constrains effort on reasoning for reasoning models. Only applicable to reasoning models from specific providers that support reasoning effort. (Default: medium)": "",
 	"Contact Admin for WebUI Access": "Kontakt din administrator for adgang til WebUI",
 	"Contact Admin for WebUI Access": "Kontakt din administrator for adgang til WebUI",
@@ -215,6 +220,7 @@
 	"Copy Link": "Kopier link",
 	"Copy Link": "Kopier link",
 	"Copy to clipboard": "",
 	"Copy to clipboard": "",
 	"Copying to clipboard was successful!": "Kopieret til udklipsholder!",
 	"Copying to clipboard was successful!": "Kopieret til udklipsholder!",
+	"CORS must be properly configured by the provider to allow requests from Open WebUI.": "",
 	"Create": "",
 	"Create": "",
 	"Create a knowledge base": "",
 	"Create a knowledge base": "",
 	"Create a model": "Lav en model",
 	"Create a model": "Lav en model",
@@ -268,6 +274,9 @@
 	"Describe your knowledge base and objectives": "",
 	"Describe your knowledge base and objectives": "",
 	"Description": "Beskrivelse",
 	"Description": "Beskrivelse",
 	"Didn't fully follow instructions": "Fulgte ikke instruktioner",
 	"Didn't fully follow instructions": "Fulgte ikke instruktioner",
+	"Direct Connections": "",
+	"Direct Connections allow users to connect to their own OpenAI compatible API endpoints.": "",
+	"Direct Connections settings updated": "",
 	"Disabled": "Inaktiv",
 	"Disabled": "Inaktiv",
 	"Discover a function": "Find en funktion",
 	"Discover a function": "Find en funktion",
 	"Discover a model": "Find en model",
 	"Discover a model": "Find en model",
@@ -290,6 +299,7 @@
 	"Documentation": "Dokumentation",
 	"Documentation": "Dokumentation",
 	"Documents": "Dokumenter",
 	"Documents": "Dokumenter",
 	"does not make any external connections, and your data stays securely on your locally hosted server.": "laver ikke eksterne kald, og din data bliver sikkert på din egen lokalt hostede server.",
 	"does not make any external connections, and your data stays securely on your locally hosted server.": "laver ikke eksterne kald, og din data bliver sikkert på din egen lokalt hostede server.",
+	"Domain Filter List": "",
 	"Don't have an account?": "Har du ikke en profil?",
 	"Don't have an account?": "Har du ikke en profil?",
 	"don't install random functions from sources you don't trust.": "lad være med at installere tilfældige funktioner fra kilder, som du ikke stoler på.",
 	"don't install random functions from sources you don't trust.": "lad være med at installere tilfældige funktioner fra kilder, som du ikke stoler på.",
 	"don't install random tools from sources you don't trust.": "lad være med at installere tilfældige værktøjer fra kilder, som du ikke stoler på.",
 	"don't install random tools from sources you don't trust.": "lad være med at installere tilfældige værktøjer fra kilder, som du ikke stoler på.",
@@ -325,6 +335,7 @@
 	"Embedding model set to \"{{embedding_model}}\"": "Embedding model sat til \"{{embedding_model}}\"",
 	"Embedding model set to \"{{embedding_model}}\"": "Embedding model sat til \"{{embedding_model}}\"",
 	"Enable API Key": "",
 	"Enable API Key": "",
 	"Enable autocomplete generation for chat messages": "",
 	"Enable autocomplete generation for chat messages": "",
+	"Enable Code Interpreter": "",
 	"Enable Community Sharing": "Aktiver deling til Community",
 	"Enable Community Sharing": "Aktiver deling til Community",
 	"Enable Google Drive": "",
 	"Enable Google Drive": "",
 	"Enable Memory Locking (mlock) to prevent model data from being swapped out of RAM. This option locks the model's working set of pages into RAM, ensuring that they will not be swapped out to disk. This can help maintain performance by avoiding page faults and ensuring fast data access.": "",
 	"Enable Memory Locking (mlock) to prevent model data from being swapped out of RAM. This option locks the model's working set of pages into RAM, ensuring that they will not be swapped out to disk. This can help maintain performance by avoiding page faults and ensuring fast data access.": "",
@@ -343,18 +354,23 @@
 	"Enter Application DN Password": "",
 	"Enter Application DN Password": "",
 	"Enter Bing Search V7 Endpoint": "",
 	"Enter Bing Search V7 Endpoint": "",
 	"Enter Bing Search V7 Subscription Key": "",
 	"Enter Bing Search V7 Subscription Key": "",
+	"Enter Bocha Search API Key": "",
 	"Enter Brave Search API Key": "Indtast Brave Search API-nøgle",
 	"Enter Brave Search API Key": "Indtast Brave Search API-nøgle",
 	"Enter certificate path": "",
 	"Enter certificate path": "",
 	"Enter CFG Scale (e.g. 7.0)": "Indtast CFG-skala (f.eks. 7.0)",
 	"Enter CFG Scale (e.g. 7.0)": "Indtast CFG-skala (f.eks. 7.0)",
 	"Enter Chunk Overlap": "Indtast overlapning af tekststykker",
 	"Enter Chunk Overlap": "Indtast overlapning af tekststykker",
 	"Enter Chunk Size": "Indtast størrelse af tekststykker",
 	"Enter Chunk Size": "Indtast størrelse af tekststykker",
 	"Enter description": "",
 	"Enter description": "",
+	"Enter domains separated by commas (e.g., example.com,site.org)": "",
 	"Enter Exa API Key": "",
 	"Enter Exa API Key": "",
 	"Enter Github Raw URL": "Indtast Github Raw URL",
 	"Enter Github Raw URL": "Indtast Github Raw URL",
 	"Enter Google PSE API Key": "Indtast Google PSE API-nøgle",
 	"Enter Google PSE API Key": "Indtast Google PSE API-nøgle",
 	"Enter Google PSE Engine Id": "Indtast Google PSE Engine ID",
 	"Enter Google PSE Engine Id": "Indtast Google PSE Engine ID",
 	"Enter Image Size (e.g. 512x512)": "Indtast billedstørrelse (f.eks. 512x512)",
 	"Enter Image Size (e.g. 512x512)": "Indtast billedstørrelse (f.eks. 512x512)",
 	"Enter Jina API Key": "",
 	"Enter Jina API Key": "",
+	"Enter Jupyter Password": "",
+	"Enter Jupyter Token": "",
+	"Enter Jupyter URL": "",
 	"Enter Kagi Search API Key": "",
 	"Enter Kagi Search API Key": "",
 	"Enter language codes": "Indtast sprogkoder",
 	"Enter language codes": "Indtast sprogkoder",
 	"Enter Model ID": "Indtast model-ID",
 	"Enter Model ID": "Indtast model-ID",
@@ -540,6 +556,8 @@
 	"JSON Preview": "JSON-forhåndsvisning",
 	"JSON Preview": "JSON-forhåndsvisning",
 	"July": "Juli",
 	"July": "Juli",
 	"June": "Juni",
 	"June": "Juni",
+	"Jupyter Auth": "",
+	"Jupyter URL": "",
 	"JWT Expiration": "JWT-udløb",
 	"JWT Expiration": "JWT-udløb",
 	"JWT Token": "JWT-token",
 	"JWT Token": "JWT-token",
 	"Kagi Search API Key": "",
 	"Kagi Search API Key": "",
@@ -552,6 +570,8 @@
 	"Knowledge deleted successfully.": "Viden slettet.",
 	"Knowledge deleted successfully.": "Viden slettet.",
 	"Knowledge reset successfully.": "Viden nulstillet.",
 	"Knowledge reset successfully.": "Viden nulstillet.",
 	"Knowledge updated successfully": "Viden opdateret.",
 	"Knowledge updated successfully": "Viden opdateret.",
+	"Kokoro.js (Browser)": "",
+	"Kokoro.js Dtype": "",
 	"Label": "",
 	"Label": "",
 	"Landing Page Mode": "Landing Page-tilstand",
 	"Landing Page Mode": "Landing Page-tilstand",
 	"Language": "Sprog",
 	"Language": "Sprog",
@@ -566,19 +586,22 @@
 	"Leave empty to include all models from \"{{URL}}/models\" endpoint": "",
 	"Leave empty to include all models from \"{{URL}}/models\" endpoint": "",
 	"Leave empty to include all models or select specific models": "",
 	"Leave empty to include all models or select specific models": "",
 	"Leave empty to use the default prompt, or enter a custom prompt": "Lad stå tomt for at bruge standardprompten, eller indtast en brugerdefineret prompt",
 	"Leave empty to use the default prompt, or enter a custom prompt": "Lad stå tomt for at bruge standardprompten, eller indtast en brugerdefineret prompt",
+	"Leave model field empty to use the default model.": "",
 	"Light": "Lys",
 	"Light": "Lys",
 	"Listening...": "Lytter...",
 	"Listening...": "Lytter...",
 	"Llama.cpp": "",
 	"Llama.cpp": "",
 	"LLMs can make mistakes. Verify important information.": "LLM'er kan lave fejl. Bekræft vigtige oplysninger.",
 	"LLMs can make mistakes. Verify important information.": "LLM'er kan lave fejl. Bekræft vigtige oplysninger.",
+	"Loading Kokoro.js...": "",
 	"Local": "",
 	"Local": "",
 	"Local Models": "Lokale modeller",
 	"Local Models": "Lokale modeller",
 	"Lost": "",
 	"Lost": "",
 	"LTR": "LTR",
 	"LTR": "LTR",
-	"Made by OpenWebUI Community": "Lavet af OpenWebUI Community",
+	"Made by Open WebUI Community": "Lavet af OpenWebUI Community",
 	"Make sure to enclose them with": "Sørg for at omslutte dem med",
 	"Make sure to enclose them with": "Sørg for at omslutte dem med",
 	"Make sure to export a workflow.json file as API format from ComfyUI.": "Sørg for at eksportere en workflow.json-fil som API-format fra ComfyUI.",
 	"Make sure to export a workflow.json file as API format from ComfyUI.": "Sørg for at eksportere en workflow.json-fil som API-format fra ComfyUI.",
 	"Manage": "Administrer",
 	"Manage": "Administrer",
 	"Manage Arena Models": "",
 	"Manage Arena Models": "",
+	"Manage Direct Connections": "",
 	"Manage Models": "",
 	"Manage Models": "",
 	"Manage Ollama": "",
 	"Manage Ollama": "",
 	"Manage Ollama API Connections": "",
 	"Manage Ollama API Connections": "",
@@ -722,6 +745,7 @@
 	"Plain text (.txt)": "Almindelig tekst (.txt)",
 	"Plain text (.txt)": "Almindelig tekst (.txt)",
 	"Playground": "Legeplads",
 	"Playground": "Legeplads",
 	"Please carefully review the following warnings:": "Gennemgå omhyggeligt følgende advarsler:",
 	"Please carefully review the following warnings:": "Gennemgå omhyggeligt følgende advarsler:",
+	"Please do not close the settings page while loading the model.": "",
 	"Please enter a prompt": "",
 	"Please enter a prompt": "",
 	"Please fill in all fields.": "Udfyld alle felter.",
 	"Please fill in all fields.": "Udfyld alle felter.",
 	"Please select a model first.": "",
 	"Please select a model first.": "",
@@ -754,7 +778,7 @@
 	"Read Aloud": "Læs højt",
 	"Read Aloud": "Læs højt",
 	"Reasoning Effort": "",
 	"Reasoning Effort": "",
 	"Record voice": "Optag stemme",
 	"Record voice": "Optag stemme",
-	"Redirecting you to OpenWebUI Community": "Omdirigerer dig til OpenWebUI Community",
+	"Redirecting you to Open WebUI Community": "Omdirigerer dig til OpenWebUI Community",
 	"Reduces the probability of generating nonsense. A higher value (e.g. 100) will give more diverse answers, while a lower value (e.g. 10) will be more conservative. (Default: 40)": "",
 	"Reduces the probability of generating nonsense. A higher value (e.g. 100) will give more diverse answers, while a lower value (e.g. 10) will be more conservative. (Default: 40)": "",
 	"Refer to yourself as \"User\" (e.g., \"User is learning Spanish\")": "Referer til dig selv som \"Bruger\" (f.eks. \"Bruger lærer spansk\")",
 	"Refer to yourself as \"User\" (e.g., \"User is learning Spanish\")": "Referer til dig selv som \"Bruger\" (f.eks. \"Bruger lærer spansk\")",
 	"References from": "",
 	"References from": "",
@@ -829,6 +853,7 @@
 	"Select a pipeline": "Vælg en pipeline",
 	"Select a pipeline": "Vælg en pipeline",
 	"Select a pipeline url": "Vælg en pipeline-URL",
 	"Select a pipeline url": "Vælg en pipeline-URL",
 	"Select a tool": "Vælg et værktøj",
 	"Select a tool": "Vælg et værktøj",
+	"Select an auth method": "",
 	"Select an Ollama instance": "",
 	"Select an Ollama instance": "",
 	"Select Engine": "Vælg engine",
 	"Select Engine": "Vælg engine",
 	"Select Knowledge": "Vælg viden",
 	"Select Knowledge": "Vælg viden",
@@ -869,7 +894,7 @@
 	"Settings saved successfully!": "Indstillinger gemt!",
 	"Settings saved successfully!": "Indstillinger gemt!",
 	"Share": "Del",
 	"Share": "Del",
 	"Share Chat": "Del chat",
 	"Share Chat": "Del chat",
-	"Share to OpenWebUI Community": "Del til OpenWebUI Community",
+	"Share to Open WebUI Community": "Del til OpenWebUI Community",
 	"Show": "Vis",
 	"Show": "Vis",
 	"Show \"What's New\" modal on login": "",
 	"Show \"What's New\" modal on login": "",
 	"Show Admin Details in Account Pending Overlay": "Vis administratordetaljer i overlay for ventende konto",
 	"Show Admin Details in Account Pending Overlay": "Vis administratordetaljer i overlay for ventende konto",
@@ -944,6 +969,7 @@
 	"This will reset the knowledge base and sync all files. Do you wish to continue?": "Dette vil nulstille vidensbasen og synkronisere alle filer. Vil du fortsætte?",
 	"This will reset the knowledge base and sync all files. Do you wish to continue?": "Dette vil nulstille vidensbasen og synkronisere alle filer. Vil du fortsætte?",
 	"Thorough explanation": "Grundig forklaring",
 	"Thorough explanation": "Grundig forklaring",
 	"Thought for {{DURATION}}": "",
 	"Thought for {{DURATION}}": "",
+	"Thought for {{DURATION}} seconds": "",
 	"Tika": "Tika",
 	"Tika": "Tika",
 	"Tika Server URL required.": "Tika-server-URL påkrævet.",
 	"Tika Server URL required.": "Tika-server-URL påkrævet.",
 	"Tiktoken": "",
 	"Tiktoken": "",

+ 130 - 104
src/lib/i18n/locales/de-DE/translation.json

@@ -1,11 +1,11 @@
 {
 {
-	"-1 for no limit, or a positive integer for a specific limit": "",
+	"-1 for no limit, or a positive integer for a specific limit": "-1 für kein Limit oder eine positive Zahl für ein spezifisches Limit",
 	"'s', 'm', 'h', 'd', 'w' or '-1' for no expiration.": "'s', 'm', 'h', 'd', 'w' oder '-1' für keine Ablaufzeit.",
 	"'s', 'm', 'h', 'd', 'w' or '-1' for no expiration.": "'s', 'm', 'h', 'd', 'w' oder '-1' für keine Ablaufzeit.",
 	"(e.g. `sh webui.sh --api --api-auth username_password`)": "(z. B. `sh webui.sh --api --api-auth username_password`)",
 	"(e.g. `sh webui.sh --api --api-auth username_password`)": "(z. B. `sh webui.sh --api --api-auth username_password`)",
 	"(e.g. `sh webui.sh --api`)": "(z. B. `sh webui.sh --api`)",
 	"(e.g. `sh webui.sh --api`)": "(z. B. `sh webui.sh --api`)",
 	"(latest)": "(neueste)",
 	"(latest)": "(neueste)",
 	"{{ models }}": "{{ Modelle }}",
 	"{{ models }}": "{{ Modelle }}",
-	"{{COUNT}} Replies": "",
+	"{{COUNT}} Replies": "{{COUNT}} Antworten",
 	"{{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) sind für die Bildgenerierung erforderlich",
 	"*Prompt node ID(s) are required for image generation": "*Prompt-Node-ID(s) sind für die Bildgenerierung erforderlich",
@@ -35,7 +35,7 @@
 	"Add Group": "Gruppe hinzufügen",
 	"Add Group": "Gruppe hinzufügen",
 	"Add Memory": "Erinnerung hinzufügen",
 	"Add Memory": "Erinnerung hinzufügen",
 	"Add Model": "Modell hinzufügen",
 	"Add Model": "Modell hinzufügen",
-	"Add Reaction": "",
+	"Add Reaction": "Reaktion hinzufügen",
 	"Add Tag": "Tag hinzufügen",
 	"Add Tag": "Tag hinzufügen",
 	"Add Tags": "Tags hinzufügen",
 	"Add Tags": "Tags hinzufügen",
 	"Add text content": "Textinhalt hinzufügen",
 	"Add text content": "Textinhalt hinzufügen",
@@ -51,7 +51,7 @@
 	"Advanced Params": "Erweiterte Parameter",
 	"Advanced Params": "Erweiterte Parameter",
 	"All Documents": "Alle Dokumente",
 	"All Documents": "Alle Dokumente",
 	"All models deleted successfully": "Alle Modelle erfolgreich gelöscht",
 	"All models deleted successfully": "Alle Modelle erfolgreich gelöscht",
-	"Allow Chat Controls": "",
+	"Allow Chat Controls": "Chat-Steuerung erlauben",
 	"Allow Chat Delete": "Löschen von Unterhaltungen erlauben",
 	"Allow Chat Delete": "Löschen von Unterhaltungen erlauben",
 	"Allow Chat Deletion": "Löschen von Unterhaltungen erlauben",
 	"Allow Chat Deletion": "Löschen von Unterhaltungen erlauben",
 	"Allow Chat Edit": "Bearbeiten von Unterhaltungen erlauben",
 	"Allow Chat Edit": "Bearbeiten von Unterhaltungen erlauben",
@@ -60,21 +60,21 @@
 	"Allow Temporary Chat": "Temporäre Unterhaltungen erlauben",
 	"Allow Temporary Chat": "Temporäre Unterhaltungen erlauben",
 	"Allow User Location": "Standort freigeben",
 	"Allow User Location": "Standort freigeben",
 	"Allow Voice Interruption in Call": "Unterbrechung durch Stimme im Anruf zulassen",
 	"Allow Voice Interruption in Call": "Unterbrechung durch Stimme im Anruf zulassen",
-	"Allowed Endpoints": "",
+	"Allowed Endpoints": "Erlaubte Endpunkte",
 	"Already have an account?": "Haben Sie bereits einen Account?",
 	"Already have an account?": "Haben Sie bereits einen Account?",
 	"Alternative to the top_p, and aims to ensure a balance of quality and variety. The parameter p represents the minimum probability for a token to be considered, relative to the probability of the most likely token. For example, with p=0.05 and the most likely token having a probability of 0.9, logits with a value less than 0.045 are filtered out. (Default: 0.0)": "Alternative zu top_p und zielt darauf ab, ein Gleichgewicht zwischen Qualität und Vielfalt zu gewährleisten. Der Parameter p repräsentiert die Mindestwahrscheinlichkeit für ein Token, um berücksichtigt zu werden, relativ zur Wahrscheinlichkeit des wahrscheinlichsten Tokens. Zum Beispiel, bei p=0.05 und das wahrscheinlichste Token hat eine Wahrscheinlichkeit von 0.9, werden Logits mit einem Wert von weniger als 0.045 herausgefiltert. (Standard: 0.0)",
 	"Alternative to the top_p, and aims to ensure a balance of quality and variety. The parameter p represents the minimum probability for a token to be considered, relative to the probability of the most likely token. For example, with p=0.05 and the most likely token having a probability of 0.9, logits with a value less than 0.045 are filtered out. (Default: 0.0)": "Alternative zu top_p und zielt darauf ab, ein Gleichgewicht zwischen Qualität und Vielfalt zu gewährleisten. Der Parameter p repräsentiert die Mindestwahrscheinlichkeit für ein Token, um berücksichtigt zu werden, relativ zur Wahrscheinlichkeit des wahrscheinlichsten Tokens. Zum Beispiel, bei p=0.05 und das wahrscheinlichste Token hat eine Wahrscheinlichkeit von 0.9, werden Logits mit einem Wert von weniger als 0.045 herausgefiltert. (Standard: 0.0)",
-	"Always": "",
+	"Always": "Immer",
 	"Amazing": "Fantastisch",
 	"Amazing": "Fantastisch",
 	"an assistant": "ein Assistent",
 	"an assistant": "ein Assistent",
-	"Analyzed": "",
-	"Analyzing...": "",
+	"Analyzed": "Analysiert",
+	"Analyzing...": "Analysiere...",
 	"and": "und",
 	"and": "und",
 	"and {{COUNT}} more": "und {{COUNT}} mehr",
 	"and {{COUNT}} more": "und {{COUNT}} mehr",
 	"and create a new shared link.": "und erstellen Sie einen neuen freigegebenen Link.",
 	"and create a new shared link.": "und erstellen Sie einen neuen freigegebenen Link.",
 	"API Base URL": "API-Basis-URL",
 	"API Base URL": "API-Basis-URL",
 	"API Key": "API-Schlüssel",
 	"API Key": "API-Schlüssel",
 	"API Key created.": "API-Schlüssel erstellt.",
 	"API Key created.": "API-Schlüssel erstellt.",
-	"API Key Endpoint Restrictions": "",
+	"API Key Endpoint Restrictions": "API-Schlüssel Endpunkteinschränkungen",
 	"API keys": "API-Schlüssel",
 	"API keys": "API-Schlüssel",
 	"Application DN": "Anwendungs-DN",
 	"Application DN": "Anwendungs-DN",
 	"Application DN Password": "Anwendungs-DN-Passwort",
 	"Application DN Password": "Anwendungs-DN-Passwort",
@@ -84,8 +84,8 @@
 	"Archive All Chats": "Alle Unterhaltungen archivieren",
 	"Archive All Chats": "Alle Unterhaltungen archivieren",
 	"Archived Chats": "Archivierte Unterhaltungen",
 	"Archived Chats": "Archivierte Unterhaltungen",
 	"archived-chat-export": "archivierter-chat-export",
 	"archived-chat-export": "archivierter-chat-export",
-	"Are you sure you want to delete this channel?": "",
-	"Are you sure you want to delete this message?": "",
+	"Are you sure you want to delete this channel?": "Sind Sie sicher, dass Sie diesen Kanal löschen möchten?",
+	"Are you sure you want to delete this message?": "Sind Sie sicher, dass Sie diese Nachricht löschen möchten?",
 	"Are you sure you want to unarchive all archived chats?": "Sind Sie sicher, dass Sie alle archivierten Unterhaltungen wiederherstellen möchten?",
 	"Are you sure you want to unarchive all archived chats?": "Sind Sie sicher, dass Sie alle archivierten Unterhaltungen wiederherstellen möchten?",
 	"Are you sure?": "Sind Sie sicher?",
 	"Are you sure?": "Sind Sie sicher?",
 	"Arena Models": "Arena-Modelle",
 	"Arena Models": "Arena-Modelle",
@@ -94,15 +94,15 @@
 	"Assistant": "Assistent",
 	"Assistant": "Assistent",
 	"Attach file": "Datei anhängen",
 	"Attach file": "Datei anhängen",
 	"Attention to detail": "Aufmerksamkeit für Details",
 	"Attention to detail": "Aufmerksamkeit für Details",
-	"Attribute for Mail": "",
+	"Attribute for Mail": "Attribut für E-Mail",
 	"Attribute for Username": "Attribut für Benutzername",
 	"Attribute for Username": "Attribut für Benutzername",
 	"Audio": "Audio",
 	"Audio": "Audio",
 	"August": "August",
 	"August": "August",
 	"Authenticate": "Authentifizieren",
 	"Authenticate": "Authentifizieren",
 	"Auto-Copy Response to Clipboard": "Antwort automatisch in die Zwischenablage kopieren",
 	"Auto-Copy Response to Clipboard": "Antwort automatisch in die Zwischenablage kopieren",
 	"Auto-playback response": "Antwort automatisch abspielen",
 	"Auto-playback response": "Antwort automatisch abspielen",
-	"Autocomplete Generation": "",
-	"Autocomplete Generation Input Max Length": "",
+	"Autocomplete Generation": "Automatische Vervollständigung",
+	"Autocomplete Generation Input Max Length": "Maximale Eingabenlände für automatische Vervollständigung",
 	"Automatic1111": "Automatic1111",
 	"Automatic1111": "Automatic1111",
 	"AUTOMATIC1111 Api Auth String": "AUTOMATIC1111-API-Authentifizierungszeichenfolge",
 	"AUTOMATIC1111 Api Auth String": "AUTOMATIC1111-API-Authentifizierungszeichenfolge",
 	"AUTOMATIC1111 Base URL": "AUTOMATIC1111-Basis-URL",
 	"AUTOMATIC1111 Base URL": "AUTOMATIC1111-Basis-URL",
@@ -119,9 +119,10 @@
 	"Batch Size (num_batch)": "Stapelgröße (num_batch)",
 	"Batch Size (num_batch)": "Stapelgröße (num_batch)",
 	"before": "bereits geteilt",
 	"before": "bereits geteilt",
 	"Being lazy": "Faulheit",
 	"Being lazy": "Faulheit",
-	"Beta": "",
+	"Beta": "Beta",
 	"Bing Search V7 Endpoint": "Bing Search V7-Endpunkt",
 	"Bing Search V7 Endpoint": "Bing Search V7-Endpunkt",
 	"Bing Search V7 Subscription Key": "Bing Search V7-Abonnement-Schlüssel",
 	"Bing Search V7 Subscription Key": "Bing Search V7-Abonnement-Schlüssel",
+	"Bocha Search API Key": "",
 	"Brave Search API Key": "Brave Search API-Schlüssel",
 	"Brave Search API Key": "Brave Search API-Schlüssel",
 	"By {{name}}": "Von {{name}}",
 	"By {{name}}": "Von {{name}}",
 	"Bypass SSL verification for Websites": "SSL-Überprüfung für Webseiten umgehen",
 	"Bypass SSL verification for Websites": "SSL-Überprüfung für Webseiten umgehen",
@@ -130,13 +131,13 @@
 	"Camera": "Kamera",
 	"Camera": "Kamera",
 	"Cancel": "Abbrechen",
 	"Cancel": "Abbrechen",
 	"Capabilities": "Fähigkeiten",
 	"Capabilities": "Fähigkeiten",
-	"Capture": "",
+	"Capture": "Aufnehmen",
 	"Certificate Path": "Zertifikatpfad",
 	"Certificate Path": "Zertifikatpfad",
 	"Change Password": "Passwort ändern",
 	"Change Password": "Passwort ändern",
-	"Channel Name": "",
-	"Channels": "",
+	"Channel Name": "Kanalname",
+	"Channels": "Kanäle",
 	"Character": "Zeichen",
 	"Character": "Zeichen",
-	"Character limit for autocomplete generation input": "",
+	"Character limit for autocomplete generation input": "Zeichenlimit für die Eingabe der automatischen Vervollständigung",
 	"Chart new frontiers": "Neue Wege beschreiten",
 	"Chart new frontiers": "Neue Wege beschreiten",
 	"Chat": "Gespräch",
 	"Chat": "Gespräch",
 	"Chat Background Image": "Hintergrundbild des Unterhaltungsfensters",
 	"Chat Background Image": "Hintergrundbild des Unterhaltungsfensters",
@@ -163,6 +164,7 @@
 	"Click here to": "Klicken Sie hier, um",
 	"Click here to": "Klicken Sie hier, um",
 	"Click here to download user import template file.": "Klicken Sie hier, um die Vorlage für den Benutzerimport herunterzuladen.",
 	"Click here to download user import template file.": "Klicken Sie hier, um die Vorlage für den Benutzerimport herunterzuladen.",
 	"Click here to learn more about faster-whisper and see the available models.": "Klicken Sie hier, um mehr über faster-whisper zu erfahren und die verfügbaren Modelle zu sehen.",
 	"Click here to learn more about faster-whisper and see the available models.": "Klicken Sie hier, um mehr über faster-whisper zu erfahren und die verfügbaren Modelle zu sehen.",
+	"Click here to see available models.": "",
 	"Click here to select": "Klicke Sie zum Auswählen hier",
 	"Click here to select": "Klicke Sie zum Auswählen hier",
 	"Click here to select a csv file.": "Klicken Sie zum Auswählen einer CSV-Datei hier.",
 	"Click here to select a csv file.": "Klicken Sie zum Auswählen einer CSV-Datei hier.",
 	"Click here to select a py file.": "Klicken Sie zum Auswählen einer py-Datei hier.",
 	"Click here to select a py file.": "Klicken Sie zum Auswählen einer py-Datei hier.",
@@ -171,16 +173,18 @@
 	"Click on the user role button to change a user's role.": "Klicken Sie auf die Benutzerrolle, um sie zu ändern.",
 	"Click on the user role button to change a user's role.": "Klicken Sie auf die Benutzerrolle, um sie zu ändern.",
 	"Clipboard write permission denied. Please check your browser settings to grant the necessary access.": "Schreibberechtigung für die Zwischenablage verweigert. Bitte überprüfen Sie Ihre Browsereinstellungen, um den erforderlichen Zugriff zu erlauben.",
 	"Clipboard write permission denied. Please check your browser settings to grant the necessary access.": "Schreibberechtigung für die Zwischenablage verweigert. Bitte überprüfen Sie Ihre Browsereinstellungen, um den erforderlichen Zugriff zu erlauben.",
 	"Clone": "Klonen",
 	"Clone": "Klonen",
-	"Clone Chat": "",
-	"Clone of {{TITLE}}": "",
+	"Clone Chat": "Konversation klonen",
+	"Clone of {{TITLE}}": "Klon von {{TITLE}}",
 	"Close": "Schließen",
 	"Close": "Schließen",
 	"Code execution": "Codeausführung",
 	"Code execution": "Codeausführung",
 	"Code formatted successfully": "Code erfolgreich formatiert",
 	"Code formatted successfully": "Code erfolgreich formatiert",
-	"Code Interpreter": "",
+	"Code Interpreter": "Code-Interpreter",
+	"Code Interpreter Engine": "",
+	"Code Interpreter Prompt Template": "",
 	"Collection": "Kollektion",
 	"Collection": "Kollektion",
 	"Color": "Farbe",
 	"Color": "Farbe",
 	"ComfyUI": "ComfyUI",
 	"ComfyUI": "ComfyUI",
-	"ComfyUI API Key": "",
+	"ComfyUI API Key": "ComfyUI-API-Schlüssel",
 	"ComfyUI Base URL": "ComfyUI-Basis-URL",
 	"ComfyUI Base URL": "ComfyUI-Basis-URL",
 	"ComfyUI Base URL is required.": "ComfyUI-Basis-URL wird benötigt.",
 	"ComfyUI Base URL is required.": "ComfyUI-Basis-URL wird benötigt.",
 	"ComfyUI Workflow": "ComfyUI-Workflow",
 	"ComfyUI Workflow": "ComfyUI-Workflow",
@@ -192,9 +196,10 @@
 	"Confirm": "Bestätigen",
 	"Confirm": "Bestätigen",
 	"Confirm Password": "Passwort bestätigen",
 	"Confirm Password": "Passwort bestätigen",
 	"Confirm your action": "Bestätigen Sie Ihre Aktion.",
 	"Confirm your action": "Bestätigen Sie Ihre Aktion.",
-	"Confirm your new password": "",
+	"Confirm your new password": "Neues Passwort bestätigen",
+	"Connect to your own OpenAI compatible API endpoints.": "",
 	"Connections": "Verbindungen",
 	"Connections": "Verbindungen",
-	"Constrains effort on reasoning for reasoning models. Only applicable to reasoning models from specific providers that support reasoning effort. (Default: medium)": "",
+	"Constrains effort on reasoning for reasoning models. Only applicable to reasoning models from specific providers that support reasoning effort. (Default: medium)": "Beschränkt den Aufwand für das Schlussfolgern bei Schlussfolgerungsmodellen. Nur anwendbar auf Schlussfolgerungsmodelle von spezifischen Anbietern, die den Schlussfolgerungsaufwand unterstützen. (Standard: medium)",
 	"Contact Admin for WebUI Access": "Kontaktieren Sie den Administrator für den Zugriff auf die Weboberfläche",
 	"Contact Admin for WebUI Access": "Kontaktieren Sie den Administrator für den Zugriff auf die Weboberfläche",
 	"Content": "Info",
 	"Content": "Info",
 	"Content Extraction": "Inhaltsextraktion",
 	"Content Extraction": "Inhaltsextraktion",
@@ -215,12 +220,13 @@
 	"Copy Link": "Link kopieren",
 	"Copy Link": "Link kopieren",
 	"Copy to clipboard": "In die Zwischenablage kopieren",
 	"Copy to clipboard": "In die Zwischenablage kopieren",
 	"Copying to clipboard was successful!": "Das Kopieren in die Zwischenablage war erfolgreich!",
 	"Copying to clipboard was successful!": "Das Kopieren in die Zwischenablage war erfolgreich!",
+	"CORS must be properly configured by the provider to allow requests from Open WebUI.": "",
 	"Create": "Erstellen",
 	"Create": "Erstellen",
 	"Create a knowledge base": "Wissensspeicher erstellen",
 	"Create a knowledge base": "Wissensspeicher erstellen",
 	"Create a model": "Modell erstellen",
 	"Create a model": "Modell erstellen",
 	"Create Account": "Konto erstellen",
 	"Create Account": "Konto erstellen",
 	"Create Admin Account": "Administrator-Account erstellen",
 	"Create Admin Account": "Administrator-Account erstellen",
-	"Create Channel": "",
+	"Create Channel": "Kanal erstellen",
 	"Create Group": "Gruppe erstellen",
 	"Create Group": "Gruppe erstellen",
 	"Create Knowledge": "Wissen erstellen",
 	"Create Knowledge": "Wissen erstellen",
 	"Create new key": "Neuen Schlüssel erstellen",
 	"Create new key": "Neuen Schlüssel erstellen",
@@ -238,10 +244,10 @@
 	"Default": "Standard",
 	"Default": "Standard",
 	"Default (Open AI)": "Standard (Open AI)",
 	"Default (Open AI)": "Standard (Open AI)",
 	"Default (SentenceTransformers)": "Standard (SentenceTransformers)",
 	"Default (SentenceTransformers)": "Standard (SentenceTransformers)",
-	"Default mode works with a wider range of models by calling tools once before execution. Native mode leverages the model’s built-in tool-calling capabilities, but requires the model to inherently support this feature.": "",
+	"Default mode works with a wider range of models by calling tools once before execution. Native mode leverages the model’s built-in tool-calling capabilities, but requires the model to inherently support this feature.": "Der Standardmodus funktioniert mit einer breiteren Auswahl von Modellen, indem er Werkzeuge einmal vor der Ausführung aufruft. Der native Modus nutzt die integrierten Tool-Aufrufmöglichkeiten des Modells, erfordert jedoch, dass das Modell diese Funktion von Natur aus unterstützt.",
 	"Default Model": "Standardmodell",
 	"Default Model": "Standardmodell",
 	"Default model updated": "Standardmodell aktualisiert",
 	"Default model updated": "Standardmodell aktualisiert",
-	"Default Models": "",
+	"Default Models": "Standardmodelle",
 	"Default permissions": "Standardberechtigungen",
 	"Default permissions": "Standardberechtigungen",
 	"Default permissions updated successfully": "Standardberechtigungen erfolgreich aktualisiert",
 	"Default permissions updated successfully": "Standardberechtigungen erfolgreich aktualisiert",
 	"Default Prompt Suggestions": "Prompt-Vorschläge",
 	"Default Prompt Suggestions": "Prompt-Vorschläge",
@@ -257,7 +263,7 @@
 	"Delete chat?": "Unterhaltung löschen?",
 	"Delete chat?": "Unterhaltung löschen?",
 	"Delete folder?": "Ordner löschen?",
 	"Delete folder?": "Ordner löschen?",
 	"Delete function?": "Funktion löschen?",
 	"Delete function?": "Funktion löschen?",
-	"Delete Message": "",
+	"Delete Message": "Nachricht löschen",
 	"Delete prompt?": "Prompt löschen?",
 	"Delete prompt?": "Prompt löschen?",
 	"delete this link": "diesen Link löschen",
 	"delete this link": "diesen Link löschen",
 	"Delete tool?": "Werkzeug löschen?",
 	"Delete tool?": "Werkzeug löschen?",
@@ -268,6 +274,9 @@
 	"Describe your knowledge base and objectives": "Beschreibe deinen Wissensspeicher und deine Ziele",
 	"Describe your knowledge base and objectives": "Beschreibe deinen Wissensspeicher und deine Ziele",
 	"Description": "Beschreibung",
 	"Description": "Beschreibung",
 	"Didn't fully follow instructions": "Nicht genau den Answeisungen gefolgt",
 	"Didn't fully follow instructions": "Nicht genau den Answeisungen gefolgt",
+	"Direct Connections": "",
+	"Direct Connections allow users to connect to their own OpenAI compatible API endpoints.": "",
+	"Direct Connections settings updated": "",
 	"Disabled": "Deaktiviert",
 	"Disabled": "Deaktiviert",
 	"Discover a function": "Entdecken Sie weitere Funktionen",
 	"Discover a function": "Entdecken Sie weitere Funktionen",
 	"Discover a model": "Entdecken Sie weitere Modelle",
 	"Discover a model": "Entdecken Sie weitere Modelle",
@@ -290,6 +299,7 @@
 	"Documentation": "Dokumentation",
 	"Documentation": "Dokumentation",
 	"Documents": "Dokumente",
 	"Documents": "Dokumente",
 	"does not make any external connections, and your data stays securely on your locally hosted server.": "stellt keine externen Verbindungen her, und Ihre Daten bleiben sicher auf Ihrem lokal gehosteten Server.",
 	"does not make any external connections, and your data stays securely on your locally hosted server.": "stellt keine externen Verbindungen her, und Ihre Daten bleiben sicher auf Ihrem lokal gehosteten Server.",
+	"Domain Filter List": "",
 	"Don't have an account?": "Haben Sie noch kein Benutzerkonto?",
 	"Don't have an account?": "Haben Sie noch kein Benutzerkonto?",
 	"don't install random functions from sources you don't trust.": "installieren Sie keine Funktionen aus Quellen, denen Sie nicht vertrauen.",
 	"don't install random functions from sources you don't trust.": "installieren Sie keine Funktionen aus Quellen, denen Sie nicht vertrauen.",
 	"don't install random tools from sources you don't trust.": "installieren Sie keine Werkzeuge aus Quellen, denen Sie nicht vertrauen.",
 	"don't install random tools from sources you don't trust.": "installieren Sie keine Werkzeuge aus Quellen, denen Sie nicht vertrauen.",
@@ -310,7 +320,7 @@
 	"e.g. Tools for performing various operations": "z. B. Werkzeuge für verschiedene Operationen",
 	"e.g. Tools for performing various operations": "z. B. Werkzeuge für verschiedene Operationen",
 	"Edit": "Bearbeiten",
 	"Edit": "Bearbeiten",
 	"Edit Arena Model": "Arena-Modell bearbeiten",
 	"Edit Arena Model": "Arena-Modell bearbeiten",
-	"Edit Channel": "",
+	"Edit Channel": "Kanal bearbeiten",
 	"Edit Connection": "Verbindung bearbeiten",
 	"Edit Connection": "Verbindung bearbeiten",
 	"Edit Default Permissions": "Standardberechtigungen bearbeiten",
 	"Edit Default Permissions": "Standardberechtigungen bearbeiten",
 	"Edit Memory": "Erinnerungen bearbeiten",
 	"Edit Memory": "Erinnerungen bearbeiten",
@@ -323,10 +333,11 @@
 	"Embedding Model": "Embedding-Modell",
 	"Embedding Model": "Embedding-Modell",
 	"Embedding Model Engine": "Embedding-Modell-Engine",
 	"Embedding Model Engine": "Embedding-Modell-Engine",
 	"Embedding model set to \"{{embedding_model}}\"": "Embedding-Modell auf \"{{embedding_model}}\" gesetzt",
 	"Embedding model set to \"{{embedding_model}}\"": "Embedding-Modell auf \"{{embedding_model}}\" gesetzt",
-	"Enable API Key": "",
-	"Enable autocomplete generation for chat messages": "",
+	"Enable API Key": "API-Schlüssel aktivieren",
+	"Enable autocomplete generation for chat messages": "Automatische Vervollständigung für Chat-Nachrichten aktivieren",
+	"Enable Code Interpreter": "",
 	"Enable Community Sharing": "Community-Freigabe aktivieren",
 	"Enable Community Sharing": "Community-Freigabe aktivieren",
-	"Enable Google Drive": "",
+	"Enable Google Drive": "Google Drive aktivieren",
 	"Enable Memory Locking (mlock) to prevent model data from being swapped out of RAM. This option locks the model's working set of pages into RAM, ensuring that they will not be swapped out to disk. This can help maintain performance by avoiding page faults and ensuring fast data access.": "Aktiviere Memory Locking (mlock), um zu verhindern, dass Modelldaten aus dem RAM ausgelagert werden. Diese Option sperrt die Arbeitsseiten des Modells im RAM, um sicherzustellen, dass sie nicht auf die Festplatte ausgelagert werden. Dies kann die Leistung verbessern, indem Page Faults vermieden und ein schneller Datenzugriff sichergestellt werden.",
 	"Enable Memory Locking (mlock) to prevent model data from being swapped out of RAM. This option locks the model's working set of pages into RAM, ensuring that they will not be swapped out to disk. This can help maintain performance by avoiding page faults and ensuring fast data access.": "Aktiviere Memory Locking (mlock), um zu verhindern, dass Modelldaten aus dem RAM ausgelagert werden. Diese Option sperrt die Arbeitsseiten des Modells im RAM, um sicherzustellen, dass sie nicht auf die Festplatte ausgelagert werden. Dies kann die Leistung verbessern, indem Page Faults vermieden und ein schneller Datenzugriff sichergestellt werden.",
 	"Enable Memory Mapping (mmap) to load model data. This option allows the system to use disk storage as an extension of RAM by treating disk files as if they were in RAM. This can improve model performance by allowing for faster data access. However, it may not work correctly with all systems and can consume a significant amount of disk space.": "Aktiviere Memory Mapping (mmap), um Modelldaten zu laden. Diese Option ermöglicht es dem System, den Festplattenspeicher als Erweiterung des RAM zu verwenden, indem Festplattendateien so behandelt werden, als ob sie im RAM wären. Dies kann die Modellleistung verbessern, indem ein schnellerer Datenzugriff ermöglicht wird. Es kann jedoch nicht auf allen Systemen korrekt funktionieren und einen erheblichen Teil des Festplattenspeichers beanspruchen.",
 	"Enable Memory Mapping (mmap) to load model data. This option allows the system to use disk storage as an extension of RAM by treating disk files as if they were in RAM. This can improve model performance by allowing for faster data access. However, it may not work correctly with all systems and can consume a significant amount of disk space.": "Aktiviere Memory Mapping (mmap), um Modelldaten zu laden. Diese Option ermöglicht es dem System, den Festplattenspeicher als Erweiterung des RAM zu verwenden, indem Festplattendateien so behandelt werden, als ob sie im RAM wären. Dies kann die Modellleistung verbessern, indem ein schnellerer Datenzugriff ermöglicht wird. Es kann jedoch nicht auf allen Systemen korrekt funktionieren und einen erheblichen Teil des Festplattenspeichers beanspruchen.",
 	"Enable Message Rating": "Nachrichtenbewertung aktivieren",
 	"Enable Message Rating": "Nachrichtenbewertung aktivieren",
@@ -343,26 +354,31 @@
 	"Enter Application DN Password": "Geben Sie das Anwendungs-DN-Passwort ein",
 	"Enter Application DN Password": "Geben Sie das Anwendungs-DN-Passwort ein",
 	"Enter Bing Search V7 Endpoint": "Geben Sie den Bing Search V7-Endpunkt ein",
 	"Enter Bing Search V7 Endpoint": "Geben Sie den Bing Search V7-Endpunkt ein",
 	"Enter Bing Search V7 Subscription Key": "Geben Sie den Bing Search V7-Abonnement-Schlüssel ein",
 	"Enter Bing Search V7 Subscription Key": "Geben Sie den Bing Search V7-Abonnement-Schlüssel ein",
+	"Enter Bocha Search API Key": "",
 	"Enter Brave Search API Key": "Geben Sie den Brave Search API-Schlüssel ein",
 	"Enter Brave Search API Key": "Geben Sie den Brave Search API-Schlüssel ein",
 	"Enter certificate path": "Geben Sie den Zertifikatpfad ein",
 	"Enter certificate path": "Geben Sie den Zertifikatpfad ein",
 	"Enter CFG Scale (e.g. 7.0)": "Geben Sie die CFG-Skala ein (z. B. 7.0)",
 	"Enter CFG Scale (e.g. 7.0)": "Geben Sie die CFG-Skala ein (z. B. 7.0)",
 	"Enter Chunk Overlap": "Geben Sie die Blocküberlappung ein",
 	"Enter Chunk Overlap": "Geben Sie die Blocküberlappung ein",
 	"Enter Chunk Size": "Geben Sie die Blockgröße ein",
 	"Enter Chunk Size": "Geben Sie die Blockgröße ein",
 	"Enter description": "Geben Sie eine Beschreibung ein",
 	"Enter description": "Geben Sie eine Beschreibung ein",
-	"Enter Exa API Key": "",
+	"Enter domains separated by commas (e.g., example.com,site.org)": "",
+	"Enter Exa API Key": "Geben Sie den Exa-API-Schlüssel ein",
 	"Enter Github Raw URL": "Geben Sie die Github Raw-URL ein",
 	"Enter Github Raw URL": "Geben Sie die Github Raw-URL ein",
 	"Enter Google PSE API Key": "Geben Sie den Google PSE-API-Schlüssel ein",
 	"Enter Google PSE API Key": "Geben Sie den Google PSE-API-Schlüssel ein",
 	"Enter Google PSE Engine Id": "Geben Sie die Google PSE-Engine-ID ein",
 	"Enter Google PSE Engine Id": "Geben Sie die Google PSE-Engine-ID ein",
 	"Enter Image Size (e.g. 512x512)": "Geben Sie die Bildgröße ein (z. B. 512x512)",
 	"Enter Image Size (e.g. 512x512)": "Geben Sie die Bildgröße ein (z. B. 512x512)",
 	"Enter Jina API Key": "Geben Sie den Jina-API-Schlüssel ein",
 	"Enter Jina API Key": "Geben Sie den Jina-API-Schlüssel ein",
-	"Enter Kagi Search API Key": "",
+	"Enter Jupyter Password": "",
+	"Enter Jupyter Token": "",
+	"Enter Jupyter URL": "",
+	"Enter Kagi Search API Key": "Geben sie den Kagi Search API-Schlüssel ein",
 	"Enter language codes": "Geben Sie die Sprachcodes ein",
 	"Enter language codes": "Geben Sie die Sprachcodes ein",
 	"Enter Model ID": "Geben Sie die Modell-ID ein",
 	"Enter Model ID": "Geben Sie die Modell-ID ein",
 	"Enter model tag (e.g. {{modelTag}})": "Geben Sie den Model-Tag ein",
 	"Enter model tag (e.g. {{modelTag}})": "Geben Sie den Model-Tag ein",
 	"Enter Mojeek Search API Key": "Geben Sie den Mojeek Search API-Schlüssel ein",
 	"Enter Mojeek Search API Key": "Geben Sie den Mojeek Search API-Schlüssel ein",
 	"Enter Number of Steps (e.g. 50)": "Geben Sie die Anzahl an Schritten ein (z. B. 50)",
 	"Enter Number of Steps (e.g. 50)": "Geben Sie die Anzahl an Schritten ein (z. B. 50)",
-	"Enter proxy URL (e.g. https://user:password@host:port)": "",
-	"Enter reasoning effort": "",
+	"Enter proxy URL (e.g. https://user:password@host:port)": "Geben sie die Proxy-URL ein (z. B. https://user:password@host:port)",
+	"Enter reasoning effort": "Geben Sie den Schlussfolgerungsaufwand ein",
 	"Enter Sampler (e.g. Euler a)": "Geben Sie den Sampler ein (z. B. Euler a)",
 	"Enter Sampler (e.g. Euler a)": "Geben Sie den Sampler ein (z. B. Euler a)",
 	"Enter Scheduler (e.g. Karras)": "Geben Sie den Scheduler ein (z. B. Karras)",
 	"Enter Scheduler (e.g. Karras)": "Geben Sie den Scheduler ein (z. B. Karras)",
 	"Enter Score": "Punktzahl eingeben",
 	"Enter Score": "Punktzahl eingeben",
@@ -379,33 +395,33 @@
 	"Enter stop sequence": "Stop-Sequenz eingeben",
 	"Enter stop sequence": "Stop-Sequenz eingeben",
 	"Enter system prompt": "Systemprompt eingeben",
 	"Enter system prompt": "Systemprompt eingeben",
 	"Enter Tavily API Key": "Geben Sie den Tavily-API-Schlüssel ein",
 	"Enter Tavily API Key": "Geben Sie den Tavily-API-Schlüssel ein",
-	"Enter the public URL of your WebUI. This URL will be used to generate links in the notifications.": "",
+	"Enter the public URL of your WebUI. This URL will be used to generate links in the notifications.": "Geben sie die öffentliche URL Ihrer WebUI ein. Diese URL wird verwendet, um Links in den Benachrichtigungen zu generieren.",
 	"Enter Tika Server URL": "Geben Sie die Tika-Server-URL ein",
 	"Enter Tika Server URL": "Geben Sie die Tika-Server-URL ein",
 	"Enter Top K": "Geben Sie Top K ein",
 	"Enter Top K": "Geben Sie Top K ein",
 	"Enter URL (e.g. http://127.0.0.1:7860/)": "Geben Sie die URL ein (z. B. http://127.0.0.1:7860/)",
 	"Enter URL (e.g. http://127.0.0.1:7860/)": "Geben Sie die URL ein (z. B. http://127.0.0.1:7860/)",
 	"Enter URL (e.g. http://localhost:11434)": "Geben Sie die URL ein (z. B. http://localhost:11434)",
 	"Enter URL (e.g. http://localhost:11434)": "Geben Sie die URL ein (z. B. http://localhost:11434)",
-	"Enter your current password": "",
+	"Enter your current password": "Geben Sie Ihr aktuelles Passwort ein",
 	"Enter Your Email": "Geben Sie Ihre E-Mail-Adresse ein",
 	"Enter Your Email": "Geben Sie Ihre E-Mail-Adresse ein",
 	"Enter Your Full Name": "Geben Sie Ihren vollständigen Namen ein",
 	"Enter Your Full Name": "Geben Sie Ihren vollständigen Namen ein",
 	"Enter your message": "Geben Sie Ihre Nachricht ein",
 	"Enter your message": "Geben Sie Ihre Nachricht ein",
-	"Enter your new password": "",
+	"Enter your new password": "Geben Sie Ihr neues Passwort ein",
 	"Enter Your Password": "Geben Sie Ihr Passwort ein",
 	"Enter Your Password": "Geben Sie Ihr Passwort ein",
 	"Enter Your Role": "Geben Sie Ihre Rolle ein",
 	"Enter Your Role": "Geben Sie Ihre Rolle ein",
 	"Enter Your Username": "Geben Sie Ihren Benutzernamen ein",
 	"Enter Your Username": "Geben Sie Ihren Benutzernamen ein",
-	"Enter your webhook URL": "",
+	"Enter your webhook URL": "Geben Sie Ihre Webhook-URL ein",
 	"Error": "Fehler",
 	"Error": "Fehler",
 	"ERROR": "FEHLER",
 	"ERROR": "FEHLER",
-	"Error accessing Google Drive: {{error}}": "",
-	"Error uploading file: {{error}}": "",
+	"Error accessing Google Drive: {{error}}": "Fehler beim Zugriff auf Google Drive: {{error}}",
+	"Error uploading file: {{error}}": "Fehler beim Hochladen der Datei: {{error}}",
 	"Evaluations": "Evaluationen",
 	"Evaluations": "Evaluationen",
-	"Exa API Key": "",
+	"Exa API Key": "Exa-API-Schlüssel",
 	"Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Beispiel: (&(objectClass=inetOrgPerson)(uid=%s))",
 	"Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Beispiel: (&(objectClass=inetOrgPerson)(uid=%s))",
 	"Example: ALL": "Beispiel: ALL",
 	"Example: ALL": "Beispiel: ALL",
-	"Example: mail": "",
+	"Example: mail": "Beispiel: mail",
 	"Example: ou=users,dc=foo,dc=example": "Beispiel: ou=users,dc=foo,dc=example",
 	"Example: ou=users,dc=foo,dc=example": "Beispiel: ou=users,dc=foo,dc=example",
 	"Example: sAMAccountName or uid or userPrincipalName": "Beispiel: sAMAccountName or uid or userPrincipalName",
 	"Example: sAMAccountName or uid or userPrincipalName": "Beispiel: sAMAccountName or uid or userPrincipalName",
 	"Exclude": "Ausschließen",
 	"Exclude": "Ausschließen",
-	"Execute code for analysis": "",
+	"Execute code for analysis": "Code für Analyse ausführen",
 	"Experimental": "Experimentell",
 	"Experimental": "Experimentell",
 	"Explore the cosmos": "Erforschen Sie das Universum",
 	"Explore the cosmos": "Erforschen Sie das Universum",
 	"Export": "Exportieren",
 	"Export": "Exportieren",
@@ -423,12 +439,12 @@
 	"External Models": "Externe Modelle",
 	"External Models": "Externe Modelle",
 	"Failed to add file.": "Fehler beim Hinzufügen der Datei.",
 	"Failed to add file.": "Fehler beim Hinzufügen der Datei.",
 	"Failed to create API Key.": "Fehler beim Erstellen des API-Schlüssels.",
 	"Failed to create API Key.": "Fehler beim Erstellen des API-Schlüssels.",
-	"Failed to fetch models": "",
+	"Failed to fetch models": "Fehler beim Abrufen der Modelle",
 	"Failed to read clipboard contents": "Fehler beim Abruf der Zwischenablage",
 	"Failed to read clipboard contents": "Fehler beim Abruf der Zwischenablage",
-	"Failed to save models configuration": "",
+	"Failed to save models configuration": "Fehler beim Speichern der Modellkonfiguration",
 	"Failed to update settings": "Fehler beim Aktualisieren der Einstellungen",
 	"Failed to update settings": "Fehler beim Aktualisieren der Einstellungen",
 	"Failed to upload file.": "Fehler beim Hochladen der Datei.",
 	"Failed to upload file.": "Fehler beim Hochladen der Datei.",
-	"Features Permissions": "",
+	"Features Permissions": "Funktionen-Berechtigungen",
 	"February": "Februar",
 	"February": "Februar",
 	"Feedback History": "Feedback-Verlauf",
 	"Feedback History": "Feedback-Verlauf",
 	"Feedbacks": "Feedbacks",
 	"Feedbacks": "Feedbacks",
@@ -440,7 +456,7 @@
 	"File not found.": "Datei nicht gefunden.",
 	"File not found.": "Datei nicht gefunden.",
 	"File removed successfully.": "Datei erfolgreich entfernt.",
 	"File removed successfully.": "Datei erfolgreich entfernt.",
 	"File size should not exceed {{maxSize}} MB.": "Datei darf nicht größer als {{maxSize}} MB sein.",
 	"File size should not exceed {{maxSize}} MB.": "Datei darf nicht größer als {{maxSize}} MB sein.",
-	"File uploaded successfully": "",
+	"File uploaded successfully": "Datei erfolgreich hochgeladen",
 	"Files": "Dateien",
 	"Files": "Dateien",
 	"Filter is now globally disabled": "Filter ist jetzt global deaktiviert",
 	"Filter is now globally disabled": "Filter ist jetzt global deaktiviert",
 	"Filter is now globally enabled": "Filter ist jetzt global aktiviert",
 	"Filter is now globally enabled": "Filter ist jetzt global aktiviert",
@@ -458,7 +474,7 @@
 	"Format your variables using brackets like this:": "Formatieren Sie Ihre Variablen mit Klammern, wie hier:",
 	"Format your variables using brackets like this:": "Formatieren Sie Ihre Variablen mit Klammern, wie hier:",
 	"Frequency Penalty": "Frequenzstrafe",
 	"Frequency Penalty": "Frequenzstrafe",
 	"Function": "Funktion",
 	"Function": "Funktion",
-	"Function Calling": "",
+	"Function Calling": "Funktionsaufruf",
 	"Function created successfully": "Funktion erfolgreich erstellt",
 	"Function created successfully": "Funktion erfolgreich erstellt",
 	"Function deleted successfully": "Funktion erfolgreich gelöscht",
 	"Function deleted successfully": "Funktion erfolgreich gelöscht",
 	"Function Description": "Funktionsbeschreibung",
 	"Function Description": "Funktionsbeschreibung",
@@ -473,14 +489,14 @@
 	"Functions imported successfully": "Funktionen erfolgreich importiert",
 	"Functions imported successfully": "Funktionen erfolgreich importiert",
 	"General": "Allgemein",
 	"General": "Allgemein",
 	"General Settings": "Allgemeine Einstellungen",
 	"General Settings": "Allgemeine Einstellungen",
-	"Generate an image": "",
+	"Generate an image": "Bild erzeugen",
 	"Generate Image": "Bild erzeugen",
 	"Generate Image": "Bild erzeugen",
 	"Generating search query": "Suchanfrage wird erstellt",
 	"Generating search query": "Suchanfrage wird erstellt",
 	"Get started": "Loslegen",
 	"Get started": "Loslegen",
 	"Get started with {{WEBUI_NAME}}": "Loslegen mit {{WEBUI_NAME}}",
 	"Get started with {{WEBUI_NAME}}": "Loslegen mit {{WEBUI_NAME}}",
 	"Global": "Global",
 	"Global": "Global",
 	"Good Response": "Gute Antwort",
 	"Good Response": "Gute Antwort",
-	"Google Drive": "",
+	"Google Drive": "Google Drive",
 	"Google PSE API Key": "Google PSE-API-Schlüssel",
 	"Google PSE API Key": "Google PSE-API-Schlüssel",
 	"Google PSE Engine Id": "Google PSE-Engine-ID",
 	"Google PSE Engine Id": "Google PSE-Engine-ID",
 	"Group created successfully": "Gruppe erfolgreich erstellt",
 	"Group created successfully": "Gruppe erfolgreich erstellt",
@@ -504,14 +520,14 @@
 	"I acknowledge that I have read and I understand the implications of my action. I am aware of the risks associated with executing arbitrary code and I have verified the trustworthiness of the source.": "Ich bestätige, dass ich gelesen habe und die Auswirkungen meiner Aktion verstehe. Mir sind die Risiken bewusst, die mit der Ausführung beliebigen Codes verbunden sind, und ich habe die Vertrauenswürdigkeit der Quelle überprüft.",
 	"I acknowledge that I have read and I understand the implications of my action. I am aware of the risks associated with executing arbitrary code and I have verified the trustworthiness of the source.": "Ich bestätige, dass ich gelesen habe und die Auswirkungen meiner Aktion verstehe. Mir sind die Risiken bewusst, die mit der Ausführung beliebigen Codes verbunden sind, und ich habe die Vertrauenswürdigkeit der Quelle überprüft.",
 	"ID": "ID",
 	"ID": "ID",
 	"Ignite curiosity": "Neugier entfachen",
 	"Ignite curiosity": "Neugier entfachen",
-	"Image": "",
-	"Image Compression": "",
-	"Image Generation": "",
+	"Image": "Bild",
+	"Image Compression": "Bildkomprimierung",
+	"Image Generation": "Bildgenerierung",
 	"Image Generation (Experimental)": "Bildgenerierung (experimentell)",
 	"Image Generation (Experimental)": "Bildgenerierung (experimentell)",
 	"Image Generation Engine": "Bildgenerierungs-Engine",
 	"Image Generation Engine": "Bildgenerierungs-Engine",
-	"Image Max Compression Size": "",
-	"Image Prompt Generation": "",
-	"Image Prompt Generation Prompt": "",
+	"Image Max Compression Size": "Maximale Bildkomprimierungsgröße",
+	"Image Prompt Generation": "Bild-Prompt-Generierung",
+	"Image Prompt Generation Prompt": "Prompt für die Bild-Prompt-Generierung",
 	"Image Settings": "Bildeinstellungen",
 	"Image Settings": "Bildeinstellungen",
 	"Images": "Bilder",
 	"Images": "Bilder",
 	"Import Chats": "Unterhaltungen importieren",
 	"Import Chats": "Unterhaltungen importieren",
@@ -532,7 +548,7 @@
 	"Interface": "Benutzeroberfläche",
 	"Interface": "Benutzeroberfläche",
 	"Invalid file format.": "Ungültiges Dateiformat.",
 	"Invalid file format.": "Ungültiges Dateiformat.",
 	"Invalid Tag": "Ungültiger Tag",
 	"Invalid Tag": "Ungültiger Tag",
-	"is typing...": "",
+	"is typing...": "schreibt ...",
 	"January": "Januar",
 	"January": "Januar",
 	"Jina API Key": "Jina-API-Schlüssel",
 	"Jina API Key": "Jina-API-Schlüssel",
 	"join our Discord for help.": "Treten Sie unserem Discord bei, um Hilfe zu erhalten.",
 	"join our Discord for help.": "Treten Sie unserem Discord bei, um Hilfe zu erhalten.",
@@ -540,9 +556,11 @@
 	"JSON Preview": "JSON-Vorschau",
 	"JSON Preview": "JSON-Vorschau",
 	"July": "Juli",
 	"July": "Juli",
 	"June": "Juni",
 	"June": "Juni",
+	"Jupyter Auth": "",
+	"Jupyter URL": "",
 	"JWT Expiration": "JWT-Ablauf",
 	"JWT Expiration": "JWT-Ablauf",
 	"JWT Token": "JWT-Token",
 	"JWT Token": "JWT-Token",
-	"Kagi Search API Key": "",
+	"Kagi Search API Key": "Kagi Search API-Schlüssel",
 	"Keep Alive": "Verbindung aufrechterhalten",
 	"Keep Alive": "Verbindung aufrechterhalten",
 	"Key": "Schlüssel",
 	"Key": "Schlüssel",
 	"Keyboard shortcuts": "Tastenkombinationen",
 	"Keyboard shortcuts": "Tastenkombinationen",
@@ -552,12 +570,14 @@
 	"Knowledge deleted successfully.": "Wissen erfolgreich gelöscht.",
 	"Knowledge deleted successfully.": "Wissen erfolgreich gelöscht.",
 	"Knowledge reset successfully.": "Wissen erfolgreich zurückgesetzt.",
 	"Knowledge reset successfully.": "Wissen erfolgreich zurückgesetzt.",
 	"Knowledge updated successfully": "Wissen erfolgreich aktualisiert",
 	"Knowledge updated successfully": "Wissen erfolgreich aktualisiert",
+	"Kokoro.js (Browser)": "",
+	"Kokoro.js Dtype": "",
 	"Label": "Label",
 	"Label": "Label",
 	"Landing Page Mode": "Startseitenmodus",
 	"Landing Page Mode": "Startseitenmodus",
 	"Language": "Sprache",
 	"Language": "Sprache",
 	"Last Active": "Zuletzt aktiv",
 	"Last Active": "Zuletzt aktiv",
 	"Last Modified": "Zuletzt bearbeitet",
 	"Last Modified": "Zuletzt bearbeitet",
-	"Last reply": "",
+	"Last reply": "Letzte Antwort",
 	"LDAP": "LDAP",
 	"LDAP": "LDAP",
 	"LDAP server updated": "LDAP-Server aktualisiert",
 	"LDAP server updated": "LDAP-Server aktualisiert",
 	"Leaderboard": "Bestenliste",
 	"Leaderboard": "Bestenliste",
@@ -566,20 +586,23 @@
 	"Leave empty to include all models from \"{{URL}}/models\" endpoint": "Leer lassen, um alle Modelle vom \"{{URL}}/models\"-Endpunkt einzuschließen",
 	"Leave empty to include all models from \"{{URL}}/models\" endpoint": "Leer lassen, um alle Modelle vom \"{{URL}}/models\"-Endpunkt einzuschließen",
 	"Leave empty to include all models or select specific models": "Leer lassen, um alle Modelle einzuschließen oder spezifische Modelle auszuwählen",
 	"Leave empty to include all models or select specific models": "Leer lassen, um alle Modelle einzuschließen oder spezifische Modelle auszuwählen",
 	"Leave empty to use the default prompt, or enter a custom prompt": "Leer lassen, um den Standardprompt zu verwenden, oder geben Sie einen benutzerdefinierten Prompt ein",
 	"Leave empty to use the default prompt, or enter a custom prompt": "Leer lassen, um den Standardprompt zu verwenden, oder geben Sie einen benutzerdefinierten Prompt ein",
+	"Leave model field empty to use the default model.": "",
 	"Light": "Hell",
 	"Light": "Hell",
 	"Listening...": "Höre zu...",
 	"Listening...": "Höre zu...",
-	"Llama.cpp": "",
+	"Llama.cpp": "Llama.cpp",
 	"LLMs can make mistakes. Verify important information.": "LLMs können Fehler machen. Überprüfe wichtige Informationen.",
 	"LLMs can make mistakes. Verify important information.": "LLMs können Fehler machen. Überprüfe wichtige Informationen.",
+	"Loading Kokoro.js...": "",
 	"Local": "Lokal",
 	"Local": "Lokal",
 	"Local Models": "Lokale Modelle",
 	"Local Models": "Lokale Modelle",
 	"Lost": "Verloren",
 	"Lost": "Verloren",
 	"LTR": "LTR",
 	"LTR": "LTR",
-	"Made by OpenWebUI Community": "Von der OpenWebUI-Community",
+	"Made by Open WebUI Community": "Von der OpenWebUI-Community",
 	"Make sure to enclose them with": "Umschließe Variablen mit",
 	"Make sure to enclose them with": "Umschließe Variablen mit",
 	"Make sure to export a workflow.json file as API format from ComfyUI.": "Stellen Sie sicher, dass sie eine workflow.json-Datei im API-Format von ComfyUI exportieren.",
 	"Make sure to export a workflow.json file as API format from ComfyUI.": "Stellen Sie sicher, dass sie eine workflow.json-Datei im API-Format von ComfyUI exportieren.",
 	"Manage": "Verwalten",
 	"Manage": "Verwalten",
 	"Manage Arena Models": "Arena-Modelle verwalten",
 	"Manage Arena Models": "Arena-Modelle verwalten",
-	"Manage Models": "",
+	"Manage Direct Connections": "",
+	"Manage Models": "Modelle verwalten",
 	"Manage Ollama": "Ollama verwalten",
 	"Manage Ollama": "Ollama verwalten",
 	"Manage Ollama API Connections": "Ollama-API-Verbindungen verwalten",
 	"Manage Ollama API Connections": "Ollama-API-Verbindungen verwalten",
 	"Manage OpenAI API Connections": "OpenAI-API-Verbindungen verwalten",
 	"Manage OpenAI API Connections": "OpenAI-API-Verbindungen verwalten",
@@ -624,17 +647,17 @@
 	"Modelfile Content": "Modelfile-Inhalt",
 	"Modelfile Content": "Modelfile-Inhalt",
 	"Models": "Modelle",
 	"Models": "Modelle",
 	"Models Access": "Modell-Zugriff",
 	"Models Access": "Modell-Zugriff",
-	"Models configuration saved successfully": "",
+	"Models configuration saved successfully": "Modellkonfiguration erfolgreich gespeichert",
 	"Mojeek Search API Key": "Mojeek Search API-Schlüssel",
 	"Mojeek Search API Key": "Mojeek Search API-Schlüssel",
 	"more": "mehr",
 	"more": "mehr",
 	"More": "Mehr",
 	"More": "Mehr",
 	"Name": "Name",
 	"Name": "Name",
 	"Name your knowledge base": "Benennen Sie Ihren Wissensspeicher",
 	"Name your knowledge base": "Benennen Sie Ihren Wissensspeicher",
-	"Native": "",
+	"Native": "Nativ",
 	"New Chat": "Neue Unterhaltung",
 	"New Chat": "Neue Unterhaltung",
-	"New Folder": "",
+	"New Folder": "Neuer Ordner",
 	"New Password": "Neues Passwort",
 	"New Password": "Neues Passwort",
-	"new-channel": "",
+	"new-channel": "neuer-kanal",
 	"No content found": "Kein Inhalt gefunden",
 	"No content found": "Kein Inhalt gefunden",
 	"No content to speak": "Kein Inhalt zum Vorlesen",
 	"No content to speak": "Kein Inhalt zum Vorlesen",
 	"No distance available": "Keine Distanz verfügbar",
 	"No distance available": "Keine Distanz verfügbar",
@@ -643,11 +666,11 @@
 	"No files found.": "Keine Dateien gefunden.",
 	"No files found.": "Keine Dateien gefunden.",
 	"No groups with access, add a group to grant access": "Keine Gruppen mit Zugriff, fügen Sie eine Gruppe hinzu, um Zugriff zu gewähren",
 	"No groups with access, add a group to grant access": "Keine Gruppen mit Zugriff, fügen Sie eine Gruppe hinzu, um Zugriff zu gewähren",
 	"No HTML, CSS, or JavaScript content found.": "Keine HTML-, CSS- oder JavaScript-Inhalte gefunden.",
 	"No HTML, CSS, or JavaScript content found.": "Keine HTML-, CSS- oder JavaScript-Inhalte gefunden.",
-	"No inference engine with management support found": "",
+	"No inference engine with management support found": "Keine Inferenz-Engine mit Management-Unterstützung gefunden",
 	"No knowledge found": "Kein Wissen gefunden",
 	"No knowledge found": "Kein Wissen gefunden",
 	"No model IDs": "Keine Modell-IDs",
 	"No model IDs": "Keine Modell-IDs",
 	"No models found": "Keine Modelle gefunden",
 	"No models found": "Keine Modelle gefunden",
-	"No models selected": "",
+	"No models selected": "Keine Modelle ausgewählt",
 	"No results found": "Keine Ergebnisse gefunden",
 	"No results found": "Keine Ergebnisse gefunden",
 	"No search query generated": "Keine Suchanfrage generiert",
 	"No search query generated": "Keine Suchanfrage generiert",
 	"No source available": "Keine Quelle verfügbar",
 	"No source available": "Keine Quelle verfügbar",
@@ -658,8 +681,8 @@
 	"Not helpful": "Nich hilfreich",
 	"Not helpful": "Nich hilfreich",
 	"Note: If you set a minimum score, the search will only return documents with a score greater than or equal to the minimum score.": "Hinweis: Wenn Sie eine Mindestpunktzahl festlegen, werden in der Suche nur Dokumente mit einer Punktzahl größer oder gleich der Mindestpunktzahl zurückgegeben.",
 	"Note: If you set a minimum score, the search will only return documents with a score greater than or equal to the minimum score.": "Hinweis: Wenn Sie eine Mindestpunktzahl festlegen, werden in der Suche nur Dokumente mit einer Punktzahl größer oder gleich der Mindestpunktzahl zurückgegeben.",
 	"Notes": "Notizen",
 	"Notes": "Notizen",
-	"Notification Sound": "",
-	"Notification Webhook": "",
+	"Notification Sound": "Benachrichtigungston",
+	"Notification Webhook": "Benachrichtigungs-Webhook",
 	"Notifications": "Benachrichtigungen",
 	"Notifications": "Benachrichtigungen",
 	"November": "November",
 	"November": "November",
 	"num_gpu (Ollama)": "num_gpu (Ollama)",
 	"num_gpu (Ollama)": "num_gpu (Ollama)",
@@ -722,10 +745,11 @@
 	"Plain text (.txt)": "Nur Text (.txt)",
 	"Plain text (.txt)": "Nur Text (.txt)",
 	"Playground": "Testumgebung",
 	"Playground": "Testumgebung",
 	"Please carefully review the following warnings:": "Bitte überprüfen Sie die folgenden Warnungen sorgfältig:",
 	"Please carefully review the following warnings:": "Bitte überprüfen Sie die folgenden Warnungen sorgfältig:",
+	"Please do not close the settings page while loading the model.": "",
 	"Please enter a prompt": "Bitte geben Sie einen Prompt ein",
 	"Please enter a prompt": "Bitte geben Sie einen Prompt ein",
 	"Please fill in all fields.": "Bitte füllen Sie alle Felder aus.",
 	"Please fill in all fields.": "Bitte füllen Sie alle Felder aus.",
-	"Please select a model first.": "",
-	"Please select a model.": "",
+	"Please select a model first.": "Bitte wählen Sie zuerst ein Modell aus.",
+	"Please select a model.": "Bitte wählen Sie ein Modell aus.",
 	"Please select a reason": "Bitte wählen Sie einen Grund aus",
 	"Please select a reason": "Bitte wählen Sie einen Grund aus",
 	"Port": "Port",
 	"Port": "Port",
 	"Positive attitude": "Positive Einstellung",
 	"Positive attitude": "Positive Einstellung",
@@ -734,7 +758,7 @@
 	"Previous 30 days": "Vorherige 30 Tage",
 	"Previous 30 days": "Vorherige 30 Tage",
 	"Previous 7 days": "Vorherige 7 Tage",
 	"Previous 7 days": "Vorherige 7 Tage",
 	"Profile Image": "Profilbild",
 	"Profile Image": "Profilbild",
-	"Prompt": "",
+	"Prompt": "Prompt",
 	"Prompt (e.g. Tell me a fun fact about the Roman Empire)": "Prompt (z. B. \"Erzähle mir eine interessante Tatsache über das Römische Reich\")",
 	"Prompt (e.g. Tell me a fun fact about the Roman Empire)": "Prompt (z. B. \"Erzähle mir eine interessante Tatsache über das Römische Reich\")",
 	"Prompt Content": "Prompt-Inhalt",
 	"Prompt Content": "Prompt-Inhalt",
 	"Prompt created successfully": "Prompt erfolgreich erstellt",
 	"Prompt created successfully": "Prompt erfolgreich erstellt",
@@ -742,7 +766,7 @@
 	"Prompt updated successfully": "Prompt erfolgreich aktualisiert",
 	"Prompt updated successfully": "Prompt erfolgreich aktualisiert",
 	"Prompts": "Prompts",
 	"Prompts": "Prompts",
 	"Prompts Access": "Prompt-Zugriff",
 	"Prompts Access": "Prompt-Zugriff",
-	"Proxy URL": "",
+	"Proxy URL": "Proxy-URL",
 	"Pull \"{{searchValue}}\" from Ollama.com": "\"{{searchValue}}\" von Ollama.com beziehen",
 	"Pull \"{{searchValue}}\" from Ollama.com": "\"{{searchValue}}\" von Ollama.com beziehen",
 	"Pull a model from Ollama.com": "Modell von Ollama.com beziehen",
 	"Pull a model from Ollama.com": "Modell von Ollama.com beziehen",
 	"Query Generation Prompt": "Abfragegenerierungsprompt",
 	"Query Generation Prompt": "Abfragegenerierungsprompt",
@@ -750,11 +774,11 @@
 	"RAG Template": "RAG-Vorlage",
 	"RAG Template": "RAG-Vorlage",
 	"Rating": "Bewertung",
 	"Rating": "Bewertung",
 	"Re-rank models by topic similarity": "Modelle nach thematischer Ähnlichkeit neu ordnen",
 	"Re-rank models by topic similarity": "Modelle nach thematischer Ähnlichkeit neu ordnen",
-	"Read": "",
+	"Read": "Lesen",
 	"Read Aloud": "Vorlesen",
 	"Read Aloud": "Vorlesen",
-	"Reasoning Effort": "",
+	"Reasoning Effort": "Schlussfolgerungsaufwand",
 	"Record voice": "Stimme aufnehmen",
 	"Record voice": "Stimme aufnehmen",
-	"Redirecting you to OpenWebUI Community": "Sie werden zur OpenWebUI-Community weitergeleitet",
+	"Redirecting you to Open WebUI Community": "Sie werden zur OpenWebUI-Community weitergeleitet",
 	"Reduces the probability of generating nonsense. A higher value (e.g. 100) will give more diverse answers, while a lower value (e.g. 10) will be more conservative. (Default: 40)": "Reduziert die Wahrscheinlichkeit, Unsinn zu generieren. Ein höherer Wert (z.B. 100) liefert vielfältigere Antworten, während ein niedrigerer Wert (z.B. 10) konservativer ist. (Standard: 40)",
 	"Reduces the probability of generating nonsense. A higher value (e.g. 100) will give more diverse answers, while a lower value (e.g. 10) will be more conservative. (Default: 40)": "Reduziert die Wahrscheinlichkeit, Unsinn zu generieren. Ein höherer Wert (z.B. 100) liefert vielfältigere Antworten, während ein niedrigerer Wert (z.B. 10) konservativer ist. (Standard: 40)",
 	"Refer to yourself as \"User\" (e.g., \"User is learning Spanish\")": "Beziehen Sie sich auf sich selbst als \"Benutzer\" (z. B. \"Benutzer lernt Spanisch\")",
 	"Refer to yourself as \"User\" (e.g., \"User is learning Spanish\")": "Beziehen Sie sich auf sich selbst als \"Benutzer\" (z. B. \"Benutzer lernt Spanisch\")",
 	"References from": "Referenzen aus",
 	"References from": "Referenzen aus",
@@ -765,22 +789,22 @@
 	"Remove": "Entfernen",
 	"Remove": "Entfernen",
 	"Remove Model": "Modell entfernen",
 	"Remove Model": "Modell entfernen",
 	"Rename": "Umbenennen",
 	"Rename": "Umbenennen",
-	"Reorder Models": "",
+	"Reorder Models": "Modelle neu anordnen",
 	"Repeat Last N": "Wiederhole die letzten N",
 	"Repeat Last N": "Wiederhole die letzten N",
-	"Reply in Thread": "",
+	"Reply in Thread": "Im Thread antworten",
 	"Request Mode": "Anforderungsmodus",
 	"Request Mode": "Anforderungsmodus",
 	"Reranking Model": "Reranking-Modell",
 	"Reranking Model": "Reranking-Modell",
 	"Reranking model disabled": "Reranking-Modell deaktiviert",
 	"Reranking model disabled": "Reranking-Modell deaktiviert",
 	"Reranking model set to \"{{reranking_model}}\"": "Reranking-Modell \"{{reranking_model}}\" fesgelegt",
 	"Reranking model set to \"{{reranking_model}}\"": "Reranking-Modell \"{{reranking_model}}\" fesgelegt",
 	"Reset": "Zurücksetzen",
 	"Reset": "Zurücksetzen",
-	"Reset All Models": "",
+	"Reset All Models": "Alle Modelle zurücksetzen",
 	"Reset Upload Directory": "Upload-Verzeichnis zurücksetzen",
 	"Reset Upload Directory": "Upload-Verzeichnis zurücksetzen",
 	"Reset Vector Storage/Knowledge": "Vektorspeicher/Wissen zurücksetzen",
 	"Reset Vector Storage/Knowledge": "Vektorspeicher/Wissen zurücksetzen",
-	"Reset view": "",
+	"Reset view": "Ansicht zurücksetzen",
 	"Response notifications cannot be activated as the website permissions have been denied. Please visit your browser settings to grant the necessary access.": "Benachrichtigungen können nicht aktiviert werden, da die Website-Berechtigungen abgelehnt wurden. Bitte besuchen Sie Ihre Browser-Einstellungen, um den erforderlichen Zugriff zu gewähren.",
 	"Response notifications cannot be activated as the website permissions have been denied. Please visit your browser settings to grant the necessary access.": "Benachrichtigungen können nicht aktiviert werden, da die Website-Berechtigungen abgelehnt wurden. Bitte besuchen Sie Ihre Browser-Einstellungen, um den erforderlichen Zugriff zu gewähren.",
 	"Response splitting": "Antwortaufteilung",
 	"Response splitting": "Antwortaufteilung",
 	"Result": "Ergebnis",
 	"Result": "Ergebnis",
-	"Retrieval Query Generation": "",
+	"Retrieval Query Generation": "Abfragegenerierung",
 	"Rich Text Input for Chat": "Rich-Text-Eingabe für Unterhaltungen",
 	"Rich Text Input for Chat": "Rich-Text-Eingabe für Unterhaltungen",
 	"RK": "RK",
 	"RK": "RK",
 	"Role": "Rolle",
 	"Role": "Rolle",
@@ -810,11 +834,11 @@
 	"Search options": "Suchoptionen",
 	"Search options": "Suchoptionen",
 	"Search Prompts": "Prompts durchsuchen...",
 	"Search Prompts": "Prompts durchsuchen...",
 	"Search Result Count": "Anzahl der Suchergebnisse",
 	"Search Result Count": "Anzahl der Suchergebnisse",
-	"Search the internet": "",
+	"Search the internet": "Im Internet suchen",
 	"Search Tools": "Werkzeuge durchsuchen...",
 	"Search Tools": "Werkzeuge durchsuchen...",
 	"SearchApi API Key": "SearchApi-API-Schlüssel",
 	"SearchApi API Key": "SearchApi-API-Schlüssel",
 	"SearchApi Engine": "SearchApi-Engine",
 	"SearchApi Engine": "SearchApi-Engine",
-	"Searched {{count}} sites": "",
+	"Searched {{count}} sites": "{{count}} Websites durchsucht",
 	"Searching \"{{searchQuery}}\"": "Suche nach \"{{searchQuery}}\"",
 	"Searching \"{{searchQuery}}\"": "Suche nach \"{{searchQuery}}\"",
 	"Searching Knowledge for \"{{searchQuery}}\"": "Suche im Wissen nach \"{{searchQuery}}\"",
 	"Searching Knowledge for \"{{searchQuery}}\"": "Suche im Wissen nach \"{{searchQuery}}\"",
 	"Searxng Query URL": "Searxng-Abfrage-URL",
 	"Searxng Query URL": "Searxng-Abfrage-URL",
@@ -829,7 +853,8 @@
 	"Select a pipeline": "Wählen Sie eine Pipeline",
 	"Select a pipeline": "Wählen Sie eine Pipeline",
 	"Select a pipeline url": "Wählen Sie eine Pipeline-URL",
 	"Select a pipeline url": "Wählen Sie eine Pipeline-URL",
 	"Select a tool": "Wählen Sie ein Werkzeug",
 	"Select a tool": "Wählen Sie ein Werkzeug",
-	"Select an Ollama instance": "",
+	"Select an auth method": "",
+	"Select an Ollama instance": "Wählen Sie eine Ollama-Instanz",
 	"Select Engine": "Engine auswählen",
 	"Select Engine": "Engine auswählen",
 	"Select Knowledge": "Wissensdatenbank auswählen",
 	"Select Knowledge": "Wissensdatenbank auswählen",
 	"Select model": "Modell auswählen",
 	"Select model": "Modell auswählen",
@@ -856,7 +881,7 @@
 	"Set Scheduler": "Scheduler festlegen",
 	"Set Scheduler": "Scheduler festlegen",
 	"Set Steps": "Schrittgröße festlegen",
 	"Set Steps": "Schrittgröße festlegen",
 	"Set Task Model": "Aufgabenmodell festlegen",
 	"Set Task Model": "Aufgabenmodell festlegen",
-	"Set the number of layers, which will be off-loaded to GPU. Increasing this value can significantly improve performance for models that are optimized for GPU acceleration but may also consume more power and GPU resources.": "",
+	"Set the number of layers, which will be off-loaded to GPU. Increasing this value can significantly improve performance for models that are optimized for GPU acceleration but may also consume more power and GPU resources.": "Legen Sie die Anzahl der Schichten fest, die auf die GPU ausgelagert werden. Eine Erhöhung dieses Wertes kann die Leistung für Modelle, die für die GPU-Beschleunigung optimiert sind, erheblich verbessern, kann jedoch auch mehr Strom und GPU-Ressourcen verbrauchen.",
 	"Set the number of worker threads used for computation. This option controls how many threads are used to process incoming requests concurrently. Increasing this value can improve performance under high concurrency workloads but may also consume more CPU resources.": "Legt die Anzahl der für die Berechnung verwendeten GPU-Geräte fest. Diese Option steuert, wie viele GPU-Geräte (falls verfügbar) zur Verarbeitung eingehender Anfragen verwendet werden. Eine Erhöhung dieses Wertes kann die Leistung für Modelle, die für GPU-Beschleunigung optimiert sind, erheblich verbessern, kann jedoch auch mehr Strom und GPU-Ressourcen verbrauchen.",
 	"Set the number of worker threads used for computation. This option controls how many threads are used to process incoming requests concurrently. Increasing this value can improve performance under high concurrency workloads but may also consume more CPU resources.": "Legt die Anzahl der für die Berechnung verwendeten GPU-Geräte fest. Diese Option steuert, wie viele GPU-Geräte (falls verfügbar) zur Verarbeitung eingehender Anfragen verwendet werden. Eine Erhöhung dieses Wertes kann die Leistung für Modelle, die für GPU-Beschleunigung optimiert sind, erheblich verbessern, kann jedoch auch mehr Strom und GPU-Ressourcen verbrauchen.",
 	"Set Voice": "Stimme festlegen",
 	"Set Voice": "Stimme festlegen",
 	"Set whisper model": "Whisper-Modell festlegen",
 	"Set whisper model": "Whisper-Modell festlegen",
@@ -869,7 +894,7 @@
 	"Settings saved successfully!": "Einstellungen erfolgreich gespeichert!",
 	"Settings saved successfully!": "Einstellungen erfolgreich gespeichert!",
 	"Share": "Teilen",
 	"Share": "Teilen",
 	"Share Chat": "Unterhaltung teilen",
 	"Share Chat": "Unterhaltung teilen",
-	"Share to OpenWebUI Community": "Mit OpenWebUI Community teilen",
+	"Share to Open WebUI Community": "Mit OpenWebUI Community teilen",
 	"Show": "Anzeigen",
 	"Show": "Anzeigen",
 	"Show \"What's New\" modal on login": "\"Was gibt's Neues\"-Modal beim Anmelden anzeigen",
 	"Show \"What's New\" modal on login": "\"Was gibt's Neues\"-Modal beim Anmelden anzeigen",
 	"Show Admin Details in Account Pending Overlay": "Admin-Details im Account-Pending-Overlay anzeigen",
 	"Show Admin Details in Account Pending Overlay": "Admin-Details im Account-Pending-Overlay anzeigen",
@@ -883,7 +908,7 @@
 	"Sign up": "Registrieren",
 	"Sign up": "Registrieren",
 	"Sign up to {{WEBUI_NAME}}": "Bei {{WEBUI_NAME}} registrieren",
 	"Sign up to {{WEBUI_NAME}}": "Bei {{WEBUI_NAME}} registrieren",
 	"Signing in to {{WEBUI_NAME}}": "Wird bei {{WEBUI_NAME}} angemeldet",
 	"Signing in to {{WEBUI_NAME}}": "Wird bei {{WEBUI_NAME}} angemeldet",
-	"sk-1234": "",
+	"sk-1234": "sk-1234",
 	"Source": "Quelle",
 	"Source": "Quelle",
 	"Speech Playback Speed": "Sprachwiedergabegeschwindigkeit",
 	"Speech Playback Speed": "Sprachwiedergabegeschwindigkeit",
 	"Speech recognition error: {{error}}": "Spracherkennungsfehler: {{error}}",
 	"Speech recognition error: {{error}}": "Spracherkennungsfehler: {{error}}",
@@ -903,7 +928,7 @@
 	"System": "System",
 	"System": "System",
 	"System Instructions": "Systemanweisungen",
 	"System Instructions": "Systemanweisungen",
 	"System Prompt": "System-Prompt",
 	"System Prompt": "System-Prompt",
-	"Tags Generation": "",
+	"Tags Generation": "Tag-Generierung",
 	"Tags Generation Prompt": "Prompt für Tag-Generierung",
 	"Tags Generation Prompt": "Prompt für Tag-Generierung",
 	"Tail free sampling is used to reduce the impact of less probable tokens from the output. A higher value (e.g., 2.0) will reduce the impact more, while a value of 1.0 disables this setting. (default: 1)": "Tail-Free Sampling wird verwendet, um den Einfluss weniger wahrscheinlicher Tokens auf die Ausgabe zu reduzieren. Ein höherer Wert (z.B. 2.0) reduziert den Einfluss stärker, während ein Wert von 1.0 diese Einstellung deaktiviert. (Standard: 1)",
 	"Tail free sampling is used to reduce the impact of less probable tokens from the output. A higher value (e.g., 2.0) will reduce the impact more, while a value of 1.0 disables this setting. (default: 1)": "Tail-Free Sampling wird verwendet, um den Einfluss weniger wahrscheinlicher Tokens auf die Ausgabe zu reduzieren. Ein höherer Wert (z.B. 2.0) reduziert den Einfluss stärker, während ein Wert von 1.0 diese Einstellung deaktiviert. (Standard: 1)",
 	"Tap to interrupt": "Zum Unterbrechen tippen",
 	"Tap to interrupt": "Zum Unterbrechen tippen",
@@ -921,7 +946,7 @@
 	"The batch size determines how many text requests are processed together at once. A higher batch size can increase the performance and speed of the model, but it also requires more memory.  (Default: 512)": "Die Batch-Größe bestimmt, wie viele Textanfragen gleichzeitig verarbeitet werden. Eine größere Batch-Größe kann die Leistung und Geschwindigkeit des Modells erhöhen, erfordert jedoch auch mehr Speicher. (Standard: 512)",
 	"The batch size determines how many text requests are processed together at once. A higher batch size can increase the performance and speed of the model, but it also requires more memory.  (Default: 512)": "Die Batch-Größe bestimmt, wie viele Textanfragen gleichzeitig verarbeitet werden. Eine größere Batch-Größe kann die Leistung und Geschwindigkeit des Modells erhöhen, erfordert jedoch auch mehr Speicher. (Standard: 512)",
 	"The developers behind this plugin are passionate volunteers from the community. If you find this plugin helpful, please consider contributing to its development.": "Die Entwickler hinter diesem Plugin sind leidenschaftliche Freiwillige aus der Community. Wenn Sie dieses Plugin hilfreich finden, erwägen Sie bitte, zu seiner Entwicklung beizutragen.",
 	"The developers behind this plugin are passionate volunteers from the community. If you find this plugin helpful, please consider contributing to its development.": "Die Entwickler hinter diesem Plugin sind leidenschaftliche Freiwillige aus der Community. Wenn Sie dieses Plugin hilfreich finden, erwägen Sie bitte, zu seiner Entwicklung beizutragen.",
 	"The evaluation leaderboard is based on the Elo rating system and is updated in real-time.": "Die Bewertungs-Bestenliste basiert auf dem Elo-Bewertungssystem und wird in Echtzeit aktualisiert.",
 	"The evaluation leaderboard is based on the Elo rating system and is updated in real-time.": "Die Bewertungs-Bestenliste basiert auf dem Elo-Bewertungssystem und wird in Echtzeit aktualisiert.",
-	"The LDAP attribute that maps to the mail that users use to sign in.": "",
+	"The LDAP attribute that maps to the mail that users use to sign in.": "Das LDAP-Attribut, das der Mail zugeordnet ist, die Benutzer zum Anmelden verwenden.",
 	"The LDAP attribute that maps to the username that users use to sign in.": "Das LDAP-Attribut, das dem Benutzernamen zugeordnet ist, den Benutzer zum Anmelden verwenden.",
 	"The LDAP attribute that maps to the username that users use to sign in.": "Das LDAP-Attribut, das dem Benutzernamen zugeordnet ist, den Benutzer zum Anmelden verwenden.",
 	"The leaderboard is currently in beta, and we may adjust the rating calculations as we refine the algorithm.": "Die Bestenliste befindet sich derzeit in der Beta-Phase, und es ist möglich, dass wir die Bewertungsberechnungen anpassen, während wir den Algorithmus verfeinern.",
 	"The leaderboard is currently in beta, and we may adjust the rating calculations as we refine the algorithm.": "Die Bestenliste befindet sich derzeit in der Beta-Phase, und es ist möglich, dass wir die Bewertungsberechnungen anpassen, während wir den Algorithmus verfeinern.",
 	"The maximum file size in MB. If the file size exceeds this limit, the file will not be uploaded.": "Die maximale Dateigröße in MB. Wenn die Dateigröße dieses Limit überschreitet, wird die Datei nicht hochgeladen.",
 	"The maximum file size in MB. If the file size exceeds this limit, the file will not be uploaded.": "Die maximale Dateigröße in MB. Wenn die Dateigröße dieses Limit überschreitet, wird die Datei nicht hochgeladen.",
@@ -943,7 +968,8 @@
 	"This will delete all models including custom models and cannot be undone.": "Dies wird alle Modelle einschließlich benutzerdefinierter Modelle löschen und kann nicht rückgängig gemacht werden.",
 	"This will delete all models including custom models and cannot be undone.": "Dies wird alle Modelle einschließlich benutzerdefinierter Modelle löschen und kann nicht rückgängig gemacht werden.",
 	"This will reset the knowledge base and sync all files. Do you wish to continue?": "Dadurch wird die Wissensdatenbank zurückgesetzt und alle Dateien synchronisiert. Möchten Sie fortfahren?",
 	"This will reset the knowledge base and sync all files. Do you wish to continue?": "Dadurch wird die Wissensdatenbank zurückgesetzt und alle Dateien synchronisiert. Möchten Sie fortfahren?",
 	"Thorough explanation": "Ausführliche Erklärung",
 	"Thorough explanation": "Ausführliche Erklärung",
-	"Thought for {{DURATION}}": "",
+	"Thought for {{DURATION}}": "Nachgedacht für {{DURATION}}",
+	"Thought for {{DURATION}} seconds": "",
 	"Tika": "Tika",
 	"Tika": "Tika",
 	"Tika Server URL required.": "Tika-Server-URL erforderlich.",
 	"Tika Server URL required.": "Tika-Server-URL erforderlich.",
 	"Tiktoken": "Tiktoken",
 	"Tiktoken": "Tiktoken",
@@ -958,7 +984,7 @@
 	"To access the GGUF models available for downloading,": "Um auf die verfügbaren GGUF-Modelle zuzugreifen,",
 	"To access the GGUF models available for downloading,": "Um auf die verfügbaren GGUF-Modelle zuzugreifen,",
 	"To access the WebUI, please reach out to the administrator. Admins can manage user statuses from the Admin Panel.": "Um auf das WebUI zugreifen zu können, wenden Sie sich bitte an einen Administrator. Administratoren können den Benutzerstatus über das Admin-Panel verwalten.",
 	"To access the WebUI, please reach out to the administrator. Admins can manage user statuses from the Admin Panel.": "Um auf das WebUI zugreifen zu können, wenden Sie sich bitte an einen Administrator. Administratoren können den Benutzerstatus über das Admin-Panel verwalten.",
 	"To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "Um Wissensdatenbanken hier anzuhängen, fügen Sie sie zunächst dem Arbeitsbereich \"Wissen\" hinzu.",
 	"To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "Um Wissensdatenbanken hier anzuhängen, fügen Sie sie zunächst dem Arbeitsbereich \"Wissen\" hinzu.",
-	"To learn more about available endpoints, visit our documentation.": "",
+	"To learn more about available endpoints, visit our documentation.": "Um mehr über verfügbare Endpunkte zu erfahren, besuchen Sie unsere Dokumentation.",
 	"To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "Um Ihre Privatsphäre zu schützen, werden nur Bewertungen, Modell-IDs, Tags und Metadaten aus Ihrem Feedback geteilt – Ihre Unterhaltungen bleiben privat und werden nicht einbezogen.",
 	"To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "Um Ihre Privatsphäre zu schützen, werden nur Bewertungen, Modell-IDs, Tags und Metadaten aus Ihrem Feedback geteilt – Ihre Unterhaltungen bleiben privat und werden nicht einbezogen.",
 	"To select actions here, add them to the \"Functions\" workspace first.": "Um Aktionen auszuwählen, fügen Sie diese zunächst dem Arbeitsbereich „Funktionen“ hinzu.",
 	"To select actions here, add them to the \"Functions\" workspace first.": "Um Aktionen auszuwählen, fügen Sie diese zunächst dem Arbeitsbereich „Funktionen“ hinzu.",
 	"To select filters here, add them to the \"Functions\" workspace first.": "Um Filter auszuwählen, fügen Sie diese zunächst dem Arbeitsbereich „Funktionen“ hinzu.",
 	"To select filters here, add them to the \"Functions\" workspace first.": "Um Filter auszuwählen, fügen Sie diese zunächst dem Arbeitsbereich „Funktionen“ hinzu.",
@@ -980,7 +1006,7 @@
 	"Tools": "Werkzeuge",
 	"Tools": "Werkzeuge",
 	"Tools Access": "Werkzeugzugriff",
 	"Tools Access": "Werkzeugzugriff",
 	"Tools are a function calling system with arbitrary code execution": "Wekzeuge sind ein Funktionssystem mit beliebiger Codeausführung",
 	"Tools are a function calling system with arbitrary code execution": "Wekzeuge sind ein Funktionssystem mit beliebiger Codeausführung",
-	"Tools Function Calling Prompt": "",
+	"Tools Function Calling Prompt": "Prompt für Funktionssystemaufrufe",
 	"Tools have a function calling system that allows arbitrary code execution": "Werkezuge verfügen über ein Funktionssystem, das die Ausführung beliebigen Codes ermöglicht",
 	"Tools have a function calling system that allows arbitrary code execution": "Werkezuge verfügen über ein Funktionssystem, das die Ausführung beliebigen Codes ermöglicht",
 	"Tools have a function calling system that allows arbitrary code execution.": "Werkzeuge verfügen über ein Funktionssystem, das die Ausführung beliebigen Codes ermöglicht.",
 	"Tools have a function calling system that allows arbitrary code execution.": "Werkzeuge verfügen über ein Funktionssystem, das die Ausführung beliebigen Codes ermöglicht.",
 	"Top K": "Top K",
 	"Top K": "Top K",
@@ -992,7 +1018,7 @@
 	"TTS Voice": "TTS-Stimme",
 	"TTS Voice": "TTS-Stimme",
 	"Type": "Art",
 	"Type": "Art",
 	"Type Hugging Face Resolve (Download) URL": "Geben Sie die Hugging Face Resolve-URL ein",
 	"Type Hugging Face Resolve (Download) URL": "Geben Sie die Hugging Face Resolve-URL ein",
-	"Uh-oh! There was an issue with the response.": "",
+	"Uh-oh! There was an issue with the response.": "Oh nein! Es gab ein Problem mit der Antwort.",
 	"UI": "Oberfläche",
 	"UI": "Oberfläche",
 	"Unarchive All": "Alle wiederherstellen",
 	"Unarchive All": "Alle wiederherstellen",
 	"Unarchive All Archived Chats": "Alle archivierten Unterhaltungen wiederherstellen",
 	"Unarchive All Archived Chats": "Alle archivierten Unterhaltungen wiederherstellen",
@@ -1038,7 +1064,7 @@
 	"variable to have them replaced with clipboard content.": "Variable, um den Inhalt der Zwischenablage beim Nutzen des Prompts zu ersetzen.",
 	"variable to have them replaced with clipboard content.": "Variable, um den Inhalt der Zwischenablage beim Nutzen des Prompts zu ersetzen.",
 	"Version": "Version",
 	"Version": "Version",
 	"Version {{selectedVersion}} of {{totalVersions}}": "Version {{selectedVersion}} von {{totalVersions}}",
 	"Version {{selectedVersion}} of {{totalVersions}}": "Version {{selectedVersion}} von {{totalVersions}}",
-	"View Replies": "",
+	"View Replies": "Antworten anzeigen",
 	"Visibility": "Sichtbarkeit",
 	"Visibility": "Sichtbarkeit",
 	"Voice": "Stimme",
 	"Voice": "Stimme",
 	"Voice Input": "Spracheingabe",
 	"Voice Input": "Spracheingabe",
@@ -1051,11 +1077,11 @@
 	"Web Loader Settings": "Web Loader Einstellungen",
 	"Web Loader Settings": "Web Loader Einstellungen",
 	"Web Search": "Websuche",
 	"Web Search": "Websuche",
 	"Web Search Engine": "Suchmaschine",
 	"Web Search Engine": "Suchmaschine",
-	"Web Search in Chat": "",
-	"Web Search Query Generation": "",
+	"Web Search in Chat": "Websuche im Chat",
+	"Web Search Query Generation": "Abfragegenerierung für Websuche",
 	"Webhook URL": "Webhook URL",
 	"Webhook URL": "Webhook URL",
 	"WebUI Settings": "WebUI-Einstellungen",
 	"WebUI Settings": "WebUI-Einstellungen",
-	"WebUI URL": "",
+	"WebUI URL": "WebUI-URL",
 	"WebUI will make requests to \"{{url}}/api/chat\"": "WebUI wird Anfragen an \"{{url}}/api/chat\" senden",
 	"WebUI will make requests to \"{{url}}/api/chat\"": "WebUI wird Anfragen an \"{{url}}/api/chat\" senden",
 	"WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI wird Anfragen an \"{{url}}/chat/completions\" senden",
 	"WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI wird Anfragen an \"{{url}}/chat/completions\" senden",
 	"What are you trying to achieve?": "Was versuchen Sie zu erreichen?",
 	"What are you trying to achieve?": "Was versuchen Sie zu erreichen?",
@@ -1070,7 +1096,7 @@
 	"Works together with top-k. A higher value (e.g., 0.95) will lead to more diverse text, while a lower value (e.g., 0.5) will generate more focused and conservative text. (Default: 0.9)": "Funktioniert zusammen mit top-k. Ein höherer Wert (z.B. 0,95) führt zu vielfältigerem Text, während ein niedrigerer Wert (z.B. 0,5) fokussierteren und konservativeren Text erzeugt. (Standard: 0,9)",
 	"Works together with top-k. A higher value (e.g., 0.95) will lead to more diverse text, while a lower value (e.g., 0.5) will generate more focused and conservative text. (Default: 0.9)": "Funktioniert zusammen mit top-k. Ein höherer Wert (z.B. 0,95) führt zu vielfältigerem Text, während ein niedrigerer Wert (z.B. 0,5) fokussierteren und konservativeren Text erzeugt. (Standard: 0,9)",
 	"Workspace": "Arbeitsbereich",
 	"Workspace": "Arbeitsbereich",
 	"Workspace Permissions": "Arbeitsbereichsberechtigungen",
 	"Workspace Permissions": "Arbeitsbereichsberechtigungen",
-	"Write": "",
+	"Write": "Schreiben",
 	"Write a prompt suggestion (e.g. Who are you?)": "Schreiben Sie einen Promptvorschlag (z. B. Wer sind Sie?)",
 	"Write a prompt suggestion (e.g. Who are you?)": "Schreiben Sie einen Promptvorschlag (z. B. Wer sind Sie?)",
 	"Write a summary in 50 words that summarizes [topic or keyword].": "Schreibe eine kurze Zusammenfassung in 50 Wörtern, die [Thema oder Schlüsselwort] zusammenfasst.",
 	"Write a summary in 50 words that summarizes [topic or keyword].": "Schreibe eine kurze Zusammenfassung in 50 Wörtern, die [Thema oder Schlüsselwort] zusammenfasst.",
 	"Write something...": "Schreiben Sie etwas...",
 	"Write something...": "Schreiben Sie etwas...",
@@ -1080,8 +1106,8 @@
 	"You can only chat with a maximum of {{maxCount}} file(s) at a time.": "Sie können nur mit maximal {{maxCount}} Datei(en) gleichzeitig chatten.",
 	"You can only chat with a maximum of {{maxCount}} file(s) at a time.": "Sie können nur mit maximal {{maxCount}} Datei(en) gleichzeitig chatten.",
 	"You can personalize your interactions with LLMs by adding memories through the 'Manage' button below, making them more helpful and tailored to you.": "Personalisieren Sie Interaktionen mit LLMs, indem Sie über die Schaltfläche \"Verwalten\" Erinnerungen hinzufügen.",
 	"You can personalize your interactions with LLMs by adding memories through the 'Manage' button below, making them more helpful and tailored to you.": "Personalisieren Sie Interaktionen mit LLMs, indem Sie über die Schaltfläche \"Verwalten\" Erinnerungen hinzufügen.",
 	"You cannot upload an empty file.": "Sie können keine leere Datei hochladen.",
 	"You cannot upload an empty file.": "Sie können keine leere Datei hochladen.",
-	"You do not have permission to access this feature.": "",
-	"You do not have permission to upload files": "",
+	"You do not have permission to access this feature.": "Sie haben keine Berechtigung, auf diese Funktion zuzugreifen.",
+	"You do not have permission to upload files": "Sie haben keine Berechtigung, Dateien hochzuladen",
 	"You do not have permission to upload files.": "Sie haben keine Berechtigung zum Hochladen von Dateien.",
 	"You do not have permission to upload files.": "Sie haben keine Berechtigung zum Hochladen von Dateien.",
 	"You have no archived conversations.": "Du hast keine archivierten Unterhaltungen.",
 	"You have no archived conversations.": "Du hast keine archivierten Unterhaltungen.",
 	"You have shared this chat": "Sie haben diese Unterhaltung geteilt",
 	"You have shared this chat": "Sie haben diese Unterhaltung geteilt",

+ 29 - 3
src/lib/i18n/locales/dg-DG/translation.json

@@ -122,6 +122,7 @@
 	"Beta": "",
 	"Beta": "",
 	"Bing Search V7 Endpoint": "",
 	"Bing Search V7 Endpoint": "",
 	"Bing Search V7 Subscription Key": "",
 	"Bing Search V7 Subscription Key": "",
+	"Bocha Search API Key": "",
 	"Brave Search API Key": "",
 	"Brave Search API Key": "",
 	"By {{name}}": "",
 	"By {{name}}": "",
 	"Bypass SSL verification for Websites": "",
 	"Bypass SSL verification for Websites": "",
@@ -163,6 +164,7 @@
 	"Click here to": "",
 	"Click here to": "",
 	"Click here to download user import template file.": "",
 	"Click here to download user import template file.": "",
 	"Click here to learn more about faster-whisper and see the available models.": "",
 	"Click here to learn more about faster-whisper and see the available models.": "",
+	"Click here to see available models.": "",
 	"Click here to select": "Click to select",
 	"Click here to select": "Click to select",
 	"Click here to select a csv file.": "",
 	"Click here to select a csv file.": "",
 	"Click here to select a py file.": "",
 	"Click here to select a py file.": "",
@@ -177,6 +179,8 @@
 	"Code execution": "",
 	"Code execution": "",
 	"Code formatted successfully": "",
 	"Code formatted successfully": "",
 	"Code Interpreter": "",
 	"Code Interpreter": "",
+	"Code Interpreter Engine": "",
+	"Code Interpreter Prompt Template": "",
 	"Collection": "Collection",
 	"Collection": "Collection",
 	"Color": "",
 	"Color": "",
 	"ComfyUI": "",
 	"ComfyUI": "",
@@ -193,6 +197,7 @@
 	"Confirm Password": "Confirm Password",
 	"Confirm Password": "Confirm Password",
 	"Confirm your action": "",
 	"Confirm your action": "",
 	"Confirm your new password": "",
 	"Confirm your new password": "",
+	"Connect to your own OpenAI compatible API endpoints.": "",
 	"Connections": "Connections",
 	"Connections": "Connections",
 	"Constrains effort on reasoning for reasoning models. Only applicable to reasoning models from specific providers that support reasoning effort. (Default: medium)": "",
 	"Constrains effort on reasoning for reasoning models. Only applicable to reasoning models from specific providers that support reasoning effort. (Default: medium)": "",
 	"Contact Admin for WebUI Access": "",
 	"Contact Admin for WebUI Access": "",
@@ -215,6 +220,7 @@
 	"Copy Link": "",
 	"Copy Link": "",
 	"Copy to clipboard": "",
 	"Copy to clipboard": "",
 	"Copying to clipboard was successful!": "Copying to clipboard was success! Very success!",
 	"Copying to clipboard was successful!": "Copying to clipboard was success! Very success!",
+	"CORS must be properly configured by the provider to allow requests from Open WebUI.": "",
 	"Create": "",
 	"Create": "",
 	"Create a knowledge base": "",
 	"Create a knowledge base": "",
 	"Create a model": "",
 	"Create a model": "",
@@ -268,6 +274,9 @@
 	"Describe your knowledge base and objectives": "",
 	"Describe your knowledge base and objectives": "",
 	"Description": "Description",
 	"Description": "Description",
 	"Didn't fully follow instructions": "",
 	"Didn't fully follow instructions": "",
+	"Direct Connections": "",
+	"Direct Connections allow users to connect to their own OpenAI compatible API endpoints.": "",
+	"Direct Connections settings updated": "",
 	"Disabled": "",
 	"Disabled": "",
 	"Discover a function": "",
 	"Discover a function": "",
 	"Discover a model": "",
 	"Discover a model": "",
@@ -290,6 +299,7 @@
 	"Documentation": "",
 	"Documentation": "",
 	"Documents": "Documents",
 	"Documents": "Documents",
 	"does not make any external connections, and your data stays securely on your locally hosted server.": "does not connect external, data stays safe locally.",
 	"does not make any external connections, and your data stays securely on your locally hosted server.": "does not connect external, data stays safe locally.",
+	"Domain Filter List": "",
 	"Don't have an account?": "No account? Much sad.",
 	"Don't have an account?": "No account? Much sad.",
 	"don't install random functions from sources you don't trust.": "",
 	"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 tools from sources you don't trust.": "",
@@ -325,6 +335,7 @@
 	"Embedding model set to \"{{embedding_model}}\"": "",
 	"Embedding model set to \"{{embedding_model}}\"": "",
 	"Enable API Key": "",
 	"Enable API Key": "",
 	"Enable autocomplete generation for chat messages": "",
 	"Enable autocomplete generation for chat messages": "",
+	"Enable Code Interpreter": "",
 	"Enable Community Sharing": "",
 	"Enable Community Sharing": "",
 	"Enable Google Drive": "",
 	"Enable Google Drive": "",
 	"Enable Memory Locking (mlock) to prevent model data from being swapped out of RAM. This option locks the model's working set of pages into RAM, ensuring that they will not be swapped out to disk. This can help maintain performance by avoiding page faults and ensuring fast data access.": "",
 	"Enable Memory Locking (mlock) to prevent model data from being swapped out of RAM. This option locks the model's working set of pages into RAM, ensuring that they will not be swapped out to disk. This can help maintain performance by avoiding page faults and ensuring fast data access.": "",
@@ -343,18 +354,23 @@
 	"Enter Application DN Password": "",
 	"Enter Application DN Password": "",
 	"Enter Bing Search V7 Endpoint": "",
 	"Enter Bing Search V7 Endpoint": "",
 	"Enter Bing Search V7 Subscription Key": "",
 	"Enter Bing Search V7 Subscription Key": "",
+	"Enter Bocha Search API Key": "",
 	"Enter Brave Search API Key": "",
 	"Enter Brave Search API Key": "",
 	"Enter certificate path": "",
 	"Enter certificate path": "",
 	"Enter CFG Scale (e.g. 7.0)": "",
 	"Enter CFG Scale (e.g. 7.0)": "",
 	"Enter Chunk Overlap": "Enter Overlap of Chunks",
 	"Enter Chunk Overlap": "Enter Overlap of Chunks",
 	"Enter Chunk Size": "Enter Size of Chunk",
 	"Enter Chunk Size": "Enter Size of Chunk",
 	"Enter description": "",
 	"Enter description": "",
+	"Enter domains separated by commas (e.g., example.com,site.org)": "",
 	"Enter Exa API Key": "",
 	"Enter Exa API Key": "",
 	"Enter Github Raw URL": "",
 	"Enter Github Raw URL": "",
 	"Enter Google PSE API Key": "",
 	"Enter Google PSE API Key": "",
 	"Enter Google PSE Engine Id": "",
 	"Enter Google PSE Engine Id": "",
 	"Enter Image Size (e.g. 512x512)": "Enter Size of Wow (e.g. 512x512)",
 	"Enter Image Size (e.g. 512x512)": "Enter Size of Wow (e.g. 512x512)",
 	"Enter Jina API Key": "",
 	"Enter Jina API Key": "",
+	"Enter Jupyter Password": "",
+	"Enter Jupyter Token": "",
+	"Enter Jupyter URL": "",
 	"Enter Kagi Search API Key": "",
 	"Enter Kagi Search API Key": "",
 	"Enter language codes": "",
 	"Enter language codes": "",
 	"Enter Model ID": "",
 	"Enter Model ID": "",
@@ -540,6 +556,8 @@
 	"JSON Preview": "",
 	"JSON Preview": "",
 	"July": "",
 	"July": "",
 	"June": "",
 	"June": "",
+	"Jupyter Auth": "",
+	"Jupyter URL": "",
 	"JWT Expiration": "JWT Expire",
 	"JWT Expiration": "JWT Expire",
 	"JWT Token": "JWT Borken",
 	"JWT Token": "JWT Borken",
 	"Kagi Search API Key": "",
 	"Kagi Search API Key": "",
@@ -552,6 +570,8 @@
 	"Knowledge deleted successfully.": "",
 	"Knowledge deleted successfully.": "",
 	"Knowledge reset successfully.": "",
 	"Knowledge reset successfully.": "",
 	"Knowledge updated successfully": "",
 	"Knowledge updated successfully": "",
+	"Kokoro.js (Browser)": "",
+	"Kokoro.js Dtype": "",
 	"Label": "",
 	"Label": "",
 	"Landing Page Mode": "",
 	"Landing Page Mode": "",
 	"Language": "Doge Speak",
 	"Language": "Doge Speak",
@@ -566,19 +586,22 @@
 	"Leave empty to include all models from \"{{URL}}/models\" endpoint": "",
 	"Leave empty to include all models from \"{{URL}}/models\" endpoint": "",
 	"Leave empty to include all models or select specific models": "",
 	"Leave empty to include all models or select specific models": "",
 	"Leave empty to use the default prompt, or enter a custom prompt": "",
 	"Leave empty to use the default prompt, or enter a custom prompt": "",
+	"Leave model field empty to use the default model.": "",
 	"Light": "Light",
 	"Light": "Light",
 	"Listening...": "",
 	"Listening...": "",
 	"Llama.cpp": "",
 	"Llama.cpp": "",
 	"LLMs can make mistakes. Verify important information.": "LLMs can make borks. Verify important info.",
 	"LLMs can make mistakes. Verify important information.": "LLMs can make borks. Verify important info.",
+	"Loading Kokoro.js...": "",
 	"Local": "",
 	"Local": "",
 	"Local Models": "",
 	"Local Models": "",
 	"Lost": "",
 	"Lost": "",
 	"LTR": "",
 	"LTR": "",
-	"Made by OpenWebUI Community": "Made by OpenWebUI Community",
+	"Made by Open WebUI Community": "Made by Open WebUI Community",
 	"Make sure to enclose them with": "Make sure to enclose them with",
 	"Make sure to enclose them with": "Make sure to enclose them with",
 	"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.": "",
 	"Manage": "",
 	"Manage": "",
 	"Manage Arena Models": "",
 	"Manage Arena Models": "",
+	"Manage Direct Connections": "",
 	"Manage Models": "",
 	"Manage Models": "",
 	"Manage Ollama": "",
 	"Manage Ollama": "",
 	"Manage Ollama API Connections": "",
 	"Manage Ollama API Connections": "",
@@ -722,6 +745,7 @@
 	"Plain text (.txt)": "Plain text (.txt)",
 	"Plain text (.txt)": "Plain text (.txt)",
 	"Playground": "Playground",
 	"Playground": "Playground",
 	"Please carefully review the following warnings:": "",
 	"Please carefully review the following warnings:": "",
+	"Please do not close the settings page while loading the model.": "",
 	"Please enter a prompt": "",
 	"Please enter a prompt": "",
 	"Please fill in all fields.": "",
 	"Please fill in all fields.": "",
 	"Please select a model first.": "",
 	"Please select a model first.": "",
@@ -754,7 +778,7 @@
 	"Read Aloud": "",
 	"Read Aloud": "",
 	"Reasoning Effort": "",
 	"Reasoning Effort": "",
 	"Record voice": "Record Bark",
 	"Record voice": "Record Bark",
-	"Redirecting you to OpenWebUI Community": "Redirecting you to OpenWebUI Community",
+	"Redirecting you to Open WebUI Community": "Redirecting you to Open WebUI Community",
 	"Reduces the probability of generating nonsense. A higher value (e.g. 100) will give more diverse answers, while a lower value (e.g. 10) will be more conservative. (Default: 40)": "",
 	"Reduces the probability of generating nonsense. A higher value (e.g. 100) will give more diverse answers, while a lower value (e.g. 10) will be more conservative. (Default: 40)": "",
 	"Refer to yourself as \"User\" (e.g., \"User is learning Spanish\")": "",
 	"Refer to yourself as \"User\" (e.g., \"User is learning Spanish\")": "",
 	"References from": "",
 	"References from": "",
@@ -829,6 +853,7 @@
 	"Select a pipeline": "",
 	"Select a pipeline": "",
 	"Select a pipeline url": "",
 	"Select a pipeline url": "",
 	"Select a tool": "",
 	"Select a tool": "",
+	"Select an auth method": "",
 	"Select an Ollama instance": "",
 	"Select an Ollama instance": "",
 	"Select Engine": "",
 	"Select Engine": "",
 	"Select Knowledge": "",
 	"Select Knowledge": "",
@@ -869,7 +894,7 @@
 	"Settings saved successfully!": "Settings saved successfully! Very success!",
 	"Settings saved successfully!": "Settings saved successfully! Very success!",
 	"Share": "",
 	"Share": "",
 	"Share Chat": "",
 	"Share Chat": "",
-	"Share to OpenWebUI Community": "Share to OpenWebUI Community much community",
+	"Share to Open WebUI Community": "Share to Open WebUI Community much community",
 	"Show": "Show much show",
 	"Show": "Show much show",
 	"Show \"What's New\" modal on login": "",
 	"Show \"What's New\" modal on login": "",
 	"Show Admin Details in Account Pending Overlay": "",
 	"Show Admin Details in Account Pending Overlay": "",
@@ -944,6 +969,7 @@
 	"This will reset the knowledge base and sync all files. Do you wish to continue?": "",
 	"This will reset the knowledge base and sync all files. Do you wish to continue?": "",
 	"Thorough explanation": "",
 	"Thorough explanation": "",
 	"Thought for {{DURATION}}": "",
 	"Thought for {{DURATION}}": "",
+	"Thought for {{DURATION}} seconds": "",
 	"Tika": "",
 	"Tika": "",
 	"Tika Server URL required.": "",
 	"Tika Server URL required.": "",
 	"Tiktoken": "",
 	"Tiktoken": "",

+ 29 - 3
src/lib/i18n/locales/el-GR/translation.json

@@ -122,6 +122,7 @@
 	"Beta": "",
 	"Beta": "",
 	"Bing Search V7 Endpoint": "Τέλος Bing Search V7",
 	"Bing Search V7 Endpoint": "Τέλος Bing Search V7",
 	"Bing Search V7 Subscription Key": "Κλειδί Συνδρομής Bing Search V7",
 	"Bing Search V7 Subscription Key": "Κλειδί Συνδρομής Bing Search V7",
+	"Bocha Search API Key": "",
 	"Brave Search API Key": "Κλειδί API Brave Search",
 	"Brave Search API Key": "Κλειδί API Brave Search",
 	"By {{name}}": "Από {{name}}",
 	"By {{name}}": "Από {{name}}",
 	"Bypass SSL verification for Websites": "Παράκαμψη επαλήθευσης SSL για Ιστότοπους",
 	"Bypass SSL verification for Websites": "Παράκαμψη επαλήθευσης SSL για Ιστότοπους",
@@ -163,6 +164,7 @@
 	"Click here to": "Κάντε κλικ εδώ για να",
 	"Click here to": "Κάντε κλικ εδώ για να",
 	"Click here to download user import template file.": "Κάντε κλικ εδώ για να κατεβάσετε το αρχείο προτύπου εισαγωγής χρήστη.",
 	"Click here to download user import template file.": "Κάντε κλικ εδώ για να κατεβάσετε το αρχείο προτύπου εισαγωγής χρήστη.",
 	"Click here to learn more about faster-whisper and see the available models.": "Κάντε κλικ εδώ για να μάθετε περισσότερα σχετικά με το faster-whisper και να δείτε τα διαθέσιμα μοντέλα.",
 	"Click here to learn more about faster-whisper and see the available models.": "Κάντε κλικ εδώ για να μάθετε περισσότερα σχετικά με το faster-whisper και να δείτε τα διαθέσιμα μοντέλα.",
+	"Click here to see available models.": "",
 	"Click here to select": "Κάντε κλικ εδώ για επιλογή",
 	"Click here to select": "Κάντε κλικ εδώ για επιλογή",
 	"Click here to select a csv file.": "Κάντε κλικ εδώ για να επιλέξετε ένα αρχείο csv.",
 	"Click here to select a csv file.": "Κάντε κλικ εδώ για να επιλέξετε ένα αρχείο csv.",
 	"Click here to select a py file.": "Κάντε κλικ εδώ για να επιλέξετε ένα αρχείο py.",
 	"Click here to select a py file.": "Κάντε κλικ εδώ για να επιλέξετε ένα αρχείο py.",
@@ -177,6 +179,8 @@
 	"Code execution": "Εκτέλεση κώδικα",
 	"Code execution": "Εκτέλεση κώδικα",
 	"Code formatted successfully": "Ο κώδικας μορφοποιήθηκε επιτυχώς",
 	"Code formatted successfully": "Ο κώδικας μορφοποιήθηκε επιτυχώς",
 	"Code Interpreter": "",
 	"Code Interpreter": "",
+	"Code Interpreter Engine": "",
+	"Code Interpreter Prompt Template": "",
 	"Collection": "Συλλογή",
 	"Collection": "Συλλογή",
 	"Color": "Χρώμα",
 	"Color": "Χρώμα",
 	"ComfyUI": "ComfyUI",
 	"ComfyUI": "ComfyUI",
@@ -193,6 +197,7 @@
 	"Confirm Password": "Επιβεβαίωση Κωδικού",
 	"Confirm Password": "Επιβεβαίωση Κωδικού",
 	"Confirm your action": "Επιβεβαιώστε την ενέργειά σας",
 	"Confirm your action": "Επιβεβαιώστε την ενέργειά σας",
 	"Confirm your new password": "",
 	"Confirm your new password": "",
+	"Connect to your own OpenAI compatible API endpoints.": "",
 	"Connections": "Συνδέσεις",
 	"Connections": "Συνδέσεις",
 	"Constrains effort on reasoning for reasoning models. Only applicable to reasoning models from specific providers that support reasoning effort. (Default: medium)": "",
 	"Constrains effort on reasoning for reasoning models. Only applicable to reasoning models from specific providers that support reasoning effort. (Default: medium)": "",
 	"Contact Admin for WebUI Access": "Επικοινωνήστε με τον Διαχειριστή για Πρόσβαση στο WebUI",
 	"Contact Admin for WebUI Access": "Επικοινωνήστε με τον Διαχειριστή για Πρόσβαση στο WebUI",
@@ -215,6 +220,7 @@
 	"Copy Link": "Αντιγραφή Συνδέσμου",
 	"Copy Link": "Αντιγραφή Συνδέσμου",
 	"Copy to clipboard": "Αντιγραφή στο πρόχειρο",
 	"Copy to clipboard": "Αντιγραφή στο πρόχειρο",
 	"Copying to clipboard was successful!": "Η αντιγραφή στο πρόχειρο ήταν επιτυχής!",
 	"Copying to clipboard was successful!": "Η αντιγραφή στο πρόχειρο ήταν επιτυχής!",
+	"CORS must be properly configured by the provider to allow requests from Open WebUI.": "",
 	"Create": "Δημιουργία",
 	"Create": "Δημιουργία",
 	"Create a knowledge base": "Δημιουργία βάσης γνώσης",
 	"Create a knowledge base": "Δημιουργία βάσης γνώσης",
 	"Create a model": "Δημιουργία μοντέλου",
 	"Create a model": "Δημιουργία μοντέλου",
@@ -268,6 +274,9 @@
 	"Describe your knowledge base and objectives": "Περιγράψτε τη βάση γνώσης και τους στόχους σας",
 	"Describe your knowledge base and objectives": "Περιγράψτε τη βάση γνώσης και τους στόχους σας",
 	"Description": "Περιγραφή",
 	"Description": "Περιγραφή",
 	"Didn't fully follow instructions": "Δεν ακολούθησε πλήρως τις οδηγίες",
 	"Didn't fully follow instructions": "Δεν ακολούθησε πλήρως τις οδηγίες",
+	"Direct Connections": "",
+	"Direct Connections allow users to connect to their own OpenAI compatible API endpoints.": "",
+	"Direct Connections settings updated": "",
 	"Disabled": "Απενεργοποιημένο",
 	"Disabled": "Απενεργοποιημένο",
 	"Discover a function": "Ανακάλυψη λειτουργίας",
 	"Discover a function": "Ανακάλυψη λειτουργίας",
 	"Discover a model": "Ανακάλυψη μοντέλου",
 	"Discover a model": "Ανακάλυψη μοντέλου",
@@ -290,6 +299,7 @@
 	"Documentation": "Τεκμηρίωση",
 	"Documentation": "Τεκμηρίωση",
 	"Documents": "Έγγραφα",
 	"Documents": "Έγγραφα",
 	"does not make any external connections, and your data stays securely on your locally hosted server.": "δεν κάνει καμία εξωτερική σύνδεση, και τα δεδομένα σας παραμένουν ασφαλή στον τοπικά φιλοξενούμενο διακομιστή σας.",
 	"does not make any external connections, and your data stays securely on your locally hosted server.": "δεν κάνει καμία εξωτερική σύνδεση, και τα δεδομένα σας παραμένουν ασφαλή στον τοπικά φιλοξενούμενο διακομιστή σας.",
+	"Domain Filter List": "",
 	"Don't have an account?": "Δεν έχετε λογαριασμό;",
 	"Don't have an account?": "Δεν έχετε λογαριασμό;",
 	"don't install random functions from sources you don't trust.": "μην εγκαθιστάτε τυχαίες λειτουργίες από πηγές που δεν εμπιστεύεστε.",
 	"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 tools from sources you don't trust.": "μην εγκαθιστάτε τυχαία εργαλεία από πηγές που δεν εμπιστεύεστε.",
@@ -325,6 +335,7 @@
 	"Embedding model set to \"{{embedding_model}}\"": "Το μοντέλο ενσωμάτωσης έχει οριστεί σε \"{{embedding_model}}\"",
 	"Embedding model set to \"{{embedding_model}}\"": "Το μοντέλο ενσωμάτωσης έχει οριστεί σε \"{{embedding_model}}\"",
 	"Enable API Key": "",
 	"Enable API Key": "",
 	"Enable autocomplete generation for chat messages": "",
 	"Enable autocomplete generation for chat messages": "",
+	"Enable Code Interpreter": "",
 	"Enable Community Sharing": "Ενεργοποίηση Κοινοτικής Κοινής Χρήσης",
 	"Enable Community Sharing": "Ενεργοποίηση Κοινοτικής Κοινής Χρήσης",
 	"Enable Google Drive": "",
 	"Enable Google Drive": "",
 	"Enable Memory Locking (mlock) to prevent model data from being swapped out of RAM. This option locks the model's working set of pages into RAM, ensuring that they will not be swapped out to disk. This can help maintain performance by avoiding page faults and ensuring fast data access.": "Ενεργοποίηση Κλείδωσης Μνήμης (mlock) για την αποτροπή της ανταλλαγής δεδομένων του μοντέλου από τη μνήμη RAM. Αυτή η επιλογή κλειδώνει το σύνολο εργασίας των σελίδων του μοντέλου στη μνήμη RAM, διασφαλίζοντας ότι δεν θα ανταλλαχθούν στο δίσκο. Αυτό μπορεί να βοηθήσει στη διατήρηση της απόδοσης αποφεύγοντας σφάλματα σελίδων και διασφαλίζοντας γρήγορη πρόσβαση στα δεδομένα.",
 	"Enable Memory Locking (mlock) to prevent model data from being swapped out of RAM. This option locks the model's working set of pages into RAM, ensuring that they will not be swapped out to disk. This can help maintain performance by avoiding page faults and ensuring fast data access.": "Ενεργοποίηση Κλείδωσης Μνήμης (mlock) για την αποτροπή της ανταλλαγής δεδομένων του μοντέλου από τη μνήμη RAM. Αυτή η επιλογή κλειδώνει το σύνολο εργασίας των σελίδων του μοντέλου στη μνήμη RAM, διασφαλίζοντας ότι δεν θα ανταλλαχθούν στο δίσκο. Αυτό μπορεί να βοηθήσει στη διατήρηση της απόδοσης αποφεύγοντας σφάλματα σελίδων και διασφαλίζοντας γρήγορη πρόσβαση στα δεδομένα.",
@@ -343,18 +354,23 @@
 	"Enter Application DN Password": "Εισάγετε Κωδικό DN Εφαρμογής",
 	"Enter Application DN Password": "Εισάγετε Κωδικό DN Εφαρμογής",
 	"Enter Bing Search V7 Endpoint": "Εισάγετε το Τέλος Bing Search V7",
 	"Enter Bing Search V7 Endpoint": "Εισάγετε το Τέλος Bing Search V7",
 	"Enter Bing Search V7 Subscription Key": "Εισάγετε το Κλειδί Συνδρομής Bing Search V7",
 	"Enter Bing Search V7 Subscription Key": "Εισάγετε το Κλειδί Συνδρομής Bing Search V7",
+	"Enter Bocha Search API Key": "",
 	"Enter Brave Search API Key": "Εισάγετε το Κλειδί API Brave Search",
 	"Enter Brave Search API Key": "Εισάγετε το Κλειδί API Brave Search",
 	"Enter certificate path": "Εισάγετε τη διαδρομή πιστοποιητικού",
 	"Enter certificate path": "Εισάγετε τη διαδρομή πιστοποιητικού",
 	"Enter CFG Scale (e.g. 7.0)": "Εισάγετε το CFG Scale (π.χ. 7.0)",
 	"Enter CFG Scale (e.g. 7.0)": "Εισάγετε το CFG Scale (π.χ. 7.0)",
 	"Enter Chunk Overlap": "Εισάγετε την Επικάλυψη Τμημάτων",
 	"Enter Chunk Overlap": "Εισάγετε την Επικάλυψη Τμημάτων",
 	"Enter Chunk Size": "Εισάγετε το Μέγεθος Τμημάτων",
 	"Enter Chunk Size": "Εισάγετε το Μέγεθος Τμημάτων",
 	"Enter description": "Εισάγετε την περιγραφή",
 	"Enter description": "Εισάγετε την περιγραφή",
+	"Enter domains separated by commas (e.g., example.com,site.org)": "",
 	"Enter Exa API Key": "",
 	"Enter Exa API Key": "",
 	"Enter Github Raw URL": "Εισάγετε το Github Raw URL",
 	"Enter Github Raw URL": "Εισάγετε το Github Raw URL",
 	"Enter Google PSE API Key": "Εισάγετε το Κλειδί API Google PSE",
 	"Enter Google PSE API Key": "Εισάγετε το Κλειδί API Google PSE",
 	"Enter Google PSE Engine Id": "Εισάγετε το Αναγνωριστικό Μηχανής Google PSE",
 	"Enter Google PSE Engine Id": "Εισάγετε το Αναγνωριστικό Μηχανής Google PSE",
 	"Enter Image Size (e.g. 512x512)": "Εισάγετε το Μέγεθος Εικόνας (π.χ. 512x512)",
 	"Enter Image Size (e.g. 512x512)": "Εισάγετε το Μέγεθος Εικόνας (π.χ. 512x512)",
 	"Enter Jina API Key": "Εισάγετε το Κλειδί API Jina",
 	"Enter Jina API Key": "Εισάγετε το Κλειδί API Jina",
+	"Enter Jupyter Password": "",
+	"Enter Jupyter Token": "",
+	"Enter Jupyter URL": "",
 	"Enter Kagi Search API Key": "",
 	"Enter Kagi Search API Key": "",
 	"Enter language codes": "Εισάγετε κωδικούς γλώσσας",
 	"Enter language codes": "Εισάγετε κωδικούς γλώσσας",
 	"Enter Model ID": "Εισάγετε το ID Μοντέλου",
 	"Enter Model ID": "Εισάγετε το ID Μοντέλου",
@@ -540,6 +556,8 @@
 	"JSON Preview": "Προεπισκόπηση JSON",
 	"JSON Preview": "Προεπισκόπηση JSON",
 	"July": "Ιούλιος",
 	"July": "Ιούλιος",
 	"June": "Ιούνιος",
 	"June": "Ιούνιος",
+	"Jupyter Auth": "",
+	"Jupyter URL": "",
 	"JWT Expiration": "Λήξη JWT",
 	"JWT Expiration": "Λήξη JWT",
 	"JWT Token": "Token JWT",
 	"JWT Token": "Token JWT",
 	"Kagi Search API Key": "",
 	"Kagi Search API Key": "",
@@ -552,6 +570,8 @@
 	"Knowledge deleted successfully.": "Η γνώση διαγράφηκε με επιτυχία.",
 	"Knowledge deleted successfully.": "Η γνώση διαγράφηκε με επιτυχία.",
 	"Knowledge reset successfully.": "Η γνώση επαναφέρθηκε με επιτυχία.",
 	"Knowledge reset successfully.": "Η γνώση επαναφέρθηκε με επιτυχία.",
 	"Knowledge updated successfully": "Η γνώση ενημερώθηκε με επιτυχία",
 	"Knowledge updated successfully": "Η γνώση ενημερώθηκε με επιτυχία",
+	"Kokoro.js (Browser)": "",
+	"Kokoro.js Dtype": "",
 	"Label": "Ετικέτα",
 	"Label": "Ετικέτα",
 	"Landing Page Mode": "Λειτουργία Σελίδας Άφιξης",
 	"Landing Page Mode": "Λειτουργία Σελίδας Άφιξης",
 	"Language": "Γλώσσα",
 	"Language": "Γλώσσα",
@@ -566,19 +586,22 @@
 	"Leave empty to include all models from \"{{URL}}/models\" endpoint": "Αφήστε κενό για να συμπεριλάβετε όλα τα μοντέλα από το endpoint \"{{URL}}/models\"",
 	"Leave empty to include all models from \"{{URL}}/models\" endpoint": "Αφήστε κενό για να συμπεριλάβετε όλα τα μοντέλα από το endpoint \"{{URL}}/models\"",
 	"Leave empty to include all models or select specific models": "Αφήστε κενό για να χρησιμοποιήσετε όλα τα μοντέλα ή επιλέξτε συγκεκριμένα μοντέλα",
 	"Leave empty to include all models or select specific models": "Αφήστε κενό για να χρησιμοποιήσετε όλα τα μοντέλα ή επιλέξτε συγκεκριμένα μοντέλα",
 	"Leave empty to use the default prompt, or enter a custom prompt": "Αφήστε κενό για να χρησιμοποιήσετε την προεπιλεγμένη προτροπή, ή εισάγετε μια προσαρμοσμένη προτροπή",
 	"Leave empty to use the default prompt, or enter a custom prompt": "Αφήστε κενό για να χρησιμοποιήσετε την προεπιλεγμένη προτροπή, ή εισάγετε μια προσαρμοσμένη προτροπή",
+	"Leave model field empty to use the default model.": "",
 	"Light": "Φως",
 	"Light": "Φως",
 	"Listening...": "Ακούγεται...",
 	"Listening...": "Ακούγεται...",
 	"Llama.cpp": "",
 	"Llama.cpp": "",
 	"LLMs can make mistakes. Verify important information.": "Τα LLM μπορούν να κάνουν λάθη. Επαληθεύστε σημαντικές πληροφορίες.",
 	"LLMs can make mistakes. Verify important information.": "Τα LLM μπορούν να κάνουν λάθη. Επαληθεύστε σημαντικές πληροφορίες.",
+	"Loading Kokoro.js...": "",
 	"Local": "Τοπικό",
 	"Local": "Τοπικό",
 	"Local Models": "Τοπικά Μοντέλα",
 	"Local Models": "Τοπικά Μοντέλα",
 	"Lost": "Χαμένος",
 	"Lost": "Χαμένος",
 	"LTR": "LTR",
 	"LTR": "LTR",
-	"Made by OpenWebUI Community": "Δημιουργήθηκε από την Κοινότητα OpenWebUI",
+	"Made by Open WebUI Community": "Δημιουργήθηκε από την Κοινότητα OpenWebUI",
 	"Make sure to enclose them with": "Βεβαιωθείτε ότι τα περικλείετε με",
 	"Make sure to enclose them with": "Βεβαιωθείτε ότι τα περικλείετε με",
 	"Make sure to export a workflow.json file as API format from ComfyUI.": "Βεβαιωθείτε ότι εξάγετε ένα αρχείο workflow.json ως μορφή API από το ComfyUI.",
 	"Make sure to export a workflow.json file as API format from ComfyUI.": "Βεβαιωθείτε ότι εξάγετε ένα αρχείο workflow.json ως μορφή API από το ComfyUI.",
 	"Manage": "Διαχείριση",
 	"Manage": "Διαχείριση",
 	"Manage Arena Models": "Διαχείριση Μοντέλων Arena",
 	"Manage Arena Models": "Διαχείριση Μοντέλων Arena",
+	"Manage Direct Connections": "",
 	"Manage Models": "",
 	"Manage Models": "",
 	"Manage Ollama": "Διαχείριση Ollama",
 	"Manage Ollama": "Διαχείριση Ollama",
 	"Manage Ollama API Connections": "Διαχείριση Συνδέσεων API Ollama",
 	"Manage Ollama API Connections": "Διαχείριση Συνδέσεων API Ollama",
@@ -722,6 +745,7 @@
 	"Plain text (.txt)": "Απλό κείμενο (.txt)",
 	"Plain text (.txt)": "Απλό κείμενο (.txt)",
 	"Playground": "Γήπεδο παιχνιδιών",
 	"Playground": "Γήπεδο παιχνιδιών",
 	"Please carefully review the following warnings:": "Παρακαλώ αναθεωρήστε προσεκτικά τις ακόλουθες προειδοποιήσεις:",
 	"Please carefully review the following warnings:": "Παρακαλώ αναθεωρήστε προσεκτικά τις ακόλουθες προειδοποιήσεις:",
+	"Please do not close the settings page while loading the model.": "",
 	"Please enter a prompt": "Παρακαλώ εισάγετε μια προτροπή",
 	"Please enter a prompt": "Παρακαλώ εισάγετε μια προτροπή",
 	"Please fill in all fields.": "Παρακαλώ συμπληρώστε όλα τα πεδία.",
 	"Please fill in all fields.": "Παρακαλώ συμπληρώστε όλα τα πεδία.",
 	"Please select a model first.": "",
 	"Please select a model first.": "",
@@ -754,7 +778,7 @@
 	"Read Aloud": "Ανάγνωση Φωναχτά",
 	"Read Aloud": "Ανάγνωση Φωναχτά",
 	"Reasoning Effort": "",
 	"Reasoning Effort": "",
 	"Record voice": "Εγγραφή φωνής",
 	"Record voice": "Εγγραφή φωνής",
-	"Redirecting you to OpenWebUI Community": "Μετακατεύθυνση στην Κοινότητα OpenWebUI",
+	"Redirecting you to Open WebUI Community": "Μετακατεύθυνση στην Κοινότητα OpenWebUI",
 	"Reduces the probability of generating nonsense. A higher value (e.g. 100) will give more diverse answers, while a lower value (e.g. 10) will be more conservative. (Default: 40)": "Μειώνει την πιθανότητα δημιουργίας ανοησιών. Μια υψηλότερη τιμή (π.χ. 100) θα δώσει πιο ποικίλες απαντήσεις, ενώ μια χαμηλότερη τιμή (π.χ. 10) θα δημιουργήσει πιο συντηρητικές απαντήσεις. (Προεπιλογή: 40)",
 	"Reduces the probability of generating nonsense. A higher value (e.g. 100) will give more diverse answers, while a lower value (e.g. 10) will be more conservative. (Default: 40)": "Μειώνει την πιθανότητα δημιουργίας ανοησιών. Μια υψηλότερη τιμή (π.χ. 100) θα δώσει πιο ποικίλες απαντήσεις, ενώ μια χαμηλότερη τιμή (π.χ. 10) θα δημιουργήσει πιο συντηρητικές απαντήσεις. (Προεπιλογή: 40)",
 	"Refer to yourself as \"User\" (e.g., \"User is learning Spanish\")": "Αναφέρεστε στον εαυτό σας ως \"User\" (π.χ., \"User μαθαίνει Ισπανικά\")",
 	"Refer to yourself as \"User\" (e.g., \"User is learning Spanish\")": "Αναφέρεστε στον εαυτό σας ως \"User\" (π.χ., \"User μαθαίνει Ισπανικά\")",
 	"References from": "Αναφορές από",
 	"References from": "Αναφορές από",
@@ -829,6 +853,7 @@
 	"Select a pipeline": "Επιλέξτε ένα pipeline",
 	"Select a pipeline": "Επιλέξτε ένα pipeline",
 	"Select a pipeline url": "Επιλέξτε ένα pipeline url",
 	"Select a pipeline url": "Επιλέξτε ένα pipeline url",
 	"Select a tool": "Επιλέξτε ένα εργαλείο",
 	"Select a tool": "Επιλέξτε ένα εργαλείο",
+	"Select an auth method": "",
 	"Select an Ollama instance": "",
 	"Select an Ollama instance": "",
 	"Select Engine": "Επιλέξτε Μηχανή",
 	"Select Engine": "Επιλέξτε Μηχανή",
 	"Select Knowledge": "Επιλέξτε Γνώση",
 	"Select Knowledge": "Επιλέξτε Γνώση",
@@ -869,7 +894,7 @@
 	"Settings saved successfully!": "Οι Ρυθμίσεις αποθηκεύτηκαν με επιτυχία!",
 	"Settings saved successfully!": "Οι Ρυθμίσεις αποθηκεύτηκαν με επιτυχία!",
 	"Share": "Κοινή Χρήση",
 	"Share": "Κοινή Χρήση",
 	"Share Chat": "Κοινή Χρήση Συνομιλίας",
 	"Share Chat": "Κοινή Χρήση Συνομιλίας",
-	"Share to OpenWebUI Community": "Κοινή Χρήση στην Κοινότητα OpenWebUI",
+	"Share to Open WebUI Community": "Κοινή Χρήση στην Κοινότητα OpenWebUI",
 	"Show": "Εμφάνιση",
 	"Show": "Εμφάνιση",
 	"Show \"What's New\" modal on login": "Εμφάνιση του παράθυρου \"Τι νέο υπάρχει\" κατά την είσοδο",
 	"Show \"What's New\" modal on login": "Εμφάνιση του παράθυρου \"Τι νέο υπάρχει\" κατά την είσοδο",
 	"Show Admin Details in Account Pending Overlay": "Εμφάνιση Λεπτομερειών Διαχειριστή στο Υπέρθεση Εκκρεμής Λογαριασμού",
 	"Show Admin Details in Account Pending Overlay": "Εμφάνιση Λεπτομερειών Διαχειριστή στο Υπέρθεση Εκκρεμής Λογαριασμού",
@@ -944,6 +969,7 @@
 	"This will reset the knowledge base and sync all files. Do you wish to continue?": "Αυτό θα επαναφέρει τη βάση γνώσης και θα συγχρονίσει όλα τα αρχεία. Θέλετε να συνεχίσετε;",
 	"This will reset the knowledge base and sync all files. Do you wish to continue?": "Αυτό θα επαναφέρει τη βάση γνώσης και θα συγχρονίσει όλα τα αρχεία. Θέλετε να συνεχίσετε;",
 	"Thorough explanation": "Λεπτομερής εξήγηση",
 	"Thorough explanation": "Λεπτομερής εξήγηση",
 	"Thought for {{DURATION}}": "",
 	"Thought for {{DURATION}}": "",
+	"Thought for {{DURATION}} seconds": "",
 	"Tika": "Tika",
 	"Tika": "Tika",
 	"Tika Server URL required.": "Απαιτείται το URL διακομιστή Tika.",
 	"Tika Server URL required.": "Απαιτείται το URL διακομιστή Tika.",
 	"Tiktoken": "Tiktoken",
 	"Tiktoken": "Tiktoken",

+ 29 - 3
src/lib/i18n/locales/en-GB/translation.json

@@ -122,6 +122,7 @@
 	"Beta": "",
 	"Beta": "",
 	"Bing Search V7 Endpoint": "",
 	"Bing Search V7 Endpoint": "",
 	"Bing Search V7 Subscription Key": "",
 	"Bing Search V7 Subscription Key": "",
+	"Bocha Search API Key": "",
 	"Brave Search API Key": "",
 	"Brave Search API Key": "",
 	"By {{name}}": "",
 	"By {{name}}": "",
 	"Bypass SSL verification for Websites": "",
 	"Bypass SSL verification for Websites": "",
@@ -163,6 +164,7 @@
 	"Click here to": "",
 	"Click here to": "",
 	"Click here to download user import template file.": "",
 	"Click here to download user import template file.": "",
 	"Click here to learn more about faster-whisper and see the available models.": "",
 	"Click here to learn more about faster-whisper and see the available models.": "",
+	"Click here to see available models.": "",
 	"Click here to select": "",
 	"Click here to select": "",
 	"Click here to select a csv file.": "",
 	"Click here to select a csv file.": "",
 	"Click here to select a py file.": "",
 	"Click here to select a py file.": "",
@@ -177,6 +179,8 @@
 	"Code execution": "",
 	"Code execution": "",
 	"Code formatted successfully": "",
 	"Code formatted successfully": "",
 	"Code Interpreter": "",
 	"Code Interpreter": "",
+	"Code Interpreter Engine": "",
+	"Code Interpreter Prompt Template": "",
 	"Collection": "",
 	"Collection": "",
 	"Color": "",
 	"Color": "",
 	"ComfyUI": "",
 	"ComfyUI": "",
@@ -193,6 +197,7 @@
 	"Confirm Password": "",
 	"Confirm Password": "",
 	"Confirm your action": "",
 	"Confirm your action": "",
 	"Confirm your new password": "",
 	"Confirm your new password": "",
+	"Connect to your own OpenAI compatible API endpoints.": "",
 	"Connections": "",
 	"Connections": "",
 	"Constrains effort on reasoning for reasoning models. Only applicable to reasoning models from specific providers that support reasoning effort. (Default: medium)": "",
 	"Constrains effort on reasoning for reasoning models. Only applicable to reasoning models from specific providers that support reasoning effort. (Default: medium)": "",
 	"Contact Admin for WebUI Access": "",
 	"Contact Admin for WebUI Access": "",
@@ -215,6 +220,7 @@
 	"Copy Link": "",
 	"Copy Link": "",
 	"Copy to clipboard": "",
 	"Copy to clipboard": "",
 	"Copying to clipboard was successful!": "",
 	"Copying to clipboard was successful!": "",
+	"CORS must be properly configured by the provider to allow requests from Open WebUI.": "",
 	"Create": "",
 	"Create": "",
 	"Create a knowledge base": "",
 	"Create a knowledge base": "",
 	"Create a model": "",
 	"Create a model": "",
@@ -268,6 +274,9 @@
 	"Describe your knowledge base and objectives": "",
 	"Describe your knowledge base and objectives": "",
 	"Description": "",
 	"Description": "",
 	"Didn't fully follow instructions": "",
 	"Didn't fully follow instructions": "",
+	"Direct Connections": "",
+	"Direct Connections allow users to connect to their own OpenAI compatible API endpoints.": "",
+	"Direct Connections settings updated": "",
 	"Disabled": "",
 	"Disabled": "",
 	"Discover a function": "",
 	"Discover a function": "",
 	"Discover a model": "",
 	"Discover a model": "",
@@ -290,6 +299,7 @@
 	"Documentation": "",
 	"Documentation": "",
 	"Documents": "",
 	"Documents": "",
 	"does not make any external connections, and your data stays securely on your locally hosted server.": "",
 	"does not make any external connections, and your data stays securely on your locally hosted server.": "",
+	"Domain Filter List": "",
 	"Don't have an account?": "",
 	"Don't have an account?": "",
 	"don't install random functions from sources you don't trust.": "",
 	"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 tools from sources you don't trust.": "",
@@ -325,6 +335,7 @@
 	"Embedding model set to \"{{embedding_model}}\"": "",
 	"Embedding model set to \"{{embedding_model}}\"": "",
 	"Enable API Key": "",
 	"Enable API Key": "",
 	"Enable autocomplete generation for chat messages": "",
 	"Enable autocomplete generation for chat messages": "",
+	"Enable Code Interpreter": "",
 	"Enable Community Sharing": "",
 	"Enable Community Sharing": "",
 	"Enable Google Drive": "",
 	"Enable Google Drive": "",
 	"Enable Memory Locking (mlock) to prevent model data from being swapped out of RAM. This option locks the model's working set of pages into RAM, ensuring that they will not be swapped out to disk. This can help maintain performance by avoiding page faults and ensuring fast data access.": "",
 	"Enable Memory Locking (mlock) to prevent model data from being swapped out of RAM. This option locks the model's working set of pages into RAM, ensuring that they will not be swapped out to disk. This can help maintain performance by avoiding page faults and ensuring fast data access.": "",
@@ -343,18 +354,23 @@
 	"Enter Application DN Password": "",
 	"Enter Application DN Password": "",
 	"Enter Bing Search V7 Endpoint": "",
 	"Enter Bing Search V7 Endpoint": "",
 	"Enter Bing Search V7 Subscription Key": "",
 	"Enter Bing Search V7 Subscription Key": "",
+	"Enter Bocha Search API Key": "",
 	"Enter Brave Search API Key": "",
 	"Enter Brave Search API Key": "",
 	"Enter certificate path": "",
 	"Enter certificate path": "",
 	"Enter CFG Scale (e.g. 7.0)": "",
 	"Enter CFG Scale (e.g. 7.0)": "",
 	"Enter Chunk Overlap": "",
 	"Enter Chunk Overlap": "",
 	"Enter Chunk Size": "",
 	"Enter Chunk Size": "",
 	"Enter description": "",
 	"Enter description": "",
+	"Enter domains separated by commas (e.g., example.com,site.org)": "",
 	"Enter Exa API Key": "",
 	"Enter Exa API Key": "",
 	"Enter Github Raw URL": "",
 	"Enter Github Raw URL": "",
 	"Enter Google PSE API Key": "",
 	"Enter Google PSE API Key": "",
 	"Enter Google PSE Engine Id": "",
 	"Enter Google PSE Engine Id": "",
 	"Enter Image Size (e.g. 512x512)": "",
 	"Enter Image Size (e.g. 512x512)": "",
 	"Enter Jina API Key": "",
 	"Enter Jina API Key": "",
+	"Enter Jupyter Password": "",
+	"Enter Jupyter Token": "",
+	"Enter Jupyter URL": "",
 	"Enter Kagi Search API Key": "",
 	"Enter Kagi Search API Key": "",
 	"Enter language codes": "",
 	"Enter language codes": "",
 	"Enter Model ID": "",
 	"Enter Model ID": "",
@@ -540,6 +556,8 @@
 	"JSON Preview": "",
 	"JSON Preview": "",
 	"July": "",
 	"July": "",
 	"June": "",
 	"June": "",
+	"Jupyter Auth": "",
+	"Jupyter URL": "",
 	"JWT Expiration": "",
 	"JWT Expiration": "",
 	"JWT Token": "",
 	"JWT Token": "",
 	"Kagi Search API Key": "",
 	"Kagi Search API Key": "",
@@ -552,6 +570,8 @@
 	"Knowledge deleted successfully.": "",
 	"Knowledge deleted successfully.": "",
 	"Knowledge reset successfully.": "",
 	"Knowledge reset successfully.": "",
 	"Knowledge updated successfully": "",
 	"Knowledge updated successfully": "",
+	"Kokoro.js (Browser)": "",
+	"Kokoro.js Dtype": "",
 	"Label": "",
 	"Label": "",
 	"Landing Page Mode": "",
 	"Landing Page Mode": "",
 	"Language": "",
 	"Language": "",
@@ -566,19 +586,22 @@
 	"Leave empty to include all models from \"{{URL}}/models\" endpoint": "",
 	"Leave empty to include all models from \"{{URL}}/models\" endpoint": "",
 	"Leave empty to include all models or select specific models": "",
 	"Leave empty to include all models or select specific models": "",
 	"Leave empty to use the default prompt, or enter a custom prompt": "",
 	"Leave empty to use the default prompt, or enter a custom prompt": "",
+	"Leave model field empty to use the default model.": "",
 	"Light": "",
 	"Light": "",
 	"Listening...": "",
 	"Listening...": "",
 	"Llama.cpp": "",
 	"Llama.cpp": "",
 	"LLMs can make mistakes. Verify important information.": "",
 	"LLMs can make mistakes. Verify important information.": "",
+	"Loading Kokoro.js...": "",
 	"Local": "",
 	"Local": "",
 	"Local Models": "",
 	"Local Models": "",
 	"Lost": "",
 	"Lost": "",
 	"LTR": "",
 	"LTR": "",
-	"Made by OpenWebUI Community": "",
+	"Made by Open WebUI Community": "",
 	"Make sure to enclose them with": "",
 	"Make sure to enclose them with": "",
 	"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.": "",
 	"Manage": "",
 	"Manage": "",
 	"Manage Arena Models": "",
 	"Manage Arena Models": "",
+	"Manage Direct Connections": "",
 	"Manage Models": "",
 	"Manage Models": "",
 	"Manage Ollama": "",
 	"Manage Ollama": "",
 	"Manage Ollama API Connections": "",
 	"Manage Ollama API Connections": "",
@@ -722,6 +745,7 @@
 	"Plain text (.txt)": "",
 	"Plain text (.txt)": "",
 	"Playground": "",
 	"Playground": "",
 	"Please carefully review the following warnings:": "",
 	"Please carefully review the following warnings:": "",
+	"Please do not close the settings page while loading the model.": "",
 	"Please enter a prompt": "",
 	"Please enter a prompt": "",
 	"Please fill in all fields.": "",
 	"Please fill in all fields.": "",
 	"Please select a model first.": "",
 	"Please select a model first.": "",
@@ -754,7 +778,7 @@
 	"Read Aloud": "",
 	"Read Aloud": "",
 	"Reasoning Effort": "",
 	"Reasoning Effort": "",
 	"Record voice": "",
 	"Record voice": "",
-	"Redirecting you to OpenWebUI Community": "",
+	"Redirecting you to Open WebUI Community": "",
 	"Reduces the probability of generating nonsense. A higher value (e.g. 100) will give more diverse answers, while a lower value (e.g. 10) will be more conservative. (Default: 40)": "",
 	"Reduces the probability of generating nonsense. A higher value (e.g. 100) will give more diverse answers, while a lower value (e.g. 10) will be more conservative. (Default: 40)": "",
 	"Refer to yourself as \"User\" (e.g., \"User is learning Spanish\")": "",
 	"Refer to yourself as \"User\" (e.g., \"User is learning Spanish\")": "",
 	"References from": "",
 	"References from": "",
@@ -829,6 +853,7 @@
 	"Select a pipeline": "",
 	"Select a pipeline": "",
 	"Select a pipeline url": "",
 	"Select a pipeline url": "",
 	"Select a tool": "",
 	"Select a tool": "",
+	"Select an auth method": "",
 	"Select an Ollama instance": "",
 	"Select an Ollama instance": "",
 	"Select Engine": "",
 	"Select Engine": "",
 	"Select Knowledge": "",
 	"Select Knowledge": "",
@@ -869,7 +894,7 @@
 	"Settings saved successfully!": "",
 	"Settings saved successfully!": "",
 	"Share": "",
 	"Share": "",
 	"Share Chat": "",
 	"Share Chat": "",
-	"Share to OpenWebUI Community": "",
+	"Share to Open WebUI Community": "",
 	"Show": "",
 	"Show": "",
 	"Show \"What's New\" modal on login": "",
 	"Show \"What's New\" modal on login": "",
 	"Show Admin Details in Account Pending Overlay": "",
 	"Show Admin Details in Account Pending Overlay": "",
@@ -944,6 +969,7 @@
 	"This will reset the knowledge base and sync all files. Do you wish to continue?": "",
 	"This will reset the knowledge base and sync all files. Do you wish to continue?": "",
 	"Thorough explanation": "",
 	"Thorough explanation": "",
 	"Thought for {{DURATION}}": "",
 	"Thought for {{DURATION}}": "",
+	"Thought for {{DURATION}} seconds": "",
 	"Tika": "",
 	"Tika": "",
 	"Tika Server URL required.": "",
 	"Tika Server URL required.": "",
 	"Tiktoken": "",
 	"Tiktoken": "",

+ 29 - 3
src/lib/i18n/locales/en-US/translation.json

@@ -122,6 +122,7 @@
 	"Beta": "",
 	"Beta": "",
 	"Bing Search V7 Endpoint": "",
 	"Bing Search V7 Endpoint": "",
 	"Bing Search V7 Subscription Key": "",
 	"Bing Search V7 Subscription Key": "",
+	"Bocha Search API Key": "",
 	"Brave Search API Key": "",
 	"Brave Search API Key": "",
 	"By {{name}}": "",
 	"By {{name}}": "",
 	"Bypass SSL verification for Websites": "",
 	"Bypass SSL verification for Websites": "",
@@ -163,6 +164,7 @@
 	"Click here to": "",
 	"Click here to": "",
 	"Click here to download user import template file.": "",
 	"Click here to download user import template file.": "",
 	"Click here to learn more about faster-whisper and see the available models.": "",
 	"Click here to learn more about faster-whisper and see the available models.": "",
+	"Click here to see available models.": "",
 	"Click here to select": "",
 	"Click here to select": "",
 	"Click here to select a csv file.": "",
 	"Click here to select a csv file.": "",
 	"Click here to select a py file.": "",
 	"Click here to select a py file.": "",
@@ -177,6 +179,8 @@
 	"Code execution": "",
 	"Code execution": "",
 	"Code formatted successfully": "",
 	"Code formatted successfully": "",
 	"Code Interpreter": "",
 	"Code Interpreter": "",
+	"Code Interpreter Engine": "",
+	"Code Interpreter Prompt Template": "",
 	"Collection": "",
 	"Collection": "",
 	"Color": "",
 	"Color": "",
 	"ComfyUI": "",
 	"ComfyUI": "",
@@ -193,6 +197,7 @@
 	"Confirm Password": "",
 	"Confirm Password": "",
 	"Confirm your action": "",
 	"Confirm your action": "",
 	"Confirm your new password": "",
 	"Confirm your new password": "",
+	"Connect to your own OpenAI compatible API endpoints.": "",
 	"Connections": "",
 	"Connections": "",
 	"Constrains effort on reasoning for reasoning models. Only applicable to reasoning models from specific providers that support reasoning effort. (Default: medium)": "",
 	"Constrains effort on reasoning for reasoning models. Only applicable to reasoning models from specific providers that support reasoning effort. (Default: medium)": "",
 	"Contact Admin for WebUI Access": "",
 	"Contact Admin for WebUI Access": "",
@@ -215,6 +220,7 @@
 	"Copy Link": "",
 	"Copy Link": "",
 	"Copy to clipboard": "",
 	"Copy to clipboard": "",
 	"Copying to clipboard was successful!": "",
 	"Copying to clipboard was successful!": "",
+	"CORS must be properly configured by the provider to allow requests from Open WebUI.": "",
 	"Create": "",
 	"Create": "",
 	"Create a knowledge base": "",
 	"Create a knowledge base": "",
 	"Create a model": "",
 	"Create a model": "",
@@ -268,6 +274,9 @@
 	"Describe your knowledge base and objectives": "",
 	"Describe your knowledge base and objectives": "",
 	"Description": "",
 	"Description": "",
 	"Didn't fully follow instructions": "",
 	"Didn't fully follow instructions": "",
+	"Direct Connections": "",
+	"Direct Connections allow users to connect to their own OpenAI compatible API endpoints.": "",
+	"Direct Connections settings updated": "",
 	"Disabled": "",
 	"Disabled": "",
 	"Discover a function": "",
 	"Discover a function": "",
 	"Discover a model": "",
 	"Discover a model": "",
@@ -290,6 +299,7 @@
 	"Documentation": "",
 	"Documentation": "",
 	"Documents": "",
 	"Documents": "",
 	"does not make any external connections, and your data stays securely on your locally hosted server.": "",
 	"does not make any external connections, and your data stays securely on your locally hosted server.": "",
+	"Domain Filter List": "",
 	"Don't have an account?": "",
 	"Don't have an account?": "",
 	"don't install random functions from sources you don't trust.": "",
 	"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 tools from sources you don't trust.": "",
@@ -325,6 +335,7 @@
 	"Embedding model set to \"{{embedding_model}}\"": "",
 	"Embedding model set to \"{{embedding_model}}\"": "",
 	"Enable API Key": "",
 	"Enable API Key": "",
 	"Enable autocomplete generation for chat messages": "",
 	"Enable autocomplete generation for chat messages": "",
+	"Enable Code Interpreter": "",
 	"Enable Community Sharing": "",
 	"Enable Community Sharing": "",
 	"Enable Google Drive": "",
 	"Enable Google Drive": "",
 	"Enable Memory Locking (mlock) to prevent model data from being swapped out of RAM. This option locks the model's working set of pages into RAM, ensuring that they will not be swapped out to disk. This can help maintain performance by avoiding page faults and ensuring fast data access.": "",
 	"Enable Memory Locking (mlock) to prevent model data from being swapped out of RAM. This option locks the model's working set of pages into RAM, ensuring that they will not be swapped out to disk. This can help maintain performance by avoiding page faults and ensuring fast data access.": "",
@@ -343,18 +354,23 @@
 	"Enter Application DN Password": "",
 	"Enter Application DN Password": "",
 	"Enter Bing Search V7 Endpoint": "",
 	"Enter Bing Search V7 Endpoint": "",
 	"Enter Bing Search V7 Subscription Key": "",
 	"Enter Bing Search V7 Subscription Key": "",
+	"Enter Bocha Search API Key": "",
 	"Enter Brave Search API Key": "",
 	"Enter Brave Search API Key": "",
 	"Enter certificate path": "",
 	"Enter certificate path": "",
 	"Enter CFG Scale (e.g. 7.0)": "",
 	"Enter CFG Scale (e.g. 7.0)": "",
 	"Enter Chunk Overlap": "",
 	"Enter Chunk Overlap": "",
 	"Enter Chunk Size": "",
 	"Enter Chunk Size": "",
 	"Enter description": "",
 	"Enter description": "",
+	"Enter domains separated by commas (e.g., example.com,site.org)": "",
 	"Enter Exa API Key": "",
 	"Enter Exa API Key": "",
 	"Enter Github Raw URL": "",
 	"Enter Github Raw URL": "",
 	"Enter Google PSE API Key": "",
 	"Enter Google PSE API Key": "",
 	"Enter Google PSE Engine Id": "",
 	"Enter Google PSE Engine Id": "",
 	"Enter Image Size (e.g. 512x512)": "",
 	"Enter Image Size (e.g. 512x512)": "",
 	"Enter Jina API Key": "",
 	"Enter Jina API Key": "",
+	"Enter Jupyter Password": "",
+	"Enter Jupyter Token": "",
+	"Enter Jupyter URL": "",
 	"Enter Kagi Search API Key": "",
 	"Enter Kagi Search API Key": "",
 	"Enter language codes": "",
 	"Enter language codes": "",
 	"Enter Model ID": "",
 	"Enter Model ID": "",
@@ -540,6 +556,8 @@
 	"JSON Preview": "",
 	"JSON Preview": "",
 	"July": "",
 	"July": "",
 	"June": "",
 	"June": "",
+	"Jupyter Auth": "",
+	"Jupyter URL": "",
 	"JWT Expiration": "",
 	"JWT Expiration": "",
 	"JWT Token": "",
 	"JWT Token": "",
 	"Kagi Search API Key": "",
 	"Kagi Search API Key": "",
@@ -552,6 +570,8 @@
 	"Knowledge deleted successfully.": "",
 	"Knowledge deleted successfully.": "",
 	"Knowledge reset successfully.": "",
 	"Knowledge reset successfully.": "",
 	"Knowledge updated successfully": "",
 	"Knowledge updated successfully": "",
+	"Kokoro.js (Browser)": "",
+	"Kokoro.js Dtype": "",
 	"Label": "",
 	"Label": "",
 	"Landing Page Mode": "",
 	"Landing Page Mode": "",
 	"Language": "",
 	"Language": "",
@@ -566,19 +586,22 @@
 	"Leave empty to include all models from \"{{URL}}/models\" endpoint": "",
 	"Leave empty to include all models from \"{{URL}}/models\" endpoint": "",
 	"Leave empty to include all models or select specific models": "",
 	"Leave empty to include all models or select specific models": "",
 	"Leave empty to use the default prompt, or enter a custom prompt": "",
 	"Leave empty to use the default prompt, or enter a custom prompt": "",
+	"Leave model field empty to use the default model.": "",
 	"Light": "",
 	"Light": "",
 	"Listening...": "",
 	"Listening...": "",
 	"Llama.cpp": "",
 	"Llama.cpp": "",
 	"LLMs can make mistakes. Verify important information.": "",
 	"LLMs can make mistakes. Verify important information.": "",
+	"Loading Kokoro.js...": "",
 	"Local": "",
 	"Local": "",
 	"Local Models": "",
 	"Local Models": "",
 	"Lost": "",
 	"Lost": "",
 	"LTR": "",
 	"LTR": "",
-	"Made by OpenWebUI Community": "",
+	"Made by Open WebUI Community": "",
 	"Make sure to enclose them with": "",
 	"Make sure to enclose them with": "",
 	"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.": "",
 	"Manage": "",
 	"Manage": "",
 	"Manage Arena Models": "",
 	"Manage Arena Models": "",
+	"Manage Direct Connections": "",
 	"Manage Models": "",
 	"Manage Models": "",
 	"Manage Ollama": "",
 	"Manage Ollama": "",
 	"Manage Ollama API Connections": "",
 	"Manage Ollama API Connections": "",
@@ -722,6 +745,7 @@
 	"Plain text (.txt)": "",
 	"Plain text (.txt)": "",
 	"Playground": "",
 	"Playground": "",
 	"Please carefully review the following warnings:": "",
 	"Please carefully review the following warnings:": "",
+	"Please do not close the settings page while loading the model.": "",
 	"Please enter a prompt": "",
 	"Please enter a prompt": "",
 	"Please fill in all fields.": "",
 	"Please fill in all fields.": "",
 	"Please select a model first.": "",
 	"Please select a model first.": "",
@@ -754,7 +778,7 @@
 	"Read Aloud": "",
 	"Read Aloud": "",
 	"Reasoning Effort": "",
 	"Reasoning Effort": "",
 	"Record voice": "",
 	"Record voice": "",
-	"Redirecting you to OpenWebUI Community": "",
+	"Redirecting you to Open WebUI Community": "",
 	"Reduces the probability of generating nonsense. A higher value (e.g. 100) will give more diverse answers, while a lower value (e.g. 10) will be more conservative. (Default: 40)": "",
 	"Reduces the probability of generating nonsense. A higher value (e.g. 100) will give more diverse answers, while a lower value (e.g. 10) will be more conservative. (Default: 40)": "",
 	"Refer to yourself as \"User\" (e.g., \"User is learning Spanish\")": "",
 	"Refer to yourself as \"User\" (e.g., \"User is learning Spanish\")": "",
 	"References from": "",
 	"References from": "",
@@ -829,6 +853,7 @@
 	"Select a pipeline": "",
 	"Select a pipeline": "",
 	"Select a pipeline url": "",
 	"Select a pipeline url": "",
 	"Select a tool": "",
 	"Select a tool": "",
+	"Select an auth method": "",
 	"Select an Ollama instance": "",
 	"Select an Ollama instance": "",
 	"Select Engine": "",
 	"Select Engine": "",
 	"Select Knowledge": "",
 	"Select Knowledge": "",
@@ -869,7 +894,7 @@
 	"Settings saved successfully!": "",
 	"Settings saved successfully!": "",
 	"Share": "",
 	"Share": "",
 	"Share Chat": "",
 	"Share Chat": "",
-	"Share to OpenWebUI Community": "",
+	"Share to Open WebUI Community": "",
 	"Show": "",
 	"Show": "",
 	"Show \"What's New\" modal on login": "",
 	"Show \"What's New\" modal on login": "",
 	"Show Admin Details in Account Pending Overlay": "",
 	"Show Admin Details in Account Pending Overlay": "",
@@ -944,6 +969,7 @@
 	"This will reset the knowledge base and sync all files. Do you wish to continue?": "",
 	"This will reset the knowledge base and sync all files. Do you wish to continue?": "",
 	"Thorough explanation": "",
 	"Thorough explanation": "",
 	"Thought for {{DURATION}}": "",
 	"Thought for {{DURATION}}": "",
+	"Thought for {{DURATION}} seconds": "",
 	"Tika": "",
 	"Tika": "",
 	"Tika Server URL required.": "",
 	"Tika Server URL required.": "",
 	"Tiktoken": "",
 	"Tiktoken": "",

File diff suppressed because it is too large
+ 325 - 301
src/lib/i18n/locales/es-ES/translation.json


+ 29 - 3
src/lib/i18n/locales/eu-ES/translation.json

@@ -122,6 +122,7 @@
 	"Beta": "",
 	"Beta": "",
 	"Bing Search V7 Endpoint": "Bing Bilaketa V7 Endpointua",
 	"Bing Search V7 Endpoint": "Bing Bilaketa V7 Endpointua",
 	"Bing Search V7 Subscription Key": "Bing Bilaketa V7 Harpidetza Gakoa",
 	"Bing Search V7 Subscription Key": "Bing Bilaketa V7 Harpidetza Gakoa",
+	"Bocha Search API Key": "",
 	"Brave Search API Key": "Brave Bilaketa API Gakoa",
 	"Brave Search API Key": "Brave Bilaketa API Gakoa",
 	"By {{name}}": "{{name}}-k",
 	"By {{name}}": "{{name}}-k",
 	"Bypass SSL verification for Websites": "Saihestu SSL egiaztapena Webguneentzat",
 	"Bypass SSL verification for Websites": "Saihestu SSL egiaztapena Webguneentzat",
@@ -163,6 +164,7 @@
 	"Click here to": "Klikatu hemen",
 	"Click here to": "Klikatu hemen",
 	"Click here to download user import template file.": "Klikatu hemen erabiltzaileen inportazio txantiloia deskargatzeko.",
 	"Click here to download user import template file.": "Klikatu hemen erabiltzaileen inportazio txantiloia deskargatzeko.",
 	"Click here to learn more about faster-whisper and see the available models.": "Klikatu hemen faster-whisper-i buruz gehiago ikasteko eta eredu erabilgarriak ikusteko.",
 	"Click here to learn more about faster-whisper and see the available models.": "Klikatu hemen faster-whisper-i buruz gehiago ikasteko eta eredu erabilgarriak ikusteko.",
+	"Click here to see available models.": "",
 	"Click here to select": "Klikatu hemen hautatzeko",
 	"Click here to select": "Klikatu hemen hautatzeko",
 	"Click here to select a csv file.": "Klikatu hemen csv fitxategi bat hautatzeko.",
 	"Click here to select a csv file.": "Klikatu hemen csv fitxategi bat hautatzeko.",
 	"Click here to select a py file.": "Klikatu hemen py fitxategi bat hautatzeko.",
 	"Click here to select a py file.": "Klikatu hemen py fitxategi bat hautatzeko.",
@@ -177,6 +179,8 @@
 	"Code execution": "Kodearen exekuzioa",
 	"Code execution": "Kodearen exekuzioa",
 	"Code formatted successfully": "Kodea ongi formateatu da",
 	"Code formatted successfully": "Kodea ongi formateatu da",
 	"Code Interpreter": "",
 	"Code Interpreter": "",
+	"Code Interpreter Engine": "",
+	"Code Interpreter Prompt Template": "",
 	"Collection": "Bilduma",
 	"Collection": "Bilduma",
 	"Color": "Kolorea",
 	"Color": "Kolorea",
 	"ComfyUI": "ComfyUI",
 	"ComfyUI": "ComfyUI",
@@ -193,6 +197,7 @@
 	"Confirm Password": "Berretsi Pasahitza",
 	"Confirm Password": "Berretsi Pasahitza",
 	"Confirm your action": "Berretsi zure ekintza",
 	"Confirm your action": "Berretsi zure ekintza",
 	"Confirm your new password": "",
 	"Confirm your new password": "",
+	"Connect to your own OpenAI compatible API endpoints.": "",
 	"Connections": "Konexioak",
 	"Connections": "Konexioak",
 	"Constrains effort on reasoning for reasoning models. Only applicable to reasoning models from specific providers that support reasoning effort. (Default: medium)": "",
 	"Constrains effort on reasoning for reasoning models. Only applicable to reasoning models from specific providers that support reasoning effort. (Default: medium)": "",
 	"Contact Admin for WebUI Access": "Jarri harremanetan Administratzailearekin WebUI Sarbiderako",
 	"Contact Admin for WebUI Access": "Jarri harremanetan Administratzailearekin WebUI Sarbiderako",
@@ -215,6 +220,7 @@
 	"Copy Link": "Kopiatu Esteka",
 	"Copy Link": "Kopiatu Esteka",
 	"Copy to clipboard": "Kopiatu arbelera",
 	"Copy to clipboard": "Kopiatu arbelera",
 	"Copying to clipboard was successful!": "Arbelera kopiatzea arrakastatsua izan da!",
 	"Copying to clipboard was successful!": "Arbelera kopiatzea arrakastatsua izan da!",
+	"CORS must be properly configured by the provider to allow requests from Open WebUI.": "",
 	"Create": "Sortu",
 	"Create": "Sortu",
 	"Create a knowledge base": "Sortu ezagutza-base bat",
 	"Create a knowledge base": "Sortu ezagutza-base bat",
 	"Create a model": "Sortu eredu bat",
 	"Create a model": "Sortu eredu bat",
@@ -268,6 +274,9 @@
 	"Describe your knowledge base and objectives": "Deskribatu zure ezagutza-basea eta helburuak",
 	"Describe your knowledge base and objectives": "Deskribatu zure ezagutza-basea eta helburuak",
 	"Description": "Deskribapena",
 	"Description": "Deskribapena",
 	"Didn't fully follow instructions": "Ez ditu jarraibideak guztiz jarraitu",
 	"Didn't fully follow instructions": "Ez ditu jarraibideak guztiz jarraitu",
+	"Direct Connections": "",
+	"Direct Connections allow users to connect to their own OpenAI compatible API endpoints.": "",
+	"Direct Connections settings updated": "",
 	"Disabled": "Desgaituta",
 	"Disabled": "Desgaituta",
 	"Discover a function": "Aurkitu funtzio bat",
 	"Discover a function": "Aurkitu funtzio bat",
 	"Discover a model": "Aurkitu eredu bat",
 	"Discover a model": "Aurkitu eredu bat",
@@ -290,6 +299,7 @@
 	"Documentation": "Dokumentazioa",
 	"Documentation": "Dokumentazioa",
 	"Documents": "Dokumentuak",
 	"Documents": "Dokumentuak",
 	"does not make any external connections, and your data stays securely on your locally hosted server.": "ez du kanpo konexiorik egiten, eta zure datuak modu seguruan mantentzen dira zure zerbitzari lokalean.",
 	"does not make any external connections, and your data stays securely on your locally hosted server.": "ez du kanpo konexiorik egiten, eta zure datuak modu seguruan mantentzen dira zure zerbitzari lokalean.",
+	"Domain Filter List": "",
 	"Don't have an account?": "Ez duzu konturik?",
 	"Don't have an account?": "Ez duzu konturik?",
 	"don't install random functions from sources you don't trust.": "ez instalatu fidagarriak ez diren iturrietatik datozen ausazko funtzioak.",
 	"don't install random functions from sources you don't trust.": "ez instalatu fidagarriak ez diren iturrietatik datozen ausazko funtzioak.",
 	"don't install random tools from sources you don't trust.": "ez instalatu fidagarriak ez diren iturrietatik datozen ausazko tresnak.",
 	"don't install random tools from sources you don't trust.": "ez instalatu fidagarriak ez diren iturrietatik datozen ausazko tresnak.",
@@ -325,6 +335,7 @@
 	"Embedding model set to \"{{embedding_model}}\"": "Embedding eredua \"{{embedding_model}}\"-ra ezarri da",
 	"Embedding model set to \"{{embedding_model}}\"": "Embedding eredua \"{{embedding_model}}\"-ra ezarri da",
 	"Enable API Key": "",
 	"Enable API Key": "",
 	"Enable autocomplete generation for chat messages": "",
 	"Enable autocomplete generation for chat messages": "",
+	"Enable Code Interpreter": "",
 	"Enable Community Sharing": "Gaitu Komunitatearen Partekatzea",
 	"Enable Community Sharing": "Gaitu Komunitatearen Partekatzea",
 	"Enable Google Drive": "",
 	"Enable Google Drive": "",
 	"Enable Memory Locking (mlock) to prevent model data from being swapped out of RAM. This option locks the model's working set of pages into RAM, ensuring that they will not be swapped out to disk. This can help maintain performance by avoiding page faults and ensuring fast data access.": "Gaitu Memoria Blokeatzea (mlock) ereduaren datuak RAM memoriatik kanpo ez trukatzeko. Aukera honek ereduaren lan-orri multzoa RAMean blokatzen du, diskora ez direla trukatuko ziurtatuz. Honek errendimendua mantentzen lagun dezake, orri-hutsegiteak saihestuz eta datuen sarbide azkarra bermatuz.",
 	"Enable Memory Locking (mlock) to prevent model data from being swapped out of RAM. This option locks the model's working set of pages into RAM, ensuring that they will not be swapped out to disk. This can help maintain performance by avoiding page faults and ensuring fast data access.": "Gaitu Memoria Blokeatzea (mlock) ereduaren datuak RAM memoriatik kanpo ez trukatzeko. Aukera honek ereduaren lan-orri multzoa RAMean blokatzen du, diskora ez direla trukatuko ziurtatuz. Honek errendimendua mantentzen lagun dezake, orri-hutsegiteak saihestuz eta datuen sarbide azkarra bermatuz.",
@@ -343,18 +354,23 @@
 	"Enter Application DN Password": "Sartu Aplikazioaren DN Pasahitza",
 	"Enter Application DN Password": "Sartu Aplikazioaren DN Pasahitza",
 	"Enter Bing Search V7 Endpoint": "Sartu Bing Bilaketa V7 Endpointua",
 	"Enter Bing Search V7 Endpoint": "Sartu Bing Bilaketa V7 Endpointua",
 	"Enter Bing Search V7 Subscription Key": "Sartu Bing Bilaketa V7 Harpidetza Gakoa",
 	"Enter Bing Search V7 Subscription Key": "Sartu Bing Bilaketa V7 Harpidetza Gakoa",
+	"Enter Bocha Search API Key": "",
 	"Enter Brave Search API Key": "Sartu Brave Bilaketa API Gakoa",
 	"Enter Brave Search API Key": "Sartu Brave Bilaketa API Gakoa",
 	"Enter certificate path": "Sartu ziurtagiriaren bidea",
 	"Enter certificate path": "Sartu ziurtagiriaren bidea",
 	"Enter CFG Scale (e.g. 7.0)": "Sartu CFG Eskala (adib. 7.0)",
 	"Enter CFG Scale (e.g. 7.0)": "Sartu CFG Eskala (adib. 7.0)",
 	"Enter Chunk Overlap": "Sartu Zatien Gainjartzea (chunk overlap)",
 	"Enter Chunk Overlap": "Sartu Zatien Gainjartzea (chunk overlap)",
 	"Enter Chunk Size": "Sartu Zati Tamaina",
 	"Enter Chunk Size": "Sartu Zati Tamaina",
 	"Enter description": "Sartu deskribapena",
 	"Enter description": "Sartu deskribapena",
+	"Enter domains separated by commas (e.g., example.com,site.org)": "",
 	"Enter Exa API Key": "",
 	"Enter Exa API Key": "",
 	"Enter Github Raw URL": "Sartu Github Raw URLa",
 	"Enter Github Raw URL": "Sartu Github Raw URLa",
 	"Enter Google PSE API Key": "Sartu Google PSE API Gakoa",
 	"Enter Google PSE API Key": "Sartu Google PSE API Gakoa",
 	"Enter Google PSE Engine Id": "Sartu Google PSE Motor IDa",
 	"Enter Google PSE Engine Id": "Sartu Google PSE Motor IDa",
 	"Enter Image Size (e.g. 512x512)": "Sartu Irudi Tamaina (adib. 512x512)",
 	"Enter Image Size (e.g. 512x512)": "Sartu Irudi Tamaina (adib. 512x512)",
 	"Enter Jina API Key": "Sartu Jina API Gakoa",
 	"Enter Jina API Key": "Sartu Jina API Gakoa",
+	"Enter Jupyter Password": "",
+	"Enter Jupyter Token": "",
+	"Enter Jupyter URL": "",
 	"Enter Kagi Search API Key": "",
 	"Enter Kagi Search API Key": "",
 	"Enter language codes": "Sartu hizkuntza kodeak",
 	"Enter language codes": "Sartu hizkuntza kodeak",
 	"Enter Model ID": "Sartu Eredu IDa",
 	"Enter Model ID": "Sartu Eredu IDa",
@@ -540,6 +556,8 @@
 	"JSON Preview": "JSON Aurrebista",
 	"JSON Preview": "JSON Aurrebista",
 	"July": "Uztaila",
 	"July": "Uztaila",
 	"June": "Ekaina",
 	"June": "Ekaina",
+	"Jupyter Auth": "",
+	"Jupyter URL": "",
 	"JWT Expiration": "JWT Iraungitzea",
 	"JWT Expiration": "JWT Iraungitzea",
 	"JWT Token": "JWT Tokena",
 	"JWT Token": "JWT Tokena",
 	"Kagi Search API Key": "",
 	"Kagi Search API Key": "",
@@ -552,6 +570,8 @@
 	"Knowledge deleted successfully.": "Ezagutza ongi ezabatu da.",
 	"Knowledge deleted successfully.": "Ezagutza ongi ezabatu da.",
 	"Knowledge reset successfully.": "Ezagutza ongi berrezarri da.",
 	"Knowledge reset successfully.": "Ezagutza ongi berrezarri da.",
 	"Knowledge updated successfully": "Ezagutza ongi eguneratu da.",
 	"Knowledge updated successfully": "Ezagutza ongi eguneratu da.",
+	"Kokoro.js (Browser)": "",
+	"Kokoro.js Dtype": "",
 	"Label": "Etiketa",
 	"Label": "Etiketa",
 	"Landing Page Mode": "Hasiera Orriaren Modua",
 	"Landing Page Mode": "Hasiera Orriaren Modua",
 	"Language": "Hizkuntza",
 	"Language": "Hizkuntza",
@@ -566,19 +586,22 @@
 	"Leave empty to include all models from \"{{URL}}/models\" endpoint": "Utzi hutsik \"{{URL}}/models\" endpointuko eredu guztiak sartzeko",
 	"Leave empty to include all models from \"{{URL}}/models\" endpoint": "Utzi hutsik \"{{URL}}/models\" endpointuko eredu guztiak sartzeko",
 	"Leave empty to include all models or select specific models": "Utzi hutsik eredu guztiak sartzeko edo hautatu eredu zehatzak",
 	"Leave empty to include all models or select specific models": "Utzi hutsik eredu guztiak sartzeko edo hautatu eredu zehatzak",
 	"Leave empty to use the default prompt, or enter a custom prompt": "Utzi hutsik prompt lehenetsia erabiltzeko, edo sartu prompt pertsonalizatu bat",
 	"Leave empty to use the default prompt, or enter a custom prompt": "Utzi hutsik prompt lehenetsia erabiltzeko, edo sartu prompt pertsonalizatu bat",
+	"Leave model field empty to use the default model.": "",
 	"Light": "Argia",
 	"Light": "Argia",
 	"Listening...": "Entzuten...",
 	"Listening...": "Entzuten...",
 	"Llama.cpp": "",
 	"Llama.cpp": "",
 	"LLMs can make mistakes. Verify important information.": "LLMek akatsak egin ditzakete. Egiaztatu informazio garrantzitsua.",
 	"LLMs can make mistakes. Verify important information.": "LLMek akatsak egin ditzakete. Egiaztatu informazio garrantzitsua.",
+	"Loading Kokoro.js...": "",
 	"Local": "Lokala",
 	"Local": "Lokala",
 	"Local Models": "Modelo lokalak",
 	"Local Models": "Modelo lokalak",
 	"Lost": "Galduta",
 	"Lost": "Galduta",
 	"LTR": "LTR",
 	"LTR": "LTR",
-	"Made by OpenWebUI Community": "OpenWebUI Komunitateak egina",
+	"Made by Open WebUI Community": "OpenWebUI Komunitateak egina",
 	"Make sure to enclose them with": "Ziurtatu hauek gehitzen dituzula",
 	"Make sure to enclose them with": "Ziurtatu hauek gehitzen dituzula",
 	"Make sure to export a workflow.json file as API format from ComfyUI.": "Ziurtatu workflow.json fitxategia API formatu gisa esportatzen duzula ComfyUI-tik.",
 	"Make sure to export a workflow.json file as API format from ComfyUI.": "Ziurtatu workflow.json fitxategia API formatu gisa esportatzen duzula ComfyUI-tik.",
 	"Manage": "Kudeatu",
 	"Manage": "Kudeatu",
 	"Manage Arena Models": "Kudeatu Arena Modeloak",
 	"Manage Arena Models": "Kudeatu Arena Modeloak",
+	"Manage Direct Connections": "",
 	"Manage Models": "",
 	"Manage Models": "",
 	"Manage Ollama": "Kudeatu Ollama",
 	"Manage Ollama": "Kudeatu Ollama",
 	"Manage Ollama API Connections": "Kudeatu Ollama API Konexioak",
 	"Manage Ollama API Connections": "Kudeatu Ollama API Konexioak",
@@ -722,6 +745,7 @@
 	"Plain text (.txt)": "Testu laua (.txt)",
 	"Plain text (.txt)": "Testu laua (.txt)",
 	"Playground": "Jolaslekua",
 	"Playground": "Jolaslekua",
 	"Please carefully review the following warnings:": "Mesedez, berrikusi arretaz hurrengo oharrak:",
 	"Please carefully review the following warnings:": "Mesedez, berrikusi arretaz hurrengo oharrak:",
+	"Please do not close the settings page while loading the model.": "",
 	"Please enter a prompt": "Mesedez, sartu prompt bat",
 	"Please enter a prompt": "Mesedez, sartu prompt bat",
 	"Please fill in all fields.": "Mesedez, bete eremu guztiak.",
 	"Please fill in all fields.": "Mesedez, bete eremu guztiak.",
 	"Please select a model first.": "",
 	"Please select a model first.": "",
@@ -754,7 +778,7 @@
 	"Read Aloud": "Irakurri ozen",
 	"Read Aloud": "Irakurri ozen",
 	"Reasoning Effort": "",
 	"Reasoning Effort": "",
 	"Record voice": "Grabatu ahotsa",
 	"Record voice": "Grabatu ahotsa",
-	"Redirecting you to OpenWebUI Community": "OpenWebUI Komunitatera berbideratzen",
+	"Redirecting you to Open WebUI Community": "OpenWebUI Komunitatera berbideratzen",
 	"Reduces the probability of generating nonsense. A higher value (e.g. 100) will give more diverse answers, while a lower value (e.g. 10) will be more conservative. (Default: 40)": "Zentzugabekeriak sortzeko probabilitatea murrizten du. Balio altuago batek (adib. 100) erantzun anitzagoak emango ditu, balio baxuago batek (adib. 10) kontserbadoreagoa izango den bitartean. (Lehenetsia: 40)",
 	"Reduces the probability of generating nonsense. A higher value (e.g. 100) will give more diverse answers, while a lower value (e.g. 10) will be more conservative. (Default: 40)": "Zentzugabekeriak sortzeko probabilitatea murrizten du. Balio altuago batek (adib. 100) erantzun anitzagoak emango ditu, balio baxuago batek (adib. 10) kontserbadoreagoa izango den bitartean. (Lehenetsia: 40)",
 	"Refer to yourself as \"User\" (e.g., \"User is learning Spanish\")": "Egin erreferentzia zure buruari \"Erabiltzaile\" gisa (adib., \"Erabiltzailea gaztelania ikasten ari da\")",
 	"Refer to yourself as \"User\" (e.g., \"User is learning Spanish\")": "Egin erreferentzia zure buruari \"Erabiltzaile\" gisa (adib., \"Erabiltzailea gaztelania ikasten ari da\")",
 	"References from": "Erreferentziak hemendik",
 	"References from": "Erreferentziak hemendik",
@@ -829,6 +853,7 @@
 	"Select a pipeline": "Hautatu pipeline bat",
 	"Select a pipeline": "Hautatu pipeline bat",
 	"Select a pipeline url": "Hautatu pipeline url bat",
 	"Select a pipeline url": "Hautatu pipeline url bat",
 	"Select a tool": "Hautatu tresna bat",
 	"Select a tool": "Hautatu tresna bat",
+	"Select an auth method": "",
 	"Select an Ollama instance": "",
 	"Select an Ollama instance": "",
 	"Select Engine": "Hautatu motorra",
 	"Select Engine": "Hautatu motorra",
 	"Select Knowledge": "Hautatu ezagutza",
 	"Select Knowledge": "Hautatu ezagutza",
@@ -869,7 +894,7 @@
 	"Settings saved successfully!": "Ezarpenak ongi gorde dira!",
 	"Settings saved successfully!": "Ezarpenak ongi gorde dira!",
 	"Share": "Partekatu",
 	"Share": "Partekatu",
 	"Share Chat": "Partekatu txata",
 	"Share Chat": "Partekatu txata",
-	"Share to OpenWebUI Community": "Partekatu OpenWebUI komunitatearekin",
+	"Share to Open WebUI Community": "Partekatu OpenWebUI komunitatearekin",
 	"Show": "Erakutsi",
 	"Show": "Erakutsi",
 	"Show \"What's New\" modal on login": "Erakutsi \"Berritasunak\" modala saioa hastean",
 	"Show \"What's New\" modal on login": "Erakutsi \"Berritasunak\" modala saioa hastean",
 	"Show Admin Details in Account Pending Overlay": "Erakutsi administratzaile xehetasunak kontu zain geruzan",
 	"Show Admin Details in Account Pending Overlay": "Erakutsi administratzaile xehetasunak kontu zain geruzan",
@@ -944,6 +969,7 @@
 	"This will reset the knowledge base and sync all files. Do you wish to continue?": "Honek ezagutza-basea berrezarri eta fitxategi guztiak sinkronizatuko ditu. Jarraitu nahi duzu?",
 	"This will reset the knowledge base and sync all files. Do you wish to continue?": "Honek ezagutza-basea berrezarri eta fitxategi guztiak sinkronizatuko ditu. Jarraitu nahi duzu?",
 	"Thorough explanation": "Azalpen sakona",
 	"Thorough explanation": "Azalpen sakona",
 	"Thought for {{DURATION}}": "",
 	"Thought for {{DURATION}}": "",
+	"Thought for {{DURATION}} seconds": "",
 	"Tika": "Tika",
 	"Tika": "Tika",
 	"Tika Server URL required.": "Tika zerbitzariaren URLa beharrezkoa da.",
 	"Tika Server URL required.": "Tika zerbitzariaren URLa beharrezkoa da.",
 	"Tiktoken": "Tiktoken",
 	"Tiktoken": "Tiktoken",

+ 29 - 3
src/lib/i18n/locales/fa-IR/translation.json

@@ -122,6 +122,7 @@
 	"Beta": "",
 	"Beta": "",
 	"Bing Search V7 Endpoint": "",
 	"Bing Search V7 Endpoint": "",
 	"Bing Search V7 Subscription Key": "",
 	"Bing Search V7 Subscription Key": "",
+	"Bocha Search API Key": "",
 	"Brave Search API Key": "کلید API جستجوی شجاع",
 	"Brave Search API Key": "کلید API جستجوی شجاع",
 	"By {{name}}": "",
 	"By {{name}}": "",
 	"Bypass SSL verification for Websites": "عبور از تأیید SSL برای وب سایت ها",
 	"Bypass SSL verification for Websites": "عبور از تأیید SSL برای وب سایت ها",
@@ -163,6 +164,7 @@
 	"Click here to": "برای کمک اینجا را کلیک کنید.",
 	"Click here to": "برای کمک اینجا را کلیک کنید.",
 	"Click here to download user import template file.": "",
 	"Click here to download user import template file.": "",
 	"Click here to learn more about faster-whisper and see the available models.": "",
 	"Click here to learn more about faster-whisper and see the available models.": "",
+	"Click here to see available models.": "",
 	"Click here to select": "برای انتخاب اینجا کلیک کنید",
 	"Click here to select": "برای انتخاب اینجا کلیک کنید",
 	"Click here to select a csv file.": "برای انتخاب یک فایل csv اینجا را کلیک کنید.",
 	"Click here to select a csv file.": "برای انتخاب یک فایل csv اینجا را کلیک کنید.",
 	"Click here to select a py file.": "",
 	"Click here to select a py file.": "",
@@ -177,6 +179,8 @@
 	"Code execution": "",
 	"Code execution": "",
 	"Code formatted successfully": "",
 	"Code formatted successfully": "",
 	"Code Interpreter": "",
 	"Code Interpreter": "",
+	"Code Interpreter Engine": "",
+	"Code Interpreter Prompt Template": "",
 	"Collection": "مجموعه",
 	"Collection": "مجموعه",
 	"Color": "",
 	"Color": "",
 	"ComfyUI": "کومیوآی",
 	"ComfyUI": "کومیوآی",
@@ -193,6 +197,7 @@
 	"Confirm Password": "تایید رمز عبور",
 	"Confirm Password": "تایید رمز عبور",
 	"Confirm your action": "",
 	"Confirm your action": "",
 	"Confirm your new password": "",
 	"Confirm your new password": "",
+	"Connect to your own OpenAI compatible API endpoints.": "",
 	"Connections": "ارتباطات",
 	"Connections": "ارتباطات",
 	"Constrains effort on reasoning for reasoning models. Only applicable to reasoning models from specific providers that support reasoning effort. (Default: medium)": "",
 	"Constrains effort on reasoning for reasoning models. Only applicable to reasoning models from specific providers that support reasoning effort. (Default: medium)": "",
 	"Contact Admin for WebUI Access": "برای دسترسی به WebUI با مدیر تماس بگیرید",
 	"Contact Admin for WebUI Access": "برای دسترسی به WebUI با مدیر تماس بگیرید",
@@ -215,6 +220,7 @@
 	"Copy Link": "کپی لینک",
 	"Copy Link": "کپی لینک",
 	"Copy to clipboard": "",
 	"Copy to clipboard": "",
 	"Copying to clipboard was successful!": "کپی کردن در کلیپ بورد با موفقیت انجام شد!",
 	"Copying to clipboard was successful!": "کپی کردن در کلیپ بورد با موفقیت انجام شد!",
+	"CORS must be properly configured by the provider to allow requests from Open WebUI.": "",
 	"Create": "",
 	"Create": "",
 	"Create a knowledge base": "",
 	"Create a knowledge base": "",
 	"Create a model": "ایجاد یک مدل",
 	"Create a model": "ایجاد یک مدل",
@@ -268,6 +274,9 @@
 	"Describe your knowledge base and objectives": "",
 	"Describe your knowledge base and objectives": "",
 	"Description": "توضیحات",
 	"Description": "توضیحات",
 	"Didn't fully follow instructions": "نمی تواند دستورالعمل را کامل پیگیری کند",
 	"Didn't fully follow instructions": "نمی تواند دستورالعمل را کامل پیگیری کند",
+	"Direct Connections": "",
+	"Direct Connections allow users to connect to their own OpenAI compatible API endpoints.": "",
+	"Direct Connections settings updated": "",
 	"Disabled": "",
 	"Disabled": "",
 	"Discover a function": "",
 	"Discover a function": "",
 	"Discover a model": "کشف یک مدل",
 	"Discover a model": "کشف یک مدل",
@@ -290,6 +299,7 @@
 	"Documentation": "",
 	"Documentation": "",
 	"Documents": "اسناد",
 	"Documents": "اسناد",
 	"does not make any external connections, and your data stays securely on your locally hosted server.": "هیچ اتصال خارجی ایجاد نمی کند و داده های شما به طور ایمن در سرور میزبان محلی شما باقی می ماند.",
 	"does not make any external connections, and your data stays securely on your locally hosted server.": "هیچ اتصال خارجی ایجاد نمی کند و داده های شما به طور ایمن در سرور میزبان محلی شما باقی می ماند.",
+	"Domain Filter List": "",
 	"Don't have an account?": "حساب کاربری ندارید؟",
 	"Don't have an account?": "حساب کاربری ندارید؟",
 	"don't install random functions from sources you don't trust.": "",
 	"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 tools from sources you don't trust.": "",
@@ -325,6 +335,7 @@
 	"Embedding model set to \"{{embedding_model}}\"": "مدل پیدائش را به \"{{embedding_model}}\" تنظیم کنید",
 	"Embedding model set to \"{{embedding_model}}\"": "مدل پیدائش را به \"{{embedding_model}}\" تنظیم کنید",
 	"Enable API Key": "",
 	"Enable API Key": "",
 	"Enable autocomplete generation for chat messages": "",
 	"Enable autocomplete generation for chat messages": "",
+	"Enable Code Interpreter": "",
 	"Enable Community Sharing": "فعالسازی اشتراک انجمن",
 	"Enable Community Sharing": "فعالسازی اشتراک انجمن",
 	"Enable Google Drive": "",
 	"Enable Google Drive": "",
 	"Enable Memory Locking (mlock) to prevent model data from being swapped out of RAM. This option locks the model's working set of pages into RAM, ensuring that they will not be swapped out to disk. This can help maintain performance by avoiding page faults and ensuring fast data access.": "",
 	"Enable Memory Locking (mlock) to prevent model data from being swapped out of RAM. This option locks the model's working set of pages into RAM, ensuring that they will not be swapped out to disk. This can help maintain performance by avoiding page faults and ensuring fast data access.": "",
@@ -343,18 +354,23 @@
 	"Enter Application DN Password": "",
 	"Enter Application DN Password": "",
 	"Enter Bing Search V7 Endpoint": "",
 	"Enter Bing Search V7 Endpoint": "",
 	"Enter Bing Search V7 Subscription Key": "",
 	"Enter Bing Search V7 Subscription Key": "",
+	"Enter Bocha Search API Key": "",
 	"Enter Brave Search API Key": "کلید API جستجوی شجاع را وارد کنید",
 	"Enter Brave Search API Key": "کلید API جستجوی شجاع را وارد کنید",
 	"Enter certificate path": "",
 	"Enter certificate path": "",
 	"Enter CFG Scale (e.g. 7.0)": "",
 	"Enter CFG Scale (e.g. 7.0)": "",
 	"Enter Chunk Overlap": "مقدار Chunk Overlap را وارد کنید",
 	"Enter Chunk Overlap": "مقدار Chunk Overlap را وارد کنید",
 	"Enter Chunk Size": "مقدار Chunk Size را وارد کنید",
 	"Enter Chunk Size": "مقدار Chunk Size را وارد کنید",
 	"Enter description": "",
 	"Enter description": "",
+	"Enter domains separated by commas (e.g., example.com,site.org)": "",
 	"Enter Exa API Key": "",
 	"Enter Exa API Key": "",
 	"Enter Github Raw URL": "ادرس Github Raw را وارد کنید",
 	"Enter Github Raw URL": "ادرس Github Raw را وارد کنید",
 	"Enter Google PSE API Key": "کلید API گوگل PSE را وارد کنید",
 	"Enter Google PSE API Key": "کلید API گوگل PSE را وارد کنید",
 	"Enter Google PSE Engine Id": "شناسه موتور PSE گوگل را وارد کنید",
 	"Enter Google PSE Engine Id": "شناسه موتور PSE گوگل را وارد کنید",
 	"Enter Image Size (e.g. 512x512)": "اندازه تصویر را وارد کنید (مثال: 512x512)",
 	"Enter Image Size (e.g. 512x512)": "اندازه تصویر را وارد کنید (مثال: 512x512)",
 	"Enter Jina API Key": "",
 	"Enter Jina API Key": "",
+	"Enter Jupyter Password": "",
+	"Enter Jupyter Token": "",
+	"Enter Jupyter URL": "",
 	"Enter Kagi Search API Key": "",
 	"Enter Kagi Search API Key": "",
 	"Enter language codes": "کد زبان را وارد کنید",
 	"Enter language codes": "کد زبان را وارد کنید",
 	"Enter Model ID": "",
 	"Enter Model ID": "",
@@ -540,6 +556,8 @@
 	"JSON Preview": "پیش نمایش JSON",
 	"JSON Preview": "پیش نمایش JSON",
 	"July": "ژوئن",
 	"July": "ژوئن",
 	"June": "جولای",
 	"June": "جولای",
+	"Jupyter Auth": "",
+	"Jupyter URL": "",
 	"JWT Expiration": "JWT انقضای",
 	"JWT Expiration": "JWT انقضای",
 	"JWT Token": "JWT توکن",
 	"JWT Token": "JWT توکن",
 	"Kagi Search API Key": "",
 	"Kagi Search API Key": "",
@@ -552,6 +570,8 @@
 	"Knowledge deleted successfully.": "",
 	"Knowledge deleted successfully.": "",
 	"Knowledge reset successfully.": "",
 	"Knowledge reset successfully.": "",
 	"Knowledge updated successfully": "",
 	"Knowledge updated successfully": "",
+	"Kokoro.js (Browser)": "",
+	"Kokoro.js Dtype": "",
 	"Label": "",
 	"Label": "",
 	"Landing Page Mode": "",
 	"Landing Page Mode": "",
 	"Language": "زبان",
 	"Language": "زبان",
@@ -566,19 +586,22 @@
 	"Leave empty to include all models from \"{{URL}}/models\" endpoint": "",
 	"Leave empty to include all models from \"{{URL}}/models\" endpoint": "",
 	"Leave empty to include all models or select specific models": "",
 	"Leave empty to include all models or select specific models": "",
 	"Leave empty to use the default prompt, or enter a custom prompt": "",
 	"Leave empty to use the default prompt, or enter a custom prompt": "",
+	"Leave model field empty to use the default model.": "",
 	"Light": "روشن",
 	"Light": "روشن",
 	"Listening...": "",
 	"Listening...": "",
 	"Llama.cpp": "",
 	"Llama.cpp": "",
 	"LLMs can make mistakes. Verify important information.": "مدل\u200cهای زبانی بزرگ می\u200cتوانند اشتباه کنند. اطلاعات مهم را راستی\u200cآزمایی کنید.",
 	"LLMs can make mistakes. Verify important information.": "مدل\u200cهای زبانی بزرگ می\u200cتوانند اشتباه کنند. اطلاعات مهم را راستی\u200cآزمایی کنید.",
+	"Loading Kokoro.js...": "",
 	"Local": "",
 	"Local": "",
 	"Local Models": "",
 	"Local Models": "",
 	"Lost": "",
 	"Lost": "",
 	"LTR": "LTR",
 	"LTR": "LTR",
-	"Made by OpenWebUI Community": "ساخته شده توسط OpenWebUI Community",
+	"Made by Open WebUI Community": "ساخته شده توسط OpenWebUI Community",
 	"Make sure to enclose them with": "مطمئن شوید که آنها را با این محصور کنید:",
 	"Make sure to enclose them with": "مطمئن شوید که آنها را با این محصور کنید:",
 	"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.": "",
 	"Manage": "",
 	"Manage": "",
 	"Manage Arena Models": "",
 	"Manage Arena Models": "",
+	"Manage Direct Connections": "",
 	"Manage Models": "",
 	"Manage Models": "",
 	"Manage Ollama": "",
 	"Manage Ollama": "",
 	"Manage Ollama API Connections": "",
 	"Manage Ollama API Connections": "",
@@ -722,6 +745,7 @@
 	"Plain text (.txt)": "متن ساده (.txt)",
 	"Plain text (.txt)": "متن ساده (.txt)",
 	"Playground": "زمین بازی",
 	"Playground": "زمین بازی",
 	"Please carefully review the following warnings:": "",
 	"Please carefully review the following warnings:": "",
+	"Please do not close the settings page while loading the model.": "",
 	"Please enter a prompt": "",
 	"Please enter a prompt": "",
 	"Please fill in all fields.": "",
 	"Please fill in all fields.": "",
 	"Please select a model first.": "",
 	"Please select a model first.": "",
@@ -754,7 +778,7 @@
 	"Read Aloud": "خواندن به صورت صوتی",
 	"Read Aloud": "خواندن به صورت صوتی",
 	"Reasoning Effort": "",
 	"Reasoning Effort": "",
 	"Record voice": "ضبط صدا",
 	"Record voice": "ضبط صدا",
-	"Redirecting you to OpenWebUI Community": "در حال هدایت به OpenWebUI Community",
+	"Redirecting you to Open WebUI Community": "در حال هدایت به OpenWebUI Community",
 	"Reduces the probability of generating nonsense. A higher value (e.g. 100) will give more diverse answers, while a lower value (e.g. 10) will be more conservative. (Default: 40)": "",
 	"Reduces the probability of generating nonsense. A higher value (e.g. 100) will give more diverse answers, while a lower value (e.g. 10) will be more conservative. (Default: 40)": "",
 	"Refer to yourself as \"User\" (e.g., \"User is learning Spanish\")": "",
 	"Refer to yourself as \"User\" (e.g., \"User is learning Spanish\")": "",
 	"References from": "",
 	"References from": "",
@@ -829,6 +853,7 @@
 	"Select a pipeline": "انتخاب یک خط لوله",
 	"Select a pipeline": "انتخاب یک خط لوله",
 	"Select a pipeline url": "یک ادرس خط لوله را انتخاب کنید",
 	"Select a pipeline url": "یک ادرس خط لوله را انتخاب کنید",
 	"Select a tool": "انتخاب یک ابقزار",
 	"Select a tool": "انتخاب یک ابقزار",
+	"Select an auth method": "",
 	"Select an Ollama instance": "",
 	"Select an Ollama instance": "",
 	"Select Engine": "انتخاب موتور",
 	"Select Engine": "انتخاب موتور",
 	"Select Knowledge": "انتخاب دانش",
 	"Select Knowledge": "انتخاب دانش",
@@ -869,7 +894,7 @@
 	"Settings saved successfully!": "تنظیمات با موفقیت ذخیره شد!",
 	"Settings saved successfully!": "تنظیمات با موفقیت ذخیره شد!",
 	"Share": "اشتراک\u200cگذاری",
 	"Share": "اشتراک\u200cگذاری",
 	"Share Chat": "اشتراک\u200cگذاری چت",
 	"Share Chat": "اشتراک\u200cگذاری چت",
-	"Share to OpenWebUI Community": "اشتراک گذاری با OpenWebUI Community",
+	"Share to Open WebUI Community": "اشتراک گذاری با OpenWebUI Community",
 	"Show": "نمایش",
 	"Show": "نمایش",
 	"Show \"What's New\" modal on login": "",
 	"Show \"What's New\" modal on login": "",
 	"Show Admin Details in Account Pending Overlay": "",
 	"Show Admin Details in Account Pending Overlay": "",
@@ -944,6 +969,7 @@
 	"This will reset the knowledge base and sync all files. Do you wish to continue?": "",
 	"This will reset the knowledge base and sync all files. Do you wish to continue?": "",
 	"Thorough explanation": "توضیح کامل",
 	"Thorough explanation": "توضیح کامل",
 	"Thought for {{DURATION}}": "",
 	"Thought for {{DURATION}}": "",
+	"Thought for {{DURATION}} seconds": "",
 	"Tika": "",
 	"Tika": "",
 	"Tika Server URL required.": "",
 	"Tika Server URL required.": "",
 	"Tiktoken": "",
 	"Tiktoken": "",

+ 29 - 3
src/lib/i18n/locales/fi-FI/translation.json

@@ -122,6 +122,7 @@
 	"Beta": "",
 	"Beta": "",
 	"Bing Search V7 Endpoint": "Bing Search V7 -päätepisteen osoite",
 	"Bing Search V7 Endpoint": "Bing Search V7 -päätepisteen osoite",
 	"Bing Search V7 Subscription Key": "Bing Search V7 -tilauskäyttäjäavain",
 	"Bing Search V7 Subscription Key": "Bing Search V7 -tilauskäyttäjäavain",
+	"Bocha Search API Key": "",
 	"Brave Search API Key": "Brave Search API -avain",
 	"Brave Search API Key": "Brave Search API -avain",
 	"By {{name}}": "Tekijä {{name}}",
 	"By {{name}}": "Tekijä {{name}}",
 	"Bypass SSL verification for Websites": "Ohita SSL-varmennus verkkosivustoille",
 	"Bypass SSL verification for Websites": "Ohita SSL-varmennus verkkosivustoille",
@@ -163,6 +164,7 @@
 	"Click here to": "Klikkaa tästä",
 	"Click here to": "Klikkaa tästä",
 	"Click here to download user import template file.": "Lataa käyttäjien tuontipohjatiedosto klikkaamalla tästä.",
 	"Click here to download user import template file.": "Lataa käyttäjien tuontipohjatiedosto klikkaamalla tästä.",
 	"Click here to learn more about faster-whisper and see the available models.": "Klikkaa tästä oppiaksesi lisää faster-whisperista ja nähdäksesi saatavilla olevat mallit.",
 	"Click here to learn more about faster-whisper and see the available models.": "Klikkaa tästä oppiaksesi lisää faster-whisperista ja nähdäksesi saatavilla olevat mallit.",
+	"Click here to see available models.": "",
 	"Click here to select": "Klikkaa tästä valitaksesi",
 	"Click here to select": "Klikkaa tästä valitaksesi",
 	"Click here to select a csv file.": "Klikkaa tästä valitaksesi CSV-tiedosto.",
 	"Click here to select a csv file.": "Klikkaa tästä valitaksesi CSV-tiedosto.",
 	"Click here to select a py file.": "Klikkaa tästä valitaksesi py-tiedosto.",
 	"Click here to select a py file.": "Klikkaa tästä valitaksesi py-tiedosto.",
@@ -177,6 +179,8 @@
 	"Code execution": "Koodin suorittaminen",
 	"Code execution": "Koodin suorittaminen",
 	"Code formatted successfully": "Koodin muotoilu onnistui",
 	"Code formatted successfully": "Koodin muotoilu onnistui",
 	"Code Interpreter": "",
 	"Code Interpreter": "",
+	"Code Interpreter Engine": "",
+	"Code Interpreter Prompt Template": "",
 	"Collection": "Kokoelma",
 	"Collection": "Kokoelma",
 	"Color": "Väri",
 	"Color": "Väri",
 	"ComfyUI": "ComfyUI",
 	"ComfyUI": "ComfyUI",
@@ -193,6 +197,7 @@
 	"Confirm Password": "Vahvista salasana",
 	"Confirm Password": "Vahvista salasana",
 	"Confirm your action": "Vahvista toimintasi",
 	"Confirm your action": "Vahvista toimintasi",
 	"Confirm your new password": "",
 	"Confirm your new password": "",
+	"Connect to your own OpenAI compatible API endpoints.": "",
 	"Connections": "Yhteydet",
 	"Connections": "Yhteydet",
 	"Constrains effort on reasoning for reasoning models. Only applicable to reasoning models from specific providers that support reasoning effort. (Default: medium)": "",
 	"Constrains effort on reasoning for reasoning models. Only applicable to reasoning models from specific providers that support reasoning effort. (Default: medium)": "",
 	"Contact Admin for WebUI Access": "Ota yhteyttä ylläpitäjään WebUI-käyttöä varten",
 	"Contact Admin for WebUI Access": "Ota yhteyttä ylläpitäjään WebUI-käyttöä varten",
@@ -215,6 +220,7 @@
 	"Copy Link": "Kopioi linkki",
 	"Copy Link": "Kopioi linkki",
 	"Copy to clipboard": "Kopioi leikepöydälle",
 	"Copy to clipboard": "Kopioi leikepöydälle",
 	"Copying to clipboard was successful!": "Kopioiminen leikepöydälle onnistui!",
 	"Copying to clipboard was successful!": "Kopioiminen leikepöydälle onnistui!",
+	"CORS must be properly configured by the provider to allow requests from Open WebUI.": "",
 	"Create": "Luo",
 	"Create": "Luo",
 	"Create a knowledge base": "Luo tietokanta",
 	"Create a knowledge base": "Luo tietokanta",
 	"Create a model": "Luo malli",
 	"Create a model": "Luo malli",
@@ -268,6 +274,9 @@
 	"Describe your knowledge base and objectives": "Kuvaa tietokantasi ja tavoitteesi",
 	"Describe your knowledge base and objectives": "Kuvaa tietokantasi ja tavoitteesi",
 	"Description": "Kuvaus",
 	"Description": "Kuvaus",
 	"Didn't fully follow instructions": "Ei noudattanut ohjeita täysin",
 	"Didn't fully follow instructions": "Ei noudattanut ohjeita täysin",
+	"Direct Connections": "",
+	"Direct Connections allow users to connect to their own OpenAI compatible API endpoints.": "",
+	"Direct Connections settings updated": "",
 	"Disabled": "Ei käytössä",
 	"Disabled": "Ei käytössä",
 	"Discover a function": "Löydä toiminto",
 	"Discover a function": "Löydä toiminto",
 	"Discover a model": "Tutustu malliin",
 	"Discover a model": "Tutustu malliin",
@@ -290,6 +299,7 @@
 	"Documentation": "Dokumentaatio",
 	"Documentation": "Dokumentaatio",
 	"Documents": "Asiakirjat",
 	"Documents": "Asiakirjat",
 	"does not make any external connections, and your data stays securely on your locally hosted server.": "ei tee ulkoisia yhteyksiä, ja tietosi pysyvät turvallisesti paikallisesti isännöidyllä palvelimellasi.",
 	"does not make any external connections, and your data stays securely on your locally hosted server.": "ei tee ulkoisia yhteyksiä, ja tietosi pysyvät turvallisesti paikallisesti isännöidyllä palvelimellasi.",
+	"Domain Filter List": "",
 	"Don't have an account?": "Eikö sinulla ole tiliä?",
 	"Don't have an account?": "Eikö sinulla ole tiliä?",
 	"don't install random functions from sources you don't trust.": "älä asenna satunnaisia toimintoja lähteistä, joihin et luota.",
 	"don't install random functions from sources you don't trust.": "älä asenna satunnaisia toimintoja lähteistä, joihin et luota.",
 	"don't install random tools from sources you don't trust.": "älä asenna satunnaisia työkaluja lähteistä, joihin et luota.",
 	"don't install random tools from sources you don't trust.": "älä asenna satunnaisia työkaluja lähteistä, joihin et luota.",
@@ -325,6 +335,7 @@
 	"Embedding model set to \"{{embedding_model}}\"": "\"{{embedding_model}}\" valittu upotusmalliksi",
 	"Embedding model set to \"{{embedding_model}}\"": "\"{{embedding_model}}\" valittu upotusmalliksi",
 	"Enable API Key": "",
 	"Enable API Key": "",
 	"Enable autocomplete generation for chat messages": "Ota automaattinen täydennys käyttöön keskusteluviesteissä",
 	"Enable autocomplete generation for chat messages": "Ota automaattinen täydennys käyttöön keskusteluviesteissä",
+	"Enable Code Interpreter": "",
 	"Enable Community Sharing": "Ota yhteisön jakaminen käyttöön",
 	"Enable Community Sharing": "Ota yhteisön jakaminen käyttöön",
 	"Enable Google Drive": "",
 	"Enable Google Drive": "",
 	"Enable Memory Locking (mlock) to prevent model data from being swapped out of RAM. This option locks the model's working set of pages into RAM, ensuring that they will not be swapped out to disk. This can help maintain performance by avoiding page faults and ensuring fast data access.": "Ota Memory Locking (mlock) käyttöön estääksesi mallidatan vaihtamisen pois RAM-muistista. Tämä lukitsee mallin työsivut RAM-muistiin, varmistaen että niitä ei vaihdeta levylle. Tämä voi parantaa suorituskykyä välttämällä sivuvikoja ja varmistamalla nopean tietojen käytön.",
 	"Enable Memory Locking (mlock) to prevent model data from being swapped out of RAM. This option locks the model's working set of pages into RAM, ensuring that they will not be swapped out to disk. This can help maintain performance by avoiding page faults and ensuring fast data access.": "Ota Memory Locking (mlock) käyttöön estääksesi mallidatan vaihtamisen pois RAM-muistista. Tämä lukitsee mallin työsivut RAM-muistiin, varmistaen että niitä ei vaihdeta levylle. Tämä voi parantaa suorituskykyä välttämällä sivuvikoja ja varmistamalla nopean tietojen käytön.",
@@ -343,18 +354,23 @@
 	"Enter Application DN Password": "Kirjoita sovelluksen DN-salasana",
 	"Enter Application DN Password": "Kirjoita sovelluksen DN-salasana",
 	"Enter Bing Search V7 Endpoint": "Kirjoita Bing Search V7 -päätepisteen osoite",
 	"Enter Bing Search V7 Endpoint": "Kirjoita Bing Search V7 -päätepisteen osoite",
 	"Enter Bing Search V7 Subscription Key": "Kirjoita Bing Search V7 -tilauskäyttäjäavain",
 	"Enter Bing Search V7 Subscription Key": "Kirjoita Bing Search V7 -tilauskäyttäjäavain",
+	"Enter Bocha Search API Key": "",
 	"Enter Brave Search API Key": "Kirjoita Brave Search API -avain",
 	"Enter Brave Search API Key": "Kirjoita Brave Search API -avain",
 	"Enter certificate path": "Kirjoita varmennepolku",
 	"Enter certificate path": "Kirjoita varmennepolku",
 	"Enter CFG Scale (e.g. 7.0)": "Kirjoita CFG-mitta (esim. 7.0)",
 	"Enter CFG Scale (e.g. 7.0)": "Kirjoita CFG-mitta (esim. 7.0)",
 	"Enter Chunk Overlap": "Syötä osien päällekkäisyys",
 	"Enter Chunk Overlap": "Syötä osien päällekkäisyys",
 	"Enter Chunk Size": "Syötä osien koko",
 	"Enter Chunk Size": "Syötä osien koko",
 	"Enter description": "Kirjoita kuvaus",
 	"Enter description": "Kirjoita kuvaus",
+	"Enter domains separated by commas (e.g., example.com,site.org)": "",
 	"Enter Exa API Key": "",
 	"Enter Exa API Key": "",
 	"Enter Github Raw URL": "Kirjoita Github Raw -URL-osoite",
 	"Enter Github Raw URL": "Kirjoita Github Raw -URL-osoite",
 	"Enter Google PSE API Key": "Kirjoita Google PSE API -avain",
 	"Enter Google PSE API Key": "Kirjoita Google PSE API -avain",
 	"Enter Google PSE Engine Id": "Kirjoita Google PSE -moottorin tunnus",
 	"Enter Google PSE Engine Id": "Kirjoita Google PSE -moottorin tunnus",
 	"Enter Image Size (e.g. 512x512)": "Kirjoita kuvan koko (esim. 512x512)",
 	"Enter Image Size (e.g. 512x512)": "Kirjoita kuvan koko (esim. 512x512)",
 	"Enter Jina API Key": "Kirjoita Jina API -avain",
 	"Enter Jina API Key": "Kirjoita Jina API -avain",
+	"Enter Jupyter Password": "",
+	"Enter Jupyter Token": "",
+	"Enter Jupyter URL": "",
 	"Enter Kagi Search API Key": "",
 	"Enter Kagi Search API Key": "",
 	"Enter language codes": "Kirjoita kielikoodit",
 	"Enter language codes": "Kirjoita kielikoodit",
 	"Enter Model ID": "Kirjoita mallitunnus",
 	"Enter Model ID": "Kirjoita mallitunnus",
@@ -540,6 +556,8 @@
 	"JSON Preview": "JSON-esikatselu",
 	"JSON Preview": "JSON-esikatselu",
 	"July": "heinäkuu",
 	"July": "heinäkuu",
 	"June": "kesäkuu",
 	"June": "kesäkuu",
+	"Jupyter Auth": "",
+	"Jupyter URL": "",
 	"JWT Expiration": "JWT-vanheneminen",
 	"JWT Expiration": "JWT-vanheneminen",
 	"JWT Token": "JWT-token",
 	"JWT Token": "JWT-token",
 	"Kagi Search API Key": "",
 	"Kagi Search API Key": "",
@@ -552,6 +570,8 @@
 	"Knowledge deleted successfully.": "Tietokanta poistettu onnistuneesti.",
 	"Knowledge deleted successfully.": "Tietokanta poistettu onnistuneesti.",
 	"Knowledge reset successfully.": "Tietokanta nollattu onnistuneesti.",
 	"Knowledge reset successfully.": "Tietokanta nollattu onnistuneesti.",
 	"Knowledge updated successfully": "Tietokanta päivitetty onnistuneesti",
 	"Knowledge updated successfully": "Tietokanta päivitetty onnistuneesti",
+	"Kokoro.js (Browser)": "",
+	"Kokoro.js Dtype": "",
 	"Label": "Tunniste",
 	"Label": "Tunniste",
 	"Landing Page Mode": "Etusivun tila",
 	"Landing Page Mode": "Etusivun tila",
 	"Language": "Kieli",
 	"Language": "Kieli",
@@ -566,19 +586,22 @@
 	"Leave empty to include all models from \"{{URL}}/models\" endpoint": "Jätä tyhjäksi, jos haluat sisällyttää kaikki mallit \"{{URL}}/models\" -päätepistestä",
 	"Leave empty to include all models from \"{{URL}}/models\" endpoint": "Jätä tyhjäksi, jos haluat sisällyttää kaikki mallit \"{{URL}}/models\" -päätepistestä",
 	"Leave empty to include all models or select specific models": "Jätä tyhjäksi, jos haluat sisällyttää kaikki mallit tai valitse tietyt mallit",
 	"Leave empty to include all models or select specific models": "Jätä tyhjäksi, jos haluat sisällyttää kaikki mallit tai valitse tietyt mallit",
 	"Leave empty to use the default prompt, or enter a custom prompt": "Jätä tyhjäksi käyttääksesi oletuskehotetta tai kirjoita mukautettu kehote",
 	"Leave empty to use the default prompt, or enter a custom prompt": "Jätä tyhjäksi käyttääksesi oletuskehotetta tai kirjoita mukautettu kehote",
+	"Leave model field empty to use the default model.": "",
 	"Light": "Vaalea",
 	"Light": "Vaalea",
 	"Listening...": "Kuuntelee...",
 	"Listening...": "Kuuntelee...",
 	"Llama.cpp": "",
 	"Llama.cpp": "",
 	"LLMs can make mistakes. Verify important information.": "Kielimallit voivat tehdä virheitä. Tarkista tärkeät tiedot.",
 	"LLMs can make mistakes. Verify important information.": "Kielimallit voivat tehdä virheitä. Tarkista tärkeät tiedot.",
+	"Loading Kokoro.js...": "",
 	"Local": "Paikallinen",
 	"Local": "Paikallinen",
 	"Local Models": "Paikalliset mallit",
 	"Local Models": "Paikalliset mallit",
 	"Lost": "Mennyt",
 	"Lost": "Mennyt",
 	"LTR": "LTR",
 	"LTR": "LTR",
-	"Made by OpenWebUI Community": "Tehnyt OpenWebUI-yhteisö",
+	"Made by Open WebUI Community": "Tehnyt OpenWebUI-yhteisö",
 	"Make sure to enclose them with": "Varmista, että suljet ne",
 	"Make sure to enclose them with": "Varmista, että suljet ne",
 	"Make sure to export a workflow.json file as API format from ComfyUI.": "Muista viedä workflow.json-tiedosto API-muodossa ComfyUI:sta.",
 	"Make sure to export a workflow.json file as API format from ComfyUI.": "Muista viedä workflow.json-tiedosto API-muodossa ComfyUI:sta.",
 	"Manage": "Hallitse",
 	"Manage": "Hallitse",
 	"Manage Arena Models": "Hallitse Arena-malleja",
 	"Manage Arena Models": "Hallitse Arena-malleja",
+	"Manage Direct Connections": "",
 	"Manage Models": "",
 	"Manage Models": "",
 	"Manage Ollama": "Hallitse Ollamaa",
 	"Manage Ollama": "Hallitse Ollamaa",
 	"Manage Ollama API Connections": "Hallitse Ollama API -yhteyksiä",
 	"Manage Ollama API Connections": "Hallitse Ollama API -yhteyksiä",
@@ -722,6 +745,7 @@
 	"Plain text (.txt)": "Pelkkä teksti (.txt)",
 	"Plain text (.txt)": "Pelkkä teksti (.txt)",
 	"Playground": "Leikkipaikka",
 	"Playground": "Leikkipaikka",
 	"Please carefully review the following warnings:": "Tarkista huolellisesti seuraavat varoitukset:",
 	"Please carefully review the following warnings:": "Tarkista huolellisesti seuraavat varoitukset:",
+	"Please do not close the settings page while loading the model.": "",
 	"Please enter a prompt": "Kirjoita kehote",
 	"Please enter a prompt": "Kirjoita kehote",
 	"Please fill in all fields.": "Täytä kaikki kentät.",
 	"Please fill in all fields.": "Täytä kaikki kentät.",
 	"Please select a model first.": "Valitse ensin malli.",
 	"Please select a model first.": "Valitse ensin malli.",
@@ -754,7 +778,7 @@
 	"Read Aloud": "Lue ääneen",
 	"Read Aloud": "Lue ääneen",
 	"Reasoning Effort": "",
 	"Reasoning Effort": "",
 	"Record voice": "Nauhoita ääni",
 	"Record voice": "Nauhoita ääni",
-	"Redirecting you to OpenWebUI Community": "Ohjataan sinut OpenWebUI-yhteisöön",
+	"Redirecting you to Open WebUI Community": "Ohjataan sinut OpenWebUI-yhteisöön",
 	"Reduces the probability of generating nonsense. A higher value (e.g. 100) will give more diverse answers, while a lower value (e.g. 10) will be more conservative. (Default: 40)": "Vähentää merkityksetöntä sisältöä tuottavan todennäköisyyttä. Korkeampi arvo (esim. 100) antaa monipuolisempia vastauksia, kun taas alhaisempi arvo (esim. 10) on konservatiivisempi. (Oletus: 40)",
 	"Reduces the probability of generating nonsense. A higher value (e.g. 100) will give more diverse answers, while a lower value (e.g. 10) will be more conservative. (Default: 40)": "Vähentää merkityksetöntä sisältöä tuottavan todennäköisyyttä. Korkeampi arvo (esim. 100) antaa monipuolisempia vastauksia, kun taas alhaisempi arvo (esim. 10) on konservatiivisempi. (Oletus: 40)",
 	"Refer to yourself as \"User\" (e.g., \"User is learning Spanish\")": "Viittaa itseen \"Käyttäjänä\" (esim. \"Käyttäjä opiskelee espanjaa\")",
 	"Refer to yourself as \"User\" (e.g., \"User is learning Spanish\")": "Viittaa itseen \"Käyttäjänä\" (esim. \"Käyttäjä opiskelee espanjaa\")",
 	"References from": "Viitteet lähteistä",
 	"References from": "Viitteet lähteistä",
@@ -829,6 +853,7 @@
 	"Select a pipeline": "Valitse putki",
 	"Select a pipeline": "Valitse putki",
 	"Select a pipeline url": "Valitse putken URL-osoite",
 	"Select a pipeline url": "Valitse putken URL-osoite",
 	"Select a tool": "Valitse työkalu",
 	"Select a tool": "Valitse työkalu",
+	"Select an auth method": "",
 	"Select an Ollama instance": "",
 	"Select an Ollama instance": "",
 	"Select Engine": "Valitse moottori",
 	"Select Engine": "Valitse moottori",
 	"Select Knowledge": "Valitse tietämys",
 	"Select Knowledge": "Valitse tietämys",
@@ -869,7 +894,7 @@
 	"Settings saved successfully!": "Asetukset tallennettu onnistuneesti!",
 	"Settings saved successfully!": "Asetukset tallennettu onnistuneesti!",
 	"Share": "Jaa",
 	"Share": "Jaa",
 	"Share Chat": "Jaa keskustelu",
 	"Share Chat": "Jaa keskustelu",
-	"Share to OpenWebUI Community": "Jaa OpenWebUI-yhteisöön",
+	"Share to Open WebUI Community": "Jaa OpenWebUI-yhteisöön",
 	"Show": "Näytä",
 	"Show": "Näytä",
 	"Show \"What's New\" modal on login": "Näytä \"Mitä uutta\" -modaali kirjautumisen yhteydessä",
 	"Show \"What's New\" modal on login": "Näytä \"Mitä uutta\" -modaali kirjautumisen yhteydessä",
 	"Show Admin Details in Account Pending Overlay": "Näytä ylläpitäjän tiedot odottavan tilin päällä",
 	"Show Admin Details in Account Pending Overlay": "Näytä ylläpitäjän tiedot odottavan tilin päällä",
@@ -944,6 +969,7 @@
 	"This will reset the knowledge base and sync all files. Do you wish to continue?": "Tämä nollaa tietokannan ja synkronoi kaikki tiedostot. Haluatko jatkaa?",
 	"This will reset the knowledge base and sync all files. Do you wish to continue?": "Tämä nollaa tietokannan ja synkronoi kaikki tiedostot. Haluatko jatkaa?",
 	"Thorough explanation": "Perusteellinen selitys",
 	"Thorough explanation": "Perusteellinen selitys",
 	"Thought for {{DURATION}}": "",
 	"Thought for {{DURATION}}": "",
+	"Thought for {{DURATION}} seconds": "",
 	"Tika": "Tika",
 	"Tika": "Tika",
 	"Tika Server URL required.": "Tika Server URL vaaditaan.",
 	"Tika Server URL required.": "Tika Server URL vaaditaan.",
 	"Tiktoken": "Tiktoken",
 	"Tiktoken": "Tiktoken",

+ 29 - 3
src/lib/i18n/locales/fr-CA/translation.json

@@ -122,6 +122,7 @@
 	"Beta": "",
 	"Beta": "",
 	"Bing Search V7 Endpoint": "",
 	"Bing Search V7 Endpoint": "",
 	"Bing Search V7 Subscription Key": "",
 	"Bing Search V7 Subscription Key": "",
+	"Bocha Search API Key": "",
 	"Brave Search API Key": "Clé API Brave Search",
 	"Brave Search API Key": "Clé API Brave Search",
 	"By {{name}}": "",
 	"By {{name}}": "",
 	"Bypass SSL verification for Websites": "Bypasser la vérification SSL pour les sites web",
 	"Bypass SSL verification for Websites": "Bypasser la vérification SSL pour les sites web",
@@ -163,6 +164,7 @@
 	"Click here to": "Cliquez ici pour",
 	"Click here to": "Cliquez ici pour",
 	"Click here to download user import template file.": "Cliquez ici pour télécharger le fichier modèle d'importation utilisateur.",
 	"Click here to download user import template file.": "Cliquez ici pour télécharger le fichier modèle d'importation utilisateur.",
 	"Click here to learn more about faster-whisper and see the available models.": "",
 	"Click here to learn more about faster-whisper and see the available models.": "",
+	"Click here to see available models.": "",
 	"Click here to select": "Cliquez ici pour sélectionner",
 	"Click here to select": "Cliquez ici pour sélectionner",
 	"Click here to select a csv file.": "Cliquez ici pour sélectionner un fichier CSV.",
 	"Click here to select a csv file.": "Cliquez ici pour sélectionner un fichier CSV.",
 	"Click here to select a py file.": "Cliquez ici pour sélectionner un fichier .py.",
 	"Click here to select a py file.": "Cliquez ici pour sélectionner un fichier .py.",
@@ -177,6 +179,8 @@
 	"Code execution": "",
 	"Code execution": "",
 	"Code formatted successfully": "Le code a été formaté avec succès",
 	"Code formatted successfully": "Le code a été formaté avec succès",
 	"Code Interpreter": "",
 	"Code Interpreter": "",
+	"Code Interpreter Engine": "",
+	"Code Interpreter Prompt Template": "",
 	"Collection": "Collection",
 	"Collection": "Collection",
 	"Color": "",
 	"Color": "",
 	"ComfyUI": "ComfyUI",
 	"ComfyUI": "ComfyUI",
@@ -193,6 +197,7 @@
 	"Confirm Password": "Confirmer le mot de passe",
 	"Confirm Password": "Confirmer le mot de passe",
 	"Confirm your action": "Confirmez votre action",
 	"Confirm your action": "Confirmez votre action",
 	"Confirm your new password": "",
 	"Confirm your new password": "",
+	"Connect to your own OpenAI compatible API endpoints.": "",
 	"Connections": "Connexions",
 	"Connections": "Connexions",
 	"Constrains effort on reasoning for reasoning models. Only applicable to reasoning models from specific providers that support reasoning effort. (Default: medium)": "",
 	"Constrains effort on reasoning for reasoning models. Only applicable to reasoning models from specific providers that support reasoning effort. (Default: medium)": "",
 	"Contact Admin for WebUI Access": "Contacter l'administrateur pour l'accès à l'interface Web",
 	"Contact Admin for WebUI Access": "Contacter l'administrateur pour l'accès à l'interface Web",
@@ -215,6 +220,7 @@
 	"Copy Link": "Copier le lien",
 	"Copy Link": "Copier le lien",
 	"Copy to clipboard": "",
 	"Copy to clipboard": "",
 	"Copying to clipboard was successful!": "La copie dans le presse-papiers a réussi !",
 	"Copying to clipboard was successful!": "La copie dans le presse-papiers a réussi !",
+	"CORS must be properly configured by the provider to allow requests from Open WebUI.": "",
 	"Create": "",
 	"Create": "",
 	"Create a knowledge base": "",
 	"Create a knowledge base": "",
 	"Create a model": "Créer un modèle",
 	"Create a model": "Créer un modèle",
@@ -268,6 +274,9 @@
 	"Describe your knowledge base and objectives": "",
 	"Describe your knowledge base and objectives": "",
 	"Description": "Description",
 	"Description": "Description",
 	"Didn't fully follow instructions": "N'a pas entièrement respecté les instructions",
 	"Didn't fully follow instructions": "N'a pas entièrement respecté les instructions",
+	"Direct Connections": "",
+	"Direct Connections allow users to connect to their own OpenAI compatible API endpoints.": "",
+	"Direct Connections settings updated": "",
 	"Disabled": "",
 	"Disabled": "",
 	"Discover a function": "Découvrez une fonction",
 	"Discover a function": "Découvrez une fonction",
 	"Discover a model": "Découvrir un modèle",
 	"Discover a model": "Découvrir un modèle",
@@ -290,6 +299,7 @@
 	"Documentation": "Documentation",
 	"Documentation": "Documentation",
 	"Documents": "Documents",
 	"Documents": "Documents",
 	"does not make any external connections, and your data stays securely on your locally hosted server.": "ne fait aucune connexion externe et garde vos données en sécurité sur votre serveur local.",
 	"does not make any external connections, and your data stays securely on your locally hosted server.": "ne fait aucune connexion externe et garde vos données en sécurité sur votre serveur local.",
+	"Domain Filter List": "",
 	"Don't have an account?": "Vous n'avez pas de compte ?",
 	"Don't have an account?": "Vous n'avez pas de compte ?",
 	"don't install random functions from sources you don't trust.": "",
 	"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 tools from sources you don't trust.": "",
@@ -325,6 +335,7 @@
 	"Embedding model set to \"{{embedding_model}}\"": "Modèle d'encodage défini sur « {{embedding_model}} »",
 	"Embedding model set to \"{{embedding_model}}\"": "Modèle d'encodage défini sur « {{embedding_model}} »",
 	"Enable API Key": "",
 	"Enable API Key": "",
 	"Enable autocomplete generation for chat messages": "",
 	"Enable autocomplete generation for chat messages": "",
+	"Enable Code Interpreter": "",
 	"Enable Community Sharing": "Activer le partage communautaire",
 	"Enable Community Sharing": "Activer le partage communautaire",
 	"Enable Google Drive": "",
 	"Enable Google Drive": "",
 	"Enable Memory Locking (mlock) to prevent model data from being swapped out of RAM. This option locks the model's working set of pages into RAM, ensuring that they will not be swapped out to disk. This can help maintain performance by avoiding page faults and ensuring fast data access.": "",
 	"Enable Memory Locking (mlock) to prevent model data from being swapped out of RAM. This option locks the model's working set of pages into RAM, ensuring that they will not be swapped out to disk. This can help maintain performance by avoiding page faults and ensuring fast data access.": "",
@@ -343,18 +354,23 @@
 	"Enter Application DN Password": "",
 	"Enter Application DN Password": "",
 	"Enter Bing Search V7 Endpoint": "",
 	"Enter Bing Search V7 Endpoint": "",
 	"Enter Bing Search V7 Subscription Key": "",
 	"Enter Bing Search V7 Subscription Key": "",
+	"Enter Bocha Search API Key": "",
 	"Enter Brave Search API Key": "Entrez la clé API Brave Search",
 	"Enter Brave Search API Key": "Entrez la clé API Brave Search",
 	"Enter certificate path": "",
 	"Enter certificate path": "",
 	"Enter CFG Scale (e.g. 7.0)": "",
 	"Enter CFG Scale (e.g. 7.0)": "",
 	"Enter Chunk Overlap": "Entrez le chevauchement de chunk",
 	"Enter Chunk Overlap": "Entrez le chevauchement de chunk",
 	"Enter Chunk Size": "Entrez la taille de bloc",
 	"Enter Chunk Size": "Entrez la taille de bloc",
 	"Enter description": "",
 	"Enter description": "",
+	"Enter domains separated by commas (e.g., example.com,site.org)": "",
 	"Enter Exa API Key": "",
 	"Enter Exa API Key": "",
 	"Enter Github Raw URL": "Entrez l'URL brute de GitHub",
 	"Enter Github Raw URL": "Entrez l'URL brute de GitHub",
 	"Enter Google PSE API Key": "Entrez la clé API Google PSE",
 	"Enter Google PSE API Key": "Entrez la clé API Google PSE",
 	"Enter Google PSE Engine Id": "Entrez l'identifiant du moteur Google PSE",
 	"Enter Google PSE Engine Id": "Entrez l'identifiant du moteur Google PSE",
 	"Enter Image Size (e.g. 512x512)": "Entrez la taille de l'image (par ex. 512x512)",
 	"Enter Image Size (e.g. 512x512)": "Entrez la taille de l'image (par ex. 512x512)",
 	"Enter Jina API Key": "",
 	"Enter Jina API Key": "",
+	"Enter Jupyter Password": "",
+	"Enter Jupyter Token": "",
+	"Enter Jupyter URL": "",
 	"Enter Kagi Search API Key": "",
 	"Enter Kagi Search API Key": "",
 	"Enter language codes": "Entrez les codes de langue",
 	"Enter language codes": "Entrez les codes de langue",
 	"Enter Model ID": "",
 	"Enter Model ID": "",
@@ -540,6 +556,8 @@
 	"JSON Preview": "Aperçu JSON",
 	"JSON Preview": "Aperçu JSON",
 	"July": "Juillet",
 	"July": "Juillet",
 	"June": "Juin",
 	"June": "Juin",
+	"Jupyter Auth": "",
+	"Jupyter URL": "",
 	"JWT Expiration": "Expiration du jeton JWT",
 	"JWT Expiration": "Expiration du jeton JWT",
 	"JWT Token": "Jeton JWT",
 	"JWT Token": "Jeton JWT",
 	"Kagi Search API Key": "",
 	"Kagi Search API Key": "",
@@ -552,6 +570,8 @@
 	"Knowledge deleted successfully.": "",
 	"Knowledge deleted successfully.": "",
 	"Knowledge reset successfully.": "",
 	"Knowledge reset successfully.": "",
 	"Knowledge updated successfully": "",
 	"Knowledge updated successfully": "",
+	"Kokoro.js (Browser)": "",
+	"Kokoro.js Dtype": "",
 	"Label": "",
 	"Label": "",
 	"Landing Page Mode": "",
 	"Landing Page Mode": "",
 	"Language": "Langue",
 	"Language": "Langue",
@@ -566,19 +586,22 @@
 	"Leave empty to include all models from \"{{URL}}/models\" endpoint": "",
 	"Leave empty to include all models from \"{{URL}}/models\" endpoint": "",
 	"Leave empty to include all models or select specific models": "",
 	"Leave empty to include all models or select specific models": "",
 	"Leave empty to use the default prompt, or enter a custom prompt": "",
 	"Leave empty to use the default prompt, or enter a custom prompt": "",
+	"Leave model field empty to use the default model.": "",
 	"Light": "Lumineux",
 	"Light": "Lumineux",
 	"Listening...": "En train d'écouter...",
 	"Listening...": "En train d'écouter...",
 	"Llama.cpp": "",
 	"Llama.cpp": "",
 	"LLMs can make mistakes. Verify important information.": "Les LLM peuvent faire des erreurs. Vérifiez les informations importantes.",
 	"LLMs can make mistakes. Verify important information.": "Les LLM peuvent faire des erreurs. Vérifiez les informations importantes.",
+	"Loading Kokoro.js...": "",
 	"Local": "",
 	"Local": "",
 	"Local Models": "Modèles locaux",
 	"Local Models": "Modèles locaux",
 	"Lost": "",
 	"Lost": "",
 	"LTR": "LTR",
 	"LTR": "LTR",
-	"Made by OpenWebUI Community": "Réalisé par la communauté OpenWebUI",
+	"Made by Open WebUI Community": "Réalisé par la communauté OpenWebUI",
 	"Make sure to enclose them with": "Assurez-vous de les inclure dans",
 	"Make sure to enclose them with": "Assurez-vous de les inclure dans",
 	"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.": "",
 	"Manage": "Gérer",
 	"Manage": "Gérer",
 	"Manage Arena Models": "",
 	"Manage Arena Models": "",
+	"Manage Direct Connections": "",
 	"Manage Models": "",
 	"Manage Models": "",
 	"Manage Ollama": "",
 	"Manage Ollama": "",
 	"Manage Ollama API Connections": "",
 	"Manage Ollama API Connections": "",
@@ -722,6 +745,7 @@
 	"Plain text (.txt)": "Texte simple (.txt)",
 	"Plain text (.txt)": "Texte simple (.txt)",
 	"Playground": "Aire de jeux",
 	"Playground": "Aire de jeux",
 	"Please carefully review the following warnings:": "",
 	"Please carefully review the following warnings:": "",
+	"Please do not close the settings page while loading the model.": "",
 	"Please enter a prompt": "",
 	"Please enter a prompt": "",
 	"Please fill in all fields.": "",
 	"Please fill in all fields.": "",
 	"Please select a model first.": "",
 	"Please select a model first.": "",
@@ -754,7 +778,7 @@
 	"Read Aloud": "Lire à haute voix",
 	"Read Aloud": "Lire à haute voix",
 	"Reasoning Effort": "",
 	"Reasoning Effort": "",
 	"Record voice": "Enregistrer la voix",
 	"Record voice": "Enregistrer la voix",
-	"Redirecting you to OpenWebUI Community": "Redirection vers la communauté OpenWebUI",
+	"Redirecting you to Open WebUI Community": "Redirection vers la communauté OpenWebUI",
 	"Reduces the probability of generating nonsense. A higher value (e.g. 100) will give more diverse answers, while a lower value (e.g. 10) will be more conservative. (Default: 40)": "",
 	"Reduces the probability of generating nonsense. A higher value (e.g. 100) will give more diverse answers, while a lower value (e.g. 10) will be more conservative. (Default: 40)": "",
 	"Refer to yourself as \"User\" (e.g., \"User is learning Spanish\")": "Désignez-vous comme « Utilisateur » (par ex. « L'utilisateur apprend l'espagnol »)",
 	"Refer to yourself as \"User\" (e.g., \"User is learning Spanish\")": "Désignez-vous comme « Utilisateur » (par ex. « L'utilisateur apprend l'espagnol »)",
 	"References from": "",
 	"References from": "",
@@ -829,6 +853,7 @@
 	"Select a pipeline": "Sélectionnez un pipeline",
 	"Select a pipeline": "Sélectionnez un pipeline",
 	"Select a pipeline url": "Sélectionnez l'URL du pipeline",
 	"Select a pipeline url": "Sélectionnez l'URL du pipeline",
 	"Select a tool": "Sélectionnez un outil",
 	"Select a tool": "Sélectionnez un outil",
+	"Select an auth method": "",
 	"Select an Ollama instance": "",
 	"Select an Ollama instance": "",
 	"Select Engine": "",
 	"Select Engine": "",
 	"Select Knowledge": "",
 	"Select Knowledge": "",
@@ -869,7 +894,7 @@
 	"Settings saved successfully!": "Paramètres enregistrés avec succès !",
 	"Settings saved successfully!": "Paramètres enregistrés avec succès !",
 	"Share": "Partager",
 	"Share": "Partager",
 	"Share Chat": "Partage de conversation",
 	"Share Chat": "Partage de conversation",
-	"Share to OpenWebUI Community": "Partager avec la communauté OpenWebUI",
+	"Share to Open WebUI Community": "Partager avec la communauté OpenWebUI",
 	"Show": "Montrer",
 	"Show": "Montrer",
 	"Show \"What's New\" modal on login": "",
 	"Show \"What's New\" modal on login": "",
 	"Show Admin Details in Account Pending Overlay": "Afficher les détails de l'administrateur dans la superposition en attente du compte",
 	"Show Admin Details in Account Pending Overlay": "Afficher les détails de l'administrateur dans la superposition en attente du compte",
@@ -944,6 +969,7 @@
 	"This will reset the knowledge base and sync all files. Do you wish to continue?": "",
 	"This will reset the knowledge base and sync all files. Do you wish to continue?": "",
 	"Thorough explanation": "Explication approfondie",
 	"Thorough explanation": "Explication approfondie",
 	"Thought for {{DURATION}}": "",
 	"Thought for {{DURATION}}": "",
+	"Thought for {{DURATION}} seconds": "",
 	"Tika": "Tika",
 	"Tika": "Tika",
 	"Tika Server URL required.": "URL du serveur Tika requise.",
 	"Tika Server URL required.": "URL du serveur Tika requise.",
 	"Tiktoken": "",
 	"Tiktoken": "",

+ 29 - 3
src/lib/i18n/locales/fr-FR/translation.json

@@ -122,6 +122,7 @@
 	"Beta": "Bêta",
 	"Beta": "Bêta",
 	"Bing Search V7 Endpoint": "Point de terminaison Bing Search V7",
 	"Bing Search V7 Endpoint": "Point de terminaison Bing Search V7",
 	"Bing Search V7 Subscription Key": "Clé d'abonnement Bing Search V7",
 	"Bing Search V7 Subscription Key": "Clé d'abonnement Bing Search V7",
+	"Bocha Search API Key": "",
 	"Brave Search API Key": "Clé API Brave Search",
 	"Brave Search API Key": "Clé API Brave Search",
 	"By {{name}}": "Par {{name}}",
 	"By {{name}}": "Par {{name}}",
 	"Bypass SSL verification for Websites": "Bypasser la vérification SSL pour les sites web",
 	"Bypass SSL verification for Websites": "Bypasser la vérification SSL pour les sites web",
@@ -163,6 +164,7 @@
 	"Click here to": "Cliquez ici pour",
 	"Click here to": "Cliquez ici pour",
 	"Click here to download user import template file.": "Cliquez ici pour télécharger le fichier modèle d'importation des utilisateurs.",
 	"Click here to download user import template file.": "Cliquez ici pour télécharger le fichier modèle d'importation des utilisateurs.",
 	"Click here to learn more about faster-whisper and see the available models.": "Cliquez ici pour en savoir plus sur faster-whisper et voir les modèles disponibles.",
 	"Click here to learn more about faster-whisper and see the available models.": "Cliquez ici pour en savoir plus sur faster-whisper et voir les modèles disponibles.",
+	"Click here to see available models.": "",
 	"Click here to select": "Cliquez ici pour sélectionner",
 	"Click here to select": "Cliquez ici pour sélectionner",
 	"Click here to select a csv file.": "Cliquez ici pour sélectionner un fichier .csv.",
 	"Click here to select a csv file.": "Cliquez ici pour sélectionner un fichier .csv.",
 	"Click here to select a py file.": "Cliquez ici pour sélectionner un fichier .py.",
 	"Click here to select a py file.": "Cliquez ici pour sélectionner un fichier .py.",
@@ -177,6 +179,8 @@
 	"Code execution": "Exécution de code",
 	"Code execution": "Exécution de code",
 	"Code formatted successfully": "Le code a été formaté avec succès",
 	"Code formatted successfully": "Le code a été formaté avec succès",
 	"Code Interpreter": "",
 	"Code Interpreter": "",
+	"Code Interpreter Engine": "",
+	"Code Interpreter Prompt Template": "",
 	"Collection": "Collection",
 	"Collection": "Collection",
 	"Color": "Couleur",
 	"Color": "Couleur",
 	"ComfyUI": "ComfyUI",
 	"ComfyUI": "ComfyUI",
@@ -193,6 +197,7 @@
 	"Confirm Password": "Confirmer le mot de passe",
 	"Confirm Password": "Confirmer le mot de passe",
 	"Confirm your action": "Confirmer votre action",
 	"Confirm your action": "Confirmer votre action",
 	"Confirm your new password": "Confirmer votre nouveau mot de passe",
 	"Confirm your new password": "Confirmer votre nouveau mot de passe",
+	"Connect to your own OpenAI compatible API endpoints.": "",
 	"Connections": "Connexions",
 	"Connections": "Connexions",
 	"Constrains effort on reasoning for reasoning models. Only applicable to reasoning models from specific providers that support reasoning effort. (Default: medium)": "Contraint l'effort de raisonnement pour les modèles de raisonnement. Applicable uniquement aux modèles de raisonnement de fournisseurs spécifiques qui prennent en charge l'effort de raisonnement. (Par défaut : medium)",
 	"Constrains effort on reasoning for reasoning models. Only applicable to reasoning models from specific providers that support reasoning effort. (Default: medium)": "Contraint l'effort de raisonnement pour les modèles de raisonnement. Applicable uniquement aux modèles de raisonnement de fournisseurs spécifiques qui prennent en charge l'effort de raisonnement. (Par défaut : medium)",
 	"Contact Admin for WebUI Access": "Contacter l'administrateur pour obtenir l'accès à WebUI",
 	"Contact Admin for WebUI Access": "Contacter l'administrateur pour obtenir l'accès à WebUI",
@@ -215,6 +220,7 @@
 	"Copy Link": "Copier le lien",
 	"Copy Link": "Copier le lien",
 	"Copy to clipboard": "Copier dans le presse-papiers",
 	"Copy to clipboard": "Copier dans le presse-papiers",
 	"Copying to clipboard was successful!": "La copie dans le presse-papiers a réussi !",
 	"Copying to clipboard was successful!": "La copie dans le presse-papiers a réussi !",
+	"CORS must be properly configured by the provider to allow requests from Open WebUI.": "",
 	"Create": "Créer",
 	"Create": "Créer",
 	"Create a knowledge base": "Créer une base de connaissances",
 	"Create a knowledge base": "Créer une base de connaissances",
 	"Create a model": "Créer un modèle",
 	"Create a model": "Créer un modèle",
@@ -268,6 +274,9 @@
 	"Describe your knowledge base and objectives": "Décrivez votre base de connaissances et vos objectifs",
 	"Describe your knowledge base and objectives": "Décrivez votre base de connaissances et vos objectifs",
 	"Description": "Description",
 	"Description": "Description",
 	"Didn't fully follow instructions": "N'a pas entièrement respecté les instructions",
 	"Didn't fully follow instructions": "N'a pas entièrement respecté les instructions",
+	"Direct Connections": "",
+	"Direct Connections allow users to connect to their own OpenAI compatible API endpoints.": "",
+	"Direct Connections settings updated": "",
 	"Disabled": "Désactivé",
 	"Disabled": "Désactivé",
 	"Discover a function": "Trouvez une fonction",
 	"Discover a function": "Trouvez une fonction",
 	"Discover a model": "Trouvez un modèle",
 	"Discover a model": "Trouvez un modèle",
@@ -290,6 +299,7 @@
 	"Documentation": "Documentation",
 	"Documentation": "Documentation",
 	"Documents": "Documents",
 	"Documents": "Documents",
 	"does not make any external connections, and your data stays securely on your locally hosted server.": "n'établit aucune connexion externe et garde vos données en sécurité sur votre serveur local.",
 	"does not make any external connections, and your data stays securely on your locally hosted server.": "n'établit aucune connexion externe et garde vos données en sécurité sur votre serveur local.",
+	"Domain Filter List": "",
 	"Don't have an account?": "Vous n'avez pas de compte ?",
 	"Don't have an account?": "Vous n'avez pas de compte ?",
 	"don't install random functions from sources you don't trust.": "n'installez pas de fonctions aléatoires provenant de sources auxquelles vous ne faites pas confiance.",
 	"don't install random functions from sources you don't trust.": "n'installez pas de fonctions aléatoires provenant de sources auxquelles vous ne faites pas confiance.",
 	"don't install random tools from sources you don't trust.": "n'installez pas d'outils aléatoires provenant de sources auxquelles vous ne faites pas confiance.",
 	"don't install random tools from sources you don't trust.": "n'installez pas d'outils aléatoires provenant de sources auxquelles vous ne faites pas confiance.",
@@ -325,6 +335,7 @@
 	"Embedding model set to \"{{embedding_model}}\"": "Modèle d'embedding défini sur « {{embedding_model}} »",
 	"Embedding model set to \"{{embedding_model}}\"": "Modèle d'embedding défini sur « {{embedding_model}} »",
 	"Enable API Key": "Activer la clé API",
 	"Enable API Key": "Activer la clé API",
 	"Enable autocomplete generation for chat messages": "Activer la génération des suggestions pour les messages",
 	"Enable autocomplete generation for chat messages": "Activer la génération des suggestions pour les messages",
+	"Enable Code Interpreter": "",
 	"Enable Community Sharing": "Activer le partage communautaire",
 	"Enable Community Sharing": "Activer le partage communautaire",
 	"Enable Google Drive": "Activer Google Drive",
 	"Enable Google Drive": "Activer Google Drive",
 	"Enable Memory Locking (mlock) to prevent model data from being swapped out of RAM. This option locks the model's working set of pages into RAM, ensuring that they will not be swapped out to disk. This can help maintain performance by avoiding page faults and ensuring fast data access.": "Activer le verrouillage de la mémoire (mlock) pour empêcher les données du modèle d'être échangées de la RAM. Cette option verrouille l'ensemble de pages de travail du modèle en RAM, garantissant qu'elles ne seront pas échangées vers le disque. Cela peut aider à maintenir les performances en évitant les défauts de page et en assurant un accès rapide aux données.",
 	"Enable Memory Locking (mlock) to prevent model data from being swapped out of RAM. This option locks the model's working set of pages into RAM, ensuring that they will not be swapped out to disk. This can help maintain performance by avoiding page faults and ensuring fast data access.": "Activer le verrouillage de la mémoire (mlock) pour empêcher les données du modèle d'être échangées de la RAM. Cette option verrouille l'ensemble de pages de travail du modèle en RAM, garantissant qu'elles ne seront pas échangées vers le disque. Cela peut aider à maintenir les performances en évitant les défauts de page et en assurant un accès rapide aux données.",
@@ -343,18 +354,23 @@
 	"Enter Application DN Password": "Entrez le mot de passe DN de l'application",
 	"Enter Application DN Password": "Entrez le mot de passe DN de l'application",
 	"Enter Bing Search V7 Endpoint": "Entrez le point de terminaison Bing Search V7",
 	"Enter Bing Search V7 Endpoint": "Entrez le point de terminaison Bing Search V7",
 	"Enter Bing Search V7 Subscription Key": "Entrez la clé d'abonnement Bing Search V7",
 	"Enter Bing Search V7 Subscription Key": "Entrez la clé d'abonnement Bing Search V7",
+	"Enter Bocha Search API Key": "",
 	"Enter Brave Search API Key": "Entrez la clé API Brave Search",
 	"Enter Brave Search API Key": "Entrez la clé API Brave Search",
 	"Enter certificate path": "Entrez le chemin du certificat",
 	"Enter certificate path": "Entrez le chemin du certificat",
 	"Enter CFG Scale (e.g. 7.0)": "Entrez l'échelle CFG (par ex. 7.0)",
 	"Enter CFG Scale (e.g. 7.0)": "Entrez l'échelle CFG (par ex. 7.0)",
 	"Enter Chunk Overlap": "Entrez le chevauchement des chunks",
 	"Enter Chunk Overlap": "Entrez le chevauchement des chunks",
 	"Enter Chunk Size": "Entrez la taille des chunks",
 	"Enter Chunk Size": "Entrez la taille des chunks",
 	"Enter description": "Entrez la description",
 	"Enter description": "Entrez la description",
+	"Enter domains separated by commas (e.g., example.com,site.org)": "",
 	"Enter Exa API Key": "",
 	"Enter Exa API Key": "",
 	"Enter Github Raw URL": "Entrez l'URL brute de GitHub",
 	"Enter Github Raw URL": "Entrez l'URL brute de GitHub",
 	"Enter Google PSE API Key": "Entrez la clé API Google PSE",
 	"Enter Google PSE API Key": "Entrez la clé API Google PSE",
 	"Enter Google PSE Engine Id": "Entrez l'identifiant du moteur Google PSE",
 	"Enter Google PSE Engine Id": "Entrez l'identifiant du moteur Google PSE",
 	"Enter Image Size (e.g. 512x512)": "Entrez la taille de l'image (par ex. 512x512)",
 	"Enter Image Size (e.g. 512x512)": "Entrez la taille de l'image (par ex. 512x512)",
 	"Enter Jina API Key": "Entrez la clé API Jina",
 	"Enter Jina API Key": "Entrez la clé API Jina",
+	"Enter Jupyter Password": "",
+	"Enter Jupyter Token": "",
+	"Enter Jupyter URL": "",
 	"Enter Kagi Search API Key": "Entrez la clé API Kagi Search",
 	"Enter Kagi Search API Key": "Entrez la clé API Kagi Search",
 	"Enter language codes": "Entrez les codes de langue",
 	"Enter language codes": "Entrez les codes de langue",
 	"Enter Model ID": "Entrez l'ID du modèle",
 	"Enter Model ID": "Entrez l'ID du modèle",
@@ -540,6 +556,8 @@
 	"JSON Preview": "Aperçu JSON",
 	"JSON Preview": "Aperçu JSON",
 	"July": "Juillet",
 	"July": "Juillet",
 	"June": "Juin",
 	"June": "Juin",
+	"Jupyter Auth": "",
+	"Jupyter URL": "",
 	"JWT Expiration": "Expiration du token JWT",
 	"JWT Expiration": "Expiration du token JWT",
 	"JWT Token": "Token JWT",
 	"JWT Token": "Token JWT",
 	"Kagi Search API Key": "Clé API Kagi Search",
 	"Kagi Search API Key": "Clé API Kagi Search",
@@ -552,6 +570,8 @@
 	"Knowledge deleted successfully.": "Connaissance supprimée avec succès.",
 	"Knowledge deleted successfully.": "Connaissance supprimée avec succès.",
 	"Knowledge reset successfully.": "Connaissance réinitialisée avec succès.",
 	"Knowledge reset successfully.": "Connaissance réinitialisée avec succès.",
 	"Knowledge updated successfully": "Connaissance mise à jour avec succès",
 	"Knowledge updated successfully": "Connaissance mise à jour avec succès",
+	"Kokoro.js (Browser)": "",
+	"Kokoro.js Dtype": "",
 	"Label": "Étiquette",
 	"Label": "Étiquette",
 	"Landing Page Mode": "Mode de la page d'accueil",
 	"Landing Page Mode": "Mode de la page d'accueil",
 	"Language": "Langue",
 	"Language": "Langue",
@@ -566,19 +586,22 @@
 	"Leave empty to include all models from \"{{URL}}/models\" endpoint": "Laissez vide pour inclure tous les modèles depuis le point de terminaison \"{{URL}}/models\"",
 	"Leave empty to include all models from \"{{URL}}/models\" endpoint": "Laissez vide pour inclure tous les modèles depuis le point de terminaison \"{{URL}}/models\"",
 	"Leave empty to include all models or select specific models": "Laissez vide pour inclure tous les modèles ou sélectionnez des modèles spécifiques",
 	"Leave empty to include all models or select specific models": "Laissez vide pour inclure tous les modèles ou sélectionnez des modèles spécifiques",
 	"Leave empty to use the default prompt, or enter a custom prompt": "Laissez vide pour utiliser le prompt par défaut, ou entrez un prompt personnalisé",
 	"Leave empty to use the default prompt, or enter a custom prompt": "Laissez vide pour utiliser le prompt par défaut, ou entrez un prompt personnalisé",
+	"Leave model field empty to use the default model.": "",
 	"Light": "Clair",
 	"Light": "Clair",
 	"Listening...": "Écoute en cours...",
 	"Listening...": "Écoute en cours...",
 	"Llama.cpp": "Llama.cpp",
 	"Llama.cpp": "Llama.cpp",
 	"LLMs can make mistakes. Verify important information.": "Les LLM peuvent faire des erreurs. Vérifiez les informations importantes.",
 	"LLMs can make mistakes. Verify important information.": "Les LLM peuvent faire des erreurs. Vérifiez les informations importantes.",
+	"Loading Kokoro.js...": "",
 	"Local": "Local",
 	"Local": "Local",
 	"Local Models": "Modèles locaux",
 	"Local Models": "Modèles locaux",
 	"Lost": "Perdu",
 	"Lost": "Perdu",
 	"LTR": "LTR",
 	"LTR": "LTR",
-	"Made by OpenWebUI Community": "Réalisé par la communauté OpenWebUI",
+	"Made by Open WebUI Community": "Réalisé par la communauté OpenWebUI",
 	"Make sure to enclose them with": "Assurez-vous de les inclure dans",
 	"Make sure to enclose them with": "Assurez-vous de les inclure dans",
 	"Make sure to export a workflow.json file as API format from ComfyUI.": "Veillez à exporter un fichier workflow.json au format API depuis ComfyUI.",
 	"Make sure to export a workflow.json file as API format from ComfyUI.": "Veillez à exporter un fichier workflow.json au format API depuis ComfyUI.",
 	"Manage": "Gérer",
 	"Manage": "Gérer",
 	"Manage Arena Models": "Gérer les modèles d'arène",
 	"Manage Arena Models": "Gérer les modèles d'arène",
+	"Manage Direct Connections": "",
 	"Manage Models": "Gérer les modèles",
 	"Manage Models": "Gérer les modèles",
 	"Manage Ollama": "Gérer Ollama",
 	"Manage Ollama": "Gérer Ollama",
 	"Manage Ollama API Connections": "Gérer les connexions API Ollama",
 	"Manage Ollama API Connections": "Gérer les connexions API Ollama",
@@ -722,6 +745,7 @@
 	"Plain text (.txt)": "Texte simple (.txt)",
 	"Plain text (.txt)": "Texte simple (.txt)",
 	"Playground": "Playground",
 	"Playground": "Playground",
 	"Please carefully review the following warnings:": "Veuillez lire attentivement les avertissements suivants :",
 	"Please carefully review the following warnings:": "Veuillez lire attentivement les avertissements suivants :",
+	"Please do not close the settings page while loading the model.": "",
 	"Please enter a prompt": "Veuillez saisir un prompt",
 	"Please enter a prompt": "Veuillez saisir un prompt",
 	"Please fill in all fields.": "Veuillez remplir tous les champs.",
 	"Please fill in all fields.": "Veuillez remplir tous les champs.",
 	"Please select a model first.": "Veuillez d'abord sélectionner un modèle.",
 	"Please select a model first.": "Veuillez d'abord sélectionner un modèle.",
@@ -754,7 +778,7 @@
 	"Read Aloud": "Lire à haute voix",
 	"Read Aloud": "Lire à haute voix",
 	"Reasoning Effort": "Effort de raisonnement",
 	"Reasoning Effort": "Effort de raisonnement",
 	"Record voice": "Enregistrer la voix",
 	"Record voice": "Enregistrer la voix",
-	"Redirecting you to OpenWebUI Community": "Redirection vers la communauté OpenWebUI",
+	"Redirecting you to Open WebUI Community": "Redirection vers la communauté OpenWebUI",
 	"Reduces the probability of generating nonsense. A higher value (e.g. 100) will give more diverse answers, while a lower value (e.g. 10) will be more conservative. (Default: 40)": "Réduit la probabilité de générer des non-sens. Une valeur plus élevée (par exemple 100) donnera des réponses plus diversifiées, tandis qu'une valeur plus basse (par exemple 10) sera plus conservatrice. (Par défaut : 40)",
 	"Reduces the probability of generating nonsense. A higher value (e.g. 100) will give more diverse answers, while a lower value (e.g. 10) will be more conservative. (Default: 40)": "Réduit la probabilité de générer des non-sens. Une valeur plus élevée (par exemple 100) donnera des réponses plus diversifiées, tandis qu'une valeur plus basse (par exemple 10) sera plus conservatrice. (Par défaut : 40)",
 	"Refer to yourself as \"User\" (e.g., \"User is learning Spanish\")": "Désignez-vous comme « Utilisateur » (par ex. « L'utilisateur apprend l'espagnol »)",
 	"Refer to yourself as \"User\" (e.g., \"User is learning Spanish\")": "Désignez-vous comme « Utilisateur » (par ex. « L'utilisateur apprend l'espagnol »)",
 	"References from": "Références de",
 	"References from": "Références de",
@@ -829,6 +853,7 @@
 	"Select a pipeline": "Sélectionnez un pipeline",
 	"Select a pipeline": "Sélectionnez un pipeline",
 	"Select a pipeline url": "Sélectionnez l'URL du pipeline",
 	"Select a pipeline url": "Sélectionnez l'URL du pipeline",
 	"Select a tool": "Sélectionnez un outil",
 	"Select a tool": "Sélectionnez un outil",
+	"Select an auth method": "",
 	"Select an Ollama instance": "Sélectionnez une instance Ollama",
 	"Select an Ollama instance": "Sélectionnez une instance Ollama",
 	"Select Engine": "Sélectionnez le moteur",
 	"Select Engine": "Sélectionnez le moteur",
 	"Select Knowledge": "Sélectionnez une connaissance",
 	"Select Knowledge": "Sélectionnez une connaissance",
@@ -869,7 +894,7 @@
 	"Settings saved successfully!": "Paramètres enregistrés avec succès !",
 	"Settings saved successfully!": "Paramètres enregistrés avec succès !",
 	"Share": "Partager",
 	"Share": "Partager",
 	"Share Chat": "Partage de conversation",
 	"Share Chat": "Partage de conversation",
-	"Share to OpenWebUI Community": "Partager avec la communauté OpenWebUI",
+	"Share to Open WebUI Community": "Partager avec la communauté OpenWebUI",
 	"Show": "Afficher",
 	"Show": "Afficher",
 	"Show \"What's New\" modal on login": "Afficher la fenêtre modale \"Quoi de neuf\" lors de la connexion",
 	"Show \"What's New\" modal on login": "Afficher la fenêtre modale \"Quoi de neuf\" lors de la connexion",
 	"Show Admin Details in Account Pending Overlay": "Afficher les coordonnées de l'administrateur aux comptes en attente",
 	"Show Admin Details in Account Pending Overlay": "Afficher les coordonnées de l'administrateur aux comptes en attente",
@@ -944,6 +969,7 @@
 	"This will reset the knowledge base and sync all files. Do you wish to continue?": "Cela réinitialisera la base de connaissances et synchronisera tous les fichiers. Souhaitez-vous continuer ?",
 	"This will reset the knowledge base and sync all files. Do you wish to continue?": "Cela réinitialisera la base de connaissances et synchronisera tous les fichiers. Souhaitez-vous continuer ?",
 	"Thorough explanation": "Explication approfondie",
 	"Thorough explanation": "Explication approfondie",
 	"Thought for {{DURATION}}": "Réflexion de {{DURATION}}",
 	"Thought for {{DURATION}}": "Réflexion de {{DURATION}}",
+	"Thought for {{DURATION}} seconds": "",
 	"Tika": "Tika",
 	"Tika": "Tika",
 	"Tika Server URL required.": "URL du serveur Tika requise.",
 	"Tika Server URL required.": "URL du serveur Tika requise.",
 	"Tiktoken": "Tiktoken",
 	"Tiktoken": "Tiktoken",

+ 29 - 3
src/lib/i18n/locales/he-IL/translation.json

@@ -122,6 +122,7 @@
 	"Beta": "",
 	"Beta": "",
 	"Bing Search V7 Endpoint": "",
 	"Bing Search V7 Endpoint": "",
 	"Bing Search V7 Subscription Key": "",
 	"Bing Search V7 Subscription Key": "",
+	"Bocha Search API Key": "",
 	"Brave Search API Key": "מפתח API של חיפוש אמיץ",
 	"Brave Search API Key": "מפתח API של חיפוש אמיץ",
 	"By {{name}}": "",
 	"By {{name}}": "",
 	"Bypass SSL verification for Websites": "עקוף אימות SSL עבור אתרים",
 	"Bypass SSL verification for Websites": "עקוף אימות SSL עבור אתרים",
@@ -163,6 +164,7 @@
 	"Click here to": "לחץ כאן כדי",
 	"Click here to": "לחץ כאן כדי",
 	"Click here to download user import template file.": "",
 	"Click here to download user import template file.": "",
 	"Click here to learn more about faster-whisper and see the available models.": "",
 	"Click here to learn more about faster-whisper and see the available models.": "",
+	"Click here to see available models.": "",
 	"Click here to select": "לחץ כאן לבחירה",
 	"Click here to select": "לחץ כאן לבחירה",
 	"Click here to select a csv file.": "לחץ כאן לבחירת קובץ csv.",
 	"Click here to select a csv file.": "לחץ כאן לבחירת קובץ csv.",
 	"Click here to select a py file.": "",
 	"Click here to select a py file.": "",
@@ -177,6 +179,8 @@
 	"Code execution": "",
 	"Code execution": "",
 	"Code formatted successfully": "",
 	"Code formatted successfully": "",
 	"Code Interpreter": "",
 	"Code Interpreter": "",
+	"Code Interpreter Engine": "",
+	"Code Interpreter Prompt Template": "",
 	"Collection": "אוסף",
 	"Collection": "אוסף",
 	"Color": "",
 	"Color": "",
 	"ComfyUI": "ComfyUI",
 	"ComfyUI": "ComfyUI",
@@ -193,6 +197,7 @@
 	"Confirm Password": "אשר סיסמה",
 	"Confirm Password": "אשר סיסמה",
 	"Confirm your action": "",
 	"Confirm your action": "",
 	"Confirm your new password": "",
 	"Confirm your new password": "",
+	"Connect to your own OpenAI compatible API endpoints.": "",
 	"Connections": "חיבורים",
 	"Connections": "חיבורים",
 	"Constrains effort on reasoning for reasoning models. Only applicable to reasoning models from specific providers that support reasoning effort. (Default: medium)": "",
 	"Constrains effort on reasoning for reasoning models. Only applicable to reasoning models from specific providers that support reasoning effort. (Default: medium)": "",
 	"Contact Admin for WebUI Access": "",
 	"Contact Admin for WebUI Access": "",
@@ -215,6 +220,7 @@
 	"Copy Link": "העתק קישור",
 	"Copy Link": "העתק קישור",
 	"Copy to clipboard": "",
 	"Copy to clipboard": "",
 	"Copying to clipboard was successful!": "ההעתקה ללוח הייתה מוצלחת!",
 	"Copying to clipboard was successful!": "ההעתקה ללוח הייתה מוצלחת!",
+	"CORS must be properly configured by the provider to allow requests from Open WebUI.": "",
 	"Create": "",
 	"Create": "",
 	"Create a knowledge base": "",
 	"Create a knowledge base": "",
 	"Create a model": "יצירת מודל",
 	"Create a model": "יצירת מודל",
@@ -268,6 +274,9 @@
 	"Describe your knowledge base and objectives": "",
 	"Describe your knowledge base and objectives": "",
 	"Description": "תיאור",
 	"Description": "תיאור",
 	"Didn't fully follow instructions": "לא עקב אחרי ההוראות באופן מלא",
 	"Didn't fully follow instructions": "לא עקב אחרי ההוראות באופן מלא",
+	"Direct Connections": "",
+	"Direct Connections allow users to connect to their own OpenAI compatible API endpoints.": "",
+	"Direct Connections settings updated": "",
 	"Disabled": "",
 	"Disabled": "",
 	"Discover a function": "",
 	"Discover a function": "",
 	"Discover a model": "גלה מודל",
 	"Discover a model": "גלה מודל",
@@ -290,6 +299,7 @@
 	"Documentation": "",
 	"Documentation": "",
 	"Documents": "מסמכים",
 	"Documents": "מסמכים",
 	"does not make any external connections, and your data stays securely on your locally hosted server.": "לא מבצע חיבורים חיצוניים, והנתונים שלך נשמרים באופן מאובטח בשרת המקומי שלך.",
 	"does not make any external connections, and your data stays securely on your locally hosted server.": "לא מבצע חיבורים חיצוניים, והנתונים שלך נשמרים באופן מאובטח בשרת המקומי שלך.",
+	"Domain Filter List": "",
 	"Don't have an account?": "אין לך חשבון?",
 	"Don't have an account?": "אין לך חשבון?",
 	"don't install random functions from sources you don't trust.": "",
 	"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 tools from sources you don't trust.": "",
@@ -325,6 +335,7 @@
 	"Embedding model set to \"{{embedding_model}}\"": "מודל ההטמעה הוגדר ל-\"{{embedding_model}}\"",
 	"Embedding model set to \"{{embedding_model}}\"": "מודל ההטמעה הוגדר ל-\"{{embedding_model}}\"",
 	"Enable API Key": "",
 	"Enable API Key": "",
 	"Enable autocomplete generation for chat messages": "",
 	"Enable autocomplete generation for chat messages": "",
+	"Enable Code Interpreter": "",
 	"Enable Community Sharing": "הפיכת שיתוף קהילה לזמין",
 	"Enable Community Sharing": "הפיכת שיתוף קהילה לזמין",
 	"Enable Google Drive": "",
 	"Enable Google Drive": "",
 	"Enable Memory Locking (mlock) to prevent model data from being swapped out of RAM. This option locks the model's working set of pages into RAM, ensuring that they will not be swapped out to disk. This can help maintain performance by avoiding page faults and ensuring fast data access.": "",
 	"Enable Memory Locking (mlock) to prevent model data from being swapped out of RAM. This option locks the model's working set of pages into RAM, ensuring that they will not be swapped out to disk. This can help maintain performance by avoiding page faults and ensuring fast data access.": "",
@@ -343,18 +354,23 @@
 	"Enter Application DN Password": "",
 	"Enter Application DN Password": "",
 	"Enter Bing Search V7 Endpoint": "",
 	"Enter Bing Search V7 Endpoint": "",
 	"Enter Bing Search V7 Subscription Key": "",
 	"Enter Bing Search V7 Subscription Key": "",
+	"Enter Bocha Search API Key": "",
 	"Enter Brave Search API Key": "הזן מפתח API של חיפוש אמיץ",
 	"Enter Brave Search API Key": "הזן מפתח API של חיפוש אמיץ",
 	"Enter certificate path": "",
 	"Enter certificate path": "",
 	"Enter CFG Scale (e.g. 7.0)": "",
 	"Enter CFG Scale (e.g. 7.0)": "",
 	"Enter Chunk Overlap": "הזן חפיפת נתונים",
 	"Enter Chunk Overlap": "הזן חפיפת נתונים",
 	"Enter Chunk Size": "הזן גודל נתונים",
 	"Enter Chunk Size": "הזן גודל נתונים",
 	"Enter description": "",
 	"Enter description": "",
+	"Enter domains separated by commas (e.g., example.com,site.org)": "",
 	"Enter Exa API Key": "",
 	"Enter Exa API Key": "",
 	"Enter Github Raw URL": "הזן כתובת URL של Github Raw",
 	"Enter Github Raw URL": "הזן כתובת URL של Github Raw",
 	"Enter Google PSE API Key": "הזן מפתח API של Google PSE",
 	"Enter Google PSE API Key": "הזן מפתח API של Google PSE",
 	"Enter Google PSE Engine Id": "הזן את מזהה מנוע PSE של Google",
 	"Enter Google PSE Engine Id": "הזן את מזהה מנוע PSE של Google",
 	"Enter Image Size (e.g. 512x512)": "הזן גודל תמונה (למשל 512x512)",
 	"Enter Image Size (e.g. 512x512)": "הזן גודל תמונה (למשל 512x512)",
 	"Enter Jina API Key": "",
 	"Enter Jina API Key": "",
+	"Enter Jupyter Password": "",
+	"Enter Jupyter Token": "",
+	"Enter Jupyter URL": "",
 	"Enter Kagi Search API Key": "",
 	"Enter Kagi Search API Key": "",
 	"Enter language codes": "הזן קודי שפה",
 	"Enter language codes": "הזן קודי שפה",
 	"Enter Model ID": "",
 	"Enter Model ID": "",
@@ -540,6 +556,8 @@
 	"JSON Preview": "תצוגה מקדימה של JSON",
 	"JSON Preview": "תצוגה מקדימה של JSON",
 	"July": "יולי",
 	"July": "יולי",
 	"June": "יוני",
 	"June": "יוני",
+	"Jupyter Auth": "",
+	"Jupyter URL": "",
 	"JWT Expiration": "תפוגת JWT",
 	"JWT Expiration": "תפוגת JWT",
 	"JWT Token": "אסימון JWT",
 	"JWT Token": "אסימון JWT",
 	"Kagi Search API Key": "",
 	"Kagi Search API Key": "",
@@ -552,6 +570,8 @@
 	"Knowledge deleted successfully.": "",
 	"Knowledge deleted successfully.": "",
 	"Knowledge reset successfully.": "",
 	"Knowledge reset successfully.": "",
 	"Knowledge updated successfully": "",
 	"Knowledge updated successfully": "",
+	"Kokoro.js (Browser)": "",
+	"Kokoro.js Dtype": "",
 	"Label": "",
 	"Label": "",
 	"Landing Page Mode": "",
 	"Landing Page Mode": "",
 	"Language": "שפה",
 	"Language": "שפה",
@@ -566,19 +586,22 @@
 	"Leave empty to include all models from \"{{URL}}/models\" endpoint": "",
 	"Leave empty to include all models from \"{{URL}}/models\" endpoint": "",
 	"Leave empty to include all models or select specific models": "",
 	"Leave empty to include all models or select specific models": "",
 	"Leave empty to use the default prompt, or enter a custom prompt": "",
 	"Leave empty to use the default prompt, or enter a custom prompt": "",
+	"Leave model field empty to use the default model.": "",
 	"Light": "בהיר",
 	"Light": "בהיר",
 	"Listening...": "",
 	"Listening...": "",
 	"Llama.cpp": "",
 	"Llama.cpp": "",
 	"LLMs can make mistakes. Verify important information.": "מודלים בשפה טבעית יכולים לטעות. אמת מידע חשוב.",
 	"LLMs can make mistakes. Verify important information.": "מודלים בשפה טבעית יכולים לטעות. אמת מידע חשוב.",
+	"Loading Kokoro.js...": "",
 	"Local": "",
 	"Local": "",
 	"Local Models": "",
 	"Local Models": "",
 	"Lost": "",
 	"Lost": "",
 	"LTR": "LTR",
 	"LTR": "LTR",
-	"Made by OpenWebUI Community": "נוצר על ידי קהילת OpenWebUI",
+	"Made by Open WebUI Community": "נוצר על ידי קהילת OpenWebUI",
 	"Make sure to enclose them with": "ודא להקיף אותם עם",
 	"Make sure to enclose them with": "ודא להקיף אותם עם",
 	"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.": "",
 	"Manage": "",
 	"Manage": "",
 	"Manage Arena Models": "",
 	"Manage Arena Models": "",
+	"Manage Direct Connections": "",
 	"Manage Models": "",
 	"Manage Models": "",
 	"Manage Ollama": "",
 	"Manage Ollama": "",
 	"Manage Ollama API Connections": "",
 	"Manage Ollama API Connections": "",
@@ -722,6 +745,7 @@
 	"Plain text (.txt)": "טקסט פשוט (.txt)",
 	"Plain text (.txt)": "טקסט פשוט (.txt)",
 	"Playground": "אזור משחקים",
 	"Playground": "אזור משחקים",
 	"Please carefully review the following warnings:": "",
 	"Please carefully review the following warnings:": "",
+	"Please do not close the settings page while loading the model.": "",
 	"Please enter a prompt": "",
 	"Please enter a prompt": "",
 	"Please fill in all fields.": "",
 	"Please fill in all fields.": "",
 	"Please select a model first.": "",
 	"Please select a model first.": "",
@@ -754,7 +778,7 @@
 	"Read Aloud": "קרא בקול",
 	"Read Aloud": "קרא בקול",
 	"Reasoning Effort": "",
 	"Reasoning Effort": "",
 	"Record voice": "הקלט קול",
 	"Record voice": "הקלט קול",
-	"Redirecting you to OpenWebUI Community": "מפנה אותך לקהילת OpenWebUI",
+	"Redirecting you to Open WebUI Community": "מפנה אותך לקהילת OpenWebUI",
 	"Reduces the probability of generating nonsense. A higher value (e.g. 100) will give more diverse answers, while a lower value (e.g. 10) will be more conservative. (Default: 40)": "",
 	"Reduces the probability of generating nonsense. A higher value (e.g. 100) will give more diverse answers, while a lower value (e.g. 10) will be more conservative. (Default: 40)": "",
 	"Refer to yourself as \"User\" (e.g., \"User is learning Spanish\")": "",
 	"Refer to yourself as \"User\" (e.g., \"User is learning Spanish\")": "",
 	"References from": "",
 	"References from": "",
@@ -829,6 +853,7 @@
 	"Select a pipeline": "בחר קו צינור",
 	"Select a pipeline": "בחר קו צינור",
 	"Select a pipeline url": "בחר כתובת URL של קו צינור",
 	"Select a pipeline url": "בחר כתובת URL של קו צינור",
 	"Select a tool": "",
 	"Select a tool": "",
+	"Select an auth method": "",
 	"Select an Ollama instance": "",
 	"Select an Ollama instance": "",
 	"Select Engine": "",
 	"Select Engine": "",
 	"Select Knowledge": "",
 	"Select Knowledge": "",
@@ -869,7 +894,7 @@
 	"Settings saved successfully!": "ההגדרות נשמרו בהצלחה!",
 	"Settings saved successfully!": "ההגדרות נשמרו בהצלחה!",
 	"Share": "שתף",
 	"Share": "שתף",
 	"Share Chat": "שתף צ'אט",
 	"Share Chat": "שתף צ'אט",
-	"Share to OpenWebUI Community": "שתף לקהילת OpenWebUI",
+	"Share to Open WebUI Community": "שתף לקהילת OpenWebUI",
 	"Show": "הצג",
 	"Show": "הצג",
 	"Show \"What's New\" modal on login": "",
 	"Show \"What's New\" modal on login": "",
 	"Show Admin Details in Account Pending Overlay": "",
 	"Show Admin Details in Account Pending Overlay": "",
@@ -944,6 +969,7 @@
 	"This will reset the knowledge base and sync all files. Do you wish to continue?": "",
 	"This will reset the knowledge base and sync all files. Do you wish to continue?": "",
 	"Thorough explanation": "תיאור מפורט",
 	"Thorough explanation": "תיאור מפורט",
 	"Thought for {{DURATION}}": "",
 	"Thought for {{DURATION}}": "",
+	"Thought for {{DURATION}} seconds": "",
 	"Tika": "",
 	"Tika": "",
 	"Tika Server URL required.": "",
 	"Tika Server URL required.": "",
 	"Tiktoken": "",
 	"Tiktoken": "",

+ 29 - 3
src/lib/i18n/locales/hi-IN/translation.json

@@ -122,6 +122,7 @@
 	"Beta": "",
 	"Beta": "",
 	"Bing Search V7 Endpoint": "",
 	"Bing Search V7 Endpoint": "",
 	"Bing Search V7 Subscription Key": "",
 	"Bing Search V7 Subscription Key": "",
+	"Bocha Search API Key": "",
 	"Brave Search API Key": "Brave सर्च एपीआई कुंजी",
 	"Brave Search API Key": "Brave सर्च एपीआई कुंजी",
 	"By {{name}}": "",
 	"By {{name}}": "",
 	"Bypass SSL verification for Websites": "वेबसाइटों के लिए SSL सुनिश्चिती को छोड़ें",
 	"Bypass SSL verification for Websites": "वेबसाइटों के लिए SSL सुनिश्चिती को छोड़ें",
@@ -163,6 +164,7 @@
 	"Click here to": "यहां क्लिक करें",
 	"Click here to": "यहां क्लिक करें",
 	"Click here to download user import template file.": "",
 	"Click here to download user import template file.": "",
 	"Click here to learn more about faster-whisper and see the available models.": "",
 	"Click here to learn more about faster-whisper and see the available models.": "",
+	"Click here to see available models.": "",
 	"Click here to select": "चयन करने के लिए यहां क्लिक करें।",
 	"Click here to select": "चयन करने के लिए यहां क्लिक करें।",
 	"Click here to select a csv file.": "सीएसवी फ़ाइल का चयन करने के लिए यहां क्लिक करें।",
 	"Click here to select a csv file.": "सीएसवी फ़ाइल का चयन करने के लिए यहां क्लिक करें।",
 	"Click here to select a py file.": "",
 	"Click here to select a py file.": "",
@@ -177,6 +179,8 @@
 	"Code execution": "",
 	"Code execution": "",
 	"Code formatted successfully": "",
 	"Code formatted successfully": "",
 	"Code Interpreter": "",
 	"Code Interpreter": "",
+	"Code Interpreter Engine": "",
+	"Code Interpreter Prompt Template": "",
 	"Collection": "संग्रह",
 	"Collection": "संग्रह",
 	"Color": "",
 	"Color": "",
 	"ComfyUI": "ComfyUI",
 	"ComfyUI": "ComfyUI",
@@ -193,6 +197,7 @@
 	"Confirm Password": "पासवर्ड की पुष्टि कीजिये",
 	"Confirm Password": "पासवर्ड की पुष्टि कीजिये",
 	"Confirm your action": "",
 	"Confirm your action": "",
 	"Confirm your new password": "",
 	"Confirm your new password": "",
+	"Connect to your own OpenAI compatible API endpoints.": "",
 	"Connections": "सम्बन्ध",
 	"Connections": "सम्बन्ध",
 	"Constrains effort on reasoning for reasoning models. Only applicable to reasoning models from specific providers that support reasoning effort. (Default: medium)": "",
 	"Constrains effort on reasoning for reasoning models. Only applicable to reasoning models from specific providers that support reasoning effort. (Default: medium)": "",
 	"Contact Admin for WebUI Access": "",
 	"Contact Admin for WebUI Access": "",
@@ -215,6 +220,7 @@
 	"Copy Link": "लिंक को कॉपी करें",
 	"Copy Link": "लिंक को कॉपी करें",
 	"Copy to clipboard": "",
 	"Copy to clipboard": "",
 	"Copying to clipboard was successful!": "क्लिपबोर्ड पर कॉपी बनाना सफल रहा!",
 	"Copying to clipboard was successful!": "क्लिपबोर्ड पर कॉपी बनाना सफल रहा!",
+	"CORS must be properly configured by the provider to allow requests from Open WebUI.": "",
 	"Create": "",
 	"Create": "",
 	"Create a knowledge base": "",
 	"Create a knowledge base": "",
 	"Create a model": "एक मॉडल बनाएं",
 	"Create a model": "एक मॉडल बनाएं",
@@ -268,6 +274,9 @@
 	"Describe your knowledge base and objectives": "",
 	"Describe your knowledge base and objectives": "",
 	"Description": "विवरण",
 	"Description": "विवरण",
 	"Didn't fully follow instructions": "निर्देशों का पूरी तरह से पालन नहीं किया",
 	"Didn't fully follow instructions": "निर्देशों का पूरी तरह से पालन नहीं किया",
+	"Direct Connections": "",
+	"Direct Connections allow users to connect to their own OpenAI compatible API endpoints.": "",
+	"Direct Connections settings updated": "",
 	"Disabled": "",
 	"Disabled": "",
 	"Discover a function": "",
 	"Discover a function": "",
 	"Discover a model": "एक मॉडल की खोज करें",
 	"Discover a model": "एक मॉडल की खोज करें",
@@ -290,6 +299,7 @@
 	"Documentation": "",
 	"Documentation": "",
 	"Documents": "दस्तावेज़",
 	"Documents": "दस्तावेज़",
 	"does not make any external connections, and your data stays securely on your locally hosted server.": "कोई बाहरी कनेक्शन नहीं बनाता है, और आपका डेटा आपके स्थानीय रूप से होस्ट किए गए सर्वर पर सुरक्षित रूप से रहता है।",
 	"does not make any external connections, and your data stays securely on your locally hosted server.": "कोई बाहरी कनेक्शन नहीं बनाता है, और आपका डेटा आपके स्थानीय रूप से होस्ट किए गए सर्वर पर सुरक्षित रूप से रहता है।",
+	"Domain Filter List": "",
 	"Don't have an account?": "कोई खाता नहीं है?",
 	"Don't have an account?": "कोई खाता नहीं है?",
 	"don't install random functions from sources you don't trust.": "",
 	"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 tools from sources you don't trust.": "",
@@ -325,6 +335,7 @@
 	"Embedding model set to \"{{embedding_model}}\"": "एम्बेडिंग मॉडल को \"{{embedding_model}}\" पर सेट किया गया",
 	"Embedding model set to \"{{embedding_model}}\"": "एम्बेडिंग मॉडल को \"{{embedding_model}}\" पर सेट किया गया",
 	"Enable API Key": "",
 	"Enable API Key": "",
 	"Enable autocomplete generation for chat messages": "",
 	"Enable autocomplete generation for chat messages": "",
+	"Enable Code Interpreter": "",
 	"Enable Community Sharing": "समुदाय साझाकरण सक्षम करें",
 	"Enable Community Sharing": "समुदाय साझाकरण सक्षम करें",
 	"Enable Google Drive": "",
 	"Enable Google Drive": "",
 	"Enable Memory Locking (mlock) to prevent model data from being swapped out of RAM. This option locks the model's working set of pages into RAM, ensuring that they will not be swapped out to disk. This can help maintain performance by avoiding page faults and ensuring fast data access.": "",
 	"Enable Memory Locking (mlock) to prevent model data from being swapped out of RAM. This option locks the model's working set of pages into RAM, ensuring that they will not be swapped out to disk. This can help maintain performance by avoiding page faults and ensuring fast data access.": "",
@@ -343,18 +354,23 @@
 	"Enter Application DN Password": "",
 	"Enter Application DN Password": "",
 	"Enter Bing Search V7 Endpoint": "",
 	"Enter Bing Search V7 Endpoint": "",
 	"Enter Bing Search V7 Subscription Key": "",
 	"Enter Bing Search V7 Subscription Key": "",
+	"Enter Bocha Search API Key": "",
 	"Enter Brave Search API Key": "Brave सर्च एपीआई कुंजी डालें",
 	"Enter Brave Search API Key": "Brave सर्च एपीआई कुंजी डालें",
 	"Enter certificate path": "",
 	"Enter certificate path": "",
 	"Enter CFG Scale (e.g. 7.0)": "",
 	"Enter CFG Scale (e.g. 7.0)": "",
 	"Enter Chunk Overlap": "चंक ओवरलैप दर्ज करें",
 	"Enter Chunk Overlap": "चंक ओवरलैप दर्ज करें",
 	"Enter Chunk Size": "खंड आकार दर्ज करें",
 	"Enter Chunk Size": "खंड आकार दर्ज करें",
 	"Enter description": "",
 	"Enter description": "",
+	"Enter domains separated by commas (e.g., example.com,site.org)": "",
 	"Enter Exa API Key": "",
 	"Enter Exa API Key": "",
 	"Enter Github Raw URL": "Github Raw URL दर्ज करें",
 	"Enter Github Raw URL": "Github Raw URL दर्ज करें",
 	"Enter Google PSE API Key": "Google PSE API कुंजी दर्ज करें",
 	"Enter Google PSE API Key": "Google PSE API कुंजी दर्ज करें",
 	"Enter Google PSE Engine Id": "Google PSE इंजन आईडी दर्ज करें",
 	"Enter Google PSE Engine Id": "Google PSE इंजन आईडी दर्ज करें",
 	"Enter Image Size (e.g. 512x512)": "छवि का आकार दर्ज करें (उदा. 512x512)",
 	"Enter Image Size (e.g. 512x512)": "छवि का आकार दर्ज करें (उदा. 512x512)",
 	"Enter Jina API Key": "",
 	"Enter Jina API Key": "",
+	"Enter Jupyter Password": "",
+	"Enter Jupyter Token": "",
+	"Enter Jupyter URL": "",
 	"Enter Kagi Search API Key": "",
 	"Enter Kagi Search API Key": "",
 	"Enter language codes": "भाषा कोड दर्ज करें",
 	"Enter language codes": "भाषा कोड दर्ज करें",
 	"Enter Model ID": "",
 	"Enter Model ID": "",
@@ -540,6 +556,8 @@
 	"JSON Preview": "JSON पूर्वावलोकन",
 	"JSON Preview": "JSON पूर्वावलोकन",
 	"July": "जुलाई",
 	"July": "जुलाई",
 	"June": "जुन",
 	"June": "जुन",
+	"Jupyter Auth": "",
+	"Jupyter URL": "",
 	"JWT Expiration": "JWT समाप्ति",
 	"JWT Expiration": "JWT समाप्ति",
 	"JWT Token": "जट टोकन",
 	"JWT Token": "जट टोकन",
 	"Kagi Search API Key": "",
 	"Kagi Search API Key": "",
@@ -552,6 +570,8 @@
 	"Knowledge deleted successfully.": "",
 	"Knowledge deleted successfully.": "",
 	"Knowledge reset successfully.": "",
 	"Knowledge reset successfully.": "",
 	"Knowledge updated successfully": "",
 	"Knowledge updated successfully": "",
+	"Kokoro.js (Browser)": "",
+	"Kokoro.js Dtype": "",
 	"Label": "",
 	"Label": "",
 	"Landing Page Mode": "",
 	"Landing Page Mode": "",
 	"Language": "भाषा",
 	"Language": "भाषा",
@@ -566,19 +586,22 @@
 	"Leave empty to include all models from \"{{URL}}/models\" endpoint": "",
 	"Leave empty to include all models from \"{{URL}}/models\" endpoint": "",
 	"Leave empty to include all models or select specific models": "",
 	"Leave empty to include all models or select specific models": "",
 	"Leave empty to use the default prompt, or enter a custom prompt": "",
 	"Leave empty to use the default prompt, or enter a custom prompt": "",
+	"Leave model field empty to use the default model.": "",
 	"Light": "सुन",
 	"Light": "सुन",
 	"Listening...": "",
 	"Listening...": "",
 	"Llama.cpp": "",
 	"Llama.cpp": "",
 	"LLMs can make mistakes. Verify important information.": "एलएलएम गलतियाँ कर सकते हैं। महत्वपूर्ण जानकारी सत्यापित करें.",
 	"LLMs can make mistakes. Verify important information.": "एलएलएम गलतियाँ कर सकते हैं। महत्वपूर्ण जानकारी सत्यापित करें.",
+	"Loading Kokoro.js...": "",
 	"Local": "",
 	"Local": "",
 	"Local Models": "",
 	"Local Models": "",
 	"Lost": "",
 	"Lost": "",
 	"LTR": "LTR",
 	"LTR": "LTR",
-	"Made by OpenWebUI Community": "OpenWebUI समुदाय द्वारा निर्मित",
+	"Made by Open WebUI Community": "OpenWebUI समुदाय द्वारा निर्मित",
 	"Make sure to enclose them with": "उन्हें संलग्न करना सुनिश्चित करें",
 	"Make sure to enclose them with": "उन्हें संलग्न करना सुनिश्चित करें",
 	"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.": "",
 	"Manage": "",
 	"Manage": "",
 	"Manage Arena Models": "",
 	"Manage Arena Models": "",
+	"Manage Direct Connections": "",
 	"Manage Models": "",
 	"Manage Models": "",
 	"Manage Ollama": "",
 	"Manage Ollama": "",
 	"Manage Ollama API Connections": "",
 	"Manage Ollama API Connections": "",
@@ -722,6 +745,7 @@
 	"Plain text (.txt)": "सादा पाठ (.txt)",
 	"Plain text (.txt)": "सादा पाठ (.txt)",
 	"Playground": "कार्यक्षेत्र",
 	"Playground": "कार्यक्षेत्र",
 	"Please carefully review the following warnings:": "",
 	"Please carefully review the following warnings:": "",
+	"Please do not close the settings page while loading the model.": "",
 	"Please enter a prompt": "",
 	"Please enter a prompt": "",
 	"Please fill in all fields.": "",
 	"Please fill in all fields.": "",
 	"Please select a model first.": "",
 	"Please select a model first.": "",
@@ -754,7 +778,7 @@
 	"Read Aloud": "जोर से पढ़ें",
 	"Read Aloud": "जोर से पढ़ें",
 	"Reasoning Effort": "",
 	"Reasoning Effort": "",
 	"Record voice": "आवाज रिकॉर्ड करना",
 	"Record voice": "आवाज रिकॉर्ड करना",
-	"Redirecting you to OpenWebUI Community": "आपको OpenWebUI समुदाय पर पुनर्निर्देशित किया जा रहा है",
+	"Redirecting you to Open WebUI Community": "आपको OpenWebUI समुदाय पर पुनर्निर्देशित किया जा रहा है",
 	"Reduces the probability of generating nonsense. A higher value (e.g. 100) will give more diverse answers, while a lower value (e.g. 10) will be more conservative. (Default: 40)": "",
 	"Reduces the probability of generating nonsense. A higher value (e.g. 100) will give more diverse answers, while a lower value (e.g. 10) will be more conservative. (Default: 40)": "",
 	"Refer to yourself as \"User\" (e.g., \"User is learning Spanish\")": "",
 	"Refer to yourself as \"User\" (e.g., \"User is learning Spanish\")": "",
 	"References from": "",
 	"References from": "",
@@ -829,6 +853,7 @@
 	"Select a pipeline": "एक पाइपलाइन का चयन करें",
 	"Select a pipeline": "एक पाइपलाइन का चयन करें",
 	"Select a pipeline url": "एक पाइपलाइन url चुनें",
 	"Select a pipeline url": "एक पाइपलाइन url चुनें",
 	"Select a tool": "",
 	"Select a tool": "",
+	"Select an auth method": "",
 	"Select an Ollama instance": "",
 	"Select an Ollama instance": "",
 	"Select Engine": "",
 	"Select Engine": "",
 	"Select Knowledge": "",
 	"Select Knowledge": "",
@@ -869,7 +894,7 @@
 	"Settings saved successfully!": "सेटिंग्स सफलतापूर्वक सहेजी गईं!",
 	"Settings saved successfully!": "सेटिंग्स सफलतापूर्वक सहेजी गईं!",
 	"Share": "साझा करें",
 	"Share": "साझा करें",
 	"Share Chat": "चैट साझा करें",
 	"Share Chat": "चैट साझा करें",
-	"Share to OpenWebUI Community": "OpenWebUI समुदाय में साझा करें",
+	"Share to Open WebUI Community": "OpenWebUI समुदाय में साझा करें",
 	"Show": "दिखाओ",
 	"Show": "दिखाओ",
 	"Show \"What's New\" modal on login": "",
 	"Show \"What's New\" modal on login": "",
 	"Show Admin Details in Account Pending Overlay": "",
 	"Show Admin Details in Account Pending Overlay": "",
@@ -944,6 +969,7 @@
 	"This will reset the knowledge base and sync all files. Do you wish to continue?": "",
 	"This will reset the knowledge base and sync all files. Do you wish to continue?": "",
 	"Thorough explanation": "विस्तृत व्याख्या",
 	"Thorough explanation": "विस्तृत व्याख्या",
 	"Thought for {{DURATION}}": "",
 	"Thought for {{DURATION}}": "",
+	"Thought for {{DURATION}} seconds": "",
 	"Tika": "",
 	"Tika": "",
 	"Tika Server URL required.": "",
 	"Tika Server URL required.": "",
 	"Tiktoken": "",
 	"Tiktoken": "",

+ 29 - 3
src/lib/i18n/locales/hr-HR/translation.json

@@ -122,6 +122,7 @@
 	"Beta": "",
 	"Beta": "",
 	"Bing Search V7 Endpoint": "",
 	"Bing Search V7 Endpoint": "",
 	"Bing Search V7 Subscription Key": "",
 	"Bing Search V7 Subscription Key": "",
+	"Bocha Search API Key": "",
 	"Brave Search API Key": "Brave tražilica - API ključ",
 	"Brave Search API Key": "Brave tražilica - API ključ",
 	"By {{name}}": "",
 	"By {{name}}": "",
 	"Bypass SSL verification for Websites": "Zaobiđi SSL provjeru za web stranice",
 	"Bypass SSL verification for Websites": "Zaobiđi SSL provjeru za web stranice",
@@ -163,6 +164,7 @@
 	"Click here to": "Kliknite ovdje za",
 	"Click here to": "Kliknite ovdje za",
 	"Click here to download user import template file.": "",
 	"Click here to download user import template file.": "",
 	"Click here to learn more about faster-whisper and see the available models.": "",
 	"Click here to learn more about faster-whisper and see the available models.": "",
+	"Click here to see available models.": "",
 	"Click here to select": "Kliknite ovdje za odabir",
 	"Click here to select": "Kliknite ovdje za odabir",
 	"Click here to select a csv file.": "Kliknite ovdje da odaberete csv datoteku.",
 	"Click here to select a csv file.": "Kliknite ovdje da odaberete csv datoteku.",
 	"Click here to select a py file.": "",
 	"Click here to select a py file.": "",
@@ -177,6 +179,8 @@
 	"Code execution": "",
 	"Code execution": "",
 	"Code formatted successfully": "",
 	"Code formatted successfully": "",
 	"Code Interpreter": "",
 	"Code Interpreter": "",
+	"Code Interpreter Engine": "",
+	"Code Interpreter Prompt Template": "",
 	"Collection": "Kolekcija",
 	"Collection": "Kolekcija",
 	"Color": "",
 	"Color": "",
 	"ComfyUI": "ComfyUI",
 	"ComfyUI": "ComfyUI",
@@ -193,6 +197,7 @@
 	"Confirm Password": "Potvrdite lozinku",
 	"Confirm Password": "Potvrdite lozinku",
 	"Confirm your action": "",
 	"Confirm your action": "",
 	"Confirm your new password": "",
 	"Confirm your new password": "",
+	"Connect to your own OpenAI compatible API endpoints.": "",
 	"Connections": "Povezivanja",
 	"Connections": "Povezivanja",
 	"Constrains effort on reasoning for reasoning models. Only applicable to reasoning models from specific providers that support reasoning effort. (Default: medium)": "",
 	"Constrains effort on reasoning for reasoning models. Only applicable to reasoning models from specific providers that support reasoning effort. (Default: medium)": "",
 	"Contact Admin for WebUI Access": "Kontaktirajte admina za WebUI pristup",
 	"Contact Admin for WebUI Access": "Kontaktirajte admina za WebUI pristup",
@@ -215,6 +220,7 @@
 	"Copy Link": "Kopiraj vezu",
 	"Copy Link": "Kopiraj vezu",
 	"Copy to clipboard": "",
 	"Copy to clipboard": "",
 	"Copying to clipboard was successful!": "Kopiranje u međuspremnik je uspješno!",
 	"Copying to clipboard was successful!": "Kopiranje u međuspremnik je uspješno!",
+	"CORS must be properly configured by the provider to allow requests from Open WebUI.": "",
 	"Create": "",
 	"Create": "",
 	"Create a knowledge base": "",
 	"Create a knowledge base": "",
 	"Create a model": "Izradite model",
 	"Create a model": "Izradite model",
@@ -268,6 +274,9 @@
 	"Describe your knowledge base and objectives": "",
 	"Describe your knowledge base and objectives": "",
 	"Description": "Opis",
 	"Description": "Opis",
 	"Didn't fully follow instructions": "Nije u potpunosti slijedio upute",
 	"Didn't fully follow instructions": "Nije u potpunosti slijedio upute",
+	"Direct Connections": "",
+	"Direct Connections allow users to connect to their own OpenAI compatible API endpoints.": "",
+	"Direct Connections settings updated": "",
 	"Disabled": "",
 	"Disabled": "",
 	"Discover a function": "",
 	"Discover a function": "",
 	"Discover a model": "Otkrijte model",
 	"Discover a model": "Otkrijte model",
@@ -290,6 +299,7 @@
 	"Documentation": "Dokumentacija",
 	"Documentation": "Dokumentacija",
 	"Documents": "Dokumenti",
 	"Documents": "Dokumenti",
 	"does not make any external connections, and your data stays securely on your locally hosted server.": "ne uspostavlja vanjske veze, a vaši podaci ostaju sigurno na vašem lokalno hostiranom poslužitelju.",
 	"does not make any external connections, and your data stays securely on your locally hosted server.": "ne uspostavlja vanjske veze, a vaši podaci ostaju sigurno na vašem lokalno hostiranom poslužitelju.",
+	"Domain Filter List": "",
 	"Don't have an account?": "Nemate račun?",
 	"Don't have an account?": "Nemate račun?",
 	"don't install random functions from sources you don't trust.": "",
 	"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 tools from sources you don't trust.": "",
@@ -325,6 +335,7 @@
 	"Embedding model set to \"{{embedding_model}}\"": "Embedding model postavljen na \"{{embedding_model}}\"",
 	"Embedding model set to \"{{embedding_model}}\"": "Embedding model postavljen na \"{{embedding_model}}\"",
 	"Enable API Key": "",
 	"Enable API Key": "",
 	"Enable autocomplete generation for chat messages": "",
 	"Enable autocomplete generation for chat messages": "",
+	"Enable Code Interpreter": "",
 	"Enable Community Sharing": "Omogući zajedničko korištenje zajednice",
 	"Enable Community Sharing": "Omogući zajedničko korištenje zajednice",
 	"Enable Google Drive": "",
 	"Enable Google Drive": "",
 	"Enable Memory Locking (mlock) to prevent model data from being swapped out of RAM. This option locks the model's working set of pages into RAM, ensuring that they will not be swapped out to disk. This can help maintain performance by avoiding page faults and ensuring fast data access.": "",
 	"Enable Memory Locking (mlock) to prevent model data from being swapped out of RAM. This option locks the model's working set of pages into RAM, ensuring that they will not be swapped out to disk. This can help maintain performance by avoiding page faults and ensuring fast data access.": "",
@@ -343,18 +354,23 @@
 	"Enter Application DN Password": "",
 	"Enter Application DN Password": "",
 	"Enter Bing Search V7 Endpoint": "",
 	"Enter Bing Search V7 Endpoint": "",
 	"Enter Bing Search V7 Subscription Key": "",
 	"Enter Bing Search V7 Subscription Key": "",
+	"Enter Bocha Search API Key": "",
 	"Enter Brave Search API Key": "Unesite Brave Search API ključ",
 	"Enter Brave Search API Key": "Unesite Brave Search API ključ",
 	"Enter certificate path": "",
 	"Enter certificate path": "",
 	"Enter CFG Scale (e.g. 7.0)": "",
 	"Enter CFG Scale (e.g. 7.0)": "",
 	"Enter Chunk Overlap": "Unesite preklapanje dijelova",
 	"Enter Chunk Overlap": "Unesite preklapanje dijelova",
 	"Enter Chunk Size": "Unesite veličinu dijela",
 	"Enter Chunk Size": "Unesite veličinu dijela",
 	"Enter description": "",
 	"Enter description": "",
+	"Enter domains separated by commas (e.g., example.com,site.org)": "",
 	"Enter Exa API Key": "",
 	"Enter Exa API Key": "",
 	"Enter Github Raw URL": "Unesite Github sirovi URL",
 	"Enter Github Raw URL": "Unesite Github sirovi URL",
 	"Enter Google PSE API Key": "Unesite Google PSE API ključ",
 	"Enter Google PSE API Key": "Unesite Google PSE API ključ",
 	"Enter Google PSE Engine Id": "Unesite ID Google PSE motora",
 	"Enter Google PSE Engine Id": "Unesite ID Google PSE motora",
 	"Enter Image Size (e.g. 512x512)": "Unesite veličinu slike (npr. 512x512)",
 	"Enter Image Size (e.g. 512x512)": "Unesite veličinu slike (npr. 512x512)",
 	"Enter Jina API Key": "",
 	"Enter Jina API Key": "",
+	"Enter Jupyter Password": "",
+	"Enter Jupyter Token": "",
+	"Enter Jupyter URL": "",
 	"Enter Kagi Search API Key": "",
 	"Enter Kagi Search API Key": "",
 	"Enter language codes": "Unesite kodove jezika",
 	"Enter language codes": "Unesite kodove jezika",
 	"Enter Model ID": "",
 	"Enter Model ID": "",
@@ -540,6 +556,8 @@
 	"JSON Preview": "JSON pretpregled",
 	"JSON Preview": "JSON pretpregled",
 	"July": "Srpanj",
 	"July": "Srpanj",
 	"June": "Lipanj",
 	"June": "Lipanj",
+	"Jupyter Auth": "",
+	"Jupyter URL": "",
 	"JWT Expiration": "Isticanje JWT-a",
 	"JWT Expiration": "Isticanje JWT-a",
 	"JWT Token": "JWT token",
 	"JWT Token": "JWT token",
 	"Kagi Search API Key": "",
 	"Kagi Search API Key": "",
@@ -552,6 +570,8 @@
 	"Knowledge deleted successfully.": "",
 	"Knowledge deleted successfully.": "",
 	"Knowledge reset successfully.": "",
 	"Knowledge reset successfully.": "",
 	"Knowledge updated successfully": "",
 	"Knowledge updated successfully": "",
+	"Kokoro.js (Browser)": "",
+	"Kokoro.js Dtype": "",
 	"Label": "",
 	"Label": "",
 	"Landing Page Mode": "",
 	"Landing Page Mode": "",
 	"Language": "Jezik",
 	"Language": "Jezik",
@@ -566,19 +586,22 @@
 	"Leave empty to include all models from \"{{URL}}/models\" endpoint": "",
 	"Leave empty to include all models from \"{{URL}}/models\" endpoint": "",
 	"Leave empty to include all models or select specific models": "",
 	"Leave empty to include all models or select specific models": "",
 	"Leave empty to use the default prompt, or enter a custom prompt": "",
 	"Leave empty to use the default prompt, or enter a custom prompt": "",
+	"Leave model field empty to use the default model.": "",
 	"Light": "Svijetlo",
 	"Light": "Svijetlo",
 	"Listening...": "Slušam...",
 	"Listening...": "Slušam...",
 	"Llama.cpp": "",
 	"Llama.cpp": "",
 	"LLMs can make mistakes. Verify important information.": "LLM-ovi mogu pogriješiti. Provjerite važne informacije.",
 	"LLMs can make mistakes. Verify important information.": "LLM-ovi mogu pogriješiti. Provjerite važne informacije.",
+	"Loading Kokoro.js...": "",
 	"Local": "",
 	"Local": "",
 	"Local Models": "Lokalni modeli",
 	"Local Models": "Lokalni modeli",
 	"Lost": "",
 	"Lost": "",
 	"LTR": "LTR",
 	"LTR": "LTR",
-	"Made by OpenWebUI Community": "Izradio OpenWebUI Community",
+	"Made by Open WebUI Community": "Izradio OpenWebUI Community",
 	"Make sure to enclose them with": "Provjerite da ih zatvorite s",
 	"Make sure to enclose them with": "Provjerite da ih zatvorite s",
 	"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.": "",
 	"Manage": "Upravljaj",
 	"Manage": "Upravljaj",
 	"Manage Arena Models": "",
 	"Manage Arena Models": "",
+	"Manage Direct Connections": "",
 	"Manage Models": "",
 	"Manage Models": "",
 	"Manage Ollama": "",
 	"Manage Ollama": "",
 	"Manage Ollama API Connections": "",
 	"Manage Ollama API Connections": "",
@@ -722,6 +745,7 @@
 	"Plain text (.txt)": "Običan tekst (.txt)",
 	"Plain text (.txt)": "Običan tekst (.txt)",
 	"Playground": "Igralište",
 	"Playground": "Igralište",
 	"Please carefully review the following warnings:": "",
 	"Please carefully review the following warnings:": "",
+	"Please do not close the settings page while loading the model.": "",
 	"Please enter a prompt": "",
 	"Please enter a prompt": "",
 	"Please fill in all fields.": "",
 	"Please fill in all fields.": "",
 	"Please select a model first.": "",
 	"Please select a model first.": "",
@@ -754,7 +778,7 @@
 	"Read Aloud": "Čitaj naglas",
 	"Read Aloud": "Čitaj naglas",
 	"Reasoning Effort": "",
 	"Reasoning Effort": "",
 	"Record voice": "Snimanje glasa",
 	"Record voice": "Snimanje glasa",
-	"Redirecting you to OpenWebUI Community": "Preusmjeravanje na OpenWebUI zajednicu",
+	"Redirecting you to Open WebUI Community": "Preusmjeravanje na OpenWebUI zajednicu",
 	"Reduces the probability of generating nonsense. A higher value (e.g. 100) will give more diverse answers, while a lower value (e.g. 10) will be more conservative. (Default: 40)": "",
 	"Reduces the probability of generating nonsense. A higher value (e.g. 100) will give more diverse answers, while a lower value (e.g. 10) will be more conservative. (Default: 40)": "",
 	"Refer to yourself as \"User\" (e.g., \"User is learning Spanish\")": "Nazivajte se \"Korisnik\" (npr. \"Korisnik uči španjolski\")",
 	"Refer to yourself as \"User\" (e.g., \"User is learning Spanish\")": "Nazivajte se \"Korisnik\" (npr. \"Korisnik uči španjolski\")",
 	"References from": "",
 	"References from": "",
@@ -829,6 +853,7 @@
 	"Select a pipeline": "Odabir kanala",
 	"Select a pipeline": "Odabir kanala",
 	"Select a pipeline url": "Odabir URL-a kanala",
 	"Select a pipeline url": "Odabir URL-a kanala",
 	"Select a tool": "",
 	"Select a tool": "",
+	"Select an auth method": "",
 	"Select an Ollama instance": "",
 	"Select an Ollama instance": "",
 	"Select Engine": "",
 	"Select Engine": "",
 	"Select Knowledge": "",
 	"Select Knowledge": "",
@@ -869,7 +894,7 @@
 	"Settings saved successfully!": "Postavke su uspješno spremljene!",
 	"Settings saved successfully!": "Postavke su uspješno spremljene!",
 	"Share": "Podijeli",
 	"Share": "Podijeli",
 	"Share Chat": "Podijeli razgovor",
 	"Share Chat": "Podijeli razgovor",
-	"Share to OpenWebUI Community": "Podijeli u OpenWebUI zajednici",
+	"Share to Open WebUI Community": "Podijeli u OpenWebUI zajednici",
 	"Show": "Pokaži",
 	"Show": "Pokaži",
 	"Show \"What's New\" modal on login": "",
 	"Show \"What's New\" modal on login": "",
 	"Show Admin Details in Account Pending Overlay": "",
 	"Show Admin Details in Account Pending Overlay": "",
@@ -944,6 +969,7 @@
 	"This will reset the knowledge base and sync all files. Do you wish to continue?": "",
 	"This will reset the knowledge base and sync all files. Do you wish to continue?": "",
 	"Thorough explanation": "Detaljno objašnjenje",
 	"Thorough explanation": "Detaljno objašnjenje",
 	"Thought for {{DURATION}}": "",
 	"Thought for {{DURATION}}": "",
+	"Thought for {{DURATION}} seconds": "",
 	"Tika": "",
 	"Tika": "",
 	"Tika Server URL required.": "",
 	"Tika Server URL required.": "",
 	"Tiktoken": "",
 	"Tiktoken": "",

+ 29 - 3
src/lib/i18n/locales/hu-HU/translation.json

@@ -122,6 +122,7 @@
 	"Beta": "",
 	"Beta": "",
 	"Bing Search V7 Endpoint": "",
 	"Bing Search V7 Endpoint": "",
 	"Bing Search V7 Subscription Key": "",
 	"Bing Search V7 Subscription Key": "",
+	"Bocha Search API Key": "",
 	"Brave Search API Key": "Brave Search API kulcs",
 	"Brave Search API Key": "Brave Search API kulcs",
 	"By {{name}}": "",
 	"By {{name}}": "",
 	"Bypass SSL verification for Websites": "SSL ellenőrzés kihagyása weboldalakhoz",
 	"Bypass SSL verification for Websites": "SSL ellenőrzés kihagyása weboldalakhoz",
@@ -163,6 +164,7 @@
 	"Click here to": "Kattints ide",
 	"Click here to": "Kattints ide",
 	"Click here to download user import template file.": "Kattints ide a felhasználó importálási sablon letöltéséhez.",
 	"Click here to download user import template file.": "Kattints ide a felhasználó importálási sablon letöltéséhez.",
 	"Click here to learn more about faster-whisper and see the available models.": "Kattints ide, hogy többet tudj meg a faster-whisperről és lásd az elérhető modelleket.",
 	"Click here to learn more about faster-whisper and see the available models.": "Kattints ide, hogy többet tudj meg a faster-whisperről és lásd az elérhető modelleket.",
+	"Click here to see available models.": "",
 	"Click here to select": "Kattints ide a kiválasztáshoz",
 	"Click here to select": "Kattints ide a kiválasztáshoz",
 	"Click here to select a csv file.": "Kattints ide egy CSV fájl kiválasztásához.",
 	"Click here to select a csv file.": "Kattints ide egy CSV fájl kiválasztásához.",
 	"Click here to select a py file.": "Kattints ide egy py fájl kiválasztásához.",
 	"Click here to select a py file.": "Kattints ide egy py fájl kiválasztásához.",
@@ -177,6 +179,8 @@
 	"Code execution": "Kód végrehajtás",
 	"Code execution": "Kód végrehajtás",
 	"Code formatted successfully": "Kód sikeresen formázva",
 	"Code formatted successfully": "Kód sikeresen formázva",
 	"Code Interpreter": "",
 	"Code Interpreter": "",
+	"Code Interpreter Engine": "",
+	"Code Interpreter Prompt Template": "",
 	"Collection": "Gyűjtemény",
 	"Collection": "Gyűjtemény",
 	"Color": "",
 	"Color": "",
 	"ComfyUI": "ComfyUI",
 	"ComfyUI": "ComfyUI",
@@ -193,6 +197,7 @@
 	"Confirm Password": "Jelszó megerősítése",
 	"Confirm Password": "Jelszó megerősítése",
 	"Confirm your action": "Erősítsd meg a műveletet",
 	"Confirm your action": "Erősítsd meg a műveletet",
 	"Confirm your new password": "",
 	"Confirm your new password": "",
+	"Connect to your own OpenAI compatible API endpoints.": "",
 	"Connections": "Kapcsolatok",
 	"Connections": "Kapcsolatok",
 	"Constrains effort on reasoning for reasoning models. Only applicable to reasoning models from specific providers that support reasoning effort. (Default: medium)": "",
 	"Constrains effort on reasoning for reasoning models. Only applicable to reasoning models from specific providers that support reasoning effort. (Default: medium)": "",
 	"Contact Admin for WebUI Access": "Lépj kapcsolatba az adminnal a WebUI hozzáférésért",
 	"Contact Admin for WebUI Access": "Lépj kapcsolatba az adminnal a WebUI hozzáférésért",
@@ -215,6 +220,7 @@
 	"Copy Link": "Link másolása",
 	"Copy Link": "Link másolása",
 	"Copy to clipboard": "Másolás a vágólapra",
 	"Copy to clipboard": "Másolás a vágólapra",
 	"Copying to clipboard was successful!": "Sikeres másolás a vágólapra!",
 	"Copying to clipboard was successful!": "Sikeres másolás a vágólapra!",
+	"CORS must be properly configured by the provider to allow requests from Open WebUI.": "",
 	"Create": "",
 	"Create": "",
 	"Create a knowledge base": "",
 	"Create a knowledge base": "",
 	"Create a model": "Modell létrehozása",
 	"Create a model": "Modell létrehozása",
@@ -268,6 +274,9 @@
 	"Describe your knowledge base and objectives": "",
 	"Describe your knowledge base and objectives": "",
 	"Description": "Leírás",
 	"Description": "Leírás",
 	"Didn't fully follow instructions": "Nem követte teljesen az utasításokat",
 	"Didn't fully follow instructions": "Nem követte teljesen az utasításokat",
+	"Direct Connections": "",
+	"Direct Connections allow users to connect to their own OpenAI compatible API endpoints.": "",
+	"Direct Connections settings updated": "",
 	"Disabled": "Letiltva",
 	"Disabled": "Letiltva",
 	"Discover a function": "Funkció felfedezése",
 	"Discover a function": "Funkció felfedezése",
 	"Discover a model": "Modell felfedezése",
 	"Discover a model": "Modell felfedezése",
@@ -290,6 +299,7 @@
 	"Documentation": "Dokumentáció",
 	"Documentation": "Dokumentáció",
 	"Documents": "Dokumentumok",
 	"Documents": "Dokumentumok",
 	"does not make any external connections, and your data stays securely on your locally hosted server.": "nem létesít külső kapcsolatokat, és az adataid biztonságban maradnak a helyileg hosztolt szervereden.",
 	"does not make any external connections, and your data stays securely on your locally hosted server.": "nem létesít külső kapcsolatokat, és az adataid biztonságban maradnak a helyileg hosztolt szervereden.",
+	"Domain Filter List": "",
 	"Don't have an account?": "Nincs még fiókod?",
 	"Don't have an account?": "Nincs még fiókod?",
 	"don't install random functions from sources you don't trust.": "ne telepíts véletlenszerű funkciókat olyan forrásokból, amelyekben nem bízol.",
 	"don't install random functions from sources you don't trust.": "ne telepíts véletlenszerű funkciókat olyan forrásokból, amelyekben nem bízol.",
 	"don't install random tools from sources you don't trust.": "ne telepíts véletlenszerű eszközöket olyan forrásokból, amelyekben nem bízol.",
 	"don't install random tools from sources you don't trust.": "ne telepíts véletlenszerű eszközöket olyan forrásokból, amelyekben nem bízol.",
@@ -325,6 +335,7 @@
 	"Embedding model set to \"{{embedding_model}}\"": "Beágyazási modell beállítva: \"{{embedding_model}}\"",
 	"Embedding model set to \"{{embedding_model}}\"": "Beágyazási modell beállítva: \"{{embedding_model}}\"",
 	"Enable API Key": "",
 	"Enable API Key": "",
 	"Enable autocomplete generation for chat messages": "",
 	"Enable autocomplete generation for chat messages": "",
+	"Enable Code Interpreter": "",
 	"Enable Community Sharing": "Közösségi megosztás engedélyezése",
 	"Enable Community Sharing": "Közösségi megosztás engedélyezése",
 	"Enable Google Drive": "",
 	"Enable Google Drive": "",
 	"Enable Memory Locking (mlock) to prevent model data from being swapped out of RAM. This option locks the model's working set of pages into RAM, ensuring that they will not be swapped out to disk. This can help maintain performance by avoiding page faults and ensuring fast data access.": "",
 	"Enable Memory Locking (mlock) to prevent model data from being swapped out of RAM. This option locks the model's working set of pages into RAM, ensuring that they will not be swapped out to disk. This can help maintain performance by avoiding page faults and ensuring fast data access.": "",
@@ -343,18 +354,23 @@
 	"Enter Application DN Password": "",
 	"Enter Application DN Password": "",
 	"Enter Bing Search V7 Endpoint": "",
 	"Enter Bing Search V7 Endpoint": "",
 	"Enter Bing Search V7 Subscription Key": "",
 	"Enter Bing Search V7 Subscription Key": "",
+	"Enter Bocha Search API Key": "",
 	"Enter Brave Search API Key": "Add meg a Brave Search API kulcsot",
 	"Enter Brave Search API Key": "Add meg a Brave Search API kulcsot",
 	"Enter certificate path": "",
 	"Enter certificate path": "",
 	"Enter CFG Scale (e.g. 7.0)": "Add meg a CFG skálát (pl. 7.0)",
 	"Enter CFG Scale (e.g. 7.0)": "Add meg a CFG skálát (pl. 7.0)",
 	"Enter Chunk Overlap": "Add meg a darab átfedést",
 	"Enter Chunk Overlap": "Add meg a darab átfedést",
 	"Enter Chunk Size": "Add meg a darab méretet",
 	"Enter Chunk Size": "Add meg a darab méretet",
 	"Enter description": "Add meg a leírást",
 	"Enter description": "Add meg a leírást",
+	"Enter domains separated by commas (e.g., example.com,site.org)": "",
 	"Enter Exa API Key": "",
 	"Enter Exa API Key": "",
 	"Enter Github Raw URL": "Add meg a Github Raw URL-t",
 	"Enter Github Raw URL": "Add meg a Github Raw URL-t",
 	"Enter Google PSE API Key": "Add meg a Google PSE API kulcsot",
 	"Enter Google PSE API Key": "Add meg a Google PSE API kulcsot",
 	"Enter Google PSE Engine Id": "Add meg a Google PSE motor azonosítót",
 	"Enter Google PSE Engine Id": "Add meg a Google PSE motor azonosítót",
 	"Enter Image Size (e.g. 512x512)": "Add meg a kép méretet (pl. 512x512)",
 	"Enter Image Size (e.g. 512x512)": "Add meg a kép méretet (pl. 512x512)",
 	"Enter Jina API Key": "",
 	"Enter Jina API Key": "",
+	"Enter Jupyter Password": "",
+	"Enter Jupyter Token": "",
+	"Enter Jupyter URL": "",
 	"Enter Kagi Search API Key": "",
 	"Enter Kagi Search API Key": "",
 	"Enter language codes": "Add meg a nyelvi kódokat",
 	"Enter language codes": "Add meg a nyelvi kódokat",
 	"Enter Model ID": "Add meg a modell azonosítót",
 	"Enter Model ID": "Add meg a modell azonosítót",
@@ -540,6 +556,8 @@
 	"JSON Preview": "JSON előnézet",
 	"JSON Preview": "JSON előnézet",
 	"July": "Július",
 	"July": "Július",
 	"June": "Június",
 	"June": "Június",
+	"Jupyter Auth": "",
+	"Jupyter URL": "",
 	"JWT Expiration": "JWT lejárat",
 	"JWT Expiration": "JWT lejárat",
 	"JWT Token": "JWT token",
 	"JWT Token": "JWT token",
 	"Kagi Search API Key": "",
 	"Kagi Search API Key": "",
@@ -552,6 +570,8 @@
 	"Knowledge deleted successfully.": "Tudásbázis sikeresen törölve.",
 	"Knowledge deleted successfully.": "Tudásbázis sikeresen törölve.",
 	"Knowledge reset successfully.": "Tudásbázis sikeresen visszaállítva.",
 	"Knowledge reset successfully.": "Tudásbázis sikeresen visszaállítva.",
 	"Knowledge updated successfully": "Tudásbázis sikeresen frissítve",
 	"Knowledge updated successfully": "Tudásbázis sikeresen frissítve",
+	"Kokoro.js (Browser)": "",
+	"Kokoro.js Dtype": "",
 	"Label": "",
 	"Label": "",
 	"Landing Page Mode": "Kezdőlap mód",
 	"Landing Page Mode": "Kezdőlap mód",
 	"Language": "Nyelv",
 	"Language": "Nyelv",
@@ -566,19 +586,22 @@
 	"Leave empty to include all models from \"{{URL}}/models\" endpoint": "",
 	"Leave empty to include all models from \"{{URL}}/models\" endpoint": "",
 	"Leave empty to include all models or select specific models": "Hagyja üresen az összes modell használatához, vagy válasszon ki konkrét modelleket",
 	"Leave empty to include all models or select specific models": "Hagyja üresen az összes modell használatához, vagy válasszon ki konkrét modelleket",
 	"Leave empty to use the default prompt, or enter a custom prompt": "Hagyja üresen az alapértelmezett prompt használatához, vagy adjon meg egyéni promptot",
 	"Leave empty to use the default prompt, or enter a custom prompt": "Hagyja üresen az alapértelmezett prompt használatához, vagy adjon meg egyéni promptot",
+	"Leave model field empty to use the default model.": "",
 	"Light": "Világos",
 	"Light": "Világos",
 	"Listening...": "Hallgatás...",
 	"Listening...": "Hallgatás...",
 	"Llama.cpp": "",
 	"Llama.cpp": "",
 	"LLMs can make mistakes. Verify important information.": "Az LLM-ek hibázhatnak. Ellenőrizze a fontos információkat.",
 	"LLMs can make mistakes. Verify important information.": "Az LLM-ek hibázhatnak. Ellenőrizze a fontos információkat.",
+	"Loading Kokoro.js...": "",
 	"Local": "",
 	"Local": "",
 	"Local Models": "Helyi modellek",
 	"Local Models": "Helyi modellek",
 	"Lost": "Elveszett",
 	"Lost": "Elveszett",
 	"LTR": "LTR",
 	"LTR": "LTR",
-	"Made by OpenWebUI Community": "Az OpenWebUI közösség által készítve",
+	"Made by Open WebUI Community": "Az OpenWebUI közösség által készítve",
 	"Make sure to enclose them with": "Győződjön meg róla, hogy körülveszi őket",
 	"Make sure to enclose them with": "Győződjön meg róla, hogy körülveszi őket",
 	"Make sure to export a workflow.json file as API format from ComfyUI.": "Győződjön meg róla, hogy exportál egy workflow.json fájlt API formátumban a ComfyUI-ból.",
 	"Make sure to export a workflow.json file as API format from ComfyUI.": "Győződjön meg róla, hogy exportál egy workflow.json fájlt API formátumban a ComfyUI-ból.",
 	"Manage": "Kezelés",
 	"Manage": "Kezelés",
 	"Manage Arena Models": "Arena modellek kezelése",
 	"Manage Arena Models": "Arena modellek kezelése",
+	"Manage Direct Connections": "",
 	"Manage Models": "",
 	"Manage Models": "",
 	"Manage Ollama": "",
 	"Manage Ollama": "",
 	"Manage Ollama API Connections": "",
 	"Manage Ollama API Connections": "",
@@ -722,6 +745,7 @@
 	"Plain text (.txt)": "Egyszerű szöveg (.txt)",
 	"Plain text (.txt)": "Egyszerű szöveg (.txt)",
 	"Playground": "Játszótér",
 	"Playground": "Játszótér",
 	"Please carefully review the following warnings:": "Kérjük, gondosan tekintse át a következő figyelmeztetéseket:",
 	"Please carefully review the following warnings:": "Kérjük, gondosan tekintse át a következő figyelmeztetéseket:",
+	"Please do not close the settings page while loading the model.": "",
 	"Please enter a prompt": "Kérjük, adjon meg egy promptot",
 	"Please enter a prompt": "Kérjük, adjon meg egy promptot",
 	"Please fill in all fields.": "Kérjük, töltse ki az összes mezőt.",
 	"Please fill in all fields.": "Kérjük, töltse ki az összes mezőt.",
 	"Please select a model first.": "",
 	"Please select a model first.": "",
@@ -754,7 +778,7 @@
 	"Read Aloud": "Felolvasás",
 	"Read Aloud": "Felolvasás",
 	"Reasoning Effort": "",
 	"Reasoning Effort": "",
 	"Record voice": "Hang rögzítése",
 	"Record voice": "Hang rögzítése",
-	"Redirecting you to OpenWebUI Community": "Átirányítás az OpenWebUI közösséghez",
+	"Redirecting you to Open WebUI Community": "Átirányítás az OpenWebUI közösséghez",
 	"Reduces the probability of generating nonsense. A higher value (e.g. 100) will give more diverse answers, while a lower value (e.g. 10) will be more conservative. (Default: 40)": "",
 	"Reduces the probability of generating nonsense. A higher value (e.g. 100) will give more diverse answers, while a lower value (e.g. 10) will be more conservative. (Default: 40)": "",
 	"Refer to yourself as \"User\" (e.g., \"User is learning Spanish\")": "Hivatkozzon magára \"Felhasználó\"-ként (pl. \"A Felhasználó spanyolul tanul\")",
 	"Refer to yourself as \"User\" (e.g., \"User is learning Spanish\")": "Hivatkozzon magára \"Felhasználó\"-ként (pl. \"A Felhasználó spanyolul tanul\")",
 	"References from": "Hivatkozások innen",
 	"References from": "Hivatkozások innen",
@@ -829,6 +853,7 @@
 	"Select a pipeline": "Válasszon egy folyamatot",
 	"Select a pipeline": "Válasszon egy folyamatot",
 	"Select a pipeline url": "Válasszon egy folyamat URL-t",
 	"Select a pipeline url": "Válasszon egy folyamat URL-t",
 	"Select a tool": "Válasszon egy eszközt",
 	"Select a tool": "Válasszon egy eszközt",
+	"Select an auth method": "",
 	"Select an Ollama instance": "",
 	"Select an Ollama instance": "",
 	"Select Engine": "Motor kiválasztása",
 	"Select Engine": "Motor kiválasztása",
 	"Select Knowledge": "Tudásbázis kiválasztása",
 	"Select Knowledge": "Tudásbázis kiválasztása",
@@ -869,7 +894,7 @@
 	"Settings saved successfully!": "Beállítások sikeresen mentve!",
 	"Settings saved successfully!": "Beállítások sikeresen mentve!",
 	"Share": "Megosztás",
 	"Share": "Megosztás",
 	"Share Chat": "Beszélgetés megosztása",
 	"Share Chat": "Beszélgetés megosztása",
-	"Share to OpenWebUI Community": "Megosztás az OpenWebUI közösséggel",
+	"Share to Open WebUI Community": "Megosztás az OpenWebUI közösséggel",
 	"Show": "Mutat",
 	"Show": "Mutat",
 	"Show \"What's New\" modal on login": "",
 	"Show \"What's New\" modal on login": "",
 	"Show Admin Details in Account Pending Overlay": "Admin részletek megjelenítése a függő fiók átfedésben",
 	"Show Admin Details in Account Pending Overlay": "Admin részletek megjelenítése a függő fiók átfedésben",
@@ -944,6 +969,7 @@
 	"This will reset the knowledge base and sync all files. Do you wish to continue?": "Ez visszaállítja a tudásbázist és szinkronizálja az összes fájlt. Szeretné folytatni?",
 	"This will reset the knowledge base and sync all files. Do you wish to continue?": "Ez visszaállítja a tudásbázist és szinkronizálja az összes fájlt. Szeretné folytatni?",
 	"Thorough explanation": "Alapos magyarázat",
 	"Thorough explanation": "Alapos magyarázat",
 	"Thought for {{DURATION}}": "",
 	"Thought for {{DURATION}}": "",
+	"Thought for {{DURATION}} seconds": "",
 	"Tika": "Tika",
 	"Tika": "Tika",
 	"Tika Server URL required.": "Tika szerver URL szükséges.",
 	"Tika Server URL required.": "Tika szerver URL szükséges.",
 	"Tiktoken": "Tiktoken",
 	"Tiktoken": "Tiktoken",

+ 29 - 3
src/lib/i18n/locales/id-ID/translation.json

@@ -122,6 +122,7 @@
 	"Beta": "",
 	"Beta": "",
 	"Bing Search V7 Endpoint": "",
 	"Bing Search V7 Endpoint": "",
 	"Bing Search V7 Subscription Key": "",
 	"Bing Search V7 Subscription Key": "",
+	"Bocha Search API Key": "",
 	"Brave Search API Key": "Kunci API Pencarian Berani",
 	"Brave Search API Key": "Kunci API Pencarian Berani",
 	"By {{name}}": "",
 	"By {{name}}": "",
 	"Bypass SSL verification for Websites": "Lewati verifikasi SSL untuk Situs Web",
 	"Bypass SSL verification for Websites": "Lewati verifikasi SSL untuk Situs Web",
@@ -163,6 +164,7 @@
 	"Click here to": "Klik di sini untuk",
 	"Click here to": "Klik di sini untuk",
 	"Click here to download user import template file.": "Klik di sini untuk mengunduh file templat impor pengguna.",
 	"Click here to download user import template file.": "Klik di sini untuk mengunduh file templat impor pengguna.",
 	"Click here to learn more about faster-whisper and see the available models.": "",
 	"Click here to learn more about faster-whisper and see the available models.": "",
+	"Click here to see available models.": "",
 	"Click here to select": "Klik di sini untuk memilih",
 	"Click here to select": "Klik di sini untuk memilih",
 	"Click here to select a csv file.": "Klik di sini untuk memilih file csv.",
 	"Click here to select a csv file.": "Klik di sini untuk memilih file csv.",
 	"Click here to select a py file.": "Klik di sini untuk memilih file py.",
 	"Click here to select a py file.": "Klik di sini untuk memilih file py.",
@@ -177,6 +179,8 @@
 	"Code execution": "",
 	"Code execution": "",
 	"Code formatted successfully": "Kode berhasil diformat",
 	"Code formatted successfully": "Kode berhasil diformat",
 	"Code Interpreter": "",
 	"Code Interpreter": "",
+	"Code Interpreter Engine": "",
+	"Code Interpreter Prompt Template": "",
 	"Collection": "Koleksi",
 	"Collection": "Koleksi",
 	"Color": "",
 	"Color": "",
 	"ComfyUI": "ComfyUI",
 	"ComfyUI": "ComfyUI",
@@ -193,6 +197,7 @@
 	"Confirm Password": "Konfirmasi Kata Sandi",
 	"Confirm Password": "Konfirmasi Kata Sandi",
 	"Confirm your action": "Konfirmasi tindakan Anda",
 	"Confirm your action": "Konfirmasi tindakan Anda",
 	"Confirm your new password": "",
 	"Confirm your new password": "",
+	"Connect to your own OpenAI compatible API endpoints.": "",
 	"Connections": "Koneksi",
 	"Connections": "Koneksi",
 	"Constrains effort on reasoning for reasoning models. Only applicable to reasoning models from specific providers that support reasoning effort. (Default: medium)": "",
 	"Constrains effort on reasoning for reasoning models. Only applicable to reasoning models from specific providers that support reasoning effort. (Default: medium)": "",
 	"Contact Admin for WebUI Access": "Hubungi Admin untuk Akses WebUI",
 	"Contact Admin for WebUI Access": "Hubungi Admin untuk Akses WebUI",
@@ -215,6 +220,7 @@
 	"Copy Link": "Salin Tautan",
 	"Copy Link": "Salin Tautan",
 	"Copy to clipboard": "",
 	"Copy to clipboard": "",
 	"Copying to clipboard was successful!": "Penyalinan ke papan klip berhasil!",
 	"Copying to clipboard was successful!": "Penyalinan ke papan klip berhasil!",
+	"CORS must be properly configured by the provider to allow requests from Open WebUI.": "",
 	"Create": "",
 	"Create": "",
 	"Create a knowledge base": "",
 	"Create a knowledge base": "",
 	"Create a model": "Buat model",
 	"Create a model": "Buat model",
@@ -268,6 +274,9 @@
 	"Describe your knowledge base and objectives": "",
 	"Describe your knowledge base and objectives": "",
 	"Description": "Deskripsi",
 	"Description": "Deskripsi",
 	"Didn't fully follow instructions": "Tidak sepenuhnya mengikuti instruksi",
 	"Didn't fully follow instructions": "Tidak sepenuhnya mengikuti instruksi",
+	"Direct Connections": "",
+	"Direct Connections allow users to connect to their own OpenAI compatible API endpoints.": "",
+	"Direct Connections settings updated": "",
 	"Disabled": "",
 	"Disabled": "",
 	"Discover a function": "Menemukan sebuah fungsi",
 	"Discover a function": "Menemukan sebuah fungsi",
 	"Discover a model": "Menemukan sebuah model",
 	"Discover a model": "Menemukan sebuah model",
@@ -290,6 +299,7 @@
 	"Documentation": "Dokumentasi",
 	"Documentation": "Dokumentasi",
 	"Documents": "Dokumen",
 	"Documents": "Dokumen",
 	"does not make any external connections, and your data stays securely on your locally hosted server.": "tidak membuat koneksi eksternal apa pun, dan data Anda tetap aman di server yang dihosting secara lokal.",
 	"does not make any external connections, and your data stays securely on your locally hosted server.": "tidak membuat koneksi eksternal apa pun, dan data Anda tetap aman di server yang dihosting secara lokal.",
+	"Domain Filter List": "",
 	"Don't have an account?": "Tidak memiliki akun?",
 	"Don't have an account?": "Tidak memiliki akun?",
 	"don't install random functions from sources you don't trust.": "",
 	"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 tools from sources you don't trust.": "",
@@ -325,6 +335,7 @@
 	"Embedding model set to \"{{embedding_model}}\"": "Model penyematan diatur ke \"{{embedding_model}}\"",
 	"Embedding model set to \"{{embedding_model}}\"": "Model penyematan diatur ke \"{{embedding_model}}\"",
 	"Enable API Key": "",
 	"Enable API Key": "",
 	"Enable autocomplete generation for chat messages": "",
 	"Enable autocomplete generation for chat messages": "",
+	"Enable Code Interpreter": "",
 	"Enable Community Sharing": "Aktifkan Berbagi Komunitas",
 	"Enable Community Sharing": "Aktifkan Berbagi Komunitas",
 	"Enable Google Drive": "",
 	"Enable Google Drive": "",
 	"Enable Memory Locking (mlock) to prevent model data from being swapped out of RAM. This option locks the model's working set of pages into RAM, ensuring that they will not be swapped out to disk. This can help maintain performance by avoiding page faults and ensuring fast data access.": "",
 	"Enable Memory Locking (mlock) to prevent model data from being swapped out of RAM. This option locks the model's working set of pages into RAM, ensuring that they will not be swapped out to disk. This can help maintain performance by avoiding page faults and ensuring fast data access.": "",
@@ -343,18 +354,23 @@
 	"Enter Application DN Password": "",
 	"Enter Application DN Password": "",
 	"Enter Bing Search V7 Endpoint": "",
 	"Enter Bing Search V7 Endpoint": "",
 	"Enter Bing Search V7 Subscription Key": "",
 	"Enter Bing Search V7 Subscription Key": "",
+	"Enter Bocha Search API Key": "",
 	"Enter Brave Search API Key": "Masukkan Kunci API Pencarian Berani",
 	"Enter Brave Search API Key": "Masukkan Kunci API Pencarian Berani",
 	"Enter certificate path": "",
 	"Enter certificate path": "",
 	"Enter CFG Scale (e.g. 7.0)": "",
 	"Enter CFG Scale (e.g. 7.0)": "",
 	"Enter Chunk Overlap": "Masukkan Tumpang Tindih Chunk",
 	"Enter Chunk Overlap": "Masukkan Tumpang Tindih Chunk",
 	"Enter Chunk Size": "Masukkan Ukuran Potongan",
 	"Enter Chunk Size": "Masukkan Ukuran Potongan",
 	"Enter description": "",
 	"Enter description": "",
+	"Enter domains separated by commas (e.g., example.com,site.org)": "",
 	"Enter Exa API Key": "",
 	"Enter Exa API Key": "",
 	"Enter Github Raw URL": "Masukkan URL Mentah Github",
 	"Enter Github Raw URL": "Masukkan URL Mentah Github",
 	"Enter Google PSE API Key": "Masukkan Kunci API Google PSE",
 	"Enter Google PSE API Key": "Masukkan Kunci API Google PSE",
 	"Enter Google PSE Engine Id": "Masukkan Id Mesin Google PSE",
 	"Enter Google PSE Engine Id": "Masukkan Id Mesin Google PSE",
 	"Enter Image Size (e.g. 512x512)": "Masukkan Ukuran Gambar (mis. 512x512)",
 	"Enter Image Size (e.g. 512x512)": "Masukkan Ukuran Gambar (mis. 512x512)",
 	"Enter Jina API Key": "",
 	"Enter Jina API Key": "",
+	"Enter Jupyter Password": "",
+	"Enter Jupyter Token": "",
+	"Enter Jupyter URL": "",
 	"Enter Kagi Search API Key": "",
 	"Enter Kagi Search API Key": "",
 	"Enter language codes": "Masukkan kode bahasa",
 	"Enter language codes": "Masukkan kode bahasa",
 	"Enter Model ID": "",
 	"Enter Model ID": "",
@@ -540,6 +556,8 @@
 	"JSON Preview": "Pratinjau JSON",
 	"JSON Preview": "Pratinjau JSON",
 	"July": "Juli",
 	"July": "Juli",
 	"June": "Juni",
 	"June": "Juni",
+	"Jupyter Auth": "",
+	"Jupyter URL": "",
 	"JWT Expiration": "Kedaluwarsa JWT",
 	"JWT Expiration": "Kedaluwarsa JWT",
 	"JWT Token": "Token JWT",
 	"JWT Token": "Token JWT",
 	"Kagi Search API Key": "",
 	"Kagi Search API Key": "",
@@ -552,6 +570,8 @@
 	"Knowledge deleted successfully.": "",
 	"Knowledge deleted successfully.": "",
 	"Knowledge reset successfully.": "",
 	"Knowledge reset successfully.": "",
 	"Knowledge updated successfully": "",
 	"Knowledge updated successfully": "",
+	"Kokoro.js (Browser)": "",
+	"Kokoro.js Dtype": "",
 	"Label": "",
 	"Label": "",
 	"Landing Page Mode": "",
 	"Landing Page Mode": "",
 	"Language": "Bahasa",
 	"Language": "Bahasa",
@@ -566,19 +586,22 @@
 	"Leave empty to include all models from \"{{URL}}/models\" endpoint": "",
 	"Leave empty to include all models from \"{{URL}}/models\" endpoint": "",
 	"Leave empty to include all models or select specific models": "",
 	"Leave empty to include all models or select specific models": "",
 	"Leave empty to use the default prompt, or enter a custom prompt": "",
 	"Leave empty to use the default prompt, or enter a custom prompt": "",
+	"Leave model field empty to use the default model.": "",
 	"Light": "Cahaya",
 	"Light": "Cahaya",
 	"Listening...": "Mendengarkan",
 	"Listening...": "Mendengarkan",
 	"Llama.cpp": "",
 	"Llama.cpp": "",
 	"LLMs can make mistakes. Verify important information.": "LLM dapat membuat kesalahan. Verifikasi informasi penting.",
 	"LLMs can make mistakes. Verify important information.": "LLM dapat membuat kesalahan. Verifikasi informasi penting.",
+	"Loading Kokoro.js...": "",
 	"Local": "",
 	"Local": "",
 	"Local Models": "Model Lokal",
 	"Local Models": "Model Lokal",
 	"Lost": "",
 	"Lost": "",
 	"LTR": "LTR",
 	"LTR": "LTR",
-	"Made by OpenWebUI Community": "Dibuat oleh Komunitas OpenWebUI",
+	"Made by Open WebUI Community": "Dibuat oleh Komunitas OpenWebUI",
 	"Make sure to enclose them with": "Pastikan untuk melampirkannya dengan",
 	"Make sure to enclose them with": "Pastikan untuk melampirkannya dengan",
 	"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.": "",
 	"Manage": "Mengelola",
 	"Manage": "Mengelola",
 	"Manage Arena Models": "",
 	"Manage Arena Models": "",
+	"Manage Direct Connections": "",
 	"Manage Models": "",
 	"Manage Models": "",
 	"Manage Ollama": "",
 	"Manage Ollama": "",
 	"Manage Ollama API Connections": "",
 	"Manage Ollama API Connections": "",
@@ -722,6 +745,7 @@
 	"Plain text (.txt)": "Teks biasa (.txt)",
 	"Plain text (.txt)": "Teks biasa (.txt)",
 	"Playground": "Taman bermain",
 	"Playground": "Taman bermain",
 	"Please carefully review the following warnings:": "",
 	"Please carefully review the following warnings:": "",
+	"Please do not close the settings page while loading the model.": "",
 	"Please enter a prompt": "",
 	"Please enter a prompt": "",
 	"Please fill in all fields.": "",
 	"Please fill in all fields.": "",
 	"Please select a model first.": "",
 	"Please select a model first.": "",
@@ -754,7 +778,7 @@
 	"Read Aloud": "Baca dengan Keras",
 	"Read Aloud": "Baca dengan Keras",
 	"Reasoning Effort": "",
 	"Reasoning Effort": "",
 	"Record voice": "Rekam suara",
 	"Record voice": "Rekam suara",
-	"Redirecting you to OpenWebUI Community": "Mengarahkan Anda ke Komunitas OpenWebUI",
+	"Redirecting you to Open WebUI Community": "Mengarahkan Anda ke Komunitas OpenWebUI",
 	"Reduces the probability of generating nonsense. A higher value (e.g. 100) will give more diverse answers, while a lower value (e.g. 10) will be more conservative. (Default: 40)": "",
 	"Reduces the probability of generating nonsense. A higher value (e.g. 100) will give more diverse answers, while a lower value (e.g. 10) will be more conservative. (Default: 40)": "",
 	"Refer to yourself as \"User\" (e.g., \"User is learning Spanish\")": "Merujuk diri Anda sebagai \"Pengguna\" (misalnya, \"Pengguna sedang belajar bahasa Spanyol\")",
 	"Refer to yourself as \"User\" (e.g., \"User is learning Spanish\")": "Merujuk diri Anda sebagai \"Pengguna\" (misalnya, \"Pengguna sedang belajar bahasa Spanyol\")",
 	"References from": "",
 	"References from": "",
@@ -829,6 +853,7 @@
 	"Select a pipeline": "Pilih saluran pipa",
 	"Select a pipeline": "Pilih saluran pipa",
 	"Select a pipeline url": "Pilih url saluran pipa",
 	"Select a pipeline url": "Pilih url saluran pipa",
 	"Select a tool": "Pilih alat",
 	"Select a tool": "Pilih alat",
+	"Select an auth method": "",
 	"Select an Ollama instance": "",
 	"Select an Ollama instance": "",
 	"Select Engine": "",
 	"Select Engine": "",
 	"Select Knowledge": "",
 	"Select Knowledge": "",
@@ -869,7 +894,7 @@
 	"Settings saved successfully!": "Pengaturan berhasil disimpan!",
 	"Settings saved successfully!": "Pengaturan berhasil disimpan!",
 	"Share": "Berbagi",
 	"Share": "Berbagi",
 	"Share Chat": "Bagikan Obrolan",
 	"Share Chat": "Bagikan Obrolan",
-	"Share to OpenWebUI Community": "Bagikan ke Komunitas OpenWebUI",
+	"Share to Open WebUI Community": "Bagikan ke Komunitas OpenWebUI",
 	"Show": "Tampilkan",
 	"Show": "Tampilkan",
 	"Show \"What's New\" modal on login": "",
 	"Show \"What's New\" modal on login": "",
 	"Show Admin Details in Account Pending Overlay": "Tampilkan Detail Admin di Hamparan Akun Tertunda",
 	"Show Admin Details in Account Pending Overlay": "Tampilkan Detail Admin di Hamparan Akun Tertunda",
@@ -944,6 +969,7 @@
 	"This will reset the knowledge base and sync all files. Do you wish to continue?": "",
 	"This will reset the knowledge base and sync all files. Do you wish to continue?": "",
 	"Thorough explanation": "Penjelasan menyeluruh",
 	"Thorough explanation": "Penjelasan menyeluruh",
 	"Thought for {{DURATION}}": "",
 	"Thought for {{DURATION}}": "",
+	"Thought for {{DURATION}} seconds": "",
 	"Tika": "",
 	"Tika": "",
 	"Tika Server URL required.": "",
 	"Tika Server URL required.": "",
 	"Tiktoken": "",
 	"Tiktoken": "",

Some files were not shown because too many files changed in this diff