Compare commits

..
134 Commits
Author SHA1 Message Date
Timothy Jaeryang Baek 506dc0149c Merge pull request #8246 from open-webui/dev
0.5.4
2025-01-05 01:38:42 -08:00
Timothy Jaeryang Baek d651cdb1e4 doc: changelog 2025-01-05 01:38:34 -08:00
Timothy Jaeryang Baek 0c40319371 doc: readme 2025-01-05 01:36:27 -08:00
Timothy Jaeryang Baek c74083ace7 doc: wording 2025-01-05 01:34:31 -08:00
Timothy Jaeryang Baek a3ca39f377 refac 2025-01-05 01:33:12 -08:00
Timothy Jaeryang Baek d11e6e40b1 doc: changelog 2025-01-05 01:32:26 -08:00
Timothy Jaeryang Baek 71bbdf25c6 refac 2025-01-05 01:18:30 -08:00
Timothy Jaeryang Baek f4a595db11 chore: format 2025-01-05 01:12:19 -08:00
Timothy Jaeryang Baek c8be0ee1e0 fix: temp chat json export 2025-01-05 01:10:45 -08:00
Timothy Jaeryang Baek 6ed8c3cb70 Update pyproject.toml 2025-01-05 00:56:32 -08:00
Timothy Jaeryang Baek c434aff1a2 refac: styling 2025-01-05 00:48:41 -08:00
Timothy Jaeryang Baek 3886c82ed0 Merge pull request #8286 from srajangarg/sg
feat: functionality to clone shared chats
2025-01-05 00:45:55 -08:00
Timothy Jaeryang Baek fe59b7f39c refac 2025-01-05 00:44:38 -08:00
Timothy Jaeryang Baek a4132322d9 refac 2025-01-05 00:28:36 -08:00
Timothy Jaeryang Baek d477f73c7e enh: torch mps support 2025-01-05 00:27:44 -08:00
Timothy Jaeryang Baek 614379a427 fix: chat drag and drop 2025-01-04 02:42:26 -08:00
Timothy Jaeryang Baek b4d91b5cb4 refac 2025-01-04 02:34:12 -08:00
Timothy Jaeryang Baek f31e2af349 refac: play sound only in last active tab 2025-01-04 02:30:51 -08:00
Timothy Jaeryang Baek afcbf2cafb enh: native notifications 2025-01-04 02:15:57 -08:00
Timothy Jaeryang Baek c0b93791dc refac 2025-01-04 02:05:42 -08:00
Timothy Jaeryang Baek f3a4d61f81 fix: actions 2025-01-03 21:31:24 -08:00
Timothy Jaeryang Baek 99c3194181 fix: API_KEY_ALLOWED_ENDPOINTS 2025-01-03 13:08:21 -08:00
Timothy Jaeryang Baek 0e805e7dc4 Merge pull request #8298 from jk-f5/feat/pg_vector_size
feat: Allow setting the initial vector length on pgvector document_chunk table
2025-01-03 13:03:53 -08:00
Timothy Jaeryang Baek 226408ffe3 Merge pull request #8309 from yarikoptic/enh-codespell
ci: add codespell support (config, workflow to detect/not fix) and make it fix few typos
2025-01-03 13:02:32 -08:00
Yaroslav Halchenko 8f1953e667 [DATALAD RUNCMD] run codespell throughout fixing few left typos automagically
=== Do not change lines below ===
{
 "chain": [],
 "cmd": "codespell -w",
 "exit": 0,
 "extra_inputs": [],
 "inputs": [],
 "outputs": [],
 "pwd": "."
}
^^^ Do not change lines above ^^^
2025-01-03 15:07:21 -05:00
Yaroslav Halchenko 1a928bc6a4 Add rudimentary codespell config 2025-01-03 15:07:21 -05:00
Yaroslav Halchenko 2e5fbba961 Add github action to codespell main on push and PRs 2025-01-03 15:07:21 -05:00
Jason Kidd 70b74b5217 feat: Allow setting the initial vector length on pgvector document_chunk table 2025-01-03 09:18:59 -08:00
Timothy Jaeryang Baek 996ade9090 refac: notification sound behaviour 2025-01-02 21:39:40 -08:00
Srajan Garg 2444327a47 add functionality to clone shared chats 2025-01-03 00:08:49 -05:00
Timothy Jaeryang Baek 6b3be4bb5b refac: sidebar styling 2025-01-02 20:53:30 -08:00
Timothy Jaeryang Baek b2b56d14cb fix: channel thread 2025-01-02 20:48:50 -08:00
Timothy Jaeryang Baek 3e9c92729d refac: styling 2025-01-02 20:28:01 -08:00
Timothy Jaeryang Baek 0c49553f79 refac: styling 2025-01-02 20:23:07 -08:00
Timothy Jaeryang Baek 66b8166397 refac: styling 2025-01-02 20:19:52 -08:00
Timothy Jaeryang Baek 87ba39df57 fix: moa 2025-01-02 14:32:25 -08:00
Timothy Jaeryang Baek 43964de675 refac: audio input 2025-01-02 02:32:51 -08:00
Timothy Jaeryang Baek fab82b51de fix: generate_queries 2025-01-01 20:13:28 -08:00
Timothy Jaeryang Baek 44716a4cb2 refac: disable ENABLE_REALTIME_CHAT_SAVE by default 2025-01-01 20:12:42 -08:00
Timothy Jaeryang Baek d9fb971196 Merge pull request #8249 from albinvar/main
fix: raise exceptions properly in process_chat_payload
2025-01-01 18:44:42 -08:00
Timothy Jaeryang Baek 51d875a14e Merge pull request #8251 from TiancongLx/dev
i18n: update zh-TW
2025-01-01 18:44:16 -08:00
Tiancong Li 45cc0e6209 i18n: update zh-TW
待翻譯:「Add Reaction」
2025-01-01 21:20:11 +08:00
Albin Varghese c561eb7bbd fix: raise exceptions properly in process_chat_payload 2025-01-01 17:15:06 +05:30
Timothy Jaeryang Baek 00a089b596 doc: readme 2024-12-31 20:37:54 -08:00
Timothy Jaeryang Baek 541fa37c5c Merge pull request #8245 from open-webui/dependabot/pip/backend/dev/peewee-3.17.8
build(deps): bump peewee from 3.17.6 to 3.17.8 in /backend
2024-12-31 20:00:01 -08:00
Timothy Jaeryang Baek 06301aa90d Merge pull request #8243 from open-webui/dependabot/pip/backend/dev/validators-0.34.0
build(deps): bump validators from 0.33.0 to 0.34.0 in /backend
2024-12-31 19:59:45 -08:00
Timothy Jaeryang Baek 55fbc60ad3 Merge pull request #8244 from open-webui/dependabot/pip/backend/dev/flask-3.1.0
build(deps): bump flask from 3.0.3 to 3.1.0 in /backend
2024-12-31 19:59:36 -08:00
Timothy Jaeryang Baek b69941caf4 Merge pull request #8242 from open-webui/dependabot/pip/backend/dev/fpdf2-2.8.2
build(deps): bump fpdf2 from 2.7.9 to 2.8.2 in /backend
2024-12-31 19:59:13 -08:00
Timothy Jaeryang Baek 80600dbe63 Merge pull request #8241 from open-webui/dependabot/pip/backend/dev/pyjwt-crypto--2.10.1
build(deps): bump pyjwt[crypto] from 2.9.0 to 2.10.1 in /backend
2024-12-31 19:58:59 -08:00
Timothy Jaeryang Baek 085f48366b refac 2024-12-31 19:54:11 -08:00
Timothy Jaeryang Baek 60fc24cd39 refac: channel message input 2024-12-31 19:42:49 -08:00
dependabot[bot] 7fb87ddf99 build(deps): bump peewee from 3.17.6 to 3.17.8 in /backend
Bumps [peewee](https://github.com/coleifer/peewee) from 3.17.6 to 3.17.8.
- [Release notes](https://github.com/coleifer/peewee/releases)
- [Changelog](https://github.com/coleifer/peewee/blob/master/CHANGELOG.md)
- [Commits](https://github.com/coleifer/peewee/compare/3.17.6...3.17.8)

---
updated-dependencies:
- dependency-name: peewee
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-01 02:15:02 +00:00
dependabot[bot] b41c1128c6 build(deps): bump flask from 3.0.3 to 3.1.0 in /backend
Bumps [flask](https://github.com/pallets/flask) from 3.0.3 to 3.1.0.
- [Release notes](https://github.com/pallets/flask/releases)
- [Changelog](https://github.com/pallets/flask/blob/main/CHANGES.rst)
- [Commits](https://github.com/pallets/flask/compare/3.0.3...3.1.0)

---
updated-dependencies:
- dependency-name: flask
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-01 02:14:54 +00:00
dependabot[bot] 5bb308a098 build(deps): bump validators from 0.33.0 to 0.34.0 in /backend
Bumps [validators](https://github.com/python-validators/validators) from 0.33.0 to 0.34.0.
- [Release notes](https://github.com/python-validators/validators/releases)
- [Changelog](https://github.com/python-validators/validators/blob/master/CHANGES.md)
- [Commits](https://github.com/python-validators/validators/compare/0.33.0...0.34.0)

---
updated-dependencies:
- dependency-name: validators
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-01 02:14:51 +00:00
dependabot[bot] 236410cd95 build(deps): bump fpdf2 from 2.7.9 to 2.8.2 in /backend
Bumps [fpdf2](https://github.com/py-pdf/fpdf2) from 2.7.9 to 2.8.2.
- [Release notes](https://github.com/py-pdf/fpdf2/releases)
- [Changelog](https://github.com/py-pdf/fpdf2/blob/master/CHANGELOG.md)
- [Commits](https://github.com/py-pdf/fpdf2/compare/2.7.9...2.8.2)

---
updated-dependencies:
- dependency-name: fpdf2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-01 02:14:48 +00:00
dependabot[bot] f1800e2853 build(deps): bump pyjwt[crypto] from 2.9.0 to 2.10.1 in /backend
Bumps [pyjwt[crypto]](https://github.com/jpadilla/pyjwt) from 2.9.0 to 2.10.1.
- [Release notes](https://github.com/jpadilla/pyjwt/releases)
- [Changelog](https://github.com/jpadilla/pyjwt/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/jpadilla/pyjwt/compare/2.9.0...2.10.1)

---
updated-dependencies:
- dependency-name: pyjwt[crypto]
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-01 02:14:45 +00:00
Timothy Jaeryang Baek 4bc9904b3c Merge pull request #8159 from open-webui/dev
0.5.3
2024-12-31 13:41:03 -08:00
Timothy Jaeryang Baek 995f80002f doc: changelog 2024-12-31 13:40:49 -08:00
Timothy Jaeryang Baek ffdb45cc4b refac 2024-12-31 13:39:03 -08:00
Timothy Jaeryang Baek f5ee5deec8 chore: format 2024-12-31 13:30:59 -08:00
Timothy Jaeryang Baek 02777ffc54 doc: changelog 2024-12-31 13:23:05 -08:00
Timothy Jaeryang Baek a5627d4226 refac 2024-12-31 13:09:17 -08:00
Timothy Jaeryang Baek 435a174316 Merge pull request #8232 from okamototk/improve-jp-trans
i18n - Updated Japanese Translation
2024-12-31 13:04:58 -08:00
Timothy Jaeryang Baek d905202afb refac 2024-12-31 13:04:27 -08:00
Takashi Okamoto 221cc19ac6 i18n - Updated Japanese Translation 2024-12-31 11:58:43 +00:00
Timothy Jaeryang Baek 3d69eaf34f refac: styling 2024-12-31 03:57:43 -08:00
Timothy Jaeryang Baek e7c501677c refac 2024-12-31 03:54:43 -08:00
Timothy Jaeryang Baek 96b1c2024b refac 2024-12-31 03:45:54 -08:00
Timothy Jaeryang Baek f7ecfafe1a refac: styling 2024-12-31 03:25:25 -08:00
Timothy Jaeryang Baek 6ecee8b920 refac: emoji picker optimisation 2024-12-31 03:24:05 -08:00
Timothy Jaeryang Baek cce8f37ada refac 2024-12-31 02:58:15 -08:00
Timothy Jaeryang Baek 60247fe18d refac 2024-12-31 02:51:52 -08:00
Timothy Jaeryang Baek de4e086bd5 refac 2024-12-31 02:48:43 -08:00
Timothy Jaeryang Baek 3da7ff1721 refac 2024-12-31 02:42:46 -08:00
Timothy Jaeryang Baek c8cdc6377b refac 2024-12-31 02:30:03 -08:00
Timothy Jaeryang Baek 85038cef69 refac: styling 2024-12-31 02:27:49 -08:00
Timothy Jaeryang Baek 016b91adda chore: format 2024-12-31 02:26:30 -08:00
Timothy Jaeryang Baek 0846a08795 Merge pull request #8230 from moblangeois/dev
i18n: update fr-FR
2024-12-31 02:24:42 -08:00
Timothy Jaeryang Baek 277eef62c2 Merge pull request #8210 from open-webui/channels
enh: channel threads & reactions
2024-12-31 02:24:10 -08:00
Timothy Jaeryang Baek 9f19933e64 refac: styling 2024-12-31 02:23:26 -08:00
Timothy Jaeryang Baek 904ddcec13 refac: styling 2024-12-31 02:19:22 -08:00
Timothy Jaeryang Baek 77da0a6cc1 refac: styling 2024-12-31 02:17:39 -08:00
Timothy Jaeryang Baek a754a4388a feat: channel threads 2024-12-31 02:16:07 -08:00
Morgan Blangeois 93f262c6a2 i18n: update fr-FR 2024-12-31 11:09:31 +01:00
Timothy Jaeryang Baek 16a48ef4eb fix 2024-12-31 02:06:55 -08:00
Timothy Jaeryang Baek 841f74894e refac 2024-12-31 02:06:19 -08:00
Timothy Jaeryang Baek 9c337552e6 enh: reply count 2024-12-31 02:05:11 -08:00
Timothy Jaeryang Baek 584e9e6da5 refac: threads 2024-12-31 00:51:43 -08:00
Timothy Jaeryang Baek a3dfa90668 refac: optimisation 2024-12-31 00:11:46 -08:00
Timothy Jaeryang Baek 00e8849445 refac 2024-12-30 23:55:19 -08:00
Timothy Jaeryang Baek 2840ff405b refac 2024-12-30 23:48:55 -08:00
Timothy Jaeryang Baek 9d39404e6c refac: styling 2024-12-30 23:16:50 -08:00
Timothy Jaeryang Baek 371201d820 refac 2024-12-30 23:12:50 -08:00
Timothy Jaeryang Baek f93c2e4a8d feat: reactions 2024-12-30 23:06:34 -08:00
Timothy Jaeryang Baek 4b0fa112bb Merge pull request #8222 from open-webui/dev
dev
2024-12-30 17:55:13 -08:00
Timothy Jaeryang Baek fd0170c179 revert 2024-12-30 16:55:29 -08:00
Timothy Jaeryang Baek 9b56b64cfa Merge pull request #8212 from ashm-dev/main
feat: Small optimization
2024-12-30 16:00:18 -08:00
Timothy Jaeryang Baek 887627fa34 Merge pull request #8217 from gabriel-ecegi/batch_fix
fix: Add missing request parameter to knowledge and retrieval routes
2024-12-30 15:58:10 -08:00
Timothy Jaeryang Baek 46bcf98ef2 fix: usage stats 2024-12-30 15:52:07 -08:00
Timothy Jaeryang Baek 947f5600d6 refac 2024-12-30 15:39:35 -08:00
Timothy Jaeryang Baek 79ce6e0a3f refac 2024-12-30 11:29:18 -08:00
Gabriel Ecegi 46e57706c1 refac: formatting 2024-12-30 17:45:43 +01:00
Gabriel Ecegi ba2964cb01 fix: missing parameter 2024-12-30 17:36:34 +01:00
shamil a0aee4ff28 feat: Small optimization 2024-12-30 13:45:20 +03:00
Timothy Jaeryang Baek 45289b0fa8 refac 2024-12-30 02:21:45 -08:00
Timothy Jaeryang Baek eece28ccc6 feat: emoji picker 2024-12-30 02:20:09 -08:00
Timothy Jaeryang Baek c216d89520 enh: threads & reactions 2024-12-29 23:16:18 -08:00
Timothy Jaeryang Baek d94134ad2d refac 2024-12-29 22:11:20 -08:00
Timothy Jaeryang Baek 952822ad5d refac 2024-12-29 21:02:11 -08:00
Timothy Jaeryang Baek 79d7e67e51 fix: ollama options 2024-12-29 16:30:36 -08:00
Timothy Jaeryang Baek 6de1923151 Merge pull request #8192 from TiancongLx/dev
i18n: update zh-TW
2024-12-29 15:36:19 -08:00
Tiancong Li abdbd6a67e i18n: update zh-TW 2024-12-30 03:13:20 +08:00
Timothy Jaeryang Baek a14dee87e8 Merge pull request #8184 from vishwamartur/fix-offline-docker
Fix offline docker container startup issue
2024-12-28 22:26:38 -08:00
Vishwanath Martur 00e6ffe83c Fix offline docker container startup issue
Related to #7207

Modify the code to allow the docker container to start in an offline environment for versions >= 0.4.0.

* **backend/open_webui/retrieval/utils.py**
  - Import `OFFLINE_MODE` from `open_webui.env`.
  - Set `local_files_only` to `True` when `OFFLINE_MODE` is enabled in `snapshot_kwargs`.

* **backend/open_webui/env.py**
  - Add logic to set `HF_HUB_OFFLINE` environment variable to `1` when `OFFLINE_MODE` is enabled.

* **README.md**
  - Document setting `HF_HUB_OFFLINE` environment variable to `1` for offline environments.
2024-12-29 11:53:09 +05:30
Timothy Jaeryang Baek 36d927e1ba refac 2024-12-28 19:31:03 -08:00
Timothy Jaeryang Baek 091e9e2f40 refac 2024-12-28 18:08:30 -08:00
Timothy Jaeryang Baek 54daf3b765 fix: outlet filter hook 2024-12-28 18:05:07 -08:00
Timothy Jaeryang Baek 76decdba2a fix: delete file 2024-12-28 17:40:00 -08:00
Timothy Jaeryang Baek e6e8978f78 refac 2024-12-28 16:42:43 -08:00
Timothy Jaeryang Baek fcaeb2f539 Merge pull request #8179 from cvaz1306/add_reset_button_mermaidjs_renderer
i18n: Add reset panzoom button to SVGPanZoom and cleanup
2024-12-28 16:27:44 -08:00
cvaz1306 f7d1833f41 Fixing formatting 2024-12-28 15:50:23 -08:00
cvaz1306 95598e5435 Merge branch 'dev' into add_reset_button_mermaidjs_renderer 2024-12-28 15:46:23 -08:00
cvaz1306 8a7e8b57a8 Add reset panzoom button to SVGPanZoom and cleanup 2024-12-28 15:27:47 -08:00
Timothy Jaeryang Baek 5a720a4a31 refac 2024-12-27 22:46:50 -08:00
Timothy Jaeryang Baek d55884b50e enh: ENABLE_REALTIME_CHAT_SAVE 2024-12-27 22:36:14 -08:00
Timothy Jaeryang Baek c8fb11db59 Merge pull request #8158 from cvaz1306/add_reset_button_mermaidjs_renderer
feat: Add reset button mermaidjs renderer
2024-12-27 17:55:00 -08:00
cvaz1306 7b3a86475d Add reset panzoom button to SVGPanZoom and cleanup 2024-12-27 17:06:15 -08:00
Timothy Jaeryang Baek 59ed53ec1e Merge pull request #8145 from bernadinm/fix/modified_update_ollama_models.sh
fix: Add execute permissions to update_ollama_models.sh
2024-12-27 16:24:32 -08:00
Timothy Jaeryang Baek 7f8b6ebbd5 refac: styling 2024-12-27 12:24:58 -08:00
Miguel Bernadin 3f0dd80898 fix: chmod +x update_ollama_models.sh 2024-12-27 08:29:54 -08:00
Timothy Jaeryang Baek 2299f48430 Merge pull request #8131 from open-webui/dev
fix: api key restrictions
2024-12-27 00:32:37 -08:00
Timothy Jaeryang Baek 99386bf680 fix: api key restrictions 2024-12-27 00:32:25 -08:00
Timothy Jaeryang Baek 4e4e2792b1 Merge pull request #8130 from open-webui/dev
refac
2024-12-27 00:06:41 -08:00
Timothy Jaeryang Baek d99e3d49e1 refac 2024-12-27 00:05:32 -08:00
3954 changed files with 13507 additions and 555 deletions
+25
View File
@@ -0,0 +1,25 @@
# Codespell configuration is within pyproject.toml
---
name: Codespell
on:
push:
branches: [main]
pull_request:
branches: [main]
permissions:
contents: read
jobs:
codespell:
name: Check for spelling errors
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Annotate locations with typos
uses: codespell-project/codespell-problem-matcher@v1
- name: Codespell
uses: codespell-project/actions-codespell@v2
+47
View File
@@ -5,6 +5,53 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [0.5.4] - 2024-01-05
### Added
- **🔄 Clone Shared Chats**: Effortlessly clone shared chats to save time and streamline collaboration, perfect for reusing insightful discussions or custom setups.
- **📣 Native Notifications for Channel Messages**: Stay informed with integrated desktop notifications for channel messages, ensuring you never miss important updates while multitasking.
- **🔥 Torch MPS Support**: MPS support for Mac users when Open WebUI is installed directly, offering better performance and compatibility for AI workloads.
- **🌍 Enhanced Translations**: Small improvements to various translations, ensuring a smoother global user experience.
### Fixed
- **🖼️ Image-Only Messages in Channels**: You can now send images without accompanying text or content in channels.
- **❌ Proper Exception Handling**: Enhanced error feedback by ensuring exceptions are raised clearly, reducing confusion and promoting smoother debugging.
- **🔍 RAG Query Generation Restored**: Fixed query generation issues for Retrieval-Augmented Generation, improving retrieval accuracy and ensuring seamless functionality.
- **📩 MOA Response Functionality Fixed**: Addressed an error with the MOA response generation feature.
- **💬 Channel Thread Loading with 50+ Messages**: Resolved an issue where channel threads stalled when exceeding 50 messages, ensuring smooth navigation in active discussions.
- **🔑 API Endpoint Restrictions Resolution**: Fixed a critical bug where the 'API_KEY_ALLOWED_ENDPOINTS' setting was not functioning as intended, ensuring API access is limited to specified endpoints for enhanced security.
- **🛠️ Action Functions Restored**: Corrected an issue preventing action functions from working, restoring their utility for customized automations and workflows.
- **📂 Temporary Chat JSON Export Fix**: Resolved a bug blocking temporary chats from being exported in JSON format, ensuring seamless data portability.
### Changed
- **🎛️ Sidebar UI Tweaks**: Chat folders, including pinned folders, now display below the Chats section for better organization; the "New Folder" button has been relocated to the Chats section for a more intuitive workflow.
- **🏗️ Real-Time Save Disabled by Default**: The 'ENABLE_REALTIME_CHAT_SAVE' setting is now off by default, boosting response speed for users who prioritize performance in high-paced workflows or less critical scenarios.
- **🎤 Audio Input Echo Cancellation**: Audio input now features echo cancellation enabled by default, reducing audio feedback for improved clarity during conversations or voice-based interactions.
- **🔧 General Reliability Improvements**: Numerous under-the-hood enhancements have been made to improve platform stability, boost overall performance, and ensure a more seamless, dependable experience across workflows.
## [0.5.3] - 2024-12-31
### Added
- **💬 Channel Reactions with Built-In Emoji Picker**: Easily express yourself in channel threads and messages with reactions, featuring an intuitive built-in emoji picker for seamless selection.
- **🧵 Threads for Channels**: Organize discussions within channels by creating threads, improving clarity and fostering focused conversations.
- **🔄 Reset Button for SVG Pan/Zoom**: Added a handy reset button to SVG Pan/Zoom, allowing users to quickly return diagrams or visuals to their default state without hassle.
- **⚡ Realtime Chat Save Environment Variable**: Introduced the ENABLE_REALTIME_CHAT_SAVE environment variable. Choose between faster responses by disabling realtime chat saving or ensuring chunk-by-chunk data persistency for critical operations.
- **🌍 Translation Enhancements**: Updated and refined translations across multiple languages, providing a smoother experience for international users.
- **📚 Improved Documentation**: Expanded documentation on functions, including clearer guidance on function plugins and detailed instructions for migrating to v0.5. This ensures users can adapt and harness new updates more effectively. (https://docs.openwebui.com/features/plugin/)
### Fixed
- **🛠️ Ollama Parameters Respected**: Resolved an issue where input parameters for Ollama were being ignored, ensuring precise and consistent model behavior.
- **🔧 Function Plugin Outlet Hook Reliability**: Fixed a bug causing issues with 'event_emitter' and outlet hooks in filter function plugins, guaranteeing smoother operation within custom extensions.
- **🖋️ Weird Custom Status Descriptions**: Adjusted the formatting and functionality for custom user statuses, ensuring they display correctly and intuitively.
- **🔗 Restored API Functionality**: Fixed a critical issue where APIs were not operational for certain configurations, ensuring uninterrupted access.
- **⏳ Custom Pipe Function Completion**: Resolved an issue where chats using specific custom pipe function plugins weren’t finishing properly, restoring consistent chat workflows.
- **✅ General Stability Enhancements**: Implemented various under-the-hood improvements to boost overall reliability, ensuring smoother and more consistent performance across the WebUI.
## [0.5.2] - 2024-12-26
### Added
+1 -1
View File
@@ -2,7 +2,7 @@
## 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, socioeconomic 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.
+11 -1
View File
@@ -11,7 +11,9 @@
[![Discord](https://img.shields.io/badge/Discord-Open_WebUI-blue?logo=discord&logoColor=white)](https://discord.gg/5rJgQTnV4s)
[![](https://img.shields.io/static/v1?label=Sponsor&message=%E2%9D%A4&logo=GitHub&color=%23fe8e86)](https://github.com/sponsors/tjbck)
Open WebUI is an [extensible](https://github.com/open-webui/pipelines), feature-rich, and user-friendly self-hosted WebUI designed to operate entirely offline. It supports various LLM runners, including Ollama and OpenAI-compatible APIs. For more information, be sure to check out our [Open WebUI Documentation](https://docs.openwebui.com/).
**Open WebUI is an [extensible](https://docs.openwebui.com/features/plugin/), feature-rich, and user-friendly self-hosted AI platform designed to operate entirely offline.** It supports various LLM runners like **Ollama** and **OpenAI-compatible APIs**, with **built-in inference engine** for RAG, making it a **powerful AI deployment solution**.
For more information, be sure to check out our [Open WebUI Documentation](https://docs.openwebui.com/).
![Open WebUI Demo](./demo.gif)
@@ -185,6 +187,14 @@ If you want to try out the latest bleeding-edge features and are okay with occas
docker run -d -p 3000:8080 -v open-webui:/app/backend/data --name open-webui --add-host=host.docker.internal:host-gateway --restart always ghcr.io/open-webui/open-webui:dev
```
### Offline Mode
If you are running Open WebUI in an offline environment, you can set the `HF_HUB_OFFLINE` environment variable to `1` to prevent attempts to download models from the internet.
```bash
export HF_HUB_OFFLINE=1
```
## What's Next? 🌟
Discover upcoming features on our roadmap in the [Open WebUI Documentation](https://docs.openwebui.com/roadmap/).
+3
View File
@@ -1211,6 +1211,9 @@ if VECTOR_DB == "pgvector" and not PGVECTOR_DB_URL.startswith("postgres"):
raise ValueError(
"Pgvector requires setting PGVECTOR_DB_URL or using Postgres with vector extension as the primary database."
)
PGVECTOR_INITIALIZE_MAX_VECTOR_LENGTH = int(
os.environ.get("PGVECTOR_INITIALIZE_MAX_VECTOR_LENGTH", "1536")
)
####################################
# Information Retrieval (RAG)
+13
View File
@@ -53,6 +53,11 @@ if USE_CUDA.lower() == "true":
else:
DEVICE_TYPE = "cpu"
try:
if torch.backends.mps.is_available() and torch.backends.mps.is_built():
DEVICE_TYPE = "mps"
except Exception:
pass
####################################
# LOGGING
@@ -311,6 +316,11 @@ RESET_CONFIG_ON_START = (
os.environ.get("RESET_CONFIG_ON_START", "False").lower() == "true"
)
ENABLE_REALTIME_CHAT_SAVE = (
os.environ.get("ENABLE_REALTIME_CHAT_SAVE", "False").lower() == "true"
)
####################################
# REDIS
####################################
@@ -392,3 +402,6 @@ else:
####################################
OFFLINE_MODE = os.environ.get("OFFLINE_MODE", "false").lower() == "true"
if OFFLINE_MODE:
os.environ["HF_HUB_OFFLINE"] = "1"
@@ -0,0 +1,70 @@
"""Update message & channel tables
Revision ID: 3781e22d8b01
Revises: 7826ab40b532
Create Date: 2024-12-30 03:00:00.000000
"""
from alembic import op
import sqlalchemy as sa
revision = "3781e22d8b01"
down_revision = "7826ab40b532"
branch_labels = None
depends_on = None
def upgrade():
# Add 'type' column to the 'channel' table
op.add_column(
"channel",
sa.Column(
"type",
sa.Text(),
nullable=True,
),
)
# Add 'parent_id' column to the 'message' table for threads
op.add_column(
"message",
sa.Column("parent_id", sa.Text(), nullable=True),
)
op.create_table(
"message_reaction",
sa.Column(
"id", sa.Text(), nullable=False, primary_key=True, unique=True
), # Unique reaction ID
sa.Column("user_id", sa.Text(), nullable=False), # User who reacted
sa.Column(
"message_id", sa.Text(), nullable=False
), # Message that was reacted to
sa.Column(
"name", sa.Text(), nullable=False
), # Reaction name (e.g. "thumbs_up")
sa.Column(
"created_at", sa.BigInteger(), nullable=True
), # Timestamp of when the reaction was added
)
op.create_table(
"channel_member",
sa.Column(
"id", sa.Text(), nullable=False, primary_key=True, unique=True
), # Record ID for the membership row
sa.Column("channel_id", sa.Text(), nullable=False), # Associated channel
sa.Column("user_id", sa.Text(), nullable=False), # Associated user
sa.Column(
"created_at", sa.BigInteger(), nullable=True
), # Timestamp of when the user joined the channel
)
def downgrade():
# Revert 'type' column addition to the 'channel' table
op.drop_column("channel", "type")
op.drop_column("message", "parent_id")
op.drop_table("message_reaction")
op.drop_table("channel_member")
+6 -2
View File
@@ -21,6 +21,7 @@ class Channel(Base):
id = Column(Text, primary_key=True)
user_id = Column(Text)
type = Column(Text, nullable=True)
name = Column(Text)
description = Column(Text, nullable=True)
@@ -38,9 +39,11 @@ class ChannelModel(BaseModel):
id: str
user_id: str
description: Optional[str] = None
type: Optional[str] = None
name: str
description: Optional[str] = None
data: Optional[dict] = None
meta: Optional[dict] = None
access_control: Optional[dict] = None
@@ -64,12 +67,13 @@ class ChannelForm(BaseModel):
class ChannelTable:
def insert_new_channel(
self, form_data: ChannelForm, user_id: str
self, type: Optional[str], form_data: ChannelForm, user_id: str
) -> Optional[ChannelModel]:
with get_db() as db:
channel = ChannelModel(
**{
**form_data.model_dump(),
"type": type,
"name": form_data.name.lower(),
"id": str(uuid.uuid4()),
"user_id": user_id,
+11
View File
@@ -212,6 +212,15 @@ class ChatTable:
return chat.chat.get("history", {}).get("messages", {}) or {}
def get_message_by_id_and_message_id(
self, id: str, message_id: str
) -> Optional[dict]:
chat = self.get_chat_by_id(id)
if chat is None:
return None
return chat.chat.get("history", {}).get("messages", {}).get(message_id, {})
def upsert_message_to_chat_by_id_and_message_id(
self, id: str, message_id: str, message: dict
) -> Optional[ChatModel]:
@@ -460,6 +469,8 @@ class ChatTable:
def get_chat_by_share_id(self, id: str) -> Optional[ChatModel]:
try:
with get_db() as db:
# it is possible that the shared link was deleted. hence,
# we check if the chat is still shared by checkng if a chat with the share_id exists
chat = db.query(Chat).filter_by(share_id=id).first()
if chat:
+144 -6
View File
@@ -17,6 +17,25 @@ from sqlalchemy.sql import exists
####################
class MessageReaction(Base):
__tablename__ = "message_reaction"
id = Column(Text, primary_key=True)
user_id = Column(Text)
message_id = Column(Text)
name = Column(Text)
created_at = Column(BigInteger)
class MessageReactionModel(BaseModel):
model_config = ConfigDict(from_attributes=True)
id: str
user_id: str
message_id: str
name: str
created_at: int # timestamp in epoch
class Message(Base):
__tablename__ = "message"
id = Column(Text, primary_key=True)
@@ -24,6 +43,8 @@ class Message(Base):
user_id = Column(Text)
channel_id = Column(Text, nullable=True)
parent_id = Column(Text, nullable=True)
content = Column(Text)
data = Column(JSON, nullable=True)
meta = Column(JSON, nullable=True)
@@ -39,6 +60,8 @@ class MessageModel(BaseModel):
user_id: str
channel_id: Optional[str] = None
parent_id: Optional[str] = None
content: str
data: Optional[dict] = None
meta: Optional[dict] = None
@@ -54,10 +77,23 @@ class MessageModel(BaseModel):
class MessageForm(BaseModel):
content: str
parent_id: Optional[str] = None
data: Optional[dict] = None
meta: Optional[dict] = None
class Reactions(BaseModel):
name: str
user_ids: list[str]
count: int
class MessageResponse(MessageModel):
latest_reply_at: Optional[int]
reply_count: int
reactions: list[Reactions]
class MessageTable:
def insert_new_message(
self, form_data: MessageForm, channel_id: str, user_id: str
@@ -71,6 +107,7 @@ class MessageTable:
"id": id,
"user_id": user_id,
"channel_id": channel_id,
"parent_id": form_data.parent_id,
"content": form_data.content,
"data": form_data.data,
"meta": form_data.meta,
@@ -85,10 +122,40 @@ class MessageTable:
db.refresh(result)
return MessageModel.model_validate(result) if result else None
def get_message_by_id(self, id: str) -> Optional[MessageModel]:
def get_message_by_id(self, id: str) -> Optional[MessageResponse]:
with get_db() as db:
message = db.get(Message, id)
return MessageModel.model_validate(message) if message else None
if not message:
return None
reactions = self.get_reactions_by_message_id(id)
replies = self.get_replies_by_message_id(id)
return MessageResponse(
**{
**MessageModel.model_validate(message).model_dump(),
"latest_reply_at": replies[0].created_at if replies else None,
"reply_count": len(replies),
"reactions": reactions,
}
)
def get_replies_by_message_id(self, id: str) -> list[MessageModel]:
with get_db() as db:
all_messages = (
db.query(Message)
.filter_by(parent_id=id)
.order_by(Message.created_at.desc())
.all()
)
return [MessageModel.model_validate(message) for message in all_messages]
def get_reply_user_ids_by_message_id(self, id: str) -> list[str]:
with get_db() as db:
return [
message.user_id
for message in db.query(Message).filter_by(parent_id=id).all()
]
def get_messages_by_channel_id(
self, channel_id: str, skip: int = 0, limit: int = 50
@@ -96,7 +163,7 @@ class MessageTable:
with get_db() as db:
all_messages = (
db.query(Message)
.filter_by(channel_id=channel_id)
.filter_by(channel_id=channel_id, parent_id=None)
.order_by(Message.created_at.desc())
.offset(skip)
.limit(limit)
@@ -104,18 +171,28 @@ class MessageTable:
)
return [MessageModel.model_validate(message) for message in all_messages]
def get_messages_by_user_id(
self, user_id: str, skip: int = 0, limit: int = 50
def get_messages_by_parent_id(
self, channel_id: str, parent_id: str, skip: int = 0, limit: int = 50
) -> list[MessageModel]:
with get_db() as db:
message = db.get(Message, parent_id)
if not message:
return []
all_messages = (
db.query(Message)
.filter_by(user_id=user_id)
.filter_by(channel_id=channel_id, parent_id=parent_id)
.order_by(Message.created_at.desc())
.offset(skip)
.limit(limit)
.all()
)
# If length of all_messages is less than limit, then add the parent message
if len(all_messages) < limit:
all_messages.append(message)
return [MessageModel.model_validate(message) for message in all_messages]
def update_message_by_id(
@@ -131,9 +208,70 @@ class MessageTable:
db.refresh(message)
return MessageModel.model_validate(message) if message else None
def add_reaction_to_message(
self, id: str, user_id: str, name: str
) -> Optional[MessageReactionModel]:
with get_db() as db:
reaction_id = str(uuid.uuid4())
reaction = MessageReactionModel(
id=reaction_id,
user_id=user_id,
message_id=id,
name=name,
created_at=int(time.time_ns()),
)
result = MessageReaction(**reaction.model_dump())
db.add(result)
db.commit()
db.refresh(result)
return MessageReactionModel.model_validate(result) if result else None
def get_reactions_by_message_id(self, id: str) -> list[Reactions]:
with get_db() as db:
all_reactions = db.query(MessageReaction).filter_by(message_id=id).all()
reactions = {}
for reaction in all_reactions:
if reaction.name not in reactions:
reactions[reaction.name] = {
"name": reaction.name,
"user_ids": [],
"count": 0,
}
reactions[reaction.name]["user_ids"].append(reaction.user_id)
reactions[reaction.name]["count"] += 1
return [Reactions(**reaction) for reaction in reactions.values()]
def remove_reaction_by_id_and_user_id_and_name(
self, id: str, user_id: str, name: str
) -> bool:
with get_db() as db:
db.query(MessageReaction).filter_by(
message_id=id, user_id=user_id, name=name
).delete()
db.commit()
return True
def delete_reactions_by_id(self, id: str) -> bool:
with get_db() as db:
db.query(MessageReaction).filter_by(message_id=id).delete()
db.commit()
return True
def delete_replies_by_id(self, id: str) -> bool:
with get_db() as db:
db.query(Message).filter_by(parent_id=id).delete()
db.commit()
return True
def delete_message_by_id(self, id: str) -> bool:
with get_db() as db:
db.query(Message).filter_by(id=id).delete()
# Delete all reactions to this message
db.query(MessageReaction).filter_by(message_id=id).delete()
db.commit()
return True
+4 -1
View File
@@ -14,7 +14,7 @@ from langchain_core.documents import Document
from open_webui.retrieval.vector.connector import VECTOR_DB_CLIENT
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, OFFLINE_MODE
log = logging.getLogger(__name__)
log.setLevel(SRC_LOG_LEVELS["RAG"])
@@ -375,6 +375,9 @@ def get_model_path(model: str, update_model: bool = False):
local_files_only = not update_model
if OFFLINE_MODE:
local_files_only = True
snapshot_kwargs = {
"cache_dir": cache_dir,
"local_files_only": local_files_only,
@@ -5,6 +5,7 @@ from sqlalchemy import (
create_engine,
Column,
Integer,
MetaData,
select,
text,
Text,
@@ -19,9 +20,9 @@ from pgvector.sqlalchemy import Vector
from sqlalchemy.ext.mutable import MutableDict
from open_webui.retrieval.vector.main import VectorItem, SearchResult, GetResult
from open_webui.config import PGVECTOR_DB_URL
from open_webui.config import PGVECTOR_DB_URL, PGVECTOR_INITIALIZE_MAX_VECTOR_LENGTH
VECTOR_LENGTH = 1536
VECTOR_LENGTH = PGVECTOR_INITIALIZE_MAX_VECTOR_LENGTH
Base = declarative_base()
@@ -56,6 +57,9 @@ class PgvectorClient:
# Ensure the pgvector extension is available
self.session.execute(text("CREATE EXTENSION IF NOT EXISTS vector;"))
# Check vector length consistency
self.check_vector_length()
# Create the tables if they do not exist
# Base.metadata.create_all requires a bind (engine or connection)
# Get the connection from the session
@@ -82,6 +86,38 @@ class PgvectorClient:
print(f"Error during initialization: {e}")
raise
def check_vector_length(self) -> None:
"""
Check if the VECTOR_LENGTH matches the existing vector column dimension in the database.
Raises an exception if there is a mismatch.
"""
metadata = MetaData()
metadata.reflect(bind=self.session.bind, only=["document_chunk"])
if "document_chunk" in metadata.tables:
document_chunk_table = metadata.tables["document_chunk"]
if "vector" in document_chunk_table.columns:
vector_column = document_chunk_table.columns["vector"]
vector_type = vector_column.type
if isinstance(vector_type, Vector):
db_vector_length = vector_type.dim
if db_vector_length != VECTOR_LENGTH:
raise Exception(
f"VECTOR_LENGTH {VECTOR_LENGTH} does not match existing vector column dimension {db_vector_length}. "
"Cannot change vector size after initialization without migrating the data."
)
else:
raise Exception(
"The 'vector' column exists but is not of type 'Vector'."
)
else:
raise Exception(
"The 'vector' column does not exist in the 'document_chunk' table."
)
else:
# Table does not exist yet; no action needed
pass
def adjust_vector_length(self, vector: List[float]) -> List[float]:
# Adjust vector to have length VECTOR_LENGTH
current_length = len(vector)
+1 -1
View File
@@ -683,7 +683,7 @@
"age": "October 29, 2022",
"extra_snippets": [
"You can pass many options to the configure script; run ./configure --help to find out more. On macOS case-insensitive file systems and on Cygwin, the executable is called python.exe; elsewhere it's just python.",
"Building a complete Python installation requires the use of various additional third-party libraries, depending on your build platform and configure options. Not all standard library modules are buildable or useable on all platforms. Refer to the Install dependencies section of the Developer Guide for current detailed information on dependencies for various Linux distributions and macOS.",
"Building a complete Python installation requires the use of various additional third-party libraries, depending on your build platform and configure options. Not all standard library modules are buildable or usable on all platforms. Refer to the Install dependencies section of the Developer Guide for current detailed information on dependencies for various Linux distributions and macOS.",
"To get an optimized build of Python, configure --enable-optimizations before you run make. This sets the default make targets up to enable Profile Guided Optimization (PGO) and may be used to auto-enable Link Time Optimization (LTO) on some platforms. For more details, see the sections below.",
"Copyright © 2001-2024 Python Software Foundation. All rights reserved."
]
+329 -13
View File
@@ -11,7 +11,12 @@ from open_webui.socket.main import sio, get_user_ids_from_room
from open_webui.models.users import Users, UserNameResponse
from open_webui.models.channels import Channels, ChannelModel, ChannelForm
from open_webui.models.messages import Messages, MessageModel, MessageForm
from open_webui.models.messages import (
Messages,
MessageModel,
MessageResponse,
MessageForm,
)
from open_webui.config import ENABLE_ADMIN_CHAT_ACCESS, ENABLE_ADMIN_EXPORT
@@ -49,7 +54,7 @@ async def get_channels(user=Depends(get_verified_user)):
@router.post("/create", response_model=Optional[ChannelModel])
async def create_new_channel(form_data: ChannelForm, user=Depends(get_admin_user)):
try:
channel = Channels.insert_new_channel(form_data, user.id)
channel = Channels.insert_new_channel(None, form_data, user.id)
return ChannelModel(**channel.model_dump())
except Exception as e:
log.exception(e)
@@ -134,11 +139,11 @@ async def delete_channel_by_id(id: str, user=Depends(get_admin_user)):
############################
class MessageUserModel(MessageModel):
class MessageUserResponse(MessageResponse):
user: UserNameResponse
@router.get("/{id}/messages", response_model=list[MessageUserModel])
@router.get("/{id}/messages", response_model=list[MessageUserResponse])
async def get_channel_messages(
id: str, skip: int = 0, limit: int = 50, user=Depends(get_verified_user)
):
@@ -164,10 +169,16 @@ async def get_channel_messages(
user = Users.get_user_by_id(message.user_id)
users[message.user_id] = user
replies = Messages.get_replies_by_message_id(message.id)
latest_reply_at = replies[0].created_at if replies else None
messages.append(
MessageUserModel(
MessageUserResponse(
**{
**message.model_dump(),
"reply_count": len(replies),
"latest_reply_at": latest_reply_at,
"reactions": Messages.get_reactions_by_message_id(message.id),
"user": UserNameResponse(**users[message.user_id].model_dump()),
}
)
@@ -236,10 +247,17 @@ async def post_new_message(
"message_id": message.id,
"data": {
"type": "message",
"data": {
**message.model_dump(),
"user": UserNameResponse(**user.model_dump()).model_dump(),
},
"data": MessageUserResponse(
**{
**message.model_dump(),
"reply_count": 0,
"latest_reply_at": None,
"reactions": Messages.get_reactions_by_message_id(
message.id
),
"user": UserNameResponse(**user.model_dump()),
}
).model_dump(),
},
"user": UserNameResponse(**user.model_dump()).model_dump(),
"channel": channel.model_dump(),
@@ -251,6 +269,35 @@ async def post_new_message(
to=f"channel:{channel.id}",
)
if message.parent_id:
# If this message is a reply, emit to the parent message as well
parent_message = Messages.get_message_by_id(message.parent_id)
if parent_message:
await sio.emit(
"channel-events",
{
"channel_id": channel.id,
"message_id": parent_message.id,
"data": {
"type": "message:reply",
"data": MessageUserResponse(
**{
**parent_message.model_dump(),
"user": UserNameResponse(
**Users.get_user_by_id(
parent_message.user_id
).model_dump()
),
}
).model_dump(),
},
"user": UserNameResponse(**user.model_dump()).model_dump(),
"channel": channel.model_dump(),
},
to=f"channel:{channel.id}",
)
active_user_ids = get_user_ids_from_room(f"channel:{channel.id}")
background_tasks.add_task(
@@ -269,6 +316,101 @@ async def post_new_message(
)
############################
# GetChannelMessage
############################
@router.get("/{id}/messages/{message_id}", response_model=Optional[MessageUserResponse])
async def get_channel_message(
id: str, message_id: str, user=Depends(get_verified_user)
):
channel = Channels.get_channel_by_id(id)
if not channel:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail=ERROR_MESSAGES.NOT_FOUND
)
if user.role != "admin" and not has_access(
user.id, type="read", access_control=channel.access_control
):
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN, detail=ERROR_MESSAGES.DEFAULT()
)
message = Messages.get_message_by_id(message_id)
if not message:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail=ERROR_MESSAGES.NOT_FOUND
)
if message.channel_id != id:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST, detail=ERROR_MESSAGES.DEFAULT()
)
return MessageUserResponse(
**{
**message.model_dump(),
"user": UserNameResponse(
**Users.get_user_by_id(message.user_id).model_dump()
),
}
)
############################
# GetChannelThreadMessages
############################
@router.get(
"/{id}/messages/{message_id}/thread", response_model=list[MessageUserResponse]
)
async def get_channel_thread_messages(
id: str,
message_id: str,
skip: int = 0,
limit: int = 50,
user=Depends(get_verified_user),
):
channel = Channels.get_channel_by_id(id)
if not channel:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail=ERROR_MESSAGES.NOT_FOUND
)
if user.role != "admin" and not has_access(
user.id, type="read", access_control=channel.access_control
):
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN, detail=ERROR_MESSAGES.DEFAULT()
)
message_list = Messages.get_messages_by_parent_id(id, message_id, skip, limit)
users = {}
messages = []
for message in message_list:
if message.user_id not in users:
user = Users.get_user_by_id(message.user_id)
users[message.user_id] = user
messages.append(
MessageUserResponse(
**{
**message.model_dump(),
"reply_count": 0,
"latest_reply_at": None,
"reactions": Messages.get_reactions_by_message_id(message.id),
"user": UserNameResponse(**users[message.user_id].model_dump()),
}
)
)
return messages
############################
# UpdateMessageById
############################
@@ -306,6 +448,8 @@ async def update_message_by_id(
try:
message = Messages.update_message_by_id(message_id, form_data)
message = Messages.get_message_by_id(message_id)
if message:
await sio.emit(
"channel-events",
@@ -314,10 +458,14 @@ async def update_message_by_id(
"message_id": message.id,
"data": {
"type": "message:update",
"data": {
**message.model_dump(),
"user": UserNameResponse(**user.model_dump()).model_dump(),
},
"data": MessageUserResponse(
**{
**message.model_dump(),
"user": UserNameResponse(
**user.model_dump()
).model_dump(),
}
).model_dump(),
},
"user": UserNameResponse(**user.model_dump()).model_dump(),
"channel": channel.model_dump(),
@@ -333,6 +481,145 @@ async def update_message_by_id(
)
############################
# AddReactionToMessage
############################
class ReactionForm(BaseModel):
name: str
@router.post("/{id}/messages/{message_id}/reactions/add", response_model=bool)
async def add_reaction_to_message(
id: str, message_id: str, form_data: ReactionForm, user=Depends(get_verified_user)
):
channel = Channels.get_channel_by_id(id)
if not channel:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail=ERROR_MESSAGES.NOT_FOUND
)
if user.role != "admin" and not has_access(
user.id, type="read", access_control=channel.access_control
):
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN, detail=ERROR_MESSAGES.DEFAULT()
)
message = Messages.get_message_by_id(message_id)
if not message:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail=ERROR_MESSAGES.NOT_FOUND
)
if message.channel_id != id:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST, detail=ERROR_MESSAGES.DEFAULT()
)
try:
Messages.add_reaction_to_message(message_id, user.id, form_data.name)
message = Messages.get_message_by_id(message_id)
await sio.emit(
"channel-events",
{
"channel_id": channel.id,
"message_id": message.id,
"data": {
"type": "message:reaction:add",
"data": {
**message.model_dump(),
"user": UserNameResponse(
**Users.get_user_by_id(message.user_id).model_dump()
).model_dump(),
"name": form_data.name,
},
},
"user": UserNameResponse(**user.model_dump()).model_dump(),
"channel": channel.model_dump(),
},
to=f"channel:{channel.id}",
)
return True
except Exception as e:
log.exception(e)
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST, detail=ERROR_MESSAGES.DEFAULT()
)
############################
# RemoveReactionById
############################
@router.post("/{id}/messages/{message_id}/reactions/remove", response_model=bool)
async def remove_reaction_by_id_and_user_id_and_name(
id: str, message_id: str, form_data: ReactionForm, user=Depends(get_verified_user)
):
channel = Channels.get_channel_by_id(id)
if not channel:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail=ERROR_MESSAGES.NOT_FOUND
)
if user.role != "admin" and not has_access(
user.id, type="read", access_control=channel.access_control
):
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN, detail=ERROR_MESSAGES.DEFAULT()
)
message = Messages.get_message_by_id(message_id)
if not message:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail=ERROR_MESSAGES.NOT_FOUND
)
if message.channel_id != id:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST, detail=ERROR_MESSAGES.DEFAULT()
)
try:
Messages.remove_reaction_by_id_and_user_id_and_name(
message_id, user.id, form_data.name
)
message = Messages.get_message_by_id(message_id)
await sio.emit(
"channel-events",
{
"channel_id": channel.id,
"message_id": message.id,
"data": {
"type": "message:reaction:remove",
"data": {
**message.model_dump(),
"user": UserNameResponse(
**Users.get_user_by_id(message.user_id).model_dump()
).model_dump(),
"name": form_data.name,
},
},
"user": UserNameResponse(**user.model_dump()).model_dump(),
"channel": channel.model_dump(),
},
to=f"channel:{channel.id}",
)
return True
except Exception as e:
log.exception(e)
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST, detail=ERROR_MESSAGES.DEFAULT()
)
############################
# DeleteMessageById
############################
@@ -386,6 +673,35 @@ async def delete_message_by_id(
to=f"channel:{channel.id}",
)
if message.parent_id:
# If this message is a reply, emit to the parent message as well
parent_message = Messages.get_message_by_id(message.parent_id)
if parent_message:
await sio.emit(
"channel-events",
{
"channel_id": channel.id,
"message_id": parent_message.id,
"data": {
"type": "message:reply",
"data": MessageUserResponse(
**{
**parent_message.model_dump(),
"user": UserNameResponse(
**Users.get_user_by_id(
parent_message.user_id
).model_dump()
),
}
).model_dump(),
},
"user": UserNameResponse(**user.model_dump()).model_dump(),
"channel": channel.model_dump(),
},
to=f"channel:{channel.id}",
)
return True
except Exception as e:
log.exception(e)
+24
View File
@@ -463,6 +463,30 @@ async def clone_chat_by_id(id: str, user=Depends(get_verified_user)):
)
############################
# CloneSharedChatById
############################
@router.post("/{id}/clone/shared", response_model=Optional[ChatResponse])
async def clone_shared_chat_by_id(id: str, user=Depends(get_verified_user)):
chat = Chats.get_chat_by_share_id(id)
if chat:
updated_chat = {
**chat.chat,
"originalChatId": chat.id,
"branchPointMessageId": chat.chat["history"]["currentId"],
"title": f"Clone of {chat.title}",
}
chat = Chats.insert_new_chat(user.id, ChatForm(**{"chat": updated_chat}))
return ChatResponse(**chat.model_dump())
else:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED, detail=ERROR_MESSAGES.DEFAULT()
)
############################
# ArchiveChat
############################
+1 -1
View File
@@ -348,7 +348,7 @@ async def delete_file_by_id(id: str, user=Depends(get_verified_user)):
result = Files.delete_file_by_id(id)
if result:
try:
Storage.delete_file(file.filename)
Storage.delete_file(file.path)
except Exception as e:
log.exception(e)
log.error(f"Error deleting files")
+4 -8
View File
@@ -419,13 +419,6 @@ def remove_file_from_knowledge_by_id(
collection_name=knowledge.id, filter={"file_id": form_data.file_id}
)
result = VECTOR_DB_CLIENT.query(
collection_name=knowledge.id,
filter={"file_id": form_data.file_id},
)
Files.delete_file_by_id(form_data.file_id)
if knowledge:
data = knowledge.data or {}
file_ids = data.get("file_ids", [])
@@ -527,6 +520,7 @@ async def reset_knowledge_by_id(id: str, user=Depends(get_verified_user)):
@router.post("/{id}/files/batch/add", response_model=Optional[KnowledgeFilesResponse])
def add_files_to_knowledge_batch(
request: Request,
id: str,
form_data: list[KnowledgeFileIdForm],
user=Depends(get_verified_user),
@@ -562,7 +556,9 @@ def add_files_to_knowledge_batch(
# Process files
try:
result = process_files_batch(
BatchProcessFilesForm(files=files, collection_name=id)
request=request,
form_data=BatchProcessFilesForm(files=files, collection_name=id),
user=user,
)
except Exception as e:
log.error(
+5 -1
View File
@@ -1458,6 +1458,7 @@ class BatchProcessFilesResponse(BaseModel):
@router.post("/process/files/batch")
def process_files_batch(
request: Request,
form_data: BatchProcessFilesForm,
user=Depends(get_verified_user),
) -> BatchProcessFilesResponse:
@@ -1504,7 +1505,10 @@ def process_files_batch(
if all_docs:
try:
save_docs_to_vector_db(
docs=all_docs, collection_name=collection_name, add=True
request=request,
docs=all_docs,
collection_name=collection_name,
add=True,
)
# Update all files with collection name
+1 -1
View File
@@ -499,8 +499,8 @@ async def generate_moa_response(
"model": task_model_id,
"messages": [{"role": "user", "content": content}],
"stream": form_data.get("stream", False),
"chat_id": form_data.get("chat_id", None),
"metadata": {
"chat_id": form_data.get("chat_id", None),
"task": str(TASKS.MOA_RESPONSE_GENERATION),
"task_body": form_data,
},
+29
View File
@@ -237,6 +237,7 @@ async def channel_events(sid, data):
"channel-events",
{
"channel_id": data["channel_id"],
"message_id": data.get("message_id", None),
"data": event_data,
"user": UserNameResponse(**SESSION_POOL[sid]).model_dump(),
},
@@ -292,6 +293,34 @@ def get_event_emitter(request_info):
event_data.get("data", {}),
)
if "type" in event_data and event_data["type"] == "message":
message = Chats.get_message_by_id_and_message_id(
request_info["chat_id"],
request_info["message_id"],
)
content = message.get("content", "")
content += event_data.get("data", {}).get("content", "")
Chats.upsert_message_to_chat_by_id_and_message_id(
request_info["chat_id"],
request_info["message_id"],
{
"content": content,
},
)
if "type" in event_data and event_data["type"] == "replace":
content = event_data.get("data", {}).get("content", "")
Chats.upsert_message_to_chat_by_id_and_message_id(
request_info["chat_id"],
request_info["message_id"],
{
"content": content,
},
)
return __event_emitter__
+3 -1
View File
@@ -147,8 +147,10 @@ class StorageProvider:
return self._get_file_from_s3(file_path)
return self._get_file_from_local(file_path)
def delete_file(self, filename: str) -> None:
def delete_file(self, file_path: str) -> None:
"""Deletes a file either from S3 or the local file system."""
filename = file_path.split("/")[-1]
if self.storage_provider == "s3":
self._delete_from_s3(filename)
+4 -2
View File
@@ -96,10 +96,12 @@ def get_current_user(
status.HTTP_403_FORBIDDEN, detail=ERROR_MESSAGES.API_KEY_NOT_ALLOWED
)
if request.app.state.ENABLE_API_KEY_ENDPOINT_RESTRICTIONS:
if request.app.state.config.ENABLE_API_KEY_ENDPOINT_RESTRICTIONS:
allowed_paths = [
path.strip()
for path in str(request.app.state.API_KEY_ALLOWED_PATHS).split(",")
for path in str(
request.app.state.config.API_KEY_ALLOWED_ENDPOINTS
).split(",")
]
if request.url.path not in allowed_paths:
+7
View File
@@ -157,6 +157,9 @@ async def generate_chat_completion(
)
chat_completion = generate_chat_completion
async def chat_completed(request: Request, form_data: dict, user: Any):
if not request.app.state.MODELS:
await get_all_models(request)
@@ -179,6 +182,7 @@ async def chat_completed(request: Request, form_data: dict, user: Any):
"chat_id": data["chat_id"],
"message_id": data["id"],
"session_id": data["session_id"],
"user_id": user.id,
}
)
@@ -187,6 +191,7 @@ async def chat_completed(request: Request, form_data: dict, user: Any):
"chat_id": data["chat_id"],
"message_id": data["id"],
"session_id": data["session_id"],
"user_id": user.id,
}
)
@@ -310,6 +315,7 @@ async def chat_action(request: Request, action_id: str, form_data: dict, user: A
"chat_id": data["chat_id"],
"message_id": data["id"],
"session_id": data["session_id"],
"user_id": user.id,
}
)
__event_call__ = get_event_call(
@@ -317,6 +323,7 @@ async def chat_action(request: Request, action_id: str, form_data: dict, user: A
"chat_id": data["chat_id"],
"message_id": data["id"],
"session_id": data["session_id"],
"user_id": user.id,
}
)
+73 -41
View File
@@ -23,7 +23,7 @@ from open_webui.models.users import Users
from open_webui.socket.main import (
get_event_call,
get_event_emitter,
get_user_id_from_session_pool,
get_active_status_by_user_id,
)
from open_webui.routers.tasks import (
generate_queries,
@@ -65,6 +65,7 @@ from open_webui.env import (
SRC_LOG_LEVELS,
GLOBAL_LOG_LEVEL,
BYPASS_MODEL_ACCESS_CONTROL,
ENABLE_REALTIME_CHAT_SAVE,
)
from open_webui.constants import TASKS
@@ -493,6 +494,7 @@ async def chat_completion_files_handler(
if files := body.get("metadata", {}).get("files", None):
try:
queries_response = await generate_queries(
request,
{
"model": body["model"],
"messages": body["messages"],
@@ -560,7 +562,6 @@ def apply_params_to_form_data(form_data, model):
if "frequency_penalty" in params:
form_data["frequency_penalty"] = params["frequency_penalty"]
return form_data
@@ -644,7 +645,7 @@ async def process_chat_payload(request, form_data, metadata, user, model):
request, form_data, model, extra_params
)
except Exception as e:
return Exception(f"Error: {e}")
raise Exception(f"Error: {e}")
tool_ids = form_data.pop("tool_ids", None)
files = form_data.pop("files", None)
@@ -750,7 +751,7 @@ async def process_chat_response(
):
async def background_tasks_handler():
message_map = Chats.get_messages_by_chat_id(metadata["chat_id"])
message = message_map.get(metadata["message_id"])
message = message_map.get(metadata["message_id"]) if message_map else None
if message:
messages = get_message_list(message_map, message.get("id"))
@@ -896,7 +897,7 @@ async def process_chat_response(
)
# Send a webhook notification if the user is not active
if get_user_id_from_session_pool(metadata["session_id"]) is None:
if get_active_status_by_user_id(user.id) is None:
webhook_url = Users.get_user_webhook_url_by_id(user.id)
if webhook_url:
post_webhook(
@@ -928,6 +929,11 @@ async def process_chat_response(
# Handle as a background task
async def post_response_handler(response, events):
message = Chats.get_message_by_id_and_message_id(
metadata["chat_id"], metadata["message_id"]
)
content = message.get("content", "") if message else ""
try:
for event in events:
await event_emitter(
@@ -946,9 +952,6 @@ async def process_chat_response(
},
)
assistant_message = get_last_assistant_message(form_data["messages"])
content = assistant_message if assistant_message else ""
async for line in response.body_iterator:
line = line.decode("utf-8") if isinstance(line, bytes) else line
data = line
@@ -977,7 +980,6 @@ async def process_chat_response(
)
else:
value = (
data.get("choices", [])[0]
.get("delta", {})
@@ -987,55 +989,85 @@ async def process_chat_response(
if value:
content = f"{content}{value}"
# Save message in the database
Chats.upsert_message_to_chat_by_id_and_message_id(
metadata["chat_id"],
metadata["message_id"],
{
if ENABLE_REALTIME_CHAT_SAVE:
# Save message in the database
Chats.upsert_message_to_chat_by_id_and_message_id(
metadata["chat_id"],
metadata["message_id"],
{
"content": content,
},
)
else:
data = {
"content": content,
},
)
}
await event_emitter(
{
"type": "chat:completion",
"data": data,
}
)
except Exception as e:
done = "data: [DONE]" in line
title = Chats.get_chat_title_by_id(metadata["chat_id"])
if done:
data = {"done": True, "content": content, "title": title}
# Send a webhook notification if the user is not active
if (
get_user_id_from_session_pool(metadata["session_id"])
is None
):
webhook_url = Users.get_user_webhook_url_by_id(user.id)
if webhook_url:
post_webhook(
webhook_url,
f"{title} - {request.app.state.config.WEBUI_URL}/c/{metadata['chat_id']}\n\n{content}",
{
"action": "chat",
"message": content,
"title": title,
"url": f"{request.app.state.config.WEBUI_URL}/c/{metadata['chat_id']}",
},
)
pass
else:
continue
await event_emitter(
title = Chats.get_chat_title_by_id(metadata["chat_id"])
data = {"done": True, "content": content, "title": title}
if not ENABLE_REALTIME_CHAT_SAVE:
# Save message in the database
Chats.upsert_message_to_chat_by_id_and_message_id(
metadata["chat_id"],
metadata["message_id"],
{
"type": "chat:completion",
"data": data,
}
"content": content,
},
)
# Send a webhook notification if the user is not active
if get_active_status_by_user_id(user.id) is None:
webhook_url = Users.get_user_webhook_url_by_id(user.id)
if webhook_url:
post_webhook(
webhook_url,
f"{title} - {request.app.state.config.WEBUI_URL}/c/{metadata['chat_id']}\n\n{content}",
{
"action": "chat",
"message": content,
"title": title,
"url": f"{request.app.state.config.WEBUI_URL}/c/{metadata['chat_id']}",
},
)
await event_emitter(
{
"type": "chat:completion",
"data": data,
}
)
await background_tasks_handler()
except asyncio.CancelledError:
print("Task was cancelled!")
await event_emitter({"type": "task-cancelled"})
if not ENABLE_REALTIME_CHAT_SAVE:
# Save message in the database
Chats.upsert_message_to_chat_by_id_and_message_id(
metadata["chat_id"],
metadata["message_id"],
{
"content": content,
},
)
if response.background is not None:
await response.background()
+4
View File
@@ -160,6 +160,10 @@ def convert_payload_openai_to_ollama(openai_payload: dict) -> dict:
# If there are advanced parameters in the payload, format them in Ollama's options field
ollama_options = {}
if openai_payload.get("options"):
ollama_payload["options"] = openai_payload["options"]
ollama_options = openai_payload["options"]
# Handle parameters which map directly
for param in ["temperature", "top_p", "seed"]:
if param in openai_payload:
+2 -2
View File
@@ -29,7 +29,7 @@ async def convert_streaming_response_ollama_to_openai(ollama_streaming_response)
(
(
data.get("eval_count", 0)
/ ((data.get("eval_duration", 0) / 1_000_000))
/ ((data.get("eval_duration", 0) / 10_000_000))
)
* 100
),
@@ -43,7 +43,7 @@ async def convert_streaming_response_ollama_to_openai(ollama_streaming_response)
(
(
data.get("prompt_eval_count", 0)
/ ((data.get("prompt_eval_duration", 0) / 1_000_000))
/ ((data.get("prompt_eval_duration", 0) / 10_000_000))
)
* 100
),
+5 -5
View File
@@ -3,7 +3,7 @@ uvicorn[standard]==0.30.6
pydantic==2.9.2
python-multipart==0.0.18
Flask==3.0.3
Flask==3.1.0
Flask-Cors==5.0.0
python-socketio==5.11.3
@@ -18,7 +18,7 @@ aiofiles
sqlalchemy==2.0.32
alembic==1.14.0
peewee==3.17.6
peewee==3.17.8
peewee-migrate==1.12.2
psycopg2-binary==2.9.9
pgvector==0.3.5
@@ -55,7 +55,7 @@ einops==0.8.0
ftfy==6.2.3
pypdf==4.3.1
fpdf2==2.7.9
fpdf2==2.8.2
pymdown-extensions==10.11.2
docx2txt==0.8
python-pptx==1.0.0
@@ -67,7 +67,7 @@ pandas==2.2.3
openpyxl==3.1.5
pyxlsb==1.0.10
xlrd==2.0.1
validators==0.33.0
validators==0.34.0
psutil
sentencepiece
soundfile==0.12.1
@@ -78,7 +78,7 @@ rank-bm25==0.2.2
faster-whisper==1.0.3
PyJWT[crypto]==2.9.0
PyJWT[crypto]==2.10.1
authlib==1.3.2
black==24.8.0
+9 -2
View File
@@ -1,12 +1,12 @@
{
"name": "open-webui",
"version": "0.5.2",
"version": "0.5.4",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "open-webui",
"version": "0.5.2",
"version": "0.5.4",
"dependencies": {
"@codemirror/lang-javascript": "^6.2.2",
"@codemirror/lang-python": "^6.1.6",
@@ -16,6 +16,7 @@
"@mediapipe/tasks-vision": "^0.10.17",
"@pyscript/core": "^0.4.32",
"@sveltejs/adapter-node": "^2.0.0",
"@sveltejs/svelte-virtual-list": "^3.0.1",
"@tiptap/core": "^2.10.0",
"@tiptap/extension-code-block-lowlight": "^2.10.0",
"@tiptap/extension-highlight": "^2.10.0",
@@ -2291,6 +2292,12 @@
"vite": "^5.0.3 || ^6.0.0"
}
},
"node_modules/@sveltejs/svelte-virtual-list": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@sveltejs/svelte-virtual-list/-/svelte-virtual-list-3.0.1.tgz",
"integrity": "sha512-aF9TptS7NKKS7/TqpsxQBSDJ9Q0XBYzBehCeIC5DzdMEgrJZpIYao9LRLnyyo6SVodpapm2B7FE/Lj+FSA5/SQ==",
"license": "LIL"
},
"node_modules/@sveltejs/vite-plugin-svelte": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-3.1.1.tgz",
+3 -2
View File
@@ -1,6 +1,6 @@
{
"name": "open-webui",
"version": "0.5.2",
"version": "0.5.4",
"private": true,
"scripts": {
"dev": "npm run pyodide:fetch && vite dev --host",
@@ -50,7 +50,6 @@
"type": "module",
"dependencies": {
"@codemirror/lang-javascript": "^6.2.2",
"codemirror-lang-hcl": "^0.0.0-beta.2",
"@codemirror/lang-python": "^6.1.6",
"@codemirror/language-data": "^6.5.1",
"@codemirror/theme-one-dark": "^6.1.2",
@@ -58,6 +57,7 @@
"@mediapipe/tasks-vision": "^0.10.17",
"@pyscript/core": "^0.4.32",
"@sveltejs/adapter-node": "^2.0.0",
"@sveltejs/svelte-virtual-list": "^3.0.1",
"@tiptap/core": "^2.10.0",
"@tiptap/extension-code-block-lowlight": "^2.10.0",
"@tiptap/extension-highlight": "^2.10.0",
@@ -69,6 +69,7 @@
"async": "^3.2.5",
"bits-ui": "^0.19.7",
"codemirror": "^6.0.1",
"codemirror-lang-hcl": "^0.0.0-beta.2",
"crc-32": "^1.2.2",
"dayjs": "^1.11.10",
"dompurify": "^3.1.6",
+12 -5
View File
@@ -11,7 +11,7 @@ dependencies = [
"pydantic==2.9.2",
"python-multipart==0.0.18",
"Flask==3.0.3",
"Flask==3.1.0",
"Flask-Cors==5.0.0",
"python-socketio==5.11.3",
@@ -26,7 +26,7 @@ dependencies = [
"sqlalchemy==2.0.32",
"alembic==1.14.0",
"peewee==3.17.6",
"peewee==3.17.8",
"peewee-migrate==1.12.2",
"psycopg2-binary==2.9.9",
"pgvector==0.3.5",
@@ -61,7 +61,7 @@ dependencies = [
"ftfy==6.2.3",
"pypdf==4.3.1",
"fpdf2==2.7.9",
"fpdf2==2.8.2",
"pymdown-extensions==10.11.2",
"docx2txt==0.8",
"python-pptx==1.0.0",
@@ -73,7 +73,7 @@ dependencies = [
"openpyxl==3.1.5",
"pyxlsb==1.0.10",
"xlrd==2.0.1",
"validators==0.33.0",
"validators==0.34.0",
"psutil",
"sentencepiece",
"soundfile==0.12.1",
@@ -84,7 +84,7 @@ dependencies = [
"faster-whisper==1.0.3",
"PyJWT[crypto]==2.9.0",
"PyJWT[crypto]==2.10.1",
"authlib==1.3.2",
"black==24.8.0",
@@ -151,3 +151,10 @@ exclude = [
"chroma.sqlite3",
]
force-include = { "CHANGELOG.md" = "open_webui/CHANGELOG.md", build = "open_webui/frontend" }
[tool.codespell]
# Ref: https://github.com/codespell-project/codespell#using-a-config-file
skip = '.git*,*.svg,package-lock.json,i18n,*.lock,*.css,*-bundle.js,locales,example-doc.txt,emoji-shortcodes.json'
check-hidden = true
# ignore-regex = ''
ignore-words-list = 'ans'
+122
View File
@@ -1,4 +1,5 @@
import { WEBUI_API_BASE_URL } from '$lib/constants';
import { t } from 'i18next';
type ChannelForm = {
name: string;
@@ -207,7 +208,48 @@ export const getChannelMessages = async (
return res;
};
export const getChannelThreadMessages = async (
token: string = '',
channel_id: string,
message_id: string,
skip: number = 0,
limit: number = 50
) => {
let error = null;
const res = await fetch(
`${WEBUI_API_BASE_URL}/channels/${channel_id}/messages/${message_id}/thread?skip=${skip}&limit=${limit}`,
{
method: 'GET',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
authorization: `Bearer ${token}`
}
}
)
.then(async (res) => {
if (!res.ok) throw await res.json();
return res.json();
})
.then((json) => {
return json;
})
.catch((err) => {
error = err.detail;
console.log(err);
return null;
});
if (error) {
throw error;
}
return res;
};
type MessageForm = {
parent_id?: string;
content: string;
data?: object;
meta?: object;
@@ -285,6 +327,86 @@ export const updateMessage = async (
return res;
};
export const addReaction = async (
token: string = '',
channel_id: string,
message_id: string,
name: string
) => {
let error = null;
const res = await fetch(
`${WEBUI_API_BASE_URL}/channels/${channel_id}/messages/${message_id}/reactions/add`,
{
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
authorization: `Bearer ${token}`
},
body: JSON.stringify({ name })
}
)
.then(async (res) => {
if (!res.ok) throw await res.json();
return res.json();
})
.then((json) => {
return json;
})
.catch((err) => {
error = err.detail;
console.log(err);
return null;
});
if (error) {
throw error;
}
return res;
};
export const removeReaction = async (
token: string = '',
channel_id: string,
message_id: string,
name: string
) => {
let error = null;
const res = await fetch(
`${WEBUI_API_BASE_URL}/channels/${channel_id}/messages/${message_id}/reactions/remove`,
{
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
authorization: `Bearer ${token}`
},
body: JSON.stringify({ name })
}
)
.then(async (res) => {
if (!res.ok) throw await res.json();
return res.json();
})
.then((json) => {
return json;
})
.catch((err) => {
error = err.detail;
console.log(err);
return null;
});
if (error) {
throw error;
}
return res;
};
export const deleteMessage = async (token: string = '', channel_id: string, message_id: string) => {
let error = null;
+38
View File
@@ -618,6 +618,44 @@ export const cloneChatById = async (token: string, id: string) => {
return res;
};
export const cloneSharedChatById = async (token: string, id: string) => {
let error = null;
const res = await fetch(`${WEBUI_API_BASE_URL}/chats/${id}/clone/shared`, {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
...(token && { authorization: `Bearer ${token}` })
}
})
.then(async (res) => {
if (!res.ok) throw await res.json();
return res.json();
})
.then((json) => {
return json;
})
.catch((err) => {
error = err;
if ('detail' in err) {
error = err.detail;
} else {
error = err;
}
console.log(err);
return null;
});
if (error) {
throw error;
}
return res;
};
export const shareChatById = async (token: string, id: string) => {
let error = null;
+14 -3
View File
@@ -1,5 +1,5 @@
<script lang="ts">
import { settings } from '$lib/stores';
import { settings, playingNotificationSound, isLastActiveTab } from '$lib/stores';
import DOMPurify from 'dompurify';
import { marked } from 'marked';
@@ -12,9 +12,20 @@
export let content: string;
onMount(() => {
if (!navigator.userActivation.hasBeenActive) {
return;
}
if ($settings?.notificationSound ?? true) {
const audio = new Audio(`/audio/notification.mp3`);
audio.play();
if (!$playingNotificationSound && $isLastActiveTab) {
playingNotificationSound.set(true);
const audio = new Audio(`/audio/notification.mp3`);
audio.play().finally(() => {
// Ensure the global state is reset after the sound finishes
playingNotificationSound.set(false);
});
}
}
});
</script>
@@ -128,7 +128,7 @@
await toggleModelById(localStorage.token, model.id);
}
await init();
// await init();
_models.set(await getModels(localStorage.token));
};
+145 -48
View File
@@ -1,14 +1,19 @@
<script lang="ts">
import { toast } from 'svelte-sonner';
import { Pane, PaneGroup, PaneResizer } from 'paneforge';
import { onDestroy, onMount, tick } from 'svelte';
import { goto } from '$app/navigation';
import { chatId, showSidebar, socket, user } from '$lib/stores';
import { getChannelById, getChannelMessages, sendMessage } from '$lib/apis/channels';
import Messages from './Messages.svelte';
import MessageInput from './MessageInput.svelte';
import { goto } from '$app/navigation';
import Navbar from './Navbar.svelte';
import Drawer from '../common/Drawer.svelte';
import EllipsisVertical from '../icons/EllipsisVertical.svelte';
import Thread from './Thread.svelte';
export let id = '';
@@ -20,6 +25,8 @@
let channel = null;
let messages = null;
let threadId = null;
let typingUsers = [];
let typingUsersTimeout = {};
@@ -28,13 +35,19 @@
}
const scrollToBottom = () => {
messagesContainerElement.scrollTop = messagesContainerElement.scrollHeight;
if (messagesContainerElement) {
messagesContainerElement.scrollTop = messagesContainerElement.scrollHeight;
}
};
const initHandler = async () => {
top = false;
messages = null;
channel = null;
threadId = null;
typingUsers = [];
typingUsersTimeout = {};
channel = await getChannelById(localStorage.token, id).catch((error) => {
return null;
@@ -44,7 +57,7 @@
messages = await getChannelMessages(localStorage.token, id, 0);
if (messages) {
messagesContainerElement.scrollTop = messagesContainerElement.scrollHeight;
scrollToBottom();
if (messages.length < 50) {
top = true;
@@ -56,35 +69,43 @@
};
const channelEventHandler = async (event) => {
console.log(event);
if (event.channel_id === id) {
const type = event?.data?.type ?? null;
const data = event?.data?.data ?? null;
if (type === 'message') {
console.log('message', data);
messages = [data, ...messages];
if ((data?.parent_id ?? null) === null) {
messages = [data, ...messages];
if (typingUsers.find((user) => user.id === event.user.id)) {
typingUsers = typingUsers.filter((user) => user.id !== event.user.id);
}
if (typingUsers.find((user) => user.id === event.user.id)) {
typingUsers = typingUsers.filter((user) => user.id !== event.user.id);
}
await tick();
if (scrollEnd) {
messagesContainerElement.scrollTop = messagesContainerElement.scrollHeight;
await tick();
if (scrollEnd) {
scrollToBottom();
}
}
} else if (type === 'message:update') {
console.log('message:update', data);
const idx = messages.findIndex((message) => message.id === data.id);
if (idx !== -1) {
messages[idx] = data;
}
} else if (type === 'message:delete') {
console.log('message:delete', data);
messages = messages.filter((message) => message.id !== data.id);
} else if (type === 'typing') {
} else if (type === 'message:reply') {
const idx = messages.findIndex((message) => message.id === data.id);
if (idx !== -1) {
messages[idx] = data;
}
} else if (type.includes('message:reaction')) {
const idx = messages.findIndex((message) => message.id === data.id);
if (idx !== -1) {
messages[idx] = data;
}
} else if (type === 'typing' && event.message_id === null) {
if (event.user.id === $user.id) {
return;
}
@@ -115,7 +136,7 @@
};
const submitHandler = async ({ content, data }) => {
if (!content) {
if (!content && (data?.files ?? []).length === 0) {
return;
}
@@ -134,6 +155,7 @@
const onChange = async () => {
$socket?.emit('channel-events', {
channel_id: id,
message_id: null,
data: {
type: 'typing',
data: {
@@ -143,16 +165,32 @@
});
};
let mediaQuery;
let largeScreen = false;
onMount(() => {
if ($chatId) {
chatId.set('');
}
$socket?.on('channel-events', channelEventHandler);
mediaQuery = window.matchMedia('(min-width: 1024px)');
const handleMediaQuery = async (e) => {
if (e.matches) {
largeScreen = true;
} else {
largeScreen = false;
}
};
mediaQuery.addEventListener('change', handleMediaQuery);
handleMediaQuery(mediaQuery);
});
onDestroy(() => {
// $socket?.off('channel-events', channelEventHandler);
$socket?.off('channel-events', channelEventHandler);
});
</script>
@@ -166,40 +204,99 @@
: ''} w-full max-w-full flex flex-col"
id="channel-container"
>
<Navbar {channel} />
<PaneGroup direction="horizontal" class="w-full h-full">
<Pane defaultSize={50} minSize={50} class="h-full flex flex-col w-full relative">
<Navbar {channel} />
<div class="flex-1 overflow-y-auto">
{#if channel}
<div
class=" pb-2.5 max-w-full z-10 scrollbar-hidden w-full h-full pt-6 flex-1 flex flex-col-reverse overflow-auto"
id="messages-container"
bind:this={messagesContainerElement}
on:scroll={(e) => {
scrollEnd = Math.abs(messagesContainerElement.scrollTop) <= 50;
}}
<div class="flex-1 overflow-y-auto">
{#if channel}
<div
class=" pb-2.5 max-w-full z-10 scrollbar-hidden w-full h-full pt-6 flex-1 flex flex-col-reverse overflow-auto"
id="messages-container"
bind:this={messagesContainerElement}
on:scroll={(e) => {
scrollEnd = Math.abs(messagesContainerElement.scrollTop) <= 50;
}}
>
{#key id}
<Messages
{channel}
{messages}
{top}
onThread={(id) => {
threadId = id;
}}
onLoad={async () => {
const newMessages = await getChannelMessages(
localStorage.token,
id,
messages.length
);
messages = [...messages, ...newMessages];
if (newMessages.length < 50) {
top = true;
return;
}
}}
/>
{/key}
</div>
{/if}
</div>
<div class=" pb-[1rem]">
<MessageInput
id="root"
{typingUsers}
{onChange}
onSubmit={submitHandler}
{scrollToBottom}
{scrollEnd}
/>
</div>
</Pane>
{#if !largeScreen}
{#if threadId !== null}
<Drawer
show={threadId !== null}
on:close={() => {
threadId = null;
}}
>
<div class=" {threadId !== null ? ' h-screen w-screen' : 'px-6 py-4'} h-full">
<Thread
{threadId}
{channel}
onClose={() => {
threadId = null;
}}
/>
</div>
</Drawer>
{/if}
{:else if threadId !== null}
<PaneResizer
class="relative flex w-[3px] items-center justify-center bg-background group bg-gray-50 dark:bg-gray-850"
>
{#key id}
<Messages
<div class="z-10 flex h-7 w-5 items-center justify-center rounded-sm">
<EllipsisVertical className="size-4 invisible group-hover:visible" />
</div>
</PaneResizer>
<Pane defaultSize={50} minSize={30} class="h-full w-full">
<div class="h-full w-full shadow-xl">
<Thread
{threadId}
{channel}
{messages}
{top}
onLoad={async () => {
const newMessages = await getChannelMessages(localStorage.token, id, messages.length);
messages = [...messages, ...newMessages];
if (newMessages.length < 50) {
top = true;
return;
}
onClose={() => {
threadId = null;
}}
/>
{/key}
</div>
</div>
</Pane>
{/if}
</div>
<div class=" pb-[1rem]">
<MessageInput {typingUsers} {onChange} onSubmit={submitHandler} {scrollToBottom} {scrollEnd} />
</div>
</PaneGroup>
</div>
+32 -75
View File
@@ -23,6 +23,8 @@
export let placeholder = $i18n.t('Send a Message');
export let transparentBackground = false;
export let id = null;
let draggedOver = false;
let recording = false;
@@ -37,7 +39,7 @@
export let onSubmit: Function;
export let onChange: Function;
export let scrollEnd = true;
export let scrollToBottom: Function;
export let scrollToBottom: Function = () => {};
const screenCaptureHandler = async () => {
try {
@@ -241,7 +243,7 @@
};
const submitHandler = async () => {
if (content === '') {
if (content === '' && files.length === 0) {
return;
}
@@ -257,7 +259,7 @@
await tick();
const chatInputElement = document.getElementById('chat-input');
const chatInputElement = document.getElementById(`chat-input-${id}`);
chatInputElement?.focus();
};
@@ -267,7 +269,7 @@
onMount(async () => {
window.setTimeout(() => {
const chatInput = document.getElementById('chat-input');
const chatInput = document.getElementById(`chat-input-${id}`);
chatInput?.focus();
}, 0);
@@ -313,7 +315,7 @@
filesInputElement.value = '';
}}
/>
<div class="{transparentBackground ? 'bg-transparent' : 'bg-white dark:bg-gray-900'} ">
<div class="bg-transparent">
<div
class="{($settings?.widescreenMode ?? null)
? 'max-w-full'
@@ -351,10 +353,10 @@
</div>
<div class="relative">
<div class=" -mt-5 bg-gradient-to-t from-white dark:from-gray-900">
<div class=" -mt-5">
{#if typingUsers.length > 0}
<div class=" text-xs px-4 mb-1">
<span class=" font-medium text-black dark:text-white">
<span class=" font-normal text-black dark:text-white">
{typingUsers.map((user) => user.name).join(', ')}
</span>
{$i18n.t('is typing...')}
@@ -373,7 +375,7 @@
recording = false;
await tick();
document.getElementById('chat-input')?.focus();
document.getElementById(`chat-input-${id}`)?.focus();
}}
on:confirm={async (e) => {
const { text, filename } = e.detail;
@@ -381,7 +383,7 @@
recording = false;
await tick();
document.getElementById('chat-input')?.focus();
document.getElementById(`chat-input-${id}`)?.focus();
}}
/>
{:else}
@@ -392,7 +394,7 @@
}}
>
<div
class="flex-1 flex flex-col relative w-full rounded-3xl px-1 bg-gray-50 dark:bg-gray-400/5 dark:text-gray-100"
class="flex-1 flex flex-col relative w-full rounded-3xl px-1 bg-gray-600/5 dark:bg-gray-400/5 dark:text-gray-100"
dir={$settings?.chatDirection ?? 'LTR'}
>
{#if files.length > 0}
@@ -478,61 +480,21 @@
</InputMenu>
</div>
{#if $settings?.richTextInput ?? true}
<div
class="scrollbar-hidden text-left bg-transparent dark:text-gray-100 outline-none w-full py-2.5 px-1 rounded-xl resize-none h-fit max-h-80 overflow-auto"
>
<RichTextInput
bind:value={content}
id="chat-input"
messageInput={true}
shiftEnter={!$mobile ||
!(
'ontouchstart' in window ||
navigator.maxTouchPoints > 0 ||
navigator.msMaxTouchPoints > 0
)}
{placeholder}
largeTextAsFile={$settings?.largeTextAsFile ?? false}
on:keydown={async (e) => {
e = e.detail.event;
const isCtrlPressed = e.ctrlKey || e.metaKey; // metaKey is for Cmd key on Mac
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 content when Enter key is pressed
if (content !== '' && e.keyCode === 13 && !e.shiftKey) {
submitHandler();
}
}
if (e.key === 'Escape') {
console.log('Escape');
}
}}
on:paste={async (e) => {
e = e.detail.event;
console.log(e);
}}
/>
</div>
{:else}
<textarea
id="chat-input"
class="scrollbar-hidden bg-transparent dark:text-gray-100 outline-none w-full py-3 px-1 rounded-xl resize-none h-[48px]"
{placeholder}
<div
class="scrollbar-hidden text-left bg-transparent dark:text-gray-100 outline-none w-full py-2.5 px-1 rounded-xl resize-none h-fit max-h-80 overflow-auto"
>
<RichTextInput
bind:value={content}
id={`chat-input-${id}`}
messageInput={true}
shiftEnter={!$mobile ||
!(
'ontouchstart' in window ||
navigator.maxTouchPoints > 0 ||
navigator.msMaxTouchPoints > 0
)}
{placeholder}
largeTextAsFile={$settings?.largeTextAsFile ?? false}
on:keydown={async (e) => {
e = e.detail.event;
const isCtrlPressed = e.ctrlKey || e.metaKey; // metaKey is for Cmd key on Mac
@@ -560,17 +522,12 @@
console.log('Escape');
}
}}
rows="1"
on:input={async (e) => {
e.target.style.height = '';
e.target.style.height = Math.min(e.target.scrollHeight, 320) + 'px';
}}
on:focus={async (e) => {
e.target.style.height = '';
e.target.style.height = Math.min(e.target.scrollHeight, 320) + 'px';
on:paste={async (e) => {
e = e.detail.event;
console.log(e);
}}
/>
{/if}
</div>
<div class="self-end mb-1.5 flex space-x-1 mr-1">
{#if content === ''}
@@ -624,11 +581,11 @@
<Tooltip content={$i18n.t('Send message')}>
<button
id="send-message-button"
class="{content !== ''
class="{content !== '' || files.length !== 0
? 'bg-black text-white hover:bg-gray-900 dark:bg-white dark:text-black dark:hover:bg-gray-100 '
: 'text-white bg-gray-200 dark:text-gray-900 dark:bg-gray-700 disabled'} transition rounded-full p-1.5 self-center"
type="submit"
disabled={content === ''}
disabled={content === '' && files.length === 0}
>
<svg
xmlns="http://www.w3.org/2000/svg"
+82 -5
View File
@@ -11,20 +11,23 @@
dayjs.extend(isYesterday);
import { tick, getContext, onMount, createEventDispatcher } from 'svelte';
import { settings } from '$lib/stores';
import { settings, user } from '$lib/stores';
import Message from './Messages/Message.svelte';
import Loader from '../common/Loader.svelte';
import Spinner from '../common/Spinner.svelte';
import { deleteMessage, updateMessage } from '$lib/apis/channels';
import { addReaction, deleteMessage, removeReaction, updateMessage } from '$lib/apis/channels';
const i18n = getContext('i18n');
export let id = null;
export let channel = null;
export let messages = [];
export let top = false;
export let thread = false;
export let onLoad: Function = () => {};
export let onThread: Function = () => {};
let messagesLoading = false;
@@ -59,14 +62,14 @@
<div class=" ">Loading...</div>
</div>
</Loader>
{:else}
{:else if !thread}
<div
class="px-5
{($settings?.widescreenMode ?? null) ? 'max-w-full' : 'max-w-5xl'} mx-auto"
>
{#if channel}
<div class="flex flex-col gap-1.5 py-5">
<div class="flex flex-col gap-1.5 pb-5 pt-10">
<div class="text-2xl font-medium capitalize">{channel.name}</div>
<div class=" text-gray-500">
@@ -88,12 +91,15 @@
</div>
{/if}
{#each messageList as message, messageIdx (message.id)}
{#each messageList as message, messageIdx (id ? `${id}-${message.id}` : message.id)}
<Message
{message}
{thread}
showUserProfile={messageIdx === 0 ||
messageList.at(messageIdx - 1)?.user_id !== message.user_id}
onDelete={() => {
messages = messages.filter((m) => m.id !== message.id);
const res = deleteMessage(localStorage.token, message.channel_id, message.id).catch(
(error) => {
toast.error(error);
@@ -102,6 +108,13 @@
);
}}
onEdit={(content) => {
messages = messages.map((m) => {
if (m.id === message.id) {
m.content = content;
}
return m;
});
const res = updateMessage(localStorage.token, message.channel_id, message.id, {
content: content
}).catch((error) => {
@@ -109,6 +122,70 @@
return null;
});
}}
onThread={(id) => {
onThread(id);
}}
onReaction={(name) => {
if (
(message?.reactions ?? [])
.find((reaction) => reaction.name === name)
?.user_ids?.includes($user.id) ??
false
) {
messages = messages.map((m) => {
if (m.id === message.id) {
const reaction = m.reactions.find((reaction) => reaction.name === name);
if (reaction) {
reaction.user_ids = reaction.user_ids.filter((id) => id !== $user.id);
reaction.count = reaction.user_ids.length;
if (reaction.count === 0) {
m.reactions = m.reactions.filter((r) => r.name !== name);
}
}
}
return m;
});
const res = removeReaction(
localStorage.token,
message.channel_id,
message.id,
name
).catch((error) => {
toast.error(error);
return null;
});
} else {
messages = messages.map((m) => {
if (m.id === message.id) {
if (m.reactions) {
const reaction = m.reactions.find((reaction) => reaction.name === name);
if (reaction) {
reaction.user_ids.push($user.id);
reaction.count = reaction.user_ids.length;
} else {
m.reactions.push({
name: name,
user_ids: [$user.id],
count: 1
});
}
}
}
return m;
});
const res = addReaction(localStorage.token, message.channel_id, message.id, name).catch(
(error) => {
toast.error(error);
return null;
}
);
}
}}
/>
{/each}
@@ -8,10 +8,10 @@
dayjs.extend(isToday);
dayjs.extend(isYesterday);
import { getContext } from 'svelte';
import { getContext, onMount } from 'svelte';
const i18n = getContext<Writable<i18nType>>('i18n');
import { settings, user } from '$lib/stores';
import { settings, user, shortCodesToEmojis } from '$lib/stores';
import { WEBUI_BASE_URL } from '$lib/constants';
@@ -26,12 +26,21 @@
import Image from '$lib/components/common/Image.svelte';
import FileItem from '$lib/components/common/FileItem.svelte';
import ProfilePreview from './Message/ProfilePreview.svelte';
import ChatBubbleOvalEllipsis from '$lib/components/icons/ChatBubbleOvalEllipsis.svelte';
import FaceSmile from '$lib/components/icons/FaceSmile.svelte';
import ReactionPicker from './Message/ReactionPicker.svelte';
import ChevronRight from '$lib/components/icons/ChevronRight.svelte';
export let message;
export let showUserProfile = true;
export let thread = false;
export let onDelete: Function = () => {};
export let onEdit: Function = () => {};
export let onThread: Function = () => {};
export let onReaction: Function = () => {};
let showButtons = false;
let edit = false;
let editedContent = null;
@@ -66,29 +75,69 @@
? 'pt-1.5 pb-0.5'
: ''} w-full {($settings?.widescreenMode ?? null)
? 'max-w-full'
: 'max-w-5xl'} mx-auto group hover:bg-gray-500/5 transition relative"
: 'max-w-5xl'} mx-auto group hover:bg-gray-300/5 dark:hover:bg-gray-700/5 transition relative"
>
{#if (message.user_id === $user.id || $user.role === 'admin') && !edit}
<div class=" absolute invisible group-hover:visible right-1 -top-2 z-30">
{#if !edit}
<div
class=" absolute {showButtons ? '' : 'invisible group-hover:visible'} right-1 -top-2 z-10"
>
<div
class="flex gap-1 rounded-lg bg-white dark:bg-gray-850 shadow-md p-0.5 border border-gray-100 dark:border-gray-800"
>
<button
class="hover:bg-gray-100 dark:hover:bg-gray-800 transition rounded-lg p-1"
on:click={() => {
edit = true;
editedContent = message.content;
<ReactionPicker
onClose={() => (showButtons = false)}
onSubmit={(name) => {
showButtons = false;
onReaction(name);
}}
>
<Pencil />
</button>
<Tooltip content={$i18n.t('Add Reaction')}>
<button
class="hover:bg-gray-100 dark:hover:bg-gray-800 transition rounded-lg p-1"
on:click={() => {
showButtons = true;
}}
>
<FaceSmile />
</button>
</Tooltip>
</ReactionPicker>
<button
class="hover:bg-gray-100 dark:hover:bg-gray-800 transition rounded-lg p-1"
on:click={() => (showDeleteConfirmDialog = true)}
>
<GarbageBin />
</button>
{#if !thread}
<Tooltip content={$i18n.t('Reply in Thread')}>
<button
class="hover:bg-gray-100 dark:hover:bg-gray-800 transition rounded-lg p-1"
on:click={() => {
onThread(message.id);
}}
>
<ChatBubbleOvalEllipsis />
</button>
</Tooltip>
{/if}
{#if message.user_id === $user.id || $user.role === 'admin'}
<Tooltip content={$i18n.t('Edit')}>
<button
class="hover:bg-gray-100 dark:hover:bg-gray-800 transition rounded-lg p-1"
on:click={() => {
edit = true;
editedContent = message.content;
}}
>
<Pencil />
</button>
</Tooltip>
<Tooltip content={$i18n.t('Delete')}>
<button
class="hover:bg-gray-100 dark:hover:bg-gray-800 transition rounded-lg p-1"
on:click={() => (showDeleteConfirmDialog = true)}
>
<GarbageBin />
</button>
</Tooltip>
{/if}
</div>
</div>
{/if}
@@ -129,7 +178,7 @@
<div class="flex-auto w-0 pl-1">
{#if showUserProfile}
<Name>
<div class=" self-end text-base font-medium">
<div class=" self-end text-base shrink-0 font-medium truncate">
{message?.user?.name}
</div>
@@ -140,7 +189,7 @@
<Tooltip
content={dayjs(message.created_at / 1000000).format('dddd, DD MMMM YYYY HH:mm')}
>
{formatDate(message.created_at / 1000000)}
<span class="line-clamp-1">{formatDate(message.created_at / 1000000)}</span>
</Tooltip>
</div>
{/if}
@@ -222,6 +271,85 @@
>(edited)</span
>{/if}
</div>
{#if (message?.reactions ?? []).length > 0}
<div>
<div class="flex items-center flex-wrap gap-y-1.5 gap-1 mt-1 mb-2">
{#each message.reactions as reaction}
<Tooltip content={`:${reaction.name}:`}>
<button
class="flex items-center gap-1.5 transition rounded-xl px-2 py-1 cursor-pointer {reaction.user_ids.includes(
$user.id
)
? ' bg-blue-300/10 outline outline-blue-500/50 outline-1'
: 'bg-gray-300/10 dark:bg-gray-500/10 hover:outline hover:outline-gray-700/30 dark:hover:outline-gray-300/30 hover:outline-1'}"
on:click={() => {
onReaction(reaction.name);
}}
>
{#if $shortCodesToEmojis[reaction.name]}
<img
src="/assets/emojis/{$shortCodesToEmojis[
reaction.name
].toLowerCase()}.svg"
alt={reaction.name}
class=" size-4"
loading="lazy"
/>
{:else}
<div>
{reaction.name}
</div>
{/if}
{#if reaction.user_ids.length > 0}
<div class="text-xs font-medium text-gray-500 dark:text-gray-400">
{reaction.user_ids?.length}
</div>
{/if}
</button>
</Tooltip>
{/each}
<ReactionPicker
onSubmit={(name) => {
onReaction(name);
}}
>
<Tooltip content={$i18n.t('Add Reaction')}>
<div
class="flex items-center gap-1.5 bg-gray-500/10 hover:outline hover:outline-gray-700/30 dark:hover:outline-gray-300/30 hover:outline-1 transition rounded-xl px-1 py-1 cursor-pointer text-gray-500 dark:text-gray-400"
>
<FaceSmile />
</div>
</Tooltip>
</ReactionPicker>
</div>
</div>
{/if}
{#if !thread && message.reply_count > 0}
<div class="flex items-center gap-1.5 -mt-0.5 mb-1.5">
<button
class="flex items-center text-xs py-1 text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300 transition"
on:click={() => {
onThread(message.id);
}}
>
<span class="font-medium mr-1">
{$i18n.t('{{COUNT}} Replies', { COUNT: message.reply_count })}</span
><span>
{' - '}{$i18n.t('Last reply')}
{dayjs.unix(message.latest_reply_at / 1000000000).fromNow()}</span
>
<span class="ml-1">
<ChevronRight className="size-2.5" strokeWidth="3" />
</span>
<!-- {$i18n.t('View Replies')} -->
</button>
</div>
{/if}
{/if}
</div>
</div>
@@ -29,7 +29,7 @@
<slot name="content">
<DropdownMenu.Content
class="w-full max-w-[200px] rounded-lg z-50 bg-white dark:bg-black dark:text-white shadow-lg"
class="max-w-full w-[240px] rounded-lg z-[9999] bg-white dark:bg-black dark:text-white shadow-lg"
sideOffset={8}
{side}
{align}
@@ -0,0 +1,166 @@
<script lang="ts">
import { DropdownMenu } from 'bits-ui';
import { flyAndScale } from '$lib/utils/transitions';
import emojiGroups from '$lib/emoji-groups.json';
import emojiShortCodes from '$lib/emoji-shortcodes.json';
import Tooltip from '$lib/components/common/Tooltip.svelte';
import VirtualList from '@sveltejs/svelte-virtual-list';
export let onClose = () => {};
export let onSubmit = (name) => {};
export let side = 'top';
export let align = 'start';
export let user = null;
let show = false;
let emojis = emojiShortCodes;
let search = '';
let flattenedEmojis = [];
let emojiRows = [];
// Reactive statement to filter the emojis based on search query
$: {
if (search) {
emojis = Object.keys(emojiShortCodes).reduce((acc, key) => {
if (key.includes(search)) {
acc[key] = emojiShortCodes[key];
} else {
if (Array.isArray(emojiShortCodes[key])) {
const filtered = emojiShortCodes[key].filter((emoji) => emoji.includes(search));
if (filtered.length) {
acc[key] = filtered;
}
} else {
if (emojiShortCodes[key].includes(search)) {
acc[key] = emojiShortCodes[key];
}
}
}
return acc;
}, {});
} else {
emojis = emojiShortCodes;
}
}
// Flatten emoji groups and group them into rows of 8 for virtual scrolling
$: {
flattenedEmojis = [];
Object.keys(emojiGroups).forEach((group) => {
const groupEmojis = emojiGroups[group].filter((emoji) => emojis[emoji]);
if (groupEmojis.length > 0) {
flattenedEmojis.push({ type: 'group', label: group });
flattenedEmojis.push(
...groupEmojis.map((emoji) => ({
type: 'emoji',
name: emoji,
shortCodes:
typeof emojiShortCodes[emoji] === 'string'
? [emojiShortCodes[emoji]]
: emojiShortCodes[emoji]
}))
);
}
});
// Group emojis into rows of 8
emojiRows = [];
let currentRow = [];
flattenedEmojis.forEach((item) => {
if (item.type === 'emoji') {
currentRow.push(item);
if (currentRow.length === 8) {
emojiRows.push(currentRow);
currentRow = [];
}
} else if (item.type === 'group') {
if (currentRow.length > 0) {
emojiRows.push(currentRow); // Push the remaining row
currentRow = [];
}
emojiRows.push([item]); // Add the group label as a separate row
}
});
if (currentRow.length > 0) {
emojiRows.push(currentRow); // Push the final row
}
}
const ROW_HEIGHT = 48; // Approximate height for a row with multiple emojis
// Handle emoji selection
function selectEmoji(emoji) {
const selectedCode = emoji.shortCodes[0];
onSubmit(selectedCode);
show = false;
}
</script>
<DropdownMenu.Root
bind:open={show}
closeFocus={false}
onOpenChange={(state) => {
if (!state) {
search = '';
onClose();
}
}}
typeahead={false}
>
<DropdownMenu.Trigger>
<slot />
</DropdownMenu.Trigger>
<DropdownMenu.Content
class="max-w-full w-80 bg-gray-50 dark:bg-gray-850 rounded-lg z-[9999] shadow-lg dark:text-white"
sideOffset={8}
{side}
{align}
transition={flyAndScale}
>
<div class="mb-1 px-3 pt-2 pb-2">
<input
type="text"
class="w-full text-sm bg-transparent outline-none"
placeholder="Search all emojis"
bind:value={search}
/>
</div>
<!-- Virtualized Emoji List -->
<div class="w-full flex justify-start h-96 overflow-y-auto px-3 pb-3 text-sm">
{#if emojiRows.length === 0}
<div class="text-center text-xs text-gray-500 dark:text-gray-400">No results</div>
{:else}
<div class="w-full flex ml-0.5">
<VirtualList rowHeight={ROW_HEIGHT} items={emojiRows} height={384} let:item>
<div class="w-full">
{#if item.length === 1 && item[0].type === 'group'}
<!-- Render group header -->
<div class="text-xs font-medium mb-2 text-gray-500 dark:text-gray-400">
{item[0].label}
</div>
{:else}
<!-- Render emojis in a row -->
<div class="flex items-center gap-1.5 w-full">
{#each item as emojiItem}
<Tooltip
content={emojiItem.shortCodes.map((code) => `:${code}:`).join(', ')}
placement="top"
>
<button
class="p-1.5 rounded-lg cursor-pointer hover:bg-gray-200 dark:hover:bg-gray-700 transition"
on:click={() => selectEmoji(emojiItem)}
>
<img
src="/assets/emojis/{emojiItem.name.toLowerCase()}.svg"
alt={emojiItem.name}
class="size-5"
loading="lazy"
/>
</button>
</Tooltip>
{/each}
</div>
{/if}
</div>
</VirtualList>
</div>
{/if}
</div>
</DropdownMenu.Content>
</DropdownMenu.Root>
+204
View File
@@ -0,0 +1,204 @@
<script lang="ts">
import { goto } from '$app/navigation';
import { socket, user } from '$lib/stores';
import { getChannelThreadMessages, sendMessage } from '$lib/apis/channels';
import XMark from '$lib/components/icons/XMark.svelte';
import MessageInput from './MessageInput.svelte';
import Messages from './Messages.svelte';
import { onDestroy, onMount, tick } from 'svelte';
import { toast } from 'svelte-sonner';
export let threadId = null;
export let channel = null;
export let onClose = () => {};
let messages = null;
let top = false;
let typingUsers = [];
let typingUsersTimeout = {};
let messagesContainerElement = null;
$: if (threadId) {
initHandler();
}
const scrollToBottom = () => {
messagesContainerElement.scrollTop = messagesContainerElement.scrollHeight;
};
const initHandler = async () => {
messages = null;
top = false;
typingUsers = [];
typingUsersTimeout = {};
if (channel) {
messages = await getChannelThreadMessages(localStorage.token, channel.id, threadId);
if (messages.length < 50) {
top = true;
}
await tick();
scrollToBottom();
} else {
goto('/');
}
};
const channelEventHandler = async (event) => {
console.log(event);
if (event.channel_id === channel.id) {
const type = event?.data?.type ?? null;
const data = event?.data?.data ?? null;
if (type === 'message') {
if ((data?.parent_id ?? null) === threadId) {
if (messages) {
messages = [data, ...messages];
if (typingUsers.find((user) => user.id === event.user.id)) {
typingUsers = typingUsers.filter((user) => user.id !== event.user.id);
}
}
}
} else if (type === 'message:update') {
if (messages) {
const idx = messages.findIndex((message) => message.id === data.id);
if (idx !== -1) {
messages[idx] = data;
}
}
} else if (type === 'message:delete') {
if (messages) {
messages = messages.filter((message) => message.id !== data.id);
}
} else if (type.includes('message:reaction')) {
if (messages) {
const idx = messages.findIndex((message) => message.id === data.id);
if (idx !== -1) {
messages[idx] = data;
}
}
} else if (type === 'typing' && event.message_id === threadId) {
if (event.user.id === $user.id) {
return;
}
typingUsers = data.typing
? [
...typingUsers,
...(typingUsers.find((user) => user.id === event.user.id)
? []
: [
{
id: event.user.id,
name: event.user.name
}
])
]
: typingUsers.filter((user) => user.id !== event.user.id);
if (typingUsersTimeout[event.user.id]) {
clearTimeout(typingUsersTimeout[event.user.id]);
}
typingUsersTimeout[event.user.id] = setTimeout(() => {
typingUsers = typingUsers.filter((user) => user.id !== event.user.id);
}, 5000);
}
}
};
const submitHandler = async ({ content, data }) => {
if (!content) {
return;
}
const res = await sendMessage(localStorage.token, channel.id, {
parent_id: threadId,
content: content,
data: data
}).catch((error) => {
toast.error(error);
return null;
});
};
const onChange = async () => {
$socket?.emit('channel-events', {
channel_id: channel.id,
message_id: threadId,
data: {
type: 'typing',
data: {
typing: true
}
}
});
};
onMount(() => {
$socket?.on('channel-events', channelEventHandler);
});
onDestroy(() => {
$socket?.off('channel-events', channelEventHandler);
});
</script>
{#if channel}
<div class="flex flex-col w-full h-full bg-gray-50 dark:bg-gray-850">
<div class="flex items-center justify-between px-3.5 pt-3">
<div class=" font-medium text-lg">Thread</div>
<div>
<button
class="text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300 p-2"
on:click={() => {
onClose();
}}
>
<XMark />
</button>
</div>
</div>
<div class=" max-h-full w-full overflow-y-auto pt-3" bind:this={messagesContainerElement}>
<Messages
id={threadId}
{channel}
{messages}
{top}
thread={true}
onLoad={async () => {
const newMessages = await getChannelThreadMessages(
localStorage.token,
channel.id,
threadId,
messages.length
);
messages = [...messages, ...newMessages];
if (newMessages.length < 50) {
top = true;
return;
}
}}
/>
<div class=" pb-[1rem]">
<MessageInput id={threadId} {typingUsers} {onChange} onSubmit={submitHandler} />
</div>
</div>
</div>
{/if}
+38 -13
View File
@@ -427,7 +427,7 @@
onDestroy(() => {
chatIdUnsubscriber?.();
window.removeEventListener('message', onMessageHandler);
// $socket?.off('chat-events');
$socket?.off('chat-events', chatEventHandler);
});
// File upload functions
@@ -836,7 +836,7 @@
return null;
});
if (res !== null) {
if (res !== null && res.messages) {
// Update chat history with the new messages
for (const message of res.messages) {
history.messages[message.id] = {
@@ -890,7 +890,7 @@
return null;
});
if (res !== null) {
if (res !== null && res.messages) {
// Update chat history with the new messages
for (const message of res.messages) {
history.messages[message.id] = {
@@ -1053,7 +1053,7 @@
};
const chatCompletionEventHandler = async (data, message, chatId) => {
const { id, done, choices, sources, selected_model_id, error, usage } = data;
const { id, done, choices, content, sources, selected_model_id, error, usage } = data;
if (error) {
await handleOpenAIError(error, message);
@@ -1105,6 +1105,38 @@
}
}
if (content) {
// REALTIME_CHAT_SAVE is disabled
message.content = content;
if (navigator.vibrate && ($settings?.hapticFeedback ?? false)) {
navigator.vibrate(5);
}
// Emit chat event for TTS
const messageContentParts = getMessageContentParts(
message.content,
$config?.audio?.tts?.split_on ?? 'punctuation'
);
messageContentParts.pop();
// dispatch only last sentence and make sure it hasn't been dispatched before
if (
messageContentParts.length > 0 &&
messageContentParts[messageContentParts.length - 1] !== message.lastSentence
) {
message.lastSentence = messageContentParts[messageContentParts.length - 1];
eventTarget.dispatchEvent(
new CustomEvent('chat', {
detail: {
id: message.id,
content: messageContentParts[messageContentParts.length - 1]
}
})
);
}
}
if (selected_model_id) {
message.selectedModelId = selected_model_id;
message.arena = true;
@@ -1114,16 +1146,11 @@
message.usage = usage;
}
history.messages[message.id] = message;
if (done) {
message.done = true;
if ($settings.notificationEnabled && !document.hasFocus()) {
new Notification(`${message.model}`, {
body: message.content,
icon: `${WEBUI_BASE_URL}/static/favicon.png`
});
}
if ($settings.responseAutoCopy) {
copyToClipboard(message.content);
}
@@ -1158,8 +1185,6 @@
await chatCompletedHandler(chatId, message.model, message.id, createMessagesList(message.id));
}
history.messages[message.id] = message;
console.log(data);
if (autoScroll) {
scrollToBottom();
+1 -1
View File
@@ -544,7 +544,7 @@
}}
>
<div
class="flex-1 flex flex-col relative w-full rounded-3xl px-1 bg-gray-50 dark:bg-gray-400/5 dark:text-gray-100"
class="flex-1 flex flex-col relative w-full rounded-3xl px-1 bg-gray-600/5 dark:bg-gray-400/5 dark:text-gray-100"
dir={$settings?.chatDirection ?? 'LTR'}
>
{#if files.length > 0}
@@ -217,7 +217,13 @@
const startRecording = async () => {
if ($showCallOverlay) {
if (!audioStream) {
audioStream = await navigator.mediaDevices.getUserMedia({ audio: true });
audioStream = await navigator.mediaDevices.getUserMedia({
audio: {
echoCancellation: true,
noiseSuppression: true,
autoGainControl: true
}
});
}
mediaRecorder = new MediaRecorder(audioStream);
@@ -161,7 +161,13 @@
const startRecording = async () => {
startDurationCounter();
stream = await navigator.mediaDevices.getUserMedia({ audio: true });
stream = await navigator.mediaDevices.getUserMedia({
audio: {
echoCancellation: true,
noiseSuppression: true,
autoGainControl: true
}
});
mediaRecorder = new MediaRecorder(stream);
mediaRecorder.onstart = () => {
console.log('Recording started');
+3 -1
View File
@@ -16,6 +16,8 @@
const i18n = getContext('i18n');
export let className = 'h-full flex pt-8';
export let chatId = '';
export let user = $_user;
@@ -333,7 +335,7 @@
};
</script>
<div class="h-full flex pt-8">
<div class={className}>
{#if Object.keys(history?.messages ?? {}).length == 0}
<ChatPlaceholder
modelIds={selectedModels}
@@ -52,12 +52,21 @@
}
const init = () => {
selectedReason = message?.annotation?.reason ?? '';
comment = message?.annotation?.comment ?? '';
if (!selectedReason) {
selectedReason = message?.annotation?.reason ?? '';
}
if (!comment) {
comment = message?.annotation?.comment ?? '';
}
tags = (message?.annotation?.tags ?? []).map((tag) => ({
name: tag
}));
detailedRating = message?.annotation?.details?.rating ?? null;
if (!detailedRating) {
detailedRating = message?.annotation?.details?.rating ?? null;
}
};
onMount(() => {
@@ -489,11 +489,15 @@
<div class="flex-auto w-0 pl-1">
<Name>
{model?.name ?? message.model}
<Tooltip content={model?.name ?? message.model} placement="top-start">
<span class="line-clamp-1">
{model?.name ?? message.model}
</span>
</Tooltip>
{#if message.timestamp}
<span
class=" self-center invisible group-hover:visible text-gray-400 text-xs font-medium uppercase ml-0.5 -mt-0.5"
class=" self-center shrink-0 translate-y-0.5 invisible group-hover:visible text-gray-400 text-xs font-medium uppercase ml-0.5 -mt-0.5"
>
{dayjs(message.timestamp * 1000).format($i18n.t('h:mm a'))}
</span>
@@ -543,8 +547,12 @@
{$i18n.t(status?.description, {
count: status?.urls.length
})}
{:else if status?.description === 'No search query generated'}
{$i18n.t('No search query generated')}
{:else if status?.description === 'Generating search query'}
{$i18n.t('Generating search query')}
{:else}
{$i18n.t(status?.description)}
{status?.description}
{/if}
</div>
</div>
@@ -573,8 +581,12 @@
{$i18n.t(status?.description, {
searchQuery: status?.query
})}
{:else if status?.description === 'No search query generated'}
{$i18n.t('No search query generated')}
{:else if status?.description === 'Generating search query'}
{$i18n.t('Generating search query')}
{:else}
{$i18n.t(status?.description)}
{status?.description}
{/if}
</div>
</div>
@@ -106,6 +106,12 @@
<hr class=" dark:border-gray-850" />
<div class="mt-2 text-xs text-gray-400 dark:text-gray-500">
Emoji graphics provided by
<a href="https://github.com/jdecked/twemoji" target="_blank">Twemoji</a>, licensed under
<a href="https://creativecommons.org/licenses/by/4.0/" target="_blank">CC-BY 4.0</a>.
</div>
<div class="flex space-x-1">
<a href="https://discord.gg/5rJgQTnV4s" target="_blank">
<img
@@ -132,11 +132,11 @@
</div>
<div class="flex justify-end">
<div class="flex flex-col items-end space-x-1 mt-1.5">
<div class="flex flex-col items-end space-x-1 mt-3">
<div class="flex gap-1">
{#if $config?.features.enable_community_sharing}
<button
class=" self-center px-3.5 py-2 rounded-xl text-sm font-medium bg-gray-100 hover:bg-gray-200 text-gray-800 dark:bg-gray-850 dark:hover:bg-gray-800 dark:text-white"
class="self-center flex items-center gap-1 px-3.5 py-2 text-sm font-medium bg-gray-100 hover:bg-gray-200 text-gray-800 dark:bg-gray-850 dark:text-white dark:hover:bg-gray-800 transition rounded-full"
type="button"
on:click={() => {
shareChat();
@@ -148,7 +148,7 @@
{/if}
<button
class=" self-center flex items-center gap-1 px-3.5 py-2 rounded-xl text-sm font-medium bg-emerald-600 hover:bg-emerald-500 text-white"
class="self-center flex items-center gap-1 px-3.5 py-2 text-sm font-medium bg-black hover:bg-gray-900 text-white dark:bg-white dark:text-black dark:hover:bg-gray-100 transition rounded-full"
type="button"
id="copy-and-share-chat-button"
on:click={async () => {
+1 -1
View File
@@ -57,7 +57,7 @@
<div
bind:this={modalElement}
class="modal fixed 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 right-0 left-0 bottom-0 bg-black/60 w-full h-screen max-h-[100dvh] flex justify-center z-[999] overflow-hidden overscroll-contain"
in:fly={{ y: 100, duration: 100 }}
on:mousedown={() => {
show = false;
+22 -2
View File
@@ -2,7 +2,7 @@
import { onMount, getContext } from 'svelte';
const i18n = getContext('i18n');
import panzoom from 'panzoom';
import panzoom, { type PanZoom } from 'panzoom';
import DOMPurify from 'dompurify';
import DocumentDuplicate from '../icons/DocumentDuplicate.svelte';
@@ -10,12 +10,13 @@
import { toast } from 'svelte-sonner';
import Tooltip from './Tooltip.svelte';
import Clipboard from '../icons/Clipboard.svelte';
import Reset from '../icons/Reset.svelte';
export let className = '';
export let svg = '';
export let content = '';
let instance;
let instance: PanZoom;
let sceneParentElement: HTMLElement;
let sceneElement: HTMLElement;
@@ -28,6 +29,12 @@
zoomSpeed: 0.065
});
}
function resetPanZoomViewport() {
console.log('Reset View');
instance.moveTo(0, 0);
instance.zoomAbs(0, 0, 1);
console.log(instance.getTransform());
}
</script>
<div bind:this={sceneParentElement} class="relative {className}">
@@ -49,5 +56,18 @@
</button>
</Tooltip>
</div>
<div class=" absolute top-1 right-10">
<Tooltip content={$i18n.t('Reset view')}>
<button
class="p-1.5 rounded-lg border border-gray-100 dark:border-none dark:bg-gray-850 hover:bg-gray-50 dark:hover:bg-gray-800 transition"
on:click={() => {
resetPanZoomViewport();
toast.success($i18n.t('Reset view'));
}}
>
<Reset className=" size-4" />
</button>
</Tooltip>
</div>
{/if}
</div>
+1 -1
View File
@@ -56,7 +56,7 @@
<style>
.placeholder::before {
/* abolute */
/* absolute */
position: absolute;
content: attr(data-placeholder);
color: #adb5bd;
@@ -0,0 +1,19 @@
<script lang="ts">
export let className = 'size-4';
export let strokeWidth = '1.5';
</script>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width={strokeWidth}
stroke="currentColor"
class={className}
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M8.625 12a.375.375 0 1 1-.75 0 .375.375 0 0 1 .75 0Zm0 0H8.25m4.125 0a.375.375 0 1 1-.75 0 .375.375 0 0 1 .75 0Zm0 0H12m4.125 0a.375.375 0 1 1-.75 0 .375.375 0 0 1 .75 0Zm0 0h-.375M21 12c0 4.556-4.03 8.25-9 8.25a9.764 9.764 0 0 1-2.555-.337A5.972 5.972 0 0 1 5.41 20.97a5.969 5.969 0 0 1-.474-.065 4.48 4.48 0 0 0 .978-2.025c.09-.457-.133-.901-.467-1.226C3.93 16.178 3 14.189 3 12c0-4.556 4.03-8.25 9-8.25s9 3.694 9 8.25Z"
/>
</svg>
+19
View File
@@ -0,0 +1,19 @@
<script lang="ts">
export let className = 'size-4';
export let strokeWidth = '1.5';
</script>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width={strokeWidth}
stroke="currentColor"
class={className}
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M15.182 15.182a4.5 4.5 0 0 1-6.364 0M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0ZM9.75 9.75c0 .414-.168.75-.375.75S9 10.164 9 9.75 9.168 9 9.375 9s.375.336.375.75Zm-.375 0h.008v.015h-.008V9.75Zm5.625 0c0 .414-.168.75-.375.75s-.375-.336-.375-.75.168-.75.375-.75.375.336.375.75Zm-.375 0h.008v.015h-.008V9.75Z"
/>
</svg>
+9
View File
@@ -0,0 +1,9 @@
<script lang="ts">
export let className = 'size-4';
</script>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" fill="currentColor" class={className}>
<path
d="M463.5 224l8.5 0c13.3 0 24-10.7 24-24l0-128c0-9.7-5.8-18.5-14.8-22.2s-19.3-1.7-26.2 5.2L413.4 96.6c-87.6-86.5-228.7-86.2-315.8 1c-87.5 87.5-87.5 229.3 0 316.8s229.3 87.5 316.8 0c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0c-62.5 62.5-163.8 62.5-226.3 0s-62.5-163.8 0-226.3c62.2-62.2 162.7-62.5 225.3-1L327 183c-6.9 6.9-8.9 17.2-5.2 26.2s12.5 14.8 22.2 14.8l119.5 0z"
/>
</svg>
+12 -5
View File
@@ -83,12 +83,19 @@
const downloadJSONExport = async () => {
if (chat.id) {
chat = await getChatById(localStorage.token, chat.id);
let chatObj = null;
if (chat.id === 'local' || $temporaryChatEnabled) {
chatObj = chat;
} else {
chatObj = await getChatById(localStorage.token, chat.id);
}
let blob = new Blob([JSON.stringify([chatObj])], {
type: 'application/json'
});
saveAs(blob, `chat-export-${Date.now()}.json`);
}
let blob = new Blob([JSON.stringify([chat])], {
type: 'application/json'
});
saveAs(blob, `chat-export-${Date.now()}.json`);
};
</script>
+97 -106
View File
@@ -558,19 +558,6 @@
on:input={searchDebounceHandler}
placeholder={$i18n.t('Search')}
/>
<div class="absolute z-40 right-3.5 top-1">
<Tooltip content={$i18n.t('New folder')}>
<button
class="p-1 rounded-lg bg-gray-50 hover:bg-gray-100 dark:bg-gray-950 dark:hover:bg-gray-900 text-gray-500 dark:text-gray-500 transition"
on:click={() => {
createFolder();
}}
>
<Plus className=" size-3" strokeWidth="2.5" />
</button>
</Tooltip>
</div>
</div>
<div
@@ -578,82 +565,6 @@
? 'opacity-20'
: ''}"
>
{#if !search && $pinnedChats.length > 0}
<div class="flex flex-col space-y-1 rounded-xl">
<Folder
className="px-2"
bind:open={showPinnedChat}
on:change={(e) => {
localStorage.setItem('showPinnedChat', e.detail);
console.log(e.detail);
}}
on:import={(e) => {
importChatHandler(e.detail, true);
}}
on:drop={async (e) => {
const { type, id, item } = e.detail;
if (type === 'chat') {
let chat = await getChatById(localStorage.token, id).catch((error) => {
return null;
});
if (!chat && item) {
chat = await importChat(localStorage.token, item.chat, item?.meta ?? {});
}
if (chat) {
console.log(chat);
if (chat.folder_id) {
const res = await updateChatFolderIdById(
localStorage.token,
chat.id,
null
).catch((error) => {
toast.error(error);
return null;
});
}
if (!chat.pinned) {
const res = await toggleChatPinnedStatusById(localStorage.token, chat.id);
}
initChatList();
}
}
}}
name={$i18n.t('Pinned')}
>
<div
class="ml-3 pl-1 mt-[1px] flex flex-col overflow-y-auto scrollbar-hidden border-s border-gray-100 dark:border-gray-900"
>
{#each $pinnedChats as chat, idx}
<ChatItem
className=""
id={chat.id}
title={chat.title}
{shiftKey}
selected={selectedChatId === chat.id}
on:select={() => {
selectedChatId = chat.id;
}}
on:unselect={() => {
selectedChatId = null;
}}
on:change={async () => {
initChatList();
}}
on:tag={(e) => {
const { type, name } = e.detail;
tagEventHandler(type, name, chat.id);
}}
/>
{/each}
</div>
</Folder>
</div>
{/if}
{#if $config?.features?.enable_channels && ($user.role === 'admin' || $channels.length > 0) && !search}
<Folder
className="px-2 mt-0.5"
@@ -677,26 +588,14 @@
</Folder>
{/if}
{#if !search && folders}
<Folders
{folders}
on:import={(e) => {
const { folderId, items } = e.detail;
importChatHandler(items, false, folderId);
}}
on:update={async (e) => {
initChatList();
}}
on:change={async () => {
initChatList();
}}
/>
{/if}
<Folder
collapsible={!search}
className="px-2 mt-0.5"
name={$i18n.t('Chats')}
onAdd={() => {
createFolder();
}}
onAddLabel={$i18n.t('New Folder')}
on:import={(e) => {
importChatHandler(e.detail);
}}
@@ -723,7 +622,7 @@
}
if (chat.pinned) {
const res = await toggleChatPinnedStatusById(localStorage.token, chat, id);
const res = await toggleChatPinnedStatusById(localStorage.token, chat.id);
}
initChatList();
@@ -750,6 +649,98 @@
<div class="absolute z-40 w-full h-full flex justify-center"></div>
{/if}
{#if !search && $pinnedChats.length > 0}
<div class="flex flex-col space-y-1 rounded-xl">
<Folder
className=""
bind:open={showPinnedChat}
on:change={(e) => {
localStorage.setItem('showPinnedChat', e.detail);
console.log(e.detail);
}}
on:import={(e) => {
importChatHandler(e.detail, true);
}}
on:drop={async (e) => {
const { type, id, item } = e.detail;
if (type === 'chat') {
let chat = await getChatById(localStorage.token, id).catch((error) => {
return null;
});
if (!chat && item) {
chat = await importChat(localStorage.token, item.chat, item?.meta ?? {});
}
if (chat) {
console.log(chat);
if (chat.folder_id) {
const res = await updateChatFolderIdById(
localStorage.token,
chat.id,
null
).catch((error) => {
toast.error(error);
return null;
});
}
if (!chat.pinned) {
const res = await toggleChatPinnedStatusById(localStorage.token, chat.id);
}
initChatList();
}
}
}}
name={$i18n.t('Pinned')}
>
<div
class="ml-3 pl-1 mt-[1px] flex flex-col overflow-y-auto scrollbar-hidden border-s border-gray-100 dark:border-gray-900"
>
{#each $pinnedChats as chat, idx}
<ChatItem
className=""
id={chat.id}
title={chat.title}
{shiftKey}
selected={selectedChatId === chat.id}
on:select={() => {
selectedChatId = chat.id;
}}
on:unselect={() => {
selectedChatId = null;
}}
on:change={async () => {
initChatList();
}}
on:tag={(e) => {
const { type, name } = e.detail;
tagEventHandler(type, name, chat.id);
}}
/>
{/each}
</div>
</Folder>
</div>
{/if}
{#if !search && folders}
<Folders
{folders}
on:import={(e) => {
const { folderId, items } = e.detail;
importChatHandler(items, false, folderId);
}}
on:update={async (e) => {
initChatList();
}}
on:change={async () => {
initChatList();
}}
/>
{/if}
<div class=" flex-1 flex flex-col overflow-y-auto scrollbar-hidden">
<div class="pt-1.5">
{#if $chats}
@@ -81,9 +81,8 @@
{#if $user?.role === 'admin'}
<button
class="absolute z-10 right-2 invisible group-hover:visible self-center flex items-center dark:text-gray-300"
on:pointerup={(e) => {
on:click={(e) => {
e.stopPropagation();
showEditChannelModal = true;
}}
>
@@ -19,7 +19,7 @@
{#each folderList as folderId (folderId)}
<RecursiveFolder
className="px-2"
className=""
{folders}
{folderId}
on:import={(e) => {
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+8 -1
View File
@@ -5,6 +5,7 @@
"(e.g. `sh webui.sh --api`)": "( `sh webui.sh --api`مثال)",
"(latest)": "(الأخير)",
"{{ models }}": "{{ نماذج }}",
"{{COUNT}} Replies": "",
"{{user}}'s Chats": "دردشات {{user}}",
"{{webUIName}} Backend Required": "{{webUIName}} مطلوب",
"*Prompt node ID(s) are required for image generation": "",
@@ -34,6 +35,7 @@
"Add Group": "",
"Add Memory": "إضافة ذكرايات",
"Add Model": "اضافة موديل",
"Add Reaction": "",
"Add Tag": "",
"Add Tags": "اضافة تاق",
"Add text content": "",
@@ -164,6 +166,7 @@
"Click on the user role button to change a user's role.": "أضغط على أسم الصلاحيات لتغيرها للمستخدم",
"Clipboard write permission denied. Please check your browser settings to grant the necessary access.": "",
"Clone": "استنساخ",
"Clone Chat": "",
"Close": "أغلق",
"Code execution": "",
"Code formatted successfully": "",
@@ -534,6 +537,7 @@
"Language": "اللغة",
"Last Active": "آخر نشاط",
"Last Modified": "",
"Last reply": "",
"LDAP": "",
"LDAP server updated": "",
"Leaderboard": "",
@@ -608,7 +612,7 @@
"Name": "الأسم",
"Name your knowledge base": "",
"New Chat": "دردشة جديدة",
"New folder": "",
"New Folder": "",
"New Password": "كلمة المرور الجديدة",
"new-channel": "",
"No content found": "",
@@ -739,6 +743,7 @@
"Rename": "إعادة تسمية",
"Reorder Models": "",
"Repeat Last N": "N كرر آخر",
"Reply in Thread": "",
"Request Mode": "وضع الطلب",
"Reranking Model": "إعادة تقييم النموذج",
"Reranking model disabled": "تم تعطيل نموذج إعادة الترتيب",
@@ -747,6 +752,7 @@
"Reset All Models": "",
"Reset Upload Directory": "",
"Reset Vector Storage/Knowledge": "",
"Reset view": "",
"Response notifications cannot be activated as the website permissions have been denied. Please visit your browser settings to grant the necessary access.": "",
"Response splitting": "",
"Result": "",
@@ -1004,6 +1010,7 @@
"variable to have them replaced with clipboard content.": "متغير لاستبدالها بمحتوى الحافظة.",
"Version": "إصدار",
"Version {{selectedVersion}} of {{totalVersions}}": "",
"View Replies": "",
"Visibility": "",
"Voice": "",
"Voice Input": "",
+8 -1
View File
@@ -5,6 +5,7 @@
"(e.g. `sh webui.sh --api`)": "(например `sh webui.sh --api`)",
"(latest)": "(последна)",
"{{ models }}": "{{ модели }}",
"{{COUNT}} Replies": "",
"{{user}}'s Chats": "{{user}}'s чатове",
"{{webUIName}} Backend Required": "{{webUIName}} Изисква се Бекенд",
"*Prompt node ID(s) are required for image generation": "",
@@ -34,6 +35,7 @@
"Add Group": "",
"Add Memory": "Добавяне на Памет",
"Add Model": "Добавяне на Модел",
"Add Reaction": "",
"Add Tag": "",
"Add Tags": "добавяне на тагове",
"Add text content": "",
@@ -164,6 +166,7 @@
"Click on the user role button to change a user's role.": "Натиснете върху бутона за промяна на ролята на потребителя.",
"Clipboard write permission denied. Please check your browser settings to grant the necessary access.": "",
"Clone": "Клонинг",
"Clone Chat": "",
"Close": "Затвори",
"Code execution": "",
"Code formatted successfully": "",
@@ -534,6 +537,7 @@
"Language": "Език",
"Last Active": "Последни активни",
"Last Modified": "",
"Last reply": "",
"LDAP": "",
"LDAP server updated": "",
"Leaderboard": "",
@@ -608,7 +612,7 @@
"Name": "Име",
"Name your knowledge base": "",
"New Chat": "Нов чат",
"New folder": "",
"New Folder": "",
"New Password": "Нова парола",
"new-channel": "",
"No content found": "",
@@ -739,6 +743,7 @@
"Rename": "Преименуване",
"Reorder Models": "",
"Repeat Last N": "Repeat Last N",
"Reply in Thread": "",
"Request Mode": "Request Mode",
"Reranking Model": "Reranking Model",
"Reranking model disabled": "Reranking model disabled",
@@ -747,6 +752,7 @@
"Reset All Models": "",
"Reset Upload Directory": "",
"Reset Vector Storage/Knowledge": "",
"Reset view": "",
"Response notifications cannot be activated as the website permissions have been denied. Please visit your browser settings to grant the necessary access.": "",
"Response splitting": "",
"Result": "",
@@ -1004,6 +1010,7 @@
"variable to have them replaced with clipboard content.": "променливи да се заменят съдържанието от клипборд.",
"Version": "Версия",
"Version {{selectedVersion}} of {{totalVersions}}": "",
"View Replies": "",
"Visibility": "",
"Voice": "",
"Voice Input": "",
+8 -1
View File
@@ -5,6 +5,7 @@
"(e.g. `sh webui.sh --api`)": "(যেমন `sh webui.sh --api`)",
"(latest)": "(সর্বশেষ)",
"{{ models }}": "{{ মডেল}}",
"{{COUNT}} Replies": "",
"{{user}}'s Chats": "{{user}}র চ্যাটস",
"{{webUIName}} Backend Required": "{{webUIName}} ব্যাকএন্ড আবশ্যক",
"*Prompt node ID(s) are required for image generation": "",
@@ -34,6 +35,7 @@
"Add Group": "",
"Add Memory": "মেমোরি যোগ করুন",
"Add Model": "মডেল যোগ করুন",
"Add Reaction": "",
"Add Tag": "",
"Add Tags": "ট্যাগ যোগ করুন",
"Add text content": "",
@@ -164,6 +166,7 @@
"Click on the user role button to change a user's role.": "ইউজারের পদবি পরিবর্তন করার জন্য ইউজারের পদবি বাটনে ক্লিক করুন",
"Clipboard write permission denied. Please check your browser settings to grant the necessary access.": "",
"Clone": "ক্লোন",
"Clone Chat": "",
"Close": "বন্ধ",
"Code execution": "",
"Code formatted successfully": "",
@@ -534,6 +537,7 @@
"Language": "ভাষা",
"Last Active": "সর্বশেষ সক্রিয়",
"Last Modified": "",
"Last reply": "",
"LDAP": "",
"LDAP server updated": "",
"Leaderboard": "",
@@ -608,7 +612,7 @@
"Name": "নাম",
"Name your knowledge base": "",
"New Chat": "নতুন চ্যাট",
"New folder": "",
"New Folder": "",
"New Password": "নতুন পাসওয়ার্ড",
"new-channel": "",
"No content found": "",
@@ -739,6 +743,7 @@
"Rename": "রেনেম",
"Reorder Models": "",
"Repeat Last N": "রিপিট Last N",
"Reply in Thread": "",
"Request Mode": "রিকোয়েস্ট মোড",
"Reranking Model": "রির্যাক্টিং মডেল",
"Reranking model disabled": "রির্যাক্টিং মডেল নিষ্ক্রিয় করা",
@@ -747,6 +752,7 @@
"Reset All Models": "",
"Reset Upload Directory": "",
"Reset Vector Storage/Knowledge": "",
"Reset view": "",
"Response notifications cannot be activated as the website permissions have been denied. Please visit your browser settings to grant the necessary access.": "",
"Response splitting": "",
"Result": "",
@@ -1004,6 +1010,7 @@
"variable to have them replaced with clipboard content.": "ক্লিপবোর্ডের কন্টেন্ট দিয়ে যেই ভেরিয়েবল রিপ্লেস করা যাবে।",
"Version": "ভার্সন",
"Version {{selectedVersion}} of {{totalVersions}}": "",
"View Replies": "",
"Visibility": "",
"Voice": "",
"Voice Input": "",
+8 -1
View File
@@ -5,6 +5,7 @@
"(e.g. `sh webui.sh --api`)": "(p. ex. `sh webui.sh --api`)",
"(latest)": "(últim)",
"{{ models }}": "{{ models }}",
"{{COUNT}} Replies": "",
"{{user}}'s Chats": "Els xats de {{user}}",
"{{webUIName}} Backend Required": "El Backend de {{webUIName}} és necessari",
"*Prompt node ID(s) are required for image generation": "*Els identificadors de nodes d'indicacions són necessaris per a la generació d'imatges",
@@ -34,6 +35,7 @@
"Add Group": "Afegir grup",
"Add Memory": "Afegir memòria",
"Add Model": "Afegir un model",
"Add Reaction": "",
"Add Tag": "Afegir etiqueta",
"Add Tags": "Afegir etiquetes",
"Add text content": "Afegir contingut de text",
@@ -164,6 +166,7 @@
"Click on the user role button to change a user's role.": "Clica sobre el botó de rol d'usuari per canviar el rol d'un usuari.",
"Clipboard write permission denied. Please check your browser settings to grant the necessary access.": "Permís d'escriptura al porta-retalls denegat. Comprova els ajustos de navegador per donar l'accés necessari.",
"Clone": "Clonar",
"Clone Chat": "",
"Close": "Tancar",
"Code execution": "Execució de codi",
"Code formatted successfully": "Codi formatat correctament",
@@ -534,6 +537,7 @@
"Language": "Idioma",
"Last Active": "Activitat recent",
"Last Modified": "Modificació",
"Last reply": "",
"LDAP": "LDAP",
"LDAP server updated": "Servidor LDAP actualitzat",
"Leaderboard": "Tauler de classificació",
@@ -608,7 +612,7 @@
"Name": "Nom",
"Name your knowledge base": "Anomena la teva base de coneixement",
"New Chat": "Nou xat",
"New folder": "Nova carpeta",
"New Folder": "",
"New Password": "Nova contrasenya",
"new-channel": "nou-canal",
"No content found": "No s'ha trobat contingut",
@@ -739,6 +743,7 @@
"Rename": "Canviar el nom",
"Reorder Models": "Reordenar els models",
"Repeat Last N": "Repeteix els darrers N",
"Reply in Thread": "",
"Request Mode": "Mode de sol·licitud",
"Reranking Model": "Model de reavaluació",
"Reranking model disabled": "Model de reavaluació desactivat",
@@ -747,6 +752,7 @@
"Reset All Models": "Restablir tots els models",
"Reset Upload Directory": "Restableix el directori de pujades",
"Reset Vector Storage/Knowledge": "Restableix el Repositori de vectors/Coneixement",
"Reset view": "",
"Response notifications cannot be activated as the website permissions have been denied. Please visit your browser settings to grant the necessary access.": "Les notifications de resposta no es poden activar perquè els permisos del lloc web han estat rebutjats. Comprova les preferències del navegador per donar l'accés necessari.",
"Response splitting": "Divisió de la resposta",
"Result": "Resultat",
@@ -1004,6 +1010,7 @@
"variable to have them replaced with clipboard content.": "variable per tenir-les reemplaçades amb el contingut del porta-retalls.",
"Version": "Versió",
"Version {{selectedVersion}} of {{totalVersions}}": "Versió {{selectedVersion}} de {{totalVersions}}",
"View Replies": "",
"Visibility": "Visibilitat",
"Voice": "Veu",
"Voice Input": "Entrada de veu",
+8 -1
View File
@@ -5,6 +5,7 @@
"(e.g. `sh webui.sh --api`)": "(pananglitan `sh webui.sh --api`)",
"(latest)": "",
"{{ models }}": "",
"{{COUNT}} Replies": "",
"{{user}}'s Chats": "",
"{{webUIName}} Backend Required": "Backend {{webUIName}} gikinahanglan",
"*Prompt node ID(s) are required for image generation": "",
@@ -34,6 +35,7 @@
"Add Group": "",
"Add Memory": "",
"Add Model": "",
"Add Reaction": "",
"Add Tag": "",
"Add Tags": "idugang ang mga tag",
"Add text content": "",
@@ -164,6 +166,7 @@
"Click on the user role button to change a user's role.": "I-klik ang User Role button aron usbon ang role sa user.",
"Clipboard write permission denied. Please check your browser settings to grant the necessary access.": "",
"Clone": "",
"Clone Chat": "",
"Close": "Suod nga",
"Code execution": "",
"Code formatted successfully": "",
@@ -534,6 +537,7 @@
"Language": "Pinulongan",
"Last Active": "",
"Last Modified": "",
"Last reply": "",
"LDAP": "",
"LDAP server updated": "",
"Leaderboard": "",
@@ -608,7 +612,7 @@
"Name": "Ngalan",
"Name your knowledge base": "",
"New Chat": "Bag-ong diskusyon",
"New folder": "",
"New Folder": "",
"New Password": "Bag-ong Password",
"new-channel": "",
"No content found": "",
@@ -739,6 +743,7 @@
"Rename": "",
"Reorder Models": "",
"Repeat Last N": "Balika ang katapusang N",
"Reply in Thread": "",
"Request Mode": "Query mode",
"Reranking Model": "",
"Reranking model disabled": "",
@@ -747,6 +752,7 @@
"Reset All Models": "",
"Reset Upload Directory": "",
"Reset Vector Storage/Knowledge": "",
"Reset view": "",
"Response notifications cannot be activated as the website permissions have been denied. Please visit your browser settings to grant the necessary access.": "",
"Response splitting": "",
"Result": "",
@@ -1004,6 +1010,7 @@
"variable to have them replaced with clipboard content.": "variable aron pulihan kini sa mga sulud sa clipboard.",
"Version": "Bersyon",
"Version {{selectedVersion}} of {{totalVersions}}": "",
"View Replies": "",
"Visibility": "",
"Voice": "",
"Voice Input": "",
+8 -1
View File
@@ -5,6 +5,7 @@
"(e.g. `sh webui.sh --api`)": "(např. `sh webui.sh --api`)",
"(latest)": "Nejnovější",
"{{ models }}": "{{ models }}",
"{{COUNT}} Replies": "",
"{{user}}'s Chats": "{{user}}'s konverzace",
"{{webUIName}} Backend Required": "Požadován {{webUIName}} Backend",
"*Prompt node ID(s) are required for image generation": "*Jsou vyžadovány IDs pro prompt node pro generování obrázků",
@@ -34,6 +35,7 @@
"Add Group": "Přidat skupinu",
"Add Memory": "Přidat paměť",
"Add Model": "Přidat model",
"Add Reaction": "",
"Add Tag": "Přidat štítek",
"Add Tags": "Přidat štítky",
"Add text content": "Přidejte textový obsah",
@@ -164,6 +166,7 @@
"Click on the user role button to change a user's role.": "Klikněte na tlačítko role uživatele, abyste změnili roli uživatele.",
"Clipboard write permission denied. Please check your browser settings to grant the necessary access.": "Přístup k zápisu do schránky byl zamítnut. Prosím, zkontrolujte nastavení svého prohlížeče a udělte potřebný přístup.",
"Clone": "Klonovat",
"Clone Chat": "",
"Close": "Zavřít",
"Code execution": "Provádění kódu",
"Code formatted successfully": "Kód byl úspěšně naformátován.",
@@ -534,6 +537,7 @@
"Language": "Jazyk",
"Last Active": "Naposledy aktivní",
"Last Modified": "Poslední změna",
"Last reply": "",
"LDAP": "",
"LDAP server updated": "",
"Leaderboard": "Žebříček",
@@ -608,7 +612,7 @@
"Name": "Jméno",
"Name your knowledge base": "",
"New Chat": "Nový chat",
"New folder": "",
"New Folder": "",
"New Password": "Nové heslo",
"new-channel": "",
"No content found": "Nebyly nalezeny žádné obsahové informace.",
@@ -739,6 +743,7 @@
"Rename": "Přejmenovat",
"Reorder Models": "",
"Repeat Last N": "Opakovat posledních N",
"Reply in Thread": "",
"Request Mode": "Režim žádosti",
"Reranking Model": "Model pro přehodnocení pořadí",
"Reranking model disabled": "Přeřazovací model je deaktivován",
@@ -747,6 +752,7 @@
"Reset All Models": "",
"Reset Upload Directory": "Resetovat adresář nahrávání",
"Reset Vector Storage/Knowledge": "Resetování úložiště vektorů/znalostí",
"Reset view": "",
"Response notifications cannot be activated as the website permissions have been denied. Please visit your browser settings to grant the necessary access.": "Oznámení o odpovědích nelze aktivovat, protože oprávnění webu byla zamítnuta. Navštivte nastavení svého prohlížeče a udělte potřebný přístup.",
"Response splitting": "Rozdělení odpovědi",
"Result": "Výsledek",
@@ -1004,6 +1010,7 @@
"variable to have them replaced with clipboard content.": "proměnnou, aby byl jejich obsah nahrazen obsahem schránky.",
"Version": "Verze",
"Version {{selectedVersion}} of {{totalVersions}}": "Verze {{selectedVersion}} z {{totalVersions}}",
"View Replies": "",
"Visibility": "Viditelnost",
"Voice": "Hlas",
"Voice Input": "Hlasový vstup",
+8 -1
View File
@@ -5,6 +5,7 @@
"(e.g. `sh webui.sh --api`)": "(f.eks. `sh webui.sh --api`)",
"(latest)": "(seneste)",
"{{ models }}": "{{ modeller }}",
"{{COUNT}} Replies": "",
"{{user}}'s Chats": "{{user}}s chats",
"{{webUIName}} Backend Required": "{{webUIName}} Backend kræves",
"*Prompt node ID(s) are required for image generation": "*Prompt node ID(s) er påkrævet for at kunne generere billeder",
@@ -34,6 +35,7 @@
"Add Group": "",
"Add Memory": "Tilføj hukommelse",
"Add Model": "Tilføj model",
"Add Reaction": "",
"Add Tag": "Tilføj tag",
"Add Tags": "Tilføj tags",
"Add text content": "Tilføj tekst",
@@ -164,6 +166,7 @@
"Click on the user role button to change a user's role.": "Klik på bruger ikonet for at ændre brugerens rolle.",
"Clipboard write permission denied. Please check your browser settings to grant the necessary access.": "Skriveadgang til udklipsholderen ikke tilladt. Tjek venligst indstillingerne i din browser for at give adgang.",
"Clone": "Klon",
"Clone Chat": "",
"Close": "Luk",
"Code execution": "",
"Code formatted successfully": "Kode formateret korrekt",
@@ -534,6 +537,7 @@
"Language": "Sprog",
"Last Active": "Sidst aktiv",
"Last Modified": "Sidst ændret",
"Last reply": "",
"LDAP": "",
"LDAP server updated": "",
"Leaderboard": "",
@@ -608,7 +612,7 @@
"Name": "Navn",
"Name your knowledge base": "",
"New Chat": "Ny chat",
"New folder": "",
"New Folder": "",
"New Password": "Ny adgangskode",
"new-channel": "",
"No content found": "",
@@ -739,6 +743,7 @@
"Rename": "Omdøb",
"Reorder Models": "",
"Repeat Last N": "Gentag sidste N",
"Reply in Thread": "",
"Request Mode": "Forespørgselstilstand",
"Reranking Model": "Omarrangeringsmodel",
"Reranking model disabled": "Omarrangeringsmodel deaktiveret",
@@ -747,6 +752,7 @@
"Reset All Models": "",
"Reset Upload Directory": "Nulstil uploadmappe",
"Reset Vector Storage/Knowledge": "",
"Reset view": "",
"Response notifications cannot be activated as the website permissions have been denied. Please visit your browser settings to grant the necessary access.": "Svarnotifikationer kan ikke aktiveres, da webstedets tilladelser er blevet nægtet. Besøg dine browserindstillinger for at give den nødvendige adgang.",
"Response splitting": "Svaropdeling",
"Result": "",
@@ -1004,6 +1010,7 @@
"variable to have them replaced with clipboard content.": "variabel for at få dem erstattet med indholdet af udklipsholderen.",
"Version": "Version",
"Version {{selectedVersion}} of {{totalVersions}}": "Version {{selectedVersion}} af {{totalVersions}}",
"View Replies": "",
"Visibility": "",
"Voice": "Stemme",
"Voice Input": "",
+8 -1
View File
@@ -5,6 +5,7 @@
"(e.g. `sh webui.sh --api`)": "(z. B. `sh webui.sh --api`)",
"(latest)": "(neueste)",
"{{ models }}": "{{ Modelle }}",
"{{COUNT}} Replies": "",
"{{user}}'s Chats": "{{user}}s Unterhaltungen",
"{{webUIName}} Backend Required": "{{webUIName}}-Backend erforderlich",
"*Prompt node ID(s) are required for image generation": "*Prompt-Node-ID(s) sind für die Bildgenerierung erforderlich",
@@ -34,6 +35,7 @@
"Add Group": "Gruppe hinzufügen",
"Add Memory": "Erinnerung hinzufügen",
"Add Model": "Modell hinzufügen",
"Add Reaction": "",
"Add Tag": "Tag hinzufügen",
"Add Tags": "Tags hinzufügen",
"Add text content": "Textinhalt hinzufügen",
@@ -164,6 +166,7 @@
"Click on the user role button to change a user's role.": "Klicken Sie auf die Benutzerrolle, um sie zu ändern.",
"Clipboard write permission denied. Please check your browser settings to grant the necessary access.": "Schreibberechtigung für die Zwischenablage verweigert. Bitte überprüfen Sie Ihre Browsereinstellungen, um den erforderlichen Zugriff zu erlauben.",
"Clone": "Klonen",
"Clone Chat": "",
"Close": "Schließen",
"Code execution": "Codeausführung",
"Code formatted successfully": "Code erfolgreich formatiert",
@@ -534,6 +537,7 @@
"Language": "Sprache",
"Last Active": "Zuletzt aktiv",
"Last Modified": "Zuletzt bearbeitet",
"Last reply": "",
"LDAP": "LDAP",
"LDAP server updated": "LDAP-Server aktualisiert",
"Leaderboard": "Bestenliste",
@@ -608,7 +612,7 @@
"Name": "Name",
"Name your knowledge base": "Benennen Sie Ihren Wissensspeicher",
"New Chat": "Neue Unterhaltung",
"New folder": "",
"New Folder": "",
"New Password": "Neues Passwort",
"new-channel": "",
"No content found": "Kein Inhalt gefunden",
@@ -739,6 +743,7 @@
"Rename": "Umbenennen",
"Reorder Models": "",
"Repeat Last N": "Wiederhole die letzten N",
"Reply in Thread": "",
"Request Mode": "Anforderungsmodus",
"Reranking Model": "Reranking-Modell",
"Reranking model disabled": "Reranking-Modell deaktiviert",
@@ -747,6 +752,7 @@
"Reset All Models": "",
"Reset Upload Directory": "Upload-Verzeichnis zurücksetzen",
"Reset Vector Storage/Knowledge": "Vektorspeicher/Wissen zurücksetzen",
"Reset view": "",
"Response notifications cannot be activated as the website permissions have been denied. Please visit your browser settings to grant the necessary access.": "Benachrichtigungen können nicht aktiviert werden, da die Website-Berechtigungen abgelehnt wurden. Bitte besuchen Sie Ihre Browser-Einstellungen, um den erforderlichen Zugriff zu gewähren.",
"Response splitting": "Antwortaufteilung",
"Result": "Ergebnis",
@@ -1004,6 +1010,7 @@
"variable to have them replaced with clipboard content.": "Variable, um den Inhalt der Zwischenablage beim Nutzen des Prompts zu ersetzen.",
"Version": "Version",
"Version {{selectedVersion}} of {{totalVersions}}": "Version {{selectedVersion}} von {{totalVersions}}",
"View Replies": "",
"Visibility": "Sichtbarkeit",
"Voice": "Stimme",
"Voice Input": "Spracheingabe",
+8 -1
View File
@@ -5,6 +5,7 @@
"(e.g. `sh webui.sh --api`)": "(such e.g. `sh webui.sh --api`)",
"(latest)": "(much latest)",
"{{ models }}": "",
"{{COUNT}} Replies": "",
"{{user}}'s Chats": "",
"{{webUIName}} Backend Required": "{{webUIName}} Backend Much Required",
"*Prompt node ID(s) are required for image generation": "",
@@ -34,6 +35,7 @@
"Add Group": "",
"Add Memory": "",
"Add Model": "",
"Add Reaction": "",
"Add Tag": "",
"Add Tags": "",
"Add text content": "",
@@ -164,6 +166,7 @@
"Click on the user role button to change a user's role.": "Click user role button to change role.",
"Clipboard write permission denied. Please check your browser settings to grant the necessary access.": "",
"Clone": "",
"Clone Chat": "",
"Close": "Close",
"Code execution": "",
"Code formatted successfully": "",
@@ -534,6 +537,7 @@
"Language": "Doge Speak",
"Last Active": "",
"Last Modified": "",
"Last reply": "",
"LDAP": "",
"LDAP server updated": "",
"Leaderboard": "",
@@ -608,7 +612,7 @@
"Name": "Name",
"Name your knowledge base": "",
"New Chat": "New Bark",
"New folder": "",
"New Folder": "",
"New Password": "New Barkword",
"new-channel": "",
"No content found": "",
@@ -739,6 +743,7 @@
"Rename": "",
"Reorder Models": "",
"Repeat Last N": "Repeat Last N",
"Reply in Thread": "",
"Request Mode": "Request Bark",
"Reranking Model": "",
"Reranking model disabled": "",
@@ -747,6 +752,7 @@
"Reset All Models": "",
"Reset Upload Directory": "",
"Reset Vector Storage/Knowledge": "",
"Reset view": "",
"Response notifications cannot be activated as the website permissions have been denied. Please visit your browser settings to grant the necessary access.": "",
"Response splitting": "",
"Result": "",
@@ -1004,6 +1010,7 @@
"variable to have them replaced with clipboard content.": "variable to have them replaced with clipboard content. Very replace.",
"Version": "Version much version",
"Version {{selectedVersion}} of {{totalVersions}}": "",
"View Replies": "",
"Visibility": "",
"Voice": "",
"Voice Input": "",
+8 -1
View File
@@ -5,6 +5,7 @@
"(e.g. `sh webui.sh --api`)": "(π.χ. `sh webui.sh --api`)",
"(latest)": "(τελευταίο)",
"{{ models }}": "{{ models }}",
"{{COUNT}} Replies": "",
"{{user}}'s Chats": "Συνομιλίες του {{user}}",
"{{webUIName}} Backend Required": "{{webUIName}} Απαιτείται Backend",
"*Prompt node ID(s) are required for image generation": "*Τα αναγνωριστικά κόμβου Prompt απαιτούνται για τη δημιουργία εικόνων",
@@ -34,6 +35,7 @@
"Add Group": "Προσθήκη Ομάδας",
"Add Memory": "Προσθήκη Μνήμης",
"Add Model": "Προσθήκη Μοντέλου",
"Add Reaction": "",
"Add Tag": "Προσθήκη Ετικέτας",
"Add Tags": "Προσθήκη Ετικετών",
"Add text content": "Προσθήκη κειμένου",
@@ -164,6 +166,7 @@
"Click on the user role button to change a user's role.": "Κάντε κλικ στο κουμπί ρόλου χρήστη για να αλλάξετε το ρόλο ενός χρήστη.",
"Clipboard write permission denied. Please check your browser settings to grant the necessary access.": "Άρνηση δικαιώματος εγγραφής στο πρόχειρο. Παρακαλώ ελέγξτε τις ρυθμίσεις του περιηγητή σας για να δώσετε την απαραίτητη πρόσβαση.",
"Clone": "Κλώνος",
"Clone Chat": "",
"Close": "Κλείσιμο",
"Code execution": "Εκτέλεση κώδικα",
"Code formatted successfully": "Ο κώδικας μορφοποιήθηκε επιτυχώς",
@@ -534,6 +537,7 @@
"Language": "Γλώσσα",
"Last Active": "Τελευταία Ενεργή",
"Last Modified": "Τελευταία Τροποποίηση",
"Last reply": "",
"LDAP": "LDAP",
"LDAP server updated": "Ο διακομιστής LDAP ενημερώθηκε",
"Leaderboard": "Κατάταξη",
@@ -608,7 +612,7 @@
"Name": "Όνομα",
"Name your knowledge base": "Ονομάστε τη βάση γνώσης σας",
"New Chat": "Νέα Συνομιλία",
"New folder": "",
"New Folder": "",
"New Password": "Νέος Κωδικός",
"new-channel": "",
"No content found": "Δεν βρέθηκε περιεχόμενο",
@@ -739,6 +743,7 @@
"Rename": "Μετονομασία",
"Reorder Models": "Επαναταξινόμηση Μοντέλων",
"Repeat Last N": "Επανάληψη Τελευταίων N",
"Reply in Thread": "",
"Request Mode": "Λειτουργία Αιτήματος",
"Reranking Model": "Μοντέλο Επαναταξινόμησης",
"Reranking model disabled": "Το μοντέλο επαναταξινόμησης απενεργοποιήθηκε",
@@ -747,6 +752,7 @@
"Reset All Models": "Επαναφορά Όλων των Μοντέλων",
"Reset Upload Directory": "Επαναφορά Καταλόγου Ανεβάσματος",
"Reset Vector Storage/Knowledge": "Επαναφορά Αποθήκευσης Διανυσμάτων/Γνώσης",
"Reset view": "",
"Response notifications cannot be activated as the website permissions have been denied. Please visit your browser settings to grant the necessary access.": "Οι ειδοποιήσεις απάντησης δεν μπορούν να ενεργοποιηθούν καθώς οι άδειες του ιστότοπου έχουν αρνηθεί. Παρακαλώ επισκεφτείτε τις ρυθμίσεις του περιηγητή σας για να δώσετε την απαραίτητη πρόσβαση.",
"Response splitting": "Διαχωρισμός απάντησης",
"Result": "Αποτέλεσμα",
@@ -1004,6 +1010,7 @@
"variable to have them replaced with clipboard content.": "μεταβλητή να αντικατασταθούν με το περιεχόμενο του πρόχειρου.",
"Version": "Έκδοση",
"Version {{selectedVersion}} of {{totalVersions}}": "Έκδοση {{selectedVersion}} από {{totalVersions}}",
"View Replies": "",
"Visibility": "Ορατότητα",
"Voice": "Φωνή",
"Voice Input": "Εισαγωγή Φωνής",
+8 -1
View File
@@ -5,6 +5,7 @@
"(e.g. `sh webui.sh --api`)": "",
"(latest)": "",
"{{ models }}": "",
"{{COUNT}} Replies": "",
"{{user}}'s Chats": "",
"{{webUIName}} Backend Required": "",
"*Prompt node ID(s) are required for image generation": "",
@@ -34,6 +35,7 @@
"Add Group": "",
"Add Memory": "",
"Add Model": "",
"Add Reaction": "",
"Add Tag": "",
"Add Tags": "",
"Add text content": "",
@@ -164,6 +166,7 @@
"Click on the user role button to change a user's role.": "",
"Clipboard write permission denied. Please check your browser settings to grant the necessary access.": "",
"Clone": "",
"Clone Chat": "",
"Close": "",
"Code execution": "",
"Code formatted successfully": "",
@@ -534,6 +537,7 @@
"Language": "",
"Last Active": "",
"Last Modified": "",
"Last reply": "",
"LDAP": "",
"LDAP server updated": "",
"Leaderboard": "",
@@ -608,7 +612,7 @@
"Name": "",
"Name your knowledge base": "",
"New Chat": "",
"New folder": "",
"New Folder": "",
"New Password": "",
"new-channel": "",
"No content found": "",
@@ -739,6 +743,7 @@
"Rename": "",
"Reorder Models": "",
"Repeat Last N": "",
"Reply in Thread": "",
"Request Mode": "",
"Reranking Model": "",
"Reranking model disabled": "",
@@ -747,6 +752,7 @@
"Reset All Models": "",
"Reset Upload Directory": "",
"Reset Vector Storage/Knowledge": "",
"Reset view": "",
"Response notifications cannot be activated as the website permissions have been denied. Please visit your browser settings to grant the necessary access.": "",
"Response splitting": "",
"Result": "",
@@ -1004,6 +1010,7 @@
"variable to have them replaced with clipboard content.": "",
"Version": "",
"Version {{selectedVersion}} of {{totalVersions}}": "",
"View Replies": "",
"Visibility": "",
"Voice": "",
"Voice Input": "",
+8 -1
View File
@@ -5,6 +5,7 @@
"(e.g. `sh webui.sh --api`)": "",
"(latest)": "",
"{{ models }}": "",
"{{COUNT}} Replies": "",
"{{user}}'s Chats": "",
"{{webUIName}} Backend Required": "",
"*Prompt node ID(s) are required for image generation": "",
@@ -34,6 +35,7 @@
"Add Group": "",
"Add Memory": "",
"Add Model": "",
"Add Reaction": "",
"Add Tag": "",
"Add Tags": "",
"Add text content": "",
@@ -164,6 +166,7 @@
"Click on the user role button to change a user's role.": "",
"Clipboard write permission denied. Please check your browser settings to grant the necessary access.": "",
"Clone": "",
"Clone Chat": "",
"Close": "",
"Code execution": "",
"Code formatted successfully": "",
@@ -534,6 +537,7 @@
"Language": "",
"Last Active": "",
"Last Modified": "",
"Last reply": "",
"LDAP": "",
"LDAP server updated": "",
"Leaderboard": "",
@@ -608,7 +612,7 @@
"Name": "",
"Name your knowledge base": "",
"New Chat": "",
"New folder": "",
"New Folder": "",
"New Password": "",
"new-channel": "",
"No content found": "",
@@ -739,6 +743,7 @@
"Rename": "",
"Reorder Models": "",
"Repeat Last N": "",
"Reply in Thread": "",
"Request Mode": "",
"Reranking Model": "",
"Reranking model disabled": "",
@@ -747,6 +752,7 @@
"Reset All Models": "",
"Reset Upload Directory": "",
"Reset Vector Storage/Knowledge": "",
"Reset view": "",
"Response notifications cannot be activated as the website permissions have been denied. Please visit your browser settings to grant the necessary access.": "",
"Response splitting": "",
"Result": "",
@@ -1004,6 +1010,7 @@
"variable to have them replaced with clipboard content.": "",
"Version": "",
"Version {{selectedVersion}} of {{totalVersions}}": "",
"View Replies": "",
"Visibility": "",
"Voice": "",
"Voice Input": "",
+8 -1
View File
@@ -5,6 +5,7 @@
"(e.g. `sh webui.sh --api`)": "(p.ej. `sh webui.sh --api`)",
"(latest)": "(latest)",
"{{ models }}": "{{ models }}",
"{{COUNT}} Replies": "",
"{{user}}'s Chats": "Chats de {{user}}",
"{{webUIName}} Backend Required": "{{webUIName}} Servidor Requerido",
"*Prompt node ID(s) are required for image generation": "Los ID de nodo son requeridos para la generación de imágenes",
@@ -34,6 +35,7 @@
"Add Group": "",
"Add Memory": "Agregar Memoria",
"Add Model": "Agregar Modelo",
"Add Reaction": "",
"Add Tag": "Agregar etiqueta",
"Add Tags": "agregar etiquetas",
"Add text content": "Añade contenido de texto",
@@ -164,6 +166,7 @@
"Click on the user role button to change a user's role.": "Presiona en el botón de roles del usuario para cambiar su rol.",
"Clipboard write permission denied. Please check your browser settings to grant the necessary access.": "Permisos de escritura del portapapeles denegados. Por favor, comprueba las configuraciones de tu navegador para otorgar el acceso necesario.",
"Clone": "Clonar",
"Clone Chat": "",
"Close": "Cerrar",
"Code execution": "",
"Code formatted successfully": "Se ha formateado correctamente el código.",
@@ -534,6 +537,7 @@
"Language": "Lenguaje",
"Last Active": "Última Actividad",
"Last Modified": "Modificado por última vez",
"Last reply": "",
"LDAP": "",
"LDAP server updated": "",
"Leaderboard": "",
@@ -608,7 +612,7 @@
"Name": "Nombre",
"Name your knowledge base": "",
"New Chat": "Nuevo Chat",
"New folder": "",
"New Folder": "",
"New Password": "Nueva Contraseña",
"new-channel": "",
"No content found": "",
@@ -739,6 +743,7 @@
"Rename": "Renombrar",
"Reorder Models": "",
"Repeat Last N": "Repetir las últimas N",
"Reply in Thread": "",
"Request Mode": "Modo de petición",
"Reranking Model": "Modelo de reranking",
"Reranking model disabled": "Modelo de reranking deshabilitado",
@@ -747,6 +752,7 @@
"Reset All Models": "",
"Reset Upload Directory": "Reiniciar Directorio de carga",
"Reset Vector Storage/Knowledge": "",
"Reset view": "",
"Response notifications cannot be activated as the website permissions have been denied. Please visit your browser settings to grant the necessary access.": "Las notificaciones de respuesta no pueden activarse debido a que los permisos del sitio web han sido denegados. Por favor, visite las configuraciones de su navegador para otorgar el acceso necesario.",
"Response splitting": "División de respuestas",
"Result": "",
@@ -1004,6 +1010,7 @@
"variable to have them replaced with clipboard content.": "variable para reemplazarlos con el contenido del portapapeles.",
"Version": "Versión",
"Version {{selectedVersion}} of {{totalVersions}}": "Versión {{selectedVersion}} de {{totalVersions}}",
"View Replies": "",
"Visibility": "",
"Voice": "Voz",
"Voice Input": "",
+8 -1
View File
@@ -5,6 +5,7 @@
"(e.g. `sh webui.sh --api`)": "(adib. `sh webui.sh --api`)",
"(latest)": "(azkena)",
"{{ models }}": "{{ models }}",
"{{COUNT}} Replies": "",
"{{user}}'s Chats": "{{user}}-ren Txatak",
"{{webUIName}} Backend Required": "{{webUIName}} Backend-a Beharrezkoa",
"*Prompt node ID(s) are required for image generation": "Prompt nodoaren IDa(k) beharrezkoak dira irudiak sortzeko",
@@ -34,6 +35,7 @@
"Add Group": "Gehitu Taldea",
"Add Memory": "Gehitu Memoria",
"Add Model": "Gehitu Eredua",
"Add Reaction": "",
"Add Tag": "Gehitu Etiketa",
"Add Tags": "Gehitu Etiketak",
"Add text content": "Gehitu testu edukia",
@@ -164,6 +166,7 @@
"Click on the user role button to change a user's role.": "Klikatu erabiltzaile rolaren botoian erabiltzaile baten rola aldatzeko.",
"Clipboard write permission denied. Please check your browser settings to grant the necessary access.": "Arbelerako idazteko baimena ukatua. Mesedez, egiaztatu zure nabigatzailearen ezarpenak beharrezko sarbidea emateko.",
"Clone": "Klonatu",
"Clone Chat": "",
"Close": "Itxi",
"Code execution": "Kodearen exekuzioa",
"Code formatted successfully": "Kodea ongi formateatu da",
@@ -534,6 +537,7 @@
"Language": "Hizkuntza",
"Last Active": "Azken Aktibitatea",
"Last Modified": "Azken Aldaketa",
"Last reply": "",
"LDAP": "LDAP",
"LDAP server updated": "LDAP zerbitzaria eguneratu da",
"Leaderboard": "Sailkapena",
@@ -608,7 +612,7 @@
"Name": "Izena",
"Name your knowledge base": "Izendatu zure ezagutza-basea",
"New Chat": "Txat berria",
"New folder": "",
"New Folder": "",
"New Password": "Pasahitz berria",
"new-channel": "",
"No content found": "Ez da edukirik aurkitu",
@@ -739,6 +743,7 @@
"Rename": "Berrizendatu",
"Reorder Models": "Berrantolatu modeloak",
"Repeat Last N": "Errepikatu azken N",
"Reply in Thread": "",
"Request Mode": "Eskaera modua",
"Reranking Model": "Berrantolatze modeloa",
"Reranking model disabled": "Berrantolatze modeloa desgaituta",
@@ -747,6 +752,7 @@
"Reset All Models": "",
"Reset Upload Directory": "Berrezarri karga direktorioa",
"Reset Vector Storage/Knowledge": "Berrezarri bektore biltegia/ezagutza",
"Reset view": "",
"Response notifications cannot be activated as the website permissions have been denied. Please visit your browser settings to grant the necessary access.": "Erantzunen jakinarazpenak ezin dira aktibatu webgunearen baimenak ukatu direlako. Mesedez, bisitatu zure nabigatzailearen ezarpenak beharrezko sarbidea emateko.",
"Response splitting": "Erantzun banaketa",
"Result": "Emaitza",
@@ -1004,6 +1010,7 @@
"variable to have them replaced with clipboard content.": "aldagaia arbeleko edukiarekin ordezkatzeko.",
"Version": "Bertsioa",
"Version {{selectedVersion}} of {{totalVersions}}": "{{totalVersions}}-tik {{selectedVersion}}. bertsioa",
"View Replies": "",
"Visibility": "Ikusgarritasuna",
"Voice": "Ahotsa",
"Voice Input": "Ahots sarrera",
+8 -1
View File
@@ -5,6 +5,7 @@
"(e.g. `sh webui.sh --api`)": "(e.g. `sh webui.sh --api`)",
"(latest)": "(آخرین)",
"{{ models }}": "{{ models }}",
"{{COUNT}} Replies": "",
"{{user}}'s Chats": "{{user}} گفتگوهای",
"{{webUIName}} Backend Required": "بکند {{webUIName}} نیاز است.",
"*Prompt node ID(s) are required for image generation": "",
@@ -34,6 +35,7 @@
"Add Group": "",
"Add Memory": "افزودن حافظه",
"Add Model": "افزودن مدل",
"Add Reaction": "",
"Add Tag": "افزودن برچسب",
"Add Tags": "افزودن برچسب\u200cها",
"Add text content": "افزودن محتوای متنی",
@@ -164,6 +166,7 @@
"Click on the user role button to change a user's role.": "برای تغییر نقش کاربر، روی دکمه نقش کاربر کلیک کنید.",
"Clipboard write permission denied. Please check your browser settings to grant the necessary access.": "",
"Clone": "کلون",
"Clone Chat": "",
"Close": "بسته",
"Code execution": "",
"Code formatted successfully": "",
@@ -534,6 +537,7 @@
"Language": "زبان",
"Last Active": "آخرین فعال",
"Last Modified": "",
"Last reply": "",
"LDAP": "",
"LDAP server updated": "",
"Leaderboard": "",
@@ -608,7 +612,7 @@
"Name": "نام",
"Name your knowledge base": "",
"New Chat": "گپ جدید",
"New folder": "",
"New Folder": "",
"New Password": "رمز عبور جدید",
"new-channel": "",
"No content found": "",
@@ -739,6 +743,7 @@
"Rename": "تغییر نام",
"Reorder Models": "",
"Repeat Last N": "Repeat Last N",
"Reply in Thread": "",
"Request Mode": "حالت درخواست",
"Reranking Model": "مدل ری\u200cشناسی مجدد غیرفعال است",
"Reranking model disabled": "مدل ری\u200cشناسی مجدد غیرفعال است",
@@ -747,6 +752,7 @@
"Reset All Models": "",
"Reset Upload Directory": "",
"Reset Vector Storage/Knowledge": "",
"Reset view": "",
"Response notifications cannot be activated as the website permissions have been denied. Please visit your browser settings to grant the necessary access.": "",
"Response splitting": "",
"Result": "نتیجه",
@@ -1004,6 +1010,7 @@
"variable to have them replaced with clipboard content.": "متغیر برای جایگزینی آنها با محتوای بریده\u200cدان.",
"Version": "نسخه",
"Version {{selectedVersion}} of {{totalVersions}}": "نسخهٔ {{selectedVersion}} از {{totalVersions}}",
"View Replies": "",
"Visibility": "",
"Voice": "صوت",
"Voice Input": "ورودی صوتی",
+8 -1
View File
@@ -5,6 +5,7 @@
"(e.g. `sh webui.sh --api`)": "(esim. `sh webui.sh --api`)",
"(latest)": "(uusin)",
"{{ models }}": "{{ mallit }}",
"{{COUNT}} Replies": "",
"{{user}}'s Chats": "{{user}}:n keskustelut",
"{{webUIName}} Backend Required": "{{webUIName}}-backend vaaditaan",
"*Prompt node ID(s) are required for image generation": "Kuvan luomiseen vaaditaan kehote-solmun ID(t)",
@@ -34,6 +35,7 @@
"Add Group": "Lisää ryhmä",
"Add Memory": "Lisää muistia",
"Add Model": "Lisää malli",
"Add Reaction": "",
"Add Tag": "Lisää tagi",
"Add Tags": "Lisää tageja",
"Add text content": "Lisää tekstisisältöä",
@@ -164,6 +166,7 @@
"Click on the user role button to change a user's role.": "Klikkaa käyttäjän roolipainiketta vaihtaaksesi käyttäjän roolia.",
"Clipboard write permission denied. Please check your browser settings to grant the necessary access.": "Leikepöydälle kirjoitusoikeus evätty. Tarkista selaimesi asetukset ja myönnä tarvittavat käyttöoikeudet.",
"Clone": "Kloonaa",
"Clone Chat": "",
"Close": "Sulje",
"Code execution": "Koodin suorittaminen",
"Code formatted successfully": "Koodin muotoilu onnistui",
@@ -534,6 +537,7 @@
"Language": "Kieli",
"Last Active": "Viimeksi aktiivinen",
"Last Modified": "Viimeksi muokattu",
"Last reply": "",
"LDAP": "LDAP",
"LDAP server updated": "LDAP-palvelin päivitetty",
"Leaderboard": "Tulosluettelo",
@@ -608,7 +612,7 @@
"Name": "Nimi",
"Name your knowledge base": "Anna tietokannalle nimi",
"New Chat": "Uusi keskustelu",
"New folder": "",
"New Folder": "",
"New Password": "Uusi salasana",
"new-channel": "",
"No content found": "Sisältöä ei löytynyt",
@@ -739,6 +743,7 @@
"Rename": "Nimeä uudelleen",
"Reorder Models": "Uudelleenjärjestä malleja",
"Repeat Last N": "Toista viimeiset N",
"Reply in Thread": "",
"Request Mode": "Pyyntötila",
"Reranking Model": "Uudelleenpisteytymismalli",
"Reranking model disabled": "Uudelleenpisteytymismalli poistettu käytöstä",
@@ -747,6 +752,7 @@
"Reset All Models": "Palauta kaikki mallit",
"Reset Upload Directory": "Palauta latauspolku",
"Reset Vector Storage/Knowledge": "Tyhjennä vektoritallennukset/tietämys",
"Reset view": "",
"Response notifications cannot be activated as the website permissions have been denied. Please visit your browser settings to grant the necessary access.": "Vastausilmoituksia ei voida ottaa käyttöön, koska verkkosivuston käyttöoikeudet on evätty. Myönnä tarvittavat käyttöoikeudet selaimesi asetuksista.",
"Response splitting": "Vastauksen jakaminen",
"Result": "Tulos",
@@ -1004,6 +1010,7 @@
"variable to have them replaced with clipboard content.": "muuttuja korvataan leikepöydän sisällöllä.",
"Version": "Versio",
"Version {{selectedVersion}} of {{totalVersions}}": "Versio {{selectedVersion}} / {{totalVersions}}",
"View Replies": "",
"Visibility": "Näkyvyys",
"Voice": "Ääni",
"Voice Input": "Äänitulolaitteen käyttö",
+8 -1
View File
@@ -5,6 +5,7 @@
"(e.g. `sh webui.sh --api`)": "(par exemple `sh webui.sh --api`)",
"(latest)": "(dernier)",
"{{ models }}": "{{ modèles }}",
"{{COUNT}} Replies": "",
"{{user}}'s Chats": "Discussions de {{user}}",
"{{webUIName}} Backend Required": "Backend {{webUIName}} requis",
"*Prompt node ID(s) are required for image generation": "",
@@ -34,6 +35,7 @@
"Add Group": "",
"Add Memory": "Ajouter de la mémoire",
"Add Model": "Ajouter un modèle",
"Add Reaction": "",
"Add Tag": "",
"Add Tags": "Ajouter des balises",
"Add text content": "",
@@ -164,6 +166,7 @@
"Click on the user role button to change a user's role.": "Cliquez sur le bouton de rôle d'utilisateur pour modifier le rôle d'un utilisateur.",
"Clipboard write permission denied. Please check your browser settings to grant the necessary access.": "L'autorisation d'écriture du presse-papier a été refusée. Veuillez vérifier les paramètres de votre navigateur pour accorder l'accès nécessaire.",
"Clone": "Copie conforme",
"Clone Chat": "",
"Close": "Fermer",
"Code execution": "",
"Code formatted successfully": "Le code a été formaté avec succès",
@@ -534,6 +537,7 @@
"Language": "Langue",
"Last Active": "Dernière activité",
"Last Modified": "Dernière modification",
"Last reply": "",
"LDAP": "",
"LDAP server updated": "",
"Leaderboard": "",
@@ -608,7 +612,7 @@
"Name": "Nom",
"Name your knowledge base": "",
"New Chat": "Nouvelle conversation",
"New folder": "",
"New Folder": "",
"New Password": "Nouveau mot de passe",
"new-channel": "",
"No content found": "",
@@ -739,6 +743,7 @@
"Rename": "Renommer",
"Reorder Models": "",
"Repeat Last N": "Répéter les N derniers",
"Reply in Thread": "",
"Request Mode": "Mode de Requête",
"Reranking Model": "Modèle de ré-ranking",
"Reranking model disabled": "Modèle de ré-ranking désactivé",
@@ -747,6 +752,7 @@
"Reset All Models": "",
"Reset Upload Directory": "Répertoire de téléchargement réinitialisé",
"Reset Vector Storage/Knowledge": "",
"Reset view": "",
"Response notifications cannot be activated as the website permissions have been denied. Please visit your browser settings to grant the necessary access.": "Les notifications de réponse ne peuvent pas être activées car les autorisations du site web ont été refusées. Veuillez visiter les paramètres de votre navigateur pour accorder l'accès nécessaire.",
"Response splitting": "Fractionnement de la réponse",
"Result": "",
@@ -1004,6 +1010,7 @@
"variable to have them replaced with clipboard content.": "variable pour qu'elles soient remplacées par le contenu du presse-papiers.",
"Version": "Version améliorée",
"Version {{selectedVersion}} of {{totalVersions}}": "",
"View Replies": "",
"Visibility": "",
"Voice": "Voix",
"Voice Input": "",
+55 -48
View File
@@ -1,10 +1,11 @@
{
"-1 for no limit, or a positive integer for a specific limit": "",
"-1 for no limit, or a positive integer for a specific limit": "-1 pour aucune limite, ou un entier positif pour une limite spécifique",
"'s', 'm', 'h', 'd', 'w' or '-1' for no expiration.": " 's', 'm', 'h', 'd', 'w' ou '-1' pour une durée illimitée.",
"(e.g. `sh webui.sh --api --api-auth username_password`)": "(par ex. `sh webui.sh --api --api-auth username_password`)",
"(e.g. `sh webui.sh --api`)": "(par exemple `sh webui.sh --api`)",
"(latest)": "(dernière version)",
"{{ models }}": "{{ models }}",
"{{COUNT}} Replies": "",
"{{user}}'s Chats": "Conversations de {{user}}",
"{{webUIName}} Backend Required": "Backend {{webUIName}} requis",
"*Prompt node ID(s) are required for image generation": "*Les ID de noeud du prompt sont nécessaires pour la génération d’images",
@@ -34,6 +35,7 @@
"Add Group": "Ajouter un groupe",
"Add Memory": "Ajouter de la mémoire",
"Add Model": "Ajouter un modèle",
"Add Reaction": "",
"Add Tag": "Ajouter un tag",
"Add Tags": "Ajouter des tags",
"Add text content": "Ajouter du contenu textuel",
@@ -57,7 +59,7 @@
"Allow Temporary Chat": "Autoriser le chat éphémère",
"Allow User Location": "Autoriser l'emplacement de l'utilisateur",
"Allow Voice Interruption in Call": "Autoriser l'interruption vocale pendant un appel",
"Allowed Endpoints": "",
"Allowed Endpoints": "Points de terminaison autorisés",
"Already have an account?": "Avez-vous déjà un compte ?",
"Alternative to the top_p, and aims to ensure a balance of quality and variety. The parameter p represents the minimum probability for a token to be considered, relative to the probability of the most likely token. For example, with p=0.05 and the most likely token having a probability of 0.9, logits with a value less than 0.045 are filtered out. (Default: 0.0)": "Alternative au top_p, visant à assurer un équilibre entre qualité et variété. Le paramètre p représente la probabilité minimale pour qu'un token soit pris en compte, par rapport à la probabilité du token le plus probable. Par exemple, avec p=0.05 et le token le plus probable ayant une probabilité de 0.9, les logits ayant une valeur inférieure à 0.045 sont filtrés. (Par défaut : 0.0)",
"Amazing": "Incroyable",
@@ -68,7 +70,7 @@
"API Base URL": "URL de base de l'API",
"API Key": "Clé d'API",
"API Key created.": "Clé d'API générée.",
"API Key Endpoint Restrictions": "",
"API Key Endpoint Restrictions": "Restrictions des points de terminaison de la clé API",
"API keys": "Clés d'API",
"Application DN": "DN de l'application",
"Application DN Password": "Mot de passe DN de l'application",
@@ -78,8 +80,8 @@
"Archive All Chats": "Archiver toutes les conversations",
"Archived Chats": "Conversations archivées",
"archived-chat-export": "exportation de conversation archivée",
"Are you sure you want to delete this channel?": "",
"Are you sure you want to delete this message?": "",
"Are you sure you want to delete this channel?": "Êtes-vous sûr de vouloir supprimer ce canal ?",
"Are you sure you want to delete this message?": "Êtes-vous sûr de vouloir supprimer ce message ?",
"Are you sure you want to unarchive all archived chats?": "Êtes-vous sûr de vouloir désarchiver toutes les conversations archivées?",
"Are you sure?": "Êtes-vous certain ?",
"Arena Models": "Modèles d'arène",
@@ -94,8 +96,8 @@
"Authenticate": "Authentifier",
"Auto-Copy Response to Clipboard": "Copie automatique de la réponse vers le presse-papiers",
"Auto-playback response": "Lire automatiquement la réponse",
"Autocomplete Generation": "",
"Autocomplete Generation Input Max Length": "",
"Autocomplete Generation": "Génération des suggestions",
"Autocomplete Generation Input Max Length": "Longueur maximale pour la génération des suggestions",
"Automatic1111": "Automatic1111",
"AUTOMATIC1111 Api Auth String": "AUTOMATIC1111 Chaîne d'authentification de l'API",
"AUTOMATIC1111 Base URL": "URL de base AUTOMATIC1111",
@@ -112,7 +114,7 @@
"Batch Size (num_batch)": "Batch Size (num_batch)",
"before": "avant",
"Being lazy": "Être fainéant",
"Beta": "",
"Beta": "Bêta",
"Bing Search V7 Endpoint": "Point de terminaison Bing Search V7",
"Bing Search V7 Subscription Key": "Clé d'abonnement Bing Search V7",
"Brave Search API Key": "Clé API Brave Search",
@@ -123,13 +125,13 @@
"Camera": "Appareil photo",
"Cancel": "Annuler",
"Capabilities": "Capacités",
"Capture": "",
"Capture": "Prise de vue",
"Certificate Path": "Chemin du certificat",
"Change Password": "Changer le mot de passe",
"Channel Name": "",
"Channels": "",
"Channel Name": "Nom du canal",
"Channels": "Canaux",
"Character": "Caractère",
"Character limit for autocomplete generation input": "",
"Character limit for autocomplete generation input": "Limite de caractères pour la génération des suggestions",
"Chart new frontiers": "Tracer de nouvelles frontières",
"Chat": "Chat",
"Chat Background Image": "Image d'arrière-plan de la fenêtre de chat",
@@ -164,13 +166,14 @@
"Click on the user role button to change a user's role.": "Cliquez sur le bouton de rôle d'utilisateur pour modifier son rôle.",
"Clipboard write permission denied. Please check your browser settings to grant the necessary access.": "L'autorisation d'écriture du presse-papier a été refusée. Veuillez vérifier les paramètres de votre navigateur pour accorder l'accès nécessaire.",
"Clone": "Cloner",
"Clone Chat": "",
"Close": "Fermer",
"Code execution": "Exécution de code",
"Code formatted successfully": "Le code a été formaté avec succès",
"Collection": "Collection",
"Color": "Couleur",
"ComfyUI": "ComfyUI",
"ComfyUI API Key": "",
"ComfyUI API Key": "Clé API ComfyUI",
"ComfyUI Base URL": "URL de base ComfyUI",
"ComfyUI Base URL is required.": "L'URL de base ComfyUI est requise.",
"ComfyUI Workflow": "Flux de travaux de ComfyUI",
@@ -183,7 +186,7 @@
"Confirm": "Confirmer",
"Confirm Password": "Confirmer le mot de passe",
"Confirm your action": "Confirmer votre action",
"Confirm your new password": "",
"Confirm your new password": "Confirmer votre nouveau mot de passe",
"Connections": "Connexions",
"Contact Admin for WebUI Access": "Contacter l'administrateur pour obtenir l'accès à WebUI",
"Content": "Contenu",
@@ -210,7 +213,7 @@
"Create a model": "Créer un modèle",
"Create Account": "Créer un compte",
"Create Admin Account": "Créer un compte administrateur",
"Create Channel": "",
"Create Channel": "Créer un canal",
"Create Group": "Créer un groupe",
"Create Knowledge": "Créer une connaissance",
"Create new key": "Créer une nouvelle clé",
@@ -246,7 +249,7 @@
"Delete chat?": "Supprimer la conversation ?",
"Delete folder?": "Supprimer le dossier ?",
"Delete function?": "Supprimer la fonction ?",
"Delete Message": "",
"Delete Message": "Supprimer le message",
"Delete prompt?": "Supprimer le prompt ?",
"delete this link": "supprimer ce lien",
"Delete tool?": "Effacer l'outil ?",
@@ -299,7 +302,7 @@
"e.g. Tools for performing various operations": "par ex. Outils pour effectuer diverses opérations",
"Edit": "Modifier",
"Edit Arena Model": "Modifier le modèle d'arène",
"Edit Channel": "",
"Edit Channel": "Modifier le canal",
"Edit Connection": "Modifier la connexion",
"Edit Default Permissions": "Modifier les autorisations par défaut",
"Edit Memory": "Modifier la mémoire",
@@ -312,10 +315,10 @@
"Embedding Model": "Modèle d'embedding",
"Embedding Model Engine": "Moteur de modèle d'embedding",
"Embedding model set to \"{{embedding_model}}\"": "Modèle d'embedding défini sur « {{embedding_model}} »",
"Enable API Key": "",
"Enable autocomplete generation for chat messages": "",
"Enable API Key": "Activer la clé API",
"Enable autocomplete generation for chat messages": "Activer la génération des suggestions pour les messages",
"Enable Community Sharing": "Activer le partage communautaire",
"Enable Google Drive": "",
"Enable Google Drive": "Activer Google Drive",
"Enable Memory Locking (mlock) to prevent model data from being swapped out of RAM. This option locks the model's working set of pages into RAM, ensuring that they will not be swapped out to disk. This can help maintain performance by avoiding page faults and ensuring fast data access.": "Activer le verrouillage de la mémoire (mlock) pour empêcher les données du modèle d'être échangées de la RAM. Cette option verrouille l'ensemble de pages de travail du modèle en RAM, garantissant qu'elles ne seront pas échangées vers le disque. Cela peut aider à maintenir les performances en évitant les défauts de page et en assurant un accès rapide aux données.",
"Enable Memory Mapping (mmap) to load model data. This option allows the system to use disk storage as an extension of RAM by treating disk files as if they were in RAM. This can improve model performance by allowing for faster data access. However, it may not work correctly with all systems and can consume a significant amount of disk space.": "Activer le mappage de la mémoire (mmap) pour charger les données du modèle. Cette option permet au système d'utiliser le stockage disque comme une extension de la RAM en traitant les fichiers disque comme s'ils étaient en RAM. Cela peut améliorer les performances du modèle en permettant un accès plus rapide aux données. Cependant, cela peut ne pas fonctionner correctement avec tous les systèmes et peut consommer une quantité significative d'espace disque.",
"Enable Message Rating": "Activer l'évaluation des messages",
@@ -343,13 +346,13 @@
"Enter Google PSE Engine Id": "Entrez l'identifiant du moteur Google PSE",
"Enter Image Size (e.g. 512x512)": "Entrez la taille de l'image (par ex. 512x512)",
"Enter Jina API Key": "Entrez la clé API Jina",
"Enter Kagi Search API Key": "",
"Enter Kagi Search API Key": "Entrez la clé API Kagi Search",
"Enter language codes": "Entrez les codes de langue",
"Enter Model ID": "Entrez l'ID du modèle",
"Enter model tag (e.g. {{modelTag}})": "Entrez le tag du modèle (par ex. {{modelTag}})",
"Enter Mojeek Search API Key": "Entrez la clé API Mojeek",
"Enter Number of Steps (e.g. 50)": "Entrez le nombre d'étapes (par ex. 50)",
"Enter proxy URL (e.g. https://user:password@host:port)": "",
"Enter proxy URL (e.g. https://user:password@host:port)": "Entrez l'URL du proxy (par ex. https://use:password@host:port)",
"Enter Sampler (e.g. Euler a)": "Entrez le sampler (par ex. Euler a)",
"Enter Scheduler (e.g. Karras)": "Entrez le planificateur (par ex. Karras)",
"Enter Score": "Entrez votre score",
@@ -366,24 +369,24 @@
"Enter stop sequence": "Entrez la séquence d'arrêt",
"Enter system prompt": "Entrez le prompt système",
"Enter Tavily API Key": "Entrez la clé API Tavily",
"Enter the public URL of your WebUI. This URL will be used to generate links in the notifications.": "",
"Enter the public URL of your WebUI. This URL will be used to generate links in the notifications.": "Entrez l'URL publique de votre WebUI. Cette URL sera utilisée pour générer des liens dans les notifications.",
"Enter Tika Server URL": "Entrez l'URL du serveur Tika",
"Enter Top K": "Entrez les Top K",
"Enter URL (e.g. http://127.0.0.1:7860/)": "Entrez l'URL (par ex. {http://127.0.0.1:7860/})",
"Enter URL (e.g. http://localhost:11434)": "Entrez l'URL (par ex. http://localhost:11434)",
"Enter your current password": "",
"Enter your current password": "Entrez votre mot de passe actuel",
"Enter Your Email": "Entrez votre adresse e-mail",
"Enter Your Full Name": "Entrez votre nom complet",
"Enter your message": "Entrez votre message",
"Enter your new password": "",
"Enter your new password": "Entrez votre nouveau mot de passe",
"Enter Your Password": "Entrez votre mot de passe",
"Enter Your Role": "Entrez votre rôle",
"Enter Your Username": "Entrez votre nom d'utilisateur",
"Enter your webhook URL": "",
"Enter your webhook URL": "Entrez l'URL de votre webhook",
"Error": "Erreur",
"ERROR": "ERREUR",
"Error accessing Google Drive: {{error}}": "",
"Error uploading file: {{error}}": "",
"Error accessing Google Drive: {{error}}": "Erreur d'accès à Google Drive : {{error}}",
"Error uploading file: {{error}}": "Erreur de téléversement du fichier : {{error}}",
"Evaluations": "Évaluations",
"Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Exemple: (&(objectClass=inetOrgPerson)(uid=%s))",
"Example: ALL": "Exemple: TOUS",
@@ -422,7 +425,7 @@
"File not found.": "Fichier introuvable.",
"File removed successfully.": "Fichier supprimé avec succès.",
"File size should not exceed {{maxSize}} MB.": "La taille du fichier ne doit pas dépasser {{maxSize}} Mo.",
"File uploaded successfully": "",
"File uploaded successfully": "Fichier téléversé avec succès",
"Files": "Fichiers",
"Filter is now globally disabled": "Le filtre est maintenant désactivé globalement",
"Filter is now globally enabled": "Le filtre est désormais activé globalement",
@@ -460,7 +463,7 @@
"Get started with {{WEBUI_NAME}}": "Commencez avec {{WEBUI_NAME}}",
"Global": "Mondial",
"Good Response": "Bonne réponse",
"Google Drive": "",
"Google Drive": "Google Drive",
"Google PSE API Key": "Clé API Google PSE",
"Google PSE Engine Id": "ID du moteur de recherche PSE de Google",
"Group created successfully": "Groupe créé avec succès",
@@ -485,10 +488,10 @@
"I acknowledge that I have read and I understand the implications of my action. I am aware of the risks associated with executing arbitrary code and I have verified the trustworthiness of the source.": "Je reconnais avoir lu et compris les implications de mes actions. Je suis conscient des risques associés à l'exécution d'un code arbitraire et j'ai vérifié la fiabilité de la source.",
"ID": "ID",
"Ignite curiosity": "Éveiller la curiosité",
"Image Compression": "",
"Image Compression": "Compression d'image",
"Image Generation (Experimental)": "Génération d'images (expérimental)",
"Image Generation Engine": "Moteur de génération d'images",
"Image Max Compression Size": "",
"Image Max Compression Size": "Taille maximale de compression d'image",
"Image Settings": "Paramètres de génération d'images",
"Images": "Images",
"Import Chats": "Importer les conversations",
@@ -509,7 +512,7 @@
"Interface": "Interface utilisateur",
"Invalid file format.": "Format de fichier non valide.",
"Invalid Tag": "Tag non valide",
"is typing...": "",
"is typing...": "est en train d'écrire...",
"January": "Janvier",
"Jina API Key": "Clé API Jina",
"join our Discord for help.": "Rejoignez notre Discord pour obtenir de l'aide.",
@@ -519,7 +522,7 @@
"June": "Juin",
"JWT Expiration": "Expiration du token JWT",
"JWT Token": "Token JWT",
"Kagi Search API Key": "",
"Kagi Search API Key": "Clé API Kagi Search",
"Keep Alive": "Temps de maintien connecté",
"Key": "Clé",
"Keyboard shortcuts": "Raccourcis clavier",
@@ -534,6 +537,7 @@
"Language": "Langue",
"Last Active": "Dernière activité",
"Last Modified": "Dernière modification",
"Last reply": "",
"LDAP": "LDAP",
"LDAP server updated": "Serveur LDAP mis à jour",
"Leaderboard": "Classement",
@@ -608,9 +612,9 @@
"Name": "Nom d'utilisateur",
"Name your knowledge base": "Nommez votre base de connaissances",
"New Chat": "Nouvelle conversation",
"New folder": "",
"New Folder": "",
"New Password": "Nouveau mot de passe",
"new-channel": "",
"new-channel": "nouveau-canal",
"No content found": "Aucun contenu trouvé",
"No content to speak": "Rien à signaler",
"No distance available": "Aucune distance disponible",
@@ -633,8 +637,8 @@
"Not helpful": "Pas utile",
"Note: If you set a minimum score, the search will only return documents with a score greater than or equal to the minimum score.": "Note : Si vous définissez un score minimum, seuls les documents ayant un score supérieur ou égal à ce score minimum seront retournés par la recherche.",
"Notes": "Notes",
"Notification Sound": "",
"Notification Webhook": "",
"Notification Sound": "Son de notification",
"Notification Webhook": "Webhook de notification",
"Notifications": "Notifications",
"November": "Novembre",
"num_gpu (Ollama)": "num_gpu (Ollama)",
@@ -700,7 +704,7 @@
"Please carefully review the following warnings:": "Veuillez lire attentivement les avertissements suivants :",
"Please enter a prompt": "Veuillez saisir un prompt",
"Please fill in all fields.": "Veuillez remplir tous les champs.",
"Please select a model first.": "",
"Please select a model first.": "Veuillez d'abord sélectionner un modèle.",
"Please select a reason": "Veuillez sélectionner une raison",
"Port": "Port",
"Positive attitude": "Attitude positive",
@@ -716,7 +720,7 @@
"Prompt updated successfully": "Prompt mis à jour avec succès",
"Prompts": "Prompts",
"Prompts Access": "Accès aux prompts",
"Proxy URL": "",
"Proxy URL": "URL du proxy",
"Pull \"{{searchValue}}\" from Ollama.com": "Récupérer « {{searchValue}} » depuis Ollama.com",
"Pull a model from Ollama.com": "Télécharger un modèle depuis Ollama.com",
"Query Generation Prompt": "Prompt de génération de requête",
@@ -739,6 +743,7 @@
"Rename": "Renommer",
"Reorder Models": "Réorganiser les modèles",
"Repeat Last N": "Répéter les N derniers",
"Reply in Thread": "",
"Request Mode": "Mode de requête",
"Reranking Model": "Modèle de ré-ranking",
"Reranking model disabled": "Modèle de ré-ranking désactivé",
@@ -747,10 +752,11 @@
"Reset All Models": "Réinitialiser tous les modèles",
"Reset Upload Directory": "Réinitialiser le répertoire de téléchargement",
"Reset Vector Storage/Knowledge": "Réinitialiser le stockage vectoriel/connaissances",
"Reset view": "Réinitialiser la vue",
"Response notifications cannot be activated as the website permissions have been denied. Please visit your browser settings to grant the necessary access.": "Les notifications de réponse ne peuvent pas être activées car les autorisations du site web ont été refusées. Veuillez vérifier les paramètres de votre navigateur pour accorder l'accès nécessaire.",
"Response splitting": "Fractionnement de la réponse",
"Result": "Résultat",
"Retrieval Query Generation": "",
"Retrieval Query Generation": "Génération de requête de RAG",
"Rich Text Input for Chat": "Saisie de texte enrichi pour le chat",
"RK": "Rang",
"Role": "Rôle",
@@ -784,7 +790,7 @@
"Search Tools": "Rechercher des outils",
"SearchApi API Key": "Clé API SearchApi",
"SearchApi Engine": "Moteur de recherche SearchApi",
"Searched {{count}} sites": "",
"Searched {{count}} sites": "{{count}} sites recherchés",
"Searching \"{{searchQuery}}\"": "Recherche de « {{searchQuery}} »",
"Searching Knowledge for \"{{searchQuery}}\"": "Recherche des connaissances pour « {{searchQuery}} »",
"Searxng Query URL": "URL de recherche Searxng",
@@ -852,7 +858,7 @@
"Sign up": "Inscrivez-vous",
"Sign up to {{WEBUI_NAME}}": "Inscrivez-vous à {{WEBUI_NAME}}",
"Signing in to {{WEBUI_NAME}}": "Connexion à {{WEBUI_NAME}}",
"sk-1234": "",
"sk-1234": "sk-1234",
"Source": "Source",
"Speech Playback Speed": "Vitesse de lecture de la parole",
"Speech recognition error: {{error}}": "Erreur de reconnaissance vocale\u00a0: {{error}}",
@@ -872,7 +878,7 @@
"System": "Système",
"System Instructions": "Instructions système",
"System Prompt": "Prompt système",
"Tags Generation": "",
"Tags Generation": "Génération de tags",
"Tags Generation Prompt": "Prompt de génération de tags",
"Tail free sampling is used to reduce the impact of less probable tokens from the output. A higher value (e.g., 2.0) will reduce the impact more, while a value of 1.0 disables this setting. (default: 1)": "L'échantillonnage sans queue est utilisé pour réduire l'impact des tokens moins probables dans la sortie. Une valeur plus élevée (par exemple 2.0) réduira davantage l'impact, tandis qu'une valeur de 1.0 désactive ce paramètre. (par défaut : 1)",
"Tap to interrupt": "Appuyez pour interrompre",
@@ -925,7 +931,7 @@
"To access the GGUF models available for downloading,": "Pour accéder aux modèles GGUF disponibles,",
"To access the WebUI, please reach out to the administrator. Admins can manage user statuses from the Admin Panel.": "Pour accéder à l'interface Web, veuillez contacter l'administrateur. Les administrateurs peuvent gérer les statuts des utilisateurs depuis le panneau d'administration.",
"To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "Pour attacher une base de connaissances ici, ajoutez-les d'abord à l'espace de travail « Connaissances ».",
"To learn more about available endpoints, visit our documentation.": "",
"To learn more about available endpoints, visit our documentation.": "Pour en savoir plus sur les points de terminaison disponibles, consultez notre documentation.",
"To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "Pour protéger votre confidentialité, seules les notes, les identifiants de modèle, les tags et les métadonnées de vos commentaires sont partagés. Vos journaux de discussion restent privés et ne sont pas inclus.",
"To select actions here, add them to the \"Functions\" workspace first.": "Pour sélectionner des actions ici, ajoutez-les d'abord à l'espace de travail « Fonctions ».",
"To select filters here, add them to the \"Functions\" workspace first.": "Pour sélectionner des filtres ici, ajoutez-les d'abord à l'espace de travail « Fonctions ». ",
@@ -958,7 +964,7 @@
"TTS Voice": "Voix de Text-to-Speech",
"Type": "Type",
"Type Hugging Face Resolve (Download) URL": "Entrez l'URL de Téléchargement Hugging Face Resolve",
"Uh-oh! There was an issue with the response.": "",
"Uh-oh! There was an issue with the response.": "Oh! Un problème est survenu avec la réponse.",
"UI": "UI",
"Unarchive All": "Désarchiver tout",
"Unarchive All Archived Chats": "Désarchiver toutes les conversations archivées",
@@ -1004,6 +1010,7 @@
"variable to have them replaced with clipboard content.": "variable pour qu'elles soient remplacées par le contenu du presse-papiers.",
"Version": "version:",
"Version {{selectedVersion}} of {{totalVersions}}": "Version {{selectedVersion}} de {{totalVersions}}",
"View Replies": "",
"Visibility": "Visibilité",
"Voice": "Voix",
"Voice Input": "Saisie vocale",
@@ -1016,10 +1023,10 @@
"Web Loader Settings": "Paramètres du Web Loader",
"Web Search": "Recherche Web",
"Web Search Engine": "Moteur de recherche Web",
"Web Search Query Generation": "",
"Web Search Query Generation": "Génération de requête de recherche Web",
"Webhook URL": "URL du webhook",
"WebUI Settings": "Paramètres de WebUI",
"WebUI URL": "",
"WebUI URL": "URL de WebUI",
"WebUI will make requests to \"{{url}}/api/chat\"": "WebUI fera des requêtes à \"{{url}}/api/chat\"",
"WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI fera des requêtes à \"{{url}}/chat/completions\"",
"What are you trying to achieve?": "Que cherchez-vous à accomplir ?",
+8 -1
View File
@@ -5,6 +5,7 @@
"(e.g. `sh webui.sh --api`)": "(למשל `sh webui.sh --api`)",
"(latest)": "(האחרון)",
"{{ models }}": "{{ דגמים }}",
"{{COUNT}} Replies": "",
"{{user}}'s Chats": "צ'אטים של {{user}}",
"{{webUIName}} Backend Required": "נדרש Backend של {{webUIName}}",
"*Prompt node ID(s) are required for image generation": "",
@@ -34,6 +35,7 @@
"Add Group": "",
"Add Memory": "הוסף זיכרון",
"Add Model": "הוסף מודל",
"Add Reaction": "",
"Add Tag": "",
"Add Tags": "הוסף תגים",
"Add text content": "",
@@ -164,6 +166,7 @@
"Click on the user role button to change a user's role.": "לחץ על כפתור תפקיד המשתמש כדי לשנות את תפקיד המשתמש.",
"Clipboard write permission denied. Please check your browser settings to grant the necessary access.": "",
"Clone": "שיבוט",
"Clone Chat": "",
"Close": "סגור",
"Code execution": "",
"Code formatted successfully": "",
@@ -534,6 +537,7 @@
"Language": "שפה",
"Last Active": "פעיל לאחרונה",
"Last Modified": "",
"Last reply": "",
"LDAP": "",
"LDAP server updated": "",
"Leaderboard": "",
@@ -608,7 +612,7 @@
"Name": "שם",
"Name your knowledge base": "",
"New Chat": "צ'אט חדש",
"New folder": "",
"New Folder": "",
"New Password": "סיסמה חדשה",
"new-channel": "",
"No content found": "",
@@ -739,6 +743,7 @@
"Rename": "שנה שם",
"Reorder Models": "",
"Repeat Last N": "חזור על ה-N האחרונים",
"Reply in Thread": "",
"Request Mode": "מצב בקשה",
"Reranking Model": "מודל דירוג מחדש",
"Reranking model disabled": "מודל דירוג מחדש מושבת",
@@ -747,6 +752,7 @@
"Reset All Models": "",
"Reset Upload Directory": "",
"Reset Vector Storage/Knowledge": "",
"Reset view": "",
"Response notifications cannot be activated as the website permissions have been denied. Please visit your browser settings to grant the necessary access.": "",
"Response splitting": "",
"Result": "",
@@ -1004,6 +1010,7 @@
"variable to have them replaced with clipboard content.": "משתנה להחליפו ב- clipboard תוכן.",
"Version": "גרסה",
"Version {{selectedVersion}} of {{totalVersions}}": "",
"View Replies": "",
"Visibility": "",
"Voice": "",
"Voice Input": "",
+8 -1
View File
@@ -5,6 +5,7 @@
"(e.g. `sh webui.sh --api`)": "(e.g. `sh webui.sh --api`)",
"(latest)": "(latest)",
"{{ models }}": "{{ मॉडल }}",
"{{COUNT}} Replies": "",
"{{user}}'s Chats": "{{user}} की चैट",
"{{webUIName}} Backend Required": "{{webUIName}} बैकएंड आवश्यक",
"*Prompt node ID(s) are required for image generation": "",
@@ -34,6 +35,7 @@
"Add Group": "",
"Add Memory": "मेमोरी जोड़ें",
"Add Model": "मॉडल जोड़ें",
"Add Reaction": "",
"Add Tag": "",
"Add Tags": "टैगों को जोड़ें",
"Add text content": "",
@@ -164,6 +166,7 @@
"Click on the user role button to change a user's role.": "उपयोगकर्ता की भूमिका बदलने के लिए उपयोगकर्ता भूमिका बटन पर क्लिक करें।",
"Clipboard write permission denied. Please check your browser settings to grant the necessary access.": "",
"Clone": "क्लोन",
"Clone Chat": "",
"Close": "बंद करना",
"Code execution": "",
"Code formatted successfully": "",
@@ -534,6 +537,7 @@
"Language": "भाषा",
"Last Active": "पिछली बार सक्रिय",
"Last Modified": "",
"Last reply": "",
"LDAP": "",
"LDAP server updated": "",
"Leaderboard": "",
@@ -608,7 +612,7 @@
"Name": "नाम",
"Name your knowledge base": "",
"New Chat": "नई चैट",
"New folder": "",
"New Folder": "",
"New Password": "नया पासवर्ड",
"new-channel": "",
"No content found": "",
@@ -739,6 +743,7 @@
"Rename": "नाम बदलें",
"Reorder Models": "",
"Repeat Last N": "अंतिम N दोहराएँ",
"Reply in Thread": "",
"Request Mode": "अनुरोध मोड",
"Reranking Model": "रीरैकिंग मोड",
"Reranking model disabled": "पुनर्रैंकिंग मॉडल अक्षम किया गया",
@@ -747,6 +752,7 @@
"Reset All Models": "",
"Reset Upload Directory": "",
"Reset Vector Storage/Knowledge": "",
"Reset view": "",
"Response notifications cannot be activated as the website permissions have been denied. Please visit your browser settings to grant the necessary access.": "",
"Response splitting": "",
"Result": "",
@@ -1004,6 +1010,7 @@
"variable to have them replaced with clipboard content.": "उन्हें क्लिपबोर्ड सामग्री से बदलने के लिए वेरिएबल।",
"Version": "संस्करण",
"Version {{selectedVersion}} of {{totalVersions}}": "",
"View Replies": "",
"Visibility": "",
"Voice": "",
"Voice Input": "",
+8 -1
View File
@@ -5,6 +5,7 @@
"(e.g. `sh webui.sh --api`)": "(npr. `sh webui.sh --api`)",
"(latest)": "(najnovije)",
"{{ models }}": "{{ modeli }}",
"{{COUNT}} Replies": "",
"{{user}}'s Chats": "Razgovori korisnika {{user}}",
"{{webUIName}} Backend Required": "{{webUIName}} Backend je potreban",
"*Prompt node ID(s) are required for image generation": "",
@@ -34,6 +35,7 @@
"Add Group": "",
"Add Memory": "Dodaj memoriju",
"Add Model": "Dodaj model",
"Add Reaction": "",
"Add Tag": "",
"Add Tags": "Dodaj oznake",
"Add text content": "",
@@ -164,6 +166,7 @@
"Click on the user role button to change a user's role.": "Kliknite na gumb uloge korisnika za promjenu uloge korisnika.",
"Clipboard write permission denied. Please check your browser settings to grant the necessary access.": "",
"Clone": "Kloniraj",
"Clone Chat": "",
"Close": "Zatvori",
"Code execution": "",
"Code formatted successfully": "",
@@ -534,6 +537,7 @@
"Language": "Jezik",
"Last Active": "Zadnja aktivnost",
"Last Modified": "",
"Last reply": "",
"LDAP": "",
"LDAP server updated": "",
"Leaderboard": "",
@@ -608,7 +612,7 @@
"Name": "Ime",
"Name your knowledge base": "",
"New Chat": "Novi razgovor",
"New folder": "",
"New Folder": "",
"New Password": "Nova lozinka",
"new-channel": "",
"No content found": "",
@@ -739,6 +743,7 @@
"Rename": "Preimenuj",
"Reorder Models": "",
"Repeat Last N": "Ponovi zadnjih N",
"Reply in Thread": "",
"Request Mode": "Način zahtjeva",
"Reranking Model": "Model za ponovno rangiranje",
"Reranking model disabled": "Model za ponovno rangiranje onemogućen",
@@ -747,6 +752,7 @@
"Reset All Models": "",
"Reset Upload Directory": "Poništi upload direktorij",
"Reset Vector Storage/Knowledge": "",
"Reset view": "",
"Response notifications cannot be activated as the website permissions have been denied. Please visit your browser settings to grant the necessary access.": "",
"Response splitting": "",
"Result": "",
@@ -1004,6 +1010,7 @@
"variable to have them replaced with clipboard content.": "varijabla za zamjenu sadržajem međuspremnika.",
"Version": "Verzija",
"Version {{selectedVersion}} of {{totalVersions}}": "",
"View Replies": "",
"Visibility": "",
"Voice": "",
"Voice Input": "",
+8 -1
View File
@@ -5,6 +5,7 @@
"(e.g. `sh webui.sh --api`)": "(pl. `sh webui.sh --api`)",
"(latest)": "(legújabb)",
"{{ models }}": "{{ modellek }}",
"{{COUNT}} Replies": "",
"{{user}}'s Chats": "{{user}} beszélgetései",
"{{webUIName}} Backend Required": "{{webUIName}} Backend szükséges",
"*Prompt node ID(s) are required for image generation": "*Prompt node ID(k) szükségesek a képgeneráláshoz",
@@ -34,6 +35,7 @@
"Add Group": "",
"Add Memory": "Memória hozzáadása",
"Add Model": "Modell hozzáadása",
"Add Reaction": "",
"Add Tag": "Címke hozzáadása",
"Add Tags": "Címkék hozzáadása",
"Add text content": "Szöveges tartalom hozzáadása",
@@ -164,6 +166,7 @@
"Click on the user role button to change a user's role.": "Kattints a felhasználói szerep gombra a felhasználó szerepének módosításához.",
"Clipboard write permission denied. Please check your browser settings to grant the necessary access.": "Vágólap írási engedély megtagadva. Kérjük, ellenőrizd a böngésző beállításait a szükséges hozzáférés megadásához.",
"Clone": "Klónozás",
"Clone Chat": "",
"Close": "Bezárás",
"Code execution": "Kód végrehajtás",
"Code formatted successfully": "Kód sikeresen formázva",
@@ -534,6 +537,7 @@
"Language": "Nyelv",
"Last Active": "Utoljára aktív",
"Last Modified": "Utoljára módosítva",
"Last reply": "",
"LDAP": "",
"LDAP server updated": "",
"Leaderboard": "Ranglista",
@@ -608,7 +612,7 @@
"Name": "Név",
"Name your knowledge base": "",
"New Chat": "Új beszélgetés",
"New folder": "",
"New Folder": "",
"New Password": "Új jelszó",
"new-channel": "",
"No content found": "Nem található tartalom",
@@ -739,6 +743,7 @@
"Rename": "Átnevezés",
"Reorder Models": "",
"Repeat Last N": "Utolsó N ismétlése",
"Reply in Thread": "",
"Request Mode": "Kérési mód",
"Reranking Model": "Újrarangsoroló modell",
"Reranking model disabled": "Újrarangsoroló modell letiltva",
@@ -747,6 +752,7 @@
"Reset All Models": "",
"Reset Upload Directory": "Feltöltési könyvtár visszaállítása",
"Reset Vector Storage/Knowledge": "Vektor tárhely/tudásbázis visszaállítása",
"Reset view": "",
"Response notifications cannot be activated as the website permissions have been denied. Please visit your browser settings to grant the necessary access.": "A válasz értesítések nem aktiválhatók, mert a weboldal engedélyei meg lettek tagadva. Kérjük, látogasson el a böngésző beállításaihoz a szükséges hozzáférés megadásához.",
"Response splitting": "Válasz felosztás",
"Result": "Eredmény",
@@ -1004,6 +1010,7 @@
"variable to have them replaced with clipboard content.": "változó, hogy a vágólap tartalmával helyettesítse őket.",
"Version": "Verzió",
"Version {{selectedVersion}} of {{totalVersions}}": "{{selectedVersion}}. verzió a {{totalVersions}}-ból",
"View Replies": "",
"Visibility": "",
"Voice": "Hang",
"Voice Input": "Hangbevitel",
+8 -1
View File
@@ -5,6 +5,7 @@
"(e.g. `sh webui.sh --api`)": "(contoh: `sh webui.sh --api`)",
"(latest)": "(terbaru)",
"{{ models }}": "{{ models }}",
"{{COUNT}} Replies": "",
"{{user}}'s Chats": "Obrolan {{user}}",
"{{webUIName}} Backend Required": "{{webUIName}} Diperlukan Backend",
"*Prompt node ID(s) are required for image generation": "",
@@ -34,6 +35,7 @@
"Add Group": "",
"Add Memory": "Menambahkan Memori",
"Add Model": "Tambahkan Model",
"Add Reaction": "",
"Add Tag": "",
"Add Tags": "Tambahkan Tag",
"Add text content": "",
@@ -164,6 +166,7 @@
"Click on the user role button to change a user's role.": "Klik tombol peran pengguna untuk mengubah peran pengguna.",
"Clipboard write permission denied. Please check your browser settings to grant the necessary access.": "Izin menulis papan klip ditolak. Periksa pengaturan peramban Anda untuk memberikan akses yang diperlukan.",
"Clone": "Kloning",
"Clone Chat": "",
"Close": "Tutup",
"Code execution": "",
"Code formatted successfully": "Kode berhasil diformat",
@@ -534,6 +537,7 @@
"Language": "Bahasa",
"Last Active": "Terakhir Aktif",
"Last Modified": "Terakhir Dimodifikasi",
"Last reply": "",
"LDAP": "",
"LDAP server updated": "",
"Leaderboard": "",
@@ -608,7 +612,7 @@
"Name": "Nama",
"Name your knowledge base": "",
"New Chat": "Obrolan Baru",
"New folder": "",
"New Folder": "",
"New Password": "Kata Sandi Baru",
"new-channel": "",
"No content found": "",
@@ -739,6 +743,7 @@
"Rename": "Ganti nama",
"Reorder Models": "",
"Repeat Last N": "Ulangi N Terakhir",
"Reply in Thread": "",
"Request Mode": "Mode Permintaan",
"Reranking Model": "Model Pemeringkatan Ulang",
"Reranking model disabled": "Model pemeringkatan ulang dinonaktifkan",
@@ -747,6 +752,7 @@
"Reset All Models": "",
"Reset Upload Directory": "Setel Ulang Direktori Unggahan",
"Reset Vector Storage/Knowledge": "",
"Reset view": "",
"Response notifications cannot be activated as the website permissions have been denied. Please visit your browser settings to grant the necessary access.": "Notifikasi respons tidak dapat diaktifkan karena izin situs web telah ditolak. Silakan kunjungi pengaturan browser Anda untuk memberikan akses yang diperlukan.",
"Response splitting": "",
"Result": "",
@@ -1004,6 +1010,7 @@
"variable to have them replaced with clipboard content.": "variabel untuk diganti dengan konten papan klip.",
"Version": "Versi",
"Version {{selectedVersion}} of {{totalVersions}}": "",
"View Replies": "",
"Visibility": "",
"Voice": "Suara",
"Voice Input": "",
+8 -1
View File
@@ -5,6 +5,7 @@
"(e.g. `sh webui.sh --api`)": "(m.sh. `sh webui.sh --api`)",
"(latest)": "(is déanaí)",
"{{ models }}": "{{models}}",
"{{COUNT}} Replies": "",
"{{user}}'s Chats": "Comhráite {{user}}",
"{{webUIName}} Backend Required": "{{webUIName}} Ceoldeireadh Riachtanach",
"*Prompt node ID(s) are required for image generation": "* Tá ID nód pras ag teastáil chun íomhá a ghiniúint",
@@ -34,6 +35,7 @@
"Add Group": "Cuir Grúpa leis",
"Add Memory": "Cuir Cuimhne",
"Add Model": "Cuir múnla leis",
"Add Reaction": "",
"Add Tag": "Cuir Clib leis",
"Add Tags": "Cuir Clibeanna leis",
"Add text content": "Cuir ábhar téacs leis",
@@ -164,6 +166,7 @@
"Click on the user role button to change a user's role.": "Cliceáil ar an gcnaipe ról úsáideora chun ról úsáideora a athrú.",
"Clipboard write permission denied. Please check your browser settings to grant the necessary access.": "Diúltaíodh cead scríofa an ghearrthaisce. Seiceáil socruithe do bhrabhsálaí chun an rochtain riachtanach a dheonú.",
"Clone": "Clón",
"Clone Chat": "",
"Close": "Dún",
"Code execution": "Cód a fhorghníomhú",
"Code formatted successfully": "Cód formáidithe go rathúil",
@@ -534,6 +537,7 @@
"Language": "Teanga",
"Last Active": "Gníomhach Deiridh",
"Last Modified": "Athraithe Deiridh",
"Last reply": "",
"LDAP": "LDAP",
"LDAP server updated": "Nuashonraíodh freastalaí LDAP",
"Leaderboard": "An Clár Ceannairí",
@@ -608,7 +612,7 @@
"Name": "Ainm",
"Name your knowledge base": "Cuir ainm ar do bhunachar eolais",
"New Chat": "Comhrá Nua",
"New folder": "",
"New Folder": "",
"New Password": "Pasfhocal Nua",
"new-channel": "",
"No content found": "Níor aimsíodh aon ábhar",
@@ -739,6 +743,7 @@
"Rename": "Athainmnigh",
"Reorder Models": "",
"Repeat Last N": "Déan an N deireanach arís",
"Reply in Thread": "",
"Request Mode": "Mód Iarratais",
"Reranking Model": "Múnla Athrangú",
"Reranking model disabled": "Samhail athrangú faoi mhíchumas",
@@ -747,6 +752,7 @@
"Reset All Models": "",
"Reset Upload Directory": "Athshocraigh Eolaire Uas",
"Reset Vector Storage/Knowledge": "Athshocraigh Stóráil/Eolas Veicteoir",
"Reset view": "",
"Response notifications cannot be activated as the website permissions have been denied. Please visit your browser settings to grant the necessary access.": "Ní féidir fógraí freagartha a ghníomhachtú toisc gur diúltaíodh ceadanna an tsuímh Ghréasáin. Tabhair cuairt ar do shocruithe brabhsálaí chun an rochtain riachtanach a dheonú.",
"Response splitting": "Scoilt freagartha",
"Result": "Toradh",
@@ -1004,6 +1010,7 @@
"variable to have them replaced with clipboard content.": "athróg chun ábhar gearrthaisce a chur in ionad iad.",
"Version": "Leagan",
"Version {{selectedVersion}} of {{totalVersions}}": "Leagan {{selectedVersion}} de {{totalVersions}}",
"View Replies": "",
"Visibility": "Infheictheacht",
"Voice": "Guth",
"Voice Input": "Ionchur Gutha",
+8 -1
View File
@@ -5,6 +5,7 @@
"(e.g. `sh webui.sh --api`)": "(p.e. `sh webui.sh --api`)",
"(latest)": "(ultima)",
"{{ models }}": "{{ modelli }}",
"{{COUNT}} Replies": "",
"{{user}}'s Chats": "{{user}} Chat",
"{{webUIName}} Backend Required": "{{webUIName}} Backend richiesto",
"*Prompt node ID(s) are required for image generation": "",
@@ -34,6 +35,7 @@
"Add Group": "",
"Add Memory": "Aggiungi memoria",
"Add Model": "Aggiungi modello",
"Add Reaction": "",
"Add Tag": "",
"Add Tags": "Aggiungi tag",
"Add text content": "",
@@ -164,6 +166,7 @@
"Click on the user role button to change a user's role.": "Clicca sul pulsante del ruolo utente per modificare il ruolo di un utente.",
"Clipboard write permission denied. Please check your browser settings to grant the necessary access.": "",
"Clone": "Clone",
"Clone Chat": "",
"Close": "Chiudi",
"Code execution": "",
"Code formatted successfully": "",
@@ -534,6 +537,7 @@
"Language": "Lingua",
"Last Active": "Ultima attività",
"Last Modified": "",
"Last reply": "",
"LDAP": "",
"LDAP server updated": "",
"Leaderboard": "",
@@ -608,7 +612,7 @@
"Name": "Nome",
"Name your knowledge base": "",
"New Chat": "Nuova chat",
"New folder": "",
"New Folder": "",
"New Password": "Nuova password",
"new-channel": "",
"No content found": "",
@@ -739,6 +743,7 @@
"Rename": "Rinomina",
"Reorder Models": "",
"Repeat Last N": "Ripeti ultimi N",
"Reply in Thread": "",
"Request Mode": "Modalità richiesta",
"Reranking Model": "Modello di riclassificazione",
"Reranking model disabled": "Modello di riclassificazione disabilitato",
@@ -747,6 +752,7 @@
"Reset All Models": "",
"Reset Upload Directory": "",
"Reset Vector Storage/Knowledge": "",
"Reset view": "",
"Response notifications cannot be activated as the website permissions have been denied. Please visit your browser settings to grant the necessary access.": "",
"Response splitting": "",
"Result": "",
@@ -1004,6 +1010,7 @@
"variable to have them replaced with clipboard content.": "variabile per farli sostituire con il contenuto degli appunti.",
"Version": "Versione",
"Version {{selectedVersion}} of {{totalVersions}}": "",
"View Replies": "",
"Visibility": "",
"Voice": "",
"Voice Input": "",
+25 -18
View File
@@ -5,6 +5,7 @@
"(e.g. `sh webui.sh --api`)": "(例: `sh webui.sh --api`)",
"(latest)": "(最新)",
"{{ models }}": "{{ モデル }}",
"{{COUNT}} Replies": "",
"{{user}}'s Chats": "{{user}} のチャット",
"{{webUIName}} Backend Required": "{{webUIName}} バックエンドが必要です",
"*Prompt node ID(s) are required for image generation": "",
@@ -34,6 +35,7 @@
"Add Group": "",
"Add Memory": "メモリを追加",
"Add Model": "モデルを追加",
"Add Reaction": "",
"Add Tag": "タグを追加",
"Add Tags": "タグを追加",
"Add text content": "コンテンツを追加",
@@ -138,7 +140,7 @@
"Chat direction": "チャットの方向",
"Chat Overview": "チャット概要",
"Chat Permissions": "",
"Chat Tags Auto-Generation": "",
"Chat Tags Auto-Generation": "チャットタグの自動生成",
"Chats": "チャット",
"Check Again": "再確認",
"Check for updates": "アップデートを確認",
@@ -164,6 +166,7 @@
"Click on the user role button to change a user's role.": "ユーザーの役割を変更するには、ユーザー役割ボタンをクリックしてください。",
"Clipboard write permission denied. Please check your browser settings to grant the necessary access.": "クリップボードへの書き込み許可がありません。ブラウザ設定を確認し許可してください。",
"Clone": "クローン",
"Clone Chat": "",
"Close": "閉じる",
"Code execution": "",
"Code formatted successfully": "コードフォーマットに成功しました",
@@ -181,7 +184,7 @@
"Configure": "",
"Configure Models": "",
"Confirm": "確認",
"Confirm Password": "パスワードを確認",
"Confirm Password": "パスワードの確認",
"Confirm your action": "あなたのアクションの確認",
"Confirm your new password": "",
"Connections": "接続",
@@ -212,7 +215,7 @@
"Create Admin Account": "",
"Create Channel": "",
"Create Group": "",
"Create Knowledge": "知識データ作成",
"Create Knowledge": "ナレッジベース作成",
"Create new key": "新しいキーを作成",
"Create new secret key": "新しいシークレットキーを作成",
"Created at": "作成日時",
@@ -315,7 +318,7 @@
"Enable API Key": "",
"Enable autocomplete generation for chat messages": "",
"Enable Community Sharing": "コミュニティ共有を有効にする",
"Enable Google Drive": "",
"Enable Google Drive": "Google Driveの有効化",
"Enable Memory Locking (mlock) to prevent model data from being swapped out of RAM. This option locks the model's working set of pages into RAM, ensuring that they will not be swapped out to disk. This can help maintain performance by avoiding page faults and ensuring fast data access.": "",
"Enable Memory Mapping (mmap) to load model data. This option allows the system to use disk storage as an extension of RAM by treating disk files as if they were in RAM. This can improve model performance by allowing for faster data access. However, it may not work correctly with all systems and can consume a significant amount of disk space.": "",
"Enable Message Rating": "メッセージ評価を有効にする",
@@ -523,17 +526,18 @@
"Keep Alive": "キープアライブ",
"Key": "",
"Keyboard shortcuts": "キーボードショートカット",
"Knowledge": "知識",
"Knowledge": "ナレッジベース",
"Knowledge Access": "",
"Knowledge created successfully.": "知識の作成に成功しました",
"Knowledge deleted successfully.": "知識の削除に成功しました",
"Knowledge reset successfully.": "知識のリセットに成功しました",
"Knowledge updated successfully": "知識のアップデートに成功しました",
"Knowledge created successfully.": "ナレッジベースの作成に成功しました",
"Knowledge deleted successfully.": "ナレッジベースの削除に成功しました",
"Knowledge reset successfully.": "ナレッジベースのリセットに成功しました",
"Knowledge updated successfully": "ナレッジベースのアップデートに成功しました",
"Label": "",
"Landing Page Mode": "ランディングページモード",
"Language": "言語",
"Last Active": "最終アクティブ",
"Last Modified": "",
"Last reply": "",
"LDAP": "",
"LDAP server updated": "",
"Leaderboard": "",
@@ -608,7 +612,7 @@
"Name": "名前",
"Name your knowledge base": "",
"New Chat": "新しいチャット",
"New folder": "",
"New Folder": "",
"New Password": "新しいパスワード",
"new-channel": "",
"No content found": "",
@@ -619,7 +623,7 @@
"No files found.": "",
"No groups with access, add a group to grant access": "",
"No HTML, CSS, or JavaScript content found.": "",
"No knowledge found": "知識が見つかりません",
"No knowledge found": "ナレッジベースが見つかりません",
"No model IDs": "",
"No models found": "",
"No models selected": "",
@@ -633,7 +637,7 @@
"Not helpful": "",
"Note: If you set a minimum score, the search will only return documents with a score greater than or equal to the minimum score.": "注意:最小スコアを設定した場合、検索は最小スコア以上のスコアを持つドキュメントのみを返します。",
"Notes": "",
"Notification Sound": "",
"Notification Sound": "通知音",
"Notification Webhook": "",
"Notifications": "デスクトップ通知",
"November": "11月",
@@ -739,6 +743,7 @@
"Rename": "名前を変更",
"Reorder Models": "",
"Repeat Last N": "最後の N を繰り返す",
"Reply in Thread": "",
"Request Mode": "リクエストモード",
"Reranking Model": "モデルの再ランキング",
"Reranking model disabled": "再ランキングモデルが無効です",
@@ -746,7 +751,8 @@
"Reset": "",
"Reset All Models": "",
"Reset Upload Directory": "アップロードディレクトリをリセット",
"Reset Vector Storage/Knowledge": "",
"Reset Vector Storage/Knowledge": "ベクターストレージとナレッジべーうをリセット",
"Reset view": "",
"Response notifications cannot be activated as the website permissions have been denied. Please visit your browser settings to grant the necessary access.": "",
"Response splitting": "応答の分割",
"Result": "",
@@ -775,7 +781,7 @@
"Search Filters": "",
"search for tags": "",
"Search Functions": "Functionの検索",
"Search Knowledge": "知識の検索",
"Search Knowledge": "ナレッジベースの検索",
"Search Models": "モデル検索",
"Search options": "",
"Search Prompts": "プロンプトを検索",
@@ -800,7 +806,7 @@
"Select a pipeline url": "パイプラインの URL を選択する",
"Select a tool": "ツールの選択",
"Select Engine": "エンジンの選択",
"Select Knowledge": "知識の選択",
"Select Knowledge": "ナレッジベースの選択",
"Select model": "モデルを選択",
"Select only one model to call": "",
"Selected model(s) do not support image inputs": "一部のモデルは画像入力をサポートしていません",
@@ -854,7 +860,7 @@
"Signing in to {{WEBUI_NAME}}": "",
"sk-1234": "",
"Source": "ソース",
"Speech Playback Speed": "",
"Speech Playback Speed": "音声の再生速度",
"Speech recognition error: {{error}}": "音声認識エラー: {{error}}",
"Speech-to-Text Engine": "音声テキスト変換エンジン",
"Stop": "",
@@ -944,7 +950,7 @@
"Tool imported successfully": "",
"Tool Name": "",
"Tool updated successfully": "",
"Tools": "",
"Tools": "ツール",
"Tools Access": "",
"Tools are a function calling system with arbitrary code execution": "",
"Tools have a function calling system that allows arbitrary code execution": "",
@@ -983,7 +989,7 @@
"Upload Progress": "アップロードの進行状況",
"URL": "",
"URL Mode": "URL モード",
"Use '#' in the prompt input to load and include your knowledge.": "#を入力すると知識データを参照することが出来ます。",
"Use '#' in the prompt input to load and include your knowledge.": "#を入力するとナレッジベースを参照することが出来ます。",
"Use Gravatar": "Gravatar を使用する",
"Use groups to group your users and assign permissions.": "",
"Use Initials": "初期値を使用する",
@@ -1004,6 +1010,7 @@
"variable to have them replaced with clipboard content.": "クリップボードの内容に置き換える変数。",
"Version": "バージョン",
"Version {{selectedVersion}} of {{totalVersions}}": "",
"View Replies": "",
"Visibility": "",
"Voice": "ボイス",
"Voice Input": "",
+8 -1
View File
@@ -5,6 +5,7 @@
"(e.g. `sh webui.sh --api`)": "(მაგ. `sh webui.sh --api`)",
"(latest)": "(უახლესი)",
"{{ models }}": "{{ models }}",
"{{COUNT}} Replies": "",
"{{user}}'s Chats": "{{user}}-ის ჩათები",
"{{webUIName}} Backend Required": "{{webUIName}} საჭიროა ბექენდი",
"*Prompt node ID(s) are required for image generation": "",
@@ -34,6 +35,7 @@
"Add Group": "",
"Add Memory": "მემორიის დამატება",
"Add Model": "მოდელის დამატება",
"Add Reaction": "",
"Add Tag": "",
"Add Tags": "ტეგების დამატება",
"Add text content": "",
@@ -164,6 +166,7 @@
"Click on the user role button to change a user's role.": "დააკლიკეთ მომხმარებლის როლის ღილაკს რომ შეცვალოთ მომხმარების როლი",
"Clipboard write permission denied. Please check your browser settings to grant the necessary access.": "",
"Clone": "კლონი",
"Clone Chat": "",
"Close": "დახურვა",
"Code execution": "",
"Code formatted successfully": "",
@@ -534,6 +537,7 @@
"Language": "ენა",
"Last Active": "ბოლო აქტიური",
"Last Modified": "",
"Last reply": "",
"LDAP": "",
"LDAP server updated": "",
"Leaderboard": "",
@@ -608,7 +612,7 @@
"Name": "სახელი",
"Name your knowledge base": "",
"New Chat": "ახალი მიმოწერა",
"New folder": "",
"New Folder": "",
"New Password": "ახალი პაროლი",
"new-channel": "",
"No content found": "",
@@ -739,6 +743,7 @@
"Rename": "პოპულარობის რაოდენობა",
"Reorder Models": "",
"Repeat Last N": "გაიმეორეთ ბოლო N",
"Reply in Thread": "",
"Request Mode": "მოთხოვნის რეჟიმი",
"Reranking Model": "რექვექტირება",
"Reranking model disabled": "რექვექტირება არაა ჩართული",
@@ -747,6 +752,7 @@
"Reset All Models": "",
"Reset Upload Directory": "",
"Reset Vector Storage/Knowledge": "",
"Reset view": "",
"Response notifications cannot be activated as the website permissions have been denied. Please visit your browser settings to grant the necessary access.": "",
"Response splitting": "",
"Result": "",
@@ -1004,6 +1010,7 @@
"variable to have them replaced with clipboard content.": "ცვლადი, რომ შეცვალოს ისინი ბუფერში შიგთავსით.",
"Version": "ვერსია",
"Version {{selectedVersion}} of {{totalVersions}}": "",
"View Replies": "",
"Visibility": "",
"Voice": "",
"Voice Input": "",
+8 -1
View File
@@ -5,6 +5,7 @@
"(e.g. `sh webui.sh --api`)": "(예: `sh webui.sh --api`)",
"(latest)": "(최근)",
"{{ models }}": "{{ models }}",
"{{COUNT}} Replies": "",
"{{user}}'s Chats": "{{user}}의 채팅",
"{{webUIName}} Backend Required": "{{webUIName}} 백엔드가 필요합니다.",
"*Prompt node ID(s) are required for image generation": "사진 생성을 위해 프롬포트 노드 ID가 필요합니다",
@@ -34,6 +35,7 @@
"Add Group": "",
"Add Memory": "메모리 추가",
"Add Model": "모델 추가",
"Add Reaction": "",
"Add Tag": "태그 추가",
"Add Tags": "태그 추가",
"Add text content": "글 추가",
@@ -164,6 +166,7 @@
"Click on the user role button to change a user's role.": "사용자 역할 버튼을 클릭하여 사용자의 역할을 변경하세요.",
"Clipboard write permission denied. Please check your browser settings to grant the necessary access.": "클립보드 사용 권한이 거절되었습니다. 필요한 접근을 사용하기 위해 브라우져 설정을 확인 부탁드립니다.",
"Clone": "복제",
"Clone Chat": "",
"Close": "닫기",
"Code execution": "코드 실행",
"Code formatted successfully": "성공적으로 코드가 생성되었습니다",
@@ -534,6 +537,7 @@
"Language": "언어",
"Last Active": "최근 활동",
"Last Modified": "마지막 수정",
"Last reply": "",
"LDAP": "",
"LDAP server updated": "",
"Leaderboard": "리더보드",
@@ -608,7 +612,7 @@
"Name": "이름",
"Name your knowledge base": "",
"New Chat": "새 채팅",
"New folder": "",
"New Folder": "",
"New Password": "새 비밀번호",
"new-channel": "",
"No content found": "내용을 찾을 수 없음",
@@ -739,6 +743,7 @@
"Rename": "이름 변경",
"Reorder Models": "",
"Repeat Last N": "마지막 N 반복",
"Reply in Thread": "",
"Request Mode": "요청 모드",
"Reranking Model": "Reranking 모델",
"Reranking model disabled": "Reranking 모델 비활성화",
@@ -747,6 +752,7 @@
"Reset All Models": "",
"Reset Upload Directory": "업로드 디렉토리 초기화",
"Reset Vector Storage/Knowledge": "벡터 저장 공간/지식 기반 초기화",
"Reset view": "",
"Response notifications cannot be activated as the website permissions have been denied. Please visit your browser settings to grant the necessary access.": "웹사이트 권환과 같이 응답 알림이 활성화될 수 없습니다. 필요한 접근을 사용하기 위해 브라우져 설정을 확인 부탁드립니다.",
"Response splitting": "응답 나누기",
"Result": "결과",
@@ -1004,6 +1010,7 @@
"variable to have them replaced with clipboard content.": "변수를 사용하여 클립보드 내용으로 바꾸세요.",
"Version": "버전",
"Version {{selectedVersion}} of {{totalVersions}}": "버전 {{totalVersions}}의 {{selectedVersion}}",
"View Replies": "",
"Visibility": "",
"Voice": "음성",
"Voice Input": "음성 입력",
+8 -1
View File
@@ -5,6 +5,7 @@
"(e.g. `sh webui.sh --api`)": "(pvz. `sh webui.sh --api`)",
"(latest)": "(naujausias)",
"{{ models }}": "{{ models }}",
"{{COUNT}} Replies": "",
"{{user}}'s Chats": "{{user}} susirašinėjimai",
"{{webUIName}} Backend Required": "{{webUIName}} būtinas serveris",
"*Prompt node ID(s) are required for image generation": "",
@@ -34,6 +35,7 @@
"Add Group": "",
"Add Memory": "Pridėti atminį",
"Add Model": "Pridėti modelį",
"Add Reaction": "",
"Add Tag": "Pridėti žymą",
"Add Tags": "Pridėti žymas",
"Add text content": "",
@@ -164,6 +166,7 @@
"Click on the user role button to change a user's role.": "Paspauskite ant naudotojo rolės mygtuko tam, kad pakeisti naudotojo rolę.",
"Clipboard write permission denied. Please check your browser settings to grant the necessary access.": "Iškarpinės naudojimas neleidžiamas naršyklės.",
"Clone": "Klonuoti",
"Clone Chat": "",
"Close": "Uždaryti",
"Code execution": "",
"Code formatted successfully": "Kodas suformatuotas sėkmingai",
@@ -534,6 +537,7 @@
"Language": "Kalba",
"Last Active": "Paskutinį kartą aktyvus",
"Last Modified": "Paskutinis pakeitimas",
"Last reply": "",
"LDAP": "",
"LDAP server updated": "",
"Leaderboard": "",
@@ -608,7 +612,7 @@
"Name": "Pavadinimas",
"Name your knowledge base": "",
"New Chat": "Naujas pokalbis",
"New folder": "",
"New Folder": "",
"New Password": "Naujas slaptažodis",
"new-channel": "",
"No content found": "",
@@ -739,6 +743,7 @@
"Rename": "Pervadinti",
"Reorder Models": "",
"Repeat Last N": "Pakartoti paskutinius N",
"Reply in Thread": "",
"Request Mode": "Užklausos rėžimas",
"Reranking Model": "Reranking modelis",
"Reranking model disabled": "Reranking modelis neleidžiamas",
@@ -747,6 +752,7 @@
"Reset All Models": "",
"Reset Upload Directory": "Atkurti įkėlimų direktoiją",
"Reset Vector Storage/Knowledge": "",
"Reset view": "",
"Response notifications cannot be activated as the website permissions have been denied. Please visit your browser settings to grant the necessary access.": "Naršyklė neleidžia siųsti pranešimų",
"Response splitting": "",
"Result": "",
@@ -1004,6 +1010,7 @@
"variable to have them replaced with clipboard content.": "kintamoji pakeičiama kopijuoklės turiniu.",
"Version": "Versija",
"Version {{selectedVersion}} of {{totalVersions}}": "",
"View Replies": "",
"Visibility": "",
"Voice": "Balsas",
"Voice Input": "",
+8 -1
View File
@@ -5,6 +5,7 @@
"(e.g. `sh webui.sh --api`)": "(contoh `sh webui.sh --api`)",
"(latest)": "(terkini)",
"{{ models }}": "{{ models }}",
"{{COUNT}} Replies": "",
"{{user}}'s Chats": "Perbualan {{user}}",
"{{webUIName}} Backend Required": "{{webUIName}} Backend diperlukan",
"*Prompt node ID(s) are required for image generation": "",
@@ -34,6 +35,7 @@
"Add Group": "",
"Add Memory": "Tambah Memori",
"Add Model": "Tambah Model",
"Add Reaction": "",
"Add Tag": "Tambah Tag",
"Add Tags": "Tambah Tag",
"Add text content": "",
@@ -164,6 +166,7 @@
"Click on the user role button to change a user's role.": "Klik pada butang peranan pengguna untuk menukar peranan pengguna",
"Clipboard write permission denied. Please check your browser settings to grant the necessary access.": "Kebenaran untuk menulis di papan klip ditolak. Sila semak tetapan pelayan web anda untuk memberikan akses yang diperlukan",
"Clone": "Klon",
"Clone Chat": "",
"Close": "Tutup",
"Code execution": "",
"Code formatted successfully": "Kod berjaya diformatkan",
@@ -534,6 +537,7 @@
"Language": "Bahasa",
"Last Active": "Dilihat aktif terakhir pada",
"Last Modified": "Kemaskini terakhir pada",
"Last reply": "",
"LDAP": "",
"LDAP server updated": "",
"Leaderboard": "",
@@ -608,7 +612,7 @@
"Name": "Nama",
"Name your knowledge base": "",
"New Chat": "Perbualan Baru",
"New folder": "",
"New Folder": "",
"New Password": "Kata Laluan Baru",
"new-channel": "",
"No content found": "",
@@ -739,6 +743,7 @@
"Rename": "Namakan Semula",
"Reorder Models": "",
"Repeat Last N": "Ulang N Terakhir",
"Reply in Thread": "",
"Request Mode": "Mod Permintaan",
"Reranking Model": "Model 'Reranking'",
"Reranking model disabled": "Model 'Reranking' dilumpuhkan",
@@ -747,6 +752,7 @@
"Reset All Models": "",
"Reset Upload Directory": "Tetapkan Semula Direktori Muat Naik",
"Reset Vector Storage/Knowledge": "",
"Reset view": "",
"Response notifications cannot be activated as the website permissions have been denied. Please visit your browser settings to grant the necessary access.": "Pemberitahuan respons tidak boleh diaktifkan kerana kebenaran tapak web tidak diberi. Sila lawati tetapan pelayar web anda untuk memberikan akses yang diperlukan.",
"Response splitting": "",
"Result": "",
@@ -1004,6 +1010,7 @@
"variable to have them replaced with clipboard content.": "pembolehubah untuk ia digantikan dengan kandungan papan klip.",
"Version": "Versi",
"Version {{selectedVersion}} of {{totalVersions}}": "",
"View Replies": "",
"Visibility": "",
"Voice": "Suara",
"Voice Input": "",
+8 -1
View File
@@ -5,6 +5,7 @@
"(e.g. `sh webui.sh --api`)": "(f.eks. `sh webui.sh --api`)",
"(latest)": "(siste)",
"{{ models }}": "{{ modeller }}",
"{{COUNT}} Replies": "",
"{{user}}'s Chats": "{{user}} sine samtaler",
"{{webUIName}} Backend Required": "Backend til {{webUIName}} kreves",
"*Prompt node ID(s) are required for image generation": "Node-ID-er for ledetekst kreves for generering av bilder",
@@ -34,6 +35,7 @@
"Add Group": "Legg til gruppe",
"Add Memory": "Legg til minne",
"Add Model": "Legg til modell",
"Add Reaction": "",
"Add Tag": "Legg til etikett",
"Add Tags": "Legg til etiketter",
"Add text content": "Legg til tekstinnhold",
@@ -164,6 +166,7 @@
"Click on the user role button to change a user's role.": "Klikk på knappen Brukerrolle for å endre en brukers rolle.",
"Clipboard write permission denied. Please check your browser settings to grant the necessary access.": "Skrivetilgang til utklippstavlen avslått. Kontroller nettleserinnstillingene for å gi den nødvendige tilgangen.",
"Clone": "Klon",
"Clone Chat": "",
"Close": "Lukk",
"Code execution": "Kodekjøring",
"Code formatted successfully": "Koden er formatert",
@@ -534,6 +537,7 @@
"Language": "Språk",
"Last Active": "Sist aktiv",
"Last Modified": "Sist endret",
"Last reply": "",
"LDAP": "LDAP",
"LDAP server updated": "LDAP-server oppdatert",
"Leaderboard": "Ledertavle",
@@ -608,7 +612,7 @@
"Name": "Navn",
"Name your knowledge base": "Gi kunnskapsbasen et navn",
"New Chat": "Ny chat",
"New folder": "",
"New Folder": "",
"New Password": "Nytt passord",
"new-channel": "",
"No content found": "Finner ikke noe innhold",
@@ -739,6 +743,7 @@
"Rename": "Gi nytt navn",
"Reorder Models": "Sorter modeller på nytt",
"Repeat Last N": "Gjenta siste N",
"Reply in Thread": "",
"Request Mode": "Forespørselsmodus",
"Reranking Model": "Omrangeringsmodell",
"Reranking model disabled": "Omrangeringsmodell deaktivert",
@@ -747,6 +752,7 @@
"Reset All Models": "",
"Reset Upload Directory": "Tilbakestill opplastingskatalog",
"Reset Vector Storage/Knowledge": "Tilbakestill Vector-lagring/kunnskap",
"Reset view": "",
"Response notifications cannot be activated as the website permissions have been denied. Please visit your browser settings to grant the necessary access.": "Svar-varsler kan ikke aktiveres fordi tilgang til nettstedet er nektet. Gå til nettleserinnstillingene dine for å gi den nødvendige tilgangen.",
"Response splitting": "Oppdeling av svar",
"Result": "Resultat",
@@ -1004,6 +1010,7 @@
"variable to have them replaced with clipboard content.": "variabel for å erstatte dem med utklippstavleinnhold.",
"Version": "Versjon",
"Version {{selectedVersion}} of {{totalVersions}}": "Version {{selectedVersion}} av {{totalVersions}}",
"View Replies": "",
"Visibility": "Synlighet",
"Voice": "Stemme",
"Voice Input": "Taleinndata",
+8 -1
View File
@@ -5,6 +5,7 @@
"(e.g. `sh webui.sh --api`)": "(bv. `sh webui.sh --api`)",
"(latest)": "(nieuwste)",
"{{ models }}": "{{ modellen }}",
"{{COUNT}} Replies": "",
"{{user}}'s Chats": "{{user}}'s chats",
"{{webUIName}} Backend Required": "{{webUIName}} Backend Verplicht",
"*Prompt node ID(s) are required for image generation": "*Prompt node ID('s) zijn vereist voor het genereren van afbeeldingen",
@@ -34,6 +35,7 @@
"Add Group": "Voeg groep toe",
"Add Memory": "Voeg geheugen toe",
"Add Model": "Voeg model toe",
"Add Reaction": "",
"Add Tag": "Voeg tag toe",
"Add Tags": "Voeg tags toe",
"Add text content": "Voeg tekstinhoud toe",
@@ -164,6 +166,7 @@
"Click on the user role button to change a user's role.": "Klik op de gebruikersrol knop om de rol van een gebruiker te wijzigen.",
"Clipboard write permission denied. Please check your browser settings to grant the necessary access.": "Klembord schrijftoestemming geweigerd. Kijk je browserinstellingen na om de benodigde toestemming te geven.",
"Clone": "Kloon",
"Clone Chat": "",
"Close": "Sluiten",
"Code execution": "Code uitvoeren",
"Code formatted successfully": "Code succesvol geformateerd",
@@ -534,6 +537,7 @@
"Language": "Taal",
"Last Active": "Laatst Actief",
"Last Modified": "Laatst aangepast",
"Last reply": "",
"LDAP": "LDAP",
"LDAP server updated": "LDAP-server bijgewerkt",
"Leaderboard": "Klassement",
@@ -608,7 +612,7 @@
"Name": "Naam",
"Name your knowledge base": "Geef je kennisbasis een naam",
"New Chat": "Nieuwe Chat",
"New folder": "",
"New Folder": "",
"New Password": "Nieuw Wachtwoord",
"new-channel": "",
"No content found": "Geen content gevonden",
@@ -739,6 +743,7 @@
"Rename": "Hernoemen",
"Reorder Models": "Herschik modellen",
"Repeat Last N": "Herhaal Laatste N",
"Reply in Thread": "",
"Request Mode": "Request Modus",
"Reranking Model": "Reranking Model",
"Reranking model disabled": "Reranking model uitgeschakeld",
@@ -747,6 +752,7 @@
"Reset All Models": "Herstel alle modellen",
"Reset Upload Directory": "Herstel Uploadmap",
"Reset Vector Storage/Knowledge": "Herstel Vectoropslag/-kennis",
"Reset view": "",
"Response notifications cannot be activated as the website permissions have been denied. Please visit your browser settings to grant the necessary access.": "Antwoordmeldingen kunnen niet worden geactiveerd omdat de rechten voor de website zijn geweigerd. Ga naar de instellingen van uw browser om de benodigde toegang te verlenen.",
"Response splitting": "Antwoord splitsing",
"Result": "Resultaat",
@@ -1004,6 +1010,7 @@
"variable to have them replaced with clipboard content.": "variabele om ze te laten vervangen door klembord inhoud.",
"Version": "Versie",
"Version {{selectedVersion}} of {{totalVersions}}": "Versie {{selectedVersion}} van {{totalVersions}}",
"View Replies": "",
"Visibility": "Zichtbaarheid",
"Voice": "Stem",
"Voice Input": "Steminvoer",
+8 -1
View File
@@ -5,6 +5,7 @@
"(e.g. `sh webui.sh --api`)": "(ਉਦਾਹਰਣ ਦੇ ਤੌਰ ਤੇ `sh webui.sh --api`)",
"(latest)": "(ਤਾਜ਼ਾ)",
"{{ models }}": "{{ ਮਾਡਲ }}",
"{{COUNT}} Replies": "",
"{{user}}'s Chats": "{{user}} ਦੀਆਂ ਗੱਲਾਂ",
"{{webUIName}} Backend Required": "{{webUIName}} ਬੈਕਐਂਡ ਲੋੜੀਂਦਾ ਹੈ",
"*Prompt node ID(s) are required for image generation": "",
@@ -34,6 +35,7 @@
"Add Group": "",
"Add Memory": "ਮਿਹਾਨ ਸ਼ਾਮਲ ਕਰੋ",
"Add Model": "ਮਾਡਲ ਸ਼ਾਮਲ ਕਰੋ",
"Add Reaction": "",
"Add Tag": "",
"Add Tags": "ਟੈਗ ਸ਼ਾਮਲ ਕਰੋ",
"Add text content": "",
@@ -164,6 +166,7 @@
"Click on the user role button to change a user's role.": "ਉਪਭੋਗਤਾ ਦੀ ਭੂਮਿਕਾ ਬਦਲਣ ਲਈ ਉਪਭੋਗਤਾ ਭੂਮਿਕਾ ਬਟਨ 'ਤੇ ਕਲਿੱਕ ਕਰੋ।",
"Clipboard write permission denied. Please check your browser settings to grant the necessary access.": "",
"Clone": "ਕਲੋਨ",
"Clone Chat": "",
"Close": "ਬੰਦ ਕਰੋ",
"Code execution": "",
"Code formatted successfully": "",
@@ -534,6 +537,7 @@
"Language": "ਭਾਸ਼ਾ",
"Last Active": "ਆਖਰੀ ਸਰਗਰਮ",
"Last Modified": "",
"Last reply": "",
"LDAP": "",
"LDAP server updated": "",
"Leaderboard": "",
@@ -608,7 +612,7 @@
"Name": "ਨਾਮ",
"Name your knowledge base": "",
"New Chat": "ਨਵੀਂ ਗੱਲਬਾਤ",
"New folder": "",
"New Folder": "",
"New Password": "ਨਵਾਂ ਪਾਸਵਰਡ",
"new-channel": "",
"No content found": "",
@@ -739,6 +743,7 @@
"Rename": "ਨਾਮ ਬਦਲੋ",
"Reorder Models": "",
"Repeat Last N": "ਆਖਰੀ N ਨੂੰ ਦੁਹਰਾਓ",
"Reply in Thread": "",
"Request Mode": "ਬੇਨਤੀ ਮੋਡ",
"Reranking Model": "ਮਾਡਲ ਮੁੜ ਰੈਂਕਿੰਗ",
"Reranking model disabled": "ਮਾਡਲ ਮੁੜ ਰੈਂਕਿੰਗ ਅਯੋਗ ਕੀਤਾ ਗਿਆ",
@@ -747,6 +752,7 @@
"Reset All Models": "",
"Reset Upload Directory": "",
"Reset Vector Storage/Knowledge": "",
"Reset view": "",
"Response notifications cannot be activated as the website permissions have been denied. Please visit your browser settings to grant the necessary access.": "",
"Response splitting": "",
"Result": "",
@@ -1004,6 +1010,7 @@
"variable to have them replaced with clipboard content.": "ਕਲਿੱਪਬੋਰਡ ਸਮੱਗਰੀ ਨਾਲ ਬਦਲਣ ਲਈ ਵੈਰੀਏਬਲ।",
"Version": "ਵਰਜਨ",
"Version {{selectedVersion}} of {{totalVersions}}": "",
"View Replies": "",
"Visibility": "",
"Voice": "",
"Voice Input": "",
+8 -1
View File
@@ -5,6 +5,7 @@
"(e.g. `sh webui.sh --api`)": "(np. `sh webui.sh --api`)",
"(latest)": "(najnowszy)",
"{{ models }}": "{{ modele }}",
"{{COUNT}} Replies": "",
"{{user}}'s Chats": "{{user}} - czaty",
"{{webUIName}} Backend Required": "Backend {{webUIName}} wymagane",
"*Prompt node ID(s) are required for image generation": "",
@@ -34,6 +35,7 @@
"Add Group": "",
"Add Memory": "Dodaj pamięć",
"Add Model": "Dodaj model",
"Add Reaction": "",
"Add Tag": "",
"Add Tags": "Dodaj tagi",
"Add text content": "",
@@ -164,6 +166,7 @@
"Click on the user role button to change a user's role.": "Kliknij przycisk roli użytkownika, aby zmienić rolę użytkownika.",
"Clipboard write permission denied. Please check your browser settings to grant the necessary access.": "",
"Clone": "Klon",
"Clone Chat": "",
"Close": "Zamknij",
"Code execution": "",
"Code formatted successfully": "",
@@ -534,6 +537,7 @@
"Language": "Język",
"Last Active": "Ostatnio aktywny",
"Last Modified": "",
"Last reply": "",
"LDAP": "",
"LDAP server updated": "",
"Leaderboard": "",
@@ -608,7 +612,7 @@
"Name": "Nazwa",
"Name your knowledge base": "",
"New Chat": "Nowy czat",
"New folder": "",
"New Folder": "",
"New Password": "Nowe hasło",
"new-channel": "",
"No content found": "",
@@ -739,6 +743,7 @@
"Rename": "ZMień nazwę",
"Reorder Models": "",
"Repeat Last N": "Powtórz ostatnie N",
"Reply in Thread": "",
"Request Mode": "Tryb żądania",
"Reranking Model": "Zmiana rankingu modelu",
"Reranking model disabled": "Zmiana rankingu modelu zablokowana",
@@ -747,6 +752,7 @@
"Reset All Models": "",
"Reset Upload Directory": "",
"Reset Vector Storage/Knowledge": "",
"Reset view": "",
"Response notifications cannot be activated as the website permissions have been denied. Please visit your browser settings to grant the necessary access.": "",
"Response splitting": "",
"Result": "",
@@ -1004,6 +1010,7 @@
"variable to have them replaced with clipboard content.": "zmienna która zostanie zastąpiona zawartością schowka.",
"Version": "Wersja",
"Version {{selectedVersion}} of {{totalVersions}}": "",
"View Replies": "",
"Visibility": "",
"Voice": "",
"Voice Input": "",
+8 -1
View File
@@ -5,6 +5,7 @@
"(e.g. `sh webui.sh --api`)": "(por exemplo, `sh webui.sh --api`)",
"(latest)": "(último)",
"{{ models }}": "{{ models }}",
"{{COUNT}} Replies": "",
"{{user}}'s Chats": "Chats de {{user}}",
"{{webUIName}} Backend Required": "Backend {{webUIName}} necessário",
"*Prompt node ID(s) are required for image generation": "*Prompt node ID(s) são obrigatórios para gerar imagens",
@@ -34,6 +35,7 @@
"Add Group": "Adicionar Grupo",
"Add Memory": "Adicionar Memória",
"Add Model": "Adicionar Modelo",
"Add Reaction": "",
"Add Tag": "Adicionar Tag",
"Add Tags": "Adicionar Tags",
"Add text content": "Adicionar conteúdo de texto",
@@ -164,6 +166,7 @@
"Click on the user role button to change a user's role.": "Clique no botão de função do usuário para alterar a função de um usuário.",
"Clipboard write permission denied. Please check your browser settings to grant the necessary access.": "Permissão de escrita na área de transferência negada. Verifique as configurações do seu navegador para conceder o acesso necessário.",
"Clone": "Clonar",
"Clone Chat": "",
"Close": "Fechar",
"Code execution": "Execução de código",
"Code formatted successfully": "Código formatado com sucesso",
@@ -534,6 +537,7 @@
"Language": "Idioma",
"Last Active": "Última Atividade",
"Last Modified": "Última Modificação",
"Last reply": "",
"LDAP": "",
"LDAP server updated": "Servidor LDAP atualizado",
"Leaderboard": "Tabela de classificação",
@@ -608,7 +612,7 @@
"Name": "Nome",
"Name your knowledge base": "Nome da sua base de conhecimento",
"New Chat": "Novo Chat",
"New folder": "",
"New Folder": "",
"New Password": "Nova Senha",
"new-channel": "",
"No content found": "Nenhum conteúdo encontrado",
@@ -739,6 +743,7 @@
"Rename": "Renomear",
"Reorder Models": "",
"Repeat Last N": "Repetir Último N",
"Reply in Thread": "",
"Request Mode": "Modo de Solicitação",
"Reranking Model": "Modelo de Reclassificação",
"Reranking model disabled": "Modelo de Reclassificação desativado",
@@ -747,6 +752,7 @@
"Reset All Models": "",
"Reset Upload Directory": "Redefinir Diretório de Upload",
"Reset Vector Storage/Knowledge": "Redefinir Armazenamento de Vetores/Conhecimento",
"Reset view": "",
"Response notifications cannot be activated as the website permissions have been denied. Please visit your browser settings to grant the necessary access.": "Notificações de resposta não podem ser ativadas pois as permissões do site foram negadas. Por favor, visite as configurações do seu navegador para conceder o acesso necessário.",
"Response splitting": "Divisão da Resposta",
"Result": "Resultado",
@@ -1004,6 +1010,7 @@
"variable to have them replaced with clipboard content.": "variável para ser substituída pelo conteúdo da área de transferência.",
"Version": "Versão",
"Version {{selectedVersion}} of {{totalVersions}}": "Versão {{selectedVersion}} de {{totalVersions}}",
"View Replies": "",
"Visibility": "Visibilidade",
"Voice": "Voz",
"Voice Input": "Entrada de voz",
+8 -1
View File
@@ -5,6 +5,7 @@
"(e.g. `sh webui.sh --api`)": "(por exemplo, `sh webui.sh --api`)",
"(latest)": "(mais recente)",
"{{ models }}": "{{ modelos }}",
"{{COUNT}} Replies": "",
"{{user}}'s Chats": "{{user}}'s Chats",
"{{webUIName}} Backend Required": "{{webUIName}} Backend Necessário",
"*Prompt node ID(s) are required for image generation": "",
@@ -34,6 +35,7 @@
"Add Group": "",
"Add Memory": "Adicionar memória",
"Add Model": "Adicionar modelo",
"Add Reaction": "",
"Add Tag": "",
"Add Tags": "adicionar tags",
"Add text content": "",
@@ -164,6 +166,7 @@
"Click on the user role button to change a user's role.": "Clique no botão de função do utilizador para alterar a função de um utilizador.",
"Clipboard write permission denied. Please check your browser settings to grant the necessary access.": "",
"Clone": "Clonar",
"Clone Chat": "",
"Close": "Fechar",
"Code execution": "",
"Code formatted successfully": "",
@@ -534,6 +537,7 @@
"Language": "Idioma",
"Last Active": "Último Ativo",
"Last Modified": "",
"Last reply": "",
"LDAP": "",
"LDAP server updated": "",
"Leaderboard": "",
@@ -608,7 +612,7 @@
"Name": "Nome",
"Name your knowledge base": "",
"New Chat": "Nova Conversa",
"New folder": "",
"New Folder": "",
"New Password": "Nova Senha",
"new-channel": "",
"No content found": "",
@@ -739,6 +743,7 @@
"Rename": "Renomear",
"Reorder Models": "",
"Repeat Last N": "Repetir Últimos N",
"Reply in Thread": "",
"Request Mode": "Modo de Pedido",
"Reranking Model": "Modelo de Reranking",
"Reranking model disabled": "Modelo de Reranking desativado",
@@ -747,6 +752,7 @@
"Reset All Models": "",
"Reset Upload Directory": "Limpar Pasta de Carregamento",
"Reset Vector Storage/Knowledge": "",
"Reset view": "",
"Response notifications cannot be activated as the website permissions have been denied. Please visit your browser settings to grant the necessary access.": "",
"Response splitting": "",
"Result": "",
@@ -1004,6 +1010,7 @@
"variable to have them replaced with clipboard content.": "variável para que sejam substituídos pelo conteúdo da área de transferência.",
"Version": "Versão",
"Version {{selectedVersion}} of {{totalVersions}}": "",
"View Replies": "",
"Visibility": "",
"Voice": "",
"Voice Input": "",
+8 -1
View File
@@ -5,6 +5,7 @@
"(e.g. `sh webui.sh --api`)": "(de ex. `sh webui.sh --api`)",
"(latest)": "(ultimul)",
"{{ models }}": "{{ modele }}",
"{{COUNT}} Replies": "",
"{{user}}'s Chats": "Conversațiile lui {{user}}",
"{{webUIName}} Backend Required": "Este necesar backend-ul {{webUIName}}",
"*Prompt node ID(s) are required for image generation": "*Sunt necesare ID-urile nodurilor de solicitare pentru generarea imaginii*",
@@ -34,6 +35,7 @@
"Add Group": "",
"Add Memory": "Adaugă Memorie",
"Add Model": "Adaugă Model",
"Add Reaction": "",
"Add Tag": "Adaugă Etichetă",
"Add Tags": "Adaugă Etichete",
"Add text content": "Adăugați conținut textual",
@@ -164,6 +166,7 @@
"Click on the user role button to change a user's role.": "Apasă pe butonul rolului utilizatorului pentru a schimba rolul unui utilizator.",
"Clipboard write permission denied. Please check your browser settings to grant the necessary access.": "Permisiunea de scriere în clipboard a fost refuzată. Vă rugăm să verificați setările browserului pentru a acorda accesul necesar.",
"Clone": "Clonează",
"Clone Chat": "",
"Close": "Închide",
"Code execution": "Executarea codului",
"Code formatted successfully": "Cod formatat cu succes",
@@ -534,6 +537,7 @@
"Language": "Limbă",
"Last Active": "Ultima Activitate",
"Last Modified": "Ultima Modificare",
"Last reply": "",
"LDAP": "",
"LDAP server updated": "",
"Leaderboard": "Tabel de clasament",
@@ -608,7 +612,7 @@
"Name": "Nume",
"Name your knowledge base": "",
"New Chat": "Conversație Nouă",
"New folder": "",
"New Folder": "",
"New Password": "Parolă Nouă",
"new-channel": "",
"No content found": "Nu a fost găsit niciun conținut",
@@ -739,6 +743,7 @@
"Rename": "Redenumește",
"Reorder Models": "",
"Repeat Last N": "Repetă Ultimele N",
"Reply in Thread": "",
"Request Mode": "Mod de Cerere",
"Reranking Model": "Model de Rearanjare",
"Reranking model disabled": "Modelul de Rearanjare este dezactivat",
@@ -747,6 +752,7 @@
"Reset All Models": "",
"Reset Upload Directory": "Resetează Directorul de Încărcare",
"Reset Vector Storage/Knowledge": "Resetarea Stocării/Vectoului de Cunoștințe",
"Reset view": "",
"Response notifications cannot be activated as the website permissions have been denied. Please visit your browser settings to grant the necessary access.": "Notificările de răspuns nu pot fi activate deoarece permisiunile site-ului au fost refuzate. Vă rugăm să vizitați setările browserului pentru a acorda accesul necesar.",
"Response splitting": "Împărțirea răspunsurilor",
"Result": "Rezultat",
@@ -1004,6 +1010,7 @@
"variable to have them replaced with clipboard content.": "variabilă pentru a fi înlocuite cu conținutul clipboard-ului.",
"Version": "Versiune",
"Version {{selectedVersion}} of {{totalVersions}}": "Versiunea {{selectedVersion}} din {{totalVersions}}",
"View Replies": "",
"Visibility": "",
"Voice": "Voce",
"Voice Input": "Intrare vocală",
+8 -1
View File
@@ -5,6 +5,7 @@
"(e.g. `sh webui.sh --api`)": "(например, `sh webui.sh --api`)",
"(latest)": "(последняя)",
"{{ models }}": "{{ модели }}",
"{{COUNT}} Replies": "",
"{{user}}'s Chats": "Чаты {{user}}'а",
"{{webUIName}} Backend Required": "Необходимо подключение к серверу {{webUIName}}",
"*Prompt node ID(s) are required for image generation": "ID узлов промптов обязательны для генерации изображения",
@@ -34,6 +35,7 @@
"Add Group": "Добавить группу",
"Add Memory": "Добавить воспоминание",
"Add Model": "Добавить модель",
"Add Reaction": "",
"Add Tag": "Добавить тег",
"Add Tags": "Добавить теги",
"Add text content": "",
@@ -164,6 +166,7 @@
"Click on the user role button to change a user's role.": "Нажмите кнопку роли пользователя, чтобы изменить роль пользователя.",
"Clipboard write permission denied. Please check your browser settings to grant the necessary access.": "В разрешении на запись в буфер обмена отказано. Пожалуйста, проверьте настройки своего браузера, чтобы предоставить необходимый доступ.",
"Clone": "Клонировать",
"Clone Chat": "",
"Close": "Закрыть",
"Code execution": "Выполнение кода",
"Code formatted successfully": "Код успешно отформатирован",
@@ -534,6 +537,7 @@
"Language": "Язык",
"Last Active": "Последний Активный",
"Last Modified": "Последнее Изменение",
"Last reply": "",
"LDAP": "",
"LDAP server updated": "LDAP сервер обновлен",
"Leaderboard": "Таблица Лидеров",
@@ -608,7 +612,7 @@
"Name": "Имя",
"Name your knowledge base": "",
"New Chat": "Новый чат",
"New folder": "",
"New Folder": "",
"New Password": "Новый пароль",
"new-channel": "",
"No content found": "Контент не найден",
@@ -739,6 +743,7 @@
"Rename": "Переименовать",
"Reorder Models": "",
"Repeat Last N": "Повторить последние N",
"Reply in Thread": "",
"Request Mode": "Режим запроса",
"Reranking Model": "Модель реранжирования",
"Reranking model disabled": "Модель реранжирования отключена",
@@ -747,6 +752,7 @@
"Reset All Models": "",
"Reset Upload Directory": "Сбросить каталог загрузок",
"Reset Vector Storage/Knowledge": "",
"Reset view": "",
"Response notifications cannot be activated as the website permissions have been denied. Please visit your browser settings to grant the necessary access.": "Уведомления об ответах не могут быть активированы, поскольку доступ к веб-сайту был заблокирован. Пожалуйста, перейдите к настройкам своего браузера, чтобы предоставить необходимый доступ.",
"Response splitting": "Разделение ответов",
"Result": "",
@@ -1004,6 +1010,7 @@
"variable to have them replaced with clipboard content.": "переменную, чтобы заменить их содержимым буфера обмена.",
"Version": "Версия",
"Version {{selectedVersion}} of {{totalVersions}}": "",
"View Replies": "",
"Visibility": "Видимость",
"Voice": "Голос",
"Voice Input": "",

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