Browse Source

Merge pull request #7307 from open-webui/dev

0.4.5
Timothy Jaeryang Baek 5 months ago
parent
commit
4831c9e57e
82 changed files with 1108 additions and 338 deletions
  1. 14 0
      CHANGELOG.md
  2. 22 7
      CODE_OF_CONDUCT.md
  3. 47 57
      backend/open_webui/apps/audio/main.py
  4. 35 11
      backend/open_webui/apps/ollama/main.py
  5. 0 2
      backend/open_webui/apps/openai/main.py
  6. 0 40
      backend/open_webui/apps/retrieval/utils.py
  7. 15 4
      backend/open_webui/apps/webui/main.py
  8. 28 17
      backend/open_webui/apps/webui/routers/configs.py
  9. 11 6
      backend/open_webui/apps/webui/utils.py
  10. 16 9
      backend/open_webui/config.py
  11. 52 32
      backend/open_webui/main.py
  12. 47 0
      backend/open_webui/utils/task.py
  13. 32 1
      backend/open_webui/utils/tools.py
  14. 1 0
      backend/requirements.txt
  15. 2 2
      package-lock.json
  16. 1 1
      package.json
  17. 1 0
      pyproject.toml
  18. 9 0
      src/app.css
  19. 31 4
      src/lib/apis/configs/index.ts
  20. 3 26
      src/lib/apis/index.ts
  21. 1 1
      src/lib/components/admin/Functions.svelte
  22. 2 1
      src/lib/components/admin/Settings/Evaluations.svelte
  23. 2 2
      src/lib/components/admin/Settings/Evaluations/ArenaModelModal.svelte
  24. 20 24
      src/lib/components/admin/Settings/Models.svelte
  25. 258 0
      src/lib/components/admin/Settings/Models/ConfigureModelsModal.svelte
  26. 58 0
      src/lib/components/admin/Settings/Models/ModelList.svelte
  27. 14 7
      src/lib/components/chat/Chat.svelte
  28. 58 46
      src/lib/components/chat/MessageInput.svelte
  29. 3 1
      src/lib/components/chat/Messages/CitationsModal.svelte
  30. 0 2
      src/lib/components/chat/ModelSelector.svelte
  31. 2 0
      src/lib/components/chat/Settings/General.svelte
  32. 3 3
      src/lib/components/common/Modal.svelte
  33. 12 16
      src/lib/components/common/RichTextInput.svelte
  34. 7 11
      src/lib/components/common/Textarea.svelte
  35. 16 3
      src/lib/components/workspace/Models/ModelEditor.svelte
  36. 6 0
      src/lib/i18n/locales/ar-BH/translation.json
  37. 6 0
      src/lib/i18n/locales/bg-BG/translation.json
  38. 6 0
      src/lib/i18n/locales/bn-BD/translation.json
  39. 6 0
      src/lib/i18n/locales/ca-ES/translation.json
  40. 6 0
      src/lib/i18n/locales/ceb-PH/translation.json
  41. 6 0
      src/lib/i18n/locales/cs-CZ/translation.json
  42. 6 0
      src/lib/i18n/locales/da-DK/translation.json
  43. 6 0
      src/lib/i18n/locales/de-DE/translation.json
  44. 6 0
      src/lib/i18n/locales/dg-DG/translation.json
  45. 6 0
      src/lib/i18n/locales/en-GB/translation.json
  46. 6 0
      src/lib/i18n/locales/en-US/translation.json
  47. 6 0
      src/lib/i18n/locales/es-ES/translation.json
  48. 6 0
      src/lib/i18n/locales/fa-IR/translation.json
  49. 6 0
      src/lib/i18n/locales/fi-FI/translation.json
  50. 6 0
      src/lib/i18n/locales/fr-CA/translation.json
  51. 6 0
      src/lib/i18n/locales/fr-FR/translation.json
  52. 6 0
      src/lib/i18n/locales/he-IL/translation.json
  53. 6 0
      src/lib/i18n/locales/hi-IN/translation.json
  54. 6 0
      src/lib/i18n/locales/hr-HR/translation.json
  55. 6 0
      src/lib/i18n/locales/hu-HU/translation.json
  56. 6 0
      src/lib/i18n/locales/id-ID/translation.json
  57. 6 0
      src/lib/i18n/locales/ie-GA/translation.json
  58. 6 0
      src/lib/i18n/locales/it-IT/translation.json
  59. 6 0
      src/lib/i18n/locales/ja-JP/translation.json
  60. 6 0
      src/lib/i18n/locales/ka-GE/translation.json
  61. 6 0
      src/lib/i18n/locales/ko-KR/translation.json
  62. 6 0
      src/lib/i18n/locales/lt-LT/translation.json
  63. 6 0
      src/lib/i18n/locales/ms-MY/translation.json
  64. 6 0
      src/lib/i18n/locales/nb-NO/translation.json
  65. 7 1
      src/lib/i18n/locales/nl-NL/translation.json
  66. 6 0
      src/lib/i18n/locales/pa-IN/translation.json
  67. 6 0
      src/lib/i18n/locales/pl-PL/translation.json
  68. 6 0
      src/lib/i18n/locales/pt-BR/translation.json
  69. 6 0
      src/lib/i18n/locales/pt-PT/translation.json
  70. 6 0
      src/lib/i18n/locales/ro-RO/translation.json
  71. 6 0
      src/lib/i18n/locales/ru-RU/translation.json
  72. 6 0
      src/lib/i18n/locales/sr-RS/translation.json
  73. 6 0
      src/lib/i18n/locales/sv-SE/translation.json
  74. 6 0
      src/lib/i18n/locales/th-TH/translation.json
  75. 6 0
      src/lib/i18n/locales/tk-TW/translation.json
  76. 6 0
      src/lib/i18n/locales/tr-TR/translation.json
  77. 6 0
      src/lib/i18n/locales/uk-UA/translation.json
  78. 6 0
      src/lib/i18n/locales/ur-PK/translation.json
  79. 6 0
      src/lib/i18n/locales/vi-VN/translation.json
  80. 6 0
      src/lib/i18n/locales/zh-CN/translation.json
  81. 6 0
      src/lib/i18n/locales/zh-TW/translation.json
  82. 8 1
      src/lib/utils/index.ts

+ 14 - 0
CHANGELOG.md

@@ -5,6 +5,20 @@ 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.4.5] - 2024-11-26
+
+### Added
+
+- **🎨 Model Order/Defaults Reintroduced**: Brought back the ability to set model order and default models, now configurable via Admin Settings > Models > Configure (Gear Icon).
+
+### Fixed
+
+- **🔍 Query Generation Issue**: Resolved an error in web search query generation, enhancing search accuracy and ensuring smoother search workflows.
+- **📏 Textarea Auto Height Bug**: Fixed a layout issue where textarea input height was shifting unpredictably, particularly when editing system prompts.
+- **🔑 Ollama Authentication**: Corrected an issue with Ollama’s authorization headers, guaranteeing reliable authentication across all endpoints.
+- **⚙️ Missing Min_P Save**: Resolved an issue where the 'min_p' parameter was not being saved in configurations.
+- **🛠️ Tools Description**: Fixed a key issue that omitted tool descriptions in tools payload.
+
 ## [0.4.4] - 2024-11-22
 ## [0.4.4] - 2024-11-22
 
 
 ### Added
 ### Added

+ 22 - 7
CODE_OF_CONDUCT.md

@@ -1,25 +1,30 @@
 # Contributor Covenant Code of Conduct
 # Contributor Covenant Code of Conduct
 
 
 ## Our Pledge
 ## Our Pledge
+
 As members, contributors, and leaders of this community, we pledge to make participation in our open-source project a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.
 As members, contributors, and leaders of this community, we pledge to make participation in our open-source project a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.
 
 
 We are committed to creating and maintaining an open, respectful, and professional environment where positive contributions and meaningful discussions can flourish. By participating in this project, you agree to uphold these values and align your behavior to the standards outlined in this Code of Conduct.
 We are committed to creating and maintaining an open, respectful, and professional environment where positive contributions and meaningful discussions can flourish. By participating in this project, you agree to uphold these values and align your behavior to the standards outlined in this Code of Conduct.
 
 
 ## Why These Standards Are Important
 ## Why These Standards Are Important
-Open-source projects rely on a community of volunteers dedicating their time, expertise, and effort toward a shared goal. These projects are inherently collaborative but also fragile, as the success of the project depends on the goodwill, energy, and productivity of those involved. 
+
+Open-source projects rely on a community of volunteers dedicating their time, expertise, and effort toward a shared goal. These projects are inherently collaborative but also fragile, as the success of the project depends on the goodwill, energy, and productivity of those involved.
 
 
 Maintaining a positive and respectful environment is essential to safeguarding the integrity of this project and protecting contributors' efforts. Behavior that disrupts this atmosphere—whether through hostility, entitlement, or unprofessional conduct—can severely harm the morale and productivity of the community. **Strict enforcement of these standards ensures a safe and supportive space for meaningful collaboration.**
 Maintaining a positive and respectful environment is essential to safeguarding the integrity of this project and protecting contributors' efforts. Behavior that disrupts this atmosphere—whether through hostility, entitlement, or unprofessional conduct—can severely harm the morale and productivity of the community. **Strict enforcement of these standards ensures a safe and supportive space for meaningful collaboration.**
 
 
 This is a community where **respect and professionalism are mandatory.** Violations of these standards will result in **zero tolerance** and immediate enforcement to prevent disruption and ensure the well-being of all participants.
 This is a community where **respect and professionalism are mandatory.** Violations of these standards will result in **zero tolerance** and immediate enforcement to prevent disruption and ensure the well-being of all participants.
 
 
 ## Our Standards
 ## Our Standards
+
 Examples of behavior that contribute to a positive and professional community include:
 Examples of behavior that contribute to a positive and professional community include:
+
 - **Respecting others.** Be considerate, listen actively, and engage with empathy toward others' viewpoints and experiences.
 - **Respecting others.** Be considerate, listen actively, and engage with empathy toward others' viewpoints and experiences.
-- **Constructive feedback.** Provide actionable, thoughtful, and respectful feedback that helps improve the project and encourages collaboration. Avoid unproductive negativity or hypercriticism. 
+- **Constructive feedback.** Provide actionable, thoughtful, and respectful feedback that helps improve the project and encourages collaboration. Avoid unproductive negativity or hypercriticism.
 - **Recognizing volunteer contributions.** Appreciate that contributors dedicate their free time and resources selflessly. Approach them with gratitude and patience.
 - **Recognizing volunteer contributions.** Appreciate that contributors dedicate their free time and resources selflessly. Approach them with gratitude and patience.
 - **Focusing on shared goals.** Collaborate in ways that prioritize the health, success, and sustainability of the community over individual agendas.
 - **Focusing on shared goals.** Collaborate in ways that prioritize the health, success, and sustainability of the community over individual agendas.
 
 
 Examples of unacceptable behavior include:
 Examples of unacceptable behavior include:
+
 - The use of discriminatory, demeaning, or sexualized language or behavior.
 - The use of discriminatory, demeaning, or sexualized language or behavior.
 - Personal attacks, derogatory comments, trolling, or inflammatory political or ideological arguments.
 - Personal attacks, derogatory comments, trolling, or inflammatory political or ideological arguments.
 - Harassment, intimidation, or any behavior intended to create a hostile, uncomfortable, or unsafe environment.
 - Harassment, intimidation, or any behavior intended to create a hostile, uncomfortable, or unsafe environment.
@@ -29,32 +34,40 @@ Examples of unacceptable behavior include:
 - **Spamming and promotional exploitation.** Sharing irrelevant product promotions or self-promotion in the community is not allowed unless it directly contributes value to the discussion.
 - **Spamming and promotional exploitation.** Sharing irrelevant product promotions or self-promotion in the community is not allowed unless it directly contributes value to the discussion.
 
 
 ### Feedback and Community Engagement
 ### Feedback and Community Engagement
+
 - **Constructive feedback is encouraged, but hostile or entitled behavior will result in immediate action.** If you disagree with elements of the project, we encourage you to offer meaningful improvements or fork the project if necessary. Healthy discussions and technical disagreements are welcome only when handled with professionalism.
 - **Constructive feedback is encouraged, but hostile or entitled behavior will result in immediate action.** If you disagree with elements of the project, we encourage you to offer meaningful improvements or fork the project if necessary. Healthy discussions and technical disagreements are welcome only when handled with professionalism.
 - **Respect contributors' time and efforts.** No one is entitled to personalized or on-demand assistance. This is a community built on collaboration and shared effort; demanding or demeaning behavior undermines that trust and will not be allowed.
 - **Respect contributors' time and efforts.** No one is entitled to personalized or on-demand assistance. This is a community built on collaboration and shared effort; demanding or demeaning behavior undermines that trust and will not be allowed.
 
 
 ### Zero Tolerance: No Warnings, Immediate Action
 ### Zero Tolerance: No Warnings, Immediate Action
-This community operates under a **zero-tolerance policy.** Any behavior deemed unacceptable under this Code of Conduct will result in **immediate enforcement, without prior warning.** 
+
+This community operates under a **zero-tolerance policy.** Any behavior deemed unacceptable under this Code of Conduct will result in **immediate enforcement, without prior warning.**
 
 
 We employ this approach to ensure that unproductive or disruptive behavior does not escalate further or cause unnecessary harm to other contributors. The standards are clear, and violations of any kind—whether mild or severe—will be addressed decisively to protect the community.
 We employ this approach to ensure that unproductive or disruptive behavior does not escalate further or cause unnecessary harm to other contributors. The standards are clear, and violations of any kind—whether mild or severe—will be addressed decisively to protect the community.
 
 
 ## Enforcement Responsibilities
 ## Enforcement Responsibilities
+
 Community leaders are responsible for upholding and enforcing these standards. They are empowered to take **immediate and appropriate action** to address any behaviors they deem unacceptable under this Code of Conduct. These actions are taken with the goal of protecting the community and preserving its safe, positive, and productive environment.
 Community leaders are responsible for upholding and enforcing these standards. They are empowered to take **immediate and appropriate action** to address any behaviors they deem unacceptable under this Code of Conduct. These actions are taken with the goal of protecting the community and preserving its safe, positive, and productive environment.
 
 
 ## Scope
 ## Scope
+
 This Code of Conduct applies to all community spaces, including forums, repositories, social media accounts, and in-person events. It also applies when an individual represents the community in public settings, such as conferences or official communications.
 This Code of Conduct applies to all community spaces, including forums, repositories, social media accounts, and in-person events. It also applies when an individual represents the community in public settings, such as conferences or official communications.
 
 
 Additionally, any behavior outside of these defined spaces that negatively impacts the community or its members may fall within the scope of this Code of Conduct.
 Additionally, any behavior outside of these defined spaces that negatively impacts the community or its members may fall within the scope of this Code of Conduct.
 
 
 ## Reporting Violations
 ## Reporting Violations
+
 Instances of unacceptable behavior can be reported to the leadership team at **hello@openwebui.com**. Reports will be handled promptly, confidentially, and with consideration for the safety and well-being of the reporter.
 Instances of unacceptable behavior can be reported to the leadership team at **hello@openwebui.com**. Reports will be handled promptly, confidentially, and with consideration for the safety and well-being of the reporter.
 
 
 All community leaders are required to uphold confidentiality and impartiality when addressing reports of violations.
 All community leaders are required to uphold confidentiality and impartiality when addressing reports of violations.
 
 
 ## Enforcement Guidelines
 ## Enforcement Guidelines
+
 ### Ban
 ### Ban
+
 **Community Impact**: Community leaders will issue a ban to any participant whose behavior is deemed unacceptable according to this Code of Conduct. Bans are enforced immediately and without prior notice.
 **Community Impact**: Community leaders will issue a ban to any participant whose behavior is deemed unacceptable according to this Code of Conduct. Bans are enforced immediately and without prior notice.
 
 
 A ban may be temporary or permanent, depending on the severity of the violation. This includes—but is not limited to—behavior such as:
 A ban may be temporary or permanent, depending on the severity of the violation. This includes—but is not limited to—behavior such as:
+
 - Harassment or abusive behavior toward contributors.
 - Harassment or abusive behavior toward contributors.
 - Persistent negativity or hostility that disrupts the collaborative environment.
 - Persistent negativity or hostility that disrupts the collaborative environment.
 - Disrespectful, demanding, or aggressive interactions with others.
 - Disrespectful, demanding, or aggressive interactions with others.
@@ -65,6 +78,7 @@ A ban may be temporary or permanent, depending on the severity of the violation.
 This approach ensures that disruptive behaviors are addressed swiftly and decisively in order to maintain the integrity and productivity of the community.
 This approach ensures that disruptive behaviors are addressed swiftly and decisively in order to maintain the integrity and productivity of the community.
 
 
 ## Why Zero Tolerance Is Necessary
 ## Why Zero Tolerance Is Necessary
+
 Open-source projects thrive on collaboration, goodwill, and mutual respect. Toxic behaviors—such as entitlement, hostility, or persistent negativity—threaten not just individual contributors but the health of the project as a whole. Allowing such behaviors to persist robs contributors of their time, energy, and enthusiasm for the work they do.
 Open-source projects thrive on collaboration, goodwill, and mutual respect. Toxic behaviors—such as entitlement, hostility, or persistent negativity—threaten not just individual contributors but the health of the project as a whole. Allowing such behaviors to persist robs contributors of their time, energy, and enthusiasm for the work they do.
 
 
 By enforcing a zero-tolerance policy, we ensure that the community remains a safe, welcoming space for all participants. These measures are not about harshness—they are about protecting contributors and fostering a productive environment where innovation can thrive.
 By enforcing a zero-tolerance policy, we ensure that the community remains a safe, welcoming space for all participants. These measures are not about harshness—they are about protecting contributors and fostering a productive environment where innovation can thrive.
@@ -72,13 +86,14 @@ By enforcing a zero-tolerance policy, we ensure that the community remains a saf
 Our expectations are clear, and our enforcement reflects our commitment to this project's long-term success.
 Our expectations are clear, and our enforcement reflects our commitment to this project's long-term success.
 
 
 ## Attribution
 ## Attribution
+
 This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.0, available at  
 This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.0, available at  
-https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.  
+https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
 
 
-Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity).  
+Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity).
 
 
-[homepage]: https://www.contributor-covenant.org  
+[homepage]: https://www.contributor-covenant.org
 
 
 For answers to common questions about this code of conduct, see the FAQ at  
 For answers to common questions about this code of conduct, see the FAQ at  
 https://www.contributor-covenant.org/faq. Translations are available at  
 https://www.contributor-covenant.org/faq. Translations are available at  
-https://www.contributor-covenant.org/translations.
+https://www.contributor-covenant.org/translations.

+ 47 - 57
backend/open_webui/apps/audio/main.py

@@ -8,6 +8,8 @@ from pathlib import Path
 from pydub import AudioSegment
 from pydub import AudioSegment
 from pydub.silence import split_on_silence
 from pydub.silence import split_on_silence
 
 
+import aiohttp
+import aiofiles
 import requests
 import requests
 from open_webui.config import (
 from open_webui.config import (
     AUDIO_STT_ENGINE,
     AUDIO_STT_ENGINE,
@@ -292,46 +294,39 @@ async def speech(request: Request, user=Depends(get_verified_user)):
         except Exception:
         except Exception:
             pass
             pass
 
 
-        r = None
         try:
         try:
-            r = requests.post(
-                url=f"{app.state.config.TTS_OPENAI_API_BASE_URL}/audio/speech",
-                data=body,
-                headers=headers,
-                stream=True,
-            )
+            async with aiohttp.ClientSession() as session:
+                async with session.post(
+                    url=f"{app.state.config.TTS_OPENAI_API_BASE_URL}/audio/speech",
+                    data=body,
+                    headers=headers,
+                ) as r:
+                    r.raise_for_status()
+                    async with aiofiles.open(file_path, "wb") as f:
+                        await f.write(await r.read())
+
+                    async with aiofiles.open(file_body_path, "w") as f:
+                        await f.write(json.dumps(json.loads(body.decode("utf-8"))))
 
 
-            r.raise_for_status()
-
-            # Save the streaming content to a file
-            with open(file_path, "wb") as f:
-                for chunk in r.iter_content(chunk_size=8192):
-                    f.write(chunk)
-
-            with open(file_body_path, "w") as f:
-                json.dump(json.loads(body.decode("utf-8")), f)
-
-            # Return the saved file
             return FileResponse(file_path)
             return FileResponse(file_path)
 
 
         except Exception as e:
         except Exception as e:
             log.exception(e)
             log.exception(e)
             error_detail = "Open WebUI: Server Connection Error"
             error_detail = "Open WebUI: Server Connection Error"
-            if r is not None:
-                try:
-                    res = r.json()
+            try:
+                if r.status != 200:
+                    res = await r.json()
                     if "error" in res:
                     if "error" in res:
                         error_detail = f"External: {res['error']['message']}"
                         error_detail = f"External: {res['error']['message']}"
-                except Exception:
-                    error_detail = f"External: {e}"
+            except Exception:
+                error_detail = f"External: {e}"
 
 
             raise HTTPException(
             raise HTTPException(
-                status_code=r.status_code if r != None else 500,
+                status_code=getattr(r, "status", 500),
                 detail=error_detail,
                 detail=error_detail,
             )
             )
 
 
     elif app.state.config.TTS_ENGINE == "elevenlabs":
     elif app.state.config.TTS_ENGINE == "elevenlabs":
-        payload = None
         try:
         try:
             payload = json.loads(body.decode("utf-8"))
             payload = json.loads(body.decode("utf-8"))
         except Exception as e:
         except Exception as e:
@@ -339,7 +334,6 @@ async def speech(request: Request, user=Depends(get_verified_user)):
             raise HTTPException(status_code=400, detail="Invalid JSON payload")
             raise HTTPException(status_code=400, detail="Invalid JSON payload")
 
 
         voice_id = payload.get("voice", "")
         voice_id = payload.get("voice", "")
-
         if voice_id not in get_available_voices():
         if voice_id not in get_available_voices():
             raise HTTPException(
             raise HTTPException(
                 status_code=400,
                 status_code=400,
@@ -347,13 +341,11 @@ async def speech(request: Request, user=Depends(get_verified_user)):
             )
             )
 
 
         url = f"https://api.elevenlabs.io/v1/text-to-speech/{voice_id}"
         url = f"https://api.elevenlabs.io/v1/text-to-speech/{voice_id}"
-
         headers = {
         headers = {
             "Accept": "audio/mpeg",
             "Accept": "audio/mpeg",
             "Content-Type": "application/json",
             "Content-Type": "application/json",
             "xi-api-key": app.state.config.TTS_API_KEY,
             "xi-api-key": app.state.config.TTS_API_KEY,
         }
         }
-
         data = {
         data = {
             "text": payload["input"],
             "text": payload["input"],
             "model_id": app.state.config.TTS_MODEL,
             "model_id": app.state.config.TTS_MODEL,
@@ -361,39 +353,34 @@ async def speech(request: Request, user=Depends(get_verified_user)):
         }
         }
 
 
         try:
         try:
-            r = requests.post(url, json=data, headers=headers)
+            async with aiohttp.ClientSession() as session:
+                async with session.post(url, json=data, headers=headers) as r:
+                    r.raise_for_status()
+                    async with aiofiles.open(file_path, "wb") as f:
+                        await f.write(await r.read())
 
 
-            r.raise_for_status()
-
-            # Save the streaming content to a file
-            with open(file_path, "wb") as f:
-                for chunk in r.iter_content(chunk_size=8192):
-                    f.write(chunk)
+                    async with aiofiles.open(file_body_path, "w") as f:
+                        await f.write(json.dumps(json.loads(body.decode("utf-8"))))
 
 
-            with open(file_body_path, "w") as f:
-                json.dump(json.loads(body.decode("utf-8")), f)
-
-            # Return the saved file
             return FileResponse(file_path)
             return FileResponse(file_path)
 
 
         except Exception as e:
         except Exception as e:
             log.exception(e)
             log.exception(e)
             error_detail = "Open WebUI: Server Connection Error"
             error_detail = "Open WebUI: Server Connection Error"
-            if r is not None:
-                try:
-                    res = r.json()
+            try:
+                if r.status != 200:
+                    res = await r.json()
                     if "error" in res:
                     if "error" in res:
                         error_detail = f"External: {res['error']['message']}"
                         error_detail = f"External: {res['error']['message']}"
-                except Exception:
-                    error_detail = f"External: {e}"
+            except Exception:
+                error_detail = f"External: {e}"
 
 
             raise HTTPException(
             raise HTTPException(
-                status_code=r.status_code if r != None else 500,
+                status_code=getattr(r, "status", 500),
                 detail=error_detail,
                 detail=error_detail,
             )
             )
 
 
     elif app.state.config.TTS_ENGINE == "azure":
     elif app.state.config.TTS_ENGINE == "azure":
-        payload = None
         try:
         try:
             payload = json.loads(body.decode("utf-8"))
             payload = json.loads(body.decode("utf-8"))
         except Exception as e:
         except Exception as e:
@@ -416,17 +403,20 @@ async def speech(request: Request, user=Depends(get_verified_user)):
                 <voice name="{language}">{payload["input"]}</voice>
                 <voice name="{language}">{payload["input"]}</voice>
             </speak>"""
             </speak>"""
 
 
-        response = requests.post(url, headers=headers, data=data)
-
-        if response.status_code == 200:
-            with open(file_path, "wb") as f:
-                f.write(response.content)
-            return FileResponse(file_path)
-        else:
-            log.error(f"Error synthesizing speech - {response.reason}")
-            raise HTTPException(
-                status_code=500, detail=f"Error synthesizing speech - {response.reason}"
-            )
+        try:
+            async with aiohttp.ClientSession() as session:
+                async with session.post(url, headers=headers, data=data) as response:
+                    if response.status == 200:
+                        async with aiofiles.open(file_path, "wb") as f:
+                            await f.write(await response.read())
+                        return FileResponse(file_path)
+                    else:
+                        error_msg = f"Error synthesizing speech - {response.reason}"
+                        log.error(error_msg)
+                        raise HTTPException(status_code=500, detail=error_msg)
+        except Exception as e:
+            log.exception(e)
+            raise HTTPException(status_code=500, detail=str(e))
     elif app.state.config.TTS_ENGINE == "transformers":
     elif app.state.config.TTS_ENGINE == "transformers":
         payload = None
         payload = None
         try:
         try:

+ 35 - 11
backend/open_webui/apps/ollama/main.py

@@ -195,7 +195,10 @@ async def post_streaming_url(
             trust_env=True, timeout=aiohttp.ClientTimeout(total=AIOHTTP_CLIENT_TIMEOUT)
             trust_env=True, timeout=aiohttp.ClientTimeout(total=AIOHTTP_CLIENT_TIMEOUT)
         )
         )
 
 
-        api_config = app.state.config.OLLAMA_API_CONFIGS.get(url, {})
+        parsed_url = urlparse(url)
+        base_url = f"{parsed_url.scheme}://{parsed_url.netloc}"
+
+        api_config = app.state.config.OLLAMA_API_CONFIGS.get(base_url, {})
         key = api_config.get("key", None)
         key = api_config.get("key", None)
 
 
         headers = {"Content-Type": "application/json"}
         headers = {"Content-Type": "application/json"}
@@ -210,13 +213,13 @@ async def post_streaming_url(
         r.raise_for_status()
         r.raise_for_status()
 
 
         if stream:
         if stream:
-            headers = dict(r.headers)
+            response_headers = dict(r.headers)
             if content_type:
             if content_type:
-                headers["Content-Type"] = content_type
+                response_headers["Content-Type"] = content_type
             return StreamingResponse(
             return StreamingResponse(
                 r.content,
                 r.content,
                 status_code=r.status,
                 status_code=r.status,
-                headers=headers,
+                headers=response_headers,
                 background=BackgroundTask(
                 background=BackgroundTask(
                     cleanup_response, response=r, session=session
                     cleanup_response, response=r, session=session
                 ),
                 ),
@@ -324,7 +327,10 @@ async def get_ollama_tags(
     else:
     else:
         url = app.state.config.OLLAMA_BASE_URLS[url_idx]
         url = app.state.config.OLLAMA_BASE_URLS[url_idx]
 
 
-        api_config = app.state.config.OLLAMA_API_CONFIGS.get(url, {})
+        parsed_url = urlparse(url)
+        base_url = f"{parsed_url.scheme}://{parsed_url.netloc}"
+
+        api_config = app.state.config.OLLAMA_API_CONFIGS.get(base_url, {})
         key = api_config.get("key", None)
         key = api_config.get("key", None)
 
 
         headers = {}
         headers = {}
@@ -525,7 +531,10 @@ async def copy_model(
     url = app.state.config.OLLAMA_BASE_URLS[url_idx]
     url = app.state.config.OLLAMA_BASE_URLS[url_idx]
     log.info(f"url: {url}")
     log.info(f"url: {url}")
 
 
-    api_config = app.state.config.OLLAMA_API_CONFIGS.get(url, {})
+    parsed_url = urlparse(url)
+    base_url = f"{parsed_url.scheme}://{parsed_url.netloc}"
+
+    api_config = app.state.config.OLLAMA_API_CONFIGS.get(base_url, {})
     key = api_config.get("key", None)
     key = api_config.get("key", None)
 
 
     headers = {"Content-Type": "application/json"}
     headers = {"Content-Type": "application/json"}
@@ -584,7 +593,10 @@ async def delete_model(
     url = app.state.config.OLLAMA_BASE_URLS[url_idx]
     url = app.state.config.OLLAMA_BASE_URLS[url_idx]
     log.info(f"url: {url}")
     log.info(f"url: {url}")
 
 
-    api_config = app.state.config.OLLAMA_API_CONFIGS.get(url, {})
+    parsed_url = urlparse(url)
+    base_url = f"{parsed_url.scheme}://{parsed_url.netloc}"
+
+    api_config = app.state.config.OLLAMA_API_CONFIGS.get(base_url, {})
     key = api_config.get("key", None)
     key = api_config.get("key", None)
 
 
     headers = {"Content-Type": "application/json"}
     headers = {"Content-Type": "application/json"}
@@ -635,7 +647,10 @@ async def show_model_info(form_data: ModelNameForm, user=Depends(get_verified_us
     url = app.state.config.OLLAMA_BASE_URLS[url_idx]
     url = app.state.config.OLLAMA_BASE_URLS[url_idx]
     log.info(f"url: {url}")
     log.info(f"url: {url}")
 
 
-    api_config = app.state.config.OLLAMA_API_CONFIGS.get(url, {})
+    parsed_url = urlparse(url)
+    base_url = f"{parsed_url.scheme}://{parsed_url.netloc}"
+
+    api_config = app.state.config.OLLAMA_API_CONFIGS.get(base_url, {})
     key = api_config.get("key", None)
     key = api_config.get("key", None)
 
 
     headers = {"Content-Type": "application/json"}
     headers = {"Content-Type": "application/json"}
@@ -730,7 +745,10 @@ async def generate_ollama_embeddings(
     url = app.state.config.OLLAMA_BASE_URLS[url_idx]
     url = app.state.config.OLLAMA_BASE_URLS[url_idx]
     log.info(f"url: {url}")
     log.info(f"url: {url}")
 
 
-    api_config = app.state.config.OLLAMA_API_CONFIGS.get(url, {})
+    parsed_url = urlparse(url)
+    base_url = f"{parsed_url.scheme}://{parsed_url.netloc}"
+
+    api_config = app.state.config.OLLAMA_API_CONFIGS.get(base_url, {})
     key = api_config.get("key", None)
     key = api_config.get("key", None)
 
 
     headers = {"Content-Type": "application/json"}
     headers = {"Content-Type": "application/json"}
@@ -797,7 +815,10 @@ async def generate_ollama_batch_embeddings(
     url = app.state.config.OLLAMA_BASE_URLS[url_idx]
     url = app.state.config.OLLAMA_BASE_URLS[url_idx]
     log.info(f"url: {url}")
     log.info(f"url: {url}")
 
 
-    api_config = app.state.config.OLLAMA_API_CONFIGS.get(url, {})
+    parsed_url = urlparse(url)
+    base_url = f"{parsed_url.scheme}://{parsed_url.netloc}"
+
+    api_config = app.state.config.OLLAMA_API_CONFIGS.get(base_url, {})
     key = api_config.get("key", None)
     key = api_config.get("key", None)
 
 
     headers = {"Content-Type": "application/json"}
     headers = {"Content-Type": "application/json"}
@@ -974,7 +995,10 @@ async def generate_chat_completion(
     log.info(f"url: {url}")
     log.info(f"url: {url}")
     log.debug(f"generate_chat_completion() - 2.payload = {payload}")
     log.debug(f"generate_chat_completion() - 2.payload = {payload}")
 
 
-    api_config = app.state.config.OLLAMA_API_CONFIGS.get(url, {})
+    parsed_url = urlparse(url)
+    base_url = f"{parsed_url.scheme}://{parsed_url.netloc}"
+
+    api_config = app.state.config.OLLAMA_API_CONFIGS.get(base_url, {})
     prefix_id = api_config.get("prefix_id", None)
     prefix_id = api_config.get("prefix_id", None)
     if prefix_id:
     if prefix_id:
         payload["model"] = payload["model"].replace(f"{prefix_id}.", "")
         payload["model"] = payload["model"].replace(f"{prefix_id}.", "")

+ 0 - 2
backend/open_webui/apps/openai/main.py

@@ -585,8 +585,6 @@ async def generate_chat_completion(
     # Convert the modified body back to JSON
     # Convert the modified body back to JSON
     payload = json.dumps(payload)
     payload = json.dumps(payload)
 
 
-    log.debug(payload)
-
     headers = {}
     headers = {}
     headers["Authorization"] = f"Bearer {key}"
     headers["Authorization"] = f"Bearer {key}"
     headers["Content-Type"] = "application/json"
     headers["Content-Type"] = "application/json"

+ 0 - 40
backend/open_webui/apps/retrieval/utils.py

@@ -15,8 +15,6 @@ from open_webui.apps.retrieval.vector.connector import VECTOR_DB_CLIENT
 from open_webui.utils.misc import get_last_user_message
 from open_webui.utils.misc import get_last_user_message
 
 
 from open_webui.env import SRC_LOG_LEVELS
 from open_webui.env import SRC_LOG_LEVELS
-from open_webui.config import DEFAULT_RAG_TEMPLATE
-
 
 
 log = logging.getLogger(__name__)
 log = logging.getLogger(__name__)
 log.setLevel(SRC_LOG_LEVELS["RAG"])
 log.setLevel(SRC_LOG_LEVELS["RAG"])
@@ -238,44 +236,6 @@ def query_collection_with_hybrid_search(
     return merge_and_sort_query_results(results, k=k, reverse=True)
     return merge_and_sort_query_results(results, k=k, reverse=True)
 
 
 
 
-def rag_template(template: str, context: str, query: str):
-    if template == "":
-        template = DEFAULT_RAG_TEMPLATE
-
-    if "[context]" not in template and "{{CONTEXT}}" not in template:
-        log.debug(
-            "WARNING: The RAG template does not contain the '[context]' or '{{CONTEXT}}' placeholder."
-        )
-
-    if "<context>" in context and "</context>" in context:
-        log.debug(
-            "WARNING: Potential prompt injection attack: the RAG "
-            "context contains '<context>' and '</context>'. This might be "
-            "nothing, or the user might be trying to hack something."
-        )
-
-    query_placeholders = []
-    if "[query]" in context:
-        query_placeholder = "{{QUERY" + str(uuid.uuid4()) + "}}"
-        template = template.replace("[query]", query_placeholder)
-        query_placeholders.append(query_placeholder)
-
-    if "{{QUERY}}" in context:
-        query_placeholder = "{{QUERY" + str(uuid.uuid4()) + "}}"
-        template = template.replace("{{QUERY}}", query_placeholder)
-        query_placeholders.append(query_placeholder)
-
-    template = template.replace("[context]", context)
-    template = template.replace("{{CONTEXT}}", context)
-    template = template.replace("[query]", query)
-    template = template.replace("{{QUERY}}", query)
-
-    for query_placeholder in query_placeholders:
-        template = template.replace(query_placeholder, query)
-
-    return template
-
-
 def get_embedding_function(
 def get_embedding_function(
     embedding_engine,
     embedding_engine,
     embedding_model,
     embedding_model,

+ 15 - 4
backend/open_webui/apps/webui/main.py

@@ -31,6 +31,7 @@ from open_webui.config import (
     DEFAULT_MODELS,
     DEFAULT_MODELS,
     DEFAULT_PROMPT_SUGGESTIONS,
     DEFAULT_PROMPT_SUGGESTIONS,
     DEFAULT_USER_ROLE,
     DEFAULT_USER_ROLE,
+    MODEL_ORDER_LIST,
     ENABLE_COMMUNITY_SHARING,
     ENABLE_COMMUNITY_SHARING,
     ENABLE_LOGIN_FORM,
     ENABLE_LOGIN_FORM,
     ENABLE_MESSAGE_RATING,
     ENABLE_MESSAGE_RATING,
@@ -68,6 +69,7 @@ from open_webui.config import (
 )
 )
 from open_webui.env import (
 from open_webui.env import (
     ENV,
     ENV,
+    SRC_LOG_LEVELS,
     WEBUI_AUTH_TRUSTED_EMAIL_HEADER,
     WEBUI_AUTH_TRUSTED_EMAIL_HEADER,
     WEBUI_AUTH_TRUSTED_NAME_HEADER,
     WEBUI_AUTH_TRUSTED_NAME_HEADER,
 )
 )
@@ -94,6 +96,7 @@ app = FastAPI(
 )
 )
 
 
 log = logging.getLogger(__name__)
 log = logging.getLogger(__name__)
+log.setLevel(SRC_LOG_LEVELS["MAIN"])
 
 
 app.state.config = AppConfig()
 app.state.config = AppConfig()
 
 
@@ -118,6 +121,7 @@ app.state.config.DEFAULT_USER_ROLE = DEFAULT_USER_ROLE
 app.state.config.USER_PERMISSIONS = USER_PERMISSIONS
 app.state.config.USER_PERMISSIONS = USER_PERMISSIONS
 app.state.config.WEBHOOK_URL = WEBHOOK_URL
 app.state.config.WEBHOOK_URL = WEBHOOK_URL
 app.state.config.BANNERS = WEBUI_BANNERS
 app.state.config.BANNERS = WEBUI_BANNERS
+app.state.config.MODEL_ORDER_LIST = MODEL_ORDER_LIST
 
 
 app.state.config.ENABLE_COMMUNITY_SHARING = ENABLE_COMMUNITY_SHARING
 app.state.config.ENABLE_COMMUNITY_SHARING = ENABLE_COMMUNITY_SHARING
 app.state.config.ENABLE_MESSAGE_RATING = ENABLE_MESSAGE_RATING
 app.state.config.ENABLE_MESSAGE_RATING = ENABLE_MESSAGE_RATING
@@ -270,7 +274,9 @@ async def get_pipe_models():
                 log.exception(e)
                 log.exception(e)
                 sub_pipes = []
                 sub_pipes = []
 
 
-            print(sub_pipes)
+            log.debug(
+                f"get_pipe_models: function '{pipe.id}' is a manifold of {sub_pipes}"
+            )
 
 
             for p in sub_pipes:
             for p in sub_pipes:
                 sub_pipe_id = f'{pipe.id}.{p["id"]}'
                 sub_pipe_id = f'{pipe.id}.{p["id"]}'
@@ -280,6 +286,7 @@ async def get_pipe_models():
                     sub_pipe_name = f"{function_module.name}{sub_pipe_name}"
                     sub_pipe_name = f"{function_module.name}{sub_pipe_name}"
 
 
                 pipe_flag = {"type": pipe.type}
                 pipe_flag = {"type": pipe.type}
+
                 pipe_models.append(
                 pipe_models.append(
                     {
                     {
                         "id": sub_pipe_id,
                         "id": sub_pipe_id,
@@ -293,6 +300,10 @@ async def get_pipe_models():
         else:
         else:
             pipe_flag = {"type": "pipe"}
             pipe_flag = {"type": "pipe"}
 
 
+            log.debug(
+                f"get_pipe_models: function '{pipe.id}' is a single pipe {{ 'id': {pipe.id}, 'name': {pipe.name} }}"
+            )
+
             pipe_models.append(
             pipe_models.append(
                 {
                 {
                     "id": pipe.id,
                     "id": pipe.id,
@@ -346,7 +357,7 @@ def get_pipe_id(form_data: dict) -> str:
     pipe_id = form_data["model"]
     pipe_id = form_data["model"]
     if "." in pipe_id:
     if "." in pipe_id:
         pipe_id, _ = pipe_id.split(".", 1)
         pipe_id, _ = pipe_id.split(".", 1)
-    print(pipe_id)
+
     return pipe_id
     return pipe_id
 
 
 
 
@@ -453,7 +464,7 @@ async def generate_function_chat_completion(form_data, user, models: dict = {}):
                     return
                     return
 
 
             except Exception as e:
             except Exception as e:
-                print(f"Error: {e}")
+                log.error(f"Error: {e}")
                 yield f"data: {json.dumps({'error': {'detail':str(e)}})}\n\n"
                 yield f"data: {json.dumps({'error': {'detail':str(e)}})}\n\n"
                 return
                 return
 
 
@@ -483,7 +494,7 @@ async def generate_function_chat_completion(form_data, user, models: dict = {}):
             res = await execute_pipe(pipe, params)
             res = await execute_pipe(pipe, params)
 
 
         except Exception as e:
         except Exception as e:
-            print(f"Error: {e}")
+            log.error(f"Error: {e}")
             return {"error": {"detail": str(e)}}
             return {"error": {"detail": str(e)}}
 
 
         if isinstance(res, StreamingResponse) or isinstance(res, dict):
         if isinstance(res, StreamingResponse) or isinstance(res, dict):

+ 28 - 17
backend/open_webui/apps/webui/routers/configs.py

@@ -34,8 +34,32 @@ async def export_config(user=Depends(get_admin_user)):
     return get_config()
     return get_config()
 
 
 
 
-class SetDefaultModelsForm(BaseModel):
-    models: str
+############################
+# SetDefaultModels
+############################
+class ModelsConfigForm(BaseModel):
+    DEFAULT_MODELS: str
+    MODEL_ORDER_LIST: list[str]
+
+
+@router.get("/models", response_model=ModelsConfigForm)
+async def get_models_config(request: Request, user=Depends(get_admin_user)):
+    return {
+        "DEFAULT_MODELS": request.app.state.config.DEFAULT_MODELS,
+        "MODEL_ORDER_LIST": request.app.state.config.MODEL_ORDER_LIST,
+    }
+
+
+@router.post("/models", response_model=ModelsConfigForm)
+async def set_models_config(
+    request: Request, form_data: ModelsConfigForm, user=Depends(get_admin_user)
+):
+    request.app.state.config.DEFAULT_MODELS = form_data.DEFAULT_MODELS
+    request.app.state.config.MODEL_ORDER_LIST = form_data.MODEL_ORDER_LIST
+    return {
+        "DEFAULT_MODELS": request.app.state.config.DEFAULT_MODELS,
+        "MODEL_ORDER_LIST": request.app.state.config.MODEL_ORDER_LIST,
+    }
 
 
 
 
 class PromptSuggestion(BaseModel):
 class PromptSuggestion(BaseModel):
@@ -47,21 +71,8 @@ class SetDefaultSuggestionsForm(BaseModel):
     suggestions: list[PromptSuggestion]
     suggestions: list[PromptSuggestion]
 
 
 
 
-############################
-# SetDefaultModels
-############################
-
-
-@router.post("/default/models", response_model=str)
-async def set_global_default_models(
-    request: Request, form_data: SetDefaultModelsForm, user=Depends(get_admin_user)
-):
-    request.app.state.config.DEFAULT_MODELS = form_data.models
-    return request.app.state.config.DEFAULT_MODELS
-
-
-@router.post("/default/suggestions", response_model=list[PromptSuggestion])
-async def set_global_default_suggestions(
+@router.post("/suggestions", response_model=list[PromptSuggestion])
+async def set_default_suggestions(
     request: Request,
     request: Request,
     form_data: SetDefaultSuggestionsForm,
     form_data: SetDefaultSuggestionsForm,
     user=Depends(get_admin_user),
     user=Depends(get_admin_user),

+ 11 - 6
backend/open_webui/apps/webui/utils.py

@@ -5,10 +5,15 @@ import sys
 from importlib import util
 from importlib import util
 import types
 import types
 import tempfile
 import tempfile
+import logging
 
 
+from open_webui.env import SRC_LOG_LEVELS
 from open_webui.apps.webui.models.functions import Functions
 from open_webui.apps.webui.models.functions import Functions
 from open_webui.apps.webui.models.tools import Tools
 from open_webui.apps.webui.models.tools import Tools
 
 
+log = logging.getLogger(__name__)
+log.setLevel(SRC_LOG_LEVELS["MAIN"])
+
 
 
 def extract_frontmatter(content):
 def extract_frontmatter(content):
     """
     """
@@ -95,7 +100,7 @@ def load_tools_module_by_id(toolkit_id, content=None):
         # Executing the modified content in the created module's namespace
         # Executing the modified content in the created module's namespace
         exec(content, module.__dict__)
         exec(content, module.__dict__)
         frontmatter = extract_frontmatter(content)
         frontmatter = extract_frontmatter(content)
-        print(f"Loaded module: {module.__name__}")
+        log.info(f"Loaded module: {module.__name__}")
 
 
         # Create and return the object if the class 'Tools' is found in the module
         # Create and return the object if the class 'Tools' is found in the module
         if hasattr(module, "Tools"):
         if hasattr(module, "Tools"):
@@ -103,7 +108,7 @@ def load_tools_module_by_id(toolkit_id, content=None):
         else:
         else:
             raise Exception("No Tools class found in the module")
             raise Exception("No Tools class found in the module")
     except Exception as e:
     except Exception as e:
-        print(f"Error loading module: {toolkit_id}: {e}")
+        log.error(f"Error loading module: {toolkit_id}: {e}")
         del sys.modules[module_name]  # Clean up
         del sys.modules[module_name]  # Clean up
         raise e
         raise e
     finally:
     finally:
@@ -139,7 +144,7 @@ def load_function_module_by_id(function_id, content=None):
         # Execute the modified content in the created module's namespace
         # Execute the modified content in the created module's namespace
         exec(content, module.__dict__)
         exec(content, module.__dict__)
         frontmatter = extract_frontmatter(content)
         frontmatter = extract_frontmatter(content)
-        print(f"Loaded module: {module.__name__}")
+        log.info(f"Loaded module: {module.__name__}")
 
 
         # Create appropriate object based on available class type in the module
         # Create appropriate object based on available class type in the module
         if hasattr(module, "Pipe"):
         if hasattr(module, "Pipe"):
@@ -151,7 +156,7 @@ def load_function_module_by_id(function_id, content=None):
         else:
         else:
             raise Exception("No Function class found in the module")
             raise Exception("No Function class found in the module")
     except Exception as e:
     except Exception as e:
-        print(f"Error loading module: {function_id}: {e}")
+        log.error(f"Error loading module: {function_id}: {e}")
         del sys.modules[module_name]  # Cleanup by removing the module in case of error
         del sys.modules[module_name]  # Cleanup by removing the module in case of error
 
 
         Functions.update_function_by_id(function_id, {"is_active": False})
         Functions.update_function_by_id(function_id, {"is_active": False})
@@ -164,7 +169,7 @@ def install_frontmatter_requirements(requirements):
     if requirements:
     if requirements:
         req_list = [req.strip() for req in requirements.split(",")]
         req_list = [req.strip() for req in requirements.split(",")]
         for req in req_list:
         for req in req_list:
-            print(f"Installing requirement: {req}")
+            log.info(f"Installing requirement: {req}")
             subprocess.check_call([sys.executable, "-m", "pip", "install", req])
             subprocess.check_call([sys.executable, "-m", "pip", "install", req])
     else:
     else:
-        print("No requirements found in frontmatter.")
+        log.info("No requirements found in frontmatter.")

+ 16 - 9
backend/open_webui/config.py

@@ -740,6 +740,12 @@ DEFAULT_PROMPT_SUGGESTIONS = PersistentConfig(
     ],
     ],
 )
 )
 
 
+MODEL_ORDER_LIST = PersistentConfig(
+    "MODEL_ORDER_LIST",
+    "ui.model_order_list",
+    [],
+)
+
 DEFAULT_USER_ROLE = PersistentConfig(
 DEFAULT_USER_ROLE = PersistentConfig(
     "DEFAULT_USER_ROLE",
     "DEFAULT_USER_ROLE",
     "ui.default_user_role",
     "ui.default_user_role",
@@ -969,19 +975,20 @@ QUERY_GENERATION_PROMPT_TEMPLATE = PersistentConfig(
 )
 )
 
 
 DEFAULT_QUERY_GENERATION_PROMPT_TEMPLATE = """### Task:
 DEFAULT_QUERY_GENERATION_PROMPT_TEMPLATE = """### Task:
-Based on the chat history, determine whether a search is necessary, and if so, generate a 1-3 broad search queries to retrieve comprehensive and updated information. If no search is required, return an empty list.
+Analyze the chat history to determine the necessity of generating search queries. By default, **prioritize generating 1-3 broad and relevant search queries** unless it is absolutely certain that no additional information is required. The aim is to retrieve comprehensive, updated, and valuable information even with minimal uncertainty. If no search is unequivocally needed, return an empty list.
 
 
 ### Guidelines:
 ### Guidelines:
-- Respond exclusively with a JSON object.
-- If a search query is needed, return an object like: { "queries": ["query1", "query2"] } where each query is distinct and concise.
-- If no search query is necessary, output should be: { "queries": [] }
-- Default to suggesting a search query to ensure accurate and updated information, unless it is definitively clear no search is required.
-- Be concise, focusing strictly on composing search queries with no additional commentary or text.
-- When in doubt, prefer to suggest a search for comprehensiveness.
-- Today's date is: {{CURRENT_DATE}}
+- Respond **EXCLUSIVELY** with a JSON object. Any form of extra commentary, explanation, or additional text is strictly prohibited.
+- When generating search queries, respond in the format: { "queries": ["query1", "query2"] }, ensuring each query is distinct, concise, and relevant to the topic.
+- If and only if it is entirely certain that no useful results can be retrieved by a search, return: { "queries": [] }.
+- Err on the side of suggesting search queries if there is **any chance** they might provide useful or updated information.
+- Be concise and focused on composing high-quality search queries, avoiding unnecessary elaboration, commentary, or assumptions.
+- Assume today's date is: {{CURRENT_DATE}}.
+- Always prioritize providing actionable and broad queries that maximize informational coverage.
 
 
 ### Output:
 ### Output:
-JSON format: {
+Strictly return in JSON format: 
+{
   "queries": ["query1", "query2"]
   "queries": ["query1", "query2"]
 }
 }
 
 

+ 52 - 32
backend/open_webui/main.py

@@ -49,7 +49,9 @@ from open_webui.apps.openai.main import (
     get_all_models_responses as get_openai_models_responses,
     get_all_models_responses as get_openai_models_responses,
 )
 )
 from open_webui.apps.retrieval.main import app as retrieval_app
 from open_webui.apps.retrieval.main import app as retrieval_app
-from open_webui.apps.retrieval.utils import get_sources_from_files, rag_template
+from open_webui.apps.retrieval.utils import get_sources_from_files
+
+
 from open_webui.apps.socket.main import (
 from open_webui.apps.socket.main import (
     app as socket_app,
     app as socket_app,
     periodic_usage_pool_cleanup,
     periodic_usage_pool_cleanup,
@@ -122,11 +124,12 @@ from open_webui.utils.response import (
 )
 )
 from open_webui.utils.security_headers import SecurityHeadersMiddleware
 from open_webui.utils.security_headers import SecurityHeadersMiddleware
 from open_webui.utils.task import (
 from open_webui.utils.task import (
-    moa_response_generation_template,
-    tags_generation_template,
+    rag_template,
+    title_generation_template,
     query_generation_template,
     query_generation_template,
+    tags_generation_template,
     emoji_generation_template,
     emoji_generation_template,
-    title_generation_template,
+    moa_response_generation_template,
     tools_function_calling_generation_template,
     tools_function_calling_generation_template,
 )
 )
 from open_webui.utils.tools import get_tools
 from open_webui.utils.tools import get_tools
@@ -539,8 +542,6 @@ async def chat_completion_files_handler(
         if len(queries) == 0:
         if len(queries) == 0:
             queries = [get_last_user_message(body["messages"])]
             queries = [get_last_user_message(body["messages"])]
 
 
-        print(f"{queries=}")
-
         sources = get_sources_from_files(
         sources = get_sources_from_files(
             files=files,
             files=files,
             queries=queries,
             queries=queries,
@@ -970,7 +971,7 @@ app.add_middleware(SecurityHeadersMiddleware)
 @app.middleware("http")
 @app.middleware("http")
 async def commit_session_after_request(request: Request, call_next):
 async def commit_session_after_request(request: Request, call_next):
     response = await call_next(request)
     response = await call_next(request)
-    log.debug("Commit session after request")
+    # log.debug("Commit session after request")
     Session.commit()
     Session.commit()
     return response
     return response
 
 
@@ -1177,6 +1178,8 @@ async def get_all_models():
             model["actions"].extend(
             model["actions"].extend(
                 get_action_items_from_module(action_function, function_module)
                 get_action_items_from_module(action_function, function_module)
             )
             )
+    log.debug(f"get_all_models() returned {len(models)} models")
+
     return models
     return models
 
 
 
 
@@ -1191,6 +1194,14 @@ async def get_models(user=Depends(get_verified_user)):
         if "pipeline" not in model or model["pipeline"].get("type", None) != "filter"
         if "pipeline" not in model or model["pipeline"].get("type", None) != "filter"
     ]
     ]
 
 
+    model_order_list = webui_app.state.config.MODEL_ORDER_LIST
+    if model_order_list:
+        model_order_dict = {model_id: i for i, model_id in enumerate(model_order_list)}
+        # Sort models by order list priority, with fallback for those not in the list
+        models.sort(
+            key=lambda x: (model_order_dict.get(x["id"], float("inf")), x["name"])
+        )
+
     # Filter out models that the user does not have access to
     # Filter out models that the user does not have access to
     if user.role == "user":
     if user.role == "user":
         filtered_models = []
         filtered_models = []
@@ -1214,6 +1225,10 @@ async def get_models(user=Depends(get_verified_user)):
                     filtered_models.append(model)
                     filtered_models.append(model)
         models = filtered_models
         models = filtered_models
 
 
+    log.debug(
+        f"/api/models returned filtered models accessible to the user: {json.dumps([model['id'] for model in models])}"
+    )
+
     return {"data": models}
     return {"data": models}
 
 
 
 
@@ -1704,7 +1719,6 @@ async def update_task_config(form_data: TaskConfigForm, user=Depends(get_admin_u
 
 
 @app.post("/api/task/title/completions")
 @app.post("/api/task/title/completions")
 async def generate_title(form_data: dict, user=Depends(get_verified_user)):
 async def generate_title(form_data: dict, user=Depends(get_verified_user)):
-    print("generate_title")
 
 
     model_list = await get_all_models()
     model_list = await get_all_models()
     models = {model["id"]: model for model in model_list}
     models = {model["id"]: model for model in model_list}
@@ -1725,9 +1739,9 @@ async def generate_title(form_data: dict, user=Depends(get_verified_user)):
         models,
         models,
     )
     )
 
 
-    print(task_model_id)
-
-    model = models[task_model_id]
+    log.debug(
+        f"generating chat title using model {task_model_id} for user {user.email} "
+    )
 
 
     if app.state.config.TITLE_GENERATION_PROMPT_TEMPLATE != "":
     if app.state.config.TITLE_GENERATION_PROMPT_TEMPLATE != "":
         template = app.state.config.TITLE_GENERATION_PROMPT_TEMPLATE
         template = app.state.config.TITLE_GENERATION_PROMPT_TEMPLATE
@@ -1766,10 +1780,12 @@ Artificial Intelligence in Healthcare
                 "max_completion_tokens": 50,
                 "max_completion_tokens": 50,
             }
             }
         ),
         ),
-        "chat_id": form_data.get("chat_id", None),
-        "metadata": {"task": str(TASKS.TITLE_GENERATION), "task_body": form_data},
+        "metadata": {
+            "task": str(TASKS.TITLE_GENERATION),
+            "task_body": form_data,
+            "chat_id": form_data.get("chat_id", None),
+        },
     }
     }
-    log.debug(payload)
 
 
     # Handle pipeline filters
     # Handle pipeline filters
     try:
     try:
@@ -1793,7 +1809,7 @@ Artificial Intelligence in Healthcare
 
 
 @app.post("/api/task/tags/completions")
 @app.post("/api/task/tags/completions")
 async def generate_chat_tags(form_data: dict, user=Depends(get_verified_user)):
 async def generate_chat_tags(form_data: dict, user=Depends(get_verified_user)):
-    print("generate_chat_tags")
+
     if not app.state.config.ENABLE_TAGS_GENERATION:
     if not app.state.config.ENABLE_TAGS_GENERATION:
         return JSONResponse(
         return JSONResponse(
             status_code=status.HTTP_200_OK,
             status_code=status.HTTP_200_OK,
@@ -1818,7 +1834,10 @@ async def generate_chat_tags(form_data: dict, user=Depends(get_verified_user)):
         app.state.config.TASK_MODEL_EXTERNAL,
         app.state.config.TASK_MODEL_EXTERNAL,
         models,
         models,
     )
     )
-    print(task_model_id)
+
+    log.debug(
+        f"generating chat tags using model {task_model_id} for user {user.email} "
+    )
 
 
     if app.state.config.TAGS_GENERATION_PROMPT_TEMPLATE != "":
     if app.state.config.TAGS_GENERATION_PROMPT_TEMPLATE != "":
         template = app.state.config.TAGS_GENERATION_PROMPT_TEMPLATE
         template = app.state.config.TAGS_GENERATION_PROMPT_TEMPLATE
@@ -1849,9 +1868,12 @@ JSON format: { "tags": ["tag1", "tag2", "tag3"] }
         "model": task_model_id,
         "model": task_model_id,
         "messages": [{"role": "user", "content": content}],
         "messages": [{"role": "user", "content": content}],
         "stream": False,
         "stream": False,
-        "metadata": {"task": str(TASKS.TAGS_GENERATION), "task_body": form_data},
+        "metadata": {
+            "task": str(TASKS.TAGS_GENERATION),
+            "task_body": form_data,
+            "chat_id": form_data.get("chat_id", None),
+        },
     }
     }
-    log.debug(payload)
 
 
     # Handle pipeline filters
     # Handle pipeline filters
     try:
     try:
@@ -1875,7 +1897,7 @@ JSON format: { "tags": ["tag1", "tag2", "tag3"] }
 
 
 @app.post("/api/task/queries/completions")
 @app.post("/api/task/queries/completions")
 async def generate_queries(form_data: dict, user=Depends(get_verified_user)):
 async def generate_queries(form_data: dict, user=Depends(get_verified_user)):
-    print("generate_queries")
+
     type = form_data.get("type")
     type = form_data.get("type")
     if type == "web_search":
     if type == "web_search":
         if not app.state.config.ENABLE_SEARCH_QUERY_GENERATION:
         if not app.state.config.ENABLE_SEARCH_QUERY_GENERATION:
@@ -1908,9 +1930,10 @@ async def generate_queries(form_data: dict, user=Depends(get_verified_user)):
         app.state.config.TASK_MODEL_EXTERNAL,
         app.state.config.TASK_MODEL_EXTERNAL,
         models,
         models,
     )
     )
-    print(task_model_id)
 
 
-    model = models[task_model_id]
+    log.debug(
+        f"generating {type} queries using model {task_model_id} for user {user.email}"
+    )
 
 
     if app.state.config.QUERY_GENERATION_PROMPT_TEMPLATE != "":
     if app.state.config.QUERY_GENERATION_PROMPT_TEMPLATE != "":
         template = app.state.config.QUERY_GENERATION_PROMPT_TEMPLATE
         template = app.state.config.QUERY_GENERATION_PROMPT_TEMPLATE
@@ -1925,9 +1948,12 @@ async def generate_queries(form_data: dict, user=Depends(get_verified_user)):
         "model": task_model_id,
         "model": task_model_id,
         "messages": [{"role": "user", "content": content}],
         "messages": [{"role": "user", "content": content}],
         "stream": False,
         "stream": False,
-        "metadata": {"task": str(TASKS.QUERY_GENERATION), "task_body": form_data},
+        "metadata": {
+            "task": str(TASKS.QUERY_GENERATION),
+            "task_body": form_data,
+            "chat_id": form_data.get("chat_id", None),
+        },
     }
     }
-    log.debug(payload)
 
 
     # Handle pipeline filters
     # Handle pipeline filters
     try:
     try:
@@ -1951,7 +1977,6 @@ async def generate_queries(form_data: dict, user=Depends(get_verified_user)):
 
 
 @app.post("/api/task/emoji/completions")
 @app.post("/api/task/emoji/completions")
 async def generate_emoji(form_data: dict, user=Depends(get_verified_user)):
 async def generate_emoji(form_data: dict, user=Depends(get_verified_user)):
-    print("generate_emoji")
 
 
     model_list = await get_all_models()
     model_list = await get_all_models()
     models = {model["id"]: model for model in model_list}
     models = {model["id"]: model for model in model_list}
@@ -1971,9 +1996,8 @@ async def generate_emoji(form_data: dict, user=Depends(get_verified_user)):
         app.state.config.TASK_MODEL_EXTERNAL,
         app.state.config.TASK_MODEL_EXTERNAL,
         models,
         models,
     )
     )
-    print(task_model_id)
 
 
-    model = models[task_model_id]
+    log.debug(f"generating emoji using model {task_model_id} for user {user.email} ")
 
 
     template = '''
     template = '''
 Your task is to reflect the speaker's likely facial expression through a fitting emoji. Interpret emotions from the message and reflect their facial expression using fitting, diverse emojis (e.g., 😊, 😢, 😡, 😱).
 Your task is to reflect the speaker's likely facial expression through a fitting emoji. Interpret emotions from the message and reflect their facial expression using fitting, diverse emojis (e.g., 😊, 😢, 😡, 😱).
@@ -2003,7 +2027,6 @@ Message: """{{prompt}}"""
         "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": {"task": str(TASKS.EMOJI_GENERATION), "task_body": form_data},
     }
     }
-    log.debug(payload)
 
 
     # Handle pipeline filters
     # Handle pipeline filters
     try:
     try:
@@ -2027,7 +2050,6 @@ Message: """{{prompt}}"""
 
 
 @app.post("/api/task/moa/completions")
 @app.post("/api/task/moa/completions")
 async def generate_moa_response(form_data: dict, user=Depends(get_verified_user)):
 async def generate_moa_response(form_data: dict, user=Depends(get_verified_user)):
-    print("generate_moa_response")
 
 
     model_list = await get_all_models()
     model_list = await get_all_models()
     models = {model["id"]: model for model in model_list}
     models = {model["id"]: model for model in model_list}
@@ -2047,9 +2069,8 @@ async def generate_moa_response(form_data: dict, user=Depends(get_verified_user)
         app.state.config.TASK_MODEL_EXTERNAL,
         app.state.config.TASK_MODEL_EXTERNAL,
         models,
         models,
     )
     )
-    print(task_model_id)
 
 
-    model = models[task_model_id]
+    log.debug(f"generating MOA model {task_model_id} for user {user.email} ")
 
 
     template = """You have been provided with a set of responses from various models to the latest user query: "{{prompt}}"
     template = """You have been provided with a set of responses from various models to the latest user query: "{{prompt}}"
 
 
@@ -2073,7 +2094,6 @@ Responses from models: {{responses}}"""
             "task_body": form_data,
             "task_body": form_data,
         },
         },
     }
     }
-    log.debug(payload)
 
 
     try:
     try:
         payload = filter_pipeline(payload, user, models)
         payload = filter_pipeline(payload, user, models)
@@ -2108,7 +2128,7 @@ Responses from models: {{responses}}"""
 async def get_pipelines_list(user=Depends(get_admin_user)):
 async def get_pipelines_list(user=Depends(get_admin_user)):
     responses = await get_openai_models_responses()
     responses = await get_openai_models_responses()
 
 
-    print(responses)
+    log.debug(f"get_pipelines_list: get_openai_models_responses returned {responses}")
     urlIdxs = [
     urlIdxs = [
         idx
         idx
         for idx, response in enumerate(responses)
         for idx, response in enumerate(responses)

+ 47 - 0
backend/open_webui/utils/task.py

@@ -1,11 +1,20 @@
+import logging
 import math
 import math
 import re
 import re
 from datetime import datetime
 from datetime import datetime
 from typing import Optional
 from typing import Optional
+import uuid
 
 
 
 
 from open_webui.utils.misc import get_last_user_message, get_messages_content
 from open_webui.utils.misc import get_last_user_message, get_messages_content
 
 
+from open_webui.env import SRC_LOG_LEVELS
+from open_webui.config import DEFAULT_RAG_TEMPLATE
+
+
+log = logging.getLogger(__name__)
+log.setLevel(SRC_LOG_LEVELS["RAG"])
+
 
 
 def prompt_template(
 def prompt_template(
     template: str, user_name: Optional[str] = None, user_location: Optional[str] = None
     template: str, user_name: Optional[str] = None, user_location: Optional[str] = None
@@ -110,6 +119,44 @@ def replace_messages_variable(template: str, messages: list[str]) -> str:
 # {{prompt:middletruncate:8000}}
 # {{prompt:middletruncate:8000}}
 
 
 
 
+def rag_template(template: str, context: str, query: str):
+    if template == "":
+        template = DEFAULT_RAG_TEMPLATE
+
+    if "[context]" not in template and "{{CONTEXT}}" not in template:
+        log.debug(
+            "WARNING: The RAG template does not contain the '[context]' or '{{CONTEXT}}' placeholder."
+        )
+
+    if "<context>" in context and "</context>" in context:
+        log.debug(
+            "WARNING: Potential prompt injection attack: the RAG "
+            "context contains '<context>' and '</context>'. This might be "
+            "nothing, or the user might be trying to hack something."
+        )
+
+    query_placeholders = []
+    if "[query]" in context:
+        query_placeholder = "{{QUERY" + str(uuid.uuid4()) + "}}"
+        template = template.replace("[query]", query_placeholder)
+        query_placeholders.append(query_placeholder)
+
+    if "{{QUERY}}" in context:
+        query_placeholder = "{{QUERY" + str(uuid.uuid4()) + "}}"
+        template = template.replace("{{QUERY}}", query_placeholder)
+        query_placeholders.append(query_placeholder)
+
+    template = template.replace("[context]", context)
+    template = template.replace("{{CONTEXT}}", context)
+    template = template.replace("[query]", query)
+    template = template.replace("{{QUERY}}", query)
+
+    for query_placeholder in query_placeholders:
+        template = template.replace(query_placeholder, query)
+
+    return template
+
+
 def title_generation_template(
 def title_generation_template(
     template: str, messages: list[dict], user: Optional[dict] = None
     template: str, messages: list[dict], user: Optional[dict] = None
 ) -> str:
 ) -> str:

+ 32 - 1
backend/open_webui/utils/tools.py

@@ -90,6 +90,32 @@ def get_tools(
     return tools_dict
     return tools_dict
 
 
 
 
+def parse_description(docstring: str | None) -> str:
+    """
+    Parse a function's docstring to extract the description.
+
+    Args:
+        docstring (str): The docstring to parse.
+
+    Returns:
+        str: The description.
+    """
+
+    if not docstring:
+        return ""
+
+    lines = [line.strip() for line in docstring.strip().split("\n")]
+    description_lines: list[str] = []
+
+    for line in lines:
+        if re.match(r":param", line) or re.match(r":return", line):
+            break
+
+        description_lines.append(line)
+
+    return "\n".join(description_lines)
+
+
 def parse_docstring(docstring):
 def parse_docstring(docstring):
     """
     """
     Parse a function's docstring to extract parameter descriptions in reST format.
     Parse a function's docstring to extract parameter descriptions in reST format.
@@ -138,6 +164,8 @@ def function_to_pydantic_model(func: Callable) -> type[BaseModel]:
     docstring = func.__doc__
     docstring = func.__doc__
     descriptions = parse_docstring(docstring)
     descriptions = parse_docstring(docstring)
 
 
+    tool_description = parse_description(docstring)
+
     field_defs = {}
     field_defs = {}
     for name, param in parameters.items():
     for name, param in parameters.items():
         type_hint = type_hints.get(name, Any)
         type_hint = type_hints.get(name, Any)
@@ -148,7 +176,10 @@ def function_to_pydantic_model(func: Callable) -> type[BaseModel]:
             continue
             continue
         field_defs[name] = type_hint, Field(default_value, description=description)
         field_defs[name] = type_hint, Field(default_value, description=description)
 
 
-    return create_model(func.__name__, **field_defs)
+    model = create_model(func.__name__, **field_defs)
+    model.__doc__ = tool_description
+
+    return model
 
 
 
 
 def get_callable_attributes(tool: object) -> list[Callable]:
 def get_callable_attributes(tool: object) -> list[Callable]:

+ 1 - 0
backend/requirements.txt

@@ -14,6 +14,7 @@ requests==2.32.3
 aiohttp==3.10.8
 aiohttp==3.10.8
 async-timeout
 async-timeout
 aiocache
 aiocache
+aiofiles
 
 
 sqlalchemy==2.0.32
 sqlalchemy==2.0.32
 alembic==1.13.2
 alembic==1.13.2

+ 2 - 2
package-lock.json

@@ -1,12 +1,12 @@
 {
 {
 	"name": "open-webui",
 	"name": "open-webui",
-	"version": "0.4.4",
+	"version": "0.4.5",
 	"lockfileVersion": 3,
 	"lockfileVersion": 3,
 	"requires": true,
 	"requires": true,
 	"packages": {
 	"packages": {
 		"": {
 		"": {
 			"name": "open-webui",
 			"name": "open-webui",
-			"version": "0.4.4",
+			"version": "0.4.5",
 			"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",

+ 1 - 1
package.json

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

+ 1 - 0
pyproject.toml

@@ -22,6 +22,7 @@ dependencies = [
     "aiohttp==3.10.8",
     "aiohttp==3.10.8",
     "async-timeout",
     "async-timeout",
     "aiocache",
     "aiocache",
+    "aiofiles",
 
 
     "sqlalchemy==2.0.32",
     "sqlalchemy==2.0.32",
     "alembic==1.13.2",
     "alembic==1.13.2",

+ 9 - 0
src/app.css

@@ -231,6 +231,15 @@ input[type='number'] {
 	@apply dark:bg-gray-800 bg-gray-100;
 	@apply dark:bg-gray-800 bg-gray-100;
 }
 }
 
 
+.tiptap p code {
+	color: #eb5757;
+	border-width: 0px;
+	padding: 3px 8px;
+	font-size: 0.8em;
+	font-weight: 600;
+	@apply rounded-md dark:bg-gray-800 bg-gray-100 mx-0.5;
+}
+
 /* Code styling */
 /* Code styling */
 .hljs-comment,
 .hljs-comment,
 .hljs-quote {
 .hljs-quote {

+ 31 - 4
src/lib/apis/configs/index.ts

@@ -58,17 +58,44 @@ export const exportConfig = async (token: string) => {
 	return res;
 	return res;
 };
 };
 
 
-export const setDefaultModels = async (token: string, models: string) => {
+export const getModelsConfig = async (token: string) => {
 	let error = null;
 	let error = null;
 
 
-	const res = await fetch(`${WEBUI_API_BASE_URL}/configs/default/models`, {
+	const res = await fetch(`${WEBUI_API_BASE_URL}/configs/models`, {
+		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 setModelsConfig = async (token: string, config: object) => {
+	let error = null;
+
+	const res = await fetch(`${WEBUI_API_BASE_URL}/configs/models`, {
 		method: 'POST',
 		method: 'POST',
 		headers: {
 		headers: {
 			'Content-Type': 'application/json',
 			'Content-Type': 'application/json',
 			Authorization: `Bearer ${token}`
 			Authorization: `Bearer ${token}`
 		},
 		},
 		body: JSON.stringify({
 		body: JSON.stringify({
-			models: models
+			...config
 		})
 		})
 	})
 	})
 		.then(async (res) => {
 		.then(async (res) => {
@@ -91,7 +118,7 @@ export const setDefaultModels = async (token: string, models: string) => {
 export const setDefaultPromptSuggestions = async (token: string, promptSuggestions: string) => {
 export const setDefaultPromptSuggestions = async (token: string, promptSuggestions: string) => {
 	let error = null;
 	let error = null;
 
 
-	const res = await fetch(`${WEBUI_API_BASE_URL}/configs/default/suggestions`, {
+	const res = await fetch(`${WEBUI_API_BASE_URL}/configs/suggestions`, {
 		method: 'POST',
 		method: 'POST',
 		headers: {
 		headers: {
 			'Content-Type': 'application/json',
 			'Content-Type': 'application/json',

+ 3 - 26
src/lib/apis/index.ts

@@ -25,26 +25,6 @@ export const getModels = async (token: string = '', base: boolean = false) => {
 	}
 	}
 
 
 	let models = res?.data ?? [];
 	let models = res?.data ?? [];
-	models = models
-		.filter((models) => models)
-		// Sort the models
-		.sort((a, b) => {
-			// Compare case-insensitively by name for models without position property
-			const lowerA = a.name.toLowerCase();
-			const lowerB = b.name.toLowerCase();
-
-			if (lowerA < lowerB) return -1;
-			if (lowerA > lowerB) return 1;
-
-			// If same case-insensitively, sort by original strings,
-			// lowercase will come before uppercase due to ASCII values
-			if (a.name < b.name) return -1;
-			if (a.name > b.name) return 1;
-
-			return 0; // They are equal
-		});
-
-	console.log(models);
 	return models;
 	return models;
 };
 };
 
 
@@ -391,16 +371,13 @@ export const generateQueries = async (
 		// Step 1: Safely extract the response string
 		// Step 1: Safely extract the response string
 		const response = res?.choices[0]?.message?.content ?? '';
 		const response = res?.choices[0]?.message?.content ?? '';
 
 
-		// Step 2: Attempt to fix common JSON format issues like single quotes
-		const sanitizedResponse = response.replace(/['‘’`]/g, '"'); // Convert single quotes to double quotes for valid JSON
-
 		// Step 3: Find the relevant JSON block within the response
 		// Step 3: Find the relevant JSON block within the response
-		const jsonStartIndex = sanitizedResponse.indexOf('{');
-		const jsonEndIndex = sanitizedResponse.lastIndexOf('}');
+		const jsonStartIndex = response.indexOf('{');
+		const jsonEndIndex = response.lastIndexOf('}');
 
 
 		// Step 4: Check if we found a valid JSON block (with both `{` and `}`)
 		// Step 4: Check if we found a valid JSON block (with both `{` and `}`)
 		if (jsonStartIndex !== -1 && jsonEndIndex !== -1) {
 		if (jsonStartIndex !== -1 && jsonEndIndex !== -1) {
-			const jsonResponse = sanitizedResponse.substring(jsonStartIndex, jsonEndIndex + 1);
+			const jsonResponse = response.substring(jsonStartIndex, jsonEndIndex + 1);
 
 
 			// Step 5: Parse the JSON block
 			// Step 5: Parse the JSON block
 			const parsed = JSON.parse(jsonResponse);
 			const parsed = JSON.parse(jsonResponse);

+ 1 - 1
src/lib/components/admin/Functions.svelte

@@ -219,7 +219,7 @@
 </div>
 </div>
 
 
 <div class="mb-5">
 <div class="mb-5">
-	{#each filteredItems as func}
+	{#each filteredItems as func (func.id)}
 		<div
 		<div
 			class=" flex space-x-4 cursor-pointer w-full px-3 py-2 dark:hover:bg-white/5 hover:bg-black/5 rounded-xl"
 			class=" flex space-x-4 cursor-pointer w-full px-3 py-2 dark:hover:bg-white/5 hover:bg-black/5 rounded-xl"
 		>
 		>

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

@@ -5,6 +5,7 @@
 
 
 	const dispatch = createEventDispatcher();
 	const dispatch = createEventDispatcher();
 	import { getModels } from '$lib/apis';
 	import { getModels } from '$lib/apis';
+	import { getConfig, updateConfig } from '$lib/apis/evaluations';
 
 
 	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';
@@ -12,7 +13,6 @@
 	import Plus from '$lib/components/icons/Plus.svelte';
 	import Plus from '$lib/components/icons/Plus.svelte';
 	import Model from './Evaluations/Model.svelte';
 	import Model from './Evaluations/Model.svelte';
 	import ArenaModelModal from './Evaluations/ArenaModelModal.svelte';
 	import ArenaModelModal from './Evaluations/ArenaModelModal.svelte';
-	import { getConfig, updateConfig } from '$lib/apis/evaluations';
 
 
 	const i18n = getContext('i18n');
 	const i18n = getContext('i18n');
 
 
@@ -27,6 +27,7 @@
 
 
 		if (config) {
 		if (config) {
 			toast.success('Settings saved successfully');
 			toast.success('Settings saved successfully');
+			models.set(await getModels(localStorage.token));
 		}
 		}
 	};
 	};
 
 

+ 2 - 2
src/lib/components/admin/Settings/Evaluations/ArenaModelModal.svelte

@@ -375,7 +375,7 @@
 					<div class="flex justify-end pt-3 text-sm font-medium gap-1.5">
 					<div class="flex justify-end pt-3 text-sm font-medium gap-1.5">
 						{#if edit}
 						{#if edit}
 							<button
 							<button
-								class="px-3.5 py-1.5 text-sm font-medium dark:bg-black dark:hover:bg-gray-900 dark:text-white bg-white text-black hover:bg-gray-100 transition rounded-full flex flex-row space-x-1 items-center"
+								class="px-3.5 py-1.5 text-sm font-medium dark:bg-black dark:hover:bg-gray-950 dark:text-white bg-white text-black hover:bg-gray-100 transition rounded-full flex flex-row space-x-1 items-center"
 								type="button"
 								type="button"
 								on:click={() => {
 								on:click={() => {
 									dispatch('delete', model);
 									dispatch('delete', model);
@@ -387,7 +387,7 @@
 						{/if}
 						{/if}
 
 
 						<button
 						<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 flex flex-row space-x-1 items-center {loading
+							class="px-3.5 py-1.5 text-sm font-medium bg-black hover:bg-gray-950 text-white dark:bg-white dark:text-black dark:hover:bg-gray-100 transition rounded-full flex flex-row space-x-1 items-center {loading
 								? ' cursor-not-allowed'
 								? ' cursor-not-allowed'
 								: ''}"
 								: ''}"
 							type="submit"
 							type="submit"

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

@@ -24,6 +24,8 @@
 	import ModelEditor from '$lib/components/workspace/Models/ModelEditor.svelte';
 	import ModelEditor from '$lib/components/workspace/Models/ModelEditor.svelte';
 	import { toast } from 'svelte-sonner';
 	import { toast } from 'svelte-sonner';
 	import ConfirmDialog from '$lib/components/common/ConfirmDialog.svelte';
 	import ConfirmDialog from '$lib/components/common/ConfirmDialog.svelte';
+	import Cog6 from '$lib/components/icons/Cog6.svelte';
+	import ConfigureModelsModal from './Models/ConfigureModelsModal.svelte';
 
 
 	let importFiles;
 	let importFiles;
 	let modelsImportInputElement: HTMLInputElement;
 	let modelsImportInputElement: HTMLInputElement;
@@ -35,12 +37,20 @@
 
 
 	let filteredModels = [];
 	let filteredModels = [];
 	let selectedModelId = null;
 	let selectedModelId = null;
-	let showResetModal = false;
+
+	let showConfigModal = false;
 
 
 	$: if (models) {
 	$: if (models) {
-		filteredModels = models.filter(
-			(m) => searchValue === '' || m.name.toLowerCase().includes(searchValue.toLowerCase())
-		);
+		filteredModels = models
+			.filter((m) => searchValue === '' || m.name.toLowerCase().includes(searchValue.toLowerCase()))
+			.sort((a, b) => {
+				// Check if either model is inactive and push them to the bottom
+				if ((a.is_active ?? true) !== (b.is_active ?? true)) {
+					return (b.is_active ?? true) - (a.is_active ?? true);
+				}
+				// If both models' active states are the same, sort alphabetically
+				return a.name.localeCompare(b.name);
+			});
 	}
 	}
 
 
 	let searchValue = '';
 	let searchValue = '';
@@ -114,12 +124,11 @@
 			}).catch((error) => {
 			}).catch((error) => {
 				return null;
 				return null;
 			});
 			});
-
-			await init();
 		} else {
 		} else {
 			await toggleModelById(localStorage.token, model.id);
 			await toggleModelById(localStorage.token, model.id);
 		}
 		}
 
 
+		await init();
 		_models.set(await getModels(localStorage.token));
 		_models.set(await getModels(localStorage.token));
 	};
 	};
 
 
@@ -128,18 +137,7 @@
 	});
 	});
 </script>
 </script>
 
 
-<ConfirmDialog
-	title={$i18n.t('Delete All Models')}
-	message={$i18n.t('This will delete all models including custom models and cannot be undone.')}
-	bind:show={showResetModal}
-	onConfirm={async () => {
-		const res = deleteAllModels(localStorage.token);
-		if (res) {
-			toast.success($i18n.t('All models deleted successfully'));
-			init();
-		}
-	}}
-/>
+<ConfigureModelsModal bind:show={showConfigModal} {init} />
 
 
 {#if models !== null}
 {#if models !== null}
 	{#if selectedModelId === null}
 	{#if selectedModelId === null}
@@ -154,17 +152,15 @@
 				</div>
 				</div>
 
 
 				<div>
 				<div>
-					<Tooltip content={$i18n.t('This will delete all models including custom models')}>
+					<Tooltip content={$i18n.t('Configure')}>
 						<button
 						<button
 							class=" px-2.5 py-1 rounded-full flex gap-1 items-center"
 							class=" px-2.5 py-1 rounded-full flex gap-1 items-center"
 							type="button"
 							type="button"
 							on:click={() => {
 							on:click={() => {
-								showResetModal = true;
+								showConfigModal = true;
 							}}
 							}}
 						>
 						>
-							<div class="text-xs flex-shrink-0">
-								{$i18n.t('Reset')}
-							</div>
+							<Cog6 />
 						</button>
 						</button>
 					</Tooltip>
 					</Tooltip>
 				</div>
 				</div>
@@ -186,7 +182,7 @@
 
 
 		<div class=" my-2 mb-5" id="model-list">
 		<div class=" my-2 mb-5" id="model-list">
 			{#if models.length > 0}
 			{#if models.length > 0}
-				{#each filteredModels as model, modelIdx (`${model.id}-${modelIdx}`)}
+				{#each filteredModels as model, modelIdx (model.id)}
 					<div
 					<div
 						class=" flex space-x-4 cursor-pointer w-full px-3 py-2 dark:hover:bg-white/5 hover:bg-black/5 rounded-lg transition"
 						class=" flex space-x-4 cursor-pointer w-full px-3 py-2 dark:hover:bg-white/5 hover:bg-black/5 rounded-lg transition"
 						id="model-item-{model.id}"
 						id="model-item-{model.id}"

+ 258 - 0
src/lib/components/admin/Settings/Models/ConfigureModelsModal.svelte

@@ -0,0 +1,258 @@
+<script>
+	import { toast } from 'svelte-sonner';
+
+	import { createEventDispatcher, getContext, onMount } from 'svelte';
+	const i18n = getContext('i18n');
+	const dispatch = createEventDispatcher();
+
+	import { models } from '$lib/stores';
+	import { deleteAllModels } from '$lib/apis/models';
+
+	import Modal from '$lib/components/common/Modal.svelte';
+	import ConfirmDialog from '$lib/components/common/ConfirmDialog.svelte';
+	import Tooltip from '$lib/components/common/Tooltip.svelte';
+	import ModelList from './ModelList.svelte';
+	import { getModelsConfig, setModelsConfig } from '$lib/apis/configs';
+	import Spinner from '$lib/components/common/Spinner.svelte';
+	import Minus from '$lib/components/icons/Minus.svelte';
+	import Plus from '$lib/components/icons/Plus.svelte';
+
+	export let show = false;
+	export let init = () => {};
+
+	let config = null;
+
+	let selectedModelId = '';
+	let defaultModelIds = [];
+	let modelIds = [];
+
+	let loading = false;
+	let showResetModal = false;
+
+	const submitHandler = async () => {
+		loading = true;
+
+		const res = await setModelsConfig(localStorage.token, {
+			DEFAULT_MODELS: defaultModelIds.join(','),
+			MODEL_ORDER_LIST: modelIds
+		});
+
+		if (res) {
+			toast.success($i18n.t('Models configuration saved successfully'));
+			init();
+			show = false;
+		} else {
+			toast.error($i18n.t('Failed to save models configuration'));
+		}
+
+		loading = false;
+	};
+
+	onMount(async () => {
+		config = await getModelsConfig(localStorage.token);
+
+		const modelOrderList = config.MODEL_ORDER_LIST || [];
+		const allModelIds = $models.map((model) => model.id);
+
+		// Create a Set for quick lookup of ordered IDs
+		const orderedSet = new Set(modelOrderList);
+
+		modelIds = [
+			// Add all IDs from MODEL_ORDER_LIST that exist in allModelIds
+			...modelOrderList.filter((id) => orderedSet.has(id) && allModelIds.includes(id)),
+			// Add remaining IDs not in MODEL_ORDER_LIST, sorted alphabetically
+			...allModelIds.filter((id) => !orderedSet.has(id)).sort((a, b) => a.localeCompare(b))
+		];
+	});
+</script>
+
+<ConfirmDialog
+	title={$i18n.t('Delete All Models')}
+	message={$i18n.t('This will delete all models including custom models and cannot be undone.')}
+	bind:show={showResetModal}
+	onConfirm={async () => {
+		const res = deleteAllModels(localStorage.token);
+		if (res) {
+			toast.success($i18n.t('All models deleted successfully'));
+			init();
+		}
+	}}
+/>
+
+<Modal size="sm" bind:show>
+	<div>
+		<div class=" flex justify-between dark:text-gray-100 px-5 pt-4 pb-2">
+			<div class=" text-lg font-medium self-center font-primary">
+				{$i18n.t('Configure Models')}
+			</div>
+			<button
+				class="self-center"
+				on:click={() => {
+					show = false;
+				}}
+			>
+				<svg
+					xmlns="http://www.w3.org/2000/svg"
+					viewBox="0 0 20 20"
+					fill="currentColor"
+					class="w-5 h-5"
+				>
+					<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"
+					/>
+				</svg>
+			</button>
+		</div>
+
+		<div class="flex flex-col md:flex-row w-full px-5 pb-4 md:space-x-4 dark:text-gray-200">
+			<div class=" flex flex-col w-full sm:flex-row sm:justify-center sm:space-x-6">
+				{#if config}
+					<form
+						class="flex flex-col w-full"
+						on:submit|preventDefault={() => {
+							submitHandler();
+						}}
+					>
+						<div>
+							<div class="flex flex-col w-full">
+								<div class="mb-1 flex justify-between">
+									<div class="text-xs text-gray-500">{$i18n.t('Reorder Models')}</div>
+								</div>
+
+								<ModelList bind:modelIds />
+							</div>
+						</div>
+
+						<hr class=" border-gray-100 dark:border-gray-700/10 my-2.5 w-full" />
+
+						<div>
+							<div class="flex flex-col w-full">
+								<div class="mb-1 flex justify-between">
+									<div class="text-xs text-gray-500">{$i18n.t('Default Models')}</div>
+								</div>
+
+								{#if defaultModelIds.length > 0}
+									<div class="flex flex-col">
+										{#each defaultModelIds as modelId, modelIdx}
+											<div class=" flex gap-2 w-full justify-between items-center">
+												<div class=" text-sm flex-1 py-1 rounded-lg">
+													{$models.find((model) => model.id === modelId)?.name}
+												</div>
+												<div class="flex-shrink-0">
+													<button
+														type="button"
+														on:click={() => {
+															defaultModelIds = defaultModelIds.filter(
+																(_, idx) => idx !== modelIdx
+															);
+														}}
+													>
+														<Minus strokeWidth="2" className="size-3.5" />
+													</button>
+												</div>
+											</div>
+										{/each}
+									</div>
+								{:else}
+									<div class="text-gray-500 text-xs text-center py-2">
+										{$i18n.t('No models selected')}
+									</div>
+								{/if}
+
+								<hr class=" border-gray-100 dark:border-gray-700/10 my-2.5 w-full" />
+
+								<div class="flex items-center">
+									<select
+										class="w-full py-1 text-sm rounded-lg bg-transparent {selectedModelId
+											? ''
+											: 'text-gray-500'} placeholder:text-gray-300 dark:placeholder:text-gray-700 outline-none"
+										bind:value={selectedModelId}
+									>
+										<option value="">{$i18n.t('Select a model')}</option>
+										{#each $models as model}
+											<option value={model.id} class="bg-gray-50 dark:bg-gray-700"
+												>{model.name}</option
+											>
+										{/each}
+									</select>
+
+									<div>
+										<button
+											type="button"
+											on:click={() => {
+												if (defaultModelIds.includes(selectedModelId)) {
+													return;
+												}
+
+												defaultModelIds = [...defaultModelIds, selectedModelId];
+												selectedModelId = '';
+											}}
+										>
+											<Plus className="size-3.5" strokeWidth="2" />
+										</button>
+									</div>
+								</div>
+							</div>
+						</div>
+
+						<div class="flex justify-between pt-3 text-sm font-medium gap-1.5">
+							<Tooltip content={$i18n.t('This will delete all models including custom models')}>
+								<button
+									class="px-3.5 py-1.5 text-sm font-medium dark:bg-black dark:hover:bg-gray-950 dark:text-white bg-white text-black hover:bg-gray-100 transition rounded-full flex flex-row space-x-1 items-center"
+									type="button"
+									on:click={() => {
+										showResetModal = true;
+									}}
+								>
+									{$i18n.t('Delete All Models')}
+								</button>
+							</Tooltip>
+
+							<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 flex flex-row space-x-1 items-center {loading
+									? ' cursor-not-allowed'
+									: ''}"
+								type="submit"
+								disabled={loading}
+							>
+								{$i18n.t('Save')}
+
+								{#if loading}
+									<div class="ml-2 self-center">
+										<svg
+											class=" w-4 h-4"
+											viewBox="0 0 24 24"
+											fill="currentColor"
+											xmlns="http://www.w3.org/2000/svg"
+											><style>
+												.spinner_ajPY {
+													transform-origin: center;
+													animation: spinner_AtaB 0.75s infinite linear;
+												}
+												@keyframes spinner_AtaB {
+													100% {
+														transform: rotate(360deg);
+													}
+												}
+											</style><path
+												d="M12,1A11,11,0,1,0,23,12,11,11,0,0,0,12,1Zm0,19a8,8,0,1,1,8-8A8,8,0,0,1,12,20Z"
+												opacity=".25"
+											/><path
+												d="M10.14,1.16a11,11,0,0,0-9,8.92A1.59,1.59,0,0,0,2.46,12,1.52,1.52,0,0,0,4.11,10.7a8,8,0,0,1,6.66-6.61A1.42,1.42,0,0,0,12,2.69h0A1.57,1.57,0,0,0,10.14,1.16Z"
+												class="spinner_ajPY"
+											/></svg
+										>
+									</div>
+								{/if}
+							</button>
+						</div>
+					</form>
+				{:else}
+					<div>
+						<Spinner />
+					</div>
+				{/if}
+			</div>
+		</div>
+	</div>
+</Modal>

+ 58 - 0
src/lib/components/admin/Settings/Models/ModelList.svelte

@@ -0,0 +1,58 @@
+<script lang="ts">
+	import Sortable from 'sortablejs';
+
+	import { createEventDispatcher, getContext, onMount } from 'svelte';
+	const i18n = getContext('i18n');
+
+	import { models } from '$lib/stores';
+	import Tooltip from '$lib/components/common/Tooltip.svelte';
+	import EllipsisVertical from '$lib/components/icons/EllipsisVertical.svelte';
+
+	export let modelIds = [];
+
+	let sortable = null;
+	let modelListElement = null;
+
+	const positionChangeHandler = () => {
+		const modelList = Array.from(modelListElement.children).map((child) =>
+			child.id.replace('model-item-', '')
+		);
+
+		modelIds = modelList;
+	};
+
+	onMount(() => {
+		sortable = Sortable.create(modelListElement, {
+			animation: 150,
+			onUpdate: async (event) => {
+				positionChangeHandler();
+			}
+		});
+	});
+</script>
+
+{#if modelIds.length > 0}
+	<div class="flex flex-col -translate-x-1" bind:this={modelListElement}>
+		{#each modelIds as modelId, modelIdx (modelId)}
+			<div class=" flex gap-2 w-full justify-between items-center" id="model-item-{modelId}">
+				<Tooltip content={modelId} placement="top-start">
+					<div class="flex items-center gap-1">
+						<EllipsisVertical className="size-4 cursor-move" />
+
+						<div class=" text-sm flex-1 py-1 rounded-lg">
+							{#if $models.find((model) => model.id === modelId)}
+								{$models.find((model) => model.id === modelId).name}
+							{:else}
+								{modelId}
+							{/if}
+						</div>
+					</div>
+				</Tooltip>
+			</div>
+		{/each}
+	</div>
+{:else}
+	<div class="text-gray-500 text-xs text-center py-2">
+		{$i18n.t('No models found')}
+	</div>
+{/if}

+ 14 - 7
src/lib/components/chat/Chat.svelte

@@ -888,11 +888,10 @@
 		await tick();
 		await tick();
 
 
 		// Reset chat input textarea
 		// Reset chat input textarea
-		const chatInputContainer = document.getElementById('chat-input-container');
+		const chatInputElement = document.getElementById('chat-input');
 
 
-		if (chatInputContainer) {
-			chatInputContainer.value = '';
-			chatInputContainer.style.height = '';
+		if (chatInputElement) {
+			chatInputElement.style.height = '';
 		}
 		}
 
 
 		const _files = JSON.parse(JSON.stringify(files));
 		const _files = JSON.parse(JSON.stringify(files));
@@ -1977,7 +1976,7 @@
 				}
 				}
 			);
 			);
 
 
-			return title;
+			return title ? title : (lastUserMessage?.content ?? 'New Chat');
 		} else {
 		} else {
 			return lastUserMessage?.content ?? 'New Chat';
 			return lastUserMessage?.content ?? 'New Chat';
 		}
 		}
@@ -2310,7 +2309,11 @@
 								on:submit={async (e) => {
 								on:submit={async (e) => {
 									if (e.detail) {
 									if (e.detail) {
 										await tick();
 										await tick();
-										submitPrompt(e.detail.replaceAll('\n\n', '\n'));
+										submitPrompt(
+											($settings?.richTextInput ?? true)
+												? e.detail.replaceAll('\n\n', '\n')
+												: e.detail
+										);
 									}
 									}
 								}}
 								}}
 							/>
 							/>
@@ -2347,7 +2350,11 @@
 								on:submit={async (e) => {
 								on:submit={async (e) => {
 									if (e.detail) {
 									if (e.detail) {
 										await tick();
 										await tick();
-										submitPrompt(e.detail.replaceAll('\n\n', '\n'));
+										submitPrompt(
+											($settings?.richTextInput ?? true)
+												? e.detail.replaceAll('\n\n', '\n')
+												: e.detail
+										);
 									}
 									}
 								}}
 								}}
 							/>
 							/>

+ 58 - 46
src/lib/components/chat/MessageInput.svelte

@@ -592,29 +592,6 @@
 												placeholder={placeholder ? placeholder : $i18n.t('Send a Message')}
 												placeholder={placeholder ? placeholder : $i18n.t('Send a Message')}
 												largeTextAsFile={$settings?.largeTextAsFile ?? false}
 												largeTextAsFile={$settings?.largeTextAsFile ?? false}
 												bind:value={prompt}
 												bind:value={prompt}
-												on:enter={async (e) => {
-													const commandsContainerElement =
-														document.getElementById('commands-container');
-													if (commandsContainerElement) {
-														e.preventDefault();
-
-														const commandOptionButton = [
-															...document.getElementsByClassName('selected-command-option-button')
-														]?.at(-1);
-
-														if (commandOptionButton) {
-															commandOptionButton?.click();
-															return;
-														}
-													}
-
-													if (prompt !== '') {
-														dispatch('submit', prompt);
-													}
-												}}
-												on:keypress={(e) => {
-													e = e.detail.event;
-												}}
 												on:keydown={async (e) => {
 												on:keydown={async (e) => {
 													e = e.detail.event;
 													e = e.detail.event;
 
 
@@ -657,34 +634,70 @@
 														editButton?.click();
 														editButton?.click();
 													}
 													}
 
 
-													if (commandsContainerElement && e.key === 'ArrowUp') {
-														e.preventDefault();
-														commandsElement.selectUp();
+													if (commandsContainerElement) {
+														if (commandsContainerElement && e.key === 'ArrowUp') {
+															e.preventDefault();
+															commandsElement.selectUp();
+
+															const commandOptionButton = [
+																...document.getElementsByClassName('selected-command-option-button')
+															]?.at(-1);
+															commandOptionButton.scrollIntoView({ block: 'center' });
+														}
 
 
-														const commandOptionButton = [
-															...document.getElementsByClassName('selected-command-option-button')
-														]?.at(-1);
-														commandOptionButton.scrollIntoView({ block: 'center' });
-													}
+														if (commandsContainerElement && e.key === 'ArrowDown') {
+															e.preventDefault();
+															commandsElement.selectDown();
 
 
-													if (commandsContainerElement && e.key === 'ArrowDown') {
-														e.preventDefault();
-														commandsElement.selectDown();
+															const commandOptionButton = [
+																...document.getElementsByClassName('selected-command-option-button')
+															]?.at(-1);
+															commandOptionButton.scrollIntoView({ block: 'center' });
+														}
 
 
-														const commandOptionButton = [
-															...document.getElementsByClassName('selected-command-option-button')
-														]?.at(-1);
-														commandOptionButton.scrollIntoView({ block: 'center' });
-													}
+														if (commandsContainerElement && e.key === 'Tab') {
+															e.preventDefault();
 
 
-													if (commandsContainerElement && e.key === 'Tab') {
-														e.preventDefault();
+															const commandOptionButton = [
+																...document.getElementsByClassName('selected-command-option-button')
+															]?.at(-1);
 
 
-														const commandOptionButton = [
-															...document.getElementsByClassName('selected-command-option-button')
-														]?.at(-1);
+															commandOptionButton?.click();
+														}
 
 
-														commandOptionButton?.click();
+														if (commandsContainerElement && e.key === 'Enter') {
+															e.preventDefault();
+
+															const commandOptionButton = [
+																...document.getElementsByClassName('selected-command-option-button')
+															]?.at(-1);
+
+															if (commandOptionButton) {
+																commandOptionButton?.click();
+															} else {
+																document.getElementById('send-message-button')?.click();
+															}
+														}
+													} else {
+														if (
+															!$mobile ||
+															!(
+																'ontouchstart' in window ||
+																navigator.maxTouchPoints > 0 ||
+																navigator.msMaxTouchPoints > 0
+															)
+														) {
+															// Prevent Enter key from creating a new line
+															// Uses keyCode '13' for Enter key for chinese/japanese keyboards
+															if (e.keyCode === 13 && !e.shiftKey) {
+																e.preventDefault();
+															}
+
+															// Submit the prompt when Enter key is pressed
+															if (prompt !== '' && e.keyCode === 13 && !e.shiftKey) {
+																dispatch('submit', prompt);
+															}
+														}
 													}
 													}
 
 
 													if (e.key === 'Escape') {
 													if (e.key === 'Escape') {
@@ -881,7 +894,6 @@
 											on:input={async (e) => {
 											on:input={async (e) => {
 												e.target.style.height = '';
 												e.target.style.height = '';
 												e.target.style.height = Math.min(e.target.scrollHeight, 200) + 'px';
 												e.target.style.height = Math.min(e.target.scrollHeight, 200) + 'px';
-												user = null;
 											}}
 											}}
 											on:focus={async (e) => {
 											on:focus={async (e) => {
 												e.target.style.height = '';
 												e.target.style.height = '';

+ 3 - 1
src/lib/components/chat/Messages/CitationsModal.svelte

@@ -38,7 +38,9 @@
 			};
 			};
 		});
 		});
 		if (mergedDocuments.every((doc) => doc.distance !== undefined)) {
 		if (mergedDocuments.every((doc) => doc.distance !== undefined)) {
-			mergedDocuments.sort((a, b) => (a.distance ?? Infinity) - (b.distance ?? Infinity));
+			mergedDocuments = mergedDocuments.sort(
+				(a, b) => (b.distance ?? Infinity) - (a.distance ?? Infinity)
+			);
 		}
 		}
 	}
 	}
 </script>
 </script>

+ 0 - 2
src/lib/components/chat/ModelSelector.svelte

@@ -5,9 +5,7 @@
 	import Selector from './ModelSelector/Selector.svelte';
 	import Selector from './ModelSelector/Selector.svelte';
 	import Tooltip from '../common/Tooltip.svelte';
 	import Tooltip from '../common/Tooltip.svelte';
 
 
-	import { setDefaultModels } from '$lib/apis/configs';
 	import { updateUserSettings } from '$lib/apis/users';
 	import { updateUserSettings } from '$lib/apis/users';
-
 	const i18n = getContext('i18n');
 	const i18n = getContext('i18n');
 
 
 	export let selectedModels = [''];
 	export let selectedModels = [''];

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

@@ -55,6 +55,7 @@
 		mirostat_tau: null,
 		mirostat_tau: null,
 		top_k: null,
 		top_k: null,
 		top_p: null,
 		top_p: null,
+		min_p: null,
 		stop: null,
 		stop: null,
 		tfs_z: null,
 		tfs_z: null,
 		num_ctx: null,
 		num_ctx: null,
@@ -340,6 +341,7 @@
 						mirostat_tau: params.mirostat_tau !== null ? params.mirostat_tau : undefined,
 						mirostat_tau: params.mirostat_tau !== null ? params.mirostat_tau : undefined,
 						top_k: params.top_k !== null ? params.top_k : undefined,
 						top_k: params.top_k !== null ? params.top_k : undefined,
 						top_p: params.top_p !== null ? params.top_p : undefined,
 						top_p: params.top_p !== null ? params.top_p : undefined,
+						min_p: params.min_p !== null ? params.min_p : undefined,
 						tfs_z: params.tfs_z !== null ? params.tfs_z : undefined,
 						tfs_z: params.tfs_z !== null ? params.tfs_z : undefined,
 						num_ctx: params.num_ctx !== null ? params.num_ctx : undefined,
 						num_ctx: params.num_ctx !== null ? params.num_ctx : undefined,
 						num_batch: params.num_batch !== null ? params.num_batch : undefined,
 						num_batch: params.num_batch !== null ? params.num_batch : undefined,

+ 3 - 3
src/lib/components/common/Modal.svelte

@@ -6,7 +6,7 @@
 
 
 	export let show = true;
 	export let show = true;
 	export let size = 'md';
 	export let size = 'md';
-	export let className = 'bg-gray-50 dark:bg-gray-900  rounded-2xl';
+	export let className = 'bg-gray-50 dark:bg-gray-900 rounded-2xl';
 
 
 	let modalElement = null;
 	let modalElement = null;
 	let mounted = false;
 	let mounted = false;
@@ -65,7 +65,7 @@
 	<!-- svelte-ignore a11y-no-static-element-interactions -->
 	<!-- svelte-ignore a11y-no-static-element-interactions -->
 	<div
 	<div
 		bind:this={modalElement}
 		bind:this={modalElement}
-		class="modal fixed top-0 right-0 left-0 bottom-0 bg-black/60 w-full h-screen max-h-[100dvh] flex justify-center z-[9999] overflow-hidden overscroll-contain"
+		class="modal fixed top-0 right-0 left-0 bottom-0 bg-black/60 w-full h-screen max-h-[100dvh] p-3 flex justify-center z-[9999] overflow-y-auto overscroll-contain"
 		in:fade={{ duration: 10 }}
 		in:fade={{ duration: 10 }}
 		on:mousedown={() => {
 		on:mousedown={() => {
 			show = false;
 			show = false;
@@ -74,7 +74,7 @@
 		<div
 		<div
 			class=" m-auto max-w-full {sizeToWidth(size)} {size !== 'full'
 			class=" m-auto max-w-full {sizeToWidth(size)} {size !== 'full'
 				? 'mx-2'
 				? 'mx-2'
-				: ''} shadow-3xl max-h-[100dvh] overflow-y-auto scrollbar-hidden {className}"
+				: ''} shadow-3xl min-h-fit scrollbar-hidden {className}"
 			in:flyAndScale
 			in:flyAndScale
 			on:mousedown={(e) => {
 			on:mousedown={(e) => {
 				e.stopPropagation();
 				e.stopPropagation();

+ 12 - 16
src/lib/components/common/RichTextInput.svelte

@@ -1,7 +1,10 @@
 <script lang="ts">
 <script lang="ts">
 	import { marked } from 'marked';
 	import { marked } from 'marked';
 	import TurndownService from 'turndown';
 	import TurndownService from 'turndown';
-	const turndownService = new TurndownService();
+	const turndownService = new TurndownService({
+		codeBlockStyle: 'fenced'
+	});
+	turndownService.escape = (string) => string;
 
 
 	import { onMount, onDestroy } from 'svelte';
 	import { onMount, onDestroy } from 'svelte';
 	import { createEventDispatcher } from 'svelte';
 	import { createEventDispatcher } from 'svelte';
@@ -154,7 +157,11 @@
 
 
 				const newValue = turndownService.turndown(editor.getHTML());
 				const newValue = turndownService.turndown(editor.getHTML());
 				if (value !== newValue) {
 				if (value !== newValue) {
-					value = newValue; // Trigger parent updates
+					value = newValue;
+
+					if (value === '') {
+						editor.commands.clearContent();
+					}
 				}
 				}
 			},
 			},
 			editorProps: {
 			editorProps: {
@@ -164,11 +171,10 @@
 						eventDispatch('focus', { event });
 						eventDispatch('focus', { event });
 						return false;
 						return false;
 					},
 					},
-					keypress: (view, event) => {
-						eventDispatch('keypress', { event });
+					keyup: (view, event) => {
+						eventDispatch('keyup', { event });
 						return false;
 						return false;
 					},
 					},
-
 					keydown: (view, event) => {
 					keydown: (view, event) => {
 						// Handle Tab Key
 						// Handle Tab Key
 						if (event.key === 'Tab') {
 						if (event.key === 'Tab') {
@@ -210,22 +216,12 @@
 
 
 							// Handle shift + Enter for a line break
 							// Handle shift + Enter for a line break
 							if (shiftEnter) {
 							if (shiftEnter) {
-								if (event.key === 'Enter' && event.shiftKey) {
+								if (event.key === 'Enter' && event.shiftKey && !event.ctrlKey && !event.metaKey) {
 									editor.commands.setHardBreak(); // Insert a hard break
 									editor.commands.setHardBreak(); // Insert a hard break
 									view.dispatch(view.state.tr.scrollIntoView()); // Move viewport to the cursor
 									view.dispatch(view.state.tr.scrollIntoView()); // Move viewport to the cursor
 									event.preventDefault();
 									event.preventDefault();
 									return true;
 									return true;
 								}
 								}
-								if (event.key === 'Enter') {
-									eventDispatch('enter', { event });
-									event.preventDefault();
-									return true;
-								}
-							}
-							if (event.key === 'Enter') {
-								eventDispatch('enter', { event });
-								event.preventDefault();
-								return true;
 							}
 							}
 						}
 						}
 						eventDispatch('keydown', { event });
 						eventDispatch('keydown', { event });

+ 7 - 11
src/lib/components/common/Textarea.svelte

@@ -3,30 +3,27 @@
 
 
 	export let value = '';
 	export let value = '';
 	export let placeholder = '';
 	export let placeholder = '';
-
 	export let rows = 1;
 	export let rows = 1;
 	export let required = false;
 	export let required = false;
-
 	export let className =
 	export let className =
 		'w-full rounded-lg px-3 py-2 text-sm bg-gray-50 dark:text-gray-300 dark:bg-gray-850 outline-none resize-none h-full';
 		'w-full rounded-lg px-3 py-2 text-sm bg-gray-50 dark:text-gray-300 dark:bg-gray-850 outline-none resize-none h-full';
 
 
 	let textareaElement;
 	let textareaElement;
 
 
+	// Adjust height on mount and after setting the element.
 	onMount(async () => {
 	onMount(async () => {
 		await tick();
 		await tick();
-		if (textareaElement) {
-			await tick();
-			setTimeout(adjustHeight, 0);
-		}
+		adjustHeight();
 	});
 	});
 
 
-	$: if (value) {
-		setTimeout(adjustHeight, 0);
-	}
+	// This reactive statement runs whenever `value` changes
+	$: adjustHeight();
 
 
+	// Adjust height to match content
 	const adjustHeight = () => {
 	const adjustHeight = () => {
 		if (textareaElement) {
 		if (textareaElement) {
-			textareaElement.style.height = '';
+			// Reset height to calculate the correct scroll height
+			textareaElement.style.height = 'auto';
 			textareaElement.style.height = `${textareaElement.scrollHeight}px`;
 			textareaElement.style.height = `${textareaElement.scrollHeight}px`;
 		}
 		}
 	};
 	};
@@ -37,7 +34,6 @@
 	bind:value
 	bind:value
 	{placeholder}
 	{placeholder}
 	on:input={adjustHeight}
 	on:input={adjustHeight}
-	on:focus={adjustHeight}
 	class={className}
 	class={className}
 	{rows}
 	{rows}
 	{required}
 	{required}

+ 16 - 3
src/lib/components/workspace/Models/ModelEditor.svelte

@@ -317,6 +317,7 @@
 						info.meta.profile_image_url = compressedSrc;
 						info.meta.profile_image_url = compressedSrc;
 
 
 						inputFiles = null;
 						inputFiles = null;
+						filesInputElement.value = '';
 					};
 					};
 				};
 				};
 
 
@@ -345,7 +346,7 @@
 				<div class="self-center md:self-start flex justify-center my-2 flex-shrink-0">
 				<div class="self-center md:self-start flex justify-center my-2 flex-shrink-0">
 					<div class="self-center">
 					<div class="self-center">
 						<button
 						<button
-							class="rounded-2xl flex flex-shrink-0 items-center {info.meta.profile_image_url !==
+							class="rounded-xl flex flex-shrink-0 items-center {info.meta.profile_image_url !==
 							'/static/favicon.png'
 							'/static/favicon.png'
 								? 'bg-transparent'
 								? 'bg-transparent'
 								: 'bg-white'} shadow-xl group relative"
 								: 'bg-white'} shadow-xl group relative"
@@ -358,13 +359,13 @@
 								<img
 								<img
 									src={info.meta.profile_image_url}
 									src={info.meta.profile_image_url}
 									alt="model profile"
 									alt="model profile"
-									class="rounded-lg size-72 md:size-60 object-cover shrink-0"
+									class="rounded-xl size-72 md:size-60 object-cover shrink-0"
 								/>
 								/>
 							{:else}
 							{:else}
 								<img
 								<img
 									src="/static/favicon.png"
 									src="/static/favicon.png"
 									alt="model profile"
 									alt="model profile"
-									class=" rounded-lg size-72 md:size-60 object-cover shrink-0"
+									class=" rounded-xl size-72 md:size-60 object-cover shrink-0"
 								/>
 								/>
 							{/if}
 							{/if}
 
 
@@ -393,6 +394,18 @@
 								class="absolute top-0 bottom-0 left-0 right-0 bg-white dark:bg-black rounded-lg opacity-0 group-hover:opacity-20 transition"
 								class="absolute top-0 bottom-0 left-0 right-0 bg-white dark:bg-black rounded-lg opacity-0 group-hover:opacity-20 transition"
 							></div>
 							></div>
 						</button>
 						</button>
+
+						<div class="flex w-full mt-1 justify-end">
+							<button
+								class="px-2 py-1 text-gray-500 rounded-lg text-xs"
+								on:click={() => {
+									info.meta.profile_image_url = '/static/favicon.png';
+								}}
+								type="button"
+							>
+								Reset Image</button
+							>
+						</div>
 					</div>
 					</div>
 				</div>
 				</div>
 
 

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

@@ -167,6 +167,7 @@
 	"Completions": "",
 	"Completions": "",
 	"Concurrent Requests": "الطلبات المتزامنة",
 	"Concurrent Requests": "الطلبات المتزامنة",
 	"Configure": "",
 	"Configure": "",
+	"Configure Models": "",
 	"Confirm": "",
 	"Confirm": "",
 	"Confirm Password": "تأكيد كلمة المرور",
 	"Confirm Password": "تأكيد كلمة المرور",
 	"Confirm your action": "",
 	"Confirm your action": "",
@@ -215,6 +216,7 @@
 	"Default (SentenceTransformers)": "(SentenceTransformers) الإفتراضي",
 	"Default (SentenceTransformers)": "(SentenceTransformers) الإفتراضي",
 	"Default Model": "النموذج الافتراضي",
 	"Default Model": "النموذج الافتراضي",
 	"Default model updated": "الإفتراضي تحديث الموديل",
 	"Default model updated": "الإفتراضي تحديث الموديل",
+	"Default Models": "",
 	"Default permissions": "",
 	"Default permissions": "",
 	"Default permissions updated successfully": "",
 	"Default permissions updated successfully": "",
 	"Default Prompt Suggestions": "الإفتراضي Prompt الاقتراحات",
 	"Default Prompt Suggestions": "الإفتراضي Prompt الاقتراحات",
@@ -383,6 +385,7 @@
 	"Failed to add file.": "",
 	"Failed to add file.": "",
 	"Failed to create API Key.": "فشل في إنشاء مفتاح API.",
 	"Failed to create API Key.": "فشل في إنشاء مفتاح API.",
 	"Failed to read clipboard contents": "فشل في قراءة محتويات الحافظة",
 	"Failed to read clipboard contents": "فشل في قراءة محتويات الحافظة",
+	"Failed to save models configuration": "",
 	"Failed to update settings": "",
 	"Failed to update settings": "",
 	"Failed to upload file.": "",
 	"Failed to upload file.": "",
 	"February": "فبراير",
 	"February": "فبراير",
@@ -570,6 +573,7 @@
 	"Modelfile Content": "محتوى الملف النموذجي",
 	"Modelfile Content": "محتوى الملف النموذجي",
 	"Models": "الموديلات",
 	"Models": "الموديلات",
 	"Models Access": "",
 	"Models Access": "",
+	"Models configuration saved successfully": "",
 	"Mojeek Search API Key": "",
 	"Mojeek Search API Key": "",
 	"more": "",
 	"more": "",
 	"More": "المزيد",
 	"More": "المزيد",
@@ -589,6 +593,7 @@
 	"No knowledge found": "",
 	"No knowledge found": "",
 	"No model IDs": "",
 	"No model IDs": "",
 	"No models found": "",
 	"No models found": "",
+	"No models selected": "",
 	"No results found": "لا توجد نتايج",
 	"No results found": "لا توجد نتايج",
 	"No search query generated": "لم يتم إنشاء استعلام بحث",
 	"No search query generated": "لم يتم إنشاء استعلام بحث",
 	"No source available": "لا يوجد مصدر متاح",
 	"No source available": "لا يوجد مصدر متاح",
@@ -699,6 +704,7 @@
 	"Remove": "إزالة",
 	"Remove": "إزالة",
 	"Remove Model": "حذف الموديل",
 	"Remove Model": "حذف الموديل",
 	"Rename": "إعادة تسمية",
 	"Rename": "إعادة تسمية",
+	"Reorder Models": "",
 	"Repeat Last N": "N كرر آخر",
 	"Repeat Last N": "N كرر آخر",
 	"Request Mode": "وضع الطلب",
 	"Request Mode": "وضع الطلب",
 	"Reranking Model": "إعادة تقييم النموذج",
 	"Reranking Model": "إعادة تقييم النموذج",

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

@@ -167,6 +167,7 @@
 	"Completions": "",
 	"Completions": "",
 	"Concurrent Requests": "Едновременни искания",
 	"Concurrent Requests": "Едновременни искания",
 	"Configure": "",
 	"Configure": "",
+	"Configure Models": "",
 	"Confirm": "",
 	"Confirm": "",
 	"Confirm Password": "Потвърди Парола",
 	"Confirm Password": "Потвърди Парола",
 	"Confirm your action": "",
 	"Confirm your action": "",
@@ -215,6 +216,7 @@
 	"Default (SentenceTransformers)": "По подразбиране (SentenceTransformers)",
 	"Default (SentenceTransformers)": "По подразбиране (SentenceTransformers)",
 	"Default Model": "Модел по подразбиране",
 	"Default Model": "Модел по подразбиране",
 	"Default model updated": "Моделът по подразбиране е обновен",
 	"Default model updated": "Моделът по подразбиране е обновен",
+	"Default Models": "",
 	"Default permissions": "",
 	"Default permissions": "",
 	"Default permissions updated successfully": "",
 	"Default permissions updated successfully": "",
 	"Default Prompt Suggestions": "Промпт Предложения по подразбиране",
 	"Default Prompt Suggestions": "Промпт Предложения по подразбиране",
@@ -383,6 +385,7 @@
 	"Failed to add file.": "",
 	"Failed to add file.": "",
 	"Failed to create API Key.": "Неуспешно създаване на API ключ.",
 	"Failed to create API Key.": "Неуспешно създаване на API ключ.",
 	"Failed to read clipboard contents": "Грешка при четене на съдържанието от клипборда",
 	"Failed to read clipboard contents": "Грешка при четене на съдържанието от клипборда",
+	"Failed to save models configuration": "",
 	"Failed to update settings": "",
 	"Failed to update settings": "",
 	"Failed to upload file.": "",
 	"Failed to upload file.": "",
 	"February": "Февруари",
 	"February": "Февруари",
@@ -570,6 +573,7 @@
 	"Modelfile Content": "Съдържание на модфайл",
 	"Modelfile Content": "Съдържание на модфайл",
 	"Models": "Модели",
 	"Models": "Модели",
 	"Models Access": "",
 	"Models Access": "",
+	"Models configuration saved successfully": "",
 	"Mojeek Search API Key": "",
 	"Mojeek Search API Key": "",
 	"more": "",
 	"more": "",
 	"More": "Повече",
 	"More": "Повече",
@@ -589,6 +593,7 @@
 	"No knowledge found": "",
 	"No knowledge found": "",
 	"No model IDs": "",
 	"No model IDs": "",
 	"No models found": "",
 	"No models found": "",
+	"No models selected": "",
 	"No results found": "Няма намерени резултати",
 	"No results found": "Няма намерени резултати",
 	"No search query generated": "Не е генерирана заявка за търсене",
 	"No search query generated": "Не е генерирана заявка за търсене",
 	"No source available": "Няма наличен източник",
 	"No source available": "Няма наличен източник",
@@ -699,6 +704,7 @@
 	"Remove": "Изтриване",
 	"Remove": "Изтриване",
 	"Remove Model": "Изтриване на модела",
 	"Remove Model": "Изтриване на модела",
 	"Rename": "Преименуване",
 	"Rename": "Преименуване",
+	"Reorder Models": "",
 	"Repeat Last N": "Repeat Last N",
 	"Repeat Last N": "Repeat Last N",
 	"Request Mode": "Request Mode",
 	"Request Mode": "Request Mode",
 	"Reranking Model": "Reranking Model",
 	"Reranking Model": "Reranking Model",

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

@@ -167,6 +167,7 @@
 	"Completions": "",
 	"Completions": "",
 	"Concurrent Requests": "সমকালীন অনুরোধ",
 	"Concurrent Requests": "সমকালীন অনুরোধ",
 	"Configure": "",
 	"Configure": "",
+	"Configure Models": "",
 	"Confirm": "",
 	"Confirm": "",
 	"Confirm Password": "পাসওয়ার্ড নিশ্চিত করুন",
 	"Confirm Password": "পাসওয়ার্ড নিশ্চিত করুন",
 	"Confirm your action": "",
 	"Confirm your action": "",
@@ -215,6 +216,7 @@
 	"Default (SentenceTransformers)": "ডিফল্ট (SentenceTransformers)",
 	"Default (SentenceTransformers)": "ডিফল্ট (SentenceTransformers)",
 	"Default Model": "ডিফল্ট মডেল",
 	"Default Model": "ডিফল্ট মডেল",
 	"Default model updated": "ডিফল্ট মডেল আপডেট হয়েছে",
 	"Default model updated": "ডিফল্ট মডেল আপডেট হয়েছে",
+	"Default Models": "",
 	"Default permissions": "",
 	"Default permissions": "",
 	"Default permissions updated successfully": "",
 	"Default permissions updated successfully": "",
 	"Default Prompt Suggestions": "ডিফল্ট প্রম্পট সাজেশন",
 	"Default Prompt Suggestions": "ডিফল্ট প্রম্পট সাজেশন",
@@ -383,6 +385,7 @@
 	"Failed to add file.": "",
 	"Failed to add file.": "",
 	"Failed to create API Key.": "API Key তৈরি করা যায়নি।",
 	"Failed to create API Key.": "API Key তৈরি করা যায়নি।",
 	"Failed to read clipboard contents": "ক্লিপবোর্ডের বিষয়বস্তু পড়া সম্ভব হয়নি",
 	"Failed to read clipboard contents": "ক্লিপবোর্ডের বিষয়বস্তু পড়া সম্ভব হয়নি",
+	"Failed to save models configuration": "",
 	"Failed to update settings": "",
 	"Failed to update settings": "",
 	"Failed to upload file.": "",
 	"Failed to upload file.": "",
 	"February": "ফেব্রুয়ারি",
 	"February": "ফেব্রুয়ারি",
@@ -570,6 +573,7 @@
 	"Modelfile Content": "মডেলফাইল কনটেন্ট",
 	"Modelfile Content": "মডেলফাইল কনটেন্ট",
 	"Models": "মডেলসমূহ",
 	"Models": "মডেলসমূহ",
 	"Models Access": "",
 	"Models Access": "",
+	"Models configuration saved successfully": "",
 	"Mojeek Search API Key": "",
 	"Mojeek Search API Key": "",
 	"more": "",
 	"more": "",
 	"More": "আরো",
 	"More": "আরো",
@@ -589,6 +593,7 @@
 	"No knowledge found": "",
 	"No knowledge found": "",
 	"No model IDs": "",
 	"No model IDs": "",
 	"No models found": "",
 	"No models found": "",
+	"No models selected": "",
 	"No results found": "কোন ফলাফল পাওয়া যায়নি",
 	"No results found": "কোন ফলাফল পাওয়া যায়নি",
 	"No search query generated": "কোনও অনুসন্ধান ক্যোয়ারী উত্পন্ন হয়নি",
 	"No search query generated": "কোনও অনুসন্ধান ক্যোয়ারী উত্পন্ন হয়নি",
 	"No source available": "কোন উৎস পাওয়া যায়নি",
 	"No source available": "কোন উৎস পাওয়া যায়নি",
@@ -699,6 +704,7 @@
 	"Remove": "রিমুভ করুন",
 	"Remove": "রিমুভ করুন",
 	"Remove Model": "মডেল রিমুভ করুন",
 	"Remove Model": "মডেল রিমুভ করুন",
 	"Rename": "রেনেম",
 	"Rename": "রেনেম",
+	"Reorder Models": "",
 	"Repeat Last N": "রিপিট Last N",
 	"Repeat Last N": "রিপিট Last N",
 	"Request Mode": "রিকোয়েস্ট মোড",
 	"Request Mode": "রিকোয়েস্ট মোড",
 	"Reranking Model": "রির্যাক্টিং মডেল",
 	"Reranking Model": "রির্যাক্টিং মডেল",

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

@@ -167,6 +167,7 @@
 	"Completions": "Completaments",
 	"Completions": "Completaments",
 	"Concurrent Requests": "Peticions simultànies",
 	"Concurrent Requests": "Peticions simultànies",
 	"Configure": "Configurar",
 	"Configure": "Configurar",
+	"Configure Models": "",
 	"Confirm": "Confirmar",
 	"Confirm": "Confirmar",
 	"Confirm Password": "Confirmar la contrasenya",
 	"Confirm Password": "Confirmar la contrasenya",
 	"Confirm your action": "Confirma la teva acció",
 	"Confirm your action": "Confirma la teva acció",
@@ -215,6 +216,7 @@
 	"Default (SentenceTransformers)": "Per defecte (SentenceTransformers)",
 	"Default (SentenceTransformers)": "Per defecte (SentenceTransformers)",
 	"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": "",
 	"Default permissions": "Permisos per defecte",
 	"Default permissions": "Permisos per defecte",
 	"Default permissions updated successfully": "Permisos per defecte actualitzats correctament",
 	"Default permissions updated successfully": "Permisos per defecte actualitzats correctament",
 	"Default Prompt Suggestions": "Suggeriments d'indicació per defecte",
 	"Default Prompt Suggestions": "Suggeriments d'indicació per defecte",
@@ -383,6 +385,7 @@
 	"Failed to add file.": "No s'ha pogut afegir l'arxiu.",
 	"Failed to add file.": "No s'ha pogut afegir l'arxiu.",
 	"Failed to create API Key.": "No s'ha pogut crear la clau API.",
 	"Failed to create API Key.": "No s'ha pogut crear la clau API.",
 	"Failed to read clipboard contents": "No s'ha pogut llegir el contingut del porta-retalls",
 	"Failed to read clipboard contents": "No s'ha pogut llegir el contingut del porta-retalls",
+	"Failed to save models configuration": "",
 	"Failed to update settings": "No s'han pogut actualitzar les preferències",
 	"Failed to update settings": "No s'han pogut actualitzar les preferències",
 	"Failed to upload file.": "No s'ha pogut pujar l'arxiu.",
 	"Failed to upload file.": "No s'ha pogut pujar l'arxiu.",
 	"February": "Febrer",
 	"February": "Febrer",
@@ -570,6 +573,7 @@
 	"Modelfile Content": "Contingut del Modelfile",
 	"Modelfile Content": "Contingut del Modelfile",
 	"Models": "Models",
 	"Models": "Models",
 	"Models Access": "Accés als models",
 	"Models Access": "Accés als models",
+	"Models configuration saved successfully": "",
 	"Mojeek Search API Key": "Clau API de Mojeek Search",
 	"Mojeek Search API Key": "Clau API de Mojeek Search",
 	"more": "més",
 	"more": "més",
 	"More": "Més",
 	"More": "Més",
@@ -589,6 +593,7 @@
 	"No knowledge found": "No s'ha trobat Coneixement",
 	"No knowledge found": "No s'ha trobat Coneixement",
 	"No model IDs": "No hi ha IDs de model",
 	"No model IDs": "No hi ha IDs de model",
 	"No models found": "No s'han trobat models",
 	"No models found": "No s'han trobat models",
+	"No models selected": "",
 	"No results found": "No s'han trobat resultats",
 	"No results found": "No s'han trobat resultats",
 	"No search query generated": "No s'ha generat cap consulta",
 	"No search query generated": "No s'ha generat cap consulta",
 	"No source available": "Sense font disponible",
 	"No source available": "Sense font disponible",
@@ -699,6 +704,7 @@
 	"Remove": "Eliminar",
 	"Remove": "Eliminar",
 	"Remove Model": "Eliminar el model",
 	"Remove Model": "Eliminar el model",
 	"Rename": "Canviar el nom",
 	"Rename": "Canviar el nom",
+	"Reorder Models": "",
 	"Repeat Last N": "Repeteix els darrers N",
 	"Repeat Last N": "Repeteix els darrers N",
 	"Request Mode": "Mode de sol·licitud",
 	"Request Mode": "Mode de sol·licitud",
 	"Reranking Model": "Model de reavaluació",
 	"Reranking Model": "Model de reavaluació",

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

@@ -167,6 +167,7 @@
 	"Completions": "",
 	"Completions": "",
 	"Concurrent Requests": "",
 	"Concurrent Requests": "",
 	"Configure": "",
 	"Configure": "",
+	"Configure Models": "",
 	"Confirm": "",
 	"Confirm": "",
 	"Confirm Password": "Kumpirma ang password",
 	"Confirm Password": "Kumpirma ang password",
 	"Confirm your action": "",
 	"Confirm your action": "",
@@ -215,6 +216,7 @@
 	"Default (SentenceTransformers)": "",
 	"Default (SentenceTransformers)": "",
 	"Default Model": "",
 	"Default Model": "",
 	"Default model updated": "Gi-update nga default template",
 	"Default model updated": "Gi-update nga default template",
+	"Default Models": "",
 	"Default permissions": "",
 	"Default permissions": "",
 	"Default permissions updated successfully": "",
 	"Default permissions updated successfully": "",
 	"Default Prompt Suggestions": "Default nga prompt nga mga sugyot",
 	"Default Prompt Suggestions": "Default nga prompt nga mga sugyot",
@@ -383,6 +385,7 @@
 	"Failed to add file.": "",
 	"Failed to add file.": "",
 	"Failed to create API Key.": "",
 	"Failed to create API Key.": "",
 	"Failed to read clipboard contents": "Napakyas sa pagbasa sa sulod sa clipboard",
 	"Failed to read clipboard contents": "Napakyas sa pagbasa sa sulod sa clipboard",
+	"Failed to save models configuration": "",
 	"Failed to update settings": "",
 	"Failed to update settings": "",
 	"Failed to upload file.": "",
 	"Failed to upload file.": "",
 	"February": "",
 	"February": "",
@@ -570,6 +573,7 @@
 	"Modelfile Content": "Mga sulod sa template file",
 	"Modelfile Content": "Mga sulod sa template file",
 	"Models": "Mga modelo",
 	"Models": "Mga modelo",
 	"Models Access": "",
 	"Models Access": "",
+	"Models configuration saved successfully": "",
 	"Mojeek Search API Key": "",
 	"Mojeek Search API Key": "",
 	"more": "",
 	"more": "",
 	"More": "",
 	"More": "",
@@ -589,6 +593,7 @@
 	"No knowledge found": "",
 	"No knowledge found": "",
 	"No model IDs": "",
 	"No model IDs": "",
 	"No models found": "",
 	"No models found": "",
+	"No models selected": "",
 	"No results found": "",
 	"No results found": "",
 	"No search query generated": "",
 	"No search query generated": "",
 	"No source available": "Walay tinubdan nga anaa",
 	"No source available": "Walay tinubdan nga anaa",
@@ -699,6 +704,7 @@
 	"Remove": "",
 	"Remove": "",
 	"Remove Model": "",
 	"Remove Model": "",
 	"Rename": "",
 	"Rename": "",
+	"Reorder Models": "",
 	"Repeat Last N": "Balika ang katapusang N",
 	"Repeat Last N": "Balika ang katapusang N",
 	"Request Mode": "Query mode",
 	"Request Mode": "Query mode",
 	"Reranking Model": "",
 	"Reranking Model": "",

+ 6 - 0
src/lib/i18n/locales/cs-CZ/translation.json

@@ -167,6 +167,7 @@
 	"Completions": "Doplnění",
 	"Completions": "Doplnění",
 	"Concurrent Requests": "Současné požadavky",
 	"Concurrent Requests": "Současné požadavky",
 	"Configure": "",
 	"Configure": "",
+	"Configure Models": "",
 	"Confirm": "Potvrdit",
 	"Confirm": "Potvrdit",
 	"Confirm Password": "Potvrzení hesla",
 	"Confirm Password": "Potvrzení hesla",
 	"Confirm your action": "Potvrďte svoji akci",
 	"Confirm your action": "Potvrďte svoji akci",
@@ -215,6 +216,7 @@
 	"Default (SentenceTransformers)": "Výchozí (SentenceTransformers)",
 	"Default (SentenceTransformers)": "Výchozí (SentenceTransformers)",
 	"Default Model": "Výchozí model",
 	"Default Model": "Výchozí model",
 	"Default model updated": "Výchozí model aktualizován.",
 	"Default model updated": "Výchozí model aktualizován.",
+	"Default Models": "",
 	"Default permissions": "",
 	"Default permissions": "",
 	"Default permissions updated successfully": "",
 	"Default permissions updated successfully": "",
 	"Default Prompt Suggestions": "Výchozí návrhy promptů",
 	"Default Prompt Suggestions": "Výchozí návrhy promptů",
@@ -383,6 +385,7 @@
 	"Failed to add file.": "Nepodařilo se přidat soubor.",
 	"Failed to add file.": "Nepodařilo se přidat soubor.",
 	"Failed to create API Key.": "Nepodařilo se vytvořit API klíč.",
 	"Failed to create API Key.": "Nepodařilo se vytvořit API klíč.",
 	"Failed to read clipboard contents": "Nepodařilo se přečíst obsah schránky",
 	"Failed to read clipboard contents": "Nepodařilo se přečíst obsah schránky",
+	"Failed to save models configuration": "",
 	"Failed to update settings": "Nepodařilo se aktualizovat nastavení",
 	"Failed to update settings": "Nepodařilo se aktualizovat nastavení",
 	"Failed to upload file.": "Nepodařilo se nahrát soubor.",
 	"Failed to upload file.": "Nepodařilo se nahrát soubor.",
 	"February": "Únor",
 	"February": "Únor",
@@ -570,6 +573,7 @@
 	"Modelfile Content": "Obsah souboru modelfile",
 	"Modelfile Content": "Obsah souboru modelfile",
 	"Models": "Modely",
 	"Models": "Modely",
 	"Models Access": "",
 	"Models Access": "",
+	"Models configuration saved successfully": "",
 	"Mojeek Search API Key": "",
 	"Mojeek Search API Key": "",
 	"more": "více",
 	"more": "více",
 	"More": "Více",
 	"More": "Více",
@@ -589,6 +593,7 @@
 	"No knowledge found": "Nebyly nalezeny žádné znalosti",
 	"No knowledge found": "Nebyly nalezeny žádné znalosti",
 	"No model IDs": "",
 	"No model IDs": "",
 	"No models found": "Nebyly nalezeny žádné modely",
 	"No models found": "Nebyly nalezeny žádné modely",
+	"No models selected": "",
 	"No results found": "Nebyly nalezeny žádné výsledky",
 	"No results found": "Nebyly nalezeny žádné výsledky",
 	"No search query generated": "Nebyl vygenerován žádný vyhledávací dotaz.",
 	"No search query generated": "Nebyl vygenerován žádný vyhledávací dotaz.",
 	"No source available": "Není k dispozici žádný zdroj.",
 	"No source available": "Není k dispozici žádný zdroj.",
@@ -699,6 +704,7 @@
 	"Remove": "Odebrat",
 	"Remove": "Odebrat",
 	"Remove Model": "Odebrat model",
 	"Remove Model": "Odebrat model",
 	"Rename": "Přejmenovat",
 	"Rename": "Přejmenovat",
+	"Reorder Models": "",
 	"Repeat Last N": "Opakovat posledních N",
 	"Repeat Last N": "Opakovat posledních N",
 	"Request Mode": "Režim žádosti",
 	"Request Mode": "Režim žádosti",
 	"Reranking Model": "Model pro přehodnocení pořadí",
 	"Reranking Model": "Model pro přehodnocení pořadí",

+ 6 - 0
src/lib/i18n/locales/da-DK/translation.json

@@ -167,6 +167,7 @@
 	"Completions": "",
 	"Completions": "",
 	"Concurrent Requests": "Concurrent requests",
 	"Concurrent Requests": "Concurrent requests",
 	"Configure": "",
 	"Configure": "",
+	"Configure Models": "",
 	"Confirm": "Bekræft",
 	"Confirm": "Bekræft",
 	"Confirm Password": "Bekræft password",
 	"Confirm Password": "Bekræft password",
 	"Confirm your action": "Bekræft din handling",
 	"Confirm your action": "Bekræft din handling",
@@ -215,6 +216,7 @@
 	"Default (SentenceTransformers)": "Standard (SentenceTransformers)",
 	"Default (SentenceTransformers)": "Standard (SentenceTransformers)",
 	"Default Model": "Standard model",
 	"Default Model": "Standard model",
 	"Default model updated": "Standard model opdateret",
 	"Default model updated": "Standard model opdateret",
+	"Default Models": "",
 	"Default permissions": "",
 	"Default permissions": "",
 	"Default permissions updated successfully": "",
 	"Default permissions updated successfully": "",
 	"Default Prompt Suggestions": "Standardforslag til prompt",
 	"Default Prompt Suggestions": "Standardforslag til prompt",
@@ -383,6 +385,7 @@
 	"Failed to add file.": "",
 	"Failed to add file.": "",
 	"Failed to create API Key.": "Kunne ikke oprette API-nøgle.",
 	"Failed to create API Key.": "Kunne ikke oprette API-nøgle.",
 	"Failed to read clipboard contents": "Kunne ikke læse indholdet af udklipsholderen",
 	"Failed to read clipboard contents": "Kunne ikke læse indholdet af udklipsholderen",
+	"Failed to save models configuration": "",
 	"Failed to update settings": "Kunne ikke opdatere indstillinger",
 	"Failed to update settings": "Kunne ikke opdatere indstillinger",
 	"Failed to upload file.": "Kunne ikke uploade fil.",
 	"Failed to upload file.": "Kunne ikke uploade fil.",
 	"February": "Februar",
 	"February": "Februar",
@@ -570,6 +573,7 @@
 	"Modelfile Content": "Modelfilindhold",
 	"Modelfile Content": "Modelfilindhold",
 	"Models": "Modeller",
 	"Models": "Modeller",
 	"Models Access": "",
 	"Models Access": "",
+	"Models configuration saved successfully": "",
 	"Mojeek Search API Key": "",
 	"Mojeek Search API Key": "",
 	"more": "",
 	"more": "",
 	"More": "Mere",
 	"More": "Mere",
@@ -589,6 +593,7 @@
 	"No knowledge found": "Ingen viden fundet",
 	"No knowledge found": "Ingen viden fundet",
 	"No model IDs": "",
 	"No model IDs": "",
 	"No models found": "",
 	"No models found": "",
+	"No models selected": "",
 	"No results found": "Ingen resultater fundet",
 	"No results found": "Ingen resultater fundet",
 	"No search query generated": "Ingen søgeforespørgsel genereret",
 	"No search query generated": "Ingen søgeforespørgsel genereret",
 	"No source available": "Ingen kilde tilgængelig",
 	"No source available": "Ingen kilde tilgængelig",
@@ -699,6 +704,7 @@
 	"Remove": "Fjern",
 	"Remove": "Fjern",
 	"Remove Model": "Fjern model",
 	"Remove Model": "Fjern model",
 	"Rename": "Omdøb",
 	"Rename": "Omdøb",
+	"Reorder Models": "",
 	"Repeat Last N": "Gentag sidste N",
 	"Repeat Last N": "Gentag sidste N",
 	"Request Mode": "Forespørgselstilstand",
 	"Request Mode": "Forespørgselstilstand",
 	"Reranking Model": "Omarrangeringsmodel",
 	"Reranking Model": "Omarrangeringsmodel",

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

@@ -167,6 +167,7 @@
 	"Completions": "Vervollständigungen",
 	"Completions": "Vervollständigungen",
 	"Concurrent Requests": "Anzahl gleichzeitiger Anfragen",
 	"Concurrent Requests": "Anzahl gleichzeitiger Anfragen",
 	"Configure": "Konfigurieren",
 	"Configure": "Konfigurieren",
+	"Configure Models": "",
 	"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.",
@@ -215,6 +216,7 @@
 	"Default (SentenceTransformers)": "Standard (SentenceTransformers)",
 	"Default (SentenceTransformers)": "Standard (SentenceTransformers)",
 	"Default Model": "Standardmodell",
 	"Default Model": "Standardmodell",
 	"Default model updated": "Standardmodell aktualisiert",
 	"Default model updated": "Standardmodell aktualisiert",
+	"Default Models": "",
 	"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",
@@ -383,6 +385,7 @@
 	"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 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 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.",
 	"February": "Februar",
 	"February": "Februar",
@@ -570,6 +573,7 @@
 	"Modelfile Content": "Modelfile-Inhalt",
 	"Modelfile Content": "Modelfile-Inhalt",
 	"Models": "Modelle",
 	"Models": "Modelle",
 	"Models Access": "Modell-Zugriff",
 	"Models Access": "Modell-Zugriff",
+	"Models configuration saved successfully": "",
 	"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",
@@ -589,6 +593,7 @@
 	"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 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",
@@ -699,6 +704,7 @@
 	"Remove": "Entfernen",
 	"Remove": "Entfernen",
 	"Remove Model": "Modell entfernen",
 	"Remove Model": "Modell entfernen",
 	"Rename": "Umbenennen",
 	"Rename": "Umbenennen",
+	"Reorder Models": "",
 	"Repeat Last N": "Wiederhole die letzten N",
 	"Repeat Last N": "Wiederhole die letzten N",
 	"Request Mode": "Anforderungsmodus",
 	"Request Mode": "Anforderungsmodus",
 	"Reranking Model": "Reranking-Modell",
 	"Reranking Model": "Reranking-Modell",

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

@@ -167,6 +167,7 @@
 	"Completions": "",
 	"Completions": "",
 	"Concurrent Requests": "",
 	"Concurrent Requests": "",
 	"Configure": "",
 	"Configure": "",
+	"Configure Models": "",
 	"Confirm": "",
 	"Confirm": "",
 	"Confirm Password": "Confirm Password",
 	"Confirm Password": "Confirm Password",
 	"Confirm your action": "",
 	"Confirm your action": "",
@@ -215,6 +216,7 @@
 	"Default (SentenceTransformers)": "",
 	"Default (SentenceTransformers)": "",
 	"Default Model": "",
 	"Default Model": "",
 	"Default model updated": "Default model much updated",
 	"Default model updated": "Default model much updated",
+	"Default Models": "",
 	"Default permissions": "",
 	"Default permissions": "",
 	"Default permissions updated successfully": "",
 	"Default permissions updated successfully": "",
 	"Default Prompt Suggestions": "Default Prompt Suggestions",
 	"Default Prompt Suggestions": "Default Prompt Suggestions",
@@ -383,6 +385,7 @@
 	"Failed to add file.": "",
 	"Failed to add file.": "",
 	"Failed to create API Key.": "",
 	"Failed to create API Key.": "",
 	"Failed to read clipboard contents": "Failed to read clipboard borks",
 	"Failed to read clipboard contents": "Failed to read clipboard borks",
+	"Failed to save models configuration": "",
 	"Failed to update settings": "",
 	"Failed to update settings": "",
 	"Failed to upload file.": "",
 	"Failed to upload file.": "",
 	"February": "",
 	"February": "",
@@ -570,6 +573,7 @@
 	"Modelfile Content": "Modelfile Content",
 	"Modelfile Content": "Modelfile Content",
 	"Models": "Wowdels",
 	"Models": "Wowdels",
 	"Models Access": "",
 	"Models Access": "",
+	"Models configuration saved successfully": "",
 	"Mojeek Search API Key": "",
 	"Mojeek Search API Key": "",
 	"more": "",
 	"more": "",
 	"More": "",
 	"More": "",
@@ -589,6 +593,7 @@
 	"No knowledge found": "",
 	"No knowledge found": "",
 	"No model IDs": "",
 	"No model IDs": "",
 	"No models found": "",
 	"No models found": "",
+	"No models selected": "",
 	"No results found": "",
 	"No results found": "",
 	"No search query generated": "",
 	"No search query generated": "",
 	"No source available": "No source available",
 	"No source available": "No source available",
@@ -699,6 +704,7 @@
 	"Remove": "",
 	"Remove": "",
 	"Remove Model": "",
 	"Remove Model": "",
 	"Rename": "",
 	"Rename": "",
+	"Reorder Models": "",
 	"Repeat Last N": "Repeat Last N",
 	"Repeat Last N": "Repeat Last N",
 	"Request Mode": "Request Bark",
 	"Request Mode": "Request Bark",
 	"Reranking Model": "",
 	"Reranking Model": "",

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

@@ -167,6 +167,7 @@
 	"Completions": "",
 	"Completions": "",
 	"Concurrent Requests": "",
 	"Concurrent Requests": "",
 	"Configure": "",
 	"Configure": "",
+	"Configure Models": "",
 	"Confirm": "",
 	"Confirm": "",
 	"Confirm Password": "",
 	"Confirm Password": "",
 	"Confirm your action": "",
 	"Confirm your action": "",
@@ -215,6 +216,7 @@
 	"Default (SentenceTransformers)": "",
 	"Default (SentenceTransformers)": "",
 	"Default Model": "",
 	"Default Model": "",
 	"Default model updated": "",
 	"Default model updated": "",
+	"Default Models": "",
 	"Default permissions": "",
 	"Default permissions": "",
 	"Default permissions updated successfully": "",
 	"Default permissions updated successfully": "",
 	"Default Prompt Suggestions": "",
 	"Default Prompt Suggestions": "",
@@ -383,6 +385,7 @@
 	"Failed to add file.": "",
 	"Failed to add file.": "",
 	"Failed to create API Key.": "",
 	"Failed to create API Key.": "",
 	"Failed to read clipboard contents": "",
 	"Failed to read clipboard contents": "",
+	"Failed to save models configuration": "",
 	"Failed to update settings": "",
 	"Failed to update settings": "",
 	"Failed to upload file.": "",
 	"Failed to upload file.": "",
 	"February": "",
 	"February": "",
@@ -570,6 +573,7 @@
 	"Modelfile Content": "",
 	"Modelfile Content": "",
 	"Models": "",
 	"Models": "",
 	"Models Access": "",
 	"Models Access": "",
+	"Models configuration saved successfully": "",
 	"Mojeek Search API Key": "",
 	"Mojeek Search API Key": "",
 	"more": "",
 	"more": "",
 	"More": "",
 	"More": "",
@@ -589,6 +593,7 @@
 	"No knowledge found": "",
 	"No knowledge found": "",
 	"No model IDs": "",
 	"No model IDs": "",
 	"No models found": "",
 	"No models found": "",
+	"No models selected": "",
 	"No results found": "",
 	"No results found": "",
 	"No search query generated": "",
 	"No search query generated": "",
 	"No source available": "",
 	"No source available": "",
@@ -699,6 +704,7 @@
 	"Remove": "",
 	"Remove": "",
 	"Remove Model": "",
 	"Remove Model": "",
 	"Rename": "",
 	"Rename": "",
+	"Reorder Models": "",
 	"Repeat Last N": "",
 	"Repeat Last N": "",
 	"Request Mode": "",
 	"Request Mode": "",
 	"Reranking Model": "",
 	"Reranking Model": "",

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

@@ -167,6 +167,7 @@
 	"Completions": "",
 	"Completions": "",
 	"Concurrent Requests": "",
 	"Concurrent Requests": "",
 	"Configure": "",
 	"Configure": "",
+	"Configure Models": "",
 	"Confirm": "",
 	"Confirm": "",
 	"Confirm Password": "",
 	"Confirm Password": "",
 	"Confirm your action": "",
 	"Confirm your action": "",
@@ -215,6 +216,7 @@
 	"Default (SentenceTransformers)": "",
 	"Default (SentenceTransformers)": "",
 	"Default Model": "",
 	"Default Model": "",
 	"Default model updated": "",
 	"Default model updated": "",
+	"Default Models": "",
 	"Default permissions": "",
 	"Default permissions": "",
 	"Default permissions updated successfully": "",
 	"Default permissions updated successfully": "",
 	"Default Prompt Suggestions": "",
 	"Default Prompt Suggestions": "",
@@ -383,6 +385,7 @@
 	"Failed to add file.": "",
 	"Failed to add file.": "",
 	"Failed to create API Key.": "",
 	"Failed to create API Key.": "",
 	"Failed to read clipboard contents": "",
 	"Failed to read clipboard contents": "",
+	"Failed to save models configuration": "",
 	"Failed to update settings": "",
 	"Failed to update settings": "",
 	"Failed to upload file.": "",
 	"Failed to upload file.": "",
 	"February": "",
 	"February": "",
@@ -570,6 +573,7 @@
 	"Modelfile Content": "",
 	"Modelfile Content": "",
 	"Models": "",
 	"Models": "",
 	"Models Access": "",
 	"Models Access": "",
+	"Models configuration saved successfully": "",
 	"Mojeek Search API Key": "",
 	"Mojeek Search API Key": "",
 	"more": "",
 	"more": "",
 	"More": "",
 	"More": "",
@@ -589,6 +593,7 @@
 	"No knowledge found": "",
 	"No knowledge found": "",
 	"No model IDs": "",
 	"No model IDs": "",
 	"No models found": "",
 	"No models found": "",
+	"No models selected": "",
 	"No results found": "",
 	"No results found": "",
 	"No search query generated": "",
 	"No search query generated": "",
 	"No source available": "",
 	"No source available": "",
@@ -699,6 +704,7 @@
 	"Remove": "",
 	"Remove": "",
 	"Remove Model": "",
 	"Remove Model": "",
 	"Rename": "",
 	"Rename": "",
+	"Reorder Models": "",
 	"Repeat Last N": "",
 	"Repeat Last N": "",
 	"Request Mode": "",
 	"Request Mode": "",
 	"Reranking Model": "",
 	"Reranking Model": "",

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

@@ -167,6 +167,7 @@
 	"Completions": "",
 	"Completions": "",
 	"Concurrent Requests": "Solicitudes simultáneas",
 	"Concurrent Requests": "Solicitudes simultáneas",
 	"Configure": "",
 	"Configure": "",
+	"Configure Models": "",
 	"Confirm": "Confirmar",
 	"Confirm": "Confirmar",
 	"Confirm Password": "Confirmar Contraseña",
 	"Confirm Password": "Confirmar Contraseña",
 	"Confirm your action": "Confirma tu acción",
 	"Confirm your action": "Confirma tu acción",
@@ -215,6 +216,7 @@
 	"Default (SentenceTransformers)": "Predeterminado (SentenceTransformers)",
 	"Default (SentenceTransformers)": "Predeterminado (SentenceTransformers)",
 	"Default Model": "Modelo predeterminado",
 	"Default Model": "Modelo predeterminado",
 	"Default model updated": "El modelo por defecto ha sido actualizado",
 	"Default model updated": "El modelo por defecto ha sido actualizado",
+	"Default Models": "",
 	"Default permissions": "",
 	"Default permissions": "",
 	"Default permissions updated successfully": "",
 	"Default permissions updated successfully": "",
 	"Default Prompt Suggestions": "Sugerencias de mensajes por defecto",
 	"Default Prompt Suggestions": "Sugerencias de mensajes por defecto",
@@ -383,6 +385,7 @@
 	"Failed to add file.": "",
 	"Failed to add file.": "",
 	"Failed to create API Key.": "No se pudo crear la clave API.",
 	"Failed to create API Key.": "No se pudo crear la clave API.",
 	"Failed to read clipboard contents": "No se pudo leer el contenido del portapapeles",
 	"Failed to read clipboard contents": "No se pudo leer el contenido del portapapeles",
+	"Failed to save models configuration": "",
 	"Failed to update settings": "Falla al actualizar los ajustes",
 	"Failed to update settings": "Falla al actualizar los ajustes",
 	"Failed to upload file.": "Falla al subir el archivo.",
 	"Failed to upload file.": "Falla al subir el archivo.",
 	"February": "Febrero",
 	"February": "Febrero",
@@ -570,6 +573,7 @@
 	"Modelfile Content": "Contenido del Modelfile",
 	"Modelfile Content": "Contenido del Modelfile",
 	"Models": "Modelos",
 	"Models": "Modelos",
 	"Models Access": "",
 	"Models Access": "",
+	"Models configuration saved successfully": "",
 	"Mojeek Search API Key": "",
 	"Mojeek Search API Key": "",
 	"more": "",
 	"more": "",
 	"More": "Más",
 	"More": "Más",
@@ -589,6 +593,7 @@
 	"No knowledge found": "No se encontró ningún conocimiento",
 	"No knowledge found": "No se encontró ningún conocimiento",
 	"No model IDs": "",
 	"No model IDs": "",
 	"No models found": "",
 	"No models found": "",
+	"No models selected": "",
 	"No results found": "No se han encontrado resultados",
 	"No results found": "No se han encontrado resultados",
 	"No search query generated": "No se ha generado ninguna consulta de búsqueda",
 	"No search query generated": "No se ha generado ninguna consulta de búsqueda",
 	"No source available": "No hay fuente disponible",
 	"No source available": "No hay fuente disponible",
@@ -699,6 +704,7 @@
 	"Remove": "Eliminar",
 	"Remove": "Eliminar",
 	"Remove Model": "Eliminar modelo",
 	"Remove Model": "Eliminar modelo",
 	"Rename": "Renombrar",
 	"Rename": "Renombrar",
+	"Reorder Models": "",
 	"Repeat Last N": "Repetir las últimas N",
 	"Repeat Last N": "Repetir las últimas N",
 	"Request Mode": "Modo de petición",
 	"Request Mode": "Modo de petición",
 	"Reranking Model": "Modelo de reranking",
 	"Reranking Model": "Modelo de reranking",

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

@@ -167,6 +167,7 @@
 	"Completions": "",
 	"Completions": "",
 	"Concurrent Requests": "درخواست های همزمان",
 	"Concurrent Requests": "درخواست های همزمان",
 	"Configure": "",
 	"Configure": "",
+	"Configure Models": "",
 	"Confirm": "تایید",
 	"Confirm": "تایید",
 	"Confirm Password": "تایید رمز عبور",
 	"Confirm Password": "تایید رمز عبور",
 	"Confirm your action": "",
 	"Confirm your action": "",
@@ -215,6 +216,7 @@
 	"Default (SentenceTransformers)": "پیشفرض (SentenceTransformers)",
 	"Default (SentenceTransformers)": "پیشفرض (SentenceTransformers)",
 	"Default Model": "مدل پیشفرض",
 	"Default Model": "مدل پیشفرض",
 	"Default model updated": "مدل پیشفرض به\u200cروزرسانی شد",
 	"Default model updated": "مدل پیشفرض به\u200cروزرسانی شد",
+	"Default Models": "",
 	"Default permissions": "",
 	"Default permissions": "",
 	"Default permissions updated successfully": "",
 	"Default permissions updated successfully": "",
 	"Default Prompt Suggestions": "پیشنهادات پرامپت پیش فرض",
 	"Default Prompt Suggestions": "پیشنهادات پرامپت پیش فرض",
@@ -383,6 +385,7 @@
 	"Failed to add file.": "خطا در افزودن پرونده",
 	"Failed to add file.": "خطا در افزودن پرونده",
 	"Failed to create API Key.": "ایجاد کلید API با خطا مواجه شد.",
 	"Failed to create API Key.": "ایجاد کلید API با خطا مواجه شد.",
 	"Failed to read clipboard contents": "خواندن محتوای کلیپ بورد ناموفق بود",
 	"Failed to read clipboard contents": "خواندن محتوای کلیپ بورد ناموفق بود",
+	"Failed to save models configuration": "",
 	"Failed to update settings": "خطا در به\u200cروزرسانی تنظیمات",
 	"Failed to update settings": "خطا در به\u200cروزرسانی تنظیمات",
 	"Failed to upload file.": "خطا در بارگذاری پرونده",
 	"Failed to upload file.": "خطا در بارگذاری پرونده",
 	"February": "فوریه",
 	"February": "فوریه",
@@ -570,6 +573,7 @@
 	"Modelfile Content": "محتویات فایل مدل",
 	"Modelfile Content": "محتویات فایل مدل",
 	"Models": "مدل\u200cها",
 	"Models": "مدل\u200cها",
 	"Models Access": "",
 	"Models Access": "",
+	"Models configuration saved successfully": "",
 	"Mojeek Search API Key": "",
 	"Mojeek Search API Key": "",
 	"more": "",
 	"more": "",
 	"More": "بیشتر",
 	"More": "بیشتر",
@@ -589,6 +593,7 @@
 	"No knowledge found": "",
 	"No knowledge found": "",
 	"No model IDs": "",
 	"No model IDs": "",
 	"No models found": "",
 	"No models found": "",
+	"No models selected": "",
 	"No results found": "نتیجه\u200cای یافت نشد",
 	"No results found": "نتیجه\u200cای یافت نشد",
 	"No search query generated": "پرسوجوی جستجویی ایجاد نشده است",
 	"No search query generated": "پرسوجوی جستجویی ایجاد نشده است",
 	"No source available": "منبعی در دسترس نیست",
 	"No source available": "منبعی در دسترس نیست",
@@ -699,6 +704,7 @@
 	"Remove": "حذف",
 	"Remove": "حذف",
 	"Remove Model": "حذف مدل",
 	"Remove Model": "حذف مدل",
 	"Rename": "تغییر نام",
 	"Rename": "تغییر نام",
+	"Reorder Models": "",
 	"Repeat Last N": "Repeat Last N",
 	"Repeat Last N": "Repeat Last N",
 	"Request Mode": "حالت درخواست",
 	"Request Mode": "حالت درخواست",
 	"Reranking Model": "مدل ری\u200cشناسی مجدد غیرفعال است",
 	"Reranking Model": "مدل ری\u200cشناسی مجدد غیرفعال است",

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

@@ -167,6 +167,7 @@
 	"Completions": "",
 	"Completions": "",
 	"Concurrent Requests": "Samanaikaiset pyynnöt",
 	"Concurrent Requests": "Samanaikaiset pyynnöt",
 	"Configure": "",
 	"Configure": "",
+	"Configure Models": "",
 	"Confirm": "",
 	"Confirm": "",
 	"Confirm Password": "Vahvista salasana",
 	"Confirm Password": "Vahvista salasana",
 	"Confirm your action": "",
 	"Confirm your action": "",
@@ -215,6 +216,7 @@
 	"Default (SentenceTransformers)": "Oletus (SentenceTransformers)",
 	"Default (SentenceTransformers)": "Oletus (SentenceTransformers)",
 	"Default Model": "Oletusmalli",
 	"Default Model": "Oletusmalli",
 	"Default model updated": "Oletusmalli päivitetty",
 	"Default model updated": "Oletusmalli päivitetty",
+	"Default Models": "",
 	"Default permissions": "",
 	"Default permissions": "",
 	"Default permissions updated successfully": "",
 	"Default permissions updated successfully": "",
 	"Default Prompt Suggestions": "Oletuskehotteiden ehdotukset",
 	"Default Prompt Suggestions": "Oletuskehotteiden ehdotukset",
@@ -383,6 +385,7 @@
 	"Failed to add file.": "",
 	"Failed to add file.": "",
 	"Failed to create API Key.": "API-avaimen luonti epäonnistui.",
 	"Failed to create API Key.": "API-avaimen luonti epäonnistui.",
 	"Failed to read clipboard contents": "Leikepöydän sisällön lukeminen epäonnistui",
 	"Failed to read clipboard contents": "Leikepöydän sisällön lukeminen epäonnistui",
+	"Failed to save models configuration": "",
 	"Failed to update settings": "",
 	"Failed to update settings": "",
 	"Failed to upload file.": "",
 	"Failed to upload file.": "",
 	"February": "helmikuu",
 	"February": "helmikuu",
@@ -570,6 +573,7 @@
 	"Modelfile Content": "Mallitiedoston sisältö",
 	"Modelfile Content": "Mallitiedoston sisältö",
 	"Models": "Mallit",
 	"Models": "Mallit",
 	"Models Access": "",
 	"Models Access": "",
+	"Models configuration saved successfully": "",
 	"Mojeek Search API Key": "",
 	"Mojeek Search API Key": "",
 	"more": "",
 	"more": "",
 	"More": "Lisää",
 	"More": "Lisää",
@@ -589,6 +593,7 @@
 	"No knowledge found": "",
 	"No knowledge found": "",
 	"No model IDs": "",
 	"No model IDs": "",
 	"No models found": "",
 	"No models found": "",
+	"No models selected": "",
 	"No results found": "Ei tuloksia",
 	"No results found": "Ei tuloksia",
 	"No search query generated": "Hakukyselyä ei luotu",
 	"No search query generated": "Hakukyselyä ei luotu",
 	"No source available": "Ei lähdettä saatavilla",
 	"No source available": "Ei lähdettä saatavilla",
@@ -699,6 +704,7 @@
 	"Remove": "Poista",
 	"Remove": "Poista",
 	"Remove Model": "Poista malli",
 	"Remove Model": "Poista malli",
 	"Rename": "Nimeä uudelleen",
 	"Rename": "Nimeä uudelleen",
+	"Reorder Models": "",
 	"Repeat Last N": "Viimeinen N -toisto",
 	"Repeat Last N": "Viimeinen N -toisto",
 	"Request Mode": "Pyyntötila",
 	"Request Mode": "Pyyntötila",
 	"Reranking Model": "Uudelleenpisteytysmalli",
 	"Reranking Model": "Uudelleenpisteytysmalli",

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

@@ -167,6 +167,7 @@
 	"Completions": "",
 	"Completions": "",
 	"Concurrent Requests": "Demandes concurrentes",
 	"Concurrent Requests": "Demandes concurrentes",
 	"Configure": "",
 	"Configure": "",
+	"Configure Models": "",
 	"Confirm": "Confirmer",
 	"Confirm": "Confirmer",
 	"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",
@@ -215,6 +216,7 @@
 	"Default (SentenceTransformers)": "Par défaut (Sentence Transformers)",
 	"Default (SentenceTransformers)": "Par défaut (Sentence Transformers)",
 	"Default Model": "Modèle standard",
 	"Default Model": "Modèle standard",
 	"Default model updated": "Modèle par défaut mis à jour",
 	"Default model updated": "Modèle par défaut mis à jour",
+	"Default Models": "",
 	"Default permissions": "",
 	"Default permissions": "",
 	"Default permissions updated successfully": "",
 	"Default permissions updated successfully": "",
 	"Default Prompt Suggestions": "Suggestions de prompts par défaut",
 	"Default Prompt Suggestions": "Suggestions de prompts par défaut",
@@ -383,6 +385,7 @@
 	"Failed to add file.": "",
 	"Failed to add file.": "",
 	"Failed to create API Key.": "Échec de la création de la clé API.",
 	"Failed to create API Key.": "Échec de la création de la clé API.",
 	"Failed to read clipboard contents": "Échec de la lecture du contenu du presse-papiers",
 	"Failed to read clipboard contents": "Échec de la lecture du contenu du presse-papiers",
+	"Failed to save models configuration": "",
 	"Failed to update settings": "Échec de la mise à jour des paramètres",
 	"Failed to update settings": "Échec de la mise à jour des paramètres",
 	"Failed to upload file.": "",
 	"Failed to upload file.": "",
 	"February": "Février",
 	"February": "Février",
@@ -570,6 +573,7 @@
 	"Modelfile Content": "Contenu du Fichier de Modèle",
 	"Modelfile Content": "Contenu du Fichier de Modèle",
 	"Models": "Modèles",
 	"Models": "Modèles",
 	"Models Access": "",
 	"Models Access": "",
+	"Models configuration saved successfully": "",
 	"Mojeek Search API Key": "",
 	"Mojeek Search API Key": "",
 	"more": "",
 	"more": "",
 	"More": "Plus de",
 	"More": "Plus de",
@@ -589,6 +593,7 @@
 	"No knowledge found": "",
 	"No knowledge found": "",
 	"No model IDs": "",
 	"No model IDs": "",
 	"No models found": "",
 	"No models found": "",
+	"No models selected": "",
 	"No results found": "Aucun résultat trouvé",
 	"No results found": "Aucun résultat trouvé",
 	"No search query generated": "Aucune requête de recherche générée",
 	"No search query generated": "Aucune requête de recherche générée",
 	"No source available": "Aucune source n'est disponible",
 	"No source available": "Aucune source n'est disponible",
@@ -699,6 +704,7 @@
 	"Remove": "Retirer",
 	"Remove": "Retirer",
 	"Remove Model": "Retirer le modèle",
 	"Remove Model": "Retirer le modèle",
 	"Rename": "Renommer",
 	"Rename": "Renommer",
+	"Reorder Models": "",
 	"Repeat Last N": "Répéter les N derniers",
 	"Repeat Last N": "Répéter les N derniers",
 	"Request Mode": "Mode de Requête",
 	"Request Mode": "Mode de Requête",
 	"Reranking Model": "Modèle de ré-ranking",
 	"Reranking Model": "Modèle de ré-ranking",

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

@@ -167,6 +167,7 @@
 	"Completions": "Complétions",
 	"Completions": "Complétions",
 	"Concurrent Requests": "Demandes concurrentes",
 	"Concurrent Requests": "Demandes concurrentes",
 	"Configure": "",
 	"Configure": "",
+	"Configure Models": "",
 	"Confirm": "Confirmer",
 	"Confirm": "Confirmer",
 	"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",
@@ -215,6 +216,7 @@
 	"Default (SentenceTransformers)": "Par défaut (Sentence Transformers)",
 	"Default (SentenceTransformers)": "Par défaut (Sentence Transformers)",
 	"Default Model": "Modèle standard",
 	"Default Model": "Modèle standard",
 	"Default model updated": "Modèle par défaut mis à jour",
 	"Default model updated": "Modèle par défaut mis à jour",
+	"Default Models": "",
 	"Default permissions": "",
 	"Default permissions": "",
 	"Default permissions updated successfully": "",
 	"Default permissions updated successfully": "",
 	"Default Prompt Suggestions": "Suggestions de prompts par défaut",
 	"Default Prompt Suggestions": "Suggestions de prompts par défaut",
@@ -383,6 +385,7 @@
 	"Failed to add file.": "Échec de l'ajout du fichier.",
 	"Failed to add file.": "Échec de l'ajout du fichier.",
 	"Failed to create API Key.": "Échec de la création de la clé API.",
 	"Failed to create API Key.": "Échec de la création de la clé API.",
 	"Failed to read clipboard contents": "Échec de la lecture du contenu du presse-papiers",
 	"Failed to read clipboard contents": "Échec de la lecture du contenu du presse-papiers",
+	"Failed to save models configuration": "",
 	"Failed to update settings": "Échec de la mise à jour des paramètres",
 	"Failed to update settings": "Échec de la mise à jour des paramètres",
 	"Failed to upload file.": "Échec du téléchargement du fichier.",
 	"Failed to upload file.": "Échec du téléchargement du fichier.",
 	"February": "Février",
 	"February": "Février",
@@ -570,6 +573,7 @@
 	"Modelfile Content": "Contenu du Fichier de Modèle",
 	"Modelfile Content": "Contenu du Fichier de Modèle",
 	"Models": "Modèles",
 	"Models": "Modèles",
 	"Models Access": "",
 	"Models Access": "",
+	"Models configuration saved successfully": "",
 	"Mojeek Search API Key": "",
 	"Mojeek Search API Key": "",
 	"more": "plus",
 	"more": "plus",
 	"More": "Plus",
 	"More": "Plus",
@@ -589,6 +593,7 @@
 	"No knowledge found": "Aucune connaissance trouvée",
 	"No knowledge found": "Aucune connaissance trouvée",
 	"No model IDs": "",
 	"No model IDs": "",
 	"No models found": "Aucun modèle trouvé",
 	"No models found": "Aucun modèle trouvé",
+	"No models selected": "",
 	"No results found": "Aucun résultat trouvé",
 	"No results found": "Aucun résultat trouvé",
 	"No search query generated": "Aucune requête de recherche générée",
 	"No search query generated": "Aucune requête de recherche générée",
 	"No source available": "Aucune source n'est disponible",
 	"No source available": "Aucune source n'est disponible",
@@ -699,6 +704,7 @@
 	"Remove": "Retirer",
 	"Remove": "Retirer",
 	"Remove Model": "Retirer le modèle",
 	"Remove Model": "Retirer le modèle",
 	"Rename": "Renommer",
 	"Rename": "Renommer",
+	"Reorder Models": "",
 	"Repeat Last N": "Répéter les N derniers",
 	"Repeat Last N": "Répéter les N derniers",
 	"Request Mode": "Mode de requête",
 	"Request Mode": "Mode de requête",
 	"Reranking Model": "Modèle de ré-ranking",
 	"Reranking Model": "Modèle de ré-ranking",

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

@@ -167,6 +167,7 @@
 	"Completions": "",
 	"Completions": "",
 	"Concurrent Requests": "בקשות בו-זמניות",
 	"Concurrent Requests": "בקשות בו-זמניות",
 	"Configure": "",
 	"Configure": "",
+	"Configure Models": "",
 	"Confirm": "",
 	"Confirm": "",
 	"Confirm Password": "אשר סיסמה",
 	"Confirm Password": "אשר סיסמה",
 	"Confirm your action": "",
 	"Confirm your action": "",
@@ -215,6 +216,7 @@
 	"Default (SentenceTransformers)": "ברירת מחדל (SentenceTransformers)",
 	"Default (SentenceTransformers)": "ברירת מחדל (SentenceTransformers)",
 	"Default Model": "מודל ברירת מחדל",
 	"Default Model": "מודל ברירת מחדל",
 	"Default model updated": "המודל המוגדר כברירת מחדל עודכן",
 	"Default model updated": "המודל המוגדר כברירת מחדל עודכן",
+	"Default Models": "",
 	"Default permissions": "",
 	"Default permissions": "",
 	"Default permissions updated successfully": "",
 	"Default permissions updated successfully": "",
 	"Default Prompt Suggestions": "הצעות ברירת מחדל לפקודות",
 	"Default Prompt Suggestions": "הצעות ברירת מחדל לפקודות",
@@ -383,6 +385,7 @@
 	"Failed to add file.": "",
 	"Failed to add file.": "",
 	"Failed to create API Key.": "יצירת מפתח API נכשלה.",
 	"Failed to create API Key.": "יצירת מפתח API נכשלה.",
 	"Failed to read clipboard contents": "קריאת תוכן הלוח נכשלה",
 	"Failed to read clipboard contents": "קריאת תוכן הלוח נכשלה",
+	"Failed to save models configuration": "",
 	"Failed to update settings": "",
 	"Failed to update settings": "",
 	"Failed to upload file.": "",
 	"Failed to upload file.": "",
 	"February": "פברואר",
 	"February": "פברואר",
@@ -570,6 +573,7 @@
 	"Modelfile Content": "תוכן קובץ מודל",
 	"Modelfile Content": "תוכן קובץ מודל",
 	"Models": "מודלים",
 	"Models": "מודלים",
 	"Models Access": "",
 	"Models Access": "",
+	"Models configuration saved successfully": "",
 	"Mojeek Search API Key": "",
 	"Mojeek Search API Key": "",
 	"more": "",
 	"more": "",
 	"More": "עוד",
 	"More": "עוד",
@@ -589,6 +593,7 @@
 	"No knowledge found": "",
 	"No knowledge found": "",
 	"No model IDs": "",
 	"No model IDs": "",
 	"No models found": "",
 	"No models found": "",
+	"No models selected": "",
 	"No results found": "לא נמצאו תוצאות",
 	"No results found": "לא נמצאו תוצאות",
 	"No search query generated": "לא נוצרה שאילתת חיפוש",
 	"No search query generated": "לא נוצרה שאילתת חיפוש",
 	"No source available": "אין מקור זמין",
 	"No source available": "אין מקור זמין",
@@ -699,6 +704,7 @@
 	"Remove": "הסר",
 	"Remove": "הסר",
 	"Remove Model": "הסר מודל",
 	"Remove Model": "הסר מודל",
 	"Rename": "שנה שם",
 	"Rename": "שנה שם",
+	"Reorder Models": "",
 	"Repeat Last N": "חזור על ה-N האחרונים",
 	"Repeat Last N": "חזור על ה-N האחרונים",
 	"Request Mode": "מצב בקשה",
 	"Request Mode": "מצב בקשה",
 	"Reranking Model": "מודל דירוג מחדש",
 	"Reranking Model": "מודל דירוג מחדש",

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

@@ -167,6 +167,7 @@
 	"Completions": "",
 	"Completions": "",
 	"Concurrent Requests": "समवर्ती अनुरोध",
 	"Concurrent Requests": "समवर्ती अनुरोध",
 	"Configure": "",
 	"Configure": "",
+	"Configure Models": "",
 	"Confirm": "",
 	"Confirm": "",
 	"Confirm Password": "पासवर्ड की पुष्टि कीजिये",
 	"Confirm Password": "पासवर्ड की पुष्टि कीजिये",
 	"Confirm your action": "",
 	"Confirm your action": "",
@@ -215,6 +216,7 @@
 	"Default (SentenceTransformers)": "डिफ़ॉल्ट (SentenceTransformers)",
 	"Default (SentenceTransformers)": "डिफ़ॉल्ट (SentenceTransformers)",
 	"Default Model": "डिफ़ॉल्ट मॉडल",
 	"Default Model": "डिफ़ॉल्ट मॉडल",
 	"Default model updated": "डिफ़ॉल्ट मॉडल अपडेट किया गया",
 	"Default model updated": "डिफ़ॉल्ट मॉडल अपडेट किया गया",
+	"Default Models": "",
 	"Default permissions": "",
 	"Default permissions": "",
 	"Default permissions updated successfully": "",
 	"Default permissions updated successfully": "",
 	"Default Prompt Suggestions": "डिफ़ॉल्ट प्रॉम्प्ट सुझाव",
 	"Default Prompt Suggestions": "डिफ़ॉल्ट प्रॉम्प्ट सुझाव",
@@ -383,6 +385,7 @@
 	"Failed to add file.": "",
 	"Failed to add file.": "",
 	"Failed to create API Key.": "एपीआई कुंजी बनाने में विफल.",
 	"Failed to create API Key.": "एपीआई कुंजी बनाने में विफल.",
 	"Failed to read clipboard contents": "क्लिपबोर्ड सामग्री पढ़ने में विफल",
 	"Failed to read clipboard contents": "क्लिपबोर्ड सामग्री पढ़ने में विफल",
+	"Failed to save models configuration": "",
 	"Failed to update settings": "",
 	"Failed to update settings": "",
 	"Failed to upload file.": "",
 	"Failed to upload file.": "",
 	"February": "फरवरी",
 	"February": "फरवरी",
@@ -570,6 +573,7 @@
 	"Modelfile Content": "मॉडल फ़ाइल सामग्री",
 	"Modelfile Content": "मॉडल फ़ाइल सामग्री",
 	"Models": "सभी मॉडल",
 	"Models": "सभी मॉडल",
 	"Models Access": "",
 	"Models Access": "",
+	"Models configuration saved successfully": "",
 	"Mojeek Search API Key": "",
 	"Mojeek Search API Key": "",
 	"more": "",
 	"more": "",
 	"More": "और..",
 	"More": "और..",
@@ -589,6 +593,7 @@
 	"No knowledge found": "",
 	"No knowledge found": "",
 	"No model IDs": "",
 	"No model IDs": "",
 	"No models found": "",
 	"No models found": "",
+	"No models selected": "",
 	"No results found": "कोई परिणाम नहीं मिला",
 	"No results found": "कोई परिणाम नहीं मिला",
 	"No search query generated": "कोई खोज क्वेरी जनरेट नहीं हुई",
 	"No search query generated": "कोई खोज क्वेरी जनरेट नहीं हुई",
 	"No source available": "कोई स्रोत उपलब्ध नहीं है",
 	"No source available": "कोई स्रोत उपलब्ध नहीं है",
@@ -699,6 +704,7 @@
 	"Remove": "हटा दें",
 	"Remove": "हटा दें",
 	"Remove Model": "मोडेल हटाएँ",
 	"Remove Model": "मोडेल हटाएँ",
 	"Rename": "नाम बदलें",
 	"Rename": "नाम बदलें",
+	"Reorder Models": "",
 	"Repeat Last N": "अंतिम N दोहराएँ",
 	"Repeat Last N": "अंतिम N दोहराएँ",
 	"Request Mode": "अनुरोध मोड",
 	"Request Mode": "अनुरोध मोड",
 	"Reranking Model": "रीरैकिंग मोड",
 	"Reranking Model": "रीरैकिंग मोड",

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

@@ -167,6 +167,7 @@
 	"Completions": "",
 	"Completions": "",
 	"Concurrent Requests": "Istodobni zahtjevi",
 	"Concurrent Requests": "Istodobni zahtjevi",
 	"Configure": "",
 	"Configure": "",
+	"Configure Models": "",
 	"Confirm": "",
 	"Confirm": "",
 	"Confirm Password": "Potvrdite lozinku",
 	"Confirm Password": "Potvrdite lozinku",
 	"Confirm your action": "",
 	"Confirm your action": "",
@@ -215,6 +216,7 @@
 	"Default (SentenceTransformers)": "Zadano (SentenceTransformers)",
 	"Default (SentenceTransformers)": "Zadano (SentenceTransformers)",
 	"Default Model": "Zadani model",
 	"Default Model": "Zadani model",
 	"Default model updated": "Zadani model ažuriran",
 	"Default model updated": "Zadani model ažuriran",
+	"Default Models": "",
 	"Default permissions": "",
 	"Default permissions": "",
 	"Default permissions updated successfully": "",
 	"Default permissions updated successfully": "",
 	"Default Prompt Suggestions": "Zadani prijedlozi prompta",
 	"Default Prompt Suggestions": "Zadani prijedlozi prompta",
@@ -383,6 +385,7 @@
 	"Failed to add file.": "",
 	"Failed to add file.": "",
 	"Failed to create API Key.": "Neuspješno stvaranje API ključa.",
 	"Failed to create API Key.": "Neuspješno stvaranje API ključa.",
 	"Failed to read clipboard contents": "Neuspješno čitanje sadržaja međuspremnika",
 	"Failed to read clipboard contents": "Neuspješno čitanje sadržaja međuspremnika",
+	"Failed to save models configuration": "",
 	"Failed to update settings": "Greška kod ažuriranja postavki",
 	"Failed to update settings": "Greška kod ažuriranja postavki",
 	"Failed to upload file.": "",
 	"Failed to upload file.": "",
 	"February": "Veljača",
 	"February": "Veljača",
@@ -570,6 +573,7 @@
 	"Modelfile Content": "Sadržaj datoteke modela",
 	"Modelfile Content": "Sadržaj datoteke modela",
 	"Models": "Modeli",
 	"Models": "Modeli",
 	"Models Access": "",
 	"Models Access": "",
+	"Models configuration saved successfully": "",
 	"Mojeek Search API Key": "",
 	"Mojeek Search API Key": "",
 	"more": "",
 	"more": "",
 	"More": "Više",
 	"More": "Više",
@@ -589,6 +593,7 @@
 	"No knowledge found": "",
 	"No knowledge found": "",
 	"No model IDs": "",
 	"No model IDs": "",
 	"No models found": "",
 	"No models found": "",
+	"No models selected": "",
 	"No results found": "Nema rezultata",
 	"No results found": "Nema rezultata",
 	"No search query generated": "Nije generiran upit za pretraživanje",
 	"No search query generated": "Nije generiran upit za pretraživanje",
 	"No source available": "Nema dostupnog izvora",
 	"No source available": "Nema dostupnog izvora",
@@ -699,6 +704,7 @@
 	"Remove": "Ukloni",
 	"Remove": "Ukloni",
 	"Remove Model": "Ukloni model",
 	"Remove Model": "Ukloni model",
 	"Rename": "Preimenuj",
 	"Rename": "Preimenuj",
+	"Reorder Models": "",
 	"Repeat Last N": "Ponovi zadnjih N",
 	"Repeat Last N": "Ponovi zadnjih N",
 	"Request Mode": "Način zahtjeva",
 	"Request Mode": "Način zahtjeva",
 	"Reranking Model": "Model za ponovno rangiranje",
 	"Reranking Model": "Model za ponovno rangiranje",

+ 6 - 0
src/lib/i18n/locales/hu-HU/translation.json

@@ -167,6 +167,7 @@
 	"Completions": "Kiegészítések",
 	"Completions": "Kiegészítések",
 	"Concurrent Requests": "Párhuzamos kérések",
 	"Concurrent Requests": "Párhuzamos kérések",
 	"Configure": "",
 	"Configure": "",
+	"Configure Models": "",
 	"Confirm": "Megerősítés",
 	"Confirm": "Megerősítés",
 	"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",
@@ -215,6 +216,7 @@
 	"Default (SentenceTransformers)": "Alapértelmezett (SentenceTransformers)",
 	"Default (SentenceTransformers)": "Alapértelmezett (SentenceTransformers)",
 	"Default Model": "Alapértelmezett modell",
 	"Default Model": "Alapértelmezett modell",
 	"Default model updated": "Alapértelmezett modell frissítve",
 	"Default model updated": "Alapértelmezett modell frissítve",
+	"Default Models": "",
 	"Default permissions": "",
 	"Default permissions": "",
 	"Default permissions updated successfully": "",
 	"Default permissions updated successfully": "",
 	"Default Prompt Suggestions": "Alapértelmezett prompt javaslatok",
 	"Default Prompt Suggestions": "Alapértelmezett prompt javaslatok",
@@ -383,6 +385,7 @@
 	"Failed to add file.": "Nem sikerült hozzáadni a fájlt.",
 	"Failed to add file.": "Nem sikerült hozzáadni a fájlt.",
 	"Failed to create API Key.": "Nem sikerült létrehozni az API kulcsot.",
 	"Failed to create API Key.": "Nem sikerült létrehozni az API kulcsot.",
 	"Failed to read clipboard contents": "Nem sikerült olvasni a vágólap tartalmát",
 	"Failed to read clipboard contents": "Nem sikerült olvasni a vágólap tartalmát",
+	"Failed to save models configuration": "",
 	"Failed to update settings": "Nem sikerült frissíteni a beállításokat",
 	"Failed to update settings": "Nem sikerült frissíteni a beállításokat",
 	"Failed to upload file.": "Nem sikerült feltölteni a fájlt.",
 	"Failed to upload file.": "Nem sikerült feltölteni a fájlt.",
 	"February": "Február",
 	"February": "Február",
@@ -570,6 +573,7 @@
 	"Modelfile Content": "Modellfájl tartalom",
 	"Modelfile Content": "Modellfájl tartalom",
 	"Models": "Modellek",
 	"Models": "Modellek",
 	"Models Access": "",
 	"Models Access": "",
+	"Models configuration saved successfully": "",
 	"Mojeek Search API Key": "",
 	"Mojeek Search API Key": "",
 	"more": "több",
 	"more": "több",
 	"More": "Több",
 	"More": "Több",
@@ -589,6 +593,7 @@
 	"No knowledge found": "Nem található tudásbázis",
 	"No knowledge found": "Nem található tudásbázis",
 	"No model IDs": "",
 	"No model IDs": "",
 	"No models found": "Nem található modell",
 	"No models found": "Nem található modell",
+	"No models selected": "",
 	"No results found": "Nincs találat",
 	"No results found": "Nincs találat",
 	"No search query generated": "Nem generálódott keresési lekérdezés",
 	"No search query generated": "Nem generálódott keresési lekérdezés",
 	"No source available": "Nincs elérhető forrás",
 	"No source available": "Nincs elérhető forrás",
@@ -699,6 +704,7 @@
 	"Remove": "Eltávolítás",
 	"Remove": "Eltávolítás",
 	"Remove Model": "Modell eltávolítása",
 	"Remove Model": "Modell eltávolítása",
 	"Rename": "Átnevezés",
 	"Rename": "Átnevezés",
+	"Reorder Models": "",
 	"Repeat Last N": "Utolsó N ismétlése",
 	"Repeat Last N": "Utolsó N ismétlése",
 	"Request Mode": "Kérési mód",
 	"Request Mode": "Kérési mód",
 	"Reranking Model": "Újrarangsoroló modell",
 	"Reranking Model": "Újrarangsoroló modell",

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

@@ -167,6 +167,7 @@
 	"Completions": "",
 	"Completions": "",
 	"Concurrent Requests": "Permintaan Bersamaan",
 	"Concurrent Requests": "Permintaan Bersamaan",
 	"Configure": "",
 	"Configure": "",
+	"Configure Models": "",
 	"Confirm": "Konfirmasi",
 	"Confirm": "Konfirmasi",
 	"Confirm Password": "Konfirmasi Kata Sandi",
 	"Confirm Password": "Konfirmasi Kata Sandi",
 	"Confirm your action": "Konfirmasi tindakan Anda",
 	"Confirm your action": "Konfirmasi tindakan Anda",
@@ -215,6 +216,7 @@
 	"Default (SentenceTransformers)": "Default (Pengubah Kalimat)",
 	"Default (SentenceTransformers)": "Default (Pengubah Kalimat)",
 	"Default Model": "Model Default",
 	"Default Model": "Model Default",
 	"Default model updated": "Model default diperbarui",
 	"Default model updated": "Model default diperbarui",
+	"Default Models": "",
 	"Default permissions": "",
 	"Default permissions": "",
 	"Default permissions updated successfully": "",
 	"Default permissions updated successfully": "",
 	"Default Prompt Suggestions": "Saran Permintaan Default",
 	"Default Prompt Suggestions": "Saran Permintaan Default",
@@ -383,6 +385,7 @@
 	"Failed to add file.": "",
 	"Failed to add file.": "",
 	"Failed to create API Key.": "Gagal membuat API Key.",
 	"Failed to create API Key.": "Gagal membuat API Key.",
 	"Failed to read clipboard contents": "Gagal membaca konten papan klip",
 	"Failed to read clipboard contents": "Gagal membaca konten papan klip",
+	"Failed to save models configuration": "",
 	"Failed to update settings": "Gagal memperbarui pengaturan",
 	"Failed to update settings": "Gagal memperbarui pengaturan",
 	"Failed to upload file.": "",
 	"Failed to upload file.": "",
 	"February": "Februari",
 	"February": "Februari",
@@ -570,6 +573,7 @@
 	"Modelfile Content": "Konten File Model",
 	"Modelfile Content": "Konten File Model",
 	"Models": "Model",
 	"Models": "Model",
 	"Models Access": "",
 	"Models Access": "",
+	"Models configuration saved successfully": "",
 	"Mojeek Search API Key": "",
 	"Mojeek Search API Key": "",
 	"more": "",
 	"more": "",
 	"More": "Lainnya",
 	"More": "Lainnya",
@@ -589,6 +593,7 @@
 	"No knowledge found": "",
 	"No knowledge found": "",
 	"No model IDs": "",
 	"No model IDs": "",
 	"No models found": "",
 	"No models found": "",
+	"No models selected": "",
 	"No results found": "Tidak ada hasil yang ditemukan",
 	"No results found": "Tidak ada hasil yang ditemukan",
 	"No search query generated": "Tidak ada permintaan pencarian yang dibuat",
 	"No search query generated": "Tidak ada permintaan pencarian yang dibuat",
 	"No source available": "Tidak ada sumber yang tersedia",
 	"No source available": "Tidak ada sumber yang tersedia",
@@ -699,6 +704,7 @@
 	"Remove": "Hapus",
 	"Remove": "Hapus",
 	"Remove Model": "Hapus Model",
 	"Remove Model": "Hapus Model",
 	"Rename": "Ganti nama",
 	"Rename": "Ganti nama",
+	"Reorder Models": "",
 	"Repeat Last N": "Ulangi N Terakhir",
 	"Repeat Last N": "Ulangi N Terakhir",
 	"Request Mode": "Mode Permintaan",
 	"Request Mode": "Mode Permintaan",
 	"Reranking Model": "Model Pemeringkatan Ulang",
 	"Reranking Model": "Model Pemeringkatan Ulang",

+ 6 - 0
src/lib/i18n/locales/ie-GA/translation.json

@@ -167,6 +167,7 @@
 	"Completions": "Críochnaithe",
 	"Completions": "Críochnaithe",
 	"Concurrent Requests": "Iarrataí Comhthéime",
 	"Concurrent Requests": "Iarrataí Comhthéime",
 	"Configure": "Cumraigh",
 	"Configure": "Cumraigh",
+	"Configure Models": "",
 	"Confirm": "Deimhnigh",
 	"Confirm": "Deimhnigh",
 	"Confirm Password": "Deimhnigh Pasfhocal",
 	"Confirm Password": "Deimhnigh Pasfhocal",
 	"Confirm your action": "Deimhnigh do ghníomh",
 	"Confirm your action": "Deimhnigh do ghníomh",
@@ -215,6 +216,7 @@
 	"Default (SentenceTransformers)": "Réamhshocraithe (SentenceTransFormers)",
 	"Default (SentenceTransformers)": "Réamhshocraithe (SentenceTransFormers)",
 	"Default Model": "Samhail Réamhshocraithe",
 	"Default Model": "Samhail Réamhshocraithe",
 	"Default model updated": "An tsamhail réamhshocraithe",
 	"Default model updated": "An tsamhail réamhshocraithe",
+	"Default Models": "",
 	"Default permissions": "Ceadanna réamhshocraithe",
 	"Default permissions": "Ceadanna réamhshocraithe",
 	"Default permissions updated successfully": "D'éirigh le ceadanna réamhshocraithe a nuashonrú",
 	"Default permissions updated successfully": "D'éirigh le ceadanna réamhshocraithe a nuashonrú",
 	"Default Prompt Suggestions": "Moltaí Pras Réamhshocraithe",
 	"Default Prompt Suggestions": "Moltaí Pras Réamhshocraithe",
@@ -383,6 +385,7 @@
 	"Failed to add file.": "Theip ar an gcomhad a chur leis.",
 	"Failed to add file.": "Theip ar an gcomhad a chur leis.",
 	"Failed to create API Key.": "Theip ar an eochair API a chruthú.",
 	"Failed to create API Key.": "Theip ar an eochair API a chruthú.",
 	"Failed to read clipboard contents": "Theip ar ábhar gearrthaisce a lé",
 	"Failed to read clipboard contents": "Theip ar ábhar gearrthaisce a lé",
+	"Failed to save models configuration": "",
 	"Failed to update settings": "Theip ar shocruithe a nuashonrú",
 	"Failed to update settings": "Theip ar shocruithe a nuashonrú",
 	"Failed to upload file.": "Theip ar uaslódáil an chomhaid.",
 	"Failed to upload file.": "Theip ar uaslódáil an chomhaid.",
 	"February": "Feabhra",
 	"February": "Feabhra",
@@ -570,6 +573,7 @@
 	"Modelfile Content": "Ábhar Modelfile",
 	"Modelfile Content": "Ábhar Modelfile",
 	"Models": "Múnlaí",
 	"Models": "Múnlaí",
 	"Models Access": "Rochtain Múnlaí",
 	"Models Access": "Rochtain Múnlaí",
+	"Models configuration saved successfully": "",
 	"Mojeek Search API Key": "",
 	"Mojeek Search API Key": "",
 	"more": "níos mó",
 	"more": "níos mó",
 	"More": "Tuilleadh",
 	"More": "Tuilleadh",
@@ -589,6 +593,7 @@
 	"No knowledge found": "Níor aimsíodh aon eolas",
 	"No knowledge found": "Níor aimsíodh aon eolas",
 	"No model IDs": "Gan IDanna múnla",
 	"No model IDs": "Gan IDanna múnla",
 	"No models found": "Níor aimsíodh aon mhúnlaí",
 	"No models found": "Níor aimsíodh aon mhúnlaí",
+	"No models selected": "",
 	"No results found": "Níl aon torthaí le fáil",
 	"No results found": "Níl aon torthaí le fáil",
 	"No search query generated": "Ní ghintear aon cheist cuardaigh",
 	"No search query generated": "Ní ghintear aon cheist cuardaigh",
 	"No source available": "Níl aon fhoinse ar fáil",
 	"No source available": "Níl aon fhoinse ar fáil",
@@ -699,6 +704,7 @@
 	"Remove": "Bain",
 	"Remove": "Bain",
 	"Remove Model": "Bain Múnla",
 	"Remove Model": "Bain Múnla",
 	"Rename": "Athainmnigh",
 	"Rename": "Athainmnigh",
+	"Reorder Models": "",
 	"Repeat Last N": "Déan an N deireanach arís",
 	"Repeat Last N": "Déan an N deireanach arís",
 	"Request Mode": "Mód Iarratais",
 	"Request Mode": "Mód Iarratais",
 	"Reranking Model": "Múnla Athrangú",
 	"Reranking Model": "Múnla Athrangú",

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

@@ -167,6 +167,7 @@
 	"Completions": "",
 	"Completions": "",
 	"Concurrent Requests": "Richieste simultanee",
 	"Concurrent Requests": "Richieste simultanee",
 	"Configure": "",
 	"Configure": "",
+	"Configure Models": "",
 	"Confirm": "",
 	"Confirm": "",
 	"Confirm Password": "Conferma password",
 	"Confirm Password": "Conferma password",
 	"Confirm your action": "",
 	"Confirm your action": "",
@@ -215,6 +216,7 @@
 	"Default (SentenceTransformers)": "Predefinito (SentenceTransformers)",
 	"Default (SentenceTransformers)": "Predefinito (SentenceTransformers)",
 	"Default Model": "Modello di default",
 	"Default Model": "Modello di default",
 	"Default model updated": "Modello predefinito aggiornato",
 	"Default model updated": "Modello predefinito aggiornato",
+	"Default Models": "",
 	"Default permissions": "",
 	"Default permissions": "",
 	"Default permissions updated successfully": "",
 	"Default permissions updated successfully": "",
 	"Default Prompt Suggestions": "Suggerimenti prompt predefiniti",
 	"Default Prompt Suggestions": "Suggerimenti prompt predefiniti",
@@ -383,6 +385,7 @@
 	"Failed to add file.": "",
 	"Failed to add file.": "",
 	"Failed to create API Key.": "Impossibile creare la chiave API.",
 	"Failed to create API Key.": "Impossibile creare la chiave API.",
 	"Failed to read clipboard contents": "Impossibile leggere il contenuto degli appunti",
 	"Failed to read clipboard contents": "Impossibile leggere il contenuto degli appunti",
+	"Failed to save models configuration": "",
 	"Failed to update settings": "",
 	"Failed to update settings": "",
 	"Failed to upload file.": "",
 	"Failed to upload file.": "",
 	"February": "Febbraio",
 	"February": "Febbraio",
@@ -570,6 +573,7 @@
 	"Modelfile Content": "Contenuto del file modello",
 	"Modelfile Content": "Contenuto del file modello",
 	"Models": "Modelli",
 	"Models": "Modelli",
 	"Models Access": "",
 	"Models Access": "",
+	"Models configuration saved successfully": "",
 	"Mojeek Search API Key": "",
 	"Mojeek Search API Key": "",
 	"more": "",
 	"more": "",
 	"More": "Altro",
 	"More": "Altro",
@@ -589,6 +593,7 @@
 	"No knowledge found": "",
 	"No knowledge found": "",
 	"No model IDs": "",
 	"No model IDs": "",
 	"No models found": "",
 	"No models found": "",
+	"No models selected": "",
 	"No results found": "Nessun risultato trovato",
 	"No results found": "Nessun risultato trovato",
 	"No search query generated": "Nessuna query di ricerca generata",
 	"No search query generated": "Nessuna query di ricerca generata",
 	"No source available": "Nessuna fonte disponibile",
 	"No source available": "Nessuna fonte disponibile",
@@ -699,6 +704,7 @@
 	"Remove": "Rimuovi",
 	"Remove": "Rimuovi",
 	"Remove Model": "Rimuovi modello",
 	"Remove Model": "Rimuovi modello",
 	"Rename": "Rinomina",
 	"Rename": "Rinomina",
+	"Reorder Models": "",
 	"Repeat Last N": "Ripeti ultimi N",
 	"Repeat Last N": "Ripeti ultimi N",
 	"Request Mode": "Modalità richiesta",
 	"Request Mode": "Modalità richiesta",
 	"Reranking Model": "Modello di riclassificazione",
 	"Reranking Model": "Modello di riclassificazione",

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

@@ -167,6 +167,7 @@
 	"Completions": "",
 	"Completions": "",
 	"Concurrent Requests": "同時リクエスト",
 	"Concurrent Requests": "同時リクエスト",
 	"Configure": "",
 	"Configure": "",
+	"Configure Models": "",
 	"Confirm": "確認",
 	"Confirm": "確認",
 	"Confirm Password": "パスワードを確認",
 	"Confirm Password": "パスワードを確認",
 	"Confirm your action": "あなたのアクションの確認",
 	"Confirm your action": "あなたのアクションの確認",
@@ -215,6 +216,7 @@
 	"Default (SentenceTransformers)": "デフォルト (SentenceTransformers)",
 	"Default (SentenceTransformers)": "デフォルト (SentenceTransformers)",
 	"Default Model": "デフォルトモデル",
 	"Default Model": "デフォルトモデル",
 	"Default model updated": "デフォルトモデルが更新されました",
 	"Default model updated": "デフォルトモデルが更新されました",
+	"Default Models": "",
 	"Default permissions": "",
 	"Default permissions": "",
 	"Default permissions updated successfully": "",
 	"Default permissions updated successfully": "",
 	"Default Prompt Suggestions": "デフォルトのプロンプトの提案",
 	"Default Prompt Suggestions": "デフォルトのプロンプトの提案",
@@ -383,6 +385,7 @@
 	"Failed to add file.": "",
 	"Failed to add file.": "",
 	"Failed to create API Key.": "APIキーの作成に失敗しました。",
 	"Failed to create API Key.": "APIキーの作成に失敗しました。",
 	"Failed to read clipboard contents": "クリップボードの内容を読み取れませんでした",
 	"Failed to read clipboard contents": "クリップボードの内容を読み取れませんでした",
+	"Failed to save models configuration": "",
 	"Failed to update settings": "設定アップデート失敗",
 	"Failed to update settings": "設定アップデート失敗",
 	"Failed to upload file.": "ファイルアップロード失敗",
 	"Failed to upload file.": "ファイルアップロード失敗",
 	"February": "2月",
 	"February": "2月",
@@ -570,6 +573,7 @@
 	"Modelfile Content": "モデルファイルの内容",
 	"Modelfile Content": "モデルファイルの内容",
 	"Models": "モデル",
 	"Models": "モデル",
 	"Models Access": "",
 	"Models Access": "",
+	"Models configuration saved successfully": "",
 	"Mojeek Search API Key": "",
 	"Mojeek Search API Key": "",
 	"more": "",
 	"more": "",
 	"More": "もっと見る",
 	"More": "もっと見る",
@@ -589,6 +593,7 @@
 	"No knowledge found": "知識が見つかりません",
 	"No knowledge found": "知識が見つかりません",
 	"No model IDs": "",
 	"No model IDs": "",
 	"No models found": "",
 	"No models found": "",
+	"No models selected": "",
 	"No results found": "結果が見つかりません",
 	"No results found": "結果が見つかりません",
 	"No search query generated": "検索クエリは生成されません",
 	"No search query generated": "検索クエリは生成されません",
 	"No source available": "使用可能なソースがありません",
 	"No source available": "使用可能なソースがありません",
@@ -699,6 +704,7 @@
 	"Remove": "削除",
 	"Remove": "削除",
 	"Remove Model": "モデルを削除",
 	"Remove Model": "モデルを削除",
 	"Rename": "名前を変更",
 	"Rename": "名前を変更",
+	"Reorder Models": "",
 	"Repeat Last N": "最後の N を繰り返す",
 	"Repeat Last N": "最後の N を繰り返す",
 	"Request Mode": "リクエストモード",
 	"Request Mode": "リクエストモード",
 	"Reranking Model": "モデルの再ランキング",
 	"Reranking Model": "モデルの再ランキング",

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

@@ -167,6 +167,7 @@
 	"Completions": "",
 	"Completions": "",
 	"Concurrent Requests": "თანმხლები მოთხოვნები",
 	"Concurrent Requests": "თანმხლები მოთხოვნები",
 	"Configure": "",
 	"Configure": "",
+	"Configure Models": "",
 	"Confirm": "",
 	"Confirm": "",
 	"Confirm Password": "პაროლის დამოწმება",
 	"Confirm Password": "პაროლის დამოწმება",
 	"Confirm your action": "",
 	"Confirm your action": "",
@@ -215,6 +216,7 @@
 	"Default (SentenceTransformers)": "დეფოლტ (SentenceTransformers)",
 	"Default (SentenceTransformers)": "დეფოლტ (SentenceTransformers)",
 	"Default Model": "ნაგულისხმები მოდელი",
 	"Default Model": "ნაგულისხმები მოდელი",
 	"Default model updated": "დეფოლტ მოდელი განახლებულია",
 	"Default model updated": "დეფოლტ მოდელი განახლებულია",
+	"Default Models": "",
 	"Default permissions": "",
 	"Default permissions": "",
 	"Default permissions updated successfully": "",
 	"Default permissions updated successfully": "",
 	"Default Prompt Suggestions": "დეფოლტ პრომპტი პირველი პირველი",
 	"Default Prompt Suggestions": "დეფოლტ პრომპტი პირველი პირველი",
@@ -383,6 +385,7 @@
 	"Failed to add file.": "",
 	"Failed to add file.": "",
 	"Failed to create API Key.": "API ღილაკის შექმნა ვერ მოხერხდა.",
 	"Failed to create API Key.": "API ღილაკის შექმნა ვერ მოხერხდა.",
 	"Failed to read clipboard contents": "ბუფერში შიგთავსის წაკითხვა ვერ მოხერხდა",
 	"Failed to read clipboard contents": "ბუფერში შიგთავსის წაკითხვა ვერ მოხერხდა",
+	"Failed to save models configuration": "",
 	"Failed to update settings": "",
 	"Failed to update settings": "",
 	"Failed to upload file.": "",
 	"Failed to upload file.": "",
 	"February": "თებერვალი",
 	"February": "თებერვალი",
@@ -570,6 +573,7 @@
 	"Modelfile Content": "მოდელური ფაილის კონტენტი",
 	"Modelfile Content": "მოდელური ფაილის კონტენტი",
 	"Models": "მოდელები",
 	"Models": "მოდელები",
 	"Models Access": "",
 	"Models Access": "",
+	"Models configuration saved successfully": "",
 	"Mojeek Search API Key": "",
 	"Mojeek Search API Key": "",
 	"more": "",
 	"more": "",
 	"More": "ვრცლად",
 	"More": "ვრცლად",
@@ -589,6 +593,7 @@
 	"No knowledge found": "",
 	"No knowledge found": "",
 	"No model IDs": "",
 	"No model IDs": "",
 	"No models found": "",
 	"No models found": "",
+	"No models selected": "",
 	"No results found": "ჩვენ ვერ პოულობით ნაპოვნი ჩაწერები",
 	"No results found": "ჩვენ ვერ პოულობით ნაპოვნი ჩაწერები",
 	"No search query generated": "ძიების მოთხოვნა არ არის გენერირებული",
 	"No search query generated": "ძიების მოთხოვნა არ არის გენერირებული",
 	"No source available": "წყარო არ არის ხელმისაწვდომი",
 	"No source available": "წყარო არ არის ხელმისაწვდომი",
@@ -699,6 +704,7 @@
 	"Remove": "პოპულარობის რაოდენობა",
 	"Remove": "პოპულარობის რაოდენობა",
 	"Remove Model": "პოპულარობის რაოდენობა",
 	"Remove Model": "პოპულარობის რაოდენობა",
 	"Rename": "პოპულარობის რაოდენობა",
 	"Rename": "პოპულარობის რაოდენობა",
+	"Reorder Models": "",
 	"Repeat Last N": "გაიმეორეთ ბოლო N",
 	"Repeat Last N": "გაიმეორეთ ბოლო N",
 	"Request Mode": "მოთხოვნის რეჟიმი",
 	"Request Mode": "მოთხოვნის რეჟიმი",
 	"Reranking Model": "რექვექტირება",
 	"Reranking Model": "რექვექტირება",

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

@@ -167,6 +167,7 @@
 	"Completions": "완성됨",
 	"Completions": "완성됨",
 	"Concurrent Requests": "동시 요청 수",
 	"Concurrent Requests": "동시 요청 수",
 	"Configure": "",
 	"Configure": "",
+	"Configure Models": "",
 	"Confirm": "확인",
 	"Confirm": "확인",
 	"Confirm Password": "비밀번호 확인",
 	"Confirm Password": "비밀번호 확인",
 	"Confirm your action": "액션 확인",
 	"Confirm your action": "액션 확인",
@@ -215,6 +216,7 @@
 	"Default (SentenceTransformers)": "기본값 (SentenceTransformers)",
 	"Default (SentenceTransformers)": "기본값 (SentenceTransformers)",
 	"Default Model": "기본 모델",
 	"Default Model": "기본 모델",
 	"Default model updated": "기본 모델이 업데이트되었습니다.",
 	"Default model updated": "기본 모델이 업데이트되었습니다.",
+	"Default Models": "",
 	"Default permissions": "",
 	"Default permissions": "",
 	"Default permissions updated successfully": "",
 	"Default permissions updated successfully": "",
 	"Default Prompt Suggestions": "기본 프롬프트 제안",
 	"Default Prompt Suggestions": "기본 프롬프트 제안",
@@ -383,6 +385,7 @@
 	"Failed to add file.": "파일추가에 실패했습니다",
 	"Failed to add file.": "파일추가에 실패했습니다",
 	"Failed to create API Key.": "API 키 생성에 실패했습니다.",
 	"Failed to create API Key.": "API 키 생성에 실패했습니다.",
 	"Failed to read clipboard contents": "클립보드 내용 가져오기를 실패하였습니다.",
 	"Failed to read clipboard contents": "클립보드 내용 가져오기를 실패하였습니다.",
+	"Failed to save models configuration": "",
 	"Failed to update settings": "설정 업데이트에 실패하였습니다.",
 	"Failed to update settings": "설정 업데이트에 실패하였습니다.",
 	"Failed to upload file.": "파일 업로드에 실패했습니다",
 	"Failed to upload file.": "파일 업로드에 실패했습니다",
 	"February": "2월",
 	"February": "2월",
@@ -570,6 +573,7 @@
 	"Modelfile Content": "Modelfile 내용",
 	"Modelfile Content": "Modelfile 내용",
 	"Models": "모델",
 	"Models": "모델",
 	"Models Access": "",
 	"Models Access": "",
+	"Models configuration saved successfully": "",
 	"Mojeek Search API Key": "",
 	"Mojeek Search API Key": "",
 	"more": "더보기",
 	"more": "더보기",
 	"More": "더보기",
 	"More": "더보기",
@@ -589,6 +593,7 @@
 	"No knowledge found": "지식 기반 없음",
 	"No knowledge found": "지식 기반 없음",
 	"No model IDs": "",
 	"No model IDs": "",
 	"No models found": "모델 없음",
 	"No models found": "모델 없음",
+	"No models selected": "",
 	"No results found": "결과 없음",
 	"No results found": "결과 없음",
 	"No search query generated": "검색어가 생성되지 않았습니다.",
 	"No search query generated": "검색어가 생성되지 않았습니다.",
 	"No source available": "사용 가능한 소스 없음",
 	"No source available": "사용 가능한 소스 없음",
@@ -699,6 +704,7 @@
 	"Remove": "삭제",
 	"Remove": "삭제",
 	"Remove Model": "모델 삭제",
 	"Remove Model": "모델 삭제",
 	"Rename": "이름 변경",
 	"Rename": "이름 변경",
+	"Reorder Models": "",
 	"Repeat Last N": "마지막 N 반복",
 	"Repeat Last N": "마지막 N 반복",
 	"Request Mode": "요청 모드",
 	"Request Mode": "요청 모드",
 	"Reranking Model": "Reranking 모델",
 	"Reranking Model": "Reranking 모델",

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

@@ -167,6 +167,7 @@
 	"Completions": "",
 	"Completions": "",
 	"Concurrent Requests": "Kelios užklausos vienu metu",
 	"Concurrent Requests": "Kelios užklausos vienu metu",
 	"Configure": "",
 	"Configure": "",
+	"Configure Models": "",
 	"Confirm": "Patvrtinti",
 	"Confirm": "Patvrtinti",
 	"Confirm Password": "Patvirtinkite slaptažodį",
 	"Confirm Password": "Patvirtinkite slaptažodį",
 	"Confirm your action": "Patvirtinkite veiksmą",
 	"Confirm your action": "Patvirtinkite veiksmą",
@@ -215,6 +216,7 @@
 	"Default (SentenceTransformers)": "Numatytasis (SentenceTransformers)",
 	"Default (SentenceTransformers)": "Numatytasis (SentenceTransformers)",
 	"Default Model": "Numatytasis modelis",
 	"Default Model": "Numatytasis modelis",
 	"Default model updated": "Numatytasis modelis atnaujintas",
 	"Default model updated": "Numatytasis modelis atnaujintas",
+	"Default Models": "",
 	"Default permissions": "",
 	"Default permissions": "",
 	"Default permissions updated successfully": "",
 	"Default permissions updated successfully": "",
 	"Default Prompt Suggestions": "Numatytieji užklausų pasiūlymai",
 	"Default Prompt Suggestions": "Numatytieji užklausų pasiūlymai",
@@ -383,6 +385,7 @@
 	"Failed to add file.": "",
 	"Failed to add file.": "",
 	"Failed to create API Key.": "Nepavyko sukurti API rakto",
 	"Failed to create API Key.": "Nepavyko sukurti API rakto",
 	"Failed to read clipboard contents": "Nepavyko perskaityti kopijuoklės",
 	"Failed to read clipboard contents": "Nepavyko perskaityti kopijuoklės",
+	"Failed to save models configuration": "",
 	"Failed to update settings": "Nepavyko atnaujinti nustatymų",
 	"Failed to update settings": "Nepavyko atnaujinti nustatymų",
 	"Failed to upload file.": "",
 	"Failed to upload file.": "",
 	"February": "Vasaris",
 	"February": "Vasaris",
@@ -570,6 +573,7 @@
 	"Modelfile Content": "Modelio failo turinys",
 	"Modelfile Content": "Modelio failo turinys",
 	"Models": "Modeliai",
 	"Models": "Modeliai",
 	"Models Access": "",
 	"Models Access": "",
+	"Models configuration saved successfully": "",
 	"Mojeek Search API Key": "",
 	"Mojeek Search API Key": "",
 	"more": "",
 	"more": "",
 	"More": "Daugiau",
 	"More": "Daugiau",
@@ -589,6 +593,7 @@
 	"No knowledge found": "",
 	"No knowledge found": "",
 	"No model IDs": "",
 	"No model IDs": "",
 	"No models found": "",
 	"No models found": "",
+	"No models selected": "",
 	"No results found": "Rezultatų nerasta",
 	"No results found": "Rezultatų nerasta",
 	"No search query generated": "Paieškos užklausa nesugeneruota",
 	"No search query generated": "Paieškos užklausa nesugeneruota",
 	"No source available": "Šaltinių nerasta",
 	"No source available": "Šaltinių nerasta",
@@ -699,6 +704,7 @@
 	"Remove": "Pašalinti",
 	"Remove": "Pašalinti",
 	"Remove Model": "Pašalinti modelį",
 	"Remove Model": "Pašalinti modelį",
 	"Rename": "Pervadinti",
 	"Rename": "Pervadinti",
+	"Reorder Models": "",
 	"Repeat Last N": "Pakartoti paskutinius N",
 	"Repeat Last N": "Pakartoti paskutinius N",
 	"Request Mode": "Užklausos rėžimas",
 	"Request Mode": "Užklausos rėžimas",
 	"Reranking Model": "Reranking modelis",
 	"Reranking Model": "Reranking modelis",

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

@@ -167,6 +167,7 @@
 	"Completions": "",
 	"Completions": "",
 	"Concurrent Requests": "Permintaan Serentak",
 	"Concurrent Requests": "Permintaan Serentak",
 	"Configure": "",
 	"Configure": "",
+	"Configure Models": "",
 	"Confirm": "Sahkan",
 	"Confirm": "Sahkan",
 	"Confirm Password": "Sahkan kata laluan",
 	"Confirm Password": "Sahkan kata laluan",
 	"Confirm your action": "Sahkan tindakan anda",
 	"Confirm your action": "Sahkan tindakan anda",
@@ -215,6 +216,7 @@
 	"Default (SentenceTransformers)": "Lalai (SentenceTransformers)",
 	"Default (SentenceTransformers)": "Lalai (SentenceTransformers)",
 	"Default Model": "Model Lalai",
 	"Default Model": "Model Lalai",
 	"Default model updated": "Model lalai dikemas kini",
 	"Default model updated": "Model lalai dikemas kini",
+	"Default Models": "",
 	"Default permissions": "",
 	"Default permissions": "",
 	"Default permissions updated successfully": "",
 	"Default permissions updated successfully": "",
 	"Default Prompt Suggestions": "Cadangan Gesaan Lalai",
 	"Default Prompt Suggestions": "Cadangan Gesaan Lalai",
@@ -383,6 +385,7 @@
 	"Failed to add file.": "",
 	"Failed to add file.": "",
 	"Failed to create API Key.": "Gagal mencipta kekunci API",
 	"Failed to create API Key.": "Gagal mencipta kekunci API",
 	"Failed to read clipboard contents": "Gagal membaca konten papan klip",
 	"Failed to read clipboard contents": "Gagal membaca konten papan klip",
+	"Failed to save models configuration": "",
 	"Failed to update settings": "Gagal mengemaskini tetapan",
 	"Failed to update settings": "Gagal mengemaskini tetapan",
 	"Failed to upload file.": "",
 	"Failed to upload file.": "",
 	"February": "Febuari",
 	"February": "Febuari",
@@ -570,6 +573,7 @@
 	"Modelfile Content": "Kandungan Modelfail",
 	"Modelfile Content": "Kandungan Modelfail",
 	"Models": "Model",
 	"Models": "Model",
 	"Models Access": "",
 	"Models Access": "",
+	"Models configuration saved successfully": "",
 	"Mojeek Search API Key": "",
 	"Mojeek Search API Key": "",
 	"more": "",
 	"more": "",
 	"More": "Lagi",
 	"More": "Lagi",
@@ -589,6 +593,7 @@
 	"No knowledge found": "",
 	"No knowledge found": "",
 	"No model IDs": "",
 	"No model IDs": "",
 	"No models found": "",
 	"No models found": "",
+	"No models selected": "",
 	"No results found": "Tiada keputusan dijumpai",
 	"No results found": "Tiada keputusan dijumpai",
 	"No search query generated": "Tiada pertanyaan carian dijana",
 	"No search query generated": "Tiada pertanyaan carian dijana",
 	"No source available": "Tiada sumber tersedia",
 	"No source available": "Tiada sumber tersedia",
@@ -699,6 +704,7 @@
 	"Remove": "Hapuskan",
 	"Remove": "Hapuskan",
 	"Remove Model": "Hapuskan Model",
 	"Remove Model": "Hapuskan Model",
 	"Rename": "Namakan Semula",
 	"Rename": "Namakan Semula",
+	"Reorder Models": "",
 	"Repeat Last N": "Ulang N Terakhir",
 	"Repeat Last N": "Ulang N Terakhir",
 	"Request Mode": "Mod Permintaan",
 	"Request Mode": "Mod Permintaan",
 	"Reranking Model": "Model 'Reranking'",
 	"Reranking Model": "Model 'Reranking'",

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

@@ -167,6 +167,7 @@
 	"Completions": "Fullføringer",
 	"Completions": "Fullføringer",
 	"Concurrent Requests": "Samtidige forespørsler",
 	"Concurrent Requests": "Samtidige forespørsler",
 	"Configure": "Konfigurer",
 	"Configure": "Konfigurer",
+	"Configure Models": "",
 	"Confirm": "Bekreft",
 	"Confirm": "Bekreft",
 	"Confirm Password": "Bekreft passordet",
 	"Confirm Password": "Bekreft passordet",
 	"Confirm your action": "Bekreft handlingen",
 	"Confirm your action": "Bekreft handlingen",
@@ -215,6 +216,7 @@
 	"Default (SentenceTransformers)": "Standard (SentenceTransformers)",
 	"Default (SentenceTransformers)": "Standard (SentenceTransformers)",
 	"Default Model": "Standard modell",
 	"Default Model": "Standard modell",
 	"Default model updated": "Standard modell oppdatert",
 	"Default model updated": "Standard modell oppdatert",
+	"Default Models": "",
 	"Default permissions": "",
 	"Default permissions": "",
 	"Default permissions updated successfully": "",
 	"Default permissions updated successfully": "",
 	"Default Prompt Suggestions": "Standard forslag til ledetekster",
 	"Default Prompt Suggestions": "Standard forslag til ledetekster",
@@ -383,6 +385,7 @@
 	"Failed to add file.": "Kan ikke legge til filen.",
 	"Failed to add file.": "Kan ikke legge til filen.",
 	"Failed to create API Key.": "Kan ikke opprette en API-nøkkel.",
 	"Failed to create API Key.": "Kan ikke opprette en API-nøkkel.",
 	"Failed to read clipboard contents": "Kan ikke lese innhold på utklippstavlen",
 	"Failed to read clipboard contents": "Kan ikke lese innhold på utklippstavlen",
+	"Failed to save models configuration": "",
 	"Failed to update settings": "Kan ikke oppdatere innstillinger",
 	"Failed to update settings": "Kan ikke oppdatere innstillinger",
 	"Failed to upload file.": "Kan ikke laste opp filen.",
 	"Failed to upload file.": "Kan ikke laste opp filen.",
 	"February": "februar",
 	"February": "februar",
@@ -570,6 +573,7 @@
 	"Modelfile Content": "Modellfilinnhold",
 	"Modelfile Content": "Modellfilinnhold",
 	"Models": "Modeller",
 	"Models": "Modeller",
 	"Models Access": "",
 	"Models Access": "",
+	"Models configuration saved successfully": "",
 	"Mojeek Search API Key": "",
 	"Mojeek Search API Key": "",
 	"more": "mer",
 	"more": "mer",
 	"More": "Mer",
 	"More": "Mer",
@@ -589,6 +593,7 @@
 	"No knowledge found": "Finner ingen kunnskaper",
 	"No knowledge found": "Finner ingen kunnskaper",
 	"No model IDs": "",
 	"No model IDs": "",
 	"No models found": "Finner ingen modeller",
 	"No models found": "Finner ingen modeller",
+	"No models selected": "",
 	"No results found": "Finner ingen resultater",
 	"No results found": "Finner ingen resultater",
 	"No search query generated": "Ingen søkespørringer er generert",
 	"No search query generated": "Ingen søkespørringer er generert",
 	"No source available": "Ingen kilde tilgjengelig",
 	"No source available": "Ingen kilde tilgjengelig",
@@ -699,6 +704,7 @@
 	"Remove": "Fjern",
 	"Remove": "Fjern",
 	"Remove Model": "Fjern modell",
 	"Remove Model": "Fjern modell",
 	"Rename": "Gi nytt navn",
 	"Rename": "Gi nytt navn",
+	"Reorder Models": "",
 	"Repeat Last N": "Gjenta siste N",
 	"Repeat Last N": "Gjenta siste N",
 	"Request Mode": "Forespørselsmodus",
 	"Request Mode": "Forespørselsmodus",
 	"Reranking Model": "Omrangeringsmodell",
 	"Reranking Model": "Omrangeringsmodell",

+ 7 - 1
src/lib/i18n/locales/nl-NL/translation.json

@@ -167,6 +167,7 @@
 	"Completions": "Voltooiingen",
 	"Completions": "Voltooiingen",
 	"Concurrent Requests": "Gelijktijdige verzoeken",
 	"Concurrent Requests": "Gelijktijdige verzoeken",
 	"Configure": "Configureer",
 	"Configure": "Configureer",
+	"Configure Models": "",
 	"Confirm": "Bevestigen",
 	"Confirm": "Bevestigen",
 	"Confirm Password": "Bevestig wachtwoord",
 	"Confirm Password": "Bevestig wachtwoord",
 	"Confirm your action": "Bevestig uw actie",
 	"Confirm your action": "Bevestig uw actie",
@@ -215,6 +216,7 @@
 	"Default (SentenceTransformers)": "Standaard (SentenceTransformers)",
 	"Default (SentenceTransformers)": "Standaard (SentenceTransformers)",
 	"Default Model": "Standaard model",
 	"Default Model": "Standaard model",
 	"Default model updated": "Standaard model bijgewerkt",
 	"Default model updated": "Standaard model bijgewerkt",
+	"Default Models": "",
 	"Default permissions": "Standaardrechten",
 	"Default permissions": "Standaardrechten",
 	"Default permissions updated successfully": "Standaardrechten succesvol bijgewerkt",
 	"Default permissions updated successfully": "Standaardrechten succesvol bijgewerkt",
 	"Default Prompt Suggestions": "Standaard Prompt Suggesties",
 	"Default Prompt Suggestions": "Standaard Prompt Suggesties",
@@ -383,6 +385,7 @@
 	"Failed to add file.": "Het is niet gelukt om het bestand toe te voegen.",
 	"Failed to add file.": "Het is niet gelukt om het bestand toe te voegen.",
 	"Failed to create API Key.": "Kan API Key niet aanmaken.",
 	"Failed to create API Key.": "Kan API Key niet aanmaken.",
 	"Failed to read clipboard contents": "Kan klembord inhoud niet lezen",
 	"Failed to read clipboard contents": "Kan klembord inhoud niet lezen",
+	"Failed to save models configuration": "",
 	"Failed to update settings": "Instellingen konden niet worden bijgewerkt.",
 	"Failed to update settings": "Instellingen konden niet worden bijgewerkt.",
 	"Failed to upload file.": "Bestand kon niet worden geüpload.",
 	"Failed to upload file.": "Bestand kon niet worden geüpload.",
 	"February": "Februari",
 	"February": "Februari",
@@ -441,7 +444,7 @@
 	"Group Description": "Groepsbeschrijving",
 	"Group Description": "Groepsbeschrijving",
 	"Group Name": "Groepsnaam",
 	"Group Name": "Groepsnaam",
 	"Group updated successfully": "Groep succesvol bijgewerkt",
 	"Group updated successfully": "Groep succesvol bijgewerkt",
-	"Groups": "GRoepen",
+	"Groups": "Groepen",
 	"h:mm a": "h:mm a",
 	"h:mm a": "h:mm a",
 	"Haptic Feedback": "Haptische feedback",
 	"Haptic Feedback": "Haptische feedback",
 	"has no conversations.": "heeft geen gesprekken.",
 	"has no conversations.": "heeft geen gesprekken.",
@@ -570,6 +573,7 @@
 	"Modelfile Content": "Modelfile Inhoud",
 	"Modelfile Content": "Modelfile Inhoud",
 	"Models": "Modellen",
 	"Models": "Modellen",
 	"Models Access": "Modellentoegang",
 	"Models Access": "Modellentoegang",
+	"Models configuration saved successfully": "",
 	"Mojeek Search API Key": "",
 	"Mojeek Search API Key": "",
 	"more": "Meer",
 	"more": "Meer",
 	"More": "Meer",
 	"More": "Meer",
@@ -589,6 +593,7 @@
 	"No knowledge found": "Geen kennis gevonden",
 	"No knowledge found": "Geen kennis gevonden",
 	"No model IDs": "Geen model-ID's",
 	"No model IDs": "Geen model-ID's",
 	"No models found": "Geen modellen gevonden",
 	"No models found": "Geen modellen gevonden",
+	"No models selected": "",
 	"No results found": "Geen resultaten gevonden",
 	"No results found": "Geen resultaten gevonden",
 	"No search query generated": "Geen zoekopdracht gegenereerd",
 	"No search query generated": "Geen zoekopdracht gegenereerd",
 	"No source available": "Geen bron beschikbaar",
 	"No source available": "Geen bron beschikbaar",
@@ -699,6 +704,7 @@
 	"Remove": "Verwijderen",
 	"Remove": "Verwijderen",
 	"Remove Model": "Verwijder model",
 	"Remove Model": "Verwijder model",
 	"Rename": "Hernoemen",
 	"Rename": "Hernoemen",
+	"Reorder Models": "",
 	"Repeat Last N": "Herhaal Laatste N",
 	"Repeat Last N": "Herhaal Laatste N",
 	"Request Mode": "Request Modus",
 	"Request Mode": "Request Modus",
 	"Reranking Model": "Reranking Model",
 	"Reranking Model": "Reranking Model",

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

@@ -167,6 +167,7 @@
 	"Completions": "",
 	"Completions": "",
 	"Concurrent Requests": "ਸਮਕਾਲੀ ਬੇਨਤੀਆਂ",
 	"Concurrent Requests": "ਸਮਕਾਲੀ ਬੇਨਤੀਆਂ",
 	"Configure": "",
 	"Configure": "",
+	"Configure Models": "",
 	"Confirm": "",
 	"Confirm": "",
 	"Confirm Password": "ਪਾਸਵਰਡ ਦੀ ਪੁਸ਼ਟੀ ਕਰੋ",
 	"Confirm Password": "ਪਾਸਵਰਡ ਦੀ ਪੁਸ਼ਟੀ ਕਰੋ",
 	"Confirm your action": "",
 	"Confirm your action": "",
@@ -215,6 +216,7 @@
 	"Default (SentenceTransformers)": "ਮੂਲ (ਸੈਂਟੈਂਸਟ੍ਰਾਂਸਫਾਰਮਰਸ)",
 	"Default (SentenceTransformers)": "ਮੂਲ (ਸੈਂਟੈਂਸਟ੍ਰਾਂਸਫਾਰਮਰਸ)",
 	"Default Model": "ਡਿਫਾਲਟ ਮਾਡਲ",
 	"Default Model": "ਡਿਫਾਲਟ ਮਾਡਲ",
 	"Default model updated": "ਮੂਲ ਮਾਡਲ ਅੱਪਡੇਟ ਕੀਤਾ ਗਿਆ",
 	"Default model updated": "ਮੂਲ ਮਾਡਲ ਅੱਪਡੇਟ ਕੀਤਾ ਗਿਆ",
+	"Default Models": "",
 	"Default permissions": "",
 	"Default permissions": "",
 	"Default permissions updated successfully": "",
 	"Default permissions updated successfully": "",
 	"Default Prompt Suggestions": "ਮੂਲ ਪ੍ਰੰਪਟ ਸੁਝਾਅ",
 	"Default Prompt Suggestions": "ਮੂਲ ਪ੍ਰੰਪਟ ਸੁਝਾਅ",
@@ -383,6 +385,7 @@
 	"Failed to add file.": "",
 	"Failed to add file.": "",
 	"Failed to create API Key.": "API ਕੁੰਜੀ ਬਣਾਉਣ ਵਿੱਚ ਅਸਫਲ।",
 	"Failed to create API Key.": "API ਕੁੰਜੀ ਬਣਾਉਣ ਵਿੱਚ ਅਸਫਲ।",
 	"Failed to read clipboard contents": "ਕਲਿੱਪਬੋਰਡ ਸਮੱਗਰੀ ਪੜ੍ਹਣ ਵਿੱਚ ਅਸਫਲ",
 	"Failed to read clipboard contents": "ਕਲਿੱਪਬੋਰਡ ਸਮੱਗਰੀ ਪੜ੍ਹਣ ਵਿੱਚ ਅਸਫਲ",
+	"Failed to save models configuration": "",
 	"Failed to update settings": "",
 	"Failed to update settings": "",
 	"Failed to upload file.": "",
 	"Failed to upload file.": "",
 	"February": "ਫਰਵਰੀ",
 	"February": "ਫਰਵਰੀ",
@@ -570,6 +573,7 @@
 	"Modelfile Content": "ਮਾਡਲਫਾਈਲ ਸਮੱਗਰੀ",
 	"Modelfile Content": "ਮਾਡਲਫਾਈਲ ਸਮੱਗਰੀ",
 	"Models": "ਮਾਡਲ",
 	"Models": "ਮਾਡਲ",
 	"Models Access": "",
 	"Models Access": "",
+	"Models configuration saved successfully": "",
 	"Mojeek Search API Key": "",
 	"Mojeek Search API Key": "",
 	"more": "",
 	"more": "",
 	"More": "ਹੋਰ",
 	"More": "ਹੋਰ",
@@ -589,6 +593,7 @@
 	"No knowledge found": "",
 	"No knowledge found": "",
 	"No model IDs": "",
 	"No model IDs": "",
 	"No models found": "",
 	"No models found": "",
+	"No models selected": "",
 	"No results found": "ਕੋਈ ਨਤੀਜੇ ਨਹੀਂ ਮਿਲੇ",
 	"No results found": "ਕੋਈ ਨਤੀਜੇ ਨਹੀਂ ਮਿਲੇ",
 	"No search query generated": "ਕੋਈ ਖੋਜ ਪੁੱਛਗਿੱਛ ਤਿਆਰ ਨਹੀਂ ਕੀਤੀ ਗਈ",
 	"No search query generated": "ਕੋਈ ਖੋਜ ਪੁੱਛਗਿੱਛ ਤਿਆਰ ਨਹੀਂ ਕੀਤੀ ਗਈ",
 	"No source available": "ਕੋਈ ਸਰੋਤ ਉਪਲਬਧ ਨਹੀਂ",
 	"No source available": "ਕੋਈ ਸਰੋਤ ਉਪਲਬਧ ਨਹੀਂ",
@@ -699,6 +704,7 @@
 	"Remove": "ਹਟਾਓ",
 	"Remove": "ਹਟਾਓ",
 	"Remove Model": "ਮਾਡਲ ਹਟਾਓ",
 	"Remove Model": "ਮਾਡਲ ਹਟਾਓ",
 	"Rename": "ਨਾਮ ਬਦਲੋ",
 	"Rename": "ਨਾਮ ਬਦਲੋ",
+	"Reorder Models": "",
 	"Repeat Last N": "ਆਖਰੀ N ਨੂੰ ਦੁਹਰਾਓ",
 	"Repeat Last N": "ਆਖਰੀ N ਨੂੰ ਦੁਹਰਾਓ",
 	"Request Mode": "ਬੇਨਤੀ ਮੋਡ",
 	"Request Mode": "ਬੇਨਤੀ ਮੋਡ",
 	"Reranking Model": "ਮਾਡਲ ਮੁੜ ਰੈਂਕਿੰਗ",
 	"Reranking Model": "ਮਾਡਲ ਮੁੜ ਰੈਂਕਿੰਗ",

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

@@ -167,6 +167,7 @@
 	"Completions": "",
 	"Completions": "",
 	"Concurrent Requests": "Równoczesne żądania",
 	"Concurrent Requests": "Równoczesne żądania",
 	"Configure": "",
 	"Configure": "",
+	"Configure Models": "",
 	"Confirm": "",
 	"Confirm": "",
 	"Confirm Password": "Potwierdź hasło",
 	"Confirm Password": "Potwierdź hasło",
 	"Confirm your action": "",
 	"Confirm your action": "",
@@ -215,6 +216,7 @@
 	"Default (SentenceTransformers)": "Domyślny (SentenceTransformers)",
 	"Default (SentenceTransformers)": "Domyślny (SentenceTransformers)",
 	"Default Model": "Model domyślny",
 	"Default Model": "Model domyślny",
 	"Default model updated": "Domyślny model zaktualizowany",
 	"Default model updated": "Domyślny model zaktualizowany",
+	"Default Models": "",
 	"Default permissions": "",
 	"Default permissions": "",
 	"Default permissions updated successfully": "",
 	"Default permissions updated successfully": "",
 	"Default Prompt Suggestions": "Domyślne sugestie promptów",
 	"Default Prompt Suggestions": "Domyślne sugestie promptów",
@@ -383,6 +385,7 @@
 	"Failed to add file.": "",
 	"Failed to add file.": "",
 	"Failed to create API Key.": "Nie udało się utworzyć klucza API.",
 	"Failed to create API Key.": "Nie udało się utworzyć klucza API.",
 	"Failed to read clipboard contents": "Nie udało się odczytać zawartości schowka",
 	"Failed to read clipboard contents": "Nie udało się odczytać zawartości schowka",
+	"Failed to save models configuration": "",
 	"Failed to update settings": "",
 	"Failed to update settings": "",
 	"Failed to upload file.": "",
 	"Failed to upload file.": "",
 	"February": "Luty",
 	"February": "Luty",
@@ -570,6 +573,7 @@
 	"Modelfile Content": "Zawartość pliku modelu",
 	"Modelfile Content": "Zawartość pliku modelu",
 	"Models": "Modele",
 	"Models": "Modele",
 	"Models Access": "",
 	"Models Access": "",
+	"Models configuration saved successfully": "",
 	"Mojeek Search API Key": "",
 	"Mojeek Search API Key": "",
 	"more": "",
 	"more": "",
 	"More": "Więcej",
 	"More": "Więcej",
@@ -589,6 +593,7 @@
 	"No knowledge found": "",
 	"No knowledge found": "",
 	"No model IDs": "",
 	"No model IDs": "",
 	"No models found": "",
 	"No models found": "",
+	"No models selected": "",
 	"No results found": "Nie znaleziono rezultatów",
 	"No results found": "Nie znaleziono rezultatów",
 	"No search query generated": "Nie wygenerowano zapytania wyszukiwania",
 	"No search query generated": "Nie wygenerowano zapytania wyszukiwania",
 	"No source available": "Źródło nie dostępne",
 	"No source available": "Źródło nie dostępne",
@@ -699,6 +704,7 @@
 	"Remove": "Usuń",
 	"Remove": "Usuń",
 	"Remove Model": "Usuń model",
 	"Remove Model": "Usuń model",
 	"Rename": "ZMień nazwę",
 	"Rename": "ZMień nazwę",
+	"Reorder Models": "",
 	"Repeat Last N": "Powtórz ostatnie N",
 	"Repeat Last N": "Powtórz ostatnie N",
 	"Request Mode": "Tryb żądania",
 	"Request Mode": "Tryb żądania",
 	"Reranking Model": "Zmiana rankingu modelu",
 	"Reranking Model": "Zmiana rankingu modelu",

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

@@ -167,6 +167,7 @@
 	"Completions": "Conclusões",
 	"Completions": "Conclusões",
 	"Concurrent Requests": "Solicitações Concomitantes",
 	"Concurrent Requests": "Solicitações Concomitantes",
 	"Configure": "Configurar",
 	"Configure": "Configurar",
+	"Configure Models": "",
 	"Confirm": "Confirmar",
 	"Confirm": "Confirmar",
 	"Confirm Password": "Confirmar Senha",
 	"Confirm Password": "Confirmar Senha",
 	"Confirm your action": "Confirme sua ação",
 	"Confirm your action": "Confirme sua ação",
@@ -215,6 +216,7 @@
 	"Default (SentenceTransformers)": "Padrão (SentenceTransformers)",
 	"Default (SentenceTransformers)": "Padrão (SentenceTransformers)",
 	"Default Model": "Modelo Padrão",
 	"Default Model": "Modelo Padrão",
 	"Default model updated": "Modelo padrão atualizado",
 	"Default model updated": "Modelo padrão atualizado",
+	"Default Models": "",
 	"Default permissions": "Permissões padrão",
 	"Default permissions": "Permissões padrão",
 	"Default permissions updated successfully": "Permissões padrão atualizadas com sucesso",
 	"Default permissions updated successfully": "Permissões padrão atualizadas com sucesso",
 	"Default Prompt Suggestions": "Sugestões de Prompt Padrão",
 	"Default Prompt Suggestions": "Sugestões de Prompt Padrão",
@@ -383,6 +385,7 @@
 	"Failed to add file.": "Falha ao adicionar arquivo.",
 	"Failed to add file.": "Falha ao adicionar arquivo.",
 	"Failed to create API Key.": "Falha ao criar a Chave API.",
 	"Failed to create API Key.": "Falha ao criar a Chave API.",
 	"Failed to read clipboard contents": "Falha ao ler o conteúdo da área de transferência",
 	"Failed to read clipboard contents": "Falha ao ler o conteúdo da área de transferência",
+	"Failed to save models configuration": "",
 	"Failed to update settings": "Falha ao atualizar as configurações",
 	"Failed to update settings": "Falha ao atualizar as configurações",
 	"Failed to upload file.": "Falha ao carregar o arquivo.",
 	"Failed to upload file.": "Falha ao carregar o arquivo.",
 	"February": "Fevereiro",
 	"February": "Fevereiro",
@@ -570,6 +573,7 @@
 	"Modelfile Content": "Conteúdo do Arquivo do Modelo",
 	"Modelfile Content": "Conteúdo do Arquivo do Modelo",
 	"Models": "Modelos",
 	"Models": "Modelos",
 	"Models Access": "Acesso aos Modelos",
 	"Models Access": "Acesso aos Modelos",
+	"Models configuration saved successfully": "",
 	"Mojeek Search API Key": "Chave de API Mojeel Search",
 	"Mojeek Search API Key": "Chave de API Mojeel Search",
 	"more": "mais",
 	"more": "mais",
 	"More": "Mais",
 	"More": "Mais",
@@ -589,6 +593,7 @@
 	"No knowledge found": "Nenhum conhecimento encontrado",
 	"No knowledge found": "Nenhum conhecimento encontrado",
 	"No model IDs": "Nenhum ID de modelo",
 	"No model IDs": "Nenhum ID de modelo",
 	"No models found": "Nenhum modelo encontrado",
 	"No models found": "Nenhum modelo encontrado",
+	"No models selected": "",
 	"No results found": "Nenhum resultado encontrado",
 	"No results found": "Nenhum resultado encontrado",
 	"No search query generated": "Nenhuma consulta de pesquisa gerada",
 	"No search query generated": "Nenhuma consulta de pesquisa gerada",
 	"No source available": "Nenhuma fonte disponível",
 	"No source available": "Nenhuma fonte disponível",
@@ -699,6 +704,7 @@
 	"Remove": "Remover",
 	"Remove": "Remover",
 	"Remove Model": "Remover Modelo",
 	"Remove Model": "Remover Modelo",
 	"Rename": "Renomear",
 	"Rename": "Renomear",
+	"Reorder Models": "",
 	"Repeat Last N": "Repetir Último N",
 	"Repeat Last N": "Repetir Último N",
 	"Request Mode": "Modo de Solicitação",
 	"Request Mode": "Modo de Solicitação",
 	"Reranking Model": "Modelo de Reclassificação",
 	"Reranking Model": "Modelo de Reclassificação",

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

@@ -167,6 +167,7 @@
 	"Completions": "",
 	"Completions": "",
 	"Concurrent Requests": "Solicitações simultâneas",
 	"Concurrent Requests": "Solicitações simultâneas",
 	"Configure": "",
 	"Configure": "",
+	"Configure Models": "",
 	"Confirm": "",
 	"Confirm": "",
 	"Confirm Password": "Confirmar Senha",
 	"Confirm Password": "Confirmar Senha",
 	"Confirm your action": "",
 	"Confirm your action": "",
@@ -215,6 +216,7 @@
 	"Default (SentenceTransformers)": "Padrão (SentenceTransformers)",
 	"Default (SentenceTransformers)": "Padrão (SentenceTransformers)",
 	"Default Model": "Modelo padrão",
 	"Default Model": "Modelo padrão",
 	"Default model updated": "Modelo padrão atualizado",
 	"Default model updated": "Modelo padrão atualizado",
+	"Default Models": "",
 	"Default permissions": "",
 	"Default permissions": "",
 	"Default permissions updated successfully": "",
 	"Default permissions updated successfully": "",
 	"Default Prompt Suggestions": "Sugestões de Prompt Padrão",
 	"Default Prompt Suggestions": "Sugestões de Prompt Padrão",
@@ -383,6 +385,7 @@
 	"Failed to add file.": "",
 	"Failed to add file.": "",
 	"Failed to create API Key.": "Falha ao criar a Chave da API.",
 	"Failed to create API Key.": "Falha ao criar a Chave da API.",
 	"Failed to read clipboard contents": "Falha ao ler o conteúdo da área de transferência",
 	"Failed to read clipboard contents": "Falha ao ler o conteúdo da área de transferência",
+	"Failed to save models configuration": "",
 	"Failed to update settings": "Falha ao atualizar as definições",
 	"Failed to update settings": "Falha ao atualizar as definições",
 	"Failed to upload file.": "",
 	"Failed to upload file.": "",
 	"February": "Fevereiro",
 	"February": "Fevereiro",
@@ -570,6 +573,7 @@
 	"Modelfile Content": "Conteúdo do Ficheiro do Modelo",
 	"Modelfile Content": "Conteúdo do Ficheiro do Modelo",
 	"Models": "Modelos",
 	"Models": "Modelos",
 	"Models Access": "",
 	"Models Access": "",
+	"Models configuration saved successfully": "",
 	"Mojeek Search API Key": "",
 	"Mojeek Search API Key": "",
 	"more": "",
 	"more": "",
 	"More": "Mais",
 	"More": "Mais",
@@ -589,6 +593,7 @@
 	"No knowledge found": "",
 	"No knowledge found": "",
 	"No model IDs": "",
 	"No model IDs": "",
 	"No models found": "",
 	"No models found": "",
+	"No models selected": "",
 	"No results found": "Não foram encontrados resultados",
 	"No results found": "Não foram encontrados resultados",
 	"No search query generated": "Não foi gerada nenhuma consulta de pesquisa",
 	"No search query generated": "Não foi gerada nenhuma consulta de pesquisa",
 	"No source available": "Nenhuma fonte disponível",
 	"No source available": "Nenhuma fonte disponível",
@@ -699,6 +704,7 @@
 	"Remove": "Remover",
 	"Remove": "Remover",
 	"Remove Model": "Remover Modelo",
 	"Remove Model": "Remover Modelo",
 	"Rename": "Renomear",
 	"Rename": "Renomear",
+	"Reorder Models": "",
 	"Repeat Last N": "Repetir Últimos N",
 	"Repeat Last N": "Repetir Últimos N",
 	"Request Mode": "Modo de Pedido",
 	"Request Mode": "Modo de Pedido",
 	"Reranking Model": "Modelo de Reranking",
 	"Reranking Model": "Modelo de Reranking",

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

@@ -167,6 +167,7 @@
 	"Completions": "Completări",
 	"Completions": "Completări",
 	"Concurrent Requests": "Cereri Concurente",
 	"Concurrent Requests": "Cereri Concurente",
 	"Configure": "",
 	"Configure": "",
+	"Configure Models": "",
 	"Confirm": "Confirmă",
 	"Confirm": "Confirmă",
 	"Confirm Password": "Confirmă Parola",
 	"Confirm Password": "Confirmă Parola",
 	"Confirm your action": "Confirmă acțiunea ta",
 	"Confirm your action": "Confirmă acțiunea ta",
@@ -215,6 +216,7 @@
 	"Default (SentenceTransformers)": "Implicit (SentenceTransformers)",
 	"Default (SentenceTransformers)": "Implicit (SentenceTransformers)",
 	"Default Model": "Model Implicit",
 	"Default Model": "Model Implicit",
 	"Default model updated": "Modelul implicit a fost actualizat",
 	"Default model updated": "Modelul implicit a fost actualizat",
+	"Default Models": "",
 	"Default permissions": "",
 	"Default permissions": "",
 	"Default permissions updated successfully": "",
 	"Default permissions updated successfully": "",
 	"Default Prompt Suggestions": "Sugestii de Prompt Implicite",
 	"Default Prompt Suggestions": "Sugestii de Prompt Implicite",
@@ -383,6 +385,7 @@
 	"Failed to add file.": "Eșec la adăugarea fișierului.",
 	"Failed to add file.": "Eșec la adăugarea fișierului.",
 	"Failed to create API Key.": "Crearea cheii API a eșuat.",
 	"Failed to create API Key.": "Crearea cheii API a eșuat.",
 	"Failed to read clipboard contents": "Citirea conținutului clipboard-ului a eșuat",
 	"Failed to read clipboard contents": "Citirea conținutului clipboard-ului a eșuat",
+	"Failed to save models configuration": "",
 	"Failed to update settings": "Actualizarea setărilor a eșuat",
 	"Failed to update settings": "Actualizarea setărilor a eșuat",
 	"Failed to upload file.": "Încărcarea fișierului a eșuat.",
 	"Failed to upload file.": "Încărcarea fișierului a eșuat.",
 	"February": "Februarie",
 	"February": "Februarie",
@@ -570,6 +573,7 @@
 	"Modelfile Content": "Conținutul Fișierului Model",
 	"Modelfile Content": "Conținutul Fișierului Model",
 	"Models": "Modele",
 	"Models": "Modele",
 	"Models Access": "",
 	"Models Access": "",
+	"Models configuration saved successfully": "",
 	"Mojeek Search API Key": "",
 	"Mojeek Search API Key": "",
 	"more": "mai mult",
 	"more": "mai mult",
 	"More": "Mai multe",
 	"More": "Mai multe",
@@ -589,6 +593,7 @@
 	"No knowledge found": "Nu au fost găsite informații.",
 	"No knowledge found": "Nu au fost găsite informații.",
 	"No model IDs": "",
 	"No model IDs": "",
 	"No models found": "Nu s-au găsit modele",
 	"No models found": "Nu s-au găsit modele",
+	"No models selected": "",
 	"No results found": "Nu au fost găsite rezultate",
 	"No results found": "Nu au fost găsite rezultate",
 	"No search query generated": "Nu a fost generată nicio interogare de căutare",
 	"No search query generated": "Nu a fost generată nicio interogare de căutare",
 	"No source available": "Nicio sursă disponibilă",
 	"No source available": "Nicio sursă disponibilă",
@@ -699,6 +704,7 @@
 	"Remove": "Înlătură",
 	"Remove": "Înlătură",
 	"Remove Model": "Înlătură Modelul",
 	"Remove Model": "Înlătură Modelul",
 	"Rename": "Redenumește",
 	"Rename": "Redenumește",
+	"Reorder Models": "",
 	"Repeat Last N": "Repetă Ultimele N",
 	"Repeat Last N": "Repetă Ultimele N",
 	"Request Mode": "Mod de Cerere",
 	"Request Mode": "Mod de Cerere",
 	"Reranking Model": "Model de Rearanjare",
 	"Reranking Model": "Model de Rearanjare",

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

@@ -167,6 +167,7 @@
 	"Completions": "",
 	"Completions": "",
 	"Concurrent Requests": "Одновременные запросы",
 	"Concurrent Requests": "Одновременные запросы",
 	"Configure": "",
 	"Configure": "",
+	"Configure Models": "",
 	"Confirm": "Подтвердить",
 	"Confirm": "Подтвердить",
 	"Confirm Password": "Подтвердите пароль",
 	"Confirm Password": "Подтвердите пароль",
 	"Confirm your action": "Подтвердите свое действие",
 	"Confirm your action": "Подтвердите свое действие",
@@ -215,6 +216,7 @@
 	"Default (SentenceTransformers)": "По умолчанию (SentenceTransformers)",
 	"Default (SentenceTransformers)": "По умолчанию (SentenceTransformers)",
 	"Default Model": "Модель по умолчанию",
 	"Default Model": "Модель по умолчанию",
 	"Default model updated": "Модель по умолчанию обновлена",
 	"Default model updated": "Модель по умолчанию обновлена",
+	"Default Models": "",
 	"Default permissions": "",
 	"Default permissions": "",
 	"Default permissions updated successfully": "",
 	"Default permissions updated successfully": "",
 	"Default Prompt Suggestions": "Предложения промптов по умолчанию",
 	"Default Prompt Suggestions": "Предложения промптов по умолчанию",
@@ -383,6 +385,7 @@
 	"Failed to add file.": "",
 	"Failed to add file.": "",
 	"Failed to create API Key.": "Не удалось создать ключ API.",
 	"Failed to create API Key.": "Не удалось создать ключ API.",
 	"Failed to read clipboard contents": "Не удалось прочитать содержимое буфера обмена",
 	"Failed to read clipboard contents": "Не удалось прочитать содержимое буфера обмена",
+	"Failed to save models configuration": "",
 	"Failed to update settings": "Не удалось обновить настройки",
 	"Failed to update settings": "Не удалось обновить настройки",
 	"Failed to upload file.": "",
 	"Failed to upload file.": "",
 	"February": "Февраль",
 	"February": "Февраль",
@@ -570,6 +573,7 @@
 	"Modelfile Content": "Содержимое файла модели",
 	"Modelfile Content": "Содержимое файла модели",
 	"Models": "Модели",
 	"Models": "Модели",
 	"Models Access": "",
 	"Models Access": "",
+	"Models configuration saved successfully": "",
 	"Mojeek Search API Key": "",
 	"Mojeek Search API Key": "",
 	"more": "",
 	"more": "",
 	"More": "Больше",
 	"More": "Больше",
@@ -589,6 +593,7 @@
 	"No knowledge found": "",
 	"No knowledge found": "",
 	"No model IDs": "",
 	"No model IDs": "",
 	"No models found": "",
 	"No models found": "",
+	"No models selected": "",
 	"No results found": "Результатов не найдено",
 	"No results found": "Результатов не найдено",
 	"No search query generated": "Поисковый запрос не сгенерирован",
 	"No search query generated": "Поисковый запрос не сгенерирован",
 	"No source available": "Нет доступных источников",
 	"No source available": "Нет доступных источников",
@@ -699,6 +704,7 @@
 	"Remove": "Удалить",
 	"Remove": "Удалить",
 	"Remove Model": "Удалить модель",
 	"Remove Model": "Удалить модель",
 	"Rename": "Переименовать",
 	"Rename": "Переименовать",
+	"Reorder Models": "",
 	"Repeat Last N": "Повторить последние N",
 	"Repeat Last N": "Повторить последние N",
 	"Request Mode": "Режим запроса",
 	"Request Mode": "Режим запроса",
 	"Reranking Model": "Модель реранжирования",
 	"Reranking Model": "Модель реранжирования",

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

@@ -167,6 +167,7 @@
 	"Completions": "",
 	"Completions": "",
 	"Concurrent Requests": "Упоредни захтеви",
 	"Concurrent Requests": "Упоредни захтеви",
 	"Configure": "",
 	"Configure": "",
+	"Configure Models": "",
 	"Confirm": "",
 	"Confirm": "",
 	"Confirm Password": "Потврди лозинку",
 	"Confirm Password": "Потврди лозинку",
 	"Confirm your action": "",
 	"Confirm your action": "",
@@ -215,6 +216,7 @@
 	"Default (SentenceTransformers)": "Подразумевано (SentenceTransformers)",
 	"Default (SentenceTransformers)": "Подразумевано (SentenceTransformers)",
 	"Default Model": "Подразумевани модел",
 	"Default Model": "Подразумевани модел",
 	"Default model updated": "Подразумевани модел ажуриран",
 	"Default model updated": "Подразумевани модел ажуриран",
+	"Default Models": "",
 	"Default permissions": "",
 	"Default permissions": "",
 	"Default permissions updated successfully": "",
 	"Default permissions updated successfully": "",
 	"Default Prompt Suggestions": "Подразумевани предлози упита",
 	"Default Prompt Suggestions": "Подразумевани предлози упита",
@@ -383,6 +385,7 @@
 	"Failed to add file.": "",
 	"Failed to add file.": "",
 	"Failed to create API Key.": "Неуспешно стварање API кључа.",
 	"Failed to create API Key.": "Неуспешно стварање API кључа.",
 	"Failed to read clipboard contents": "Неуспешно читање садржаја оставе",
 	"Failed to read clipboard contents": "Неуспешно читање садржаја оставе",
+	"Failed to save models configuration": "",
 	"Failed to update settings": "",
 	"Failed to update settings": "",
 	"Failed to upload file.": "",
 	"Failed to upload file.": "",
 	"February": "Фебруар",
 	"February": "Фебруар",
@@ -570,6 +573,7 @@
 	"Modelfile Content": "Садржај модел-датотеке",
 	"Modelfile Content": "Садржај модел-датотеке",
 	"Models": "Модели",
 	"Models": "Модели",
 	"Models Access": "",
 	"Models Access": "",
+	"Models configuration saved successfully": "",
 	"Mojeek Search API Key": "",
 	"Mojeek Search API Key": "",
 	"more": "",
 	"more": "",
 	"More": "Више",
 	"More": "Више",
@@ -589,6 +593,7 @@
 	"No knowledge found": "",
 	"No knowledge found": "",
 	"No model IDs": "",
 	"No model IDs": "",
 	"No models found": "",
 	"No models found": "",
+	"No models selected": "",
 	"No results found": "Нема резултата",
 	"No results found": "Нема резултата",
 	"No search query generated": "Није генерисан упит за претрагу",
 	"No search query generated": "Није генерисан упит за претрагу",
 	"No source available": "Нема доступног извора",
 	"No source available": "Нема доступног извора",
@@ -699,6 +704,7 @@
 	"Remove": "Уклони",
 	"Remove": "Уклони",
 	"Remove Model": "Уклони модел",
 	"Remove Model": "Уклони модел",
 	"Rename": "Преименуј",
 	"Rename": "Преименуј",
+	"Reorder Models": "",
 	"Repeat Last N": "Понови последњих N",
 	"Repeat Last N": "Понови последњих N",
 	"Request Mode": "Режим захтева",
 	"Request Mode": "Режим захтева",
 	"Reranking Model": "Модел поновног рангирања",
 	"Reranking Model": "Модел поновног рангирања",

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

@@ -167,6 +167,7 @@
 	"Completions": "",
 	"Completions": "",
 	"Concurrent Requests": "Parallella anrop",
 	"Concurrent Requests": "Parallella anrop",
 	"Configure": "",
 	"Configure": "",
+	"Configure Models": "",
 	"Confirm": "",
 	"Confirm": "",
 	"Confirm Password": "Bekräfta lösenord",
 	"Confirm Password": "Bekräfta lösenord",
 	"Confirm your action": "",
 	"Confirm your action": "",
@@ -215,6 +216,7 @@
 	"Default (SentenceTransformers)": "Standard (SentenceTransformers)",
 	"Default (SentenceTransformers)": "Standard (SentenceTransformers)",
 	"Default Model": "Standardmodell",
 	"Default Model": "Standardmodell",
 	"Default model updated": "Standardmodell uppdaterad",
 	"Default model updated": "Standardmodell uppdaterad",
+	"Default Models": "",
 	"Default permissions": "",
 	"Default permissions": "",
 	"Default permissions updated successfully": "",
 	"Default permissions updated successfully": "",
 	"Default Prompt Suggestions": "Standardinstruktionsförslag",
 	"Default Prompt Suggestions": "Standardinstruktionsförslag",
@@ -383,6 +385,7 @@
 	"Failed to add file.": "",
 	"Failed to add file.": "",
 	"Failed to create API Key.": "Misslyckades med att skapa API-nyckel.",
 	"Failed to create API Key.": "Misslyckades med att skapa API-nyckel.",
 	"Failed to read clipboard contents": "Misslyckades med att läsa urklippsinnehåll",
 	"Failed to read clipboard contents": "Misslyckades med att läsa urklippsinnehåll",
+	"Failed to save models configuration": "",
 	"Failed to update settings": "Misslyckades med att uppdatera inställningarna",
 	"Failed to update settings": "Misslyckades med att uppdatera inställningarna",
 	"Failed to upload file.": "",
 	"Failed to upload file.": "",
 	"February": "februari",
 	"February": "februari",
@@ -570,6 +573,7 @@
 	"Modelfile Content": "Modelfilens innehåll",
 	"Modelfile Content": "Modelfilens innehåll",
 	"Models": "Modeller",
 	"Models": "Modeller",
 	"Models Access": "",
 	"Models Access": "",
+	"Models configuration saved successfully": "",
 	"Mojeek Search API Key": "",
 	"Mojeek Search API Key": "",
 	"more": "",
 	"more": "",
 	"More": "Mer",
 	"More": "Mer",
@@ -589,6 +593,7 @@
 	"No knowledge found": "",
 	"No knowledge found": "",
 	"No model IDs": "",
 	"No model IDs": "",
 	"No models found": "",
 	"No models found": "",
+	"No models selected": "",
 	"No results found": "Inga resultat hittades",
 	"No results found": "Inga resultat hittades",
 	"No search query generated": "Ingen sökfråga genererad",
 	"No search query generated": "Ingen sökfråga genererad",
 	"No source available": "Ingen tillgänglig källa",
 	"No source available": "Ingen tillgänglig källa",
@@ -699,6 +704,7 @@
 	"Remove": "Ta bort",
 	"Remove": "Ta bort",
 	"Remove Model": "Ta bort modell",
 	"Remove Model": "Ta bort modell",
 	"Rename": "Byt namn",
 	"Rename": "Byt namn",
+	"Reorder Models": "",
 	"Repeat Last N": "Upprepa senaste N",
 	"Repeat Last N": "Upprepa senaste N",
 	"Request Mode": "Frågeläge",
 	"Request Mode": "Frågeläge",
 	"Reranking Model": "Reranking modell",
 	"Reranking Model": "Reranking modell",

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

@@ -167,6 +167,7 @@
 	"Completions": "",
 	"Completions": "",
 	"Concurrent Requests": "คำขอพร้อมกัน",
 	"Concurrent Requests": "คำขอพร้อมกัน",
 	"Configure": "",
 	"Configure": "",
+	"Configure Models": "",
 	"Confirm": "ยืนยัน",
 	"Confirm": "ยืนยัน",
 	"Confirm Password": "ยืนยันรหัสผ่าน",
 	"Confirm Password": "ยืนยันรหัสผ่าน",
 	"Confirm your action": "ยืนยันการดำเนินการของคุณ",
 	"Confirm your action": "ยืนยันการดำเนินการของคุณ",
@@ -215,6 +216,7 @@
 	"Default (SentenceTransformers)": "ค่าเริ่มต้น (SentenceTransformers)",
 	"Default (SentenceTransformers)": "ค่าเริ่มต้น (SentenceTransformers)",
 	"Default Model": "โมเดลค่าเริ่มต้น",
 	"Default Model": "โมเดลค่าเริ่มต้น",
 	"Default model updated": "อัปเดตโมเดลค่าเริ่มต้นแล้ว",
 	"Default model updated": "อัปเดตโมเดลค่าเริ่มต้นแล้ว",
+	"Default Models": "",
 	"Default permissions": "",
 	"Default permissions": "",
 	"Default permissions updated successfully": "",
 	"Default permissions updated successfully": "",
 	"Default Prompt Suggestions": "คำแนะนำพรอมต์ค่าเริ่มต้น",
 	"Default Prompt Suggestions": "คำแนะนำพรอมต์ค่าเริ่มต้น",
@@ -383,6 +385,7 @@
 	"Failed to add file.": "",
 	"Failed to add file.": "",
 	"Failed to create API Key.": "สร้างคีย์ API ล้มเหลว",
 	"Failed to create API Key.": "สร้างคีย์ API ล้มเหลว",
 	"Failed to read clipboard contents": "อ่านเนื้อหาคลิปบอร์ดล้มเหลว",
 	"Failed to read clipboard contents": "อ่านเนื้อหาคลิปบอร์ดล้มเหลว",
+	"Failed to save models configuration": "",
 	"Failed to update settings": "อัปเดตการตั้งค่าล้มเหลว",
 	"Failed to update settings": "อัปเดตการตั้งค่าล้มเหลว",
 	"Failed to upload file.": "",
 	"Failed to upload file.": "",
 	"February": "กุมภาพันธ์",
 	"February": "กุมภาพันธ์",
@@ -570,6 +573,7 @@
 	"Modelfile Content": "เนื้อหาของไฟล์โมเดล",
 	"Modelfile Content": "เนื้อหาของไฟล์โมเดล",
 	"Models": "โมเดล",
 	"Models": "โมเดล",
 	"Models Access": "",
 	"Models Access": "",
+	"Models configuration saved successfully": "",
 	"Mojeek Search API Key": "",
 	"Mojeek Search API Key": "",
 	"more": "",
 	"more": "",
 	"More": "เพิ่มเติม",
 	"More": "เพิ่มเติม",
@@ -589,6 +593,7 @@
 	"No knowledge found": "",
 	"No knowledge found": "",
 	"No model IDs": "",
 	"No model IDs": "",
 	"No models found": "",
 	"No models found": "",
+	"No models selected": "",
 	"No results found": "ไม่มีผลลัพธ์",
 	"No results found": "ไม่มีผลลัพธ์",
 	"No search query generated": "ไม่มีการสร้างคำค้นหา",
 	"No search query generated": "ไม่มีการสร้างคำค้นหา",
 	"No source available": "ไม่มีแหล่งข้อมูล",
 	"No source available": "ไม่มีแหล่งข้อมูล",
@@ -699,6 +704,7 @@
 	"Remove": "ลบ",
 	"Remove": "ลบ",
 	"Remove Model": "ลบโมเดล",
 	"Remove Model": "ลบโมเดล",
 	"Rename": "เปลี่ยนชื่อ",
 	"Rename": "เปลี่ยนชื่อ",
+	"Reorder Models": "",
 	"Repeat Last N": "ทำซ้ำครั้งล่าสุด N",
 	"Repeat Last N": "ทำซ้ำครั้งล่าสุด N",
 	"Request Mode": "โหมดคำขอ",
 	"Request Mode": "โหมดคำขอ",
 	"Reranking Model": "จัดอันดับใหม่โมเดล",
 	"Reranking Model": "จัดอันดับใหม่โมเดล",

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

@@ -167,6 +167,7 @@
 	"Completions": "",
 	"Completions": "",
 	"Concurrent Requests": "",
 	"Concurrent Requests": "",
 	"Configure": "",
 	"Configure": "",
+	"Configure Models": "",
 	"Confirm": "",
 	"Confirm": "",
 	"Confirm Password": "",
 	"Confirm Password": "",
 	"Confirm your action": "",
 	"Confirm your action": "",
@@ -215,6 +216,7 @@
 	"Default (SentenceTransformers)": "",
 	"Default (SentenceTransformers)": "",
 	"Default Model": "",
 	"Default Model": "",
 	"Default model updated": "",
 	"Default model updated": "",
+	"Default Models": "",
 	"Default permissions": "",
 	"Default permissions": "",
 	"Default permissions updated successfully": "",
 	"Default permissions updated successfully": "",
 	"Default Prompt Suggestions": "",
 	"Default Prompt Suggestions": "",
@@ -383,6 +385,7 @@
 	"Failed to add file.": "",
 	"Failed to add file.": "",
 	"Failed to create API Key.": "",
 	"Failed to create API Key.": "",
 	"Failed to read clipboard contents": "",
 	"Failed to read clipboard contents": "",
+	"Failed to save models configuration": "",
 	"Failed to update settings": "",
 	"Failed to update settings": "",
 	"Failed to upload file.": "",
 	"Failed to upload file.": "",
 	"February": "",
 	"February": "",
@@ -570,6 +573,7 @@
 	"Modelfile Content": "",
 	"Modelfile Content": "",
 	"Models": "",
 	"Models": "",
 	"Models Access": "",
 	"Models Access": "",
+	"Models configuration saved successfully": "",
 	"Mojeek Search API Key": "",
 	"Mojeek Search API Key": "",
 	"more": "",
 	"more": "",
 	"More": "",
 	"More": "",
@@ -589,6 +593,7 @@
 	"No knowledge found": "",
 	"No knowledge found": "",
 	"No model IDs": "",
 	"No model IDs": "",
 	"No models found": "",
 	"No models found": "",
+	"No models selected": "",
 	"No results found": "",
 	"No results found": "",
 	"No search query generated": "",
 	"No search query generated": "",
 	"No source available": "",
 	"No source available": "",
@@ -699,6 +704,7 @@
 	"Remove": "",
 	"Remove": "",
 	"Remove Model": "",
 	"Remove Model": "",
 	"Rename": "",
 	"Rename": "",
+	"Reorder Models": "",
 	"Repeat Last N": "",
 	"Repeat Last N": "",
 	"Request Mode": "",
 	"Request Mode": "",
 	"Reranking Model": "",
 	"Reranking Model": "",

+ 6 - 0
src/lib/i18n/locales/tr-TR/translation.json

@@ -167,6 +167,7 @@
 	"Completions": "",
 	"Completions": "",
 	"Concurrent Requests": "Eşzamanlı İstekler",
 	"Concurrent Requests": "Eşzamanlı İstekler",
 	"Configure": "Yapılandırma",
 	"Configure": "Yapılandırma",
+	"Configure Models": "",
 	"Confirm": "Onayla",
 	"Confirm": "Onayla",
 	"Confirm Password": "Parolayı Onayla",
 	"Confirm Password": "Parolayı Onayla",
 	"Confirm your action": "İşleminizi onaylayın",
 	"Confirm your action": "İşleminizi onaylayın",
@@ -215,6 +216,7 @@
 	"Default (SentenceTransformers)": "Varsayılan (SentenceTransformers)",
 	"Default (SentenceTransformers)": "Varsayılan (SentenceTransformers)",
 	"Default Model": "Varsayılan Model",
 	"Default Model": "Varsayılan Model",
 	"Default model updated": "Varsayılan model güncellendi",
 	"Default model updated": "Varsayılan model güncellendi",
+	"Default Models": "",
 	"Default permissions": "",
 	"Default permissions": "",
 	"Default permissions updated successfully": "",
 	"Default permissions updated successfully": "",
 	"Default Prompt Suggestions": "Varsayılan Prompt Önerileri",
 	"Default Prompt Suggestions": "Varsayılan Prompt Önerileri",
@@ -383,6 +385,7 @@
 	"Failed to add file.": "Dosya eklenemedi.",
 	"Failed to add file.": "Dosya eklenemedi.",
 	"Failed to create API Key.": "API Anahtarı oluşturulamadı.",
 	"Failed to create API Key.": "API Anahtarı oluşturulamadı.",
 	"Failed to read clipboard contents": "Pano içeriği okunamadı",
 	"Failed to read clipboard contents": "Pano içeriği okunamadı",
+	"Failed to save models configuration": "",
 	"Failed to update settings": "Ayarlar güncellenemedi",
 	"Failed to update settings": "Ayarlar güncellenemedi",
 	"Failed to upload file.": "",
 	"Failed to upload file.": "",
 	"February": "Şubat",
 	"February": "Şubat",
@@ -570,6 +573,7 @@
 	"Modelfile Content": "Model Dosyası İçeriği",
 	"Modelfile Content": "Model Dosyası İçeriği",
 	"Models": "Modeller",
 	"Models": "Modeller",
 	"Models Access": "",
 	"Models Access": "",
+	"Models configuration saved successfully": "",
 	"Mojeek Search API Key": "",
 	"Mojeek Search API Key": "",
 	"more": "",
 	"more": "",
 	"More": "Daha Fazla",
 	"More": "Daha Fazla",
@@ -589,6 +593,7 @@
 	"No knowledge found": "Bilgi bulunamadı",
 	"No knowledge found": "Bilgi bulunamadı",
 	"No model IDs": "",
 	"No model IDs": "",
 	"No models found": "Model bulunamadı",
 	"No models found": "Model bulunamadı",
+	"No models selected": "",
 	"No results found": "Sonuç bulunamadı",
 	"No results found": "Sonuç bulunamadı",
 	"No search query generated": "Hiç arama sorgusu oluşturulmadı",
 	"No search query generated": "Hiç arama sorgusu oluşturulmadı",
 	"No source available": "Kaynak mevcut değil",
 	"No source available": "Kaynak mevcut değil",
@@ -699,6 +704,7 @@
 	"Remove": "Kaldır",
 	"Remove": "Kaldır",
 	"Remove Model": "Modeli Kaldır",
 	"Remove Model": "Modeli Kaldır",
 	"Rename": "Yeniden Adlandır",
 	"Rename": "Yeniden Adlandır",
+	"Reorder Models": "",
 	"Repeat Last N": "Son N'yi Tekrar Et",
 	"Repeat Last N": "Son N'yi Tekrar Et",
 	"Request Mode": "İstek Modu",
 	"Request Mode": "İstek Modu",
 	"Reranking Model": "Yeniden Sıralama Modeli",
 	"Reranking Model": "Yeniden Sıralama Modeli",

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

@@ -167,6 +167,7 @@
 	"Completions": "Завершення",
 	"Completions": "Завершення",
 	"Concurrent Requests": "Одночасні запити",
 	"Concurrent Requests": "Одночасні запити",
 	"Configure": "Налаштувати",
 	"Configure": "Налаштувати",
+	"Configure Models": "",
 	"Confirm": "Підтвердити",
 	"Confirm": "Підтвердити",
 	"Confirm Password": "Підтвердіть пароль",
 	"Confirm Password": "Підтвердіть пароль",
 	"Confirm your action": "Підтвердіть свою дію",
 	"Confirm your action": "Підтвердіть свою дію",
@@ -215,6 +216,7 @@
 	"Default (SentenceTransformers)": "За замовчуванням (SentenceTransformers)",
 	"Default (SentenceTransformers)": "За замовчуванням (SentenceTransformers)",
 	"Default Model": "Модель за замовчуванням",
 	"Default Model": "Модель за замовчуванням",
 	"Default model updated": "Модель за замовчуванням оновлено",
 	"Default model updated": "Модель за замовчуванням оновлено",
+	"Default Models": "",
 	"Default permissions": "Дозволи за замовчуванням",
 	"Default permissions": "Дозволи за замовчуванням",
 	"Default permissions updated successfully": "Дозволи за замовчуванням успішно оновлено",
 	"Default permissions updated successfully": "Дозволи за замовчуванням успішно оновлено",
 	"Default Prompt Suggestions": "Пропозиції промтів замовчуванням",
 	"Default Prompt Suggestions": "Пропозиції промтів замовчуванням",
@@ -383,6 +385,7 @@
 	"Failed to add file.": "Не вдалося додати файл.",
 	"Failed to add file.": "Не вдалося додати файл.",
 	"Failed to create API Key.": "Не вдалося створити API ключ.",
 	"Failed to create API Key.": "Не вдалося створити API ключ.",
 	"Failed to read clipboard contents": "Не вдалося прочитати вміст буфера обміну",
 	"Failed to read clipboard contents": "Не вдалося прочитати вміст буфера обміну",
+	"Failed to save models configuration": "",
 	"Failed to update settings": "Не вдалося оновити налаштування",
 	"Failed to update settings": "Не вдалося оновити налаштування",
 	"Failed to upload file.": "Не вдалося завантажити файл.",
 	"Failed to upload file.": "Не вдалося завантажити файл.",
 	"February": "Лютий",
 	"February": "Лютий",
@@ -570,6 +573,7 @@
 	"Modelfile Content": "Вміст файлу моделі",
 	"Modelfile Content": "Вміст файлу моделі",
 	"Models": "Моделі",
 	"Models": "Моделі",
 	"Models Access": "Доступ до моделей",
 	"Models Access": "Доступ до моделей",
+	"Models configuration saved successfully": "",
 	"Mojeek Search API Key": "API ключ для пошуку Mojeek",
 	"Mojeek Search API Key": "API ключ для пошуку Mojeek",
 	"more": "більше",
 	"more": "більше",
 	"More": "Більше",
 	"More": "Більше",
@@ -589,6 +593,7 @@
 	"No knowledge found": "Знання не знайдено.",
 	"No knowledge found": "Знання не знайдено.",
 	"No model IDs": "Немає ID моделей",
 	"No model IDs": "Немає ID моделей",
 	"No models found": "Моделей не знайдено",
 	"No models found": "Моделей не знайдено",
+	"No models selected": "",
 	"No results found": "Не знайдено жодного результату",
 	"No results found": "Не знайдено жодного результату",
 	"No search query generated": "Пошуковий запит не сформовано",
 	"No search query generated": "Пошуковий запит не сформовано",
 	"No source available": "Джерело не доступне",
 	"No source available": "Джерело не доступне",
@@ -699,6 +704,7 @@
 	"Remove": "Видалити",
 	"Remove": "Видалити",
 	"Remove Model": "Видалити модель",
 	"Remove Model": "Видалити модель",
 	"Rename": "Перейменувати",
 	"Rename": "Перейменувати",
+	"Reorder Models": "",
 	"Repeat Last N": "Повторити останні N",
 	"Repeat Last N": "Повторити останні N",
 	"Request Mode": "Режим запиту",
 	"Request Mode": "Режим запиту",
 	"Reranking Model": "Модель переранжування",
 	"Reranking Model": "Модель переранжування",

+ 6 - 0
src/lib/i18n/locales/ur-PK/translation.json

@@ -167,6 +167,7 @@
 	"Completions": "تکمیل",
 	"Completions": "تکمیل",
 	"Concurrent Requests": "ہم وقت درخواستیں",
 	"Concurrent Requests": "ہم وقت درخواستیں",
 	"Configure": "",
 	"Configure": "",
+	"Configure Models": "",
 	"Confirm": "تصدیق کریں",
 	"Confirm": "تصدیق کریں",
 	"Confirm Password": "پاس ورڈ کی توثیق کریں",
 	"Confirm Password": "پاس ورڈ کی توثیق کریں",
 	"Confirm your action": "اپنی کارروائی کی تصدیق کریں",
 	"Confirm your action": "اپنی کارروائی کی تصدیق کریں",
@@ -215,6 +216,7 @@
 	"Default (SentenceTransformers)": "ڈیفالٹ (سینٹینس ٹرانسفارمرز)",
 	"Default (SentenceTransformers)": "ڈیفالٹ (سینٹینس ٹرانسفارمرز)",
 	"Default Model": "ڈیفالٹ ماڈل",
 	"Default Model": "ڈیفالٹ ماڈل",
 	"Default model updated": "ڈیفالٹ ماڈل اپ ڈیٹ ہو گیا",
 	"Default model updated": "ڈیفالٹ ماڈل اپ ڈیٹ ہو گیا",
+	"Default Models": "",
 	"Default permissions": "",
 	"Default permissions": "",
 	"Default permissions updated successfully": "",
 	"Default permissions updated successfully": "",
 	"Default Prompt Suggestions": "ڈیفالٹ پرامپٹ تجاویز",
 	"Default Prompt Suggestions": "ڈیفالٹ پرامپٹ تجاویز",
@@ -383,6 +385,7 @@
 	"Failed to add file.": "فائل شامل کرنے میں ناکام",
 	"Failed to add file.": "فائل شامل کرنے میں ناکام",
 	"Failed to create API Key.": "API کلید بنانے میں ناکام",
 	"Failed to create API Key.": "API کلید بنانے میں ناکام",
 	"Failed to read clipboard contents": "کلپ بورڈ مواد کو پڑھنے میں ناکام",
 	"Failed to read clipboard contents": "کلپ بورڈ مواد کو پڑھنے میں ناکام",
+	"Failed to save models configuration": "",
 	"Failed to update settings": "ترتیبات کی تازہ کاری ناکام رہی",
 	"Failed to update settings": "ترتیبات کی تازہ کاری ناکام رہی",
 	"Failed to upload file.": "فائل اپلوڈ کرنے میں ناکامی ہوئی",
 	"Failed to upload file.": "فائل اپلوڈ کرنے میں ناکامی ہوئی",
 	"February": "فروری",
 	"February": "فروری",
@@ -570,6 +573,7 @@
 	"Modelfile Content": "ماڈل فائل مواد",
 	"Modelfile Content": "ماڈل فائل مواد",
 	"Models": "ماڈلز",
 	"Models": "ماڈلز",
 	"Models Access": "",
 	"Models Access": "",
+	"Models configuration saved successfully": "",
 	"Mojeek Search API Key": "",
 	"Mojeek Search API Key": "",
 	"more": "مزید",
 	"more": "مزید",
 	"More": "مزید",
 	"More": "مزید",
@@ -589,6 +593,7 @@
 	"No knowledge found": "کوئی معلومات نہیں ملی",
 	"No knowledge found": "کوئی معلومات نہیں ملی",
 	"No model IDs": "",
 	"No model IDs": "",
 	"No models found": "کوئی ماڈل نہیں ملا",
 	"No models found": "کوئی ماڈل نہیں ملا",
+	"No models selected": "",
 	"No results found": "کوئی نتائج نہیں ملے",
 	"No results found": "کوئی نتائج نہیں ملے",
 	"No search query generated": "کوئی تلاش کی درخواست نہیں بنائی گئی",
 	"No search query generated": "کوئی تلاش کی درخواست نہیں بنائی گئی",
 	"No source available": "ماخذ دستیاب نہیں ہے",
 	"No source available": "ماخذ دستیاب نہیں ہے",
@@ -699,6 +704,7 @@
 	"Remove": "ہٹا دیں",
 	"Remove": "ہٹا دیں",
 	"Remove Model": "ماڈل ہٹائیں",
 	"Remove Model": "ماڈل ہٹائیں",
 	"Rename": "تبدیل نام کریں",
 	"Rename": "تبدیل نام کریں",
+	"Reorder Models": "",
 	"Repeat Last N": "آخری این (N)",
 	"Repeat Last N": "آخری این (N)",
 	"Request Mode": "درخواست کا موڈ",
 	"Request Mode": "درخواست کا موڈ",
 	"Reranking Model": "دوبارہ درجہ بندی کا ماڈل",
 	"Reranking Model": "دوبارہ درجہ بندی کا ماڈل",

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

@@ -167,6 +167,7 @@
 	"Completions": "",
 	"Completions": "",
 	"Concurrent Requests": "Các truy vấn đồng thời",
 	"Concurrent Requests": "Các truy vấn đồng thời",
 	"Configure": "",
 	"Configure": "",
+	"Configure Models": "",
 	"Confirm": "Xác nhận",
 	"Confirm": "Xác nhận",
 	"Confirm Password": "Xác nhận Mật khẩu",
 	"Confirm Password": "Xác nhận Mật khẩu",
 	"Confirm your action": "Xác nhận hành động của bạn",
 	"Confirm your action": "Xác nhận hành động của bạn",
@@ -215,6 +216,7 @@
 	"Default (SentenceTransformers)": "Mặc định (SentenceTransformers)",
 	"Default (SentenceTransformers)": "Mặc định (SentenceTransformers)",
 	"Default Model": "Model mặc định",
 	"Default Model": "Model mặc định",
 	"Default model updated": "Mô hình mặc định đã được cập nhật",
 	"Default model updated": "Mô hình mặc định đã được cập nhật",
+	"Default Models": "",
 	"Default permissions": "",
 	"Default permissions": "",
 	"Default permissions updated successfully": "",
 	"Default permissions updated successfully": "",
 	"Default Prompt Suggestions": "Đề xuất prompt mặc định",
 	"Default Prompt Suggestions": "Đề xuất prompt mặc định",
@@ -383,6 +385,7 @@
 	"Failed to add file.": "",
 	"Failed to add file.": "",
 	"Failed to create API Key.": "Lỗi khởi tạo API Key",
 	"Failed to create API Key.": "Lỗi khởi tạo API Key",
 	"Failed to read clipboard contents": "Không thể đọc nội dung clipboard",
 	"Failed to read clipboard contents": "Không thể đọc nội dung clipboard",
+	"Failed to save models configuration": "",
 	"Failed to update settings": "Lỗi khi cập nhật các cài đặt",
 	"Failed to update settings": "Lỗi khi cập nhật các cài đặt",
 	"Failed to upload file.": "",
 	"Failed to upload file.": "",
 	"February": "Tháng 2",
 	"February": "Tháng 2",
@@ -570,6 +573,7 @@
 	"Modelfile Content": "Nội dung Tệp Mô hình",
 	"Modelfile Content": "Nội dung Tệp Mô hình",
 	"Models": "Mô hình",
 	"Models": "Mô hình",
 	"Models Access": "",
 	"Models Access": "",
+	"Models configuration saved successfully": "",
 	"Mojeek Search API Key": "",
 	"Mojeek Search API Key": "",
 	"more": "",
 	"more": "",
 	"More": "Thêm",
 	"More": "Thêm",
@@ -589,6 +593,7 @@
 	"No knowledge found": "",
 	"No knowledge found": "",
 	"No model IDs": "",
 	"No model IDs": "",
 	"No models found": "",
 	"No models found": "",
+	"No models selected": "",
 	"No results found": "Không tìm thấy kết quả",
 	"No results found": "Không tìm thấy kết quả",
 	"No search query generated": "Không có truy vấn tìm kiếm nào được tạo ra",
 	"No search query generated": "Không có truy vấn tìm kiếm nào được tạo ra",
 	"No source available": "Không có nguồn",
 	"No source available": "Không có nguồn",
@@ -699,6 +704,7 @@
 	"Remove": "Xóa",
 	"Remove": "Xóa",
 	"Remove Model": "Xóa model",
 	"Remove Model": "Xóa model",
 	"Rename": "Đổi tên",
 	"Rename": "Đổi tên",
+	"Reorder Models": "",
 	"Repeat Last N": "Repeat Last N",
 	"Repeat Last N": "Repeat Last N",
 	"Request Mode": "Request Mode",
 	"Request Mode": "Request Mode",
 	"Reranking Model": "Reranking Model",
 	"Reranking Model": "Reranking Model",

+ 6 - 0
src/lib/i18n/locales/zh-CN/translation.json

@@ -167,6 +167,7 @@
 	"Completions": "续写",
 	"Completions": "续写",
 	"Concurrent Requests": "并发请求",
 	"Concurrent Requests": "并发请求",
 	"Configure": "配置",
 	"Configure": "配置",
+	"Configure Models": "",
 	"Confirm": "确认",
 	"Confirm": "确认",
 	"Confirm Password": "确认密码",
 	"Confirm Password": "确认密码",
 	"Confirm your action": "确定吗?",
 	"Confirm your action": "确定吗?",
@@ -215,6 +216,7 @@
 	"Default (SentenceTransformers)": "默认(SentenceTransformers)",
 	"Default (SentenceTransformers)": "默认(SentenceTransformers)",
 	"Default Model": "默认模型",
 	"Default Model": "默认模型",
 	"Default model updated": "默认模型已更新",
 	"Default model updated": "默认模型已更新",
+	"Default Models": "",
 	"Default permissions": "默认权限",
 	"Default permissions": "默认权限",
 	"Default permissions updated successfully": "默认权限更新成功",
 	"Default permissions updated successfully": "默认权限更新成功",
 	"Default Prompt Suggestions": "默认提示词建议",
 	"Default Prompt Suggestions": "默认提示词建议",
@@ -383,6 +385,7 @@
 	"Failed to add file.": "添加文件失败。",
 	"Failed to add file.": "添加文件失败。",
 	"Failed to create API Key.": "无法创建 API 密钥。",
 	"Failed to create API Key.": "无法创建 API 密钥。",
 	"Failed to read clipboard contents": "无法读取剪贴板内容",
 	"Failed to read clipboard contents": "无法读取剪贴板内容",
+	"Failed to save models configuration": "",
 	"Failed to update settings": "无法更新设置",
 	"Failed to update settings": "无法更新设置",
 	"Failed to upload file.": "上传文件失败",
 	"Failed to upload file.": "上传文件失败",
 	"February": "二月",
 	"February": "二月",
@@ -570,6 +573,7 @@
 	"Modelfile Content": "模型文件内容",
 	"Modelfile Content": "模型文件内容",
 	"Models": "模型",
 	"Models": "模型",
 	"Models Access": "访问模型列表",
 	"Models Access": "访问模型列表",
+	"Models configuration saved successfully": "",
 	"Mojeek Search API Key": "",
 	"Mojeek Search API Key": "",
 	"more": "更多",
 	"more": "更多",
 	"More": "更多",
 	"More": "更多",
@@ -589,6 +593,7 @@
 	"No knowledge found": "未找到知识",
 	"No knowledge found": "未找到知识",
 	"No model IDs": "没有模型 ID",
 	"No model IDs": "没有模型 ID",
 	"No models found": "未找到任何模型",
 	"No models found": "未找到任何模型",
+	"No models selected": "",
 	"No results found": "未找到结果",
 	"No results found": "未找到结果",
 	"No search query generated": "未生成搜索查询",
 	"No search query generated": "未生成搜索查询",
 	"No source available": "没有可用来源",
 	"No source available": "没有可用来源",
@@ -699,6 +704,7 @@
 	"Remove": "移除",
 	"Remove": "移除",
 	"Remove Model": "移除模型",
 	"Remove Model": "移除模型",
 	"Rename": "重命名",
 	"Rename": "重命名",
+	"Reorder Models": "",
 	"Repeat Last N": "重复最后 N 次",
 	"Repeat Last N": "重复最后 N 次",
 	"Request Mode": "请求模式",
 	"Request Mode": "请求模式",
 	"Reranking Model": "重排模型",
 	"Reranking Model": "重排模型",

+ 6 - 0
src/lib/i18n/locales/zh-TW/translation.json

@@ -167,6 +167,7 @@
 	"Completions": "",
 	"Completions": "",
 	"Concurrent Requests": "平行請求",
 	"Concurrent Requests": "平行請求",
 	"Configure": "",
 	"Configure": "",
+	"Configure Models": "",
 	"Confirm": "確認",
 	"Confirm": "確認",
 	"Confirm Password": "確認密碼",
 	"Confirm Password": "確認密碼",
 	"Confirm your action": "確認您的操作",
 	"Confirm your action": "確認您的操作",
@@ -215,6 +216,7 @@
 	"Default (SentenceTransformers)": "預設 (SentenceTransformers)",
 	"Default (SentenceTransformers)": "預設 (SentenceTransformers)",
 	"Default Model": "預設模型",
 	"Default Model": "預設模型",
 	"Default model updated": "預設模型已更新",
 	"Default model updated": "預設模型已更新",
+	"Default Models": "",
 	"Default permissions": "",
 	"Default permissions": "",
 	"Default permissions updated successfully": "",
 	"Default permissions updated successfully": "",
 	"Default Prompt Suggestions": "預設提示詞建議",
 	"Default Prompt Suggestions": "預設提示詞建議",
@@ -383,6 +385,7 @@
 	"Failed to add file.": "無法新增檔案。",
 	"Failed to add file.": "無法新增檔案。",
 	"Failed to create API Key.": "無法建立 API 金鑰。",
 	"Failed to create API Key.": "無法建立 API 金鑰。",
 	"Failed to read clipboard contents": "無法讀取剪貼簿內容",
 	"Failed to read clipboard contents": "無法讀取剪貼簿內容",
+	"Failed to save models configuration": "",
 	"Failed to update settings": "無法更新設定",
 	"Failed to update settings": "無法更新設定",
 	"Failed to upload file.": "無法上傳檔案。",
 	"Failed to upload file.": "無法上傳檔案。",
 	"February": "2 月",
 	"February": "2 月",
@@ -570,6 +573,7 @@
 	"Modelfile Content": "模型檔案內容",
 	"Modelfile Content": "模型檔案內容",
 	"Models": "模型",
 	"Models": "模型",
 	"Models Access": "",
 	"Models Access": "",
+	"Models configuration saved successfully": "",
 	"Mojeek Search API Key": "",
 	"Mojeek Search API Key": "",
 	"more": "",
 	"more": "",
 	"More": "更多",
 	"More": "更多",
@@ -589,6 +593,7 @@
 	"No knowledge found": "找不到知識",
 	"No knowledge found": "找不到知識",
 	"No model IDs": "",
 	"No model IDs": "",
 	"No models found": "",
 	"No models found": "",
+	"No models selected": "",
 	"No results found": "找不到任何結果",
 	"No results found": "找不到任何結果",
 	"No search query generated": "未產生搜尋查詢",
 	"No search query generated": "未產生搜尋查詢",
 	"No source available": "沒有可用的來源",
 	"No source available": "沒有可用的來源",
@@ -699,6 +704,7 @@
 	"Remove": "移除",
 	"Remove": "移除",
 	"Remove Model": "移除模型",
 	"Remove Model": "移除模型",
 	"Rename": "重新命名",
 	"Rename": "重新命名",
+	"Reorder Models": "",
 	"Repeat Last N": "重複最後 N 個",
 	"Repeat Last N": "重複最後 N 個",
 	"Request Mode": "請求模式",
 	"Request Mode": "請求模式",
 	"Reranking Model": "重新排序模型",
 	"Reranking Model": "重新排序模型",

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

@@ -8,6 +8,10 @@ import { TTS_RESPONSE_SPLIT } from '$lib/types';
 // Helper functions
 // Helper functions
 //////////////////////////
 //////////////////////////
 
 
+function escapeRegExp(string: string): string {
+	return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
+}
+
 export const replaceTokens = (content, sourceIds, char, user) => {
 export const replaceTokens = (content, sourceIds, char, user) => {
 	const charToken = /{{char}}/gi;
 	const charToken = /{{char}}/gi;
 	const userToken = /{{user}}/gi;
 	const userToken = /{{user}}/gi;
@@ -39,8 +43,11 @@ export const replaceTokens = (content, sourceIds, char, user) => {
 	// Remove sourceIds from the content and replace them with <source_id>...</source_id>
 	// Remove sourceIds from the content and replace them with <source_id>...</source_id>
 	if (Array.isArray(sourceIds)) {
 	if (Array.isArray(sourceIds)) {
 		sourceIds.forEach((sourceId) => {
 		sourceIds.forEach((sourceId) => {
+			// Escape special characters in the sourceId
+			const escapedSourceId = escapeRegExp(sourceId);
+
 			// Create a token based on the exact `[sourceId]` string
 			// Create a token based on the exact `[sourceId]` string
-			const sourceToken = `\\[${sourceId}\\]`; // Escape special characters for RegExp
+			const sourceToken = `\\[${escapedSourceId}\\]`; // Escape special characters for RegExp
 			const sourceRegex = new RegExp(sourceToken, 'g'); // Match all occurrences of [sourceId]
 			const sourceRegex = new RegExp(sourceToken, 'g'); // Match all occurrences of [sourceId]
 
 
 			content = content.replace(sourceRegex, `<source_id data="${sourceId}" />`);
 			content = content.replace(sourceRegex, `<source_id data="${sourceId}" />`);