Compare commits

...
4144 Commits
Author SHA1 Message Date
Tim Jaeryang Baek 2c3655a969 Merge pull request #15909 from open-webui/dev
0.6.19
2025-08-10 02:38:48 +04:00
Timothy Jaeryang Baek bfd8c6b87e refac 2025-08-10 02:37:27 +04:00
Timothy Jaeryang Baek 0af66558ae refac 2025-08-10 02:35:41 +04:00
Timothy Jaeryang Baek 9a145c591f chore: pyproject bump 2025-08-10 02:25:40 +04:00
Timothy Jaeryang Baek d7e9b0828b refac 2025-08-10 02:17:54 +04:00
Timothy Jaeryang Baek e9c93d082e chore: format 2025-08-10 02:15:53 +04:00
Timothy Jaeryang Baek 3f7d3def02 enh: folder filter 2025-08-10 02:10:18 +04:00
Timothy Jaeryang Baek 6497b46a78 refac 2025-08-10 01:44:33 +04:00
Timothy Jaeryang Baek bd2819a96a doc: changelog 2025-08-10 01:35:43 +04:00
Timothy Jaeryang Baek d8c76e9a0c refac 2025-08-10 01:31:07 +04:00
Timothy Jaeryang Baek b1d5e3b687 refac 2025-08-10 01:29:51 +04:00
Timothy Jaeryang Baek 50181ee99e refac 2025-08-10 01:03:02 +04:00
Timothy Jaeryang Baek eac6f6be0a chore: changelog reordering 2025-08-10 00:37:12 +04:00
Tim Jaeryang Baek 72f75afb33 Merge pull request #16420 from Classic298/patch-2
Update CHANGELOG.md
2025-08-10 00:33:49 +04:00
Classic298 ca9a545a50 Update CHANGELOG.md 2025-08-09 22:26:52 +02:00
Classic298 3395a25222 Update CHANGELOG.md 2025-08-09 22:22:22 +02:00
Classic298 9b5db894d4 Update CHANGELOG.md 2025-08-09 22:11:41 +02:00
Timothy Jaeryang Baek c77b36bdcc refac 2025-08-10 00:02:58 +04:00
Timothy Jaeryang Baek 77189664c2 chore: format 2025-08-09 23:57:35 +04:00
Timothy Jaeryang Baek f85aaa4ed9 refac: sqlcipher3-wheels as optional 2025-08-09 23:56:17 +04:00
Tim Jaeryang Baek 86fa564b44 Merge pull request #16132 from rndmcnlly/feature/sqlcipher-database-encryption
feat: Implement SQLCipher support for database encryption
2025-08-09 23:55:03 +04:00
Tim Jaeryang Baek 53425ffadb Merge pull request #16419 from expruc/feat/qdrant_improvements
feat: qdrant client improvements
2025-08-09 23:52:12 +04:00
Tim Jaeryang Baek 17ca02aa6b Merge pull request #16417 from Ithanil/prevent_idle_transactions
fix: Prevent idle transactions with PGvector DB
2025-08-09 23:51:51 +04:00
Timothy Jaeryang Baek 4e9c75be50 enh: CHAT_RESPONSE_STREAM_DELTA_CHUNK_SIZE 2025-08-09 23:49:56 +04:00
Timothy Jaeryang Baek a068ba88de chore: format 2025-08-09 23:47:02 +04:00
Timothy Jaeryang BaekandJan Kessler 1a93891d97 feat: stream delta chunk
Co-Authored-By: Jan Kessler <Ithanil@users.noreply.github.com>
2025-08-09 23:43:27 +04:00
expruc 8af9ad3f30 updated query function with scroll too 2025-08-09 22:04:41 +03:00
Timothy Jaeryang Baek e2b2e8b245 refac 2025-08-09 22:59:19 +04:00
Timothy Jaeryang Baek e9c2d9d035 refac: styling 2025-08-09 22:55:19 +04:00
Timothy Jaeryang Baek 98f38f00ff enh: shift unpin pinned models 2025-08-09 22:50:27 +04:00
expruc 88abd01b87 qdrant client improvements 2025-08-09 21:12:30 +03:00
Jan Kessler 3a9601c053 use .rollback() after read-only transaction on pgvector to avoid infinitely idle transactions (and errors in certain scenarios) 2025-08-09 20:09:45 +02:00
Timothy Jaeryang Baek 4485c7a5d2 refac 2025-08-09 21:38:31 +04:00
Timothy Jaeryang Baek caf8482fba refac 2025-08-09 21:34:47 +04:00
Timothy Jaeryang Baek f4d2c6027a refac 2025-08-09 21:10:12 +04:00
Timothy Jaeryang Baek 78cf70faec chore: version bump 2025-08-09 02:12:14 +04:00
Timothy Jaeryang Baek 4b41cd1891 chore: format 2025-08-09 02:05:07 +04:00
Timothy Jaeryang Baek 92f27bb21e feat/enh: regeneration options 2025-08-09 02:00:21 +04:00
Tim Jaeryang Baek 17084f629c Merge pull request #16385 from gaby/2025-08-08-13-38-31
feat: Propagate upstream OpenAI router errors
2025-08-09 00:58:14 +04:00
Timothy Jaeryang Baek c1d566bad4 enh: oauth_sub_claim 2025-08-09 00:46:14 +04:00
Timothy Jaeryang Baek e8cb57750b refac/fix: serply 2025-08-09 00:37:37 +04:00
Timothy Jaeryang Baek 736b29ddca refac 2025-08-09 00:33:41 +04:00
Timothy Jaeryang Baek f923a85f40 refac/fix: reasoning_content chunk 2025-08-09 00:31:28 +04:00
Tim Jaeryang Baek 8714df17dd Merge pull request #16381 from psy42a/patch-1
fix: failure to bind metadata variable on insert for PGVECTOR_PGCRYPTO feature returning syntax error
2025-08-09 00:26:30 +04:00
Tim Jaeryang Baek 9fbc76f4bb Merge pull request #16397 from 17jmumford/add_gpt_5_max_token_handling
fix: added gpt-5 to reasoning model payload handler
2025-08-09 00:22:30 +04:00
Tim Jaeryang Baek ea215aa8c2 Merge pull request #16396 from andrewbbaek/dev
refac: oidc provider url validation
2025-08-09 00:21:13 +04:00
Jeremy Mumford c69f2cc776 updated comments 2025-08-08 14:20:14 -06:00
Jeremy Mumford 0c40d93da4 renamed and added gpt-5 to reflect OpenAI updates 2025-08-08 14:16:28 -06:00
Andrew Baek 451b614f4d refac: oidc provider url validation 2025-08-09 00:15:19 +04:00
Timothy Jaeryang Baek 34689e37f8 refac 2025-08-08 20:58:52 +04:00
Timothy Jaeryang Baek 95f9d69e9a refac 2025-08-08 20:52:53 +04:00
Timothy Jaeryang Baek a5683c411a refac 2025-08-08 19:58:53 +04:00
Timothy Jaeryang Baek c42c1ee632 refac: styling 2025-08-08 18:48:27 +04:00
Timothy Jaeryang Baek 69f6fbe4e7 refac 2025-08-08 18:40:03 +04:00
Juan Calderon-Perez 7619f449c8 Format code base 2025-08-08 10:10:32 -04:00
Juan Calderon-Perez d2f2d42e09 Format python code 2025-08-08 10:09:31 -04:00
Juan Calderon-Perez 5d7e8c8e5f Format openai router 2025-08-08 10:04:02 -04:00
Juan Calderon-Perez 2ae7584686 feat: forward upstream OpenAI errors 2025-08-08 09:38:34 -04:00
Timothy Jaeryang Baek 9af64f0db1 refac 2025-08-08 14:27:28 +04:00
Timothy Jaeryang Baek 3f85375db2 refac: styling 2025-08-08 14:24:54 +04:00
Timothy Jaeryang Baek 2bccc7b8fc refac 2025-08-08 14:18:17 +04:00
Timothy Jaeryang Baek 9979ed4b46 refac 2025-08-08 14:07:23 +04:00
Timothy Jaeryang Baek 151c072bbc refac 2025-08-08 14:04:44 +04:00
Timothy Jaeryang Baek 81fed7291c refac 2025-08-08 13:56:34 +04:00
Timothy Jaeryang Baek f8e8d7e048 refac 2025-08-08 13:50:53 +04:00
Timothy Jaeryang Baek 056431606b enh: tool calling support in quick actions 2025-08-08 13:43:30 +04:00
Timothy Jaeryang Baek ff9f2614f3 refac: styling 2025-08-08 13:09:40 +04:00
Timothy Jaeryang Baek c92d1ce219 refac 2025-08-08 13:05:50 +04:00
Timothy Jaeryang Baek 4ba96fe3e5 refac 2025-08-08 12:55:24 +04:00
Timothy Jaeryang Baek 04f37ca279 refac 2025-08-08 12:50:21 +04:00
Timothy Jaeryang Baek 1fc40ad5ee refac 2025-08-08 12:40:13 +04:00
Timothy Jaeryang Baek 19bc5f1c34 refac 2025-08-08 12:34:27 +04:00
Timothy Jaeryang Baek bef5e6bb29 chore: boto3 bump 2025-08-08 12:26:45 +04:00
Timothy Jaeryang Baek 8b489cb31f refac: s3 vector 2025-08-08 12:24:47 +04:00
Timothy Jaeryang Baek 601f1af0a5 refac 2025-08-08 12:17:50 +04:00
Tim Jaeryang Baek 67dcef5e9a Merge pull request #16344 from Rain6435/fix-openapi-array-parameters
fix: include items property in OpenAPI array parameters
  for OpenAI function calling
2025-08-08 12:12:28 +04:00
Timothy Jaeryang Baek d2c7a60a43 refac 2025-08-08 12:07:15 +04:00
Timothy Jaeryang Baek 961df8ef3d refac 2025-08-08 11:57:51 +04:00
Timothy Jaeryang Baek d6326549d6 refac 2025-08-08 11:57:07 +04:00
Timothy Jaeryang Baek b084613004 refac: styling 2025-08-08 11:53:06 +04:00
Timothy Jaeryang Baek e2ce735d12 refac: styling 2025-08-08 04:37:08 +04:00
Timothy Jaeryang Baek 867a86b264 refac 2025-08-08 04:32:17 +04:00
Timothy Jaeryang Baek 0b68fc0a1b refac: styling 2025-08-08 04:10:58 +04:00
Timothy Jaeryang Baek d9f46baa70 refac: sidebar 2025-08-08 03:53:09 +04:00
Timothy Jaeryang Baek e6726d8444 fix: triple backtick enter rich text input 2025-08-08 02:57:44 +04:00
Tim Jaeryang Baek 55248bed2d Merge pull request #16348 from itk-dev/feature/add-label-to-settings-modal-controls
FEAT: add label to settings modal controls
2025-08-07 20:43:17 +04:00
Sine Jespersen 8d6c1c497f add aria labels to controls in interface modal 2025-08-07 12:19:27 +02:00
Rain6435 30540cb40e fix: include items property in OpenAPI array parameters for OpenAI function calling
Resolves issue where OpenAPI specs with array query parameters were generating
  invalid OpenAI function schemas missing the required 'items' property, causing
  400 Bad Request errors from OpenAI.

  The fix ensures that when converting OpenAPI parameter schemas to OpenAI function
  schemas, array parameters properly include their 'items' property definition.

  Fixes open-webui/open-webui#14115
2025-08-07 01:21:22 -04:00
Timothy Jaeryang Baek 761d439830 refac 2025-08-07 03:42:02 +04:00
Timothy Jaeryang Baek 7611441676 refac 2025-08-07 03:37:13 +04:00
Timothy Jaeryang Baek 2bfe684716 refac: styling 2025-08-07 03:35:12 +04:00
Timothy Jaeryang Baek 07b16cc8d1 refac 2025-08-07 02:53:28 +04:00
Timothy Jaeryang Baek 2eef60ced4 refac: sidebar styling 2025-08-07 02:50:05 +04:00
Timothy Jaeryang Baek 85a3c32f07 refac: styling 2025-08-07 02:47:13 +04:00
Timothy Jaeryang Baek ca213cbd12 refac 2025-08-07 02:29:54 +04:00
Timothy Jaeryang Baek 13682e28db refac 2025-08-07 02:25:52 +04:00
Timothy Jaeryang Baek db7ea6d23f refac 2025-08-07 02:20:32 +04:00
Timothy Jaeryang Baek 4a57e581d9 refac 2025-08-07 02:15:31 +04:00
Timothy Jaeryang Baek 2e733b46b0 enh: custom action buttons 2025-08-07 02:11:27 +04:00
Timothy Jaeryang Baek 5d670cb7ce refac: interface settings styling 2025-08-07 02:11:16 +04:00
Timothy Jaeryang Baek cce1f876c9 refac 2025-08-07 01:41:51 +04:00
Timothy Jaeryang Baek f47befa902 refac: styling 2025-08-07 01:22:55 +04:00
Timothy Jaeryang Baek 73c92e2e3e refac 2025-08-07 01:19:34 +04:00
Timothy Jaeryang Baek 6598812a25 refac 2025-08-07 00:14:35 +04:00
Timothy Jaeryang Baek 353ecda084 refac 2025-08-07 00:12:24 +04:00
Timothy Jaeryang Baek 4797799400 refac 2025-08-06 23:36:43 +04:00
Timothy Jaeryang Baek 93a91a678a enh: ability to switch off floating action buttons 2025-08-06 23:28:05 +04:00
Timothy Jaeryang Baek e16251c473 refac 2025-08-06 23:15:08 +04:00
Timothy Jaeryang Baek 07aafa5fea refac 2025-08-06 23:09:34 +04:00
Timothy Jaeryang Baek 0fd5881b7d refac: styling 2025-08-06 23:08:41 +04:00
Timothy Jaeryang Baek fa04711680 refac 2025-08-06 22:55:47 +04:00
Timothy Jaeryang Baek d2fa66bb9d refac: styling 2025-08-06 22:48:12 +04:00
Timothy Jaeryang Baek 8b9c5c4c1e enh: multi model response tabbed display 2025-08-06 22:47:34 +04:00
Tim Jaeryang Baek 0067cf6eff Merge pull request #16334 from leebeomhun/i18n-ko
i18n: update and fix ko-KR translation
2025-08-06 21:32:03 +04:00
Timothy Jaeryang Baek 0912a023c2 fix: jwt token exposed in url 2025-08-06 21:02:54 +04:00
Timothy Jaeryang BaekandG30 041da26756 feat: add pinned, shared and archived tags functionality for chat search moda
Co-Authored-By: G30 <50341825+silentoplayz@users.noreply.github.com>
2025-08-06 20:55:58 +04:00
BHLee 001d07f590 i18n update and fix:ko-KR translation.json 2025-08-07 01:29:37 +09:00
Tim Jaeryang Baek d1a654019b Merge pull request #16332 from itk-dev/feature/text-contrast-settings-modal-general
FEAT: text contrast settings modal general
2025-08-06 19:53:10 +04:00
Timothy Jaeryang Baek aae6008542 chore: bump pillow 2025-08-06 19:52:16 +04:00
Timothy Jaeryang Baek b9885529a5 refac: knowledge item modal 2025-08-06 19:50:51 +04:00
Sine Jespersen 8eee4d1c12 increase text contrast on highContrastMode 2025-08-06 15:49:20 +02:00
Tim Jaeryang Baek 8e25eb104b Merge pull request #16309 from jayteaftw/fips-compatible
fix: Resolved FATAL FIPS SELFTEST FAILURE
2025-08-06 15:14:12 +04:00
Tim Jaeryang Baek 91952096c2 Merge pull request #16321 from itk-dev/feature/more-accessible-menu
Feat: enhance accessibility of menu
2025-08-06 15:13:13 +04:00
Timothy Jaeryang Baek 80dbd76d92 enh: image compression in channels 2025-08-06 15:11:43 +04:00
Timothy Jaeryang Baek 2f349b5979 refac 2025-08-06 15:06:43 +04:00
Timothy Jaeryang Baek f2cae3d0a7 refac 2025-08-06 15:02:39 +04:00
Timothy Jaeryang Baek 4cc2c1915e refac 2025-08-06 14:47:27 +04:00
Timothy Jaeryang Baek 52b2158c67 refac 2025-08-06 14:42:57 +04:00
Tim Jaeryang Baek 70eb83b701 Merge pull request #16185 from hiwylee/vector-search-branch
feat: oracle 23ai Vector search for new supported vector db
2025-08-06 14:36:14 +04:00
Tim Jaeryang Baek 1ba8c3389e Merge pull request #16284 from silentoplayz/fix-clone-chat-tags
fix: also clone the chat's tags, folder stats, and pinned status when cloning a chat
2025-08-06 14:33:04 +04:00
Sine Jespersen 52ef3e74e6 add aria-labels and aria-pressed to enhance accessibility 2025-08-06 12:29:50 +02:00
Sine Jespersen 9df790a9f9 make buttons DropdownMenuItems to make them accessible by keyboard, add handling of highContrastMode 2025-08-06 12:29:28 +02:00
Sine Jespersen ba1e32f60d add aria-label to labelless button to enhance accessibility 2025-08-06 12:28:42 +02:00
Timothy Jaeryang Baek 5d4199bf52 chore: format 2025-08-06 14:27:58 +04:00
Timothy Jaeryang Baek 428db553e2 refac 2025-08-06 14:27:07 +04:00
Timothy Jaeryang Baek 7fffecd168 refac 2025-08-06 14:26:22 +04:00
Timothy Jaeryang Baek 6c06024cf9 refac: scim 2025-08-06 14:25:42 +04:00
Tim Jaeryang Baek f0e1c3f540 Merge pull request #15694 from dieu-bis/feat/scim-2.0-support
FEAT: Add SCIM 2.0 support for automated user provisioning
2025-08-06 14:22:48 +04:00
Sine Jespersen 502a36869e aria-hidden on icons to hide them from assistive technology 2025-08-06 12:17:44 +02:00
Timothy Jaeryang Baek 5ae0036265 refac 2025-08-06 14:03:40 +04:00
Timothy Jaeryang Baek 3a1bbcb12e refac 2025-08-06 13:48:43 +04:00
Timothy Jaeryang Baek 2e36540023 refac: tag handling 2025-08-06 13:32:28 +04:00
Timothy Jaeryang Baek e9fb161bcd refac 2025-08-06 12:36:35 +04:00
Timothy Jaeryang Baek bfa42c6277 enh: formatting toolbar for chat 2025-08-06 12:21:18 +04:00
Timothy Jaeryang Baek 0acd78049d refac: hide docs, releases for users 2025-08-06 11:50:35 +04:00
jayteaftw 4079ac55d8 Set av==14.0.1 2025-08-05 15:29:40 -07:00
Timothy Jaeryang BaekandClassic298 55ad48d1c3 feat: ENABLE_ADMIN_WORKSPACE_CONTENT_ACCESS
Co-Authored-By: Classic298 <27028174+Classic298@users.noreply.github.com>
2025-08-06 01:44:52 +04:00
silentoplayz 7c4550fa92 fix: cloned chat metadata not taken into consideration 2025-08-05 16:21:03 -04:00
Timothy Jaeryang Baek 182192f3c9 chore: analytics scaffolding 2025-08-05 22:28:16 +04:00
Timothy Jaeryang Baek d0657054a5 enh: abililty to stop merge response 2025-08-05 22:25:51 +04:00
Timothy Jaeryang Baek 8b46a9010e refac: styling 2025-08-05 22:22:49 +04:00
Timothy Jaeryang Baekandpickle-dice f24b76d9a3 refac: has_users
Co-Authored-By: pickle-dice <159401444+hassan-ajek@users.noreply.github.com>
2025-08-05 22:15:22 +04:00
silentoplayz bd570b7e2e fix: chat metadata wasn't being taken into consideration when cloning a chat
fix: chat metadata wasn't being taken into consideration when cloning a chat
2025-08-05 13:43:29 -04:00
Timothy Jaeryang Baek 53a328d00b refac: styling 2025-08-05 20:31:10 +04:00
Tim Jaeryang Baek f81964b412 Merge pull request #16295 from Jakobu5/cors-custom-scheme-patch
feat: add custom cors scheme option
2025-08-05 20:03:32 +04:00
Tim Jaeryang Baek 40c525b7b9 Merge pull request #16296 from itk-dev/feature/accessible-banner
feat: translate elements in banner for accessibility
2025-08-05 20:02:49 +04:00
psy42a f3b0f7d358 Fix syntax error where the previous use of :metadata::text in some sqlachamy/postgres versions doesn't bind at all
Fix syntax error where the previous use of :metadata::text in some sqlachamy/postgres versions doesn't bind the variable at all
2025-08-05 23:27:50 +10:00
Sine Jespersen 3494fa8707 aria hidden on svgs to hide them from assistive tech 2025-08-05 12:15:55 +02:00
Sine Jespersen e2b722deb2 translate elements in banner for accessibility 2025-08-05 11:18:56 +02:00
Jakob Hagl ae2a746d0c add custom cors scheme option 2025-08-05 10:38:08 +02:00
hiwylee 797822a3a3 add oracledb only
>      "moto[s3]>=5.0.26",
-
+    "oracledb>=3.2.0",
2025-08-04 16:03:29 +00:00
Tim Jaeryang Baek 66341124a6 Merge pull request #16009 from Classic298/patch-1
feat: add OAuth configuration warning for missing OPENID_PROVIDER_URL
2025-08-04 18:31:32 +04:00
Tim Jaeryang Baek 0b627248f5 Merge pull request #15640 from ipapapa/feat/cleaner-logs
refactor(logger): Conditionally include extra_json in logs
2025-08-04 17:52:12 +04:00
Timothy Jaeryang Baek 985e54b662 refac: styling 2025-08-04 17:51:22 +04:00
Tim Jaeryang Baek f41a8e67e8 Merge pull request #15705 from rgaricano/dev-HybridSearch-bm25_slider
FEAT: STYLE: Frontend HybridSearch-BM25 Slider
2025-08-04 17:48:24 +04:00
Timothy Jaeryang Baek 3f3a69568f enh: ability to sort folder chats 2025-08-04 17:37:33 +04:00
Tim Jaeryang Baek ae2de6b09c Merge pull request #16249 from silentoplayz/fix-richtext-getwordatdocpos
fix(frontend): Attempt to resolve TypeError in RichTextInput.svelte
2025-08-04 17:31:52 +04:00
Timothy Jaeryang Baek 173fa62af3 refac 2025-08-04 17:28:26 +04:00
Timothy Jaeryang Baek 88ff0b952e refac/fix: table markdown input 2025-08-04 17:27:28 +04:00
silentoplayz 55d3c07d85 revert: Reverts requested 2025-08-04 08:42:48 -04:00
Timothy Jaeryang Baek 2d2fbdb341 fix: styling 2025-08-04 16:02:48 +04:00
Timothy Jaeryang Baek e262069265 refac/fix: folder direct file upload 2025-08-04 15:33:44 +04:00
Timothy Jaeryang Baek 4c9ab7bd50 refac 2025-08-04 15:30:09 +04:00
Timothy Jaeryang Baek e8696c63fe refac 2025-08-04 15:23:43 +04:00
Tim Jaeryang Baek 5db60ca34f Merge pull request #15903 from Hisma/marker-api-update
feat: Add configurable API URL (for self-hosting) and additional_config parameter for Datalab Marker API
2025-08-04 15:21:03 +04:00
Timothy Jaeryang Baek 60c5ea1bcc enh: include chat id in feedback modal 2025-08-04 15:15:31 +04:00
Timothy Jaeryang Baek 7aeca7dee2 refac 2025-08-04 15:12:39 +04:00
Timothy Jaeryang Baek 8562e3e438 refac: styling 2025-08-04 15:04:16 +04:00
Tim Jaeryang Baek 6ce1166b98 Merge pull request #16033 from silentoplayz/sticky-search
refac: sticky headers & smarter pagination on users list page
2025-08-04 15:03:02 +04:00
Timothy Jaeryang Baek 35400daf19 enh/refac: redis cluster support 2025-08-04 14:15:08 +04:00
Tim Jaeryang Baek 01320d99d6 Merge pull request #16246 from silentoplayz/sensitiveinput-password-fields
feat: Add password visibility toggle to password fields with SensitiveInput.svelte component
2025-08-04 10:51:39 +04:00
silentoplayz 7a80e60785 fix(frontend): Attempt to resolve TypeError in RichTextInput.svelte
Fixes an issue where `ue.getWordAtDocPos is not a function` would be thrown in `MessageInput.svelte`.

The error was caused by a timing issue where the `getWordAtDocPos` method on the `RichTextInput` component was not available when called from an event handler within the same component.

This change refactors the code to pass the `getWordAtDocPos` function as a callback prop from `RichTextInput` to `MessageInput`, ensuring it's available when needed.
2025-08-03 22:36:08 -04:00
silentoplayz 56eeed6277 feat: Add password visibility toggle to password fields w SensitiveInput.svelte component 2025-08-03 16:07:12 -04:00
Tim Jaeryang Baek 7c29084a19 Merge pull request #16237 from expruc/chore/separate_otel_logs_config
chore: separate otel logs config
2025-08-03 21:08:55 +04:00
expruc 58180c0586 added otel lgos specific config 2025-08-02 22:15:22 +03:00
Timothy Jaeryang Baek 00084c6ca6 refac/fix: tool payload 2025-08-02 19:36:46 +04:00
Tim Jaeryang Baek f47a100730 Merge pull request #16231 from hadadarjt/dev
UserMenu: Fix quote typo in docs link.
2025-08-02 19:06:57 +04:00
Tim Jaeryang Baek a1fac8fc7f Merge pull request #16233 from andrewbbaek/dev
fix: add conditional password confirmation on signup
2025-08-02 19:06:14 +04:00
Andrew Baek c1ba289ab5 fix: add conditional password confirmation on signup
Password confirmation during signup is now only enforced if the 'enable_signup_password_confirmation' feature flag is enabled in the config. This allows for more flexible signup flows based on configuration.
2025-08-02 19:04:52 +04:00
Hadad ab140ea531 UserMenu: Fix quote typo in docs link.
* Docs link in the user menu are invalid when clicked via browser.

Signed-off-by: Hadad <hadad@linuxmail.org>
2025-08-02 20:21:41 +07:00
Tim Jaeryang Baek 09e475f6cc Merge pull request #16192 from expruc/feat/otel-logger-handler
feat: otel logger handler
2025-08-02 14:52:29 +04:00
Tim Jaeryang Baek 49926f06ee Merge branch 'dev' into feat/otel-logger-handler 2025-08-02 14:52:16 +04:00
Tim Jaeryang Baek e988750272 Merge pull request #16194 from ahangarha/patch-1
i18n:update fa translation
2025-08-02 14:49:47 +04:00
Tim Jaeryang Baek bf4e13e144 Merge pull request #16197 from open-webui/dependabot/pip/backend/dev/authlib-1.6.1
chore(deps): bump authlib from 1.4.1 to 1.6.1 in /backend
2025-08-02 14:01:11 +04:00
Tim Jaeryang Baek 9992dc98bb Merge pull request #16198 from open-webui/dependabot/pip/backend/dev/markdown-3.8.2
chore(deps): bump markdown from 3.7 to 3.8.2 in /backend
2025-08-02 14:01:04 +04:00
Tim Jaeryang Baek ea38d415ce Merge pull request #16199 from open-webui/dependabot/pip/backend/dev/fake-useragent-2.2.0
chore(deps): bump fake-useragent from 2.1.0 to 2.2.0 in /backend
2025-08-02 14:00:59 +04:00
Tim Jaeryang Baek 5855517a46 Merge pull request #16200 from open-webui/dependabot/pip/backend/dev/aiohttp-3.12.15
chore(deps): bump aiohttp from 3.11.11 to 3.12.15 in /backend
2025-08-02 14:00:53 +04:00
Tim Jaeryang Baek cf00df3b96 Merge pull request #16201 from open-webui/dependabot/pip/backend/dev/google-genai-1.28.0
chore(deps): bump google-genai from 1.15.0 to 1.28.0 in /backend
2025-08-02 14:00:48 +04:00
Timothy Jaeryang Baek 446f4ee5a8 refac 2025-08-02 13:59:07 +04:00
Tim Jaeryang Baek 093acb3724 Merge pull request #16222 from expruc/feat/seperate_otel_metrics_config
feat: separate otel metrics configuration
2025-08-02 13:57:10 +04:00
expruc a679fb3f45 split otel metrics from general otel configuration 2025-08-02 11:30:34 +03:00
Timothy Jaeryang Baek 994170b482 refac 2025-08-01 18:17:09 +04:00
Timothy Jaeryang Baek d4f70830d1 refac: markdown br rendering 2025-08-01 14:07:11 +04:00
dependabot[bot] 3098471a8a chore(deps): bump google-genai from 1.15.0 to 1.28.0 in /backend
Bumps [google-genai](https://github.com/googleapis/python-genai) from 1.15.0 to 1.28.0.
- [Release notes](https://github.com/googleapis/python-genai/releases)
- [Changelog](https://github.com/googleapis/python-genai/blob/main/CHANGELOG.md)
- [Commits](https://github.com/googleapis/python-genai/compare/v1.15.0...v1.28.0)

---
updated-dependencies:
- dependency-name: google-genai
  dependency-version: 1.28.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-01 02:27:15 +00:00
dependabot[bot] fce486fe30 chore(deps): bump aiohttp from 3.11.11 to 3.12.15 in /backend
---
updated-dependencies:
- dependency-name: aiohttp
  dependency-version: 3.12.15
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-01 02:26:36 +00:00
dependabot[bot] aee68aedb2 chore(deps): bump fake-useragent from 2.1.0 to 2.2.0 in /backend
Bumps [fake-useragent](https://github.com/fake-useragent/fake-useragent) from 2.1.0 to 2.2.0.
- [Release notes](https://github.com/fake-useragent/fake-useragent/releases)
- [Commits](https://github.com/fake-useragent/fake-useragent/compare/2.1.0...2.2.0)

---
updated-dependencies:
- dependency-name: fake-useragent
  dependency-version: 2.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-01 02:26:25 +00:00
dependabot[bot] 4b0bf3130b chore(deps): bump markdown from 3.7 to 3.8.2 in /backend
Bumps [markdown](https://github.com/Python-Markdown/markdown) from 3.7 to 3.8.2.
- [Release notes](https://github.com/Python-Markdown/markdown/releases)
- [Changelog](https://github.com/Python-Markdown/markdown/blob/master/docs/changelog.md)
- [Commits](https://github.com/Python-Markdown/markdown/compare/3.7...3.8.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-01 02:25:33 +00:00
dependabot[bot] 293cdb810e chore(deps): bump authlib from 1.4.1 to 1.6.1 in /backend
Bumps [authlib](https://github.com/authlib/authlib) from 1.4.1 to 1.6.1.
- [Release notes](https://github.com/authlib/authlib/releases)
- [Changelog](https://github.com/authlib/authlib/blob/main/docs/changelog.rst)
- [Commits](https://github.com/authlib/authlib/compare/v1.4.1...v1.6.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-01 02:25:17 +00:00
Adam M. Smith 414d026d59 fix: swap sqlcipher dependency to sqlcipher3-wheels 2025-07-31 23:21:35 +00:00
Adam M. Smith c9a4bc18f4 feat: Implement SQLCipher support for database encryption
- Added sqlcipher3 dependency to requirements.txt for SQLCipher integration.
- Modified database connection handling in wrappers.py to support encrypted SQLite databases using the new sqlite+sqlcipher:// URL protocol.
- Updated db.py to handle SQLCipher URLs for SQLAlchemy connections.
- Enhanced Alembic migration environment to support SQLCipher URLs.
2025-07-31 23:21:35 +00:00
Mostafa Ahangarha 4e64c3eca9 Update fa translation
Fix a mistake in translation
2025-08-01 00:33:09 +03:30
hiwylee bd215a1b96 Merge branch 'dev' into vector-search-branch 2025-08-01 04:23:38 +09:00
expruc 2035eabb1f added otel logging handler 2025-07-31 21:58:49 +03:00
hiwylee 0e640dd71e resolve conflict 2025-08-01 02:58:51 +09:00
Timothy Jaeryang Baek d2a3aacaba refac: styling 2025-07-31 19:00:43 +04:00
Timothy Jaeryang Baek 56af3e7357 refac: granular chat controls permissions 2025-07-31 18:59:37 +04:00
Timothy Jaeryang Baek 708e0ed05e refac/enh: chat controls permissions 2025-07-31 18:58:58 +04:00
Timothy Jaeryang Baek 84289b9a8d refac 2025-07-31 18:45:39 +04:00
Tim Jaeryang Baek b378ac1f57 Merge pull request #16186 from itk-dev/feature/user-menu-tab-order-and-menu-item-accessibility
FEAT: user menu tab order and menu item accessibility
2025-07-31 17:48:17 +04:00
Timothy Jaeryang Baek 6a17ba5b7a refac: metadata handling in vectordb 2025-07-31 17:45:06 +04:00
Sine Jespersen 3dc23368aa use bits-ui dropdownmenu item to make menu items focusable 2025-07-31 15:33:27 +02:00
Timothy Jaeryang Baek aa83ebae58 refac: lazySpanExporter no longer needed 2025-07-31 17:30:37 +04:00
Timothy Jaeryang Baek cb487d3f61 chore: otel bump 2025-07-31 17:19:37 +04:00
Timothy Jaeryang Baek 6b34b2c946 refac 2025-07-31 16:47:02 +04:00
Tim Jaeryang Baek 1f22e1d84c Merge pull request #16096 from gkkachi/dev
fix: properly handle full URLs in form_data.path
2025-07-31 16:45:48 +04:00
Timothy Jaeryang Baek b510f21a5b feat: signup confirm password 2025-07-31 16:43:37 +04:00
hiwylee 6b639cd42b Ignore yarnlock 2025-07-31 21:39:03 +09:00
Timothy Jaeryang Baek 1c83f48c45 refac 2025-07-31 16:27:20 +04:00
Timothy Jaeryang Baek d3547f0f54 refac: error handling 2025-07-31 16:17:33 +04:00
Timothy Jaeryang Baek 73b07df28f enh/refac: debounce chat draft save 2025-07-31 16:02:43 +04:00
Timothy Jaeryang Baek 05895d9657 refac/enh: allow underscore for prompt command 2025-07-31 15:55:10 +04:00
Tim Jaeryang Baek f1300a8fd9 Merge pull request #16178 from itk-dev/feature/hide-decorative-images-from-assistive-tech
Feature/hide decorative images from assistive tech
2025-07-31 15:30:20 +04:00
Tim Jaeryang Baek 22f9481e99 Merge pull request #16176 from itk-dev/feature/toggle-user-assistant-button-accessibility
FEAT: toggle user assistant button accessibility
2025-07-31 15:26:41 +04:00
Sine Jespersen 6434f1ec99 remove alt text on image for accessibility 2025-07-31 13:25:14 +02:00
Sine Jespersen eac359d6b4 aria-hidden on icon for accessibility 2025-07-31 13:25:07 +02:00
Sine Jespersen 343e41886f add aria-label and aria-pressed to toggle button for accessibility 2025-07-31 13:14:53 +02:00
Sine Jespersen 77babb6b63 add aria label, make alt text translatable 2025-07-31 10:32:32 +02:00
Sine Jespersen 30218a6db0 remove duplicate button in user menu to improve tab order 2025-07-31 10:32:15 +02:00
Timothy Jaeryang Baek 0763d8e9b9 refac: message input styling 2025-07-30 14:21:18 +04:00
Timothy Jaeryang Baek f027df06d1 fix: leaderboard loading issue 2025-07-30 14:18:36 +04:00
Timothy Jaeryang Baek 3ab10c6758 enh: follow up hover tooltip 2025-07-30 14:14:02 +04:00
Timothy Jaeryang Baek 73a38aca72 refac 2025-07-30 14:09:33 +04:00
Timothy Jaeryang Baek 22d98e6ee5 fix: playground styling 2025-07-30 14:06:42 +04:00
Tim Jaeryang Baek 00a00f5162 Merge pull request #16063 from silentoplayz/fix-her-theme
fix(frontend): Ensure 'Her' theme is always a light theme
2025-07-30 13:01:31 +04:00
Tim Jaeryang Baek 47d86d3c2f Merge pull request #16061 from silentoplayz/fix/autoscrolling-in-FloatingButtons
fix: prevent error when autoscrolling in FloatingButtons
2025-07-30 13:01:02 +04:00
Tim Jaeryang Baek 4cccb097f9 Merge pull request #16131 from open-webui/main
refac
2025-07-29 23:46:00 +04:00
Timothy Jaeryang Baek b8da4a8cd8 refac 2025-07-29 23:45:25 +04:00
silentoplayz 694494ad5e Revert "fix: should fix the "breaking change""
This reverts commit f1de837fef.
2025-07-29 09:33:17 -04:00
silentoplayz f1de837fef fix: should fix the "breaking change" 2025-07-29 09:29:26 -04:00
Timothy Jaeryang Baek 071a2ac835 fix: python format issue 2025-07-29 17:08:47 +04:00
Tim Jaeryang Baek 526a98171e Merge pull request #16077 from silentoplayz/delete-duplicate-SVGs
chore: Remove `ChatBubbleOvalEllipsis` and `Download` icon components (duplicates of `ChatBubble` and `ArrowDownTray`)
2025-07-29 16:53:42 +04:00
Tim Jaeryang Baek 1339d0059a Merge pull request #16123 from ShirasawaSama/locale_improve_chinese_i18n
i18n: improve chinese
2025-07-29 16:42:25 +04:00
Shirasawa ad785c46dc Update translation.json 2025-07-29 20:38:00 +08:00
Shirasawa 57452ad49e i18n: improve zh-CN 2025-07-29 20:35:14 +08:00
Tim Jaeryang Baek 97a788e4a3 Merge pull request #16109 from amoshydra/pwa-remove-orientation-member
fix: remove orientation specifier, respect OS level rotation
2025-07-29 16:24:24 +04:00
Tim Jaeryang Baek fd9b6d1193 Merge pull request #16117 from silentoplayz/fix-autocomplete-toggle
fix: "Autocomplete Generation" toggle would appear enabled breifly, even when disabled
2025-07-29 16:23:31 +04:00
Timothy Jaeryang Baek 1cbbdf7771 fix: user menu buttons 2025-07-29 16:15:23 +04:00
silentoplayz a63b447992 fix-autocomplete-toggle 2025-07-29 06:35:54 -04:00
Tim Jaeryang Baek cd6eb9a9e2 Merge pull request #16115 from silentoplayz/draggable-pinned-models
feat: allow draggable reorganization of pinned models in chat sidebar
2025-07-29 12:56:06 +04:00
Tim Jaeryang Baek b8edcd41f3 Merge pull request #16110 from qingchunnh/Update_zh-CN-25729
i18n: Improve zh-CN
2025-07-29 12:54:59 +04:00
silentoplayz 3243344a85 feat: allow draggable reorganization of pinned models 2025-07-29 04:37:29 -04:00
Timothy Jaeryang Baek 22d53be3a5 refac 2025-07-29 11:22:14 +04:00
qingchun bf0e7651fa i18n: Improve zh-CN 2025-07-29 12:21:27 +08:00
amoshydra 56a094a34a fix(pwa): remove orientation specifier, respect OS level rotation
Related to #13949
2025-07-29 05:48:15 +08:00
Timothy Jaeryang Baek 807c34b40c fix 2025-07-29 00:51:23 +04:00
Timothy Jaeryang Baek b2a04bac03 refac 2025-07-28 18:44:27 +04:00
Konosuke Kachi 0a8f482264 fix: properly handle full URLs in form_data.path 2025-07-28 23:34:23 +09:00
Timothy Jaeryang BaekandG30 f2da65b778 fix: hide community sharing button when disabled
Co-Authored-By: G30 <50341825+silentoplayz@users.noreply.github.com>
2025-07-28 17:42:45 +04:00
Tim Jaeryang Baek 58dbd869ba Merge pull request #16071 from GSAlex/main
fix: Render template variables in folder system prompts
2025-07-28 17:40:47 +04:00
Tim Jaeryang Baek 49a928d48c Merge pull request #16048 from silentoplayz/discovery-links-adjustment
chore: update discover links
2025-07-28 17:37:40 +04:00
Timothy Jaeryang Baek bcfb4d1e43 refac 2025-07-28 13:12:38 +04:00
Timothy Jaeryang Baek c1e4139e5c feat: model sync endpoint 2025-07-28 13:06:05 +04:00
Timothy Jaeryang Baek 49a6211d36 refac 2025-07-28 11:31:06 +04:00
Timothy Jaeryang Baek 0c5fbdedd8 refac 2025-07-28 11:09:48 +04:00
silentoplayz 84e568f902 remove: ArrowRightTag.svelte and used a transform 2025-07-27 20:43:17 -04:00
silentoplayz b633cb7c24 fix: last commit here, I swear! 2025-07-27 20:23:49 -04:00
silentoplayz eeccf23e4d fix: I thought this got pushed 2025-07-27 20:23:06 -04:00
silentoplayz a64b91e2e2 chore: remove-duplicate-icons 2025-07-27 20:13:53 -04:00
Yang Yang b52d28c94c fix: Render template variables in folder system prompts
Fixes #16019
2025-07-27 23:20:43 +08:00
silentoplayz c03741df93 fix(frontend): Ensure 'Her' theme is always a light theme
This commit fixes a bug where the 'Her' theme would switch to dark mode after a logout/login cycle. The issue was caused by two problems:

1. The `dark` class was being incorrectly added to the `documentElement` when the 'Her' theme was selected in `src/app.html`.
2. The `applyTheme` function in `src/lib/components/chat/Settings/General.svelte` was not explicitly setting the 'Her' theme as a light theme.

This commit resolves both of these issues, ensuring that the 'Her' theme is always a light theme.
2025-07-27 04:02:05 -04:00
silentoplayz 1d85729b4a fix: prevent error when autoscrolling in FloatingButtons 2025-07-27 03:07:28 -04:00
silentoplayz 2d130f3bec chore: adjust discover links 2025-07-26 17:32:55 -04:00
silentoplayz 67baecdc8e fix 2025-07-25 16:05:42 -04:00
silentoplayz 92fe7544c8 Sticky top bars for Leaderboard and UserList pages 2025-07-25 15:57:03 -04:00
Tim Jaeryang Baek 48d233abc6 Merge pull request #16011 from open-webui/main
refac: styling
2025-07-25 01:09:54 +04:00
Timothy Jaeryang Baek b8912aa671 refac: styling 2025-07-25 01:09:04 +04:00
Classic298 723840dad5 add warning if OPENID_PROVIDER_URL Is not set 2025-07-24 22:15:58 +02:00
Timothy Jaeryang Baek df7b5ec907 enh/refac: function sync endpoint 2025-07-24 23:44:43 +04:00
Tim Jaeryang Baek 3220088411 Merge pull request #16007 from open-webui/main
fix: otel yaml
2025-07-24 22:48:26 +04:00
Tim Jaeryang Baek dcade8cdf8 Merge pull request #15785 from bekzod/patch-1
BREAKING CHANGE: Update docling endpoint
2025-07-24 21:09:13 +04:00
Timothy Jaeryang Baek 9f5c905592 fix: max count should not apply to knowledge 2025-07-24 19:43:17 +04:00
Tim Jaeryang Baek da01021836 Merge pull request #15885 from Classic298/admin_export_user_csv
feat: Add button (for admins) to export all users in DB as csv file
2025-07-24 19:29:38 +04:00
Timothy Jaeryang Baek 626ad9c83d fix: otel yaml 2025-07-24 19:25:13 +04:00
Tim Jaeryang Baek 4179e7e4c7 Merge pull request #15942 from amoshydra/pin-pyarrow-20-rpi-compatibility
chore: pin pyarrow version to 20 for RPI compatibility
2025-07-24 19:07:26 +04:00
Timothy Jaeryang Baek 6c476ec939 refac 2025-07-24 18:54:51 +04:00
Timothy Jaeryang Baek 7a97c25fa7 refac 2025-07-24 18:54:15 +04:00
Timothy Jaeryang Baek 274a65903b fix: otel.yaml 2025-07-24 18:53:04 +04:00
Tim Jaeryang Baek af45dfd002 Merge pull request #15980 from sihyeonn/feat/sh-share-connectionpool
feat: Reuse Redis Connection Pools to Eliminate Connection & IP Exhaustion
2025-07-24 18:38:39 +04:00
Sihyeon Jang f59da361f1 feat: Re-use Redis connection pools via local cache to prevent transient exhaustion
Every call to get_redis_connection() spawned a new pool, so workers slowly accumulated thousands of open sockets. Even though connections were eventually released, skewed release timing still pushed us past Redis’ max-clients and the cluster egress IP cap.

A module-level _CONNECTION_CACHE now memoises pools by (redis_url, sentinel_hosts, async_mode, decode_responses).

Result: flat connection count, no more IP or FD exhaustion. Public API unchanged.

Signed-off-by: Sihyeon Jang <sihyeon.jang@navercorp.com>
2025-07-24 18:44:42 +09:00
Tim Jaeryang Baek 78754fbe96 Merge pull request #15960 from itk-dev/feature/more-danish-translations
i18n: Danish translations (missing)
2025-07-23 20:15:40 +04:00
Jesper Kristensen 347e4dd73d Added missing danish translations 2025-07-23 11:35:52 +02:00
Tim Jaeryang Baek 4a3935ef9a Merge pull request #15935 from rgaricano/dev_FIX-transcription_language
FIX: STT default whisper trascription language
2025-07-23 12:20:08 +04:00
Tim Jaeryang Baek 4d93ad4474 Merge pull request #15941 from taylorwilsdon/tasks_redis_key_prefix
fix: Implement outstanding REDIS_KEY_PREFIX declarations
2025-07-23 12:18:03 +04:00
Timothy Jaeryang Baek ffa8ad0a22 refac: azure url detection 2025-07-23 12:15:02 +04:00
Tim Jaeryang Baek f44812b1a8 Merge pull request #15946 from rgaricano/dev_es-ES
i18n:UPD: Locale es-ES translation, updated to v.0.6.18
2025-07-23 12:02:34 +04:00
Tim Jaeryang Baek bd18bf5c83 Merge pull request #15951 from 0xThresh/s3vector-support
feat: Add S3 Vector Buckets Support for Knowledge
2025-07-23 12:02:20 +04:00
_00_ fc9d19e814 Update translation.json -Removed added strings
Removed added strings because are innecessary for autogenerating flow.
2025-07-23 09:22:48 +02:00
_00_ 86736a7817 Update translation.json REORDER STRING
REORDER STRING
2025-07-23 09:04:23 +02:00
_00_ 7a0b55758d Update translation.json - reorder strings
reorder strings
2025-07-23 09:01:26 +02:00
_00_ ab8e54dd29 Update audio.py Fix Format error
Fix Format error
2025-07-23 08:49:00 +02:00
_00_ 51758c429b Update audio.py - fix FORMAT error
Fix  FORMAT error
2025-07-23 08:45:10 +02:00
_00_ e71177f776 Merge branch 'dev' into dev_es-ES 2025-07-23 08:34:32 +02:00
0xThresh.eth 860f3b3cab chore: run formatting 2025-07-22 22:46:00 -06:00
0xThresh.eth 8dcf668448 chore: final cleanup 2025-07-22 22:37:57 -06:00
Richard Meyer 9590897f3a Merge branch 'open-webui:main' into marker-api-update 2025-07-23 00:35:48 -04:00
Hisma 216c991c01 move api key below url 2025-07-23 00:32:18 -04:00
0xThresh.eth 6c283cdd93 fix: boto3 version in uv.lock 2025-07-22 21:40:52 -06:00
0xThresh.eth d463a29ba1 feat: S3 vector support tested 2025-07-22 21:36:35 -06:00
Hisma 21337a2fd8 ci fix 2025-07-22 22:07:14 -04:00
Hisma a99e20cc3d add format_lines 2025-07-22 21:06:29 -04:00
Hisma f31cc07a9d feat: update marker api 2025-07-22 20:49:28 -04:00
_00_ 41ce1b5b28 i18n:UPD: Locale es-ES translation, updated to v.0.6.18
UPDATE i18n locale es-ES translation, updated to v.0.6.18.

Added translation of new strings
2025-07-23 01:38:34 +02:00
Timothy Jaeryang Baek 8da08ad73a refac: chat item edit title behaviour 2025-07-22 23:44:10 +04:00
Timothy Jaeryang Baek c03b574ef6 refac/fix 2025-07-22 23:39:33 +04:00
amoshydra b778bcd8e6 chore: pin pyarrow version to 20 for rpi compatibility
fix: #15897
2025-07-23 02:22:45 +08:00
Taylor Wilsdon 65654a3b4c fix last key prefix 2025-07-22 13:42:38 -04:00
Taylor Wilsdon 3e686e9915 implement redis_key_prefix env support in all areas invoking redis to allow for clustermode compatibility with new docs function 2025-07-22 13:40:29 -04:00
_00_ 0613563644 FIX: STT default whisper trascription language
FIX: STT default whisper trascription language

Fix the transcripcion language used by default whisper, setting as WHISPER_LANGUAGE if it is setted in env var, even if a language is detected in the file's metadata.
It is understood that if a language is set as an environment variable for transcriptions, this should be the preferred one and the one that should be used for that purpose.

It would be advisable to add this variable as configurable in UI
2025-07-22 16:47:06 +02:00
Timothy Jaeryang Baek d21a2581a6 refac/fix: title generation button issue 2025-07-22 17:31:01 +04:00
Timothy Jaeryang Baek 8bc7d85eac refac 2025-07-22 17:17:26 +04:00
Tim Jaeryang Baek dfdf94483b Merge pull request #15921 from expruc/feat/allow_admins_handle_feedbacks
fix: allow admins to get and post on feedbacks (avoid 404 errors)
2025-07-22 14:43:59 +04:00
Timothy Jaeryang Baek bf3c807047 refac 2025-07-22 11:38:47 +04:00
Timothy Jaeryang Baek ac0932f356 refac: styling 2025-07-22 11:22:01 +04:00
Timothy Jaeryang Baek 496ea40d1d refac: model item tag styling 2025-07-22 11:19:40 +04:00
0xThresh.eth f6ee1965cb merge main 2025-07-21 18:06:17 -06:00
expruc 1ff2ad0c08 ci fix 2025-07-21 22:17:08 +03:00
expruc 14c6f8bf80 added a check for admins to avoid 404 errors on feedbacks get and post 2025-07-21 21:18:37 +03:00
Timothy Jaeryang Baek d8b80caff3 refac/fix: remove insecure arg for otel http exporter 2025-07-21 16:35:23 +04:00
Timothy Jaeryang Baek a26607c720 refac: styling 2025-07-21 13:06:34 +04:00
Tim Jaeryang Baek 1e2ae1da1d Merge pull request #15888 from macnow/patch-2
i18n: update for polish translation
2025-07-21 10:57:02 +04:00
Tim Jaeryang Baek e95a93d80b Merge pull request #15894 from qingchunnh/Update_zh-CN-25721
i18n: Update & Improve & Fix zh-CN
2025-07-21 10:53:53 +04:00
qingchun 8f655ec0a6 i18n: Fix zh-CN 2025-07-21 06:59:12 +08:00
qingchun fa3c3c2443 i18n: Update & Improve & Fix zh-CN 2025-07-21 06:52:46 +08:00
0xThresh.eth 5c59c50e2d more prgoress on s3 vector 2025-07-20 16:48:23 -06:00
Maciej Nowakowski 58cbf5aba2 Update for Polish translation 2025-07-20 14:30:53 +02:00
Classic298 3acd286791 Merge branch 'dev' into admin_export_user_csv 2025-07-20 13:17:59 +02:00
Timothy Jaeryang Baek 24805ca79e refac/fix: channel messages 2025-07-20 15:17:17 +04:00
Timothy Jaeryang Baek ed20f2ea5f fix: dev.sh 2025-07-20 15:10:54 +04:00
Timothy Jaeryang Baek 40ebf8cd62 refac: memory handling 2025-07-20 15:00:24 +04:00
Tim Jaeryang Baek 521d223f05 Merge pull request #15883 from aleixdorca/dev
i18n: Update catalan translation.json
2025-07-20 14:14:57 +04:00
Classic298 a2aa68c84a Update Database.svelte 2025-07-20 11:16:08 +02:00
Classic298 74140ea251 Update Database.svelte 2025-07-20 11:12:38 +02:00
Classic298 84f7a55753 remove slash 2025-07-20 11:04:40 +02:00
Classic298 0d1b06d87c Update Database.svelte 2025-07-20 10:52:47 +02:00
Aleix Dorca 28d54f87f1 Update catalan translation.json 2025-07-20 06:51:10 +02:00
Tim Jaeryang Baek 5fbfe2bdca Merge pull request #15879 from open-webui/dev
0.6.18
2025-07-19 23:26:01 +04:00
Timothy Jaeryang Baek 6e0328798d chore: format 2025-07-19 23:23:54 +04:00
Tim Jaeryang Baek 0119036a11 Merge pull request #15871 from Classic298/cors
Enh: dev.sh default port export
2025-07-19 23:20:52 +04:00
Tim Jaeryang Baek 7a023e0841 Merge pull request #15875 from leebeomhun/i18n-ko
i18n: update and fix ko-KR translation
2025-07-19 23:20:29 +04:00
Timothy Jaeryang Baek b397008ee0 doc: changelog 2025-07-19 23:20:14 +04:00
Timothy Jaeryang Baek b329c63c80 refac 2025-07-19 23:17:14 +04:00
Timothy Jaeryang Baek 95b11207a1 fix: group user load 2025-07-19 23:16:44 +04:00
BHLee 74d0e6b2c7 i18n korean Fix typo 2025-07-20 04:10:26 +09:00
BHLee 7ffc12567f i18n update and fix:ko-KR translation.json 2025-07-20 03:46:37 +09:00
Classic298 d8ed4fa0c2 Merge branch 'open-webui:main' into cors 2025-07-19 19:53:13 +02:00
Classic298 549294ee30 Update dev.sh 2025-07-19 19:43:08 +02:00
Tim Jaeryang Baek b249809d2d Merge pull request #15738 from open-webui/dev
0.6.17
2025-07-19 21:39:46 +04:00
Timothy Jaeryang Baek a01e5126a3 refac 2025-07-19 21:34:38 +04:00
Timothy Jaeryang Baek c100442102 refac: compress image 2025-07-19 21:27:37 +04:00
Timothy Jaeryang Baek 32c85c59b1 refac 2025-07-19 21:22:12 +04:00
Timothy Jaeryang Baek 699c8073ff refac 2025-07-19 21:20:28 +04:00
Tim Jaeryang Baek 6f0def4ee3 Merge pull request #15869 from Classic298/patch-7
enh: Update CHANGELOG.md
2025-07-19 21:15:59 +04:00
Classic298 55d0534977 Update CHANGELOG.md 2025-07-19 19:13:46 +02:00
Classic298 9c82070ed9 Update CHANGELOG.md 2025-07-19 19:13:03 +02:00
Classic298 6bfe16367b Update CHANGELOG.md 2025-07-19 19:11:40 +02:00
Classic298 fb916087be Update CHANGELOG.md 2025-07-19 19:07:39 +02:00
Classic298 418a58674f Update CHANGELOG.md 2025-07-19 18:27:18 +02:00
Timothy Jaeryang Baek 4628097df9 doc: changelog 2025-07-19 19:51:47 +04:00
Timothy Jaeryang Baek 1159f3a781 enh: add folder modal 2025-07-19 19:46:35 +04:00
Timothy Jaeryang Baek a638a187bb refac 2025-07-19 19:32:52 +04:00
Timothy Jaeryang Baek 44a23a5c99 chore 2025-07-19 19:20:14 +04:00
Timothy Jaeryang Baek 08ff9863d5 refac 2025-07-19 19:15:05 +04:00
Timothy Jaeryang Baek d9a3b02e3f refac 2025-07-19 19:03:01 +04:00
Timothy Jaeryang Baek 53d94d6f61 enh: link prompt variable doc 2025-07-19 19:00:49 +04:00
Timothy Jaeryang Baek 81f8187e57 chore: format 2025-07-19 18:57:59 +04:00
Timothy Jaeryang Baek 4364dac226 refac 2025-07-19 18:20:17 +04:00
Timothy Jaeryang Baek 6362845065 refac 2025-07-19 18:12:16 +04:00
Timothy Jaeryang Baek 2db9d6b5d2 enh: disable edit button during generation 2025-07-19 18:08:58 +04:00
Timothy Jaeryang Baek 71ee33bf82 enh: search chat preview 2025-07-19 18:06:59 +04:00
Timothy Jaeryang Baek c94ce71ca3 refac 2025-07-19 16:44:28 +04:00
Timothy Jaeryang Baek 3af2938efc enh: note selection edit support 2025-07-19 16:35:03 +04:00
Tim Jaeryang Baek e35f7748f6 Merge pull request #15861 from tcx4c70/feat/log/trace_info
feat(logger): Add trace_id and span_id to log
2025-07-19 14:52:48 +04:00
Timothy Jaeryang Baek 157daa6def enh: allow direct file upload to knowledge attachment 2025-07-19 14:50:36 +04:00
Adam Tao 739098ab60 feat(logger): Add trace_id and span_id to log
Signed-off-by: Adam Tao <tcx4c70@gmail.com>
2025-07-19 18:36:54 +08:00
Timothy Jaeryang Baek 37c2fb0aa8 enh: folders 2025-07-19 14:29:08 +04:00
Timothy Jaeryang Baek 3251f8b14d refac 2025-07-19 12:44:23 +04:00
Timothy Jaeryang Baek ea18ffdade refac/fix 2025-07-19 12:17:35 +04:00
Tim Jaeryang Baek 2d4675dc1c Merge pull request #15842 from expruc/fix/handle_remove_files_from_vdb
fix: deleting files from vector DB upon file deletion
2025-07-19 12:13:03 +04:00
expruc 30a079cba8 added handler for deleting files from vdb upon files deletion 2025-07-18 18:40:29 +03:00
Timothy Jaeryang Baek 6478a50c72 refac 2025-07-18 18:26:43 +04:00
Timothy Jaeryang Baek c414f0c3ce enh: follow up prompts behaviour 2025-07-18 17:49:24 +04:00
Timothy Jaeryang Baek 5e4e1cf662 refac 2025-07-18 16:57:49 +04:00
Timothy Jaeryang Baek 18adb28da0 enh: chatFadeStreamingText toggle 2025-07-18 16:45:56 +04:00
Timothy Jaeryang Baek 853cf82ed8 enh: text fade in effect 2025-07-18 16:38:43 +04:00
Timothy Jaeryang Baek dcb1c0a146 refac 2025-07-18 16:22:49 +04:00
Timothy Jaeryang Baek c1c589d609 refac/enh: rich text input 2025-07-18 15:58:06 +04:00
Tim Jaeryang Baek 032fa52190 Merge pull request #15833 from rgaricano/dev-audio_Mime_comment
FIX: Correction of mimetypes string
2025-07-18 15:20:22 +04:00
Timothy Jaeryang Baek 671f577264 feat/enh: forward chat id in header 2025-07-18 15:03:46 +04:00
_00_ f08f6ac171 FIX: Correction of mimetypes string
Removed " , * for all) " from mimetype help string.

If mimetypes is set as * any file is tried to transcribe.
2025-07-18 12:54:08 +02:00
Tim Jaeryang Baek a395abd5d7 Merge pull request #15794 from expruc/feat/otel_user_metrics
feat: open telemetry user metrics
2025-07-18 14:22:21 +04:00
Tim Jaeryang Baek 25c3e7f851 Merge pull request #15810 from rgaricano/dev-Fix_AddPostHog_lib
FIX: Add posthog lib forcing version to avoid opentelemetry issue
2025-07-18 14:21:58 +04:00
Tim Jaeryang Baek 6bb5248812 Merge pull request #15789 from azurewtl/hotfix-web-config-clean-reranker
- fix: keep reranker_model config been removed by web search config
2025-07-18 13:00:40 +04:00
Tim Jaeryang Baek 3500d26931 Merge pull request #15825 from EventHorizon-AI/fix/ollama-tool-call
fix: ollama tool call
2025-07-18 12:58:07 +04:00
Tim Jaeryang Baek 0d3f066afc Merge pull request #15824 from zetavg/update-zh-tw-translation-0718
i18n: Update & fix zh-TW translation
2025-07-18 12:56:49 +04:00
Timothy Jaeryang Baek bcee131971 refac/fix: note chat permissions issue 2025-07-18 12:55:08 +04:00
Timothy Jaeryang Baek 3e67ce6e8e refac/fix: shortcut modal 2025-07-18 12:47:22 +04:00
Timothy Jaeryang Baek 43e11aa807 refac 2025-07-18 12:41:21 +04:00
Timothy Jaeryang Baek 2fa8aff82f refac/fix: tag handling 2025-07-18 11:56:40 +04:00
Timothy Jaeryang Baek 6ccf783f00 refac: /users/all endpoint 2025-07-18 11:46:14 +04:00
Pokai Chang bb19b71e39 i18n: Update & fix zh-TW translation 2025-07-18 06:50:03 +08:00
EntropyYue 260137fc12 fix: ollama tool call 2025-07-18 06:11:53 +08:00
Tim Jaeryang Baek 67bc431247 Merge pull request #15798 from MonsieurBibo/i18n-fr
feat(i18n): Add missing translations to fr-FR locale
2025-07-18 02:11:01 +04:00
Timothy Jaeryang Baek 86e46ebe6a chore 2025-07-17 17:53:36 +04:00
Timothy Jaeryang Baek d4ece7384c enh/refac: note image upload 2025-07-17 17:36:06 +04:00
Timothy Jaeryang Baek 9d633b062b refac/fix 2025-07-17 16:25:26 +04:00
Timothy Jaeryang Baek da91aba10f chore: tiptap bump 2025-07-17 14:43:42 +04:00
_00_ ca1a61ce60 Fix: Add posthog lib to requirement for avoid opentelemetry issue
Add "posthog==5.4.0" lib to requirements to avoid chromadb issue for lib versions incompatibility with that lib (chromadb  requiere posthog>=2.4.0,<6.0.0 ) which produce error in opentelemetry.
2025-07-17 10:15:18 +02:00
_00_ 5a0d0c6930 FIX: Add posthog lib to avoid opentelemetry issue
Add "posthog==5.4.0" lib to requirements to avoid chromadb issue for lib versions incompatibility with that lib (chromadb  requiere posthog>=2.4.0,<6.0.0 ) which produce error in opentelemetry.
2025-07-17 10:12:37 +02:00
Timothy Jaeryang Baek fce27202d9 refac 2025-07-17 02:37:18 +04:00
Timothy Jaeryang Baek 9634df4347 refac/enh: group add/remove users endpoints 2025-07-17 01:50:37 +04:00
MonsieurBibo 2e59d47e7d feat(i18n): Add missing translations to fr-FR locale
Completes various previously untranslated UI strings in the French translation file.
2025-07-16 22:25:14 +02:00
expruc cbbc4cfd26 added active and total user metrics 2025-07-16 22:06:36 +03:00
Timothy Jaeryang Baek 51242f4484 refac/fix 2025-07-16 22:22:59 +04:00
Azure Wang 9aff166f83 - fix: keep reranker_model config been removed by web search config 2025-07-16 23:51:23 +08:00
bekzod 4bc054a347 Update docling endpoint 2025-07-16 20:40:13 +05:00
Timothy Jaeryang Baek 4f5d949af6 enh: OAUTH_TOKEN_ENDPOINT_AUTH_METHOD 2025-07-16 15:46:33 +04:00
Timothy Jaeryang Baek 19f1286cc7 fix: emoji call 2025-07-16 15:38:48 +04:00
Timothy Jaeryang Baek 82093cf690 refac/fix: disable file upload by drag with unsupported model 2025-07-16 15:25:56 +04:00
Timothy Jaeryang Baek 83c09f15ac refac/enh: reasoning tag handling 2025-07-16 15:20:03 +04:00
Timothy Jaeryang Baek 980b7c55a5 refac/fix: sources handling 2025-07-16 15:12:04 +04:00
Timothy Jaeryang Baek 8807ac8cac refac/enh: file upload with paste 2025-07-16 15:01:03 +04:00
Timothy Jaeryang Baek 20b6892d9b refac: chat exception handling 2025-07-16 14:54:56 +04:00
Tim Jaeryang Baek 5832c3ea97 Merge pull request #15718 from sihyeonn/feat/sh-support-failover
feat: add Redis Sentinel failover support for high availability
2025-07-16 14:39:42 +04:00
Tim Jaeryang Baek ff8c429687 Merge pull request #15749 from Classic298/patch-1
i18n: small german updates
2025-07-16 13:58:04 +04:00
Timothy Jaeryang Baek abe280f0a3 refac/fix: reranking function 2025-07-16 13:56:02 +04:00
Sihyeon Jang 9067eac4ca chore: add log for redis.exceptions
Signed-off-by: Sihyeon Jang <sihyeon.jang@navercorp.com>
2025-07-16 15:23:18 +09:00
Sihyeon Jang 65882c30cb refactor: change MAX_RETRY_COUNT as env
Signed-off-by: Sihyeon Jang <sihyeon.jang@navercorp.com>
2025-07-16 15:23:18 +09:00
Sihyeon Jang 1b7ac7c739 chore: format, lint
Signed-off-by: Sihyeon Jang <sihyeon.jang@navercorp.com>
2025-07-16 15:23:18 +09:00
Sihyeon Jang 5fe0c835b1 chore: update lock file for pytest-asyncio
Signed-off-by: Sihyeon Jang <sihyeon.jang@navercorp.com>
2025-07-16 15:23:18 +09:00
Sihyeon Jang 728c39eed7 chore: add tests with pytest-asyncio
Signed-off-by: Sihyeon Jang <sihyeon.jang@navercorp.com>
2025-07-16 15:23:18 +09:00
Sihyeon Jang 423d0923d9 feat: add Redis Sentinel failover support for high availability
- Implement SentinelRedisProxy class with automatic master discovery
- Add retry logic for handling connection failures and read-only errors
- Support both async and sync Redis operations with Sentinel
- Ensure backward compatibility with existing Redis configurations
- Provide seamless failover during master node outages

This enhancement significantly improves system reliability by eliminating
single points of failure in Redis deployments and ensuring continuous
service availability during infrastructure issues.

Signed-off-by: Sihyeon Jang <sihyeon.jang@navercorp.com>
2025-07-16 15:23:17 +09:00
0xThresh.eth d9f2b6b14e feat: add starter config for s3 vector 2025-07-15 21:20:54 -06:00
Classic298 5b73f5065b i18n: small german updates 2025-07-15 21:34:49 +02:00
Tim Jaeryang Baek ae716bddee Merge pull request #15717 from sihyeonn/fix/sh-cleanup
fix: improve cleanup_response positioning for better resource management
2025-07-15 22:48:10 +04:00
Timothy Jaeryang Baek 500e6e64fe refac 2025-07-15 21:57:24 +04:00
Tim Jaeryang Baek 1f0cc2724a Merge pull request #15743 from byg1004/dev
fix: i18n korean
2025-07-15 21:43:27 +04:00
YG aea1a27f2f fix: i18n korean 2025-07-15 21:42:02 +04:00
Timothy J. Baek cecb3a42b0 refac 2025-07-15 21:24:05 +04:00
Timothy J. Baek fa91795b77 refac 2025-07-15 20:59:28 +04:00
Tim Jaeryang Baek 0aabbdd23a Merge pull request #15714 from macnow/patch-1
Update pl_PL locale
2025-07-15 20:50:02 +04:00
Tim Jaeryang Baek e03925ffc0 Merge pull request #15729 from rgaricano/dev-issues_15728
Fix: some FileItemModal.svelte strings to i18n
2025-07-15 20:49:34 +04:00
Tim Jaeryang Baek 2d46cc6d97 Merge pull request #15736 from ryanmrodriguez/ryanmrodriguez-patch-1
fix: DB Environment - Avoid Duplicate '@' Symbol in Credentials
2025-07-15 20:47:47 +04:00
Timothy J. Baek 14ef2e5dea refac: collaborative editor 2025-07-15 20:43:49 +04:00
Ryan Rodriguez 74392f4598 Avoid duplicate @ 2025-07-15 10:42:41 -05:00
Timothy Jaeryang Baek 6343f4293a refac 2025-07-15 18:45:59 +04:00
Timothy Jaeryang Baek e72da0df5a refac/fix: WEBSOCKET_REDIS_LOCK_TIMEOUT type 2025-07-15 18:10:36 +04:00
Timothy Jaeryang Baek f7fae947a7 fix/refac: hide system prompt for users w/o permission 2025-07-15 16:52:21 +04:00
_00_ 120b8f2a83 fix: update FileItemModal.svelte- locales strings
add strings "Using Entire Document" and "Using Focused Retrieval"  to i18n locales,

to address issue: #15728
2025-07-15 14:05:10 +02:00
_00_ 1092827895 Fix some FileItemModal.svelte- locales strings
convert strings "Using Entire Document" and "Using Focused Retrieval"  to i18n locales,

to address issue: https://github.com/open-webui/open-webui/issues/15728
2025-07-15 13:55:49 +02:00
Sihyeon Jang 058369adea fix: improve cleanup_response positioning for better resource management
Signed-off-by: Sihyeon Jang <sihyeon.jang@navercorp.com>
2025-07-15 10:14:30 +09:00
Sihyeon Jang 17f0bef2e2 refactor: use cleanup_response on openai
Signed-off-by: Sihyeon Jang <sihyeon.jang@navercorp.com>
2025-07-15 10:11:22 +09:00
Maciej Nowakowski 07bb5cc4aa Update pl_PL locale 2025-07-14 23:48:15 +02:00
_00_ 5889e8238a UPD: BM25 Hybrid Slider - Legend inline
BM25 Hybrid Slider - Legend (lexical - semantic) inline
2025-07-14 22:17:37 +02:00
Tim Jaeryang Baek 9063942055 Merge pull request #15712 from qingchunnh/Update_zh-CN-25715-2
i18n: Fix zh-CN
2025-07-14 23:58:39 +04:00
_00_ 3345514efc UPD: en-EN locales add lexical, semantic & fix previous incomplete
en-EN locales add lexical, semantic & fix previous incomplete
2025-07-14 21:23:35 +02:00
_00_ fd735590da UPD: Add lexical-semantic reference above slider
Add lexical-semantic reference above slider
2025-07-14 21:20:11 +02:00
qingchun 8a4ea2b801 i18n: Fix zh-CN 2025-07-15 03:18:12 +08:00
_00_ cd554ebce5 UPD: Add Weight BM25 Hybrid Search string
UPD: Add Weight BM25 Hybrid Search string
to fit with tooltip of new slider in PR: https://github.com/open-webui/open-webui/pull/15705
"The Weight of BM25 Hybrid Search. 0 more lexical, 1 more semantic. Default 0.5"
2025-07-14 20:19:06 +02:00
Tim Jaeryang Baek 2470da8336 Merge pull request #15708 from open-webui/dev
fix/refac: icon styling
2025-07-14 22:02:36 +04:00
Timothy Jaeryang Baek 9b6dd59b86 fix/refac: icon styling 2025-07-14 22:02:14 +04:00
Tim Jaeryang Baek f966935d1d Merge pull request #15448 from open-webui/dev
0.6.16
2025-07-14 21:39:26 +04:00
Timothy Jaeryang Baek 045984e86f doc: changelog 2025-07-14 21:25:00 +04:00
Timothy Jaeryang Baek b1752cfb6a refac: styling 2025-07-14 21:24:31 +04:00
Tim Jaeryang Baek 21eff61940 Merge pull request #15707 from Classic298/patch-1
fix: the changelog
2025-07-14 21:21:47 +04:00
Classic298 4897cfa9c8 rem backticks and md tags 2025-07-14 19:21:08 +02:00
Tim Jaeryang Baek f79746b148 Merge pull request #15706 from qingchunnh/Update_zh-CN-25715
i18n: Update zh-CN
2025-07-14 21:20:26 +04:00
Classic298 ebd2abdd0a Update CHANGELOG.md 2025-07-14 19:17:16 +02:00
Classic298 69fd8436aa Update CHANGELOG.md 2025-07-14 18:52:07 +02:00
Classic298 7063d7d103 Update CHANGELOG.md 2025-07-14 18:42:53 +02:00
Classic298 541f7bc82c Update CHANGELOG.md 2025-07-14 18:32:57 +02:00
qingchun ed8438628e i18n: Update zh-CN 2025-07-15 00:14:28 +08:00
Timothy Jaeryang Baek 288fba874e refac: styling 2025-07-14 20:08:49 +04:00
Timothy Jaeryang Baek 8f5d23ec37 refac 2025-07-14 19:57:41 +04:00
Timothy Jaeryang Baek d5b8acfbe7 chore: dep bump pyproject 2025-07-14 19:53:06 +04:00
Timothy Jaeryang Baek 50ed194c48 doc: changelog 2025-07-14 19:51:12 +04:00
_00_ 4a6d333a03 FEAT: Frontend HybridSearch-BM25 Slider
FEAT: Frontend HybridSearch-BM25 Slider

Front-end modification for the BM25-Weight parameter input.

This proposal modifies the numerical typed input to a slider similar to the advanced model parameters.
2025-07-14 17:48:49 +02:00
Timothy Jaeryang Baek 8b8ce2592d refac: styling 2025-07-14 19:34:40 +04:00
Timothy Jaeryang Baek 493e147be6 chore: format 2025-07-14 19:13:54 +04:00
Timothy Jaeryang Baek 51691adcbc refac 2025-07-14 19:12:17 +04:00
Timothy Jaeryang Baek 6a4542a321 refac: folder delete 2025-07-14 19:09:54 +04:00
Timothy Jaeryang Baek 92c9068369 refac 2025-07-14 17:50:03 +04:00
Timothy Jaeryang Baek f19d5b05a8 refac: styling 2025-07-14 17:47:21 +04:00
Timothy Jaeryang Baek 7f1f39058a enh/refac: distributed crdt 2025-07-14 17:14:56 +04:00
Timothy Jaeryang Baek fb71a4106f refac 2025-07-14 16:45:30 +04:00
Timothy Jaeryang Baek d76a3d5ce2 refac: ydoc 2025-07-14 16:29:42 +04:00
Timothy Jaeryang Baek 203c5b1956 refac 2025-07-14 14:37:28 +04:00
Timothy Jaeryang Baek f402957f05 refac 2025-07-14 14:35:13 +04:00
Timothy Jaeryang Baek 18bd83413b refac 2025-07-14 14:05:06 +04:00
Timothy Jaeryang Baek 0013f5c1fc refac/enh: forward user info header to reranker 2025-07-14 13:59:10 +04:00
Timothy Jaeryang Baek b4f04ff3a7 enh/refac: pgvector pool support 2025-07-14 12:18:44 +04:00
Timothy Jaeryang Baek 9c49d9e641 refac: aria label model item 2025-07-14 12:09:08 +04:00
Tim Jaeryang Baek c067cf996e Merge pull request #15687 from Classic298/patch-1
i18n: german translations
2025-07-14 10:12:19 +04:00
Tim Jaeryang Baek d87d6f99d3 Merge pull request #15692 from qingchunnh/Update_zh-CN-25714
i18n: Update & Improve & Fix zh-CN
2025-07-14 10:12:07 +04:00
Tim Jaeryang Baek a03bdba711 Merge pull request #15685 from rgaricano/dev-add_requirements_lib
UPD: requirements.txt adding httpx & optionals
2025-07-14 10:11:27 +04:00
Dieu 41faec758b Merge branch 'dev' into feat/scim-2.0-support 2025-07-14 00:48:50 +02:00
Dieu 6469822af1 Update configs.py 2025-07-14 00:44:25 +02:00
Dieu 519b7af6d8 remove useless 2025-07-14 00:36:14 +02:00
Dieu 1d9c1f741d Update scim.py 2025-07-13 23:54:33 +02:00
Dieu c9fda793e2 udpate 2025-07-13 23:42:33 +02:00
Dieu 39bcee3f7b remove ui config 2025-07-13 23:24:32 +02:00
qingchun 6649201fe5 i18n: Fix zh-CN 2025-07-14 02:07:09 +08:00
qingchun e89e0dea4a i18n: Improve zh-CN 2025-07-14 01:56:57 +08:00
qingchun 6ee0c0411e i18n: Update & Improve zh-CN 2025-07-14 01:45:22 +08:00
DieuandClaude f4d54c518e feat: Add SCIM 2.0 support for enterprise user provisioning
Implements SCIM 2.0 protocol for automated user and group provisioning from identity providers like Okta, Azure AD, and Google Workspace.

Backend changes:
- Add SCIM configuration with PersistentConfig for database persistence
- Implement SCIM 2.0 endpoints (Users, Groups, ServiceProviderConfig)
- Add bearer token authentication for SCIM requests
- Include comprehensive test coverage for SCIM functionality

Frontend changes:
- Add SCIM admin settings page with token generation
- Implement SCIM configuration management UI
- Add save functionality and proper error handling
- Include SCIM statistics display

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-13 16:34:41 +02:00
Timothy Jaeryang Baek 8e7731f139 refac: styling 2025-07-13 14:10:35 +04:00
Classic298 30fd6822f8 i18n: german translations 2025-07-13 12:08:58 +02:00
Timothy Jaeryang Baek a123629f74 refac 2025-07-13 14:08:19 +04:00
_00_ 3cde5fb3aa UPD: requirements.txt adding httpx
Update requirements.txt to add httpx and optional support for:

h2 - HTTP/2 support. (Optional, with httpx[http2])
socksio - SOCKS proxy support. (Optional, with httpx[socks])
rich - Rich terminal support. (Optional, with httpx[cli])
click - Command line client support. (Optional, with httpx[cli])
brotli or brotlicffi - Decoding for "brotli" compressed responses. (Optional, with httpx[brotli])
zstandard - Decoding for "zstd" compressed responses. (Optional, with httpx[zstd])
httpx[socks,http2,zstd,cli,brotli]==0.28.1
2025-07-13 11:01:25 +02:00
Tim Jaeryang Baek bd44ab64d0 refac: note editor model selection 2025-07-13 04:53:27 +04:00
Tim Jaeryang Baek d4dfece4f9 Merge pull request #15675 from rgaricano/dev_es-ES
UPD: Locale es-ES translation, rev.1 updated to v.0.6.16
2025-07-13 03:53:24 +04:00
Timothy Jaeryang Baek 98d38657cb refac: styling 2025-07-13 03:52:06 +04:00
Timothy Jaeryang Baek 6f55679a8a refac 2025-07-13 03:50:35 +04:00
Timothy Jaeryang Baek 217bd440c3 refac 2025-07-13 03:46:39 +04:00
Timothy Jaeryang Baek 2b9e30a107 refac 2025-07-13 03:43:30 +04:00
Timothy Jaeryang Baek 57156065e3 refac 2025-07-13 03:30:42 +04:00
Timothy Jaeryang Baek 751e32e427 refac 2025-07-13 03:26:52 +04:00
Timothy Jaeryang Baek ada78cb952 chore: format 2025-07-13 03:23:38 +04:00
Timothy Jaeryang BaekandClassic298 7607c53bd5 feat: folders as projects
Co-Authored-By: Classic298 <27028174+Classic298@users.noreply.github.com>
2025-07-13 03:23:05 +04:00
_00_ 027c08430a UPD: Locale es-ES translation, rev.1 updated to v.0.6.16
UPD: Locale es-ES translation, updated to v.0.6.16
rev.1

Description:

es-ES translation updated to v.0.6.16
2025-07-13 00:55:32 +02:00
Timothy Jaeryang BaekandClassic298 5abc03f4dd enh: enter into folder
Co-Authored-By: Classic298 <27028174+Classic298@users.noreply.github.com>
2025-07-13 02:40:48 +04:00
Timothy Jaeryang BaekandClassic298 6176dba3c9 refac
Co-Authored-By: Classic298 <27028174+Classic298@users.noreply.github.com>
2025-07-13 01:50:01 +04:00
Timothy Jaeryang BaekandClassic298 80f3c97668 refac: folder chat handling
Co-Authored-By: Classic298 <27028174+Classic298@users.noreply.github.com>
2025-07-13 01:26:56 +04:00
Timothy Jaeryang BaekandClassic298 5b14d15b00 feat: migrate folder table
Co-Authored-By: Classic298 <27028174+Classic298@users.noreply.github.com>
2025-07-13 00:51:58 +04:00
Timothy Jaeryang Baek 847a78a276 refac: styling 2025-07-13 00:37:24 +04:00
Timothy Jaeryang Baek d8ccb087ac refac: styling 2025-07-13 00:37:01 +04:00
Timothy Jaeryang Baek 3b4344c1bf fix: leaflet marker 2025-07-13 00:33:19 +04:00
Timothy Jaeryang Baek 87847ab31a chore: format 2025-07-13 00:15:16 +04:00
Timothy Jaeryang Baek 9ae22c5efe refac 2025-07-13 00:00:40 +04:00
Timothy Jaeryang Baek b5cbac7b28 refac 2025-07-12 23:50:41 +04:00
Timothy Jaeryang Baek 3be734fd84 enh: note editor prompts 2025-07-12 23:47:27 +04:00
Timothy Jaeryang Baek 6f896c4352 enh: note editor prompts 2025-07-12 23:34:40 +04:00
Timothy Jaeryang Baek 3e01286b61 refac 2025-07-12 23:31:04 +04:00
Timothy Jaeryang Baek b711c88bab refac: note browser title 2025-07-12 23:26:01 +04:00
Timothy Jaeryang Baek de343021c1 enh: note search 2025-07-12 23:08:46 +04:00
Timothy Jaeryang Baek f5613fb3c2 refac 2025-07-12 23:00:46 +04:00
Timothy Jaeryang Baek 9cabef67a7 refac 2025-07-12 22:55:45 +04:00
Timothy Jaeryang Baek 0df488e456 enh: generate note title 2025-07-12 22:43:09 +04:00
Timothy Jaeryang Baek bc7e5c7c04 refac 2025-07-12 22:18:52 +04:00
Timothy Jaeryang Baek 12edc3221e refac: styling 2025-07-12 22:14:41 +04:00
Timothy Jaeryang Baek 60fb643109 refac/fix: code block input 2025-07-12 21:54:05 +04:00
Timothy Jaeryang Baek fb78bff3c0 refac 2025-07-12 21:39:31 +04:00
Timothy Jaeryang Baek ce7cc37077 refac 2025-07-12 18:15:35 +04:00
Tim Jaeryang Baek 81d6e217f1 Merge pull request #15670 from rgaricano/dev_es-ES
UPD: Locale es-ES translation, updated to v.0.6.16
2025-07-12 17:18:57 +04:00
Tim Jaeryang Baek 33487283e8 Merge pull request #15669 from moblangeois/dev
i18n: Update fr-FR and fr-CA translation
2025-07-12 17:18:43 +04:00
Timothy Jaeryang Baek af59bee2ea refac 2025-07-12 17:17:31 +04:00
_00_ d3da236d96 UPD: Locale es-ES translation, updated to v.0.6.16
UPD: Locale es-ES translation, updated to v.0.6.16
2025-07-12 13:44:28 +02:00
Tim Jaeryang Baek fbaab9e446 refac 2025-07-12 15:36:30 +04:00
Tim Jaeryang Baek 4a69d857f3 refac 2025-07-12 15:32:26 +04:00
Tim Jaeryang Baek 290f4023b1 refac: add copy link functionality to notes view 2025-07-12 15:20:21 +04:00
Morgan Blangeois 4da2b050c6 Update translations files for fr-Fr and fr-CA 2025-07-12 10:12:11 +00:00
Timothy Jaeryang Baek d99698f7eb refac 2025-07-12 03:39:58 +04:00
Timothy Jaeryang Baek 12c4a7a3f7 refac: styling 2025-07-12 03:15:31 +04:00
Timothy Jaeryang Baek 955c2e2570 refac 2025-07-12 03:00:40 +04:00
Timothy Jaeryang Baek 627f680659 refac 2025-07-12 02:57:11 +04:00
Timothy Jaeryang Baek 01420fd189 refac 2025-07-12 02:51:51 +04:00
Timothy Jaeryang Baek 4351702587 refac 2025-07-12 02:38:52 +04:00
Timothy Jaeryang Baek b52a162597 refac 2025-07-12 02:20:32 +04:00
Timothy Jaeryang Baek baa1a44397 refac 2025-07-12 02:17:52 +04:00
Timothy Jaeryang Baek 3c80219808 refac 2025-07-12 01:47:41 +04:00
Timothy Jaeryang Baek bcfe1a087f refac 2025-07-12 00:38:25 +04:00
Timothy Jaeryang Baek d509ca1133 refac 2025-07-12 00:34:18 +04:00
Tim Jaeryang Baek 9b84a8e443 Merge pull request #15632 from athoik/quote
fix: don't over quote forwarded headers
2025-07-12 00:24:29 +04:00
Tim Jaeryang Baek 3402bfd96c Merge pull request #15655 from rgaricano/dev-audio_Mime_comment
DOC: Extend Audio MIME Type Setting Explanation
2025-07-12 00:23:32 +04:00
Timothy Jaeryang Baek 627b39cdbb refac 2025-07-12 00:19:24 +04:00
Timothy Jaeryang Baek 9b8d6ed6d2 refac: notes 2025-07-12 00:16:57 +04:00
Timothy Jaeryang Baek 2fbff741da feat: collaborative note 2025-07-11 23:59:48 +04:00
_00_ e3c8e1bb71 DOC: Extend Audio MIME Type Setting Explanation
DOC: Extend Audio MIME Type Setting Explanation

Add explanation to add multiple mime types in audio settings labeling
2025-07-11 20:18:54 +02:00
Timothy Jaeryang Baek d3b14ff827 refac 2025-07-11 18:41:09 +04:00
Timothy Jaeryang Baek 6820e41eb2 refac 2025-07-11 18:14:56 +04:00
Timothy Jaeryang Baek 22052d2c24 refac: task 2025-07-11 18:14:48 +04:00
Timothy Jaeryang Baek 0202926e35 refac 2025-07-11 18:09:24 +04:00
Timothy Jaeryang Baek 47cd0770e4 refac 2025-07-11 17:54:38 +04:00
Timothy Jaeryang Baek 5b50f3cd69 chore: dep 2025-07-11 17:54:27 +04:00
Timothy Jaeryang Baek 788e7d0487 refac 2025-07-11 17:53:53 +04:00
Timothy Jaeryang Baek 11914d20b4 refac: styling 2025-07-11 12:39:58 +04:00
Timothy Jaeryang Baek 77c1905609 refac 2025-07-11 12:35:42 +04:00
Ioannis Papapanagiotou 54d606eabf refactor(logger): Conditionally include extra_json in logs 2025-07-11 01:29:27 -07:00
Timothy Jaeryang Baek 033d07ee23 refac: file handling 2025-07-11 12:29:17 +04:00
Timothy Jaeryang Baek 0db8bedf45 refac: tts input 2025-07-11 12:15:13 +04:00
Timothy Jaeryang Baek 3bc5485867 enh: proper undo/redo note editor support 2025-07-11 12:00:41 +04:00
Timothy Jaeryang Baek 3b9d86de0b refac 2025-07-11 12:00:21 +04:00
Timothy Jaeryang Baek 6a3b0e3110 refac 2025-07-11 01:46:06 +04:00
Timothy Jaeryang Baek 249b12e44f refac: knowledge selector 2025-07-11 01:41:40 +04:00
Timothy Jaeryang Baek 84bf1892bb refac 2025-07-11 01:34:24 +04:00
Athanasios Oikonomou 96758176cc fix: don't over quote forwarded headers
Fix introduced on #15035 is over quoting headers.

Eg mails instead of user@example.com shown as user%40example.com
Eg names instead of First Last shown as First%20Last

Also we are spending some time quoting ids and roles without required.

Keep quote only on user name, initially had problem based on the discussion
https://github.com/open-webui/open-webui/discussions/14391

Also add space in safe characters, in order remove %20 from names.
2025-07-10 22:08:28 +03:00
Wonyong Lee a8a8fd537f yarn.lock removed 2025-07-10 12:15:13 +00:00
Wonyong Lee 46e0992a83 json_serialize returing varchar2(2096) 2025-07-10 12:12:43 +00:00
Timothy Jaeryang Baek 1f641ce1fb refac 2025-07-10 14:06:15 +04:00
Timothy Jaeryang Baek 22af53f60c refac 2025-07-10 11:14:53 +04:00
Tim Jaeryang Baek d1b0a5739d Merge pull request #15619 from amberyufangchiu/amberyufangchiu-dev
i18n: Update zh-TW (Traditional Chinese) translation.json
2025-07-10 10:33:30 +04:00
Tim Jaeryang Baek 18c19743c4 Merge branch 'dev' into amberyufangchiu-dev 2025-07-10 10:33:12 +04:00
Wonyong Lee 39e4551a45 add oracledb package to requirements.txt 2025-07-10 04:28:52 +00:00
Amber Chiu 77acb9bb41 i18n: Update zh-TW (Traditional Chinese) translation.json 2025-07-10 09:40:58 +08:00
Timothy Jaeryang Baek 24f0da172e fix: table align markdown rendering 2025-07-09 23:39:54 +04:00
Timothy Jaeryang Baek 45d58e73a9 refac: styling 2025-07-09 23:22:59 +04:00
Timothy Jaeryang Baek 8d84b4c2a4 enh/refac: temp chat file upload behaviour
client-side content extraction
2025-07-09 22:59:37 +04:00
Timothy Jaeryang Baek 8fb54b133e refac 2025-07-09 22:33:36 +04:00
Timothy Jaeryang Baek 6d31fc7875 refac: styling 2025-07-09 13:50:45 +04:00
Timothy Jaeryang Baek 49e57b6d13 refac 2025-07-09 13:47:10 +04:00
Timothy Jaeryang Baek 3b9f4a6f5e enh: note word/char counter 2025-07-09 13:38:54 +04:00
Timothy Jaeryang Baek 6ee4274b3b enh: rich text input link 2025-07-09 13:29:27 +04:00
Timothy Jaeryang Baek 04962922d7 refac 2025-07-09 13:00:28 +04:00
Tim Jaeryang Baek 9d8378d2e2 Merge pull request #15604 from EventHorizon-AI/fix/tool-results
fix: tool results
2025-07-09 12:45:10 +04:00
Tim Jaeryang Baek 67c88f90dc Merge pull request #15601 from headwAI-GmbH/streamline-resource-loading-url
chore: streamline the URL used for resources like favicon.png
2025-07-09 12:43:58 +04:00
Timothy Jaeryang Baek b615d13e46 refac: styling 2025-07-09 11:44:51 +04:00
guenhter 196af9eaf7 chore: streamline the URL used for resources like favicon.png 2025-07-09 09:14:51 +02:00
Timothy Jaeryang Baek 0a3c448a52 refac: styling 2025-07-09 11:06:40 +04:00
EntropyYue 5b8007fcb5 fix: tool result frontend 2025-07-09 15:01:19 +08:00
EntropyYue dc0d420af5 fix: tool result 2025-07-09 14:40:53 +08:00
Tim Jaeryang Baek 8882df5829 Merge pull request #15596 from qingchunnh/Update_zh-CN-2579
i18n: Update & Improve zh-CN
2025-07-09 10:26:50 +04:00
qingchun 9b5c9ffb30 i18n: Improve zh-CN 2025-07-09 10:03:09 +08:00
qingchun b09973cafe i18n: Update & Improve zh-CN 2025-07-09 09:44:55 +08:00
Timothy Jaeryang Baek 40b564dedd refac: styling 2025-07-09 04:53:31 +04:00
Timothy Jaeryang Baek a1ddbff744 refac: styling 2025-07-09 04:36:21 +04:00
Timothy Jaeryang Baek 04ac14463b refac: styling 2025-07-09 04:33:52 +04:00
Timothy Jaeryang Baek 784c5b5471 enh: remember note editor preference 2025-07-09 03:50:20 +04:00
Timothy Jaeryang Baek b93ee37f9a refac 2025-07-09 03:43:41 +04:00
Timothy Jaeryang Baek bdab9dd596 refac: task list handling 2025-07-09 03:39:57 +04:00
Timothy Jaeryang Baek e37e6e6b03 enh/refac: allow setting full context mode from model editor 2025-07-09 03:22:24 +04:00
Timothy Jaeryang Baek dd87111c80 refac 2025-07-09 03:15:20 +04:00
Timothy Jaeryang Baek c2ac797650 feat: formatting buttons 2025-07-09 03:11:51 +04:00
Timothy Jaeryang Baek 9a3a0070d6 refac: styling 2025-07-09 02:04:09 +04:00
Timothy Jaeryang Baek e2f5d7caec refac: styling 2025-07-09 01:53:51 +04:00
Timothy Jaeryang Baek 9632f40335 enh: support commands in note chat 2025-07-09 01:49:43 +04:00
Timothy Jaeryang Baek e9821c0881 refac 2025-07-09 01:31:28 +04:00
Timothy Jaeryang Baek b3c4bc6041 enh: allow full context mode for collections 2025-07-09 01:29:49 +04:00
Timothy Jaeryang Baek d5f9bbc7a7 enh: reference note in chat 2025-07-09 01:17:25 +04:00
Timothy Jaeryang Baek f2ee99d760 refac: styling 2025-07-09 01:15:32 +04:00
Tim Jaeryang Baek 91628f5392 Merge pull request #15593 from tarmst/add-openai-to-pyodide
Feat: Add OpenAI package to Pyodide code blocks
2025-07-09 00:54:06 +04:00
Timothy Jaeryang Baek 1de03c364f refac: checkbox styling 2025-07-09 00:34:03 +04:00
Timothy Jaeryang Baek 6bf218f720 refac: styling 2025-07-09 00:22:25 +04:00
Timothy Jaeryang Baek 40a715be89 refac: styling 2025-07-09 00:05:59 +04:00
Timothy Jaeryang Baek 248fd10406 enh: task list rich text input 2025-07-08 23:57:34 +04:00
tarmst 0033b3fe4e Add OpenAI package to pyodide code blocks 2025-07-08 19:28:43 +00:00
Timothy Jaeryang Baek f69db54b7e enh: model workspace tag filter view 2025-07-08 23:05:39 +04:00
Timothy Jaeryang Baek 0765f6c230 refac 2025-07-08 22:56:46 +04:00
Timothy Jaeryang Baek 42f2de68bd refac: styling 2025-07-08 22:38:31 +04:00
Timothy Jaeryang Baek 6f98379c82 enh: checkbox input variable 2025-07-08 21:33:51 +04:00
Timothy Jaeryang Baek 2cde746e38 refac: styling 2025-07-08 16:46:14 +04:00
Timothy Jaeryang Baek 74cafce4d2 refac: note revision history 2025-07-08 16:43:26 +04:00
Timothy Jaeryang Baek d3ba1a0592 refac: prompt variable handling 2025-07-08 16:30:06 +04:00
Tim Jaeryang Baek e3b8f700e4 Merge pull request #14264 from diwakar-s-maurya/patch-6
feat: add langchain markdown document splitter
2025-07-08 15:55:20 +04:00
Timothy Jaeryang Baek ed72ad1728 refac: styling 2025-07-08 14:51:50 +04:00
Timothy Jaeryang Baek 27aa628c86 chore: i18n 2025-07-08 13:29:04 +04:00
Tim Jaeryang Baek a748f19ac2 Merge pull request #15548 from expruc/fix/docling_ignore_html
fix: text/html files being detected as text when loaded with docling/tika
2025-07-08 13:16:01 +04:00
Timothy Jaeryang Baek 5d5bb9d1f2 refac 2025-07-08 13:14:22 +04:00
Timothy Jaeryang Baek 8f74070688 refac: styling 2025-07-08 12:54:11 +04:00
Timothy Jaeryang Baek 09b5c1b4dc refac 2025-07-08 12:50:06 +04:00
Timothy Jaeryang Baek 8febc54a88 refac: styling 2025-07-08 12:39:04 +04:00
Timothy Jaeryang Baek 7cfcf9b21d refac: styling 2025-07-08 12:35:35 +04:00
Timothy Jaeryang Baek 9a064d9623 feat: edit notes via chat 2025-07-08 12:31:31 +04:00
Timothy Jaeryang Baek 45085d04eb refac 2025-07-08 12:31:22 +04:00
Timothy Jaeryang Baek c107a0cbf4 refac 2025-07-08 10:09:32 +04:00
Timothy Jaeryang Baekandpython4004 793648bbd6 fix/security: note access control
Co-Authored-By: python4004 <36403473+python4004@users.noreply.github.com>
2025-07-08 10:04:13 +04:00
Timothy Jaeryang Baek c42a6d8029 refac/fix: node dom issue 2025-07-08 10:00:20 +04:00
Tim Jaeryang Baek a56e9e586b Merge pull request #15573 from flefevre/main
i18n french
2025-07-08 09:58:34 +04:00
Timothy Jaeryang BaekandG30 0450c7cf48 refac: banners
Co-Authored-By: G30 <50341825+silentoplayz@users.noreply.github.com>
2025-07-08 01:37:10 +04:00
Francois LE FEVRE c17b2f3ca0 i18n french 2025-07-07 22:15:39 +02:00
Timothy Jaeryang Baek 30521bcac7 refac: styling 2025-07-08 00:07:50 +04:00
Timothy Jaeryang Baek 3a9d5b0494 refac 2025-07-07 23:51:01 +04:00
Timothy Jaeryang Baek 78dce85b03 fix: thread image only message 2025-07-07 22:00:38 +04:00
Timothy Jaeryang Baek 2d0e55e8f6 refac 2025-07-07 21:52:46 +04:00
Timothy Jaeryang Baek 5722da8e3b feat/enh: insert prompt as rich text 2025-07-07 21:43:28 +04:00
Oracle Public Cloud User e0afd7f496 fianl : vector-search-feature 2025-07-07 17:25:16 +00:00
Timothy Jaeryang Baek ade4b0d691 feat: insert chat message to notes 2025-07-07 21:22:07 +04:00
Oracle Public Cloud User 12ebdbae81 refactor oracle23ai.py 2025-07-07 16:21:34 +00:00
Timothy Jaeryang Baek a3c2018a4a feat: chat with notes 2025-07-07 20:19:17 +04:00
Timothy Jaeryang Baek b3001f95f6 refac 2025-07-07 19:58:10 +04:00
Timothy Jaeryang Baek 8cd7de3740 refac: styling 2025-07-07 19:56:31 +04:00
Timothy Jaeryang Baek d04d0c0510 refac 2025-07-07 19:47:32 +04:00
Timothy Jaeryang Baek 821243ef40 refac 2025-07-07 19:42:08 +04:00
Timothy Jaeryang Baek 67063e6400 refac 2025-07-07 19:33:54 +04:00
Timothy Jaeryang Baek a5367145bf refac 2025-07-07 19:32:41 +04:00
Timothy Jaeryang Baek 7003395a5f refac: experimental wording 2025-07-07 19:30:05 +04:00
Timothy Jaeryang Baek 9bd001a14b feat: note chat 2025-07-07 19:26:12 +04:00
Timothy Jaeryang Baek a31a1f3c0d refac: note editor 2025-07-07 18:26:52 +04:00
Timothy Jaeryang Baek 3392e2ef15 refac/fix: channel input 2025-07-07 17:49:03 +04:00
Timothy Jaeryang Baek 57f9eadd75 feat: models?id= support for admin settings 2025-07-07 17:16:51 +04:00
Timothy Jaeryang Baek a519c62250 chore: bump 2025-07-07 16:13:18 +04:00
Oracle Public Cloud User 25e241ae41 added new feature : oracle23ai vector search 2025-07-07 12:13:05 +00:00
Timothy Jaeryang Baek 3e15c8ab69 refac 2025-07-07 15:56:05 +04:00
Timothy Jaeryang Baek be6633e3be chore: bump ddgs 2025-07-07 15:55:26 +04:00
Oracle Public Cloud User b56dbb26be alpha2 2025-07-07 08:52:58 +00:00
Timothy Jaeryang Baek cfcfefb20c refac: tools handling 2025-07-07 11:42:52 +04:00
Timothy Jaeryang Baek 05a9b72670 refac/fix: base model cache 2025-07-07 11:30:27 +04:00
Oracle Public Cloud User 3e2fd074bb oracle 23ai vector search 2025-07-07 05:58:02 +00:00
Timothy Jaeryang Baek 31c63d8898 refac 2025-07-06 21:40:53 +04:00
expruc 453a2bd9b5 fixed issue where text/html files being detected as text when loaded 2025-07-06 20:10:26 +03:00
Timothy Jaeryang Baek 4a825dce7f refac 2025-07-06 17:51:03 +04:00
Tim Jaeryang Baek 7cb105abd4 Merge pull request #15119 from denispol/dev
fix: Preserve line breaks on multi-line paste in mobile WebViews
2025-07-06 17:41:09 +04:00
Timothy Jaeryang Baek e84c521177 refac/fix: rich text input in ff 2025-07-06 17:32:03 +04:00
Timothy Jaeryang Baek be7166d6fc refac 2025-07-06 16:16:05 +04:00
Timothy Jaeryang Baek 1c41e95ba6 fix/refac: ollama api backward compatibility 2025-07-06 15:02:10 +04:00
Timothy Jaeryang Baek 9a476ae41d refac: ollama api backward compatibility 2025-07-06 14:40:21 +04:00
Timothy Jaeryang Baek 2eab43c35e fix 2025-07-06 14:38:28 +04:00
Timothy Jaeryang Baek f92890b741 refac 2025-07-06 14:32:39 +04:00
Timothy Jaeryang Baek fc2fc6516e enh: autofocus to first input variable input 2025-07-06 14:31:32 +04:00
Timothy Jaeryang Baek 0a1f9966ef refac: audio error handling 2025-07-06 14:20:38 +04:00
Timothy Jaeryang Baek 44754e4c4a enh/refac: show input modal by default for prompt variables 2025-07-06 14:16:34 +04:00
Timothy Jaeryang Baek 7cc2afe973 refac: rich text input 2025-07-06 14:15:45 +04:00
Tim Jaeryang Baek a4885ac549 Merge pull request #15527 from gmacario/gmacario-fix-api-show
FIX: Ollama.py API endpoints to match Ollama's
2025-07-05 21:23:32 +04:00
Tim Jaeryang Baek 26ce14d163 Merge pull request #15541 from open-webui/main
refac: readme
2025-07-05 21:06:51 +04:00
Timothy Jaeryang Baek 5eca495d3e refac: readme 2025-07-05 21:06:32 +04:00
Timothy Jaeryang Baek aeef5d4dcd refac: mobile navbar 2025-07-05 02:26:52 +04:00
Timothy Jaeryang BaekandClassic298 9f87a0cf21 feat: input variables
Co-Authored-By: Classic298 <27028174+Classic298@users.noreply.github.com>
2025-07-05 02:16:44 +04:00
Timothy Jaeryang Baek 5526b66165 chore: qdrant-client bump 2025-07-04 23:56:02 +04:00
Tim Jaeryang Baek a3add18fa9 Merge pull request #15289 from Anush008/main
refactor: Updated Qdrant multi-tenancy implementation
2025-07-04 23:49:11 +04:00
Timothy Jaeryang Baek 198b89faa5 refac: suggestion prompts 2025-07-04 23:40:31 +04:00
Timothy Jaeryang Baek db0d2ae6d4 refac: Improve banner handling and command visibility in chat UI 2025-07-04 20:55:31 +04:00
Timothy Jaeryang Baek c9e1f454fc refac 2025-07-04 20:30:34 +04:00
Tim Jaeryang Baek f58cb09d27 Merge pull request #15480 from itk-dev/feature/message-input-visible-outlines
Feat: message input visible outlines
2025-07-04 20:27:57 +04:00
Timothy Jaeryang Baek 2e2a63c201 fix: various rich text input issues
#15140
2025-07-04 20:26:01 +04:00
Gianpaolo Macario bdd5120407 fix: rename Ollama API parameter "name" to "model" 2025-07-04 17:33:57 +02:00
Timothy Jaeryang Baek 9b5da77ffc refac 2025-07-04 15:29:35 +04:00
Sine Jespersen 86044feaca button to div: avoid nested button, code intepreter button outline 2025-07-04 11:18:30 +02:00
Anush008 17debaa6de chore: Raise if QDRANT_URI is not set
Signed-off-by: Anush008 <anushshetty90@gmail.com>
2025-07-04 13:17:46 +05:30
Anush008 c8a49d373a refactor: Removed more swallows
Signed-off-by: Anush008 <anushshetty90@gmail.com>
2025-07-04 12:38:22 +05:30
Anush008 0ac57a088f refactor: More implementation improvements
Signed-off-by: Anush008 <anushshetty90@gmail.com>
2025-07-04 12:33:54 +05:30
Anush008 7c734d3fea Merge remote-tracking branch 'origin/dev' into Anush008/main
Signed-off-by: Anush008 <anushshetty90@gmail.com>
2025-07-04 12:22:08 +05:30
Tim Jaeryang Baek 600344f2e8 Merge pull request #15510 from kopero2000/bug/oauth_logout_fix
fix/oauth logout fix
2025-07-04 10:30:02 +04:00
Timothy Jaeryang Baek 1b237c7f60 enh: submit searchParam 2025-07-04 02:53:41 +04:00
Timothy Jaeryang Baek e28bc37e41 enh: AUDIT_UVICORN_LOGGER_NAMES 2025-07-03 21:54:25 +04:00
Timothy Jaeryang Baek 75096c24ac refac 2025-07-03 21:28:09 +04:00
Timothy Jaeryang Baek d2485bbf09 refac 2025-07-03 18:13:23 +04:00
8661c4416a feat: configurable db url
Co-Authored-By: Ryan Rodriguez <62253265+ryanmrodriguez@users.noreply.github.com>
Co-Authored-By: Mario Trangoni <mario@mariotrangoni.de>
2025-07-03 17:47:12 +04:00
Tim Jaeryang Baek e98dc0a745 Merge pull request #14957 from Classic298/fix-postgresql-null-value-search
Fix: postgresql null value search
2025-07-03 17:36:27 +04:00
Tim Jaeryang Baek ed6bbddf6e Merge pull request #15483 from headwAI-GmbH/support-deactivate-update-check
feat: Support deactivate update check without OFFLINE_MODE
2025-07-03 17:22:22 +04:00
Tim Jaeryang Baek bdbc8f048c Merge pull request #15501 from Green-PT/fix-oauth-signout-redirect
fix: sign out redirect for oauth
2025-07-03 17:18:25 +04:00
Tim Jaeryang Baek 74167f4b48 Merge pull request #15490 from sihyeonn/chore/sh-print
refactor: improve logging in task management system
2025-07-03 17:14:35 +04:00
Tim Jaeryang Baek 195e0221b8 Merge pull request #15493 from aleixdorca/dev
i18n: Update Catalan translation.json
2025-07-03 17:12:47 +04:00
Tim Jaeryang Baek 7b0fc0ad1c Merge pull request #15492 from qingchunnh/Update_zh-CN-2573
i18n: Update zh-CN
2025-07-03 16:13:17 +04:00
Tim Jaeryang Baek c093b88abe Merge pull request #15500 from aindriu80/update-ga-strings-june
i18n (ga): Update Irish translations
2025-07-03 16:12:59 +04:00
Aindriú Mac Giolla Eoin 34ec073b3d Merge branch 'dev' into update-ga-strings-june 2025-07-03 13:07:38 +01:00
Tim etc. bb0176085d fix signout redirect for oauth 2025-07-03 13:59:48 +02:00
Aindriú Mac Giolla Eoin 54e5e4bb4b i18n(ga): Update Irish translations 2025-07-03 12:40:58 +01:00
Aleix Dorca 4c7436a05c Update Catalan translation.json 2025-07-03 06:44:41 +02:00
qingchun ee00bdef63 i18n: Fix zh-CN 2025-07-03 11:52:45 +08:00
qingchun e5415b8a87 i18n: Fix zh-CN 2025-07-03 11:50:58 +08:00
qingchun 1f4e51edc6 i18n: Update zh-CN 2025-07-03 11:46:17 +08:00
Sihyeon Jang a9804e2566 refactor: replace print statements with appropriate logging levels
Signed-off-by: Sihyeon Jang <uneedsihyeon@gmail.com>
2025-07-03 08:34:25 +09:00
Timothy Jaeryang Baek e1efd54a70 fix/refac: heic image handling 2025-07-03 00:04:13 +04:00
Vizi Béla Ákos d1ee4e0925 Merge branch 'open-webui:main' into bug/oauth_logout_fix 2025-07-02 18:01:08 +02:00
Bela Vizi 9623ef4360 add trust env to clientsession 2025-07-02 17:59:56 +02:00
Timothy Jaeryang Baek bb506edcc3 refac 2025-07-02 17:50:07 +04:00
Timothy Jaeryang Baek f55e93cabe feat: additional valve input types 2025-07-02 17:45:42 +04:00
guenhter 661ea773f4 fix: avoid 'checking for updates...' always present in offline-mode 2025-07-02 15:20:43 +02:00
guenhter 34ddd62951 feat: support suppressing version checks 2025-07-02 15:20:43 +02:00
Timothy Jaeryang Baekandsilentoplayz 7adb15d4b0 refac: user pending screen
Co-Authored-By: silentoplayz <50341825+silentoplayz@users.noreply.github.com>
2025-07-02 16:11:13 +04:00
Timothy Jaeryang Baek 21f9982c5a chore: chart.js 2025-07-02 15:58:16 +04:00
Timothy Jaeryang Baek ff3dec9ef2 refac: styling 2025-07-02 15:14:48 +04:00
Timothy Jaeryang Baek 05773bc831 refac: styling 2025-07-02 14:58:28 +04:00
Tim Jaeryang Baek 6ff84d8ec0 Merge pull request #15479 from itk-dev/feature/suggestions-role-list
FEAT: give suggestions role list and items role listitem
2025-07-02 14:50:30 +04:00
Sine Jespersen 98317f4576 give suggestions role list and items role listitem 2025-07-02 12:45:15 +02:00
Timothy Jaeryang Baek 139e4f93cb refac 2025-07-02 14:30:05 +04:00
Tim Jaeryang Baek a3c9b46e9a Merge pull request #15477 from itk-dev/feature/accessibility-user-settings
Feat: accessibility user settings dropdown menu
2025-07-02 14:22:37 +04:00
Timothy Jaeryang Baekandconql 2c6227e4b6 fix: preserve dates for chat imports
Co-Authored-By: conql <49243542+conql@users.noreply.github.com>
2025-07-02 14:21:36 +04:00
Timothy Jaeryang Baek 3f800c069e refac: banner newlines 2025-07-02 14:06:06 +04:00
Timothy Jaeryang Baek 9b718e7817 refac: styling 2025-07-02 13:59:14 +04:00
Timothy Jaeryang Baek 7e273ebe86 refac: banners 2025-07-02 13:48:18 +04:00
Sine Jespersen 225d20fb84 aria hidden on decorative svgs to enhance accessibility 2025-07-02 11:29:03 +02:00
Sine Jespersen b7255854d2 change interactive elements in dropdownmenu to dropdownitems 2025-07-02 11:14:12 +02:00
Tim Jaeryang Baek bab7a65c2c Merge pull request #15452 from expruc/chore/remove_embedder_openai_api_key_requirement
chore: removed requirement for providing api key in openai embedder
2025-07-02 12:55:00 +04:00
Timothy Jaeryang Baek 1cc15e6470 refac: splash screen 2025-07-02 12:51:03 +04:00
Sine Jespersen 7e49c8733b remove nested button and add label for assistive technology 2025-07-02 10:12:48 +02:00
Tim Jaeryang Baek 40fc1a1f95 Merge pull request #15466 from itk-dev/feature/accessibility-dropdown-model-selector
Feat: accessibility in dropdown model selector
2025-07-02 12:10:29 +04:00
Sine Jespersen d7f247d7d2 make margin depend on high contrast mode, based on comment on pr 2025-07-02 09:55:47 +02:00
Timothy Jaeryang Baek 57972605f2 refac 2025-07-02 11:48:01 +04:00
Timothy Jaeryang Baek d54896ca66 chore: bump pydantic 2025-07-02 11:41:58 +04:00
Sine Jespersen 6a644cd03a aria hidden on svg, as this is decorative 2025-07-02 08:57:15 +02:00
Sine Jespersen 64b583dc29 add margin to make outline visible 2025-07-02 08:56:56 +02:00
Sine Jespersen bed2c7e34f remove nested buttons, as this is not valid html 2025-07-02 08:56:17 +02:00
Sine Jespersen e5435c6480 high contrast mode on model selector to enhance accessibility 2025-07-02 08:46:32 +02:00
expruc 555c449f49 removed requirement for providing api key in openai embedder 2025-07-01 22:03:50 +03:00
Tim Jaeryang Baek a85ecadfeb Merge pull request #15447 from itk-dev/feature/accessibility-file-item
Feat: accessibility of file input in messageinput
2025-07-01 15:57:39 +04:00
Timothy Jaeryang Baek 355a3eaedb enh: dynamic commands height 2025-07-01 15:57:01 +04:00
Timothy Jaeryang Baek 8d49288499 refac: skeleton 2025-07-01 15:32:32 +04:00
Tim Jaeryang Baek 6d0bd226c1 Merge pull request #15445 from itk-dev/feature/chat-page-accessibility
Feat: chat page accessibility
2025-07-01 15:23:06 +04:00
Sine Jespersen 3d4752480e aria label on remove file button to enchance accessibility 2025-07-01 13:21:40 +02:00
Tim Jaeryang Baek af9d264405 Merge pull request #15402 from itk-dev/feature/aria-hide-button-and-img
Feat: aria hide button and img
2025-07-01 15:18:21 +04:00
Sine Jespersen 1dd475cccf aria hidden on svg 2025-07-01 13:16:18 +02:00
Sine Jespersen 09ddf69a73 high contrast mode on file item to enhance accessibility 2025-07-01 13:15:38 +02:00
Sine Jespersen 67ac39b72b aria hidden on some svgs for accessibility 2025-07-01 12:40:03 +02:00
Sine Jespersen ab3c19dd36 aria labels and high contrast mode for accessibility 2025-07-01 12:39:35 +02:00
Tim Jaeryang Baek 7a25c9637a Merge pull request #15443 from open-webui/main
dev
2025-07-01 14:08:13 +04:00
Timothy Jaeryang Baek 59ba21bdf8 refac 2025-07-01 14:06:45 +04:00
Sine Jespersen 988fc3a72c aria-hidden and aria-label to enhance accessibility 2025-07-01 11:31:07 +02:00
Tim Jaeryang Baek 8b43641849 Merge pull request #15427 from open-webui/dependabot/npm_and_yarn/dev/html2canvas-pro-1.5.11
build(deps): bump html2canvas-pro from 1.5.8 to 1.5.11
2025-07-01 12:49:09 +04:00
Tim Jaeryang Baek b8c8c64720 Merge pull request #15419 from open-webui/dependabot/pip/backend/dev/uvicorn-standard--0.35.0
build(deps): bump uvicorn[standard] from 0.34.2 to 0.35.0 in /backend
2025-07-01 12:48:50 +04:00
Tim Jaeryang Baek 557be6c824 Merge pull request #15418 from open-webui/dependabot/pip/backend/dev/azure-identity-1.23.0
build(deps): bump azure-identity from 1.21.0 to 1.23.0 in /backend
2025-07-01 12:48:09 +04:00
Tim Jaeryang Baek c38177bcd5 Merge pull request #15438 from open-webui/dependabot/npm_and_yarn/dev/sortablejs-1.15.6
build(deps): bump sortablejs from 1.15.2 to 1.15.6
2025-07-01 12:44:58 +04:00
Sine Jespersen 00e2ad1a9f Aria labels on image 2025-07-01 10:10:37 +02:00
dependabot[bot] fffe0b8580 build(deps): bump sortablejs from 1.15.2 to 1.15.6
Bumps [sortablejs](https://github.com/SortableJS/Sortable) from 1.15.2 to 1.15.6.
- [Release notes](https://github.com/SortableJS/Sortable/releases)
- [Commits](https://github.com/SortableJS/Sortable/compare/1.15.2...1.15.6)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-01 06:59:56 +00:00
Tim Jaeryang Baek 030e9ab1ae Merge pull request #15417 from jackthgu/websearch-searxng-url-required
fix: settings/web-search : make “Searxng Query URL” field required
2025-07-01 10:56:55 +04:00
dependabot[bot] b685fd4a33 build(deps): bump html2canvas-pro from 1.5.8 to 1.5.11
Bumps [html2canvas-pro](https://github.com/yorickshan/html2canvas-pro) from 1.5.8 to 1.5.11.
- [Release notes](https://github.com/yorickshan/html2canvas-pro/releases)
- [Changelog](https://github.com/yorickshan/html2canvas-pro/blob/main/CHANGELOG.md)
- [Commits](https://github.com/yorickshan/html2canvas-pro/compare/v1.5.8...v1.5.11)

---
updated-dependencies:
- dependency-name: html2canvas-pro
  dependency-version: 1.5.11
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-01 05:55:54 +00:00
dependabot[bot] 876bb4bdc6 build(deps): bump uvicorn[standard] from 0.34.2 to 0.35.0 in /backend
Bumps [uvicorn[standard]](https://github.com/encode/uvicorn) from 0.34.2 to 0.35.0.
- [Release notes](https://github.com/encode/uvicorn/releases)
- [Changelog](https://github.com/encode/uvicorn/blob/master/docs/release-notes.md)
- [Commits](https://github.com/encode/uvicorn/compare/0.34.2...0.35.0)

---
updated-dependencies:
- dependency-name: uvicorn[standard]
  dependency-version: 0.35.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-01 05:21:20 +00:00
dependabot[bot] 534c12b1b9 build(deps): bump azure-identity from 1.21.0 to 1.23.0 in /backend
Bumps [azure-identity](https://github.com/Azure/azure-sdk-for-python) from 1.21.0 to 1.23.0.
- [Release notes](https://github.com/Azure/azure-sdk-for-python/releases)
- [Changelog](https://github.com/Azure/azure-sdk-for-python/blob/main/doc/esrp_release.md)
- [Commits](https://github.com/Azure/azure-sdk-for-python/compare/azure-identity_1.21.0...azure-identity_1.23.0)

---
updated-dependencies:
- dependency-name: azure-identity
  dependency-version: 1.23.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-01 05:21:17 +00:00
Taehong Gu 15821af252 fix(admin/web-search): add required validation to “Searxng Query URL” field 2025-07-01 14:08:01 +09:00
Tim Jaeryang Baek a463ef3c03 Merge pull request #15407 from silentoplayz/bannerlengthincrease
refac: Increase banners height limit
2025-06-30 21:41:12 +04:00
Silentoplayz 9813019489 Update Banner.svelte 2025-06-30 12:22:39 -04:00
Timothy Jaeryang Baek de018f0912 refac 2025-06-30 18:04:11 +04:00
Timothy Jaeryang Baek 8b35ea6eea enh: OTEL_OTLP_SPAN_EXPORTER 2025-06-30 15:52:32 +04:00
Timothy Jaeryang Baek bab1453b4c refac: styling 2025-06-30 15:39:43 +04:00
Timothy Jaeryang Baek a14cfb6448 enh: more info in feedback modal 2025-06-30 15:38:25 +04:00
Timothy Jaeryang Baek 71d550dd26 enh: offline mode 2025-06-30 15:20:41 +04:00
Timothy Jaeryang Baek 2748fc1e4d refac 2025-06-30 13:29:47 +04:00
Timothy Jaeryang Baek ce311598cb refac: styling 2025-06-30 13:29:23 +04:00
Timothy Jaeryang Baek 8a334decf6 refac: ENABLE_MODEL_LIST_CACHE -> ENABLE_BASE_MODELS_CACHE 2025-06-30 13:27:07 +04:00
Timothy Jaeryang Baek eac2f36f4f refac: temporary enforced behaviour 2025-06-30 13:16:46 +04:00
Tim Jaeryang Baek c75d0bd20b Merge pull request #15389 from headwAI-GmbH/add-qdrant-indices
feat: Add qdrant indices
2025-06-30 11:36:31 +04:00
Tim Jaeryang Baek 74912a5383 Merge pull request #15380 from taylorwilsdon/issues/15074/REDIS_KEY_PREFIX
feat: Support configuration of redis key prefix via environment variable
2025-06-30 10:43:35 +04:00
guenhter 5c2e0e4beb feat: add qdrant indices for metadata fields
All fieldnames which are part of a query should
have an index for performance reasons. This is
even enforced on some qdrant cluster like those
on qdrant.io, and queries using a unindexed column
fail with an error.
2025-06-29 15:30:55 +02:00
Taylor Wilsdon 7b5df819b1 fmt 2025-06-28 10:18:30 -07:00
Taylor Wilsdon 345922a970 add REDIS_KEY_PREFIX env var and default to current hardcoded value 2025-06-28 10:11:26 -07:00
Timothy Jaeryang Baek 7523613fbc refac 2025-06-28 19:29:28 +04:00
Timothy Jaeryang Baek 962e078a9a refac 2025-06-28 19:15:52 +04:00
Timothy Jaeryang Baek 1b064a6c85 chore: format 2025-06-28 15:21:20 +04:00
Timothy Jaeryang Baek e06cdea0b5 refac 2025-06-28 15:20:38 +04:00
Timothy Jaeryang Baek 8f9e202a88 refac 2025-06-28 15:13:21 +04:00
Timothy Jaeryang Baek 1a52585769 enh: ENABLE_MODEL_LIST_CACHE 2025-06-28 15:12:31 +04:00
Timothy Jaeryang Baek 2b88f66762 refac: MODEL_LIST_CACHE_TTL -> MODELS_CACHE_TTL 2025-06-28 14:44:47 +04:00
Timothy Jaeryang Baek 53a08eb00d refac: styling 2025-06-28 14:36:26 +04:00
Timothy Jaeryang Baek ffd7b004f4 fix: admin chat share issue 2025-06-28 14:02:07 +04:00
Timothy Jaeryang Baek f123d70cff fix: enforced temp chat issue 2025-06-28 14:01:58 +04:00
Timothy Jaeryang Baek 372836c87c chore: langchain dep bump 2025-06-28 00:53:07 +04:00
Timothy Jaeryang Baek ff639a20d0 refac 2025-06-28 00:48:24 +04:00
Tim Jaeryang Baek bfd92ec4af Merge pull request #15366 from akiraro/feat/oidc-httpx-timeout
feat: Custom oauth timeout
2025-06-28 00:46:21 +04:00
Haziq Yusof 88ea0f523f feat: custom oauth timeout 2025-06-28 03:08:46 +08:00
Timothy Jaeryang Baek dd1e4ee983 refac 2025-06-27 18:29:37 +04:00
Timothy Jaeryang Baek c91b0cd8c4 refac: vite config 2025-06-27 16:42:10 +04:00
Timothy Jaeryang Baek 3ff864eb63 refac: select action model behaviour 2025-06-27 16:29:04 +04:00
Timothy Jaeryang Baek 90257442e3 refac: styling 2025-06-27 16:15:16 +04:00
Timothy Jaeryang Baek 0447790e6a feat: MODEL_LIST_CACHE_TTL 2025-06-27 15:59:30 +04:00
Timothy Jaeryang Baek 09f0c6beee fix: windows start script 2025-06-27 15:46:38 +04:00
Timothy Jaeryang Baek c8e8111dd9 refac 2025-06-27 15:44:26 +04:00
Timothy Jaeryang Baek 38dfa6e6db refac 2025-06-27 15:30:00 +04:00
Tim Jaeryang Baek 276bfa02d0 Merge pull request #15314 from silentoplayz/spinner-and-xmark-icon-components
refac: Spinner and XMark components
2025-06-27 15:23:29 +04:00
Tim Jaeryang Baek 79aa73347e Merge pull request #15318 from hula-la/fix/ko-translation
i18n: Fix Korean translation errors in UI messages
2025-06-27 15:22:33 +04:00
Timothy Jaeryang Baek 2ae9bc30bd refac: feedback item click issue 2025-06-27 15:21:46 +04:00
Timothy Jaeryang Baek aa13a7caf9 refac 2025-06-27 14:58:23 +04:00
Tim Jaeryang Baek 8c5beddb5f Merge pull request #15310 from silentoplayz/icons
chore: Remove `MagnifyingGlass` icon component and update to use Search icon component
2025-06-27 14:58:06 +04:00
Tim Jaeryang Baek c303232657 Merge pull request #15344 from silentoplayz/small-fixes
fix: A couple small fixes
2025-06-27 14:31:01 +04:00
Tim Jaeryang Baek 8b49d6dda0 Merge pull request #15325 from headwAI-GmbH/make-qdrant-collection-prefix-configurable
feat: support better qdrant collection isolation
2025-06-27 14:30:26 +04:00
Silentoplayz e3bacc3296 fix: Small fixes 2025-06-27 04:35:28 -04:00
Tim Jaeryang Baek 767c4426cd Merge pull request #15328 from acwoo97/feat/lock
feat : Retry acquiring usage cleanup lock to handle potential stale locks
2025-06-27 11:52:13 +04:00
안찬우[AI Product] 789e6a0db3 feat : Retry acquiring usage cleanup lock to handle potential stale locks 2025-06-26 22:24:57 +09:00
guenhter a66206f44f feat: support better qdrant collection isolation
The prefix string for qdrant collection is now
configurable,  which means the same qdrant cluster
can be used to host more open webui instances and
to be able to separate the collections between the
different owui instances.
2025-06-26 13:52:26 +02:00
soo-jin-kim 2f4604921f fix: fix korean translation 2025-06-26 17:18:07 +09:00
Timothy Jaeryang Baek 21d616f8ed fix: code interpreter code editor issue 2025-06-26 11:05:17 +04:00
Silentoplayz f429dd667f chore: remove comment 2025-06-25 18:56:08 -04:00
Silentoplayz d1e3940abd refac: Spinner and XMark components 2025-06-25 18:44:45 -04:00
Silentoplayz cf24e39404 chore: add strokeWidth back 2025-06-25 17:36:23 -04:00
Silentoplayz dd0e6bf58f remove class="w-5 h-5" /> 2025-06-25 14:04:40 -04:00
Silentoplayz 88c4f55a51 chore: update 2025-06-25 14:00:48 -04:00
Silentoplayz 3f865f0b66 chore: MagnifyingGlass -> Search 2025-06-25 13:42:18 -04:00
Tim Jaeryang Baek b6e2b2e514 Merge pull request #15236 from headwAI-GmbH/password-login-type
fix: Use correct password autocomplete type on signup
2025-06-25 13:39:08 +04:00
Timothy Jaeryang Baek 8e95e5267c refac 2025-06-25 13:36:41 +04:00
Tim Jaeryang Baek d4fcf561e5 Merge pull request #15293 from itk-dev/feature/make-toggle-button-accessible
feat: aria-pressed and aria-label
2025-06-25 13:36:02 +04:00
Sine Jespersen 0ba84a670d add aria-pressed and aria-label to toggle button to make it accessible 2025-06-25 10:34:40 +02:00
Timothy Jaeryang Baek 1f123eb100 refac 2025-06-25 12:20:08 +04:00
Tim Jaeryang Baek 6676824947 Merge pull request #15238 from manelcomiche/main
feat(i18n): update Spanish and Catalan translations
2025-06-25 11:05:31 +04:00
Tim Jaeryang Baek 2bad7eaa07 Merge pull request #15277 from hankewyczz/bug/restore-exa-search
fix Restore exa
2025-06-25 11:04:48 +04:00
Tim Jaeryang Baek d60c800d66 Merge pull request #15276 from zhangtyzzz/update_brave_search
[fix] Update brave.py to use the correct field
2025-06-25 11:04:06 +04:00
Anush008 05bee5663d Merge remote-tracking branch 'origin/dev' 2025-06-25 12:04:23 +05:30
Tim Jaeryang Baek baa5920b7a Merge pull request #15250 from dlamoris/dev
fix: opensearch race condition, use keyword search instead of full text search for filter query
2025-06-25 10:30:36 +04:00
Tim Jaeryang Baek 889a3e1c48 Merge pull request #15262 from bobend/updated-da-DK
i18n: Updated da-DK translation
2025-06-25 10:30:18 +04:00
Tim Jaeryang Baek 565ec1567b Merge pull request #15268 from jackthgu/added-docker-compose-otel
build: add docker-compose.otel.yaml for OpenTelemetry
2025-06-25 10:26:46 +04:00
Tim Jaeryang Baek 7f681e8c02 Merge pull request #15273 from c0mplex10/translate
i18n: Improve Turkish translations
2025-06-25 10:26:15 +04:00
Zachar Hankewycz 45d7726ee0 Restore exa 2025-06-24 21:24:53 -04:00
zhangtyzzz ac5567f78d Update brave.py to use the correct field
fixing issues caused by incorrect field names.
2025-06-25 09:11:58 +08:00
c0mplex10 1875d7d726 i18n: Improve Turkish translations 2025-06-25 01:40:23 +03:00
Taehong Gu c77c4ff3f7 build: add docker-compose.otel.yaml for OpenTelemetry 2025-06-25 00:11:06 +09:00
Bo Bendtsen 2a25d625b2 Merge remote-tracking branch 'upstream/dev' into updated-da-DK 2025-06-24 12:54:17 +02:00
Bo Bendtsen 559c25fa3c Updated da-DK translation 2025-06-24 12:45:48 +02:00
Anush008 9dd24ee8fa chore: Bump qdrant-client version
Signed-off-by: Anush008 <anushshetty90@gmail.com>
2025-06-24 14:15:07 +05:30
Anush008 5dba298c1e refactor: Updated Qdrant multi-tenancy implementation
Signed-off-by: Anush008 <anushshetty90@gmail.com>
2025-06-24 14:12:44 +05:30
Tim Jaeryang Baek 0b1db0b216 Merge pull request #15242 from c0mplex10/patch-2
i18n: Improve Turkish translations
2025-06-24 11:34:59 +04:00
Timothy Jaeryang Baek 947b77db24 refac 2025-06-24 10:36:33 +04:00
Doris Lam 74ae9ab897 fix opensearch race condition, use keyword search instead of full text search in filter query 2025-06-23 18:43:33 -07:00
c0mplex10 c9c5340762 Update translation.json 2025-06-23 17:46:12 +03:00
denispol 77a96870ea Merge branch 'open-webui:dev' into dev 2025-06-23 15:42:32 +02:00
LHCLYT e237600e51 feat(i18n): update Catalan translations
Updated several Catalan translation strings to improve grammar, consistency, and clarity.

Includes fixes for technical terms and overall localization quality.
2025-06-23 12:53:49 +02:00
LHCLYT 708010a16a feat(i18n): update Spanish translations
Updated several Spanish translation strings to improve grammar, consistency, and clarity.

Includes fixes for technical terms and overall localization quality.
2025-06-23 12:43:14 +02:00
guenhter f0e60c28df fix: use correct password autocomplete for signup
Password manager act based on the 'autocomplet' attribute
of the password fields. If the attribut is set to
"current-password" they try to fill the password with an
existing one. If it is set to "new-password" they try to
support the user by generating a new password.
For signup in owui, the password was always set to
"current-password", so the password manager never proposed
a password on signup.
2025-06-23 11:48:51 +02:00
Tim Jaeryang Baek 610680ac14 Merge pull request #15213 from beecho01/patch-1
i18n: en-GB English translation updates
2025-06-23 13:12:44 +04:00
Timothy Jaeryang Baek f4b92868c4 refac 2025-06-23 12:54:50 +04:00
Tim Jaeryang Baek 9b2c3dec3a Merge pull request #15220 from prilosac/allow_auto_gpt_image_1
fix: Allowing 'auto' for IMAGE_SIZE on gpt-image-1
2025-06-23 10:50:44 +04:00
Tim Jaeryang Baek 6c7a7bc891 Merge pull request #15219 from qingchunnh/Update_zh-CN-25623
i18n: Update & Improve zh-CN
2025-06-23 10:49:41 +04:00
qingchun 018000c41b i18n: Improve zh-CN 2025-06-23 04:56:35 +08:00
Lucas Teixeira 95610080fb allowing auto on gpt-image-1 2025-06-22 13:55:29 -07:00
qingchun a5cdd25802 i18n: Update & Improve zh-CN 2025-06-23 04:20:47 +08:00
James Beeching 2df1f83e79 Merge branch 'dev' into patch-1 2025-06-22 14:17:24 +01:00
James Beeching 13cd025a7d Update missed spelling to en-GB equivalent 2025-06-22 14:03:36 +01:00
James Beeching 986e583594 Update translation.json for en-GB 2025-06-22 13:52:16 +01:00
Tim Jaeryang Baek 0563738940 Merge pull request #15208 from yukebrillianth/main
i18n: Fix translation placeholder for SSO provider in Bahasa Indonesia
2025-06-22 15:32:32 +04:00
Tim Jaeryang Baek 21d0431178 Merge pull request #15211 from Keram-Yasin/main
i18n: translation edit for ug-CN
2025-06-22 15:32:16 +04:00
Keram Yasin bb1f8f8ae9 Uyghur Translations Editted
1. The Uyghur translations are edited based on live instance.
2025-06-22 12:25:19 +02:00
Yuke Brilliant Hestiavin b1f0ad79a8 fix: SSO provider translation in Bahasa Indonesia 2025-06-22 07:00:44 +07:00
Timothy Jaeryang Baek aef0ad2d10 refac 2025-06-21 19:12:43 +04:00
Timothy Jaeryang Baek 38e8209d71 enh: ENABLE_COMPRESSION_MIDDLEWARE env var 2025-06-21 17:58:56 +04:00
Tim Jaeryang Baek 2eae63bcd4 Merge pull request #15195 from prene/proper-default-pooling-settings
[PERF] Proper default pooling settings
2025-06-21 17:39:27 +04:00
René Pfitzner 63d99abf41 Change default db pooling 2025-06-21 14:01:57 +01:00
Tim Jaeryang Baek 7513dc7e34 Merge pull request #15146 from rgaricano/dev
i18n: en-US correction of num_keep parameter description
2025-06-21 15:11:26 +04:00
Timothy Jaeryang Baek 2658ab1e46 chore: format 2025-06-21 15:07:52 +04:00
Timothy Jaeryang Baek df060df88b refac: styling 2025-06-20 21:10:56 +04:00
Timothy Jaeryang Baek e035d5d767 refac: styling 2025-06-20 20:57:13 +04:00
Timothy Jaeryang Baek 493595c891 refac: styling 2025-06-20 20:51:40 +04:00
Timothy Jaeryang Baek cd70469a8a chore: format 2025-06-20 20:32:30 +04:00
Timothy Jaeryang Baek 17b9a81504 chore: format 2025-06-20 20:32:23 +04:00
Tim Jaeryang Baek e3e2bf841e Merge pull request #15170 from Keram-Yasin/main
i18n: add translation for ug-CN
2025-06-20 20:28:53 +04:00
Tim Jaeryang Baek 2f94b3947e Merge pull request #15167 from ascodeasice/dayjs-zh-tw-locale
i18n: Add zh-tw locale support for dayjs
2025-06-20 20:28:16 +04:00
ascodeasice 9f33abf384 feat(dayjs): add zh-tw locale support 2025-06-20 16:24:04 +08:00
Tim Jaeryang Baek a21519f8f2 Merge pull request #15034 from Classic298/system-prompt-high-contrast
feat: System prompt input fields high contrast mode
2025-06-20 10:07:41 +04:00
Timothy Jaeryang Baek e1f5f1e0b1 refac 2025-06-20 09:58:44 +04:00
Tim Jaeryang Baek 4e50dd4df6 Merge pull request #15122 from tcx4c70/feat/add_stream_options_to_azure
feat(azure): Add stream_options to payload if api_version supports
2025-06-20 09:57:27 +04:00
Tim Jaeryang Baek 13c16b974c Merge pull request #15154 from Classic298/patch-1
i18n: de-DE German Translation Updates
2025-06-20 09:55:37 +04:00
Tim Jaeryang Baek b5445b5db2 Merge pull request #15148 from jackthgu/none-dbconnect-warning-message
fix: Enhance database migration error logging
2025-06-20 09:55:02 +04:00
Taehong Gu c7ef6025af Provide more detailed information to the user upon database connection failure
modified:   backend/open_webui/internal/db.py
2025-06-20 14:13:43 +09:00
Classic298 f0dea9a7c4 Update translation.json 2025-06-19 23:27:14 +02:00
Keram Yasin f7c7d72857 Uyghur Translation Review 1. The translations are reviewed and corrected for three times. 2025-06-19 22:19:17 +02:00
Timothy Jaeryang Baek 81b8267e85 feat: odt file parse support 2025-06-19 18:39:00 +04:00
_00_ f939646364 i18n: en-US correction of num_keep parameter description
i18n: en-US correction of num_keep parameter description

Correction of num_keep parameter,
In actual description example is indicated that "last" x tokens will be retained, that is wrong, it have to say "first" x tokens.

Tokens to Keep on Context Refresh (num_keep): Retains part of the previous conversation. It's used when the n_ctx limit is reached. A new prompt will be constructed with the first n_keep characters of the original prompt plus the second half of the output to free up space for more conversation. Example: Keeping 50 first tokens helps the model remember the main topic when refreshing.

https://github.com/open-webui/open-webui/discussions/3794#discussioncomment-12691428
2025-06-19 14:18:15 +02:00
Tim Jaeryang Baek 4f8f349c8f Merge pull request #15142 from Classic298/fix-oauth
fix: OAuth authentication failure on second login due to stale session state
2025-06-19 15:56:26 +04:00
Classic298 bbdb098b87 Update auths.py 2025-06-19 13:44:03 +02:00
Keram 646b3ca7f6 Uyghur Translation Uploaded
1. All the file is translated to Uyghur for the first time.
2. The next step is to review all the translations.
2025-06-19 12:30:42 +02:00
Timothy Jaeryang Baek a196b9dc26 fix: direct tool servers not displaying 2025-06-19 14:03:36 +04:00
Tim Jaeryang Baek b08fc297cf Merge pull request #15138 from zhangtyzzz/exa_search_missing
fix: Resolve exa search not being processed correctly
2025-06-19 10:34:51 +04:00
zhangtyzzz 5f60b30320 add missed exa 2025-06-19 13:52:58 +08:00
Keram Yasin 088e54c4fa Uyghur Localization Files Added
1. Uyghur localization file is added.
2. Uyghur language code is added to language list.
2025-06-18 22:11:45 +02:00
Adam Tao baafdb752c feat(openai): Add stream_options to payload if api_version supports
Signed-off-by: Adam Tao <tcx4c70@gmail.com>
2025-06-18 21:17:09 +08:00
Tim Jaeryang Baek d6f13bee5e Merge pull request #15094 from silentoplayz/small-fix
fix: sanatizeResponseContent for stop token display
2025-06-18 16:57:27 +04:00
denispol 6555cf9d7a fix: enhance paste handling for mobile WebViews and large text 2025-06-18 14:50:16 +02:00
Timothy Jaeryang Baek 1547235d47 refac: chat input object localStorage -> sessionStorage 2025-06-18 16:02:29 +04:00
Classic298 b9ea6130c7 Update General.svelte 2025-06-18 13:10:02 +02:00
Classic298 3814bbf7b3 Update General.svelte 2025-06-18 13:09:21 +02:00
Tim Jaeryang Baek 34440f95dc Merge pull request #15093 from silentoplayz/fix-sidebar-drag-and-drop
fix: refine folder component's drag-&-drop error handling
2025-06-18 14:04:52 +04:00
Tim Jaeryang Baek 1abc3847ab Merge pull request #15108 from itk-dev/feature/telemetry-auth
feat: Added support for basic auth wiht OTEL exporter
2025-06-18 14:04:15 +04:00
Timothy Jaeryang Baek 6186bbf337 refac/fix: stt supported type 2025-06-18 14:01:14 +04:00
Jesper Kristensen 4119ab261e Added support for basic auth wiht OTEL exporter 2025-06-18 11:42:33 +02:00
Tim Jaeryang Baek e79f31b9c4 Merge pull request #15029 from Classic298/correct-markdown-rendering-model-descriptions
fix: Correct markdown rendering model descriptions
2025-06-18 12:50:31 +04:00
Tim Jaeryang Baek 1d179399f3 Merge pull request #15069 from d2a-pnagel/codex/repareer-fouten-in-nl-vertaalbestand
i18n: Fix errors in Dutch translations
2025-06-18 12:49:59 +04:00
Tim Jaeryang Baek 294d6ce060 Merge pull request #15101 from itk-dev/feature/high-contrast-mode-tools-section
FEAT: high contrast mode tools section
2025-06-18 12:34:24 +04:00
Sine Jespersen 3ff5db229b accessibility: labels and placeholder contrast 2025-06-18 09:50:04 +02:00
Sine Jespersen 27f7df8ad6 accessibility: placeholder contrast on sensitiveinput 2025-06-18 09:50:04 +02:00
Sine Jespersen bd818b4524 outline on switch button 2025-06-18 09:50:04 +02:00
Sine Jespersen 99b153a132 add aria label to button 2025-06-18 09:50:04 +02:00
Sine Jespersen d837e6e579 decorative svgs hidden from screen reader 2025-06-18 09:50:04 +02:00
Sine Jespersen 226a7578c6 labels for inputs 2025-06-18 09:50:04 +02:00
Sine Jespersen f36f943a54 screen readers: label button, and remove decorative svg 2025-06-18 09:50:04 +02:00
Sine Jespersen 3cdefff0d2 change div to h1, as it is the modal header 2025-06-18 09:50:04 +02:00
Tim Jaeryang Baek e05560a49d Merge pull request #15072 from PierreMesure/better-swedish-translation-1
Better swedish translation 1
2025-06-18 10:59:43 +04:00
Tim Jaeryang Baek 05aaefd8a5 Merge pull request #15085 from qingchunnh/Update_zh-CN-25618
i18n: Update & Improve zh-CN
2025-06-18 10:59:09 +04:00
Tim Jaeryang Baek 58b5d2b727 Merge pull request #15097 from silentoplayz/index-update
Refactor: Add missing Type definitions
2025-06-18 10:55:44 +04:00
Timothy Jaeryang Baek 0134b5eca4 fix: action reserved user param 2025-06-18 10:50:49 +04:00
Silentoplayz 3be4fb25cd fix: add ? 2025-06-18 02:01:21 -04:00
Silentoplayz d66285f926 chore: add toolIds type 2025-06-18 01:55:43 -04:00
Silentoplayz 35be40c932 chore: add more Settings types in stores 2025-06-18 01:48:34 -04:00
Silentoplayz 898b65a653 fix: sanatizeResponseContent for stop token display 2025-06-18 00:12:11 -04:00
Silentoplayz b120637127 fix: refine folder component's drag-&-drop error handling 2025-06-17 23:27:45 -04:00
qingchun 70968a6caf i18n: Update & Improve zh-CN 2025-06-18 01:17:41 +08:00
Pierre 8a169d5c8e Update Swedish translation 2025-06-17 19:09:38 +02:00
d2a-pnagel 5f82631ae6 Update translation.json 2025-06-17 14:23:53 +02:00
d2a-pnagel fdeded4a20 Fix obvious typos in Dutch translation 2025-06-17 14:22:46 +02:00
Tim Jaeryang Baek 3b70841a7d Merge pull request #15049 from silentoplayz/fixopeninnewtab
fix: regression for "open in new tab"
2025-06-17 15:27:11 +04:00
Tim Jaeryang Baek 23c679d8db Merge pull request #15065 from aleixdorca/dev
i18n: Update Catalan translation.json
2025-06-17 14:25:53 +04:00
Tim Jaeryang Baek 8a587f9f84 Merge pull request #15066 from bogdanr/dev
i18n: Added a few Romanian translations
2025-06-17 14:25:44 +04:00
Timothy Jaeryang Baek fb26be7dd6 fix: confirm dialog input reset on show 2025-06-17 14:24:23 +04:00
Aleix Dorca 8908e834ac Update Catalan translation.json 2025-06-17 12:07:06 +02:00
Bogdan Radulescu 098091c95e Added a few Romanian translations 2025-06-17 12:57:09 +03:00
Tim Jaeryang Baek e866fba27c Merge pull request #15059 from d2a-raudenaerde/main
i18n Fix a incorrect translation of dutch ("Analyzing" -> from "Analysiseren" to  "Analyseren")
2025-06-17 13:23:54 +04:00
Classic298 872b0ac943 Update General.svelte 2025-06-17 11:23:24 +02:00
Classic298 22b02af703 Update General.svelte 2025-06-17 11:22:34 +02:00
Classic298 7de0e49dc6 Update Controls.svelte 2025-06-17 11:21:24 +02:00
Classic298 c330f06542 Merge branch 'dev' into system-prompt-high-contrast 2025-06-17 11:10:03 +02:00
Rob Audenaerde 6a613c2dd6 Update translation.json 2025-06-17 10:44:23 +02:00
Tim Jaeryang Baek 4254469a33 Merge pull request #15025 from Mte90/patch-1
Italian translation improved
2025-06-17 12:23:28 +04:00
Tim Jaeryang Baek 52cffef16e Merge pull request #15028 from Classic298/system-prompt-resizing
feat: System prompt input field resizable
2025-06-17 12:23:06 +04:00
Tim Jaeryang Baek d50449ea71 Merge pull request #15035 from decent-engineer-decent-datascientist/dev
fix: Resolve UnicodeEncodeError for non-ASCII usernames in forwarded headers
2025-06-17 12:22:02 +04:00
Timothy Jaeryang Baek cd975a1047 Update pyproject.toml 2025-06-17 12:17:02 +04:00
Silentoplayz 354dd3caa9 fix: regression for "open in new tab" 2025-06-16 23:27:16 -04:00
Classic298 c66576805b Merge branch 'open-webui:main' into fix-postgresql-null-value-search 2025-06-16 21:11:30 +02:00
Classic298 beb1f3f7fd Merge branch 'open-webui:main' into system-prompt-resizing 2025-06-16 21:11:21 +02:00
Classic298 c8c4e1642f Merge branch 'open-webui:main' into correct-markdown-rendering-model-descriptions 2025-06-16 21:11:18 +02:00
Classic298 135b57ca8e Update Placeholder.svelte 2025-06-16 20:28:50 +02:00
priten 8a63a601de Fix typo on ollama patch 2025-06-16 12:35:09 -05:00
priten f7920df870 Fix non-ascii error issue on ENABLE_FORWARD_USER_INFO_HEADERS 2025-06-16 12:33:11 -05:00
Classic298 5261d3d31e Update General.svelte 2025-06-16 19:26:57 +02:00
Classic298 088243349d Update Controls.svelte 2025-06-16 19:26:33 +02:00
Classic298 9d37350b97 Update Markdown.svelte 2025-06-16 18:08:20 +02:00
Classic298 4f9ce28a15 Update ChatPlaceholder.svelte 2025-06-16 18:07:30 +02:00
Classic298 9f936a0c19 Update General.svelte 2025-06-16 17:48:45 +02:00
Classic298 85724940ee Update Controls.svelte 2025-06-16 17:48:00 +02:00
Daniele Scasciafratte a7772b4b35 Italian translation improved 2025-06-16 17:09:29 +02:00
Tim Jaeryang Baek b5f4c85bb1 Merge pull request #15014 from open-webui/dev
0.6.15
2025-06-16 18:34:32 +04:00
Timothy Jaeryang Baek 340d9820b8 refac 2025-06-16 18:33:45 +04:00
Timothy Jaeryang Baek 597709c64c doc: changelog 2025-06-16 18:30:51 +04:00
Timothy Jaeryang Baek 84fd41e6ef doc: changelog 2025-06-16 18:29:38 +04:00
Timothy Jaeryang Baek 3917b04ed3 doc: changelog 2025-06-16 18:27:18 +04:00
Timothy Jaeryang Baek b6ea043d18 chore: format 2025-06-16 17:59:07 +04:00
Timothy Jaeryang Baek b082a7edbe enh: allow iframe in content 2025-06-16 17:43:17 +04:00
Timothy Jaeryang Baek 72df23ed79 refac 2025-06-16 17:24:55 +04:00
Timothy Jaeryang Baek 11476eb6ee chore: format 2025-06-16 17:21:22 +04:00
Tim Jaeryang Baek 7096baff1b Merge pull request #15021 from rgaricano/dev
i18n: es-ES Translation v.0.6.15
2025-06-16 17:19:44 +04:00
Tim Jaeryang Baek 2885ed9648 Merge pull request #15019 from itk-dev/feature/high-contrast-mode-tools-section
Feature/high contrast mode tools section
2025-06-16 17:19:30 +04:00
Timothy Jaeryang Baek ab877e1d7e refac 2025-06-16 17:18:43 +04:00
_00_ b13a824047 UPD: es-ES Translation v.0.6.15
UPD: es-ES Translation v.0.6.15
2025-06-16 15:06:33 +02:00
Timothy Jaeryang Baek 9cbe2644b1 refac 2025-06-16 16:59:47 +04:00
Timothy Jaeryang Baek 6c54ca552a feat: global image compression 2025-06-16 16:52:57 +04:00
Timothy Jaeryang Baek 2949be4f27 refac 2025-06-16 16:33:48 +04:00
Timothy Jaeryang Baek 8e139b04f0 refac: iframe include allow-downloads by default 2025-06-16 16:24:51 +04:00
Timothy Jaeryang Baek 76fe344eb8 refac 2025-06-16 16:21:57 +04:00
Timothy Jaeryang BaekandWilliamGates f3cae94028 fix: bypass webloader
Co-Authored-By: WilliamGates <3852641+williamgateszhao@users.noreply.github.com>
2025-06-16 16:17:52 +04:00
Timothy Jaeryang BaekandBryan Berns 7a1afa9c66 feat: custom stt content type
Co-Authored-By: Bryan Berns <berns@uwalumni.com>
2025-06-16 16:13:40 +04:00
Sine Jespersen 437b7c5171 add aria label to button without label for accessibility 2025-06-16 13:33:45 +02:00
Sine Jespersen 5211602c2f add text high contrast mode for accessibility 2025-06-16 13:33:25 +02:00
Timothy Jaeryang Baek 6a5aac43df refac 2025-06-16 15:29:40 +04:00
Tim Jaeryang Baek d6664369a1 Merge pull request #14886 from Constantinople-AI/fix-no-arg-mcp-call
Isolated fix to single section
2025-06-16 15:28:48 +04:00
Timothy Jaeryang Baek bc7defbdd0 refac: allow editing own email 2025-06-16 15:23:03 +04:00
Timothy Jaeryang Baek 99e18d49dc enh: system prompt user permission 2025-06-16 15:12:32 +04:00
Timothy Jaeryang Baek 1af128fb24 chore 2025-06-16 15:05:35 +04:00
Tim Jaeryang Baek b8103807cf Merge pull request #15018 from itk-dev/feature/interface-tab-settings-modal-accessibility
Feat: interface tab settings modal accessibility
2025-06-16 14:25:01 +04:00
Tim Jaeryang Baek d4f67bb266 Merge pull request #15017 from Bek85/i18n-uzbek
i18n: Add Uzbek (Cyrillic and Latin) i18n support
2025-06-16 14:24:30 +04:00
Timothy Jaeryang Baek f3deb8b8de refac 2025-06-16 14:01:03 +04:00
Timothy Jaeryang Baek 7753f57d42 chore: format 2025-06-16 13:48:50 +04:00
Timothy Jaeryang Baek 26d069080a refac 2025-06-16 13:45:36 +04:00
Timothy Jaeryang Baek d802c718a4 refac: max file count behaviour 2025-06-16 13:28:31 +04:00
Bekzod Akbarov ace2345a69 Add Uzbek (Cyrillic and Latin) i18n support
- Added `uz-Cyrl-UZ` and `uz-Latn-UZ` folders with `translation.json` files
- Updated `languages.json` to include both Uzbek language variants
2025-06-16 14:25:22 +05:00
Timothy Jaeryang Baek 59324a82e0 refac 2025-06-16 13:19:00 +04:00
Timothy Jaeryang Baek e46e87889e refac: pass through ollama error message 2025-06-16 13:03:56 +04:00
Sine Jespersen 6fcdd11fb2 add labels to image compression inputs 2025-06-16 10:56:54 +02:00
Sine Jespersen 047d8cec5d aria-labelledby on buttons to connect to labels 2025-06-16 10:51:12 +02:00
Tim Jaeryang Baek 61d8d2f2cb Merge pull request #14197 from jk-f5/otel_metrics
feat: Add OpenTelemetry Metrics Support via OTLP Exporter
2025-06-16 12:49:41 +04:00
Timothy Jaeryang Baek 51e05988bd refac 2025-06-16 12:46:04 +04:00
Tim Jaeryang Baek b37907671e Merge pull request #15010 from itk-dev/feature/outline-hidden-depend-on-high-contrast-mode
Feat: outline hidden depend on high contrast mode
2025-06-16 12:43:33 +04:00
Tim Jaeryang Baek 0e245c0afc Merge pull request #15011 from itk-dev/feature/outline-hidden-depend-on-high-contrast-mode-selects-general-tab
outline-hidden depend on highcontrastmode in selects
2025-06-16 12:42:54 +04:00
Timothy Jaeryang Baek b748d5edee fix: direct tool servers permissions 2025-06-16 12:42:16 +04:00
Timothy Jaeryang Baek debe3c752f chore: python-pptx bump 2025-06-16 12:39:42 +04:00
Timothy Jaeryang Baek ea578af45f refac: use first user message as title instead of 'new chat' 2025-06-16 12:37:41 +04:00
Timothy Jaeryang Baek 8258dfb5af enh: enable deepgram smart_format 2025-06-16 12:34:01 +04:00
Sine Jespersen 1909505466 make header h1 instead of div 2025-06-16 10:33:48 +02:00
Timothy Jaeryang Baek f98ea78964 refac: remove user & access_control field from files 2025-06-16 12:31:52 +04:00
Sine Jespersen f1e38fa376 outline-hidden depend on highcontrastmode in selects 2025-06-16 10:26:54 +02:00
Timothy Jaeryang Baek 090234735a Update apple-touch-icon.png 2025-06-16 12:13:51 +04:00
Timothy Jaeryang Baek afca606063 refac: banner scrollbar 2025-06-16 12:06:33 +04:00
Sine Jespersen 0d473a456a maje outline-hidden depend on highContrastMode due to accessibility 2025-06-16 10:05:34 +02:00
Timothy Jaeryang Baek 4a2428123b refac 2025-06-16 12:04:31 +04:00
Timothy Jaeryang Baek ba6fc385bb refac: styling 2025-06-16 12:04:15 +04:00
Timothy Jaeryang Baek 4db0da2b75 refac 2025-06-16 12:02:34 +04:00
Timothy Jaeryang Baek 5ab95cbc3a refac: remove redundant overlay with temp chat 2025-06-16 11:57:56 +04:00
Timothy Jaeryang BaekandClassic298 3b0da53457 feat: load-url search param added
Co-Authored-By: Classic298 <27028174+Classic298@users.noreply.github.com>
2025-06-16 11:55:23 +04:00
Tim Jaeryang Baek 5d90e31ab6 Merge pull request #15009 from itk-dev/feature/password-button-accessibility-again
Feat: password button accessibility again
2025-06-16 11:52:39 +04:00
Timothy Jaeryang Baek dc3055873b refac: display full model name on hover 2025-06-16 11:50:26 +04:00
Timothy Jaeryang Baek f5d250820b refac 2025-06-16 11:46:02 +04:00
Timothy Jaeryang Baek 8892c14984 refac 2025-06-16 11:44:07 +04:00
Sine Jespersen 75883dc835 outline-hidden depend on high contrast mode 2025-06-16 09:43:47 +02:00
Sine Jespersen d1677635a5 add label visible to screen readers to sensitive input 2025-06-16 09:41:29 +02:00
Sine Jespersen 400c4c3d12 add aria pressed to toggle visibility button, to show current state 2025-06-16 09:40:41 +02:00
Timothy Jaeryang Baek a47e3b429e fix/refac: enforce multiple models permission to imported chats 2025-06-16 11:40:13 +04:00
Timothy Jaeryang Baek 805e980ae5 fix: notes permissions issue 2025-06-16 11:35:01 +04:00
Timothy Jaeryang Baek b50cfd0940 refac 2025-06-16 11:14:24 +04:00
Sine Jespersen 53d044f8a2 add aria label to button with no other label 2025-06-16 09:12:12 +02:00
Sine Jespersen 0e95af01ea remove decorative svg from screen readers 2025-06-16 09:11:50 +02:00
Tim Jaeryang Baek c5b48ec551 Merge pull request #14992 from sreesdas/dev
Fix: Added support for multiple pages in external document loader
2025-06-16 11:01:33 +04:00
Timothy Jaeryang Baek e0ffe234ba refac: styling 2025-06-16 10:58:04 +04:00
Timothy Jaeryang Baek e0917e9f38 refac: new chat button moved to the leftside 2025-06-16 10:54:50 +04:00
Timothy Jaeryang Baek 177f2902db refac 2025-06-16 10:51:30 +04:00
Timothy Jaeryang Baek 423a35782b refac: usage event handling 2025-06-16 10:42:34 +04:00
Tim Jaeryang Baek deaa7133a2 Merge pull request #14903 from vaclcer/vaclavs-docling-picture-describe-fix
fix: Docling - serialize picture description parameters
2025-06-16 09:58:05 +04:00
Tim Jaeryang Baek 37658e06a2 Merge pull request #14857 from Classic298/feat/code-interpreter-url-param
feat: Enable Code Interpreter using URL Parameter
2025-06-16 09:57:25 +04:00
Tim Jaeryang Baek 1f7a93b0fb Merge pull request #14937 from silentoplayz/situational-keyboard-shortcuts
feat: Add New Keyboard Shortcuts with asterisk and tooltip to imply situational
2025-06-16 09:54:05 +04:00
Tim Jaeryang Baek 866c61bac6 Merge pull request #14982 from silentoplayz/fix-drag
fix: Replace Inline SVGs with Icon Components and Convert Links to Buttons
2025-06-16 09:53:17 +04:00
Tim Jaeryang Baek c2b4b76a90 Merge pull request #14944 from silentoplayz/sort-feedbacks
feat: Implement Client-Side Sorting for Feedback History Table
2025-06-16 09:48:17 +04:00
Tim Jaeryang Baek 5a4a293a93 Merge branch 'dev' into sort-feedbacks 2025-06-16 09:47:51 +04:00
Timothy Jaeryang Baek c060e70089 refac: styling 2025-06-16 09:43:34 +04:00
Timothy Jaeryang Baek e34f11f5cc refac: styling 2025-06-16 09:40:40 +04:00
Timothy Jaeryang Baek 3e55c7f333 refac 2025-06-16 09:36:29 +04:00
Tim Jaeryang Baek b8a4824305 Merge pull request #14985 from Classic298/multi-model-chat-highlighting
Feat: Improve selected message highlighting for multi-model chats
2025-06-16 09:21:05 +04:00
Tim Jaeryang Baek 2251a50451 Merge pull request #14990 from SadmL/patch-1
[i18n] Russian locale update
2025-06-16 09:18:33 +04:00
sree 62bfe73964 Fix: Added support for multiple pages in external document loader, added filename in api request header 2025-06-15 19:59:05 +05:30
Link [Связной] 2eeffc8c59 [i18n] Russian locale update 2025-06-15 13:54:49 +03:00
Silentoplayz 6e8c6e269e fix: select-none w-full 2025-06-14 18:26:27 -04:00
Classic298 14cfd4599c Improve selected message highlight (#12) 2025-06-14 21:49:33 +02:00
Silentoplayz 4fd7bfe19b refac: Icon files for UserMenu 2025-06-14 14:31:20 -04:00
Silentoplayz 9ccb9a87e6 fix: Prevent draggable links for Admin Panel & Playground in UserMenu 2025-06-14 13:56:30 -04:00
Tim Jaeryang Baek 53060a44ae Merge pull request #14941 from silentoplayz/chat-bubble-timestamp-on-mouse-hover
Feat: Show timestamp on hover of user message in Chat Bubble UI mode
2025-06-14 18:06:47 +04:00
Tim Jaeryang Baek 4c7c5dd860 Merge pull request #14911 from ayanahye/feedback-evaluation-modal
Feat: add modal to display more evaluation information in Feedback History
2025-06-14 18:01:05 +04:00
Tim Jaeryang Baek 69be2a1bc9 Merge pull request #14949 from ayanahye/leaderboard-evaluation-additions
Feat: add initial modal for the leaderboard
2025-06-14 18:00:17 +04:00
Tim Jaeryang Baek 42b8463fcc Merge pull request #14959 from itk-dev/feature/accessibility-edit-connection-modal
Feature/accessibility edit connection modal
2025-06-14 17:58:38 +04:00
Tim Jaeryang Baek 35df44d07e Merge pull request #14971 from qingchunnh/Update_zh-CN-25614
i18n: Update zh-CN
2025-06-14 16:53:16 +04:00
qingchun 652e1a6b19 i18n: Update zh-CN 2025-06-14 02:34:08 +08:00
Sine Jespersen 78fcfbb328 hide decorative svg 2025-06-13 14:43:03 +02:00
Sine Jespersen 33a3aed698 remove repeated classes 2025-06-13 14:42:55 +02:00
Sine Jespersen d0a114869e make taglist a list and add aria-labels 2025-06-13 14:10:29 +02:00
Sine Jespersen 7d8fb116b6 Use <ul and <li because the items are a list 2025-06-13 14:10:29 +02:00
Sine Jespersen 6f73561f7a remove decorative svg from screen readers 2025-06-13 14:10:29 +02:00
Sine Jespersen a710ea1f07 add aria label to delete button 2025-06-13 14:10:29 +02:00
Sine Jespersen b95bc727df add label for screen readers for model id input 2025-06-13 14:10:29 +02:00
Sine Jespersen ba9e9e8095 add aria label to button with no label 2025-06-13 14:10:29 +02:00
Sine Jespersen 47c65bac6c remove decorative svg from screen readers 2025-06-13 14:10:29 +02:00
Sine Jespersen 85018dd106 high contrast mode on placeholder 2025-06-13 14:10:29 +02:00
Sine Jespersen 669a9f0777 highContrastMode (for accessibility) on text color in add connection modal 2025-06-13 14:10:28 +02:00
Sine Jespersen 1160a03644 change label for url to label instead of div 2025-06-13 14:10:28 +02:00
Sine Jespersen 843810cc9f add aria hidden to decorative svg 2025-06-13 14:10:28 +02:00
Sine Jespersen 8b5f5bb327 add label to verify connection button 2025-06-13 14:10:28 +02:00
Sine Jespersen 15efb07961 add label to toggle connection button in configure connect modal 2025-06-13 14:10:28 +02:00
Sine Jespersen a1034a4ca3 correct classname to inputclassname as prop is named this 2025-06-13 14:10:28 +02:00
Tim Jaeryang Baek 4978dd9085 Merge pull request #14943 from jk-f5/fix/oauth
Fix double‐slash (//auth) in OAuth callback redirect
2025-06-13 16:08:28 +04:00
Tim Jaeryang Baek 0b8f86d27b Merge pull request #14946 from t-rekttt/patch-1
fix: Page number 1 not displaying in citation references
2025-06-13 16:06:07 +04:00
Tim Jaeryang Baek 6918eb44ac Merge pull request #14953 from itk-dev/feature/aria-label-on-cog-button
Feat: aria label on cog button
2025-06-13 16:04:55 +04:00
Tim Jaeryang Baek 91af2698be Merge pull request #14958 from Ithanil/disable_console_log
feat: Disable console.log/debug in production
2025-06-13 16:04:13 +04:00
Jan Kessler 4681b06206 also disable console.debug 2025-06-13 13:54:40 +02:00
Jan Kessler aecbc93c16 disable console.log entirely 2025-06-13 13:39:16 +02:00
Classic298 033e5c1e00 Update chats.py 2025-06-13 13:07:41 +02:00
Classic298 e50cde80f3 Fix search unicode error (#11) 2025-06-13 13:05:33 +02:00
Sine Jespersen 0313ac0166 aria-hidden true on decorative svg 2025-06-13 10:46:39 +02:00
Sine Jespersen 87a837f850 add aria label to cog button in connections tab in settings modal 2025-06-13 10:46:27 +02:00
Ayana H 4bb41d3ead Merge branch 'dev' into leaderboard-evaluation-additions 2025-06-12 22:41:20 -07:00
ayana edf927516e Add initial modal for the leadderboard as well 2025-06-12 22:28:06 -07:00
T-Rekt 190400d1e8 Fix: page number edge case
Fix when document?.metadata?.page == 0 (page 1), the page number will not be displayed
2025-06-13 04:49:17 +07:00
Silentoplayz 380a31fbac Feat: Implement Client-Side Sorting for Feedback History Table 2025-06-12 16:13:33 -04:00
Jason Kidd fced3efd98 fix: Trailing slash was never removed from request.base_url because it's not a string but rather a starlette.datastructures.URL 2025-06-12 12:29:08 -07:00
Silentoplayz d92d555c03 Feat: Show user message timestamps on hover in Chat Bubble UI mode 2025-06-12 15:13:24 -04:00
ayana 880323a4e4 update based on requested changes 2025-06-12 10:53:55 -07:00
Tim Jaeryang Baek 8a2723a7a6 Merge pull request #14922 from itk-dev/feature/high-contrast-mode-in-connections-tab-in-settings-modal
Feat: high contrast mode in connections tab in settings modal
2025-06-12 20:40:01 +04:00
Tim Jaeryang Baek 2ff889dce0 Merge pull request #14933 from itk-dev/feature/accessibility-add-edit-connection-modal
Feat: accessibility add edit connection modal
2025-06-12 20:38:35 +04:00
Tim Jaeryang Baek 6c677e4b28 Merge pull request #14868 from ayanahye/evaluation-additions
Feat: add ability to sort leaderboard
2025-06-12 20:32:47 +04:00
Silentoplayz a98661735f feat: Add New Keyboard Shortcuts with asterisk and tooltip to imply situational 2025-06-12 09:47:17 -04:00
Sine Jespersen b446bea6d1 hide decorative svg from screen readers 2025-06-12 14:37:01 +02:00
Sine Jespersen 6faa9db4a7 add aria-label to button without label 2025-06-12 14:36:44 +02:00
Sine Jespersen 2b276583c3 change div to h1, because it is the main header in the modal 2025-06-12 14:34:26 +02:00
Tim Jaeryang Baek 80a5aa7259 Merge pull request #14923 from flex-mincheol/feature/i18n-ko-kr
i18n: Update ko-KR (Korean) translation.json
2025-06-12 13:36:28 +04:00
Sine Jespersen 9d76f30f9b high contrast mode on text in connections tab on settings modal 2025-06-12 11:01:02 +02:00
Tim Jaeryang Baek 09bbcee391 Merge pull request #14893 from tcx4c70/fix/log-format-error
fix(tools): not all arguments converted during string formatting
2025-06-12 12:30:31 +04:00
Timothy Jaeryang Baek c2aa5b7399 chore: youtube-transcript-api bump 2025-06-12 12:25:28 +04:00
Timothy Jaeryang Baek 9b9d5d84f4 fix: trusted header email case sensitive issue 2025-06-12 12:22:15 +04:00
flex-mincheol 389dbd1983 i18n: Update ko-KR (Korean) translation.json 2025-06-12 17:08:43 +09:00
ayana 2f8c0b6b26 Feat: add modal to display for evaluation information in Feedbacks 2025-06-11 19:34:07 -07:00
ayana 464c67eb46 use different notation 2025-06-11 18:27:13 -07:00
Vaclav Cerny 4bbc32efa6 fix: serialize picture description parameters to JSON in DoclingLoader 2025-06-11 20:00:25 +02:00
Tim Jaeryang Baek c27d8a4a28 Merge pull request #14900 from silentoplayz/fix-references
fix: prevent redundant documents in expanded citation list
2025-06-11 21:13:30 +04:00
Timothy Jaeryang Baek 371bdd7afa refac 2025-06-11 20:40:19 +04:00
Tim Jaeryang Baek 0d00971dad Merge pull request #14898 from jackthgu/ldap-group-sync
feat: Configure LDAP group synchronization with Open WebUI
2025-06-11 20:23:53 +04:00
Tim Jaeryang Baek 80c359c24e Merge pull request #14888 from silentoplayz/i18n-fix2
chore: consistent apostrophe usage in components and i18n files
2025-06-11 20:19:32 +04:00
Timothy Jaeryang Baek 6076afd5f5 fix: url param issue
#14901
2025-06-11 20:16:53 +04:00
Silentoplayz 8e60174e0d fix: prevent redundant documents in expanded citation list 2025-06-11 11:37:46 -04:00
Taehong Gu ba591d8c41 Configure LDAP group synchronization with Open WebUI 2025-06-11 23:55:31 +09:00
Tim Jaeryang Baek 387c2377ba Merge pull request #14890 from itk-dev/feature/hide-decorative-svgs
Feat: aria hidden on svg/icons
2025-06-11 17:39:20 +04:00
Adam Tao 809d91a3df fix(tools): not all arguments converted during string formatting
Signed-off-by: Adam Tao <tcx4c70@gmail.com>
2025-06-11 21:36:36 +08:00
Sine Jespersen 99ff1684d0 aria hidden on svg/icons 2025-06-11 14:47:28 +02:00
Tim Jaeryang Baek 9a1d2a1844 Merge pull request #14878 from itk-dev/feature/settings-modal-tab-list
Feature: settings modal tab list
2025-06-11 16:36:06 +04:00
Sine Jespersen 5dd99a0ea7 add aria-controls and ids to connect tabs to content 2025-06-11 13:45:47 +02:00
Sine Jespersen aee60add1d add aria-selected to tabs 2025-06-11 13:42:50 +02:00
Sine Jespersen 6af91325e2 add roles tablist and tab to tabs in settings modal 2025-06-11 13:41:26 +02:00
Silentoplayz a3f3f58e54 chore: consistent apostrophe usage in components and i18n files 2025-06-11 07:15:44 -04:00
Timothy Jaeryang Baek bc5f7e31ac refac 2025-06-11 14:43:56 +04:00
Timothy Jaeryang Baek c70a037692 refac 2025-06-11 14:43:07 +04:00
Tim Jaeryang Baek bebbc24d27 Merge pull request #14860 from Classic298/patch-2
i18n: Add german translation for new model pinning feature
2025-06-11 14:15:48 +04:00
Tim Jaeryang Baek 4e61bdd109 Merge pull request #14858 from Kylapaallikko/dev
i18n: Update fi-FI translation
2025-06-11 14:15:38 +04:00
2underscores 88c8ea883c Isolated fix to single section 2025-06-11 19:58:55 +10:00
Timothy Jaeryang Baek 9123c57c8a refac 2025-06-11 12:12:29 +04:00
ayana af285297bc Feat: add ability to sort leaderboard 2025-06-10 21:09:25 -07:00
Classic298 5c156c854b Update translation.json 2025-06-10 21:19:24 +02:00
google-labs-jules[bot] 70333c4dcf feat: Enable Code Interpreter via URL parameter
Adds the ability to enable the Code Interpreter feature by appending
`code-interpreter=true` to the chat URL.

The `Chat.svelte` component's `initNewChat` function has been updated
to parse this URL parameter. If present, it sets the
`codeInterpreterEnabled` state variable to true.

This change leverages the existing mechanisms for:
- Saving and restoring `codeInterpreterEnabled` state to/from localStorage.
- Displaying and toggling the Code Interpreter state via the existing UI
  button in the `MessageInput` component.

No new UI elements were added as the existing UI correctly reflects
the feature's state.
2025-06-10 18:56:49 +00:00
Kylapaallikko 1ca70b886b Update fi-FI translation.json 2025-06-10 21:51:29 +03:00
Jason Kidd 210dc746f0 feat: Add OpenTelemetry Metrics Support via OTLP Exporter 2025-06-10 10:52:10 -07:00
Tim Jaeryang Baek 63256136ef Merge pull request #14675 from open-webui/dev
0.6.14
2025-06-10 18:17:50 +04:00
Timothy Jaeryang Baek fd8cdb383c doc: changelog 2025-06-10 18:10:20 +04:00
Timothy Jaeryang Baek ab42a192e6 refac: styling 2025-06-10 17:54:08 +04:00
Timothy Jaeryang Baek adab4dbf21 chore: bump 2025-06-10 17:50:32 +04:00
Tim Jaeryang Baek c14160d73a Merge pull request #14845 from itk-dev/feature/accessibility-aria-label-close-button-and-aria-hidden-svg
Feat: accessibility aria label close button and aria hidden svg
2025-06-10 17:37:31 +04:00
Timothy Jaeryang Baek a7330d97da chore: format 2025-06-10 16:53:37 +04:00
Timothy Jaeryang Baek b39d33cefb refac 2025-06-10 16:52:37 +04:00
Timothy Jaeryang Baek d2e7feea86 refac 2025-06-10 16:42:26 +04:00
Timothy Jaeryang Baek a018140c7d refac: admin settings models 2025-06-10 16:41:39 +04:00
Timothy Jaeryang Baek 9931ccef1e refac 2025-06-10 16:20:57 +04:00
Sine Jespersen 56b012e3a6 danish translation added 2025-06-10 14:06:14 +02:00
Sine Jespersen c9820d65a6 add aria-hidden to svg, as this is decorative and only cause confusion for users with assistive tech 2025-06-10 13:59:27 +02:00
Sine Jespersen 9c1c11cad0 use xmark icon instead of inline svg 2025-06-10 13:58:58 +02:00
Sine Jespersen 8b5ecfb2fe Add aria label to close button 2025-06-10 13:52:24 +02:00
Tim Jaeryang Baek 3e81705dd3 Merge pull request #14837 from itk-dev/feature/menu-link-anchor
Feat: menu link anchor
2025-06-10 15:10:58 +04:00
Tim Jaeryang Baek 5168d612dc Merge pull request #14838 from Classic298/Classic298-patch-1
i18n: Small german translation update
2025-06-10 15:09:16 +04:00
Classic298 e67ab489aa Merge branch 'dev' into Classic298-patch-1 2025-06-10 13:07:24 +02:00
Classic298 c11cc58b00 Small german translation update 2025-06-10 12:54:17 +02:00
Sine Jespersen 3288b82175 change admin settings link to anchor instead of button 2025-06-10 12:49:18 +02:00
Timothy Jaeryang Baek f67f86f06f refac: styling 2025-06-10 14:33:49 +04:00
Timothy Jaeryang Baek c4cd2b55f0 refac: styling 2025-06-10 14:13:52 +04:00
Timothy Jaeryang Baek bacf39902b refac: styling 2025-06-10 14:02:43 +04:00
Tim Jaeryang Baek aeb81767a9 Merge pull request #14834 from SadmL/patch-1
[i18n] Russian locale update
2025-06-10 13:57:23 +04:00
Timothy Jaeryang Baek 884282c4ed refac: styling 2025-06-10 13:57:13 +04:00
Timothy Jaeryang Baek f55579ce25 refac 2025-06-10 13:55:25 +04:00
Link [Связной] 02f5bfba73 [i18n] Russian locale update 2025-06-10 12:54:31 +03:00
Tim Jaeryang Baek f29c9d8dcf Merge pull request #14833 from open-webui/dependabot/pip/pip-512858e340
build(deps): bump requests from 2.32.3 to 2.32.4 in the pip group across 1 directory
2025-06-10 13:45:47 +04:00
Timothy Jaeryang Baek 4c65728443 chore: format 2025-06-10 13:43:18 +04:00
Timothy Jaeryang Baek b36b480b43 refac 2025-06-10 13:40:36 +04:00
Tim Jaeryang Baek b8450ecf01 Merge pull request #14832 from itk-dev/feature/high-contrast-mode-and-label-menu-search-bar
FEAT: high contrast mode and label menu search bar
2025-06-10 13:40:14 +04:00
Timothy Jaeryang Baek 464b086ec5 refac 2025-06-10 13:39:41 +04:00
dependabot[bot] fc83842ab2 build(deps): bump requests in the pip group across 1 directory
Bumps the pip group with 1 update in the / directory: [requests](https://github.com/psf/requests).


Updates `requests` from 2.32.3 to 2.32.4
- [Release notes](https://github.com/psf/requests/releases)
- [Changelog](https://github.com/psf/requests/blob/main/HISTORY.md)
- [Commits](https://github.com/psf/requests/compare/v2.32.3...v2.32.4)

---
updated-dependencies:
- dependency-name: requests
  dependency-version: 2.32.4
  dependency-type: direct:production
  dependency-group: pip
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-10 09:38:48 +00:00
Tim Jaeryang Baek 7b248fc1f4 Merge pull request #14830 from open-webui/dependabot/pip/backend/pip-512858e340
build(deps): bump requests from 2.32.3 to 2.32.4 in /backend in the pip group across 1 directory
2025-06-10 13:37:49 +04:00
Timothy Jaeryang Baek a28bec865b refac 2025-06-10 13:16:44 +04:00
Timothy Jaeryang Baek b7a91b1963 refac: ollama response 2025-06-10 13:10:31 +04:00
Timothy Jaeryang Baek 2ccc441b41 refac 2025-06-10 13:01:45 +04:00
dependabot[bot] 106494aa79 build(deps): bump requests
Bumps the pip group with 1 update in the /backend directory: [requests](https://github.com/psf/requests).


Updates `requests` from 2.32.3 to 2.32.4
- [Release notes](https://github.com/psf/requests/releases)
- [Changelog](https://github.com/psf/requests/blob/main/HISTORY.md)
- [Commits](https://github.com/psf/requests/compare/v2.32.3...v2.32.4)

---
updated-dependencies:
- dependency-name: requests
  dependency-version: 2.32.4
  dependency-type: direct:production
  dependency-group: pip
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-10 08:56:03 +00:00
Timothy Jaeryang Baek 0b336fb6f1 refac 2025-06-10 12:53:18 +04:00
Timothy Jaeryang Baek 8f68b25510 enh/refac: ollama advanced params 2025-06-10 12:48:34 +04:00
Sine Jespersen 7fd5304e76 add assistive technology accessible label for search input in settings modal 2025-06-10 10:27:06 +02:00
Sine Jespersen af0f2a678e highContrastMode on search input in settingsmodal for accessibility 2025-06-10 10:25:40 +02:00
Timothy Jaeryang Baek ad80643774 refac: styling 2025-06-10 12:15:47 +04:00
Tim Jaeryang Baek 6e11bf73a7 Merge pull request #14827 from itk-dev/feature/high-contrast-mode-menu
FEAT: high contrast mode menu
2025-06-10 11:49:47 +04:00
Sine Jespersen ce45939463 add highContrastMode to menu items/tabs to improve contrast 2025-06-10 09:39:10 +02:00
Timothy Jaeryang Baek d430fe9551 refac 2025-06-10 11:30:54 +04:00
Timothy Jaeryang Baek 7f488b3754 feat: experimental pgvector pgcrypto support 2025-06-09 18:14:33 +04:00
Tim Jaeryang Baek 6d4f449085 Merge pull request #14775 from janaki-sasidhar/fix/insecure-user-switching-when-trusted-email-header
fix: verify trusted email header matches active user session
2025-06-09 17:44:30 +04:00
Timothy Jaeryang Baek 7953aa5763 refac 2025-06-09 17:43:22 +04:00
Tim Jaeryang Baek 95f54f5778 Merge pull request #14811 from SadmL/patch-1
[i18n] Russian locale update
2025-06-09 17:40:35 +04:00
Timothy Jaeryang Baek 51fc98bed8 refac 2025-06-09 17:24:03 +04:00
Timothy Jaeryang Baek ea8dc333ee refac/fix: multi-replica tasks 2025-06-09 17:21:10 +04:00
Link [Связной] 5447ac2de6 [i18n] Russian locale update 2025-06-09 15:43:17 +03:00
Timothy Jaeryang Baek 5fae7360fb refac: hide profile image in mobile 2025-06-09 16:35:20 +04:00
Timothy Jaeryang Baek db3c26ab7a refac: async redis 2025-06-09 15:37:05 +04:00
Timothy Jaeryang Baek 8da1ce358f refac: model selector styling 2025-06-09 11:22:31 +04:00
Timothy Jaeryang Baek ce9455b9a2 refac: styling 2025-06-09 10:43:47 +04:00
Tim Jaeryang Baek 36e5e51510 Merge pull request #14797 from qingchunnh/Update_zh-CN-2569-2
i18n: Update zh-CN
2025-06-09 10:13:28 +04:00
qingchun 7f39097879 i18n: Update zh-CN 2025-06-09 13:04:54 +08:00
Timothy Jaeryang Baek 9409083d0b refac 2025-06-09 02:16:23 +04:00
Timothy Jaeryang Baek 2573882b88 refac 2025-06-09 02:13:25 +04:00
Timothy Jaeryang Baek d1be1de013 fix: typo 2025-06-09 01:50:10 +04:00
Timothy Jaeryang Baek 7c03601425 chore: bump 2025-06-09 01:49:01 +04:00
Timothy Jaeryang Baek 053ab2838b chore: format 2025-06-09 01:48:29 +04:00
Timothy Jaeryang Baek 602bb55434 refac: styling 2025-06-09 01:45:41 +04:00
Timothy Jaeryang Baek 19c09d216d revert 2025-06-09 01:36:32 +04:00
Tim Jaeryang Baek 7a11fd2a4d Merge pull request #14793 from qingchunnh/Update_zh-CN-2569
i18n: Update & Improve zh-CN
2025-06-09 01:31:51 +04:00
Tim Jaeryang Baek c04569fdd4 Merge pull request #14791 from aindriu80/my-clean-fix
i18n: Updated Irish translation
2025-06-09 01:31:44 +04:00
Timothy Jaeryang Baek b0da2c998b refac 2025-06-09 01:27:50 +04:00
Timothy Jaeryang Baek 86551de1f7 refac 2025-06-09 01:26:32 +04:00
Timothy Jaeryang Baek 2f338b6ae7 refac: styling 2025-06-09 01:25:42 +04:00
Timothy Jaeryang Baek a64667ca8d feat: pinned models 2025-06-09 01:24:11 +04:00
Timothy Jaeryang Baek 3448362e00 refac: styling 2025-06-09 01:16:08 +04:00
Timothy Jaeryang Baek 9cbe39718d refac 2025-06-09 01:14:40 +04:00
Timothy Jaeryang Baek 7969d8e8f3 refac 2025-06-09 00:53:16 +04:00
Timothy Jaeryang Baek c59b4cf379 chore: bump bits ui 2025-06-09 00:37:38 +04:00
Timothy Jaeryang Baek 5e91c2c1fe refac: styling 2025-06-09 00:33:41 +04:00
qingchun b66d86cb74 i18n: Update & Improve zh-CN 2025-06-09 03:24:43 +08:00
Aindriú Mac Giolla Eoin ec9e3ef2c3 Merge branch 'dev' into my-clean-fix 2025-06-08 19:32:34 +01:00
Aindriú Mac Giolla Eoin a3ed5045d3 i18n fix commit issue 2025-06-08 19:28:35 +01:00
Timothy Jaeryang Baek 7f75acff96 chore: format 2025-06-08 22:08:25 +04:00
Timothy Jaeryang Baek a944e1f526 fix: feedback score overflow styling 2025-06-08 21:29:05 +04:00
Timothy Jaeryang Baek 3a0696e1b0 refac 2025-06-08 21:21:51 +04:00
Timothy Jaeryang Baek d8d8380a78 refac/fix: multi-replica stop task (response) 2025-06-08 21:20:30 +04:00
Timothy Jaeryang Baek 0c57980e72 refac: tasks 2025-06-08 20:58:31 +04:00
Timothy Jaeryang Baek 51fe33395b refac 2025-06-08 20:27:08 +04:00
Timothy Jaeryang Baek 4fe45d4430 refac/security: python code format endpoint 2025-06-08 20:26:07 +04:00
Timothy Jaeryang Baek 87e5aee106 refac 2025-06-08 20:05:26 +04:00
Timothy Jaeryang Baek 0cd400f5ee refac: docling picture describe params 2025-06-08 20:02:14 +04:00
Timothy Jaeryang Baek b9c64d0936 refac: styling 2025-06-08 19:22:41 +04:00
Tim Jaeryang Baek 6cb519ca0e Merge pull request #14774 from rragundez/images-from-db
fix: Store and load code interpreter generated images from a central location (DB and/or cloud storage)
2025-06-08 19:09:28 +04:00
Tim Jaeryang Baek 6bf393a480 Merge pull request #14787 from vaclcer/vaclavs-custom-docling
feat: Customize Docling's "Describe Pictures" feature
2025-06-08 19:02:36 +04:00
Tim Jaeryang Baek ac4513a773 Merge pull request #14783 from mrexodia/local-dev-fixes
fix: Improve local development setup
2025-06-08 18:59:38 +04:00
Tim Jaeryang Baek dae4a7088e Merge pull request #14780 from qingchunnh/Update_zh-CN-2568
i18n: Update zh-CN
2025-06-08 18:40:44 +04:00
Tim Jaeryang Baek 50d9a2ac58 Merge pull request #14781 from lucyknada/patch-2
fix: fix #14752 and add manual transcription retrieval
2025-06-08 18:40:28 +04:00
Tim Jaeryang Baek 0b1c81791e Merge pull request #14779 from GewoonJaap/feature/audio-html-component
Add Audio HTML token support
2025-06-08 18:39:50 +04:00
Vaclav Cerny 99f05561f8 Add configuration options for picture description modes and update related components 2025-06-08 16:30:26 +02:00
Duncan Ogilvie 5e73fd569d Improve local development setup 2025-06-08 15:17:08 +02:00
Duncan Ogilvie 7010393a41 Change default CORS_ALLOW_ORIGIN to '*'
The local development setup defaults do not actually work currently.
2025-06-08 15:16:51 +02:00
Duncan Ogilvie 41220b379f Exclude the 'backend' folder from the Vite watcher.
This avoids unnecessary reloads when working on the backend.
2025-06-08 14:58:56 +02:00
lucy b0965a8184 fixes #14752 and adds manual transcription option 2025-06-08 14:26:24 +02:00
qingchun 76d1690a0c i18n: Update zh-CN 2025-06-08 19:56:11 +08:00
Jaap d269c4b8e6 Audio token 2025-06-08 12:08:07 +02:00
Tim Jaeryang Baek 2b9c466bed Merge pull request #14765 from diwakar-s-maurya/patch-10
fix: save Document settings only when Save button is pressed
2025-06-08 13:05:51 +04:00
Tim Jaeryang Baek 1facc4485a Merge pull request #14766 from EntropyYue/feature/secret-key-file
feat: add support for WEBUI_SECRET_KEY_FILE
2025-06-08 13:05:29 +04:00
Tim Jaeryang Baek de3e474224 Merge pull request #14769 from RGSS3/main
The translation might be confusing, in some cases for example tooltip…
2025-06-08 13:04:50 +04:00
Tim Jaeryang Baek cc563d9763 Merge pull request #14770 from silentoplayz/small-fix
fix: remove newline from Pending User Overlay Title input field
2025-06-08 13:04:19 +04:00
Tim Jaeryang Baek ffe7bdd213 Merge pull request #14772 from silentoplayz/fix-save-for-LDAP
Fix: Ensure Consistent LDAP Settings Save
2025-06-08 13:03:17 +04:00
sasidhar 6860dec08f fix: properly sign out user on trusted email mismatch
When using trusted email header authentication, properly sign out the user
when the logged-in user's email doesn't match the trusted email header value.
This ensures proper session cleanup when the OAuth server changes the
authenticated user.

- Add response parameter to get_current_user function
- Delete JWT token cookie on email mismatch
- Delete OAuth token cookie if present
- Force re-authentication with 401 error
2025-06-08 14:26:55 +05:30
sasidhar 61f49ff580 fix: ensure trusted email header matches logged-in user
When using trusted email header authentication, verify that the logged-in user's
email matches the value in the header. This prevents session conflicts when the
OAuth server changes the authenticated user.

- Move trusted email verification after user existence check
- Raise 401 if email mismatch is detected
- Only perform verification when WEBUI_AUTH_TRUSTED_EMAIL_HEADER is enabled
2025-06-08 14:16:10 +05:30
Rodrigo Agundez 41e28a9f6f Use standardized procedure to save and load images 2025-06-08 16:26:58 +08:00
Rodrigo Agundez 168997a58e Return tuple consistently and strip potential left string 2025-06-08 16:26:08 +08:00
Silentoplayz a6c7ddcb28 fix: Hidden delete button for playground chat messages 2025-06-08 04:16:41 -04:00
Silentoplayz 67e930e1d2 Fix: Ensure Consistent LDAP Settings Save 2025-06-08 02:17:41 -04:00
Silentoplayz 92c7549b06 fix: remove newline 2025-06-08 01:50:11 -04:00
seiran e97394958e Merge branch 'dev' into main 2025-06-08 05:58:24 +08:00
Diwakar Singh Maurya d600e60776 fix: save Document settings only when Save button is pressed 2025-06-07 15:39:13 +00:00
EntropyYue fd4c42b42e feat: add support for WEBUI_SECRET_KEY_FILE 2025-06-07 23:14:21 +08:00
Diwakar Singh Maurya 871efb4ad9 feat: add langchain markdown document splitter 2025-06-07 06:02:53 +00:00
Tim Jaeryang Baek da5fbc0e39 Merge pull request #14743 from PeterDaveHello/Improve-zh-TW-locale
i18n: improve zh-TW Traditional Chinese locale
2025-06-06 21:26:57 +04:00
Tim Jaeryang Baek 1ad4f7a244 Merge pull request #14736 from SadmL/patch-1
[i18n] Russian locale update
2025-06-06 17:46:14 +04:00
Link [Связной] c0f65ec28a [i18n] Russian locale update 2025-06-06 16:28:36 +03:00
Sine Jespersen 6fd91e58cf add highContrastMode to type Settings 2025-06-06 13:38:35 +02:00
Timothy Jaeryang Baek b433d30c26 chore: format 2025-06-06 15:27:05 +04:00
Tim Jaeryang Baek 1ff7cb7d2f Merge pull request #14720 from itk-dev/feature/accessibible-chat-buttons
Feat: accessibible chat buttons
2025-06-06 12:55:46 +04:00
Sine Jespersen 9c38183689 reindent xmlns 2025-06-06 10:52:13 +02:00
Sine Jespersen fd97882fca add aria labels to buttons that only contains decorative svgs 2025-06-06 10:46:50 +02:00
Sine Jespersen 2b4d4d2770 remove aria-label from tooltip, as tippy handles this out of the box 2025-06-06 10:32:29 +02:00
Sine Jespersen dc60bd2816 add aria-hidden to svg, as these are decorative 2025-06-06 10:32:01 +02:00
Timothy Jaeryang Baek 0b84b22b4e refac: chat item key 2025-06-05 22:38:46 +04:00
Timothy Jaeryang Baek 870c23f69d refac 2025-06-05 22:37:14 +04:00
Timothy Jaeryang Baek 12cfb7b0f0 refac: admin evaluation pages 2025-06-05 21:43:43 +04:00
Tim Jaeryang Baek 37f1d47a06 Merge pull request #14683 from headwAI-GmbH/more-ideomatic-matrix
chore: More ideomatic docker-build matrix
2025-06-05 20:48:31 +04:00
Tim Jaeryang Baek 14a890a0a5 Merge pull request #14687 from SadmL/patch-2
[i18n] Russian locale update
2025-06-05 20:43:37 +04:00
Tim Jaeryang Baek f155abc63c Merge pull request #14700 from silentoplayz/better-settings-search
feat: Enhance Settings Modal Search & Admin Settings Button Placement
2025-06-05 20:43:19 +04:00
Tim Jaeryang Baek f6f3360ef7 Merge pull request #14695 from TiancongLx/dev
i18n: update zh-TW
2025-06-05 20:42:04 +04:00
Tim Jaeryang Baek 99fe23ef66 Merge pull request #14694 from Bouby308/patch-1
fix: return json for successful userSignOut
2025-06-05 20:40:10 +04:00
Tim Jaeryang Baek 92c5773682 Merge pull request #14696 from ShirasawaSama/fix_old_ios_device_voice_recording
fix: fix old iOS device voice recording
2025-06-05 20:38:55 +04:00
Silentoplayz 3c5ae1f62e chore: Also define the standard property 'appearance' for compatibilitycss(vendorPrefix) 2025-06-05 12:02:31 -04:00
Silentoplayz 543ed432b1 Update SettingsModal.svelte 2025-06-05 11:42:05 -04:00
Peter Dave Hello a8b61204b4 i18n: improve zh-TW Traditional Chinese locale 2025-06-05 23:00:32 +08:00
Silentoplayz ec0124b521 Update SettingsModal.svelte 2025-06-05 10:48:33 -04:00
Shirasawa 07b2ecf6aa fix: fix old iOS device voice recording 2025-06-05 20:22:20 +08:00
Tiancong Li e7b86cc852 i18n: update zh-TW 2025-06-05 19:58:29 +08:00
Bouby308 eb3c080cce fix: return json for successful userSignOut
return json when signout request is successful so that frontend can get redirect url with res?.redirect_url on signout
2025-06-05 19:20:27 +08:00
Link [Связной] b3e328ed04 Update translation.json 2025-06-05 12:02:46 +03:00
Link [Связной] 6c8202d87d Update translation.json 2025-06-05 12:01:59 +03:00
Link [Связной] 936c3efe5e [i18n] Russian locale update 2025-06-05 11:55:46 +03:00
guenhter 0fe82d119f chore: make usage of matrix more ideomatic 2025-06-05 06:55:10 +02:00
Timothy Jaeryang Baek 5e35aab292 chore: format 2025-06-05 01:12:28 +04:00
Timothy Jaeryang Baek f17bfb3adb refac 2025-06-05 01:11:31 +04:00
Timothy Jaeryang Baek 00e4391a6f refac 2025-06-05 01:05:33 +04:00
Timothy Jaeryang Baek 93236cead0 refac 2025-06-05 00:46:39 +04:00
Timothy Jaeryang Baek ed1db62b12 refac 2025-06-05 00:44:15 +04:00
Timothy Jaeryang Baek ab36b8aeae refac: embeddings endpoint 2025-06-05 00:37:31 +04:00
Timothy Jaeryang Baek b02a3da4da refac: styling 2025-06-05 00:32:48 +04:00
Tim Jaeryang Baek 7c4f261aa2 Merge pull request #14616 from Davixk/feat/new-perplexity-options
feat: add Perplexity AI model and search context usage configuration options
2025-06-05 00:28:00 +04:00
Tim Jaeryang Baek 14e158fde9 Merge pull request #14667 from hdnh2006/main
feat: OpenAI-compatible `/api/embeddings` endpoint with provider-agnostic OpenWebUI architecture
2025-06-05 00:25:56 +04:00
Tim Jaeryang Baek f50755ccd9 Merge pull request #14659 from vaclcer/vaclavs-picture-description
**fix**: do_picture_description feature when using Docling as an external document parser
2025-06-05 00:24:10 +04:00
henry 04da2b05f6 convert embedding function name to be more consistence 2025-06-04 18:24:27 +02:00
Vaclav Cerny 9772c18b20 fix(loader): remove deprecated picture description configuration 2025-06-04 17:21:44 +02:00
henry cc12e9e1a3 Ollama embeddings adapted to pydantic 2025-06-04 17:06:38 +02:00
henry 3ddebefca2 openai embeddings function modified 2025-06-04 16:13:53 +02:00
henry 8f6c3f46d6 payload and response modifed for compatibility 2025-06-04 16:11:40 +02:00
henry e0769c6a1f new embedding.py added for handling openai and ollama embedding 2025-06-04 16:09:39 +02:00
Henry 415114504f Merge branch 'open-webui:main' into main 2025-06-04 15:37:33 +02:00
Tim Jaeryang Baek 94356dc3ca Merge pull request #14662 from SadmL/patch-2
[i18n] Russian locale update
2025-06-04 17:01:06 +04:00
Link [Связной] 7f04045697 [i18n] Russian locale update 2025-06-04 15:58:15 +03:00
Vaclav Cerny 0b3719cc65 This commit fixes do_picture_description feature when using Docling as an external document parser.
Merge branch 'dev' into vaclavs-picture-description
2025-06-04 14:29:41 +02:00
Vaclav Cerny c71236ba07 feat(loader): enhance picture description prompt for improved detail and clarity 2025-06-04 14:25:31 +02:00
Vaclav Cerny c4278f4784 fix description vs classification mismatch 2025-06-04 14:13:00 +02:00
Timothy Jaeryang Baek bbafeca495 refac: reserved __user__ param format 2025-06-04 15:53:07 +04:00
Tim Jaeryang Baek dcb71c2292 Merge pull request #14644 from Davixk/feat/enforce-lf-eol
refac: enforce consistent line endings across all platforms
2025-06-04 15:44:40 +04:00
Timothy Jaeryang Baek 91e826cc27 refac 2025-06-04 15:43:23 +04:00
Timothy Jaeryang BaekandRodrigo Agundez 9964ad0a5b refac: auth cache dir
Co-Authored-By: Rodrigo Agundez <rragundez@users.noreply.github.com>
2025-06-04 15:21:08 +04:00
Vaclav Cerny 8644e81a1c feat(loader): add picture description configuration for DoclingLoader 2025-06-04 12:34:39 +02:00
Tim Jaeryang Baek 7ef2345ba6 Merge pull request #14642 from ayanahye/fix-chat-title-error-message
fix: error message on chat title edit
2025-06-04 14:09:20 +04:00
Tim Jaeryang Baek 00b16cbaf2 Merge pull request #14645 from qingchunnh/Update_zh-CN-2564
i18n: Update & Improve zh-CN
2025-06-04 14:08:43 +04:00
Tim Jaeryang Baek 2b926a373c Merge pull request #14639 from silentoplayz/add-clone-to-cloned-prompts
fix: append `(Clone)` to title and `-clone` to id when cloning a workspace prompt
2025-06-04 14:08:30 +04:00
Tim Jaeryang Baek 5df4f98fc3 Merge pull request #14640 from silentoplayz/locales-is-undefined-typeerror-fix
fix: Uncaught (in promise) TypeError: locales is undefined
2025-06-04 14:07:38 +04:00
qingchun 717d58116a i18n: Improve zh-CN 2025-06-04 12:46:14 +08:00
qingchun 3e02618278 i18n: Update & Improve zh-CN 2025-06-04 12:33:07 +08:00
Dave 5fb5daf07f refac: standardize formatting in .gitattributes for consistency 2025-06-04 06:32:06 +02:00
Dave 059327cd19 refac: update .gitattributes and .prettierrc for consistent line endings 2025-06-04 06:27:25 +02:00
Ayana H fd53c737f6 update spacing 2025-06-03 19:49:52 -07:00
ayana dc05ccb73f fix: error message on chat title edit 2025-06-03 19:27:28 -07:00
Timothy Jaeryang Baek aeafcc7903 refac: styling 2025-06-04 02:51:42 +04:00
Silentoplayz 86111ad44a fix: Uncaught (in promise) TypeError: locales is undefined in Collapsible.svelte 2025-06-03 18:50:16 -04:00
Timothy Jaeryang Baek ec81e98fa2 refac 2025-06-04 02:46:30 +04:00
Timothy Jaeryang Baek fe69189dc9 refac: styling 2025-06-04 02:36:31 +04:00
Silentoplayz 5b4f81ce11 Update PromptEditor.svelte 2025-06-03 17:25:33 -04:00
Silentoplayz 6ebf522a27 Update PromptEditor.svelte 2025-06-03 17:24:54 -04:00
Silentoplayz 2a6d2392a0 fix: append (Clone) to cloned prompt title and clone to prompt id 2025-06-03 17:19:24 -04:00
Timothy Jaeryang Baek 25157ca6ba chore: format 2025-06-03 22:51:59 +04:00
Timothy Jaeryang Baek c01e29c47f refac: model tools selection not working 2025-06-03 22:04:13 +04:00
Tim Jaeryang Baek bb689b9480 Merge pull request #14630 from Yu-QX/main
fix: Rendering problem with Chinese quotation mark in **bold** & *italic* (after Chinese parentheses issue).
2025-06-03 21:59:12 +04:00
Timothy Jaeryang Baek db836c53f6 refac 2025-06-03 21:57:18 +04:00
Timothy Jaeryang Baek 7ca35068a6 refac: styling 2025-06-03 21:55:40 +04:00
Timothy Jaeryang Baek bbedc50f00 refac 2025-06-03 21:52:58 +04:00
Timothy Jaeryang Baek d2b5a1614a refac 2025-06-03 21:52:25 +04:00
Timothy Jaeryang Baek abae0a837f refac: styling 2025-06-03 21:51:12 +04:00
YuQX 4eef6f432f fix: Rendering problem with Chinese quotation mark in **bold** & *italic* (after Chinese parentheses issue). 2025-06-03 23:30:51 +08:00
Timothy Jaeryang Baek 0a1ff4a8fa refac 2025-06-03 18:49:42 +04:00
Timothy Jaeryang Baek 931e5ffa6e refac 2025-06-03 18:49:03 +04:00
Timothy Jaeryang Baek 185249623b feat: follow ups backend integration 2025-06-03 18:47:49 +04:00
YuQX ca894df2bd Merge pull request #2 from open-webui/main
Upgrade to v0.6.13
2025-06-03 22:36:28 +08:00
Timothy Jaeryang Baek 9e49fbc8bf feat: follow ups 2025-06-03 18:07:29 +04:00
Timothy Jaeryang Baek f8b941fb96 refac 2025-06-03 17:24:31 +04:00
Timothy Jaeryang Baek 2fee89dfa6 doc: readme 2025-06-03 16:49:24 +04:00
Timothy Jaeryang Baek 4d364e2967 refac: remove msg from known type 2025-06-03 16:27:28 +04:00
Tim Jaeryang Baek 8bdefa5481 Merge pull request #14592 from ER-EPR/main
Feat: Add a new docker tag cu126 to maintain support for NVIDIA cuda capability 7.0 and below (e.g. V100, GTX1080)
2025-06-03 12:48:15 +04:00
Tim Jaeryang Baek 34a8b95cc3 Merge pull request #14622 from Zyfax/patch-2
fix: remove trailing slash form test connection api url
2025-06-03 12:43:31 +04:00
Zyfax e353f15a3c fix: remove ending slash form test connection url
Removes the ending slash when testing openai and ollama api url.
2025-06-03 09:11:01 +02:00
Dave 77b357c73b fix: update label for search context usage to clarify its purpose 2025-06-03 00:27:07 +02:00
Dave 96e9bfe0e5 feat: add Perplexity model and search context usage configuration options 2025-06-03 00:19:08 +02:00
Tim Jaeryang Baek 3c32d2cada Merge pull request #14539 from PVBLIC-F/refac/mistral
perf mistral.py Enhance for Overall Speed and Efficiency
2025-06-02 23:52:59 +04:00
Timothy Jaeryang Baek 3da1802eec fix: message delete issue 2025-06-02 23:25:38 +04:00
Tim Jaeryang Baek 0ebe35c571 Merge pull request #14532 from PVBLIC-F/refac/pinecone
perf pinecone.py Improve Performance and Maintainability Using Current Best Practices
2025-06-02 23:12:48 +04:00
Tim Jaeryang Baek 29d6eb642f Merge pull request #14555 from diwakar-s-maurya/patch-8
feat: Add route for each tab in Settings
2025-06-02 22:36:36 +04:00
Tim Jaeryang Baek 7536a94585 Merge pull request #14552 from expruc/he-tr
i18n: updated hebrew locale
2025-06-02 21:42:45 +04:00
Tim Jaeryang Baek 89dcce0df2 Merge pull request #14553 from PeterDaveHello/Improve-zh-TW-locale
i18n: update and improve zh-TW Traditional Chinese locale
2025-06-02 21:40:01 +04:00
Tim Jaeryang Baek 6e2bffee69 Merge pull request #14566 from open-webui/dependabot/pip/backend/dev/uvicorn-standard--0.34.2
build(deps): bump uvicorn[standard] from 0.34.0 to 0.34.2 in /backend
2025-06-02 21:38:39 +04:00
Tim Jaeryang Baek 84c06aa582 Merge pull request #14565 from open-webui/dependabot/pip/backend/dev/pillow-11.2.1
build(deps): bump pillow from 11.1.0 to 11.2.1 in /backend
2025-06-02 21:37:45 +04:00
Tim Jaeryang Baek 281b74f4b4 Merge pull request #14563 from open-webui/dependabot/pip/backend/dev/azure-ai-documentintelligence-1.0.2
build(deps): bump azure-ai-documentintelligence from 1.0.0 to 1.0.2 in /backend
2025-06-02 21:37:37 +04:00
Tim Jaeryang Baek 816e35bd79 Merge pull request #14562 from open-webui/dependabot/pip/backend/dev/validators-0.35.0
build(deps): bump validators from 0.34.0 to 0.35.0 in /backend
2025-06-02 21:37:28 +04:00
Tim Jaeryang Baek 0469120709 Merge pull request #14573 from open-webui/dependabot/npm_and_yarn/dev/katex-0.16.22
build(deps): bump katex from 0.16.21 to 0.16.22
2025-06-02 21:37:19 +04:00
ER-EPR bf3897ec40 Merge pull request #1 from ER-EPR/ER-EPR-cuda126-1
Add cuda126 image in docker-build.yaml
2025-06-02 17:45:39 +08:00
ER-EPR d649db4ef7 Add cuda126 image in docker-build.yaml
add USE_CUDA_VER=cu126 version to support cuda capability 7.0 and below
2025-06-02 17:44:17 +08:00
dependabot[bot] 28db03e4f9 build(deps): bump katex from 0.16.21 to 0.16.22
Bumps [katex](https://github.com/KaTeX/KaTeX) from 0.16.21 to 0.16.22.
- [Release notes](https://github.com/KaTeX/KaTeX/releases)
- [Changelog](https://github.com/KaTeX/KaTeX/blob/main/CHANGELOG.md)
- [Commits](https://github.com/KaTeX/KaTeX/compare/v0.16.21...v0.16.22)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-01 02:49:05 +00:00
dependabot[bot] 26549244fc build(deps): bump uvicorn[standard] from 0.34.0 to 0.34.2 in /backend
Bumps [uvicorn[standard]](https://github.com/encode/uvicorn) from 0.34.0 to 0.34.2.
- [Release notes](https://github.com/encode/uvicorn/releases)
- [Changelog](https://github.com/encode/uvicorn/blob/master/docs/release-notes.md)
- [Commits](https://github.com/encode/uvicorn/compare/0.34.0...0.34.2)

---
updated-dependencies:
- dependency-name: uvicorn[standard]
  dependency-version: 0.34.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-01 02:28:37 +00:00
dependabot[bot] 3ccd2364ba build(deps): bump pillow from 11.1.0 to 11.2.1 in /backend
Bumps [pillow](https://github.com/python-pillow/Pillow) from 11.1.0 to 11.2.1.
- [Release notes](https://github.com/python-pillow/Pillow/releases)
- [Changelog](https://github.com/python-pillow/Pillow/blob/main/CHANGES.rst)
- [Commits](https://github.com/python-pillow/Pillow/compare/11.1.0...11.2.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-01 02:28:34 +00:00
dependabot[bot] 1131a61b8e build(deps): bump azure-ai-documentintelligence in /backend
Bumps [azure-ai-documentintelligence](https://github.com/Azure/azure-sdk-for-python) from 1.0.0 to 1.0.2.
- [Release notes](https://github.com/Azure/azure-sdk-for-python/releases)
- [Changelog](https://github.com/Azure/azure-sdk-for-python/blob/main/doc/esrp_release.md)
- [Commits](https://github.com/Azure/azure-sdk-for-python/compare/azure-ai-documentintelligence_1.0.0...azure-ai-documentintelligence_1.0.2)

---
updated-dependencies:
- dependency-name: azure-ai-documentintelligence
  dependency-version: 1.0.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-01 02:28:27 +00:00
dependabot[bot] 2f3d4622db build(deps): bump validators from 0.34.0 to 0.35.0 in /backend
Bumps [validators](https://github.com/python-validators/validators) from 0.34.0 to 0.35.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.34.0...0.35.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-01 02:28:18 +00:00
Peter Dave Hello 96d8a52fe3 i18n: update and improve zh-TW Traditional Chinese locale 2025-06-01 04:08:33 +08:00
Diwakar Singh Maurya 1ddc784af9 feat: Add route for each tab in Settings 2025-05-31 19:18:05 +00:00
expruc 185224e4e1 Locale: updated he translation 2025-05-31 21:37:42 +03:00
Timothy Jaeryang Baek 2c15f8e676 refac 2025-05-31 15:07:28 +04:00
Timothy Jaeryang Baek 4e82c44f3e refac 2025-05-31 15:04:38 +04:00
Timothy Jaeryang Baek e41e375aab refac: role update ui 2025-05-31 15:00:27 +04:00
Tim Jaeryang Baek 343dac91c9 Merge pull request #14522 from SadmL/patch-2
[i18n] Russian locale update
2025-05-31 14:42:52 +04:00
PVBLIC Foundation cf3635ba25 Update mistral.py
1. Intelligent Error Handling
Added _is_retryable_error() method to distinguish retryable vs non-retryable errors
Prevents unnecessary retries on client errors (4xx) that won't succeed
Caps retry delay at 30 seconds to prevent excessive waiting
2. Optimized Timeout Configuration
Upload: Capped at 2 minutes (was using full 5-minute timeout)
URL requests: 30 seconds (should be fast)
OCR processing: Full timeout (can take time)
Cleanup: 30 seconds (should be quick)
3. Enhanced Connection Pool
Increased connection limits: 20 total, 10 per host
Longer DNS cache TTL (10 minutes vs 5 minutes)
Increased keepalive timeout (60s vs 30s)
Added async DNS resolver for better performance
Granular timeout controls (connect, read, total)
4. Concurrency Control for Batch Processing
Added semaphore-based concurrency control (default: 5 concurrent)
Prevents API overwhelming while maintaining throughput
Configurable concurrency limit per workload
5. Memory Efficient Result Processing
Early exit for empty content validation
Better error metadata for debugging
Added content length tracking
Streamlined page processing logic
6. General Performance Improvements
Better error logging with truncated responses
Optimized metadata creation
Improved debug logging efficiency
2025-05-30 20:06:29 -07:00
PVBLIC Foundation 66bde32623 Update pinecone.py 2025-05-30 18:47:23 -07:00
sanae artoria cbc514e681 The translation might be confusing, in some cases for example tooltips over a radio button 2025-05-31 01:13:55 +08:00
PVBLIC Foundation 4ecf2a8685 Update pinecone.py
May 2025 Latest Pinecone Best Practices
2025-05-30 09:33:57 -07:00
Link [Связной] 5555d889d5 Update translation.json 2025-05-30 11:55:22 +03:00
Link [Связной] 7dde16d0ac [i18n] Russian locale update 2025-05-30 11:52:33 +03:00
Tim Jaeryang Baek 53764fe648 Merge pull request #14486 from open-webui/dev
0.6.13
2025-05-30 01:37:21 +04:00
Timothy Jaeryang Baek 235489cfc5 refac 2025-05-30 01:33:49 +04:00
Timothy Jaeryang Baek b2befd486f refac 2025-05-30 01:24:54 +04:00
Timothy Jaeryang Baek 9306ae5972 refac 2025-05-30 01:19:56 +04:00
Timothy Jaeryang Baek 036ce12dd9 doc: changelog 2025-05-30 01:14:38 +04:00
Tim Jaeryang Baek d6c3f93cfd Merge pull request #14509 from r0mdau/fix/audio-format
fix: only trust codec_name for audio conversion
2025-05-30 01:12:22 +04:00
Romain Dauby b12a493fe5 fix: only trust codec_name for audio conversion
Some files have .wav extension with incompatible OpenAI codec
2025-05-29 16:57:23 -04:00
Timothy Jaeryang Baek f4827f0c18 chore: format 2025-05-30 00:35:59 +04:00
Timothy Jaeryang Baek e1e2c096e2 refac: PLEASE follow existing convention 2025-05-30 00:34:18 +04:00
Tim Jaeryang Baek ff353578db Merge pull request #14370 from daw/feat/add-azure-openai-embeddings-option
feat:Add Azure OpenAI embedding support
2025-05-30 00:18:55 +04:00
Timothy Jaeryang Baek be989f3645 refac: better memory error handling 2025-05-30 00:12:28 +04:00
Timothy Jaeryang Baek 4c45d67677 refac/fix: memory 2025-05-30 00:10:52 +04:00
Timothy Jaeryang Baek 59768e34f4 refac 2025-05-30 00:04:13 +04:00
Timothy Jaeryang Baek 4371d2c5a5 enh: better custom param handling 2025-05-29 23:32:14 +04:00
Timothy Jaeryang Baek 9be22cb637 fix: prompt access control 2025-05-29 23:21:56 +04:00
Tim Jaeryang Baek f95f51530b Merge pull request #14488 from TiancongLx/dev
i18n: update zh-TW
2025-05-29 13:35:10 +04:00
Tiancong Li c3e8e1cbf1 i18n: update zh-TW 2025-05-29 17:18:27 +08:00
Tim Jaeryang Baek 2327c32a74 Merge pull request #14485 from jackthgu/update-korean-translation
i18n: Korean locale update
2025-05-29 13:16:00 +04:00
Taehong Gu a214e63cab Update Korean translation - Documentation 2025-05-29 18:12:54 +09:00
Tim Jaeryang Baek f1507f2458 Merge pull request #14472 from Davixk/fix/chat-loading-error
fix: Chat page fails to load on undefined message
2025-05-29 13:07:08 +04:00
Timothy Jaeryang Baek 255367934b doc: typo 2025-05-29 13:02:12 +04:00
Tim Jaeryang Baek bd4e010c76 Merge pull request #14477 from qingchunnh/Update_zh-CN-25529
i18n: Update & Improve zh-CN
2025-05-29 13:00:14 +04:00
Tim Jaeryang Baek 155518e788 Merge pull request #14478 from Kylapaallikko/dev
i18n: Update fi-FI translation
2025-05-29 12:59:52 +04:00
Timothy Jaeryang Baek d43bbcae28 refac/fix: open webui params handling 2025-05-29 12:57:58 +04:00
Kylapaallikko 309380b098 Update fi-FI translation.json 2025-05-29 09:18:42 +03:00
qingchun 2c723e1f28 i18n: Update & Improve zh-CN 2025-05-29 13:40:39 +08:00
Dave 01eedd36bc Handles undefined message case in message list creation
Prevents potential errors by returning an empty list if the
specified message ID does not exist in the history. This
enhancement ensures robustness in scenarios where a message
ID may be missing, avoiding further processing and potential
exceptions.
2025-05-29 06:19:13 +02:00
Tim Jaeryang Baek ba0088f39b Merge pull request #14441 from open-webui/dev
0.6.12
2025-05-29 03:59:24 +04:00
Timothy Jaeryang Baek 661625f362 doc: changelog 2025-05-29 03:56:42 +04:00
Timothy Jaeryang Baek 30b7ab3591 refac 2025-05-29 03:48:07 +04:00
Timothy Jaeryang Baek 7dc7d5c028 refac: PLEASE FOLLOW EXISTING CONVENTION 2025-05-29 03:47:02 +04:00
Timothy Jaeryang Baek 2c31f5c725 doc: readme 2025-05-29 03:41:38 +04:00
Timothy Jaeryang Baek a6864db8ec chore: format 2025-05-29 03:37:58 +04:00
Timothy Jaeryang Baek 21f85e63bf refac: styling 2025-05-29 03:37:13 +04:00
Timothy Jaeryang Baek 9220afe7b3 feat: custom advanced params 2025-05-29 03:33:11 +04:00
Timothy Jaeryang Baek bb4115fa0e refac: allow all params 2025-05-29 02:56:37 +04:00
Timothy Jaeryang Baek 551597b9cc chore: format 2025-05-29 02:36:33 +04:00
Timothy Jaeryang Baek cb4299eb98 refac 2025-05-29 02:33:40 +04:00
Tim Jaeryang Baek 042c37ea34 Merge pull request #14311 from Hisma/marker-api-content-extraction
feat: Marker api content extraction support
2025-05-29 02:21:13 +04:00
Timothy Jaeryang Baek 85a384fab5 enh: load tool by url 2025-05-29 02:08:54 +04:00
Timothy Jaeryang Baek 4461122a0e fix: /api/v1/retrieval/query/collection endpoint 2025-05-28 18:45:47 +04:00
YuQX 24be96a6d4 Merge pull request #1 from open-webui/main
Upgrade to v0.6.11
2025-05-28 22:24:33 +08:00
Tim Jaeryang Baek c9f983f644 Merge pull request #14445 from NotYuSheng/chore/duplicate-css-elements
chore: removed duplicate css elements
2025-05-28 17:58:59 +04:00
Timothy Jaeryang Baek cc6cbf53e8 refac 2025-05-28 17:36:05 +04:00
Timothy Jaeryang Baek 4279762ea4 refac 2025-05-28 16:36:23 +04:00
notyusheng efedb7ab1f chore: removed duplicate css elements 2025-05-28 08:31:11 -04:00
Timothy Jaeryang Baek 32135a29bb fix: image preview/download 2025-05-28 15:57:40 +04:00
Timothy Jaeryang Baek 8a74bdce37 fix: message input issue 2025-05-28 15:36:04 +04:00
Timothy Jaeryang Baek 3d9a430927 refac: styling 2025-05-28 14:28:39 +04:00
Timothy Jaeryang Baek a27a095884 refac 2025-05-28 14:27:34 +04:00
Tim Jaeryang Baek 596298fa46 Merge pull request #14405 from SadmL/patch-2
[i18n] Russian locale update
2025-05-28 14:23:33 +04:00
Timothy Jaeryang Baek bf7a18a0f8 refac 2025-05-28 02:10:54 +04:00
Timothy Jaeryang Baek d81886e315 refac 2025-05-28 01:42:42 +04:00
Timothy Jaeryang Baek 7effb04782 refac 2025-05-28 01:41:49 +04:00
Timothy Jaeryang Baek f5fefb49d5 refac 2025-05-28 01:38:24 +04:00
Timothy Jaeryang Baek e4a53e0a3c refac 2025-05-28 01:34:53 +04:00
Link [Связной] e861ba5520 [i18n] Russian locale update 2025-05-27 16:28:09 +03:00
Tim Jaeryang Baek 100a764293 Merge pull request #14402 from torisetxd/parallelized-model-fetching
perf: Parallelize base model fetching
2025-05-27 16:56:44 +04:00
Timothy Jaeryang Baek 1d216b82ba refac 2025-05-27 16:48:17 +04:00
toriset 9eccce2444 Added proper type hints to new functions
Forgot about that...
2025-05-27 15:44:20 +03:00
toriset 27de981246 Parallelize base model fetching 2025-05-27 15:35:16 +03:00
Timothy Jaeryang Baek 40bea00e3d refac 2025-05-27 16:06:00 +04:00
Timothy Jaeryang Baek 8609471eeb Revert "Merge pull request #14379 from aleixdorca/dev"
This reverts commit cb135c370a, reversing
changes made to 8cf578d9fd.
2025-05-27 16:00:19 +04:00
Tim Jaeryang Baek cb135c370a Merge pull request #14379 from aleixdorca/dev
i18n: Update Catalan translation.json
2025-05-27 15:59:37 +04:00
Tim Jaeryang Baek 8cf578d9fd Merge pull request #14368 from qingchunnh/Update_zh-CN-25527
i18n: Update & Improve zh-CN
2025-05-27 15:59:29 +04:00
Tim Jaeryang Baek 1aac41d6c3 Merge pull request #14400 from torisetxd/capabilities-fix
fix: Improve mobile styling for capabilities in workspace models
2025-05-27 15:59:16 +04:00
toriset 20403c9df7 Match capabilities styling to other settings in workspace models 2025-05-27 14:39:21 +03:00
Timothy Jaeryang Baek b944acd3ff refac: function cache 2025-05-27 14:39:35 +04:00
Tim Jaeryang Baek 1ec9e42c1e Merge pull request #14383 from TiancongLx/dev
i18n: complete and improve zh-TW
2025-05-27 13:56:51 +04:00
Tim Jaeryang Baek 5989e9bf75 Merge pull request #14387 from Zyfax/patch-1
fix: tts read aloud
2025-05-27 13:56:40 +04:00
Tim Jaeryang Baek 75b2e4a659 Merge pull request #14392 from hurxxxx/fix/improve-loading-functions
perf: Prevent duplicate function loads with caching helper and refactor
2025-05-27 13:56:13 +04:00
Gunwoo Hur 14c3d0c2d1 Prevent duplicate function module loads with caching helper and refactor 2025-05-27 18:08:58 +09:00
Tim Jaeryang Baek 737dc7797c Merge pull request #14390 from open-webui/dev
Dev
2025-05-27 12:59:28 +04:00
Timothy Jaeryang Baek eb14bfbcdf refac: bug report template 2025-05-27 12:59:01 +04:00
Zyfax 4995bfe571 fix: tts read aloud
Change: const content = removeAllDetails(content); to const content = removeAllDetails(message.content);

Error: Uncaught (in promise) ReferenceError: can't access lexical declaration 'z' before initialization.
ResponseMessage.svelte:215:42
2025-05-27 10:52:26 +02:00
Tiancong Li 098ec43413 i18n: update zh-TW 2025-05-27 16:16:09 +08:00
Aleix Dorca fcb03df9ce Update catalan translation.json 2025-05-27 09:02:42 +02:00
Hisma 19bb3589ee fix: add Datalab Marker API to Content Extraction Engine Dropdown 2025-05-27 02:24:53 -04:00
Hisma e12a79c0e2 fix: handle json output format correctly 2025-05-27 01:12:03 -04:00
Hisma a9405cc101 feat: Marker api content extraction support 2025-05-27 00:44:07 -04:00
qingchun 7988e0c6e2 i18n: Improve zh-CN 2025-05-27 11:25:12 +08:00
qingchun 14bf579e9c i18n: Fix zh-CN 2025-05-27 10:25:02 +08:00
qingchun fc2202ad76 i18n: Update zh-CN 2025-05-27 09:19:35 +08:00
Timothy Jaeryang Baek a2afd6f645 refac 2025-05-27 03:06:01 +04:00
Tim Jaeryang Baek b8e16211b9 Merge pull request #14364 from open-webui/dev
fix: image generation
2025-05-27 02:48:45 +04:00
Timothy Jaeryang Baek efb54aa2e4 fix: image generation 2025-05-27 02:48:22 +04:00
Tim Jaeryang Baek 9faa4c6a4c Merge pull request #14194 from open-webui/dev
0.6.11
2025-05-27 02:27:09 +04:00
Timothy Jaeryang Baek 5c74e56bd0 chore: format 2025-05-27 02:18:43 +04:00
Timothy Jaeryang Baek 8609fe7ab4 i18n: french 2025-05-27 02:18:02 +04:00
Tim Jaeryang Baek 1cb8fa0f03 Merge pull request #14362 from PVBLIC-F/fix/chat-engagement-critical
Fix/chat engagement critical
2025-05-27 02:17:34 +04:00
Timothy Jaeryang Baek a681d5c60e doc: changelog 2025-05-27 02:16:43 +04:00
cheadings71 256034e285 Update misc.py
Before fix: Chat engagement failed with TypeError and KeyError
After fix: Chat works smoothly with automatic title generation and proper history
2025-05-26 14:55:48 -07:00
cheadings71 d414662d23 fix: resolve chat engagement TypeError - Fix get_message_list() to return [] instead of None - Fix middleware to use correct metadata message_id - Add safe fallback for missing role field - Ensure assistant messages include role field 2025-05-26 14:35:09 -07:00
Timothy Jaeryang Baek 940a437631 refac 2025-05-27 01:16:11 +04:00
Timothy Jaeryang Baek aaff204e7b refac 2025-05-27 00:56:59 +04:00
Timothy Jaeryang Baek e68a3d28b5 refac 2025-05-27 00:40:55 +04:00
Timothy Jaeryang Baek 090619c27c refac 2025-05-27 00:29:16 +04:00
Timothy Jaeryang Baek 9c120affb6 chore: format 2025-05-27 00:21:23 +04:00
Timothy Jaeryang Baek 2c7ccc69fe enh: allow custom openapi json url 2025-05-27 00:20:47 +04:00
Timothy Jaeryang Baek a38e44e870 enh: external tool server custom name/description support 2025-05-27 00:10:33 +04:00
Timothy Jaeryang Baek 20f54616e7 chore: format 2025-05-26 23:55:39 +04:00
Timothy Jaeryang Baek b4caad928e feat: load function from url 2025-05-26 23:52:22 +04:00
Timothy Jaeryang Baek 7d756982c2 refac 2025-05-26 23:22:37 +04:00
Tim Jaeryang Baek 6062174602 Merge pull request #14228 from suleimanelkhoury/s3-tags-allowed-characters
fix: S3 allowed characters in Tags.
2025-05-26 22:43:21 +04:00
Timothy Jaeryang Baek 9a5febc2d1 feat: copy model link 2025-05-26 22:29:03 +04:00
Timothy Jaeryang Baek 2d5b82df8c enh: include sources field in non-streaming response 2025-05-26 22:22:37 +04:00
Timothy Jaeryang Baek ffa51ece0c refac: pinned chat endpoint 2025-05-26 22:15:21 +04:00
Timothy Jaeryang BaekandClassic298 a0d034fa7c feat: Bypass file creation with CTRL + SHIFT + V
Co-Authored-By: Classic298 <27028174+Classic298@users.noreply.github.com>
2025-05-26 22:10:35 +04:00
Timothy Jaeryang Baek fc5dfd3536 refac 2025-05-26 22:02:40 +04:00
Tim Jaeryang Baek 5d7c89964c Merge pull request #14314 from fl0w1nd/dev
fix: Correctly handle toggle filters to prevent unintended activation
2025-05-26 21:58:57 +04:00
Timothy Jaeryang Baek caa5ad44d4 refac 2025-05-26 19:53:29 +04:00
Tim Jaeryang Baek 040f29d058 Merge pull request #14316 from Yu-QX/main
fix: Handle special cases of LLM output not following markdown syntax
2025-05-26 19:30:48 +04:00
Yu QX bb62bd9c1f Extracting the traversal. 2025-05-26 21:04:08 +08:00
Yu QX b9f74a66b2 Seperate into processChineseContent 2025-05-26 20:43:21 +08:00
Yu QX 254dd4246e Integrate file into index.ts. 2025-05-26 19:35:28 +08:00
Timothy Jaeryang BaekandJason Baker 4da75a9e78 feat: GZip, Brotli, ZStd compression middleware support
Co-Authored-By: Jason Baker <jason.th.baker@gmail.com>
2025-05-26 14:18:29 +04:00
Yu QX 4483fa95b8 Perfect the logic of case 1.1.x 2025-05-26 17:25:33 +08:00
Tim Jaeryang Baek c157e74f0c Merge pull request #14335 from open-webui/main
dev
2025-05-26 13:02:08 +04:00
Tim Jaeryang Baek ada9655f33 Merge pull request #14317 from SadmL/patch-3
[i18n] Russian locale update
2025-05-26 13:01:39 +04:00
Tim Jaeryang Baek 9de92687f6 Merge pull request #14328 from ShirasawaSama/fix_path_leakage_caused_by_file_upload
fix: Fix path leakage caused by file upload
2025-05-26 12:57:21 +04:00
Tim Jaeryang Baek 31dbafd62e Merge pull request #14301 from qingchunnh/Update_zh-CN-25525
i18n: Update & Improve zh-CN
2025-05-26 12:56:14 +04:00
Shirasawa 0dc29a220f fix: Fix path leakage caused by file upload 2025-05-26 12:20:00 +08:00
Link [Связной] 7db9f7b8b6 Update translation.json 2025-05-25 14:53:03 +03:00
Link [Связной] dc50fa3744 [i18n] Russian locale update 2025-05-25 14:42:42 +03:00
YuQX 8ef7938c96 fix: Handle special cases of LLM output not following markdown syntax (20250525, formated) This commit introduces a utility function to address rendering issues in LLM output, particularly for Chinese characters and parentheses. The function ensures minimal modification of the original text while fixing markdown parsing problems. Changes include: - Added in for handling specific cases. - Updated in to incorporate the new utility. The fix ensures proper rendering of bold/italic text containing Chinese parentheses, improving readability for non-English content. 2025-05-25 19:37:43 +08:00
fl0w1nd 332043c38b fix: Correctly handle toggle filters to prevent unintended activation 2025-05-25 17:59:31 +08:00
YuQX 49fe137553 fix: Handle special cases of LLM output not following markdown syntax 20250525
This commit introduces a utility function  to address rendering issues in LLM output, particularly for Chinese characters and parentheses. The function ensures minimal modification of the original text while fixing markdown parsing problems.

Changes include:
- Added  in  for handling specific cases.
- Updated  in  to incorporate the new utility.

The fix ensures proper rendering of bold/italic text containing Chinese parentheses, improving readability for non-English content.
2025-05-25 13:58:32 +08:00
qingchun 6a93b54e8e i18n: Update & Improve zh-CN 2025-05-25 08:02:47 +08:00
Timothy Jaeryang Baek 8598fc9608 chore: format 2025-05-25 02:33:52 +04:00
Timothy Jaeryang Baek 5885d8e275 enh: ability to hide workspace models 2025-05-25 02:32:32 +04:00
Timothy Jaeryang Baek f9d374810d refac 2025-05-25 02:21:03 +04:00
Timothy Jaeryang Baek 358ad8ef20 enh: import/export default prompt suggestions 2025-05-25 02:17:51 +04:00
Timothy Jaeryang Baek 33f2fdb91e refac: styling 2025-05-25 02:07:13 +04:00
Timothy Jaeryang Baek e65ac97c45 refac 2025-05-25 01:59:48 +04:00
Timothy Jaeryang Baek b2b1a21299 refac 2025-05-25 01:48:37 +04:00
Timothy Jaeryang Baek 75208935d7 refac: user chat list modal 2025-05-25 01:44:53 +04:00
Timothy Jaeryang Baek 44e7e09784 refac 2025-05-25 01:28:35 +04:00
Timothy Jaeryang Baekandsilentoplayz 1d53754ea7 refac: chat list modal
Co-Authored-By: silentoplayz <50341825+silentoplayz@users.noreply.github.com>
2025-05-25 01:26:12 +04:00
Timothy Jaeryang Baek 6e8ca96799 enh: archived chats modal 2025-05-25 01:23:12 +04:00
Timothy Jaeryang Baek 5db7d8acd1 refac 2025-05-25 00:58:55 +04:00
Timothy Jaeryang Baek 0fe00ab2c3 refac 2025-05-25 00:52:53 +04:00
Timothy Jaeryang Baek 9b000d82ec refac 2025-05-25 00:51:44 +04:00
Timothy Jaeryang Baek 7e6f1f8848 enh: archived chats modal 2025-05-25 00:48:30 +04:00
Timothy Jaeryang Baek 31e2686ae6 feat: /sync functions endpoint 2025-05-24 23:39:19 +04:00
Timothy Jaeryang Baek cce5f024bd feat: WEBUI_AUTH_TRUSTED_GROUPS_HEADER 2025-05-24 23:17:12 +04:00
Tim Jaeryang Baek 17263a294f Merge pull request #14284 from diwakar-s-maurya/patch-7
feat: add support for table formatting in knowledge collection
2025-05-24 23:02:46 +04:00
Tim Jaeryang Baek 6dbab870e5 Merge pull request #14263 from qingchunnh/Update_zh-CN-25524
i18n: Update & Improve zh-CN
2025-05-24 22:59:47 +04:00
Timothy Jaeryang Baek 9598532270 enh/chore: bug report template 2025-05-24 22:56:54 +04:00
Diwakar Singh Maurya e31a7bcc4c feat: add support for table formatting in knowledge collection 2025-05-24 16:21:55 +00:00
Timothy Jaeryang Baek 261328077d refac 2025-05-24 17:20:40 +04:00
Timothy Jaeryang Baek aebbc2593b refac: scrollbar thumb styling 2025-05-24 17:19:47 +04:00
Tim Jaeryang Baek 8261f0e17e Merge pull request #14276 from Classic298/memories
feat: Make Edit/Add Memory Modal larger, and the text input box size-adjustable
2025-05-24 16:01:07 +04:00
Tim Jaeryang Baek 37d2aed26e Merge pull request #14268 from TiancongLx/dev
i18n: update zh-TW
2025-05-24 15:42:50 +04:00
Classic298 c377ff80c9 Update EditMemoryModal.svelte 2025-05-24 13:33:56 +02:00
Classic298 9bd031dae3 Update AddMemoryModal.svelte 2025-05-24 13:33:49 +02:00
Tiancong Li bc7853d6a4 i18n: update zh-TW 2025-05-24 13:38:32 +08:00
qingchun adefc811c7 i18n: Update & Improve zh-CN 2025-05-24 09:18:18 +08:00
qingchun 3c828f7828 i18n: Update & Improve zh-CN 2025-05-24 08:30:09 +08:00
Timothy Jaeryang Baek da75d0ca1e chore: format 2025-05-24 02:13:54 +04:00
Timothy Jaeryang Baek 51ab02f3af chore: format 2025-05-24 02:13:46 +04:00
Timothy Jaeryang Baek 29d08c2a16 refac: styling 2025-05-24 02:12:44 +04:00
Timothy Jaeryang Baek abcf59ab2b refac: styling 2025-05-24 01:56:02 +04:00
Timothy Jaeryang Baek ffa5db4fec refac: styling 2025-05-24 01:45:55 +04:00
Timothy Jaeryang Baek f95e52a6a6 refac: wording 2025-05-24 01:40:01 +04:00
Timothy Jaeryang Baek 17aca908c5 refac: styling 2025-05-24 01:36:53 +04:00
Tim Jaeryang Baek e663b90a9f Merge pull request #14069 from Ithanil/bm25_weight
feat: Configurable weight for BM25Retriever during hybrid search
2025-05-24 01:13:03 +04:00
Timothy Jaeryang Baek bf97dbe052 refac 2025-05-24 01:12:11 +04:00
Timothy Jaeryang Baek 80eaa24ca8 enh: provide source name in context if available 2025-05-24 00:52:09 +04:00
Timothy Jaeryang Baek 8b5e89eada chore: format 2025-05-24 00:43:38 +04:00
Timothy Jaeryang Baek a46765fd0e refac 2025-05-24 00:43:02 +04:00
Timothy Jaeryang Baek baaa285534 feat: user stt language 2025-05-24 00:36:30 +04:00
Jan Kessler a90d3f3268 add missing locale string 2025-05-23 22:30:04 +02:00
Jan Kessler e70dd33233 rename BM25_WEIGHT -> HYBRID_BM25_WEIGHT 2025-05-23 22:06:44 +02:00
Tim Jaeryang Baek 9946dc7b5f Merge pull request #14252 from Kylapaallikko/dev
i18n: Update fi-FI translation
2025-05-23 23:53:40 +04:00
Timothy Jaeryang Baek 88a296b989 refac: chat reset input behaviour 2025-05-23 23:52:10 +04:00
Kylapaallikko bf12946ac9 Update fi-FI translation.json 2025-05-23 22:12:00 +03:00
Tim Jaeryang Baek 99f88082ca Merge pull request #14248 from diwakar-s-maurya/patch-3
feat: Show tool call parameters along tool ouput
2025-05-23 22:55:08 +04:00
Timothy Jaeryang Baek 6636207e0c refac 2025-05-23 22:10:57 +04:00
Tim Jaeryang Baek c8f1bdf928 Merge pull request #14245 from PVBLIC-F/dev
perf Update mistral.py
2025-05-23 21:57:16 +04:00
Timothy Jaeryang Baek 3f2025dc6e enh: always process file with external document loader 2025-05-23 21:55:09 +04:00
Diwakar Singh Maurya 549237fb05 Show tool call parameters along tool ouput 2025-05-23 17:42:05 +00:00
Timothy Jaeryang Baek 797c7d4e56 refac: allow min_p for openai requests 2025-05-23 21:28:02 +04:00
PVBLIC Foundation bf193dfb5d Update mistral.py 2025-05-23 10:00:19 -07:00
Timothy Jaeryang Baek 30d15c1b4b chore: format 2025-05-23 20:44:41 +04:00
Timothy Jaeryang Baek b9afef85c4 refac: advanced params 2025-05-23 20:44:19 +04:00
Timothy Jaeryang Baek ed0bebc7ef enh: granular audio playback speed 2025-05-23 20:10:16 +04:00
Timothy Jaeryang Baek f75ac5cc01 refac: styling 2025-05-23 20:06:05 +04:00
Timothy Jaeryang Baek 1cf21d3fa2 feat: ollama unload model 2025-05-23 19:45:29 +04:00
Timothy Jaeryang Baek 19b69fcb66 chore: format 2025-05-23 19:22:08 +04:00
Timothy Jaeryang Baek e15ff8d9f6 refac 2025-05-23 19:15:57 +04:00
Timothy Jaeryang Baek 0e6f09a0a9 enh: ollama loaded model display 2025-05-23 19:13:18 +04:00
Timothy Jaeryang Baek a50a8e2ef9 refac: ollama ps 2025-05-23 18:47:50 +04:00
Timothy Jaeryang Baek 65d997a6c5 refac 2025-05-23 18:22:57 +04:00
Timothy Jaeryang Baek 62fbd6c91c refac 2025-05-23 18:17:35 +04:00
Timothy Jaeryang Baek 03288d9fca refac: redesign 2025-05-23 17:30:17 +04:00
Tim Jaeryang Baek 06aa59e2a5 Merge pull request #14219 from Yu-QX/main
Fix: Solve equation problems with Chinese symbols
2025-05-23 17:19:29 +04:00
Timothy Jaeryang Baek 02000b1a6c refac: include help items in user menu 2025-05-23 16:49:11 +04:00
Timothy Jaeryang Baek dd8e742c2d refac: tts details tags 2025-05-23 13:40:33 +04:00
Tim Jaeryang Baek 55a6fae9db Merge pull request #14210 from ShrootBuck/main
refac: improve prompt formatting for selected text in FloatingButtons
2025-05-23 13:14:27 +04:00
Tim Jaeryang Baek bdcd04a78c Merge pull request #14212 from qingchunnh/Update_zh-CN-25523
i18n: Update & Improve zh-CN
2025-05-23 13:13:19 +04:00
Suleiman Elkhoury e10d6ad79c Fix S3 allowed characters in Tags.
In Amazon S3 storage, only the following charaters allowed in Tagging "letters (a-z, A-Z), numbers (0-9), and spaces representable in UTF-8, and the following characters: + - = . _ : / @". Added a sanitizer function to clear tags before the put request.
2025-05-23 11:09:40 +02:00
Tim Jaeryang Baek 9c4ce0273f Merge pull request #14215 from qingchunnh/Update_zh-TW-25523
i18n: Update zh-TW
2025-05-23 13:09:23 +04:00
qingchun 3d2a26fe0b i18n: Update & Improve zh-CN 2025-05-23 16:54:20 +08:00
qingchun aa6648ba8a i18n: Update & Improve zh-CN 2025-05-23 15:46:03 +08:00
YuQX ec97fdf5d6 Fix: Solve equation problems with Chinese symbols by adding more symbols to the ALLOWED_SURROUNDING_CHARS 2025-05-23 15:06:37 +08:00
qingchun 4025c96d0f i18n: Update zh-TW 2025-05-23 12:39:45 +08:00
qingchun ed9a2c295c i18n: Update & Improve zh-CN 2025-05-23 12:34:30 +08:00
qingchun 28e44452dd i18n: Update & Improve zh-CN 2025-05-23 09:51:05 +08:00
Zayd Krunz 1d382b83c8 refac: improve prompt formatting for selected text in FloatingButtons 2025-05-23 01:16:47 +00:00
Timothy Jaeryang Baek a2f12db8d9 refac: memories 2025-05-23 03:26:14 +04:00
Timothy Jaeryang Baek 7071a03419 chore: format 2025-05-23 02:54:44 +04:00
Timothy Jaeryang Baek 7a593b63b2 fix: image generation with allowed file extensions 2025-05-23 02:53:08 +04:00
Timothy Jaeryang Baek 4c55ad71a7 fix: local/external models 2025-05-23 02:48:31 +04:00
Timothy Jaeryang Baek 1f632d3570 fix: remove leading dot for file extension check 2025-05-23 02:39:19 +04:00
2eca6f6414 feat: bypass web loader in web search
Co-Authored-By: Perry Li <peiyaoli@mail.nankai.edu.cn>
Co-Authored-By: WilliamGates <3852641+williamgateszhao@users.noreply.github.com>
2025-05-23 02:30:35 +04:00
Timothy Jaeryang Baek 0b7f927983 enh: sortable banners 2025-05-23 02:02:11 +04:00
Timothy Jaeryang Baek a68ec8822a enh: filter md image for task generations 2025-05-23 01:33:08 +04:00
Timothy Jaeryang BaekandTornike Gurgenidze aac25eac9e refac: reranker
Co-Authored-By: Tornike Gurgenidze <togurg14@freeuni.edu.ge>
2025-05-23 01:29:48 +04:00
Timothy Jaeryang Baek f2d2cae8fb enh: help menu 2025-05-23 01:16:08 +04:00
Timothy Jaeryang Baek 71288ea3f2 refac 2025-05-23 01:11:44 +04:00
Timothy Jaeryang Baek cbe84d7139 enh: token expiry buffer 2025-05-23 01:08:28 +04:00
Timothy Jaeryang Baek d4c3cfbaba refac: oauth redirect url to use WEBUI_URL 2025-05-23 01:03:28 +04:00
Tim Jaeryang Baek 336d0b45ad Merge pull request #14165 from Zyfax/patch-1
fix: image model list
2025-05-22 15:37:00 +04:00
Tim Jaeryang Baek da4aa5f08b Merge pull request #14152 from U8F69/fix_user_auth
fix(auth): correctly use password hash when duplicate email records exist
2025-05-22 14:58:10 +04:00
Zyfax 7489bc6126 fix: image model list
OpenAI image model added:
gpt-image-1

Gemini image model renamed:
id: imagen-3-0-generate-002 to imagen-3.0-generate-002
2025-05-22 11:07:46 +02:00
Tim Jaeryang Baek 4519e4eed1 Merge pull request #14158 from itk-dev/feature/4347-danishtranslations
i18n: Updated danish translations
2025-05-22 12:47:22 +04:00
Timothy Jaeryang Baek 787987d2f0 refac/fix: optional tool param type 2025-05-22 12:41:00 +04:00
Tim Jaeryang Baek 17ed331a0a Merge pull request #14126 from SadmL/patch-2
[i18n] Russian locale update
2025-05-22 12:38:01 +04:00
Tim Jaeryang Baek b339fd6fed Merge pull request #14136 from Vombit/main
[i18n] Fixed a typo in the translation
2025-05-22 12:37:31 +04:00
Tim Jaeryang Baek 0eda03bd3c Merge pull request #14147 from PVBLIC-F/dev
perf Update pinecone.py
2025-05-22 12:19:14 +04:00
Tim Jaeryang Baek a935e375f3 Merge pull request #14149 from silentoplayz/i18n-fix
fix: $i18n.t fix
2025-05-22 11:49:09 +04:00
U8F69 dd6124a84f fix(auth): fix invalid password use in auth 2025-05-22 11:03:43 +08:00
Silentoplayz 558b2b1016 Update General.svelte 2025-05-21 20:41:19 -04:00
PVBLIC Foundation 86e24bb4aa Update pinecone.py
I've improved the pinecone.py file by:
Updated from the deprecated PineconeGRPC client to the newer Pinecone client
Modified the client initialization code to match the new API requirements
Added better response handling with getattr() to safely access attributes from response objects
Removed the streaming_upsert method which is not available in the newer client
Added safer attribute access with fallbacks throughout the code
Updated the close method to reflect that the newer client doesn't need explicit closing
These changes ensure the code is compatible with the latest Pinecone Python SDK and will be more robust against future changes. The key improvement is migrating away from the deprecated gRPC client which will eventually stop working.
2025-05-21 15:28:42 -07:00
Vombit ff46fa5b33 fix: fixed a typo in the translation 2025-05-21 21:15:42 +05:00
lilosti bd40cceb2d Updated danish translations 2025-05-21 14:52:33 +02:00
Link [Связной] 9201fd4652 [i18n] Russian locale update 2025-05-21 14:48:57 +03:00
Tim Jaeryang Baek 65a44a3900 Merge pull request #14099 from Classic298/ShiftHoldingFix
fix: Holding Shift Bug fixed
2025-05-21 13:46:58 +04:00
Tim Jaeryang Baek d2e426990b Merge pull request #14110 from qingchunnh/Update_zh-CN-25521
i18n: update and improve zh-CN
2025-05-21 13:43:00 +04:00
qingchun ed0538e643 i18n: update and improve zh-CN 2025-05-21 07:34:07 +08:00
Timothy Jaeryang Baek e3e7eb96f6 refac 2025-05-20 23:55:11 +04:00
Tim Jaeryang Baek a45f2cd0a9 Merge pull request #14104 from bassettb/bryan/parse-db-user-chars
fix: handle escaped characters in DATABASE_URL username
2025-05-20 23:51:41 +04:00
Timothy Jaeryang Baek 6121d4696a enh: search input arrow controls 2025-05-20 23:47:41 +04:00
Timothy Jaeryang Baek b78354100f refac 2025-05-20 23:33:41 +04:00
Timothy Jaeryang Baek 512345f40e refac: chat transition 2025-05-20 23:33:23 +04:00
Bryan Bassett 12896fb728 use unquote_user in peewee 3.17.10 2025-05-20 15:18:32 -04:00
DrMelone 8b80555adf fix attempt #1 2025-05-20 20:03:21 +02:00
Tim Jaeryang Baek 4e4b5ab83b Merge pull request #14096 from silentoplayz/add-clear-button-to-remaining-pages
feat: Add Clear button to Functions and Models pages search bar
2025-05-20 21:30:07 +04:00
Silentoplayz 03eeb75bfe feat: Add Clear button for Function and admin Model pages 2025-05-20 12:21:32 -04:00
Timothy Jaeryang Baek 74ace200fe fix/refac: functions multi-replica issue 2025-05-20 20:20:27 +04:00
Tim Jaeryang Baek 2b5c015bcb Merge pull request #14093 from open-webui/main
dev
2025-05-20 19:48:26 +04:00
Timothy Jaeryang Baek 82716f3789 refac 2025-05-20 19:39:18 +04:00
Timothy Jaeryang Baek a8a9b35153 refac: file item modal 2025-05-20 19:29:31 +04:00
Tim Jaeryang Baek d3c7628092 Merge pull request #14059 from sreesdas/main
fix: resolve issue where external document loader was not invoked
2025-05-20 17:43:06 +04:00
Tim Jaeryang Baek 86f1aee20b Merge pull request #14054 from silentoplayz/delete-lightblub
fix: Correct typo in LightBulb component name and imports & delete lightblub.svelte (duplicate of lightbulb.svelte)
2025-05-20 17:25:42 +04:00
Tim Jaeryang Baek f9a66afe76 Merge pull request #14072 from torisetxd/alignment-fix
fix: Alignment issues with Text in Buttons in UI
2025-05-20 17:24:49 +04:00
Tim Jaeryang Baek fac5884d8c Merge pull request #14073 from tth37/fix_default_web_loader_verify_ssl
fix: Default web loader fail silently when `verify_ssl=False`
2025-05-20 17:24:22 +04:00
Tim Jaeryang Baek 6035664048 Merge pull request #14051 from Classic298/german-translation
i18n: German translation overhaul
2025-05-20 17:23:55 +04:00
Tim Jaeryang Baek 75a31e116a Merge pull request #14049 from mjmendo/web_search_optional_fields
fix: web search optional fields
2025-05-20 17:22:52 +04:00
tth37 78befd5a2f fix: Default web loader fail when verify_ssl=False 2025-05-20 19:44:18 +08:00
toriset b735042ecc Fix alignment issues with Buttons in UI 2025-05-20 14:33:04 +03:00
Jan Kessler 308d8ac04a make bm25_weight a regular parameter of query_doc.. / get_sources_from_files functions 2025-05-20 11:46:32 +02:00
Jan Kessler b5ddaf6417 make weight for bm25 retriever in hybrid search ui-configurable 2025-05-20 10:39:31 +02:00
Classic298 8d94a59f27 task models 2025-05-20 08:39:36 +02:00
Classic298 479b5ad820 fixes after feedback 2025-05-20 08:31:49 +02:00
sree f408b08965 minor bug fix for external document loader not working 2025-05-20 11:10:23 +05:30
Derek Wischusen 42be1f956a Add Azure OpenAI embedding support 2025-05-19 22:58:04 -04:00
Silentoplayz ab9486603c chore: fix on-hover visual 2025-05-19 22:42:15 -04:00
Silentoplayz 58b309149a chore: adjustment 2025-05-19 17:21:43 -04:00
Silentoplayz 83ed2d0661 chore: delete lightblub.svelte 2025-05-19 17:12:36 -04:00
DrMelone 4b538047dd various i18n fixes
typos, incomplete sentences fixed, wrong translations, inconsistencies fixed
2025-05-19 19:35:08 +02:00
DrMelone fd2ff5e777 i18n german update 1 2025-05-19 19:28:12 +02:00
Marcelo Mendoza 897727c7eb Merge branch 'open-webui:main' into web_search_optional_fields 2025-05-19 17:25:14 +02:00
Marcelo Mendoza d6ad96affb fix: use get method for title and snippet in search results 2025-05-19 17:24:47 +02:00
Tim Jaeryang Baek 5613cda5cf Merge pull request #14048 from open-webui/main
dev
2025-05-19 19:17:39 +04:00
Timothy Jaeryang Baek ed0659aca6 refac 2025-05-19 19:17:08 +04:00
Timothy Jaeryang Baek fd91b277a4 refac: pypi 2025-05-19 14:48:55 +04:00
Timothy Jaeryang Baek d2758c7fa2 refac: pypi 2025-05-19 14:35:51 +04:00
Tim Jaeryang Baek ef3232a24f Merge pull request #14023 from TiancongLx/dev
i18n: update zh-TW
2025-05-19 14:22:31 +04:00
Tim Jaeryang Baek 438eb90671 Merge pull request #14024 from hurxxxx/i18n/update-ko-KR
i18n: update ko-KR
2025-05-19 14:22:13 +04:00
Tim Jaeryang Baek c9bbfaee9d Merge pull request #14033 from SadmL/patch-2
[i18n] Russian locale update
2025-05-19 14:22:03 +04:00
Link [Связной] 1d0921de0d [i18n] Russian locale update 2025-05-19 11:24:08 +03:00
hurxxxx c1066d7e08 i18n: update ko-KR 2025-05-19 13:28:45 +09:00
Tiancong Li 23991c32c5 i18n: update zh-TW 2025-05-19 12:09:07 +08:00
Tim Jaeryang Baek e6afa69f59 Merge pull request #13887 from open-webui/dev
0.6.10
2025-05-19 05:34:23 +04:00
Timothy Jaeryang Baek 2b1c3b5208 Update CHANGELOG.md 2025-05-19 05:27:29 +04:00
Timothy Jaeryang Baek b905b73935 Update CHANGELOG.md 2025-05-19 05:24:03 +04:00
Timothy Jaeryang Baek fa5cd59ef8 doc: changelog 2025-05-19 05:20:57 +04:00
Timothy Jaeryang Baek 030c20feff refac 2025-05-19 05:12:53 +04:00
Tim Jaeryang Baek 8fb7b980a2 Merge pull request #14019 from silentoplayz/clear
feat: Improve remaining export buttons with total item count
2025-05-19 04:33:34 +04:00
Timothy Jaeryang Baek eafb8e014a chore: format 2025-05-19 04:32:00 +04:00
Timothy Jaeryang Baek 2ab5aa4d34 refac: azure openai 2025-05-19 04:31:04 +04:00
Silentoplayz 5cb1475e29 fix: apply change to functions and models pages 2025-05-18 20:12:53 -04:00
Timothy Jaeryang Baek 2f2a7ee0b0 chore: format 2025-05-19 03:58:42 +04:00
Timothy Jaeryang Baek 2e56b1f13d refac 2025-05-19 03:55:56 +04:00
Timothy Jaeryang Baek caeb822cdc feat: azure openai support 2025-05-19 03:40:32 +04:00
Timothy Jaeryang Baek 47f8b3500b feat: azure openai connections ui 2025-05-19 03:29:14 +04:00
Timothy Jaeryang Baek 73e64fe7fb refac: audio upload handling 2025-05-19 02:52:48 +04:00
Timothy Jaeryang Baekandsilentoplayz aee9d05916 enh: workspace search clear button
Co-Authored-By: silentoplayz <50341825+silentoplayz@users.noreply.github.com>
2025-05-19 02:36:15 +04:00
Timothy Jaeryang Baek 3af289d196 refac 2025-05-19 02:32:06 +04:00
Timothy Jaeryang Baek 9f9fb3403d refac 2025-05-19 02:07:41 +04:00
Timothy Jaeryang Baek c6580a2a02 refac 2025-05-19 02:01:07 +04:00
Timothy Jaeryang Baek 417ba4980a chore: format 2025-05-19 01:55:02 +04:00
Timothy Jaeryang Baek 0c6f22b20b refac 2025-05-19 01:54:26 +04:00
Timothy Jaeryang Baek 96c7a0ac3c refac 2025-05-19 01:52:40 +04:00
Timothy Jaeryang Baek e895c33baa refac 2025-05-19 01:47:12 +04:00
Timothy Jaeryang Baek fbfd3ff134 refac 2025-05-19 01:44:27 +04:00
Timothy Jaeryang Baek 5a40feea1c enh: search shortcut 2025-05-19 01:40:51 +04:00
Timothy Jaeryang Baek 1f5860c4ab refac 2025-05-19 01:40:10 +04:00
Timothy Jaeryang Baek d069d1264d feat: search modal 2025-05-19 01:39:33 +04:00
Tim Jaeryang Baek 4f4811adb1 Merge pull request #14017 from athoik/title_tags
feat: read max_tokens from model config with fallback to 1000 for title and tag generation
2025-05-19 00:43:05 +04:00
Timothy Jaeryang Baek 05b79ce221 refac: model selection 2025-05-19 00:41:49 +04:00
Timothy Jaeryang Baekandsilentoplayz 18d6311951 feat: export count
Co-Authored-By: silentoplayz <50341825+silentoplayz@users.noreply.github.com>
2025-05-19 00:15:07 +04:00
Timothy Jaeryang Baek 8f4104fb7a refac 2025-05-19 00:13:03 +04:00
Tim Jaeryang Baek 349b0ca0b7 Merge pull request #14002 from silentoplayz/search-by-user-or-email
feat: enhance search with username/email search across workspace pages
2025-05-19 00:12:11 +04:00
Tim Jaeryang Baek 2dde4102ad Merge pull request #14009 from TiancongLx/dev
i18n: update and improve zh-TW
2025-05-19 00:11:32 +04:00
Athanasios Oikonomou eabdd4a140 feat: read max_tokens from model config with fallback to 1000 for title and tag generation
Improves title and tag generation by using the max_tokens value from the model configuration when available, with a fallback to the previous default of 1000.

This change is necessary for models like Gemini Pro that generate longer responses and require a higher token limit to successfully generate titles or tags.
2025-05-18 22:45:33 +03:00
Tiancong Li 4667328d40 i18n: update zh-TW 2025-05-18 21:16:16 +08:00
Tim Jaeryang Baek 56740ab8d6 Merge pull request #13996 from Davixk/update-IT-translation
i18n: add and improve Italian translations
2025-05-18 15:04:54 +04:00
Silentoplayz 95badda1c2 feat: username and email search in workspace pages 2025-05-18 03:23:38 -04:00
Dave ebf2e4141e Merge remote-tracking branch 'upstream/dev' into update-IT-translation 2025-05-18 04:46:41 +02:00
Dave a8813c1a69 i18n: Update and Improve Italian translations 2025-05-18 04:36:12 +02:00
Tim Jaeryang Baek fbcc80485b Merge pull request #13972 from jarrod-lowe/otel-attrs
feat: Add user details to opentelemetry spans
2025-05-17 21:54:56 +04:00
Timothy Jaeryang Baek 765acc4cad chore: dep bump 2025-05-17 21:53:31 +04:00
Timothy Jaeryang Baek 9801a2d23f refac 2025-05-17 03:14:26 +04:00
Timothy Jaeryang Baek 424f6f71cf chore: duckduckgo-search bump 2025-05-17 03:03:07 +04:00
Timothy Jaeryang Baek b280f828b0 enh: very long audio transcription 2025-05-17 02:51:28 +04:00
Timothy Jaeryang Baek d54e588ec3 refac 2025-05-17 02:26:28 +04:00
Timothy Jaeryang Baek 08e4c163ea feat: local/external connections 2025-05-17 01:47:48 +04:00
Timothy Jaeryang Baek 000906cd99 chore: format 2025-05-17 01:13:36 +04:00
Timothy Jaeryang Baek c3acb30bb1 feat: model file upload capability 2025-05-17 01:13:13 +04:00
Jarrod Lowe df853246f3 Add user details to otel span 2025-05-17 09:11:26 +12:00
Timothy Jaeryang Baek 6692fb2181 chore: format 2025-05-17 01:00:37 +04:00
Timothy Jaeryang Baek b14398481d enh: model capabilities 2025-05-17 00:59:00 +04:00
Timothy Jaeryang Baek 7df6d7f325 refac/fix: signout redirect flow 2025-05-17 00:38:39 +04:00
Timothy Jaeryang Baek fcb93f3155 feat: artifacts download button 2025-05-17 00:27:20 +04:00
Timothy Jaeryang Baek 02e5bbc903 refac 2025-05-17 00:19:08 +04:00
Timothy Jaeryang Baek 359bcb837d refac 2025-05-17 00:08:03 +04:00
Timothy Jaeryang Baek ecae944fd0 refac 2025-05-16 23:59:24 +04:00
Timothy Jaeryang Baek 05f284d4a6 refac 2025-05-16 23:41:51 +04:00
Timothy Jaeryang Baek ea723374c7 refac 2025-05-16 23:36:33 +04:00
Timothy Jaeryang Baek 1f38350128 feat: toggle filter middleware 2025-05-16 23:33:02 +04:00
Timothy Jaeryang Baek e37433f2b1 refac 2025-05-16 23:21:08 +04:00
Timothy Jaeryang Baek b61efcf54a feat: toggle filter 2025-05-16 22:59:02 +04:00
Timothy Jaeryang Baek 32b386e8d0 refac 2025-05-16 22:44:47 +04:00
Timothy Jaeryang Baek 7bbeaec93b revert 2025-05-16 22:43:42 +04:00
Timothy Jaeryang Baek 34ef249a10 revert: remove reasoning capability 2025-05-16 22:24:23 +04:00
Timothy Jaeryang Baek 363ac35c09 refac 2025-05-16 22:17:47 +04:00
Tim Jaeryang Baek 50bc6d9b12 Merge pull request #13919 from dongfangzan/main
feat: add switching thinking/non-thinking modes to models
2025-05-16 22:08:04 +04:00
Timothy Jaeryang Baek 27bb5f5369 fix/refac: tts remove formattings 2025-05-16 21:51:29 +04:00
Timothy Jaeryang Baek 54dc24986f feat: preview html 2025-05-16 21:47:43 +04:00
Timothy Jaeryang Baek 07b5e84221 refac 2025-05-16 21:29:50 +04:00
Timothy Jaeryang Baek 2bd7db12a2 enh: ALLOWED_FILE_EXTENSIONS ui 2025-05-16 21:05:52 +04:00
Timothy Jaeryang Baek 528a2cf96a refac 2025-05-16 18:19:28 +04:00
Timothy Jaeryang Baek 2aa5e73728 refac: filter details 2025-05-16 18:01:55 +04:00
Timothy Jaeryang Baek dec9dd1ac0 refac: web search queries 2025-05-16 17:11:42 +04:00
Timothy Jaeryang Baek bb06df80a2 refac 2025-05-16 17:07:52 +04:00
Timothy Jaeryang Baek 0b761776c4 enh: high contrast mode 2025-05-16 17:06:21 +04:00
Timothy Jaeryang Baek 2450f2c5d8 chore: format 2025-05-16 16:57:30 +04:00
Timothy Jaeryang Baek 62180b15e1 refac: command arrow up/down behaviour 2025-05-16 15:39:26 +04:00
Tim Jaeryang Baek c201b4d689 Merge pull request #13931 from itk-dev/feature/better-frontend-error
WIP: Minor clean up of console log usage in the front end
2025-05-16 13:33:16 +04:00
Tim Jaeryang Baek bc66755fb0 Merge pull request #13950 from uryukikutani/feature/screen-reader
fix: made the chat response messages readable with a screen reader
2025-05-16 13:32:40 +04:00
Tim Jaeryang Baek e74c06d2f5 Merge pull request #13929 from mini-777/feat--Korean-translations-for-clarity-and-accuracy
i18n : korean translations for clarity and accuracy
2025-05-16 13:32:10 +04:00
uryukikutani 53dcaa63d4 made the chat response messages readable with a screen reader 2025-05-16 17:41:56 +09:00
Tim Jaeryang Baek 186a89bcba Merge pull request #13937 from tanerim/patch-1
Update translation.json
2025-05-16 10:23:47 +04:00
dongfangzan 351f0186b9 fix: typo 2025-05-16 08:05:49 +08:00
Taner Sezer 21e96247a9 Update translation.json
Added new translations
2025-05-16 01:19:53 +03:00
Jesper Kristensen 84e0605835 Cleaning up usage of console log in front end 2025-05-15 21:53:07 +02:00
Jesper Kristensen 20c1c3f66b Changed console logging of errors to use console error logging 2025-05-15 21:35:07 +02:00
mini-777 2a4fe1335e i18n: update Korean translations with new entries and corrections 2025-05-16 02:45:19 +09:00
mini-777 e24e22debe Merge commit 'e4179aa114fecc8d35ba48f091ce7c9abcc96065' into HEAD 2025-05-16 02:10:01 +09:00
mini-777 208b86ae53 feat: add new notes feature with editor and list components, and update routing for notes management 2025-05-16 02:06:36 +09:00
Tim Jaeryang Baek e4179aa114 Merge pull request #13922 from TiancongLx/dev
i18n: update zh-TW
2025-05-15 19:02:37 +04:00
Tiancong Li df5ef8e553 i18n: update zh-TW 2025-05-15 21:15:22 +08:00
dongfangzan 9b93b81f84 feat: add switching thinking/non-thinking modes to models 2025-05-15 19:56:10 +08:00
dongfangzan a7c90925ef test contribute 2025-05-15 19:31:40 +08:00
Tim Jaeryang Baek ca2cfb5bad Merge pull request #13899 from loitragg/apply-multitenant-for-qdrant
perf: implement multi-tenancy for Qdrant vector store client
2025-05-15 13:37:36 +04:00
Kiet Trinh 418ac1a8da refac: Rename Qdrant multi-tenancy variable for improved clarity and consistency 2025-05-15 09:09:24 +00:00
Tim Jaeryang Baek db24af6356 Merge pull request #13902 from yo-nagase/dev
i18n: Update Japanese translation
2025-05-15 12:59:17 +04:00
Timothy Jaeryang Baek 72b2555953 refac 2025-05-15 12:58:44 +04:00
Kiet Trinh 485bd7666c fix: Update Qdrant multi-tenancy variable name for consistency in configuration 2025-05-15 08:02:58 +00:00
Nagase Yoshimasa 6eb772c741 i18n: Update Japanese translation 2025-05-15 15:41:04 +09:00
LoiTra 184d8dfd7e feat: Implement Qdrant multi-tenancy support with collection management and tenant isolation 2025-05-15 11:28:06 +07:00
Timothy Jaeryang Baek 0a8cecfbfa feat: response watermark 2025-05-14 23:53:28 +04:00
Timothy Jaeryang Baek b143c71da2 refac: AIOHTTP_CLIENT_SESSION_SSL 2025-05-14 23:33:52 +04:00
Timothy Jaeryang Baek 04287eb6d6 refac 2025-05-14 23:27:34 +04:00
Timothy Jaeryang Baek 39b06dc3b6 refac 2025-05-14 23:13:06 +04:00
Tim Jaeryang Baek e358a66fb1 Merge pull request #13852 from fizyr-forks/self-signed-cert
feat: Add option to disable certificate validation for LDAP certificates.
2025-05-14 23:12:24 +04:00
Timothy Jaeryang Baek a6624a4b16 feat: RAG_ALLOWED_FILE_EXTENSIONS 2025-05-14 23:06:33 +04:00
Timothy Jaeryang Baek 7e241a3904 refac 2025-05-14 22:48:23 +04:00
Timothy Jaeryang Baek 42382b5167 fix 2025-05-14 22:46:01 +04:00
Timothy Jaeryang Baek 8732b64b6b feat: external document loader support 2025-05-14 22:28:40 +04:00
Timothy Jaeryang Baek 32ea31144e refac: file upload handling behaviour 2025-05-14 22:00:42 +04:00
Timothy Jaeryang Baek b80f0751f6 refac 2025-05-14 21:59:17 +04:00
Timothy Jaeryang Baek 0280ee30c7 chore: format 2025-05-14 21:56:22 +04:00
Timothy Jaeryang Baek 8fe4f789d4 fix 2025-05-14 21:53:46 +04:00
Timothy Jaeryang Baek dacf7e015d i18n: revert 2025-05-14 21:52:42 +04:00
Timothy Jaeryang Baek ac83568194 chore: format 2025-05-14 21:40:51 +04:00
Timothy Jaeryang Baek 10108fcd04 chore: format 2025-05-14 21:39:50 +04:00
Timothy Jaeryang Baek 74ccec2812 refac 2025-05-14 21:39:17 +04:00
Tim Jaeryang Baek 29ae231ee0 Merge pull request #13889 from Classic298/pendingtext
feat: Custom Title and Text for Account Activation Screen for pending users
2025-05-14 21:28:16 +04:00
Timothy Jaeryang Baek de70d0cb64 feat: docling do picture description support 2025-05-14 21:26:49 +04:00
DrMelone 3974e53cc3 i18n 2025-05-14 19:11:53 +02:00
DrMelone 92140118f2 revert i18n 2025-05-14 19:07:45 +02:00
DrMelone e9eb661b83 fix + i18n 2025-05-14 18:58:54 +02:00
DrMelone bdb3778f8b fix 2025-05-14 18:10:23 +02:00
Timothy Jaeryang Baek 6e8481e157 fix: evaluation feedback endpoints 2025-05-14 20:08:49 +04:00
DrMelone 143cb4cc34 feat custom text and title 2025-05-14 17:58:20 +02:00
Tim Jaeryang Baek 2217fc4fd9 Merge pull request #13883 from alpha-pet/fix-workspace-model-unintended-toggle
Fix: Unintentional toggling of model status on the workspace page.
2025-05-14 18:09:16 +04:00
Tim Jaeryang Baek 8029bf0dca Merge pull request #13881 from hwzhuhao/feat/vector-db
feat: Add vector type and vector factory class for vector database integration
2025-05-14 17:41:39 +04:00
Thomas Rehn 6b6ce36c96 fix: add unique key to model list to avoid state confusion when filtering 2025-05-14 15:33:32 +02:00
hwzhuhao 6f869ded43 feat:Add vector type and vector factory class for vector database integration 2025-05-14 21:30:50 +08:00
Tim Jaeryang Baek 4959e91fa7 Merge pull request #13832 from Ithanil/svelte_versioning
feat: Handle frontend updates according to Svelte docs
2025-05-14 17:19:32 +04:00
Tim Jaeryang Baek f77a076c16 Merge pull request #13882 from itk-dev/feature/enable_direct_connections
chore: Added missing "enable_direct_connections" to config type
2025-05-14 17:18:04 +04:00
Jesper Kristensen 8b194bc781 Added missing "enable_direct_connections" to config type 2025-05-14 14:53:36 +02:00
Tim Jaeryang Baek bd7d2978f1 Merge pull request #13846 from hary777/patch-2
i18n update translation.json fix typo "amin" in cs-CZ
2025-05-14 15:27:40 +04:00
Tim Jaeryang Baek c7e3ae9f39 Merge pull request #13812 from hwzhuhao/refactor/log
refactor: replace print statements with logging
2025-05-14 15:27:13 +04:00
Timothy Jaeryang Baek 92a8ea743a refac: form data edge case 2025-05-14 15:22:38 +04:00
Timothy Jaeryang Baek 3c4accaeb3 refac/security: ollama model upload path traversal 2025-05-14 15:17:07 +04:00
Timothy Jaeryang Baek a9c22bffc9 refac/security: pipelines upload path traversal 2025-05-14 15:15:05 +04:00
Tim Jaeryang Baek d89e37cc7c Merge pull request #13866 from itk-dev/feature/contrast-chat-input
feat: Contrast enhancements
2025-05-14 15:12:00 +04:00
Sine Jespersen 8eacd26573 add placeholder dark mode 2025-05-14 12:50:47 +02:00
Sine Jespersen 90bcf45b7b placeholder contrast changed 2025-05-14 10:24:09 +02:00
Yeyeong Cho bbb4e75df8 Merge pull request #2 from mini-777/i18n-ko-rewriting
feat(openwebui) : improve Korean translations for better readability Fixes mini-777/8dobibim#2
2025-05-14 17:23:48 +09:00
Sine Jespersen b052b5cced remove whitespace 2025-05-14 10:15:31 +02:00
Sine Jespersen 5db783d67b improve suggestions contrast 2025-05-14 09:52:44 +02:00
Sine Jespersen 43d0db5eea model selector contrast 2025-05-14 09:52:10 +02:00
Sine Jespersen 41f64da0d6 update message input contrast 2025-05-14 09:51:38 +02:00
Sine Jespersen 5cd0b99ae0 update toast contrast 2025-05-14 09:51:07 +02:00
mini-777 571d078a82 fix: improve Korean translations for better readability (fixes mini-777/8dobibim#2) 2025-05-14 15:37:59 +09:00
mini-777 f72fa9b269 fix: update Korean translations for clarity and accuracy 2025-05-14 15:28:46 +09:00
Hans Gaiser f63e76e653 Add option to disable certificate validation. 2025-05-13 17:38:06 +02:00
hary777 66d73cb1de Update translation.json fix typo
Fix typo "amin". I can not look at this anymore.
2025-05-13 15:24:48 +02:00
Tim Jaeryang Baek 950f3cdcc0 Merge pull request #13838 from TiancongLx/dev
i18n: update, complete, and optimize zh-TW
2025-05-13 16:53:52 +04:00
Tim Jaeryang Baek f907e7c979 Merge pull request #13836 from itk-dev/feature/build-watch
build: Added build:watch command to package.json
2025-05-13 16:53:24 +04:00
Jesper Kristensen 24c1b8911c Added build:watch script/command to package.json
Should make it eaiser to automatically build the front-end when
doing local development in docker node containers.
2025-05-13 10:36:48 +02:00
Tiancong Li b41fc1d2f4 i18n: update zh-TW 2025-05-13 16:30:59 +08:00
Jan Kessler dfd4037132 better handling of frontend updates, following svelte docs 2025-05-13 09:51:51 +02:00
Timothy Jaeryang Baek a904f874ee fix: admin signup logic 2025-05-12 20:03:40 +04:00
hwzhuhao fb2950201a refactor: replace print statements with logging 2025-05-12 22:18:47 +08:00
Timothy Jaeryang Baek e9b799676b chore: format 2025-05-12 17:34:33 +04:00
Tim Jaeryang Baek c7f743ddb7 Merge pull request #13810 from phpia/phpia-patch-1
i18n es
2025-05-12 17:31:18 +04:00
phpia 16a9210321 Update translation for mantain prompt
This pull request updates the Spanish localization by replacing all instances of "indicador"/"indicadores" with the more accurate terms "prompt"/"prompts" throughout the UI, documentation, and messages. 

Reason and Rationale: 

In the context of AI and Large Language Models (LLMs), the words "prompt" and "prompts" have become standardized terms worldwide, including within the Spanish-speaking technical community. While "indicador" is a valid literal translation of "prompt" in general Spanish, in generative AI contexts it is potentially confusing, since "indicador" more commonly refers to a gauge, dashboard indicator, or measuring device. This can cause misunderstanding for users, especially those familiar with AI concepts, who expect the term "prompt" to refer to the input text given to a model.
2025-05-12 14:59:15 +02:00
Sung Min c049837a11 Merge pull request #1 from mini-777/i18n-ko-missing
feat(openwebui) : add missing Korean translation strings Fixes mini-777/8dobibim#1
2025-05-12 20:55:14 +09:00
Tim Jaeryang Baek ca34ba318e Merge pull request #13801 from aleixdorca/dev
i18n: Update catalan translation.json
2025-05-12 14:56:19 +04:00
Tim Jaeryang Baek 0d8e24320e Merge pull request #13794 from Lutherwaves/dev
i18n: Bulgarian translations
2025-05-12 14:55:10 +04:00
Aleix Dorca b7ef9a03ac Update catalan translation.json 2025-05-12 08:56:52 +02:00
Tim Jaeryang Baek 4ce1e88750 Merge pull request #13795 from open-webui/dev
refac
2025-05-12 01:10:34 +04:00
Timothy Jaeryang Baek f32b042a00 refac 2025-05-12 01:08:49 +04:00
lutherwaves 792beb095e i18n: Bulgarian translations 2025-05-11 23:58:31 +03:00
Timothy Jaeryang Baek 4c06683e95 refac: Vazirmatn 2025-05-12 00:05:04 +04:00
Tim Jaeryang Baek 0cef844168 Merge pull request #13758 from open-webui/dev
0.6.9
2025-05-10 23:04:48 +04:00
Timothy Jaeryang Baek c56d6963b0 doc: changelog 2025-05-10 23:01:48 +04:00
Timothy Jaeryang Baek 92e2cfdd2f refac 2025-05-10 23:00:53 +04:00
Timothy Jaeryang Baek 3ad5a7d97c chore: bump 2025-05-10 22:48:26 +04:00
Timothy Jaeryang Baek 867fddb821 chore: format 2025-05-10 22:45:58 +04:00
Timothy Jaeryang Baek de69c08a1d enh: alert private task model 2025-05-10 22:43:53 +04:00
Timothy Jaeryang Baek 30cc51ec82 feat: edit message files 2025-05-10 22:27:39 +04:00
Timothy Jaeryang Baek ba69c751ca refac: temporary chat behaviour 2025-05-10 22:12:36 +04:00
Timothy Jaeryang Baek be85f7cc35 fix: confirm dialog focus 2025-05-10 22:09:05 +04:00
Tim Jaeryang Baek 4191ec692e Merge pull request #13751 from open-webui/dev
fix: external reranker
2025-05-10 19:33:59 +04:00
Timothy Jaeryang Baek 6b5f99bf66 fix: external reranker 2025-05-10 19:33:34 +04:00
Tim Jaeryang Baek ef301aa16b Merge pull request #13707 from open-webui/dev
0.6.8
2025-05-10 19:31:52 +04:00
Timothy Jaeryang Baek 32b27749ef Update CHANGELOG.md 2025-05-10 19:29:02 +04:00
Timothy Jaeryang Baek b81a5833c7 doc: changelog 2025-05-10 19:25:42 +04:00
Timothy Jaeryang Baek 6f635d8b7d refac 2025-05-10 19:16:09 +04:00
Timothy Jaeryang Baek 549989e9ec refac 2025-05-10 19:04:40 +04:00
Timothy Jaeryang Baek 1c665592e4 chore: bump 2025-05-10 19:01:12 +04:00
Timothy Jaeryang Baek c61790b355 chore: format 2025-05-10 19:00:01 +04:00
Timothy Jaeryang Baek 3a79840a87 feat: unstylized pdf export 2025-05-10 18:59:04 +04:00
Timothy Jaeryang Baek a515a5df1a refac 2025-05-10 18:38:30 +04:00
Timothy Jaeryang Baek ba72d4625f refac 2025-05-10 18:36:45 +04:00
Timothy Jaeryang Baek 3dc34c2402 feat: external reranker settings ui 2025-05-10 18:33:52 +04:00
Timothy Jaeryang Baek be912f1529 refac 2025-05-10 18:29:04 +04:00
Timothy Jaeryang BaekandBrendan Campbell d5fd3b3600 feat: external reranker
Co-Authored-By: Brendan Campbell <20541191+bcambs09@users.noreply.github.com>
2025-05-10 18:25:20 +04:00
Timothy Jaeryang BaekandMabeck 34ec10a78c refac: web search performance
Co-Authored-By: Mabeck <64421281+mmabeck@users.noreply.github.com>
2025-05-10 17:54:41 +04:00
Timothy Jaeryang Baek 015ac2f532 refac: user list loading indicator 2025-05-10 17:23:17 +04:00
Tim Jaeryang Baek 030b6b26af Merge pull request #13735 from Classic298/dev
Fix: Markdown in Knowledgebases rendered correctly now
2025-05-10 17:13:16 +04:00
Tim Jaeryang Baek 6d1c18e118 Merge pull request #13736 from taylorwilsdon/ideas/13702
enh: Improve visibility of overflow / hidden tools when more than 3 are present
2025-05-10 17:10:45 +04:00
Tim Jaeryang Baek 54dda08d39 Merge pull request #13712 from PVBLIC-F/dev
perf - Pinecone.py
2025-05-10 17:10:08 +04:00
Tim Jaeryang Baek 7bfe4c6a43 Merge pull request #13738 from dataway/dev
fix: allow non-root jupyter base_url
2025-05-10 17:09:09 +04:00
Timothy Jaeryang Baek cc1dc6cb78 refac: config 2025-05-10 17:08:09 +04:00
PVBLIC Foundation 3f58a17e47 Update pinecone.py
•	Removed the unused Pinecone REST‐client import; we now only import ServerlessSpec and the gRPC client.
	•	Enhanced close()
	•	Call self.client.close() to explicitly shut down the underlying gRPC channel.
	•	Log success or a warning on failure.
	•	Still tear down the thread‐pool executor afterward.
	•	Context‐manager support
	•	Added __enter__()/__exit__() so you can do:

with PineconeClient() as client:
    client.insert(...)
# automatically calls client.close()
2025-05-10 06:07:27 -07:00
Tim Jaeryang Baek 3e1be8b958 Merge pull request #13746 from ghscience/dev
i18n Updated Italian Language Translation Added missing translations
2025-05-10 17:05:49 +04:00
gh d704b8b686 i18n Updated Italian Language Translation 2025-05-10 09:53:52 +00:00
PVBLIC Foundation 12c2138982 Update pinecone.py
Refactor and added debug
2025-05-09 18:15:22 -07:00
Anthony Uk 337ece4d50 code_interpreter.py: allow non-root jupyter base_url 2025-05-09 20:32:01 +02:00
Taylor Wilsdon 1299c11650 only show tools toggle if overflow present 2025-05-09 10:30:45 -04:00
Taylor Wilsdon 628a10e34a make the collapse toggle more subtle & compact 2025-05-09 10:26:48 -04:00
Classic298 513895c2d5 Update KnowledgeBase.svelte 2025-05-09 16:24:07 +02:00
Taylor Wilsdon ccbc46fbbe implement visible scrollbar for tools overflow, add show all toggle 2025-05-09 10:20:17 -04:00
Tim Jaeryang Baek 8acc1ab425 Merge pull request #13731 from tth37/fix_duplicate_web_search_urls
fix: Duplicate web search urls
2025-05-09 16:43:11 +04:00
Tim Jaeryang Baek 616e9e2760 Merge pull request #13730 from Classic298/dev
feat: Increase default users per page in admin panel to 30
2025-05-09 16:42:29 +04:00
tth37 c95a65a4bd fix: Duplicate web search urls 2025-05-09 20:06:35 +08:00
Classic298 220d35ebcb Increase users shown per page to 30 2025-05-09 13:00:42 +02:00
Classic298 947f5e840e Increased PAGE_ITEM_COUNT to 30 2025-05-09 12:59:50 +02:00
Timothy Jaeryang Baek ebf5cb22ab refac: socket 2025-05-09 14:23:16 +04:00
Timothy Jaeryang Baek d84a3c0bf4 revert: websocket 2025-05-09 14:20:43 +04:00
Timothy Jaeryang Baek 9143716463 refac: chat pdf rendering 2025-05-09 13:56:53 +04:00
Yeyeong Cho 13e7a3dee9 fix:add missing Korean translation strings Fixes mini-777/8dobibim#1 2025-05-09 17:54:50 +09:00
Timothy Jaeryang Baek 9657474a8d refac: websocket 2025-05-09 12:45:53 +04:00
PVBLIC Foundation b38711a581 Update pinecone.py 2025-05-08 16:02:47 -07:00
PVBLIC Foundation 04b9065f08 Update pinecone.py
Now supports batched insert, upsert, and delete operations using a default batch size of 100, reducing API strain and improving throughput. All blocking calls to the Pinecone API are wrapped in asyncio.to_thread(...), ensuring async safety and preventing event loop blocking. The implementation includes zero-vector handling for efficient metadata-only queries, normalized cosine distance scores for accurate ranking, and protections against empty input operations. Logs for batch durations have been streamlined to minimize noise, while preserving key info-level success logs.
2025-05-08 15:53:30 -07:00
Timothy Jaeryang Baek 827326e1a2 refac: audio transcription issue 2025-05-08 22:57:48 +04:00
Timothy Jaeryang Baek bfa5550cc3 refac: openai already supports webm audio 2025-05-08 22:44:32 +04:00
Tim Jaeryang Baek e60fa7927d Merge pull request #13604 from Acters/dev
feat: Improve Default Code Interpreter Prompt
2025-05-08 22:14:29 +04:00
Tim Jaeryang Baek 1fea4f794f Merge pull request #13670 from HarrisonConsulting/fix/milvus-standalone-index
fix: enhance MilvusClient with dynamic index type and improved logging
2025-05-08 22:08:23 +04:00
Timothy Jaeryang Baek 7c8597765f refac/fix: ldap issue 2025-05-08 22:06:44 +04:00
Timothy Jaeryang Baek 08b6ea0e17 refac 2025-05-08 20:47:41 +04:00
Tim Jaeryang Baek 68f5ff540c Merge pull request #13695 from itk-dev/8908-focus-trap-modal
feat: focus trap modal
2025-05-08 20:44:36 +04:00
Tim Jaeryang Baek 9509528deb Merge pull request #13703 from hurxxxx/fix/onedrive-org-picker-error
fix: Add SharePoint tenant ID to OneDrive settings
2025-05-08 20:41:06 +04:00
hurxxxx 4ca0ea1e55 Add SharePoint tenant ID to OneDrive settings 2025-05-09 00:35:23 +09:00
Sine Jespersen 3886dee1ce add whitespace and semi colon 2025-05-08 13:29:24 +02:00
Sine Jespersen 305435b4ef use npm package focus-trap instead of npm package focus-trap-svelte 2025-05-08 13:22:47 +02:00
Matt Harrison 4abe2cfa7b fix: Specified "HNSW" for backwards compatibility prefering cluster environments over standalone. 2025-05-08 07:21:34 -04:00
Tim Jaeryang Baek a6d6c928d9 Merge pull request #13567 from tth37/fix_katex_chinese_delimiters
fix(katex): Allow CJK characters adjacent to math delimiters
2025-05-08 14:41:16 +04:00
Timothy Jaeryang Baek af518cacbf refac: filter out images 2025-05-08 12:43:13 +04:00
Tim Jaeryang Baek 54e4c1e0cc Merge pull request #13675 from feddersen-group/task/remove_files_from_tasks
perf: remove files from tasks
2025-05-08 12:38:39 +04:00
Tim Jaeryang Baek f6b20ca109 Merge pull request #13677 from silentoplayz/dev
refactor: Improve Default Title Generation Prompt Template for robust JSON output
2025-05-08 12:38:05 +04:00
silentoplayz 994f17b430 Update config.py
Update DEFAULT_TITLE_GENERATION_PROMPT_TEMPLATE
2025-05-08 07:31:51 +00:00
Alexander Grimm a655bb5a63 skip checks in title gen 2025-05-08 06:55:43 +00:00
Alexander Grimm cf5201aada remove files from message for tasks 2025-05-08 06:50:21 +00:00
Matt Harrison 2df9f7fb4d fix: remove import for os module in milvus.py 2025-05-08 00:28:24 -04:00
Matt Harrison 731251d11a refac: streamline Milvus index type handling using configuration options 2025-05-07 23:39:56 -04:00
Matt Harrison 2b8be86f23 feat: add Milvus configuration options for index and metric types 2025-05-07 23:32:58 -04:00
Matt Harrison 5e46c27806 refac: enhance MilvusClient with dynamic index type and improved logging 2025-05-07 21:51:28 -04:00
Timothy Jaeryang Baek b34401a087 refac/fix: notes hide hidden models 2025-05-07 23:55:20 +04:00
Timothy Jaeryang Baek 61a9d9927d refac/fix: message input rtl issue 2025-05-07 23:14:42 +04:00
Timothy Jaeryang Baek f761d2cf90 refac: allow html video controls 2025-05-07 23:06:00 +04:00
Timothy Jaeryang Baek 0f40cb0de4 feat: Vazirmatn font for Persian and Arabic languages 2025-05-07 22:31:59 +04:00
Timothy Jaeryang Baek b50dcb1862 refac: remove duplicate urls 2025-05-07 22:25:18 +04:00
Tim Jaeryang Baek b9f55a44b7 Merge pull request #13346 from dh4340/patch-1
Fix: Use dynamic Python command to run uvicorn and support pyenv setups.
2025-05-07 22:08:35 +04:00
Tim Jaeryang Baek f1bb43707e Merge pull request #13566 from itk-dev/8908-accessibility-enhancements
feat: Accessibility enhancements
2025-05-07 22:07:57 +04:00
Tim Jaeryang Baek 519bb64238 Merge pull request #13623 from panda44312/patch-15
i18n: zh-cn
2025-05-07 22:06:54 +04:00
Tim Jaeryang Baek 410af53eca Merge pull request #13581 from kaytwo/refreshOauthPfp
feat: refresh oauth profile picture
2025-05-07 22:06:43 +04:00
Tim Jaeryang Baek c2de7efa2f Merge pull request #13637 from mMabeck/my-dev
i18n: Update Danish translations (da-DK)
2025-05-07 22:02:29 +04:00
Tim Jaeryang Baek 6424c8b644 Merge pull request #13643 from suleimanelkhoury/S3-tagging-boto3
fix: Add S3_ENABLE_TAGGING env variable and fix S3_USE_ACCELERATE_ENDPOINT Type Error
2025-05-07 22:02:14 +04:00
Sine Jespersen bd2021e8e1 add aria modal true and role dialog to modal 2025-05-07 15:17:11 +02:00
Suleiman Elkhoury ccc64ac6b7 Update provider.py
Add S3_ENABLE_TAGGING to add tags optionally based on the env file.
2025-05-07 14:48:49 +02:00
Suleiman Elkhoury 7620a6bf8c Update config.py
Fixed S3_USE_ACCELERATE_ENDPOINT variable from "False" to "false" since boto3 expects a Python bool, not a string.
Added S3_ENABLE_TAGGING env variable to avoid incompatiblilty with Storages that does not support tagging (like Cloudflare R2)
2025-05-07 14:46:58 +02:00
Sine Jespersen 54b30e0b7f use svelte-focus-trap in modal 2025-05-07 14:21:56 +02:00
Sine Jespersen f56983632f add npm package svelte-focus-trap 2025-05-07 14:20:06 +02:00
Mabeck 3a553f7208 Updated danish translations 2025-05-07 14:06:30 +02:00
Panda 571e4c9600 Merge branch 'dev' into patch-15 2025-05-07 11:18:13 +02:00
Timothy Jaeryang Baek a38f3c7617 refac 2025-05-07 13:10:24 +04:00
Timothy Jaeryang Baek b1fb298bee enh: contributions stats script 2025-05-07 13:09:41 +04:00
Timothy Jaeryang Baek 176a7fc986 refac 2025-05-07 12:52:55 +04:00
Tim Jaeryang Baek efd50c3c5a Merge pull request #13607 from ssakar/dev
feat: add presence_penalty parameter to openai (Qwen3)
2025-05-07 12:48:23 +04:00
Sine Jespersen 263086aa91 break and indent divs 2025-05-07 09:21:04 +02:00
Tim Jaeryang Baek a3bb7df610 Merge pull request #13530 from open-webui/dev
0.6.7
2025-05-07 03:08:25 +04:00
Timothy Jaeryang Baek 3a6a05cef1 doc: changelog 2025-05-07 03:05:49 +04:00
Serkan Sakar d62353c140 enh: add presence_penalty parameter to openai 2025-05-07 00:56:20 +02:00
Timothy Jaeryang Baek 803b39b00c refac 2025-05-07 02:45:00 +04:00
Timothy Jaeryang Baek ed5de96d1d fix: tool servers ui settings can be bypassed with search 2025-05-07 02:41:33 +04:00
Timothy Jaeryang Baek c667d27c38 refac 2025-05-07 02:37:23 +04:00
acters e088f1ef23 Merge branch 'open-webui:dev' into dev 2025-05-06 16:17:54 -06:00
Timothy Jaeryang Baek ad1486c8bd refac 2025-05-07 02:06:18 +04:00
Timothy Jaeryang Baek 6359cb55fe chore: format 2025-05-07 02:01:03 +04:00
Timothy Jaeryang Baek 96618967bd refac 2025-05-07 02:00:10 +04:00
Tim Jaeryang Baek 19bf7289c1 Merge pull request #13603 from TiancongLx/dev
i18n: complete empty values and **fix a typo** in zh-TW
2025-05-07 01:53:16 +04:00
Timothy Jaeryang Baek 369f461691 refac 2025-05-07 01:48:54 +04:00
acters 9c760ace80 Improve Default Code Interpreter Prompt
The change to the default "Code Interpreter" prompt makes it more clear to the LLM to not wrap the code in markdown's code block formatting. This improves the reliability of having code generated in the XML tags that will run properly.
2025-05-06 15:36:17 -06:00
Tiancong Li 45e9d05240 i18n: update zh-TW 2025-05-07 05:16:44 +08:00
Timothy Jaeryang Baek ace3303ff5 enh: TOOL_SERVER_CONNECTIONS env var support 2025-05-07 01:11:28 +04:00
Timothy Jaeryang Baek 62e57a4cf5 refac: auth endpoint 2025-05-07 00:54:53 +04:00
Tim Jaeryang Baek 2a4dfc02a2 Merge pull request #13540 from NoMoreFood/dev
feat: Azure TTS Allow Base URL
2025-05-07 00:49:57 +04:00
Tim Jaeryang Baek e0e151f4f4 Merge pull request #13583 from torisetxd/torisetxd-image-patch
Fix: Fix Image parameter for Automatic1111 `/generations` endpoint
2025-05-07 00:45:08 +04:00
Tim Jaeryang Baek ea07e242f5 Merge pull request #13528 from Classic298/dev
feat: Enhance YouTube Transcription Loader for multi-language support
2025-05-07 00:44:45 +04:00
Timothy Jaeryang Baek 53f2ab1676 chore: wording 2025-05-06 20:15:09 +04:00
Chris Kanich 500f4d73e1 refresh oauth profile picture 2025-05-06 11:00:35 -05:00
toriset 6c957f2407 Fixed mis-use of set_image_model in automatic1111 Image generation
A custom model parameter would always throw an error.. :/
2025-05-06 18:17:52 +03:00
Classic298 1dcbec71ec Update youtube.py 2025-05-06 17:14:00 +02:00
Classic298 87dcbd198c Update youtube.py 2025-05-06 17:11:03 +02:00
Classic298 d7927506f1 Update youtube.py 2025-05-06 17:06:21 +02:00
Classic298 f65dc715f9 Update youtube.py 2025-05-06 16:30:18 +02:00
Classic298 c69278c13c Update youtube.py 2025-05-06 16:24:27 +02:00
Classic298 a129e0954e Update youtube.py 2025-05-06 16:22:40 +02:00
Classic298 5e1cb76b93 Update youtube.py 2025-05-06 16:16:58 +02:00
tth37 8e14372dd8 enh: Support more languages 2025-05-06 21:26:09 +08:00
Sine Jespersen 9d8d4393a6 remove alt text from logo, as this is decorative and provides no value for assistive tech users 2025-05-06 14:37:35 +02:00
Sine Jespersen c4a3a9c616 fix text-contrast from 3.71 to 7.55 on dark mode 2025-05-06 14:37:05 +02:00
Sine Jespersen 8c6f4f6579 change divs to labels, as this is what they semantically are 2025-05-06 14:33:26 +02:00
Sine Jespersen 86ce111edd Add aria-labelledby to icon-button to make assistive tech able to give info on what user can expect from button 2025-05-06 14:30:01 +02:00
Sine Jespersen 0889dd3a51 add close label to close button in changelog modal, only accessible for screen readers 2025-05-06 14:24:19 +02:00
tth37 de182ddec2 fix(katex): Allow Chinese characters adjacent to math delimiters 2025-05-06 18:38:42 +08:00
Panda bfdcc12cdc i18n: zh-cn 2025-05-06 08:30:28 +02:00
Tim Jaeryang Baek ed210517c2 Merge pull request #13533 from TheRauch1/main
feat: handle user OAuth groups as list or string
2025-05-06 09:57:14 +04:00
Tim Jaeryang Baek 7b5247810c Merge pull request #13542 from tuzkiyoung/main
fix: support gpt-image-1 with correct parameter
2025-05-06 09:56:48 +04:00
杨方亮 9cc00afc6b fix: support gpt-image-1 with correct parameter 2025-05-06 10:17:22 +08:00
Bryan Berns 5c055b73a3 Add Custom Azure TTS URL - Formatting 2025-05-05 22:17:18 -04:00
Bryan Berns 853adad894 Add Custom Azure TTS URL - Fix Spaces 2025-05-05 22:12:32 -04:00
Bryan Berns 5aabe21cbe Add Custom Azure TTS URL 2025-05-05 22:08:48 -04:00
Timothy Jaeryang Baek e63b8b3879 refac 2025-05-06 00:46:32 +04:00
Tim Jaeryang Baek 0a8199a056 Merge pull request #13522 from salbahra/bug/fix-missing-api-config
fix: Correct missing `api_config` for embedding Ollama proxy endpoints
2025-05-05 23:49:40 +04:00
Timothy Jaeryang Baek 7b36466c1c refac: audio transcribe supported filetype 2025-05-05 23:42:56 +04:00
Timothy Jaeryang Baek 27da31dc83 fix: tikaloader extract images 2025-05-05 23:40:34 +04:00
therauch1 c36acd46cc enh: handle user OAuth groups as list or string 2025-05-05 21:38:31 +02:00
Tim Jaeryang Baek 413297b5c7 Merge pull request #13532 from Classic298/main
i18n: Update de-DE translation
2025-05-05 23:37:54 +04:00
Classic298 f94965909c Update translation.json 2025-05-05 21:33:45 +02:00
Timothy Jaeryang Baek 982c84c8ac fix: non admin user notes 2025-05-05 23:31:37 +04:00
Timothy Jaeryang Baek 1f45b9df2e fix: notes non admin issue 2025-05-05 23:29:40 +04:00
Tim Jaeryang Baek 3dd2e80dec Merge pull request #13525 from Kylapaallikko/dev
i18n: Update fi-FI translation
2025-05-05 23:28:04 +04:00
Classic298 67a612fe24 Update youtube.py 2025-05-05 20:40:48 +02:00
Classic298 791dd24ace Update youtube.py 2025-05-05 20:08:25 +02:00
Classic298 9cf3381381 Update youtube.py 2025-05-05 20:07:52 +02:00
Classic298 b0d74a59f1 Update youtube.py 2025-05-05 20:07:37 +02:00
Classic298 1a30b3746e Update youtube.py 2025-05-05 20:03:00 +02:00
Classic298 0a3817ed86 Update youtube.py 2025-05-05 20:00:10 +02:00
Classic298 0a845db8ec Update youtube.py 2025-05-05 19:57:21 +02:00
Classic298 7680ac2517 Update youtube.py 2025-05-05 19:57:06 +02:00
Kylapaallikko b3eb3b3c05 Update fi-FI translation.json 2025-05-05 20:21:23 +03:00
Samer Albahra d5e866d839 Fix missing api_config for embedding Ollama proxy endpoints 2025-05-05 12:33:07 -04:00
Timothy Jaeryang Baek db0a0b395f fix: oauth 2025-05-05 19:38:36 +04:00
Tim Jaeryang Baek 23b9354cf6 Merge pull request #12932 from open-webui/dev
0.6.6
2025-05-05 17:58:52 +04:00
Timothy Jaeryang Baek 4fa2e136bf refac: styling 2025-05-05 17:58:40 +04:00
Timothy Jaeryang Baek 512d475ecc refac: api usage 2025-05-05 17:43:51 +04:00
Timothy Jaeryang Baek 56cefde161 doc: changelog 2025-05-05 17:13:09 +04:00
Timothy Jaeryang Baek f78811b253 chore: bump 2025-05-05 16:49:21 +04:00
Timothy Jaeryang Baek e6ca7a414b refac 2025-05-05 16:41:51 +04:00
Tim Jaeryang Baek 367f6fb8f1 Merge pull request #13498 from omahs/main
fix: typos
2025-05-05 16:27:33 +04:00
omahs 37e0313c83 Merge branch 'dev' into main 2025-05-05 14:26:40 +02:00
Timothy Jaeryang Baek 267889809d chore: format 2025-05-05 16:19:05 +04:00
Timothy Jaeryang Baek 33c206c15c enh: include profile image during user import 2025-05-05 16:17:20 +04:00
omahs 863f227be9 fix: typos 2025-05-05 14:14:59 +02:00
Timothy Jaeryang Baek abdde10b74 refac 2025-05-05 16:12:41 +04:00
Timothy Jaeryang Baek 26e9cd0b4b enh: user role update confirm dialog 2025-05-05 16:10:36 +04:00
Timothy Jaeryang Baek 457a0f318a refac 2025-05-05 16:05:39 +04:00
Timothy Jaeryang Baek 3771d27a52 refac 2025-05-05 15:50:09 +04:00
Timothy Jaeryang Baek d16ff54895 refac 2025-05-05 15:46:55 +04:00
Timothy Jaeryang Baek de0f52b686 doc: readme 2025-05-05 15:42:14 +04:00
Timothy Jaeryang Baek eec7a2afa1 refac 2025-05-05 11:25:00 +04:00
Timothy Jaeryang Baek 9e1400f055 enh: generate title 2025-05-05 10:36:01 +04:00
Timothy Jaeryang Baek aa374823ce refac 2025-05-05 10:16:34 +04:00
Timothy Jaeryang Baek a20a920ca4 refac: styling 2025-05-05 09:41:25 +04:00
Timothy Jaeryang Baek 827fd6606c refac 2025-05-05 09:36:34 +04:00
Timothy Jaeryang Baek deb1f6b6d7 feat: ai enhanced notes 2025-05-05 09:22:54 +04:00
Tim Jaeryang Baek 0f1df43bb2 Merge pull request #13485 from TiancongLx/dev
i18n: update zh-TW
2025-05-05 08:25:24 +04:00
Tiancong Li 62a5b14642 i18n: update zh-TW 2025-05-05 10:15:20 +08:00
Timothy Jaeryang Baek 9faf2d9849 refac: styling 2025-05-05 01:51:51 +04:00
Timothy Jaeryang Baek f24d0085c2 refac 2025-05-05 01:45:55 +04:00
Timothy Jaeryang Baek 463ac99e39 enh: note versioning 2025-05-05 01:35:43 +04:00
Timothy Jaeryang Baek e8b23ef0c1 refac 2025-05-05 00:05:06 +04:00
Timothy Jaeryang Baek a6a7ce6b68 enh: import md notes 2025-05-04 23:04:15 +04:00
Timothy Jaeryang Baek 8514669053 refac 2025-05-04 18:59:36 +04:00
Timothy Jaeryang Baek 291834ecbe chore: format 2025-05-04 18:32:56 +04:00
Timothy Jaeryang Baek 360b5b303a enh: note editor 2025-05-04 18:32:21 +04:00
Timothy Jaeryang Baek d8e9b000e3 enh: upload audio 2025-05-04 18:26:33 +04:00
Timothy Jaeryang Baek 62366ad020 refac: audio recording 2025-05-04 18:17:35 +04:00
Timothy Jaeryang Baek 2946f5fcce refac: styling 2025-05-04 17:33:15 +04:00
Timothy Jaeryang Baek f2cf21d64c enh: file item display audio 2025-05-04 17:29:59 +04:00
Timothy Jaeryang Baek 6475ae3b11 refac 2025-05-04 17:23:42 +04:00
Timothy Jaeryang Baek 84a05bec7b enh: notes user group permission 2025-05-04 17:22:51 +04:00
Timothy Jaeryang Baek f716968009 enh: delete notes 2025-05-04 17:01:12 +04:00
Timothy Jaeryang Baek 18149483f2 refac: note pdf export 2025-05-04 16:59:41 +04:00
Timothy Jaeryang Baek 175bbe27e9 refac 2025-05-04 16:53:48 +04:00
Tim Jaeryang Baek d1eaa9d4ee Merge pull request #13478 from SadmL/dev
[i18n] Russian locale update
2025-05-04 02:24:38 -07:00
SadmL 9b133a2245 misspell fix 2025-05-04 12:05:21 +03:00
SadmL 0e51b75654 Russian locale update 2025-05-04 11:59:13 +03:00
Timothy Jaeryang Baek 1cf9843468 refac 2025-05-04 12:02:10 +04:00
Timothy Jaeryang Baek dd42a10aa1 refac 2025-05-04 12:01:20 +04:00
Tim Jaeryang Baek 60c0aa36a2 Merge pull request #13470 from TiancongLx/dev
i18n: update zh-TW
2025-05-04 00:41:02 -07:00
Tiancong Li a7cbfeec9f i18n: update zh-TW 2025-05-04 11:58:20 +08:00
Timothy Jaeryang Baek c5c98591f9 refac 2025-05-04 00:20:30 +04:00
Timothy Jaeryang Baek 59e52add63 chore: bump 2025-05-04 00:15:46 +04:00
Timothy Jaeryang Baek 9c4a931d22 feat: capture display media audio 2025-05-04 00:14:19 +04:00
Timothy Jaeryang Baek 4cfb99248d chore: format 2025-05-03 23:48:24 +04:00
Timothy Jaeryang Baek aefd5d9557 chore: format 2025-05-03 23:48:12 +04:00
Timothy Jaeryang Baek 0f14f34dbe refac 2025-05-03 23:47:41 +04:00
Timothy Jaeryang Baek d74809853d enh: note files 2025-05-03 23:29:19 +04:00
Timothy Jaeryang Baek 23da63b06a refac: styling 2025-05-03 23:08:28 +04:00
Timothy Jaeryang Baek 116b61c53b refac 2025-05-03 23:06:46 +04:00
Timothy Jaeryang Baek f43cb87556 refac 2025-05-03 23:05:25 +04:00
Tim Jaeryang Baek 1af45435eb Merge pull request #13459 from open-webui/notes
feat: notes
2025-05-03 11:54:04 -07:00
Timothy Jaeryang Baek 4acd278624 refac 2025-05-03 22:53:23 +04:00
Timothy Jaeryang Baek 1d82a1c8c4 feat: note editor 2025-05-03 21:18:19 +04:00
Timothy Jaeryang Baek 52d32e8bf2 refac: styling 2025-05-03 21:02:21 +04:00
Timothy Jaeryang Baek a74297ed47 refac: styling 2025-05-03 18:56:27 +04:00
Timothy Jaeryang Baek 7de6112c5b feat: note list ui 2025-05-03 18:52:13 +04:00
Tim Jaeryang Baek bfacab5a0c Merge pull request #13447 from athoik/dev
feat(ocr): add support for Docling OCR engine and language configuration
2025-05-03 07:18:05 -07:00
Tim Jaeryang Baek bbc1ae0942 Merge pull request #13441 from salbahra/bug/fix-prefix-for-embedding-model
fix: Incorrect model reference with Ollama proxy when prefixes are used
2025-05-03 07:17:40 -07:00
Timothy Jaeryang Baek 7fee84c06e feat: notes 2025-05-03 18:16:32 +04:00
Athanasios Oikonomou 437804a2f8 fix: update validation logic for Docling OCR engine and language requirements
Both Docling OCR Engine and Language(s) must be provided or both left empty.
2025-05-03 08:12:58 +03:00
Athanasios Oikonomou 4801430ad2 fix: correct condition for Docling OCR engine and language validation
Both must have value or both must be empty.
2025-05-03 08:02:00 +03:00
Athanasios Oikonomou 657162e96d feat(ocr): add support for Docling OCR engine and language configuration
This commit adds support for configuring the OCR engine and language(s) for Docling.
Configuration can be set via the environment variables `DOCLING_OCR_ENGINE` and `DOCLING_OCR_LANG`, or through the UI.

Fixes #13133
2025-05-03 00:32:06 +03:00
Samer Albahra cafba3eaff Fix model reference with Ollama proxy when prefixes are used 2025-05-02 11:30:59 -04:00
Tim Jaeryang Baek 7d184c3a14 Merge pull request #13085 from ayan4m1/fix/tika-image-ocr
fix: pass extractInlineImages header to Tika if PDF_EXTRACT_IMAGES is true
2025-05-02 03:47:51 -07:00
Timothy Jaeryang Baek 754f631a07 feat: OAUTH_BLOCKED_GROUPS support 2025-05-02 14:47:02 +04:00
Timothy Jaeryang Baek c1ddb00377 refac: styling 2025-05-02 14:19:53 +04:00
Timothy Jaeryang Baek 74f160b849 refac 2025-05-02 14:16:11 +04:00
Tim Jaeryang Baek 11d599c55d Merge pull request #13111 from tth37/perf_multi_thread_web_searching
perf: Concurrent processing for web search queries
2025-05-02 03:15:49 -07:00
Tim Jaeryang Baek 7b014e44ee Merge pull request #13376 from Thaniel94/add-whisper-language-constraint
feat: Added WHISPER_LANGUAGE env variable
2025-05-02 03:08:00 -07:00
Timothy Jaeryang Baek 4a0b2a3afc chore: bump 2025-05-02 14:06:57 +04:00
Tim Jaeryang Baek 2d5643fb17 Merge pull request #13405 from yak1ex/fix_multiple_actions_in_an_action_module_do_not_work_as_intended
fix: Multiple actions in an action module do not work as intended.
2025-05-02 03:06:05 -07:00
Tim Jaeryang Baek d522914774 Merge pull request #13413 from hurxxxx/fix/eslint-version-mismatch
fix: eslint version mismatch
2025-05-02 03:05:30 -07:00
Tim Jaeryang Baek 3013ce2d1a Merge pull request #13415 from TiancongLx/dev
i18n: update zh-TW
2025-05-02 03:04:39 -07:00
Timothy Jaeryang Baek 6d81eef425 refac: reasoning detection 2025-05-02 14:04:12 +04:00
Timothy Jaeryang Baek c258272709 refac 2025-05-02 13:37:41 +04:00
Tim Jaeryang Baek a0981e01a0 Merge pull request #13417 from flefevre/dev-i8n-french
i18n french
2025-05-02 02:28:11 -07:00
hurxxxx 10243b0fac chore: bump @typescript-eslint/eslint-plugin to 8.31.1 2025-05-02 09:44:51 +09:00
nathaniel cc14aacaaa Improvements to parsing of WHISPER_LANGUAGE environment variable (Setting as empty string now equivalent to unsetting/removing WHISPER_LANGUAGE). Resolved crash caused when unset 2025-05-01 22:03:49 +01:00
nathaniel ef7acfbf3d WHISPER_LANGUAGE no longer a "PersistentConfig" variable (Was not appropriate with how WHISPER_LANGUAGE is currently configured). 2025-05-01 21:33:57 +01:00
flefevre fb8a7e8549 Merge branch 'dev' into dev-i8n-french 2025-05-01 20:17:50 +02:00
Francois LE FEVRE 754a3c4cb9 last elements to translate into french 2025-05-01 20:07:56 +02:00
Tiancong Li 725761ad6b i18n: update zh-TW 2025-05-01 22:56:47 +08:00
Francois LE FEVRE 57cb030a24 seconde review on french translation 2025-05-01 15:59:52 +02:00
Francois LE FEVRE 12626107b6 first elements translated in french 2025-05-01 15:46:58 +02:00
hurxxxx 72f985aba7 fix: align eslint plugin and parser versions 2025-05-01 22:39:29 +09:00
Timothy Jaeryang Baek 5d5e351937 feat: notes scaffolding 2025-05-01 16:39:36 +04:00
Tim Jaeryang Baek 2062d3434e Merge pull request #13385 from open-webui/dependabot/npm_and_yarn/dev/typescript-eslint/parser-8.31.1
build(deps-dev): bump @typescript-eslint/parser from 6.21.0 to 8.31.1
2025-05-01 04:59:00 -07:00
Timothy Jaeryang Baek f26cafd984 chore: langchain bump 2025-05-01 15:58:45 +04:00
Tim Jaeryang Baek aca82d64a0 Merge pull request #13391 from open-webui/dependabot/pip/backend/dev/rapidocr-onnxruntime-1.4.4
build(deps): bump rapidocr-onnxruntime from 1.3.24 to 1.4.4 in /backend
2025-05-01 04:56:32 -07:00
Tim Jaeryang Baek 3715919a6b Merge pull request #13389 from open-webui/dependabot/npm_and_yarn/dev/codemirror-lang-hcl-0.1.0
build(deps): bump codemirror-lang-hcl from 0.0.0-beta.2 to 0.1.0
2025-05-01 04:55:52 -07:00
Tim Jaeryang Baek 0e3b9f9da1 Merge pull request #13388 from open-webui/dependabot/npm_and_yarn/dev/prosemirror-schema-list-1.5.1
build(deps): bump prosemirror-schema-list from 1.4.1 to 1.5.1
2025-05-01 04:55:45 -07:00
Tim Jaeryang Baek f10e7ac81b Merge pull request #13387 from open-webui/dependabot/npm_and_yarn/dev/tiptap/core-2.11.9
build(deps): bump @tiptap/core from 2.10.0 to 2.11.9
2025-05-01 04:55:36 -07:00
Tim Jaeryang Baek 61580e9490 Merge pull request #13404 from NoMoreFood/dev
fix: Use SHA256 For Query Result Computation
2025-05-01 04:55:16 -07:00
Tim Jaeryang Baek 6f2d61dc4f Merge pull request #13398 from hurxxxx/i18n-korean
i18n: Update Korean translation.json and parsed messages
2025-05-01 04:48:56 -07:00
Bryan Berns 32257089f9 Use SHA256 For Query Result Computation 2025-05-01 03:56:20 -04:00
Yak! b5cfa2b992 fix: Multiple actions in an action module do not work as intended. 2025-05-01 16:41:06 +09:00
dependabot[bot] c826717343 build(deps): bump @tiptap/core from 2.10.0 to 2.11.9
Bumps [@tiptap/core](https://github.com/ueberdosis/tiptap/tree/HEAD/packages/core) from 2.10.0 to 2.11.9.
- [Release notes](https://github.com/ueberdosis/tiptap/releases)
- [Changelog](https://github.com/ueberdosis/tiptap/blob/@tiptap/core@2.11.9/packages/core/CHANGELOG.md)
- [Commits](https://github.com/ueberdosis/tiptap/commits/@tiptap/core@2.11.9/packages/core)

---
updated-dependencies:
- dependency-name: "@tiptap/core"
  dependency-version: 2.11.9
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-01 05:44:35 +00:00
Tim Jaeryang Baek 35a64b55a1 Merge pull request #13386 from open-webui/dependabot/npm_and_yarn/dev/tiptap/extension-code-block-lowlight-2.11.9
build(deps): bump @tiptap/extension-code-block-lowlight from 2.10.0 to 2.11.9
2025-04-30 22:43:30 -07:00
Tim Jaeryang Baek 9695e08411 Merge pull request #13392 from open-webui/dependabot/pip/backend/dev/pytest-approx-eq-8.3.5
build(deps): update pytest requirement from ~=8.3.2 to ~=8.3.5 in /backend
2025-04-30 22:43:09 -07:00
Tim Jaeryang Baek c6d76acf76 Merge pull request #13393 from open-webui/dependabot/pip/backend/dev/elasticsearch-9.0.1
build(deps): bump elasticsearch from 8.17.1 to 9.0.1 in /backend
2025-04-30 22:42:55 -07:00
Tim Jaeryang Baek b6a76dc026 Merge pull request #13394 from open-webui/dependabot/pip/backend/dev/loguru-0.7.3
build(deps): bump loguru from 0.7.2 to 0.7.3 in /backend
2025-04-30 22:42:45 -07:00
Timothy Jaeryang Baek 079af5fffe fix: send webhook notification when user is not active 2025-05-01 09:41:07 +04:00
Tim Jaeryang Baek e57f2c928a Merge pull request #13379 from NoMoreFood/dev
feat: Azure STT Allow Base URL & Max Speaker Setting
2025-04-30 22:26:18 -07:00
hurxxxx 513d5c8bf5 Fix typos 2025-05-01 13:21:15 +09:00
hurxxxx d72e41c563 Consolidate duplicate messages into a single one 2025-05-01 13:16:47 +09:00
hurxxxx 1ca5d532b8 chore(i18n): update parsed i18n data and Korean translations 2025-05-01 13:00:27 +09:00
hurxxxx f46c7d53b7 update Korean translation 2025-05-01 12:55:07 +09:00
hurxxxx a7cbf62c68 update Korean translation 2025-05-01 12:43:19 +09:00
dependabot[bot] 4eaaeb1888 build(deps): bump loguru from 0.7.2 to 0.7.3 in /backend
Bumps [loguru](https://github.com/Delgan/loguru) from 0.7.2 to 0.7.3.
- [Release notes](https://github.com/Delgan/loguru/releases)
- [Changelog](https://github.com/Delgan/loguru/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/Delgan/loguru/compare/0.7.2...0.7.3)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-01 02:54:59 +00:00
dependabot[bot] 753d530cd0 build(deps): bump elasticsearch from 8.17.1 to 9.0.1 in /backend
Bumps [elasticsearch](https://github.com/elastic/elasticsearch-py) from 8.17.1 to 9.0.1.
- [Release notes](https://github.com/elastic/elasticsearch-py/releases)
- [Commits](https://github.com/elastic/elasticsearch-py/compare/v8.17.1...v9.0.1)

---
updated-dependencies:
- dependency-name: elasticsearch
  dependency-version: 9.0.1
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-01 02:54:56 +00:00
dependabot[bot] 10f55d39d2 build(deps): update pytest requirement in /backend
Updates the requirements on [pytest](https://github.com/pytest-dev/pytest) to permit the latest version.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/8.3.2...8.3.5)

---
updated-dependencies:
- dependency-name: pytest
  dependency-version: 8.3.5
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-01 02:54:52 +00:00
dependabot[bot] 0b84863d76 build(deps): bump rapidocr-onnxruntime from 1.3.24 to 1.4.4 in /backend
Bumps [rapidocr-onnxruntime](https://github.com/RapidAI/RapidOCR) from 1.3.24 to 1.4.4.
- [Release notes](https://github.com/RapidAI/RapidOCR/releases)
- [Commits](https://github.com/RapidAI/RapidOCR/compare/v1.3.24...v1.4.4)

---
updated-dependencies:
- dependency-name: rapidocr-onnxruntime
  dependency-version: 1.4.4
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-01 02:54:49 +00:00
dependabot[bot] efc163fede build(deps): bump codemirror-lang-hcl from 0.0.0-beta.2 to 0.1.0
Bumps codemirror-lang-hcl from 0.0.0-beta.2 to 0.1.0.

---
updated-dependencies:
- dependency-name: codemirror-lang-hcl
  dependency-version: 0.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-01 02:53:31 +00:00
dependabot[bot] dc5107a473 build(deps): bump prosemirror-schema-list from 1.4.1 to 1.5.1
Bumps [prosemirror-schema-list](https://github.com/prosemirror/prosemirror-schema-list) from 1.4.1 to 1.5.1.
- [Changelog](https://github.com/ProseMirror/prosemirror-schema-list/blob/master/CHANGELOG.md)
- [Commits](https://github.com/prosemirror/prosemirror-schema-list/compare/1.4.1...1.5.1)

---
updated-dependencies:
- dependency-name: prosemirror-schema-list
  dependency-version: 1.5.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-01 02:53:26 +00:00
dependabot[bot] c5fd40d951 build(deps): bump @tiptap/extension-code-block-lowlight
Bumps [@tiptap/extension-code-block-lowlight](https://github.com/ueberdosis/tiptap/tree/HEAD/packages/extension-code-block-lowlight) from 2.10.0 to 2.11.9.
- [Release notes](https://github.com/ueberdosis/tiptap/releases)
- [Changelog](https://github.com/ueberdosis/tiptap/blob/@tiptap/extension-code-block-lowlight@2.11.9/packages/extension-code-block-lowlight/CHANGELOG.md)
- [Commits](https://github.com/ueberdosis/tiptap/commits/@tiptap/extension-code-block-lowlight@2.11.9/packages/extension-code-block-lowlight)

---
updated-dependencies:
- dependency-name: "@tiptap/extension-code-block-lowlight"
  dependency-version: 2.11.9
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-01 02:53:05 +00:00
dependabot[bot] 317032aa5c build(deps-dev): bump @typescript-eslint/parser from 6.21.0 to 8.31.1
Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 6.21.0 to 8.31.1.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.31.1/packages/parser)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/parser"
  dependency-version: 8.31.1
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-01 02:52:50 +00:00
Tim Jaeryang Baek f3b38e9777 Merge pull request #13372 from therealmichaelberna/main
**fix** convert_function_to_pydantic_model returning empty descriptions
2025-04-30 13:36:22 -07:00
Tim Jaeryang Baek 336d20fa33 Merge pull request #13364 from NovoNordisk-OpenSource/websocket-behind-auth
refactor: hiding websocket initalization behind authentication
2025-04-30 13:35:27 -07:00
Timothy Jaeryang Baek dadfa5f043 refac: HTML_FILE_ID handling 2025-05-01 00:32:29 +04:00
Timothy Jaeryang Baek e52e45d613 refac: collapsible 2025-04-30 22:26:07 +04:00
Michael Berna 4a6b964a51 Fixed convert_function_to_pydantic_model
convert_function_to_pydantic_model was returning empty function descriptions. I have renamed the variables more precisely which helps to avoid confusion and also resolved this issue which was caused by a variable naming conflict.
2025-04-30 14:22:38 -04:00
Timothy Jaeryang Baek 41904f21e4 refac 2025-04-30 19:41:16 +04:00
Timothy Jaeryang Baek ef2aeb7c0e fix: only allow admin uploaded html to be rendered as html 2025-04-30 19:34:53 +04:00
shcodenick 4c81b6ebc5 hiding websocket initalization behind authentication 2025-04-30 15:05:57 +02:00
Timothy Jaeryang Baek 783d409b1d refac 2025-04-30 16:58:38 +04:00
Timothy Jaeryang Baek c1fa989cb8 refac: styling 2025-04-30 16:54:51 +04:00
Bryan Berns 6c8a9d000e Azure STT Allow Base URL & Max Speaker Setting 2025-04-30 08:51:01 -04:00
Timothy Jaeryang Baek f9d238e850 refac: user list sub-standard code 2025-04-30 16:49:41 +04:00
Tim Jaeryang Baek db06a925fe Merge pull request #13267 from AnapatChaiwongse/dev
feat: implement pagination for /admin/users
2025-04-30 05:04:14 -07:00
Timothy Jaeryang Baek eb68b21e0f refac 2025-04-30 16:01:23 +04:00
Tim Jaeryang Baek e822984162 Merge pull request #13358 from feddersen-group/fix/load_ext_dependencies_on_startup
fix: install external requirements of tools and functions to prevent deactivation
2025-04-30 04:59:56 -07:00
Alexander Grimm e80ed32aeb fix: install external requirements of admin functions and tools on startups 2025-04-30 11:14:38 +00:00
Tim Jaeryang Baek c9d3bb35c3 Merge pull request #13342 from feddersen-group/feat/embedding_dim
feat: allow pgvector to use large embedding models
2025-04-30 02:41:26 -07:00
Alexander Grimm da9966aca1 ~ truncate vectors for pgvector if too big 2025-04-30 05:35:17 +00:00
Tim Jaeryang Baek 4ee5dd58b7 Merge pull request #13177 from tth37/fix_firecrawl_loader_default_mode
fix: FireCrawlLoader default mode to scrape
2025-04-29 08:39:06 -07:00
Tim Jaeryang Baek e87f2669fa Merge pull request #13191 from tth37/feat_firecrawl_search_engine
feat: Add Firecrawl search engine
2025-04-29 08:38:28 -07:00
Tim Jaeryang Baek 390263742c Merge pull request #13273 from spammenotinoz/dev
**FIX** Update Knowledge ReIndexing to continue upon missing\corrupt collections
2025-04-29 08:37:55 -07:00
Tim Jaeryang Baek 8f4be09dd2 Merge pull request #13315 from aleixdorca/dev
i18n: Update Catalan translation.json
2025-04-29 08:35:28 -07:00
Tim Jaeryang Baek 7b863465a9 Merge pull request #13311 from stephen304/yacy-support
feat: Yacy search support
2025-04-29 08:35:10 -07:00
Timothy Jaeryang Baek 6ae2d2c4ea refac: gpt-image-1 support 2025-04-29 19:34:00 +04:00
Timothy Jaeryang Baek addf44b21f refac 2025-04-29 19:27:54 +04:00
D 8f31b6d74a Fix: Use dynamic Python command to run uvicorn and support pyenv setups.
Updated the uvicorn startup command to dynamically detect and use either 'python3' or 'python',
ensuring compatibility across different environments and pyenv setups.
This avoids issues where only one of the commands is available.
2025-04-29 09:14:23 +01:00
Aleix Dorca bc88a9bc8b Update Catalan translation.json 2025-04-29 07:04:16 +02:00
Tim Jaeryang Baek f7f3ae7cc9 Merge pull request #13306 from tarmst/remove-blocking-websocket-awaits
Perf: Chat Websocket Sequential Awaits
2025-04-28 11:17:50 -07:00
Tim Jaeryang Baek 5a1c4dbe1b Merge pull request #13279 from panda44312/patch-14
i18n: zh-cn
2025-04-28 11:17:24 -07:00
Panda 63e4d1ea41 i18n: fix 2025-04-28 18:22:36 +02:00
tth37 cf2d7de873 refac: Implicit asyncio create_task 2025-04-29 00:20:55 +08:00
tarmst c9a9e05bb4 Fix websocket sequential awaits 2025-04-28 15:17:34 +00:00
Timothy Jaeryang Baek 3ac74a4fcb refac: styling 2025-04-28 18:21:48 +04:00
Timothy Jaeryang Baek 63fe426a52 chore: format 2025-04-28 17:46:05 +04:00
Timothy Jaeryang Baek ee8de1ee0b refac: disable jwt display for non-admin users 2025-04-28 17:45:17 +04:00
Timothy Jaeryang Baek 791c19acf7 enh: unicode char support for user import 2025-04-28 17:26:19 +04:00
Tim Jaeryang Baek a9999833d2 Merge pull request #13185 from Chayud-Ac/feature-thai-i18n
fix(i18n): improve Thai translations
2025-04-28 06:16:20 -07:00
Tim Jaeryang Baek c3da9f3026 Merge pull request #13246 from jmtatsch/fix-video-treated-as-text
Fix uploading video files
2025-04-28 06:15:40 -07:00
Tim Jaeryang Baek 2f5abf7374 Merge pull request #13187 from Mister-Hope/patch-1
feat: update default CUDA version to 12.8, close #13186
2025-04-28 06:15:01 -07:00
Tim Jaeryang Baek dedc45183f Merge pull request #13258 from choket/dev
Fix: Fixed a bug that caused user notification webhooks to never be sent
2025-04-28 06:14:24 -07:00
Tim Jaeryang Baek 6d59a5f809 Merge pull request #13253 from noexcs/dev
fix: The value of the 'Access-Control-Allow-Origin' header in the res…
2025-04-28 06:12:53 -07:00
Timothy Jaeryang Baek 10855cf5ed refac 2025-04-28 17:11:28 +04:00
Timothy Jaeryang Baek 9398c843d3 refac 2025-04-28 17:08:07 +04:00
Timothy Jaeryang Baek 45ad6776de fix: token cookie issue 2025-04-28 17:04:13 +04:00
Tim Jaeryang Baek fb1c101dc6 Merge pull request #13269 from jarrod-lowe/s3-tagging
feat: Add tags to S3 uploaded files
2025-04-28 05:57:08 -07:00
Tim Jaeryang Baek a0273aaea8 Merge pull request #13271 from schulti/patch-1
Update de-DE translation.json
2025-04-28 05:56:22 -07:00
Tim Jaeryang Baek 146a08c68f Merge branch 'dev' into patch-1 2025-04-28 05:49:50 -07:00
Timothy Jaeryang Baek 7d0a78a43a refac: aiohttp trust_env=True 2025-04-28 16:47:34 +04:00
Timothy Jaeryang Baek 9bfb4ae838 fix: ollama proxy "format" 2025-04-28 16:45:23 +04:00
Panda ec496de593 i18n: zh-cn 2025-04-28 11:05:06 +02:00
spammenotinoz 12fd7c8cb9 Update knowledge.py
Improve Error Handling ReIndexing Knowledge Database
2025-04-28 16:39:20 +10:00
Stefan Schultheis, OE1SCS d9186e138b Update de-DE translation.json
added a few translations and corrected some typos
2025-04-28 08:21:21 +02:00
Jarrod Lowe 141810039f Add tags to S3 uploaded files 2025-04-28 16:56:56 +12:00
KaeOhhhh 2112067054 Support pagination in /admin/users API
Update Users.svelte

Update index.ts

Update users.py

Update users.py

Update UserList.svelte
2025-04-28 11:29:42 +07:00
root 8a9de0a62f Fix bug that never triggers user notification webhooks 2025-04-27 21:31:34 +02:00
noexcs 4b9b24ae78 fix: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. 2025-04-27 21:29:13 +08:00
jmtatsch 056a042ef2 Update files.py
fix formatting
2025-04-27 11:18:27 +02:00
jmtatsch c51a91583e Dont attempt to infer charset for video files 2025-04-27 10:59:35 +02:00
nathaniel 1efa708f83 Added WHISPER_LANGUAGE env variable. If set to a country's ISO2, constrains Whisper's stt to that language. Detects language as normal if unset 2025-04-27 05:58:06 +01:00
Stephen Smith ea16426a8d Remove unused kwargs in yacy, update comments. 2025-04-27 00:41:46 -04:00
Stephen Smith f9b9217e98 Set Yacy search to text 2025-04-26 23:13:31 -04:00
Stephen Smith e6d43d70f3 Don't request nav and pass count to Yacy 2025-04-26 23:08:16 -04:00
Stephen Smith 240d91d38d Add yacy config for user/pass, automatically add yacy json api path 2025-04-26 22:28:30 -04:00
Stephen Smith 0f73b96616 first pass at yacy support copied from searxng 2025-04-26 14:07:13 -04:00
Timothy Jaeryang Baek 1349bc47b1 fix: chat message input ui styling 2025-04-25 14:21:58 +09:00
tth37 92dbeb1939 feat: Add Firecrawl search engine 2025-04-24 14:57:28 +08:00
Mister-Hope 5f69424215 Update Dockerfile 2025-04-24 13:59:57 +08:00
Chayud 86b9f252c6 fix(i18n): improve Thai translations 2025-04-24 10:35:02 +07:00
Timothy Jaeryang Baek 0b5514f376 refac 2025-04-24 03:16:46 +09:00
Timothy Jaeryang Baek 28ec3069de enh: exp token check 2025-04-24 03:12:22 +09:00
tth37 8f7195ceda fix: FireCrawlLoader default mode to scrape 2025-04-24 01:17:35 +08:00
Tim Jaeryang Baek 91e758f3ec Merge pull request #13165 from feddersen-group/perf/parallel_knowledge_search
perf: all knowledge searches in parallel in non-hybrid mode
2025-04-23 10:01:06 -07:00
Tim Jaeryang Baek d0a1a0f16b Merge pull request #13119 from jarrod-lowe/suggestions
feat: Set default prompt suggestions from environment variable DEFAULT_PROMPT_SUGGESTIONS
2025-04-23 09:55:57 -07:00
Timothy Jaeryang BaekandDrZoidberg09 732d7aee70 enh: sentence transformers env vars
Co-Authored-By: DrZoidberg09 <96449693+drzoidberg09@users.noreply.github.com>
2025-04-24 01:55:18 +09:00
Timothy Jaeryang Baek 3ec6652f99 chore: dep bump 2025-04-24 01:48:07 +09:00
Tim Jaeryang Baek cad9b292bf Merge pull request #13175 from PeterDaveHello/Improve-zh-TW-locale
i18n: improve zh-TW Traditional Chinese locale
2025-04-23 09:41:23 -07:00
Timothy Jaeryang Baek 09874ab83d fix: FireCrawlLoader 2025-04-24 01:40:34 +09:00
Peter Dave Hello c798adb04c i18n: improve zh-TW Traditional Chinese locale 2025-04-24 00:37:15 +08:00
Timothy Jaeryang Baek 7baca2b483 fix: ollama url model download issue 2025-04-24 01:26:19 +09:00
Tim Jaeryang Baek 2b10b378b6 Merge pull request #13170 from TiancongLx/dev
i18n: update zh-TW
2025-04-23 08:22:27 -07:00
Tim Jaeryang Baek 2652b91f5a Merge pull request #13166 from oleguldberg/update-danish-translation
i18n - Add to Danish Translation
2025-04-23 08:22:17 -07:00
Tiancong Li afdba443f4 i18n: update zh-TW 2025-04-23 21:28:46 +08:00
Ole Guldberg ba4f399ace Merge branch 'update-danish-translation' of https://github.com/oleguldberg/open-webui into update-danish-translation 2025-04-23 14:51:01 +02:00
Ole Guldberg 176ff56e85 Merge branch 'update-danish-translation' of https://github.com/oleguldberg/open-webui into update-danish-translation 2025-04-23 12:30:19 +02:00
Ole Guldberg f2765bee72 More Danish Translation
i18n - add to Danish translation. Made agains -dev.
2025-04-23 12:25:32 +02:00
Ole Guldberg 497a7b4ded More Danish Translation
i18n - add to Danish translation. Made agains -dev.
2025-04-23 12:06:17 +02:00
Alexander Grimm d182155fac ~ call knowledge searches in parallel in non-hybrid mode 2025-04-23 09:20:51 +00:00
Timothy Jaeryang Baek 5030041683 chore: format 2025-04-23 16:05:15 +09:00
Tim Jaeryang Baek faa3cac0e4 Merge pull request #13107 from tth37/fix_tavily_max_results
fix: `max_results` in Tavily search handler
2025-04-22 23:47:36 -07:00
Tim Jaeryang Baek d3e516934c Merge pull request #13098 from athoik/dev
feat: Add abstract base class for vector database integration
2025-04-22 23:24:08 -07:00
Timothy Jaeryang Baek 2f7b5acdf8 enh: chat share & export permissions 2025-04-23 14:43:33 +09:00
Tim Jaeryang Baek 7937ed3ee1 Merge pull request #13144 from PeterDaveHello/FixI18nInMultiResponseMessages
i18n: Add missing i18n locale for "Merged Response" string
2025-04-22 20:38:37 -07:00
Tim Jaeryang Baek f0a129482e Merge pull request #13145 from PeterDaveHello/Update-zh-TW-locale
i18n: improve zh-TW Traditional Chinese locale
2025-04-22 20:37:47 -07:00
Ole Guldberg 0e0ee3ca9c More Danish Translation 2025-04-22 21:32:21 +02:00
Ole Guldberg 26a2187e6e More Danish translation 2025-04-22 21:30:05 +02:00
Ole Guldberg 2b4e946f70 More danish 2025-04-22 21:10:51 +02:00
Ole Guldberg 17a9d11435 More dansh 2025-04-22 21:00:36 +02:00
Ole Guldberg a21ac3cc25 More danish 2025-04-22 20:54:33 +02:00
Peter Dave Hello 4eb6985c1b i18n: improve zh-TW Traditional Chinese locale 2025-04-23 02:03:07 +08:00
Peter Dave Hello 5f81755b86 i18n: Add missing i18n locale for "Merged Response" string 2025-04-23 02:01:18 +08:00
Ole Guldberg 4340431753 More danish translation 2025-04-22 18:10:43 +02:00
Timothy Jaeryang Baek f2314596ba enh: failed login attempts audit log 2025-04-23 00:06:44 +09:00
Timothy Jaeryang Baek 43efff0fe6 refac 2025-04-22 23:22:50 +09:00
Ole Guldberg 4e8cd688bf beginning of update 2025-04-22 16:05:13 +02:00
Jarrod Lowe af5efe1580 Set default prompt suggestions from environment variable 2025-04-22 11:39:01 +12:00
tth37 5b9c1de3d1 fix: Translatable 'Searching the web' 2025-04-22 01:24:30 +08:00
tth37 4b451b984b perf: Multi-thread web searching 2025-04-21 22:18:05 +08:00
tth37 bc315bd530 fix: max_results in Tavily search api 2025-04-21 20:59:47 +08:00
Athanasios Oikonomou 1e291aff25 feat: Add abstract base class for vector database integration
- Created `VectorDBBase` as an abstract base class to standardize vector database operations.
- Added required methods for common vector database operations: `has_collection`, `delete_collection`, `insert`, `upsert`, `search`, `query`, `get`, `delete`, `reset`.
- The base class can now be extended by any vector database implementation (e.g., Qdrant, Pinecone) to ensure a consistent API across different database systems.
2025-04-21 08:27:27 +03:00
Tim Jaeryang Baek 913f8a15f9 Merge pull request #13073 from athoik/dev
feat(vector-db): add support for Pinecone client
2025-04-20 14:42:36 -07:00
Tim Jaeryang Baek 7f85436a94 Merge pull request #13089 from izumi0004/fix/tool_calls
fix: handling tool calls in streamed responses
2025-04-20 14:08:09 -07:00
izumi0004 99ce85f20f fix: handling tool calls in streamed responses 2025-04-21 00:29:52 +08:00
ayan4m1 039dec6820 fix: pass header to Tika if PDF_EXTRACT_IMAGES is true 2025-04-20 17:36:40 +02:00
Athanasios Oikonomou e000c56ef7 feat(vector-db): add support for Pinecone client
Adds Pinecone as a supported vector database option.

- Implements `PineconeClient` with support for common operations: `add`, `query`, `delete`, `reset`.
- Emulates namespace support using metadata filtering (`collection_name` prefix).
- Dynamically configures Pinecone via the following env vars:
  - `PINECONE_API_KEY`
  - `PINECONE_ENVIRONMENT`
  - `PINECONE_INDEX_NAME`
  - `PINECONE_DIMENSION`
  - `PINECONE_METRIC`
  - `PINECONE_CLOUD`
- Integrates cleanly with the vector DB abstraction layer.
- Includes markdown documentation under `docs/getting-started/env-configuration.md`.

BREAKING CHANGE: None
2025-04-20 11:08:51 +03:00
Tim Jaeryang Baek af02708b4c Merge pull request #13072 from grandtele/fix/openai_o_series_handler
* fix: Refactor openai handler to support all o-series models universally
2025-04-20 00:42:39 -07:00
grand 5a8e417590 * refactor openai handler to support all o-series models universally 2025-04-20 09:14:27 +02:00
Timothy Jaeryang Baek 1a6e4c2948 refac 2025-04-19 23:40:31 -07:00
Timothy Jaeryang Baek 6fd082d55f enh: html token (allow yt embed) 2025-04-19 23:38:08 -07:00
Timothy Jaeryang Baek f4de3b4c45 enh: notificationSoundAlways option 2025-04-19 23:13:19 -07:00
Tim Jaeryang Baek 8fcad1df4e Merge pull request #13062 from open-webui/cla
chore: cla
2025-04-19 11:33:02 -07:00
Tim Jaeryang Baek 08a35417f2 Merge branch 'dev' into cla 2025-04-19 11:32:49 -07:00
Timothy Jaeryang Baek f7906790e1 refac 2025-04-19 11:32:16 -07:00
Timothy Jaeryang Baek 852d9dcbe9 chore: cla 2025-04-19 11:30:59 -07:00
Timothy Jaeryang Baek 48637893b1 fix: scroll on branch change w/ multi response chat 2025-04-19 04:09:46 -07:00
Timothy Jaeryang Baek 463d7fb628 refac: openapi to tool spec 2025-04-19 03:46:06 -07:00
Timothy Jaeryang Baek 332f8579d7 doc: readme 2025-04-19 02:55:02 -07:00
Timothy Jaeryang Baek ad8c8da438 refac 2025-04-19 02:47:48 -07:00
Timothy Jaeryang Baek f0447b24ab refac: wording 2025-04-19 01:51:40 -07:00
Timothy Jaeryang Baek 63a887151f chore: pr template 2025-04-19 00:47:52 -07:00
Timothy Jaeryang Baek 0aea894e2d Create CONTRIBUTOR_LICENSE_AGREEMENT.md 2025-04-19 00:41:08 -07:00
Timothy Jaeryang Baek 8507c47459 refac: WEBUI_AUTH_SIGNOUT_REDIRECT_URL 2025-04-18 23:58:37 -07:00
Tim Jaeryang Baek 221303eec5 Merge pull request #12592 from jarrod-lowe/main
feat: Redirect on sign out
2025-04-18 23:56:38 -07:00
Tim Jaeryang Baek 87844a8042 Merge pull request #12822 from tth37/feat_external_search_loader
feat: Support for Self-Hosted/External Web Search/Loader Engines
2025-04-18 23:51:27 -07:00
Timothy Jaeryang Baek 1c18282d19 fix 2025-04-18 18:21:49 -07:00
Tim Jaeryang Baek 6101067ea4 Merge pull request #12974 from holmlund/fix/prompts-international
fix: improve international character handling in prompt commands
2025-04-18 18:19:12 -07:00
Tim Jaeryang Baek d2f3c82fd6 Merge pull request #13031 from gaby/anyio-workers
feat: Add support for configuring FastAPI/AnyIO Thread Pool
2025-04-18 17:53:35 -07:00
Tim Jaeryang Baek 27936014b0 Merge pull request #13039 from taylorwilsdon/jit_oauth_groups
feat: Just-in-Time Group Creation for OAuth Groups
2025-04-18 17:53:04 -07:00
Timothy Jaeryang Baek 8b9527d887 refac 2025-04-18 17:14:09 -07:00
Timothy Jaeryang Baek a5476ef7d8 refac 2025-04-18 17:10:44 -07:00
Juan Calderon-Perez 62f87c2e38 Use default AnyIO pool size 2025-04-18 19:21:54 -04:00
Timothy Jaeryang Baek 60d84a3aae chore: license "branding" clause 2025-04-18 14:49:20 -07:00
Tim Jaeryang Baek 3e7bce0921 Merge pull request #13036 from erandow/translate-persian-texts
feat: translate all texts to persian
2025-04-18 12:32:17 -07:00
Taylor Wilsdon 1dbf4d0461 Add ENABLE_OAUTH_GROUP_CREATION flag for JIT group creation with OAuth group updates enabled 2025-04-18 10:17:08 -07:00
Taylor Wilsdon a67e5f725f Merge branch 'dev' of github.com:taylorwilsdon/open-webui into dev 2025-04-18 10:04:42 -07:00
Erfan Asadi 527c5e73dc fix: revert اولاما to ollama after feedback 2025-04-18 18:56:01 +03:30
Erfan Asadi 2ecfd3dbed Merge branch 'dev' of https://github.com/erandow/open-webui into translate-persian-texts 2025-04-18 18:55:14 +03:30
Erfan Asadi 5989b6ca12 Merge branch 'main' of https://github.com/erandow/open-webui into translate-persian-texts 2025-04-18 18:54:35 +03:30
Erfan Asadi e3af831db1 feat: translate the remaining texts in persian 2025-04-18 18:38:06 +03:30
Juan Calderon-Perez f77f6cd1e2 Update imports to match anyio docs 2025-04-18 09:30:34 -04:00
Juan Calderon-Perez e19554e9a8 Simplify import 2025-04-18 09:26:57 -04:00
Juan Calderon-Perez 19b3d88737 Add support for configuring FastAPI/AnyIO Thread Pool Size 2025-04-18 09:22:23 -04:00
Timothy Jaeryang Baek 0d09e46281 refac 2025-04-18 05:32:11 -07:00
Timothy Jaeryang Baek 961869a60c refac 2025-04-18 05:30:50 -07:00
Timothy Jaeryang Baek b8fb4e528d enh: toast close button 2025-04-18 04:33:18 -07:00
Tim Jaeryang Baek 794360addc Merge pull request #12997 from Elmolesto/feat/knowledge-lazy-load-content
feat: Lazy load file content on click
2025-04-18 04:04:29 -07:00
Tim Jaeryang Baek fa8132903e Merge pull request #12904 from hurxxxx/feat/onedrive-orgs
feat: support Organization and School accounts in OneDrive
2025-04-18 04:03:54 -07:00
Timothy Jaeryang Baek a86a932b46 refac: deprecate event dispatcher 2025-04-18 02:38:53 -07:00
Felipe Hernandez 14fa7d16f9 feat: Cache file content 2025-04-18 11:38:15 +02:00
Timothy Jaeryang Baek 64a98b2e0e refac: manifest orientation "any" 2025-04-18 02:24:44 -07:00
Timothy Jaeryang Baek 8f67ffabbd fix: model editor system not being preserved 2025-04-18 02:23:25 -07:00
Timothy Jaeryang Baek a22be555cb refac 2025-04-18 01:26:42 -07:00
Timothy Jaeryang Baek eb80719cf0 feat: AIOHTTP_CLIENT_SESSION_SSL 2025-04-17 22:11:42 -07:00
Tim Jaeryang Baek 840dd9c89a Merge pull request #12971 from tth37/fix_source_indexing
fix: Align backend <source> tag indexing with frontend citation grouping
2025-04-17 22:08:07 -07:00
Tim Jaeryang Baek 30e84adb51 Merge pull request #12883 from Classic298/patch-1
fix: UVICORN_WORKERS __init__.py pass application as string
2025-04-17 22:07:21 -07:00
Tim Jaeryang Baek 414ebc87ee Merge pull request #12894 from Classic298/patch-2
security/fix: prevent email and password changes to the primary admin account
2025-04-17 22:06:54 -07:00
Tim Jaeryang Baek 165eb50c22 Merge pull request #12958 from Youggls/fix_search_web
fix: use run_in_threadpool for search_web to prevent blocking
2025-04-17 22:03:31 -07:00
Tim Jaeryang Baek 477ac7de86 Merge pull request #12968 from alpha-pet/feat-openapi-parameter-description
feat: support OpenAPI parameter description and enum values in tool spec
2025-04-17 22:02:50 -07:00
Timothy Jaeryang Baek 824238a620 enh: AIOHTTP_CLIENT_SESSION_TOOL_SERVER_SSL 2025-04-17 22:02:16 -07:00
Felipe Hernandez 88f97372d9 fix: Show content on upload file 2025-04-18 02:01:47 +02:00
Felipe Hernandez 0577dc2990 feat: Lazy load file content on click 2025-04-18 01:40:30 +02:00
Tim Jaeryang Baek 3b20c57ea8 Merge pull request #12956 from lukasz-pekala/feat/improve-polish-translation
fix: update Polish translations for clarity and consistency
2025-04-17 12:38:14 -07:00
Tim Jaeryang Baek 43b9bf17dc Merge pull request #12966 from damianmr/dev
i18n: Update es-ES (Spanish) translation.json
2025-04-17 12:38:03 -07:00
Tim Jaeryang Baek 246ff83864 Merge pull request #12981 from knight-upstage/dev
i18n: Update ko-KR (Korean) translation.json
2025-04-17 12:37:41 -07:00
knight-upstage cdf26d8189 i18n: Update ko-KR (Korean) translation.json 2025-04-17 09:57:22 -07:00
tth37 79bde6fa47 fix: Align backend <source> tag indexing with frontend citation grouping 2025-04-17 22:27:22 +08:00
Thomas Rehn 3dcbf1acf5 feat: support OpenAPI parameter description and enum values in tool spec 2025-04-17 15:48:55 +02:00
Damian Mendez Romera b1629d8660 i18n: Update es-ES (Spanish) translation.json 2025-04-17 13:58:00 +01:00
David Holmlund 9f8b94e45f fix: improve international character handling in prompt commands 2025-04-17 14:56:57 +02:00
Youggls 9669cd3454 fix: use run_in_threadpool for search_web to prevent blocking
Used fastapi's run_in_threadpool function to execute the search_web function,
preventing the synchronous function from blocking the entire web search process.
2025-04-17 17:23:20 +08:00
Łukasz Pękala c4edcdb12a fix: update Polish translations for clarity and consistency 2025-04-17 10:56:23 +02:00
Timothy Jaeryang Baek a6ccc48d91 refac: textarea component 2025-04-17 00:35:39 -07:00
Tim Jaeryang Baek b6caa95fac Merge pull request #12947 from gaby/qdrant-grpc
feat: Add gRPC support to Qdrant
2025-04-16 23:08:50 -07:00
Juan Calderon-Perez 6188c0c5b7 Add suport for Qdrant GRPC 2025-04-17 01:13:49 -04:00
Jarrod Lowe dfe50b4e56 Merge branch 'open-webui:main' into main 2025-04-17 15:46:24 +12:00
Taylor Wilsdon 54c6e64eec Merge branch 'dev' of github.com:taylorwilsdon/open-webui into dev 2025-04-16 13:01:04 -07:00
Tim Jaeryang Baek 465e879a78 Merge pull request #12917 from rimvel/patch-1
Update translation.json
2025-04-16 08:05:44 -07:00
Tim Jaeryang Baek 93fd5185f9 Merge pull request #12921 from aleixdorca/dev
i18n: Update catalan translation.json
2025-04-16 08:05:14 -07:00
Tim Jaeryang Baek 4ebee592f2 Merge pull request #12925 from JaworIwanowRoosi/main
fix: typos in German translation
2025-04-16 08:05:05 -07:00
JaworIwanowRoosi 6076476a74 fixed: typos in German translation 2025-04-16 14:47:15 +02:00
Aleix Dorca 59918b0f54 Update catalan translation.json 2025-04-16 11:20:03 +02:00
Rimvydas bb1dea72d4 Update translation.json
Fixed typo from "Tęstti" to "Tęsti" (continue).
2025-04-16 09:59:20 +03:00
Tim Jaeryang Baek 264a87f467 Merge pull request #12901 from Kylapaallikko/dev
i18n: Update Finnish Translation
2025-04-15 19:03:52 -07:00
Tim Jaeryang Baek 07347f518a Merge pull request #12896 from gaby/fix-12893
fix: Optional content from files routes
2025-04-15 15:54:29 -07:00
hurxxxx 84f5a52923 chore: clean up unnecessary code 2025-04-16 02:38:20 +09:00
Kylapaallikko 8a50d50038 Update translation.json 2025-04-15 19:44:20 +03:00
hurxxxx 41ef596472 Merge remote-tracking branch 'upstream/main' into feat/onedrive-orgs 2025-04-16 01:41:24 +09:00
Juan Calderon-Perez b4d0d840d1 Fix formatting of qdrant.py 2025-04-15 08:56:51 -04:00
Juan Calderon-Perez b1ef53873f Check if content is present before removing 2025-04-15 08:53:05 -04:00
Classic298 4f14b17c34 Update users.py 2025-04-15 13:50:52 +02:00
Classic298 36b2052fb0 Update __init__.py 2025-04-15 09:55:35 +02:00
Timothy Jaeryang Baek 12c7ecf0f4 refac: styling 2025-04-14 22:34:38 -07:00
Tim Jaeryang Baek e5cbef0baa Merge pull request #12868 from athoik/dev
feat: add QDRANT_ON_DISK configuration option for Qdrant integration
2025-04-14 21:31:46 -07:00
Tim Jaeryang Baek 44e2785495 Merge pull request #12859 from aindriu80/main
i18n: Updated Irish translation
2025-04-14 21:30:21 -07:00
Tim Jaeryang Baek f96c610e21 Merge pull request #12847 from panda44312/patch-13
i18n: zh-cn fix
2025-04-14 21:30:17 -07:00
Taylor Wilsdon 0fc5699533 Merge branch 'dev' of github.com:taylorwilsdon/open-webui into dev 2025-04-14 19:34:12 -04:00
Athanasios Oikonomou 575c12f80c feat: add QDRANT_ON_DISK configuration option for Qdrant integration
This commit will allow configuring the on_disk client parameter, to reduce the memory usage.
https://qdrant.tech/documentation/concepts/storage/?q=mmap#configuring-memmap-storage
Default is false, keeping vectors in memory.
2025-04-15 01:40:57 +03:00
Tim Jaeryang Baek 7e0e6177e9 Merge pull request #12865 from TiancongLx/dev
i18n: update zh-TW
2025-04-14 13:53:24 -07:00
Tiancong Li 0d388b4e54 i18n: update zh-TW 2025-04-15 03:33:30 +08:00
Aindriú Mac Giolla Eoin a3d950872c Updated Irish translations - April 2025-04-14 17:14:02 +01:00
hurxxxx 55d077b52a refactor 2025-04-15 00:35:18 +09:00
hurxxxx 2d7062fc99 fix: onedrive orgs selection 2025-04-15 00:27:59 +09:00
hurxxxx 5fd794612e add onedrive sub menu 2025-04-14 22:57:32 +09:00
Panda 21206bf4b9 i18n: zh-cn fix 2025-04-14 14:26:10 +02:00
tth37 dcb3f18e1e refac: styling 2025-04-14 18:56:47 +08:00
tth37 85f8e91288 feat: Allow admin editing external search/loader settings 2025-04-14 18:19:26 +08:00
tth37 008fec80c1 fix: Update external search/loader method to POST 2025-04-14 18:17:27 +08:00
Tim Jaeryang Baek 07d8460126 Merge pull request #12809 from open-webui/dev
0.6.5
2025-04-14 02:13:21 -07:00
Timothy Jaeryang Baek e4c7417522 refac 2025-04-14 02:12:58 -07:00
Timothy Jaeryang Baek 91523bbb07 chore: bump 2025-04-14 02:08:11 -07:00
Timothy Jaeryang Baek 49bf3207e8 chore: format 2025-04-14 02:00:52 -07:00
Timothy Jaeryang Baek ec730b08c5 chore: format 2025-04-14 02:00:46 -07:00
Timothy Jaeryang Baek 815d18b57e revert 2025-04-14 01:57:23 -07:00
Timothy Jaeryang Baek 8d33b5e063 refac 2025-04-14 01:56:52 -07:00
Timothy Jaeryang BaekandSebastian Whincop aa8db40376 enh: copy formatted option
Co-Authored-By: Sebastian Whincop <123417897+macjedi42@users.noreply.github.com>
2025-04-14 01:56:15 -07:00
Timothy Jaeryang Baek 95fca7b700 refac 2025-04-14 01:41:58 -07:00
Timothy Jaeryang Baek 87aa01a5c2 refac: styling 2025-04-14 01:40:29 -07:00
Timothy Jaeryang Baek d932fc555d enh: tts/stt user permissions 2025-04-14 01:40:22 -07:00
Timothy Jaeryang Baek ec3b8fab5b refac 2025-04-14 01:08:16 -07:00
Timothy Jaeryang Baek 403295600f refac: audio tts voice list 2025-04-14 00:20:51 -07:00
Tim Jaeryang Baek ceffac87b6 Merge pull request #12835 from weisser-dev/dev
Fix: Robust Handling of LDAP Email Attribute Types
2025-04-14 00:15:51 -07:00
Timothy Jaeryang Baek e7332fd6fe refac 2025-04-13 23:39:38 -07:00
Tim Jaeryang Baek 60596c362a Merge pull request #12815 from TomBayne/enh/vad_filter
feat/Enable vad_filter to improve quality of transcription in faster-whisper
2025-04-13 23:27:03 -07:00
Erik c749083935 Update auths.py 2025-04-14 08:12:37 +02:00
Timothy Jaeryang Baek 70718dda90 refac 2025-04-13 22:31:43 -07:00
Timothy Jaeryang Baek 2fcf5d8578 refac 2025-04-13 17:28:09 -07:00
Tim Jaeryang Baek bc2b5d3cc8 Merge pull request #12816 from SadmL/dev
[i18n] Russian locale update
2025-04-13 14:11:16 -07:00
Tim Jaeryang Baek 370f934158 Merge pull request #12819 from athoik/dev
fix: Properly handle ldap3.abstract.attribute.Attribute value
2025-04-13 14:09:56 -07:00
tth37 22f0365cef format 2025-04-14 02:05:58 +08:00
tth37 839ba22c90 feat: Backend for Self-Hosted/External Web Search/Loader Engines 2025-04-14 01:49:05 +08:00
Athanasios Oikonomou c70fedb626 Properly handle ldap3.abstract.attribute.Attribute value
This commit fixes an issue created on commit 2e7a01f30a.

Ldap object is type <class 'ldap3.abstract.attribute.Attribute'>.
So we need to return the value and verify if it's null, string or list.

Fixes #12813
2025-04-13 18:00:42 +03:00
SadmL 08bcfdb8cc [i18n] Russian locale update 2025-04-13 15:37:18 +03:00
Tom 24367d459b Enable vad_filter to improve quality of transcription in faster-whisper model. 2025-04-13 13:03:57 +01:00
Tim Jaeryang Baek 8158609c93 Merge pull request #12810 from tth37/i18n_small_fix
i18n: update zh-CN
2025-04-12 23:15:54 -07:00
tth37 70d9405e64 i18n: update zh-CN 2025-04-13 14:14:34 +08:00
Timothy Jaeryang Baek aaefba2777 chore: bump 2025-04-12 23:06:40 -07:00
Tim Jaeryang Baek aca37f592d Merge pull request #12807 from open-webui/dev
0.6.4
2025-04-12 23:01:19 -07:00
Timothy Jaeryang Baek 888b468576 fix 2025-04-12 23:00:34 -07:00
Timothy Jaeryang Baek 9348c05f1a doc: changelog 2025-04-12 22:57:13 -07:00
Timothy Jaeryang Baek 4dafbbccfc fix: rag template display issue 2025-04-12 22:55:24 -07:00
Tim Jaeryang Baek 8b0e565e2c Merge pull request #12715 from open-webui/dev
0.6.3
2025-04-12 22:44:24 -07:00
Timothy Jaeryang Baek 2766d7df6a doc: changelog 2025-04-12 22:44:00 -07:00
Tim Jaeryang Baek 8e810e758d Merge pull request #12806 from tth37/fix_web_rag_settings
fix: Resolve small bugs on updated web/rag settings
2025-04-12 22:26:04 -07:00
Timothy Jaeryang Baek e7821288f5 doc: changelog 2025-04-12 22:25:02 -07:00
tth37 db9d4ead59 format 2025-04-13 13:10:39 +08:00
Timothy Jaeryang Baek 1a6eaf6445 chore: dependency bump 2025-04-12 22:07:23 -07:00
tth37 8d53f1e770 fix: small bugs on updated web/rag settings 2025-04-13 12:55:50 +08:00
Timothy Jaeryang Baek c1444cbbba refac 2025-04-12 21:47:46 -07:00
Timothy Jaeryang Baek 40f9747ae4 refac 2025-04-12 21:44:47 -07:00
Timothy Jaeryang Baek ac8e81834c refac 2025-04-12 21:44:15 -07:00
Timothy Jaeryang Baek 8d62cc1935 refac 2025-04-12 21:09:26 -07:00
Timothy Jaeryang Baek f3fe82da80 fix: ongoing chat stop issue 2025-04-12 20:51:02 -07:00
Timothy Jaeryang Baek fa61065c1e refac 2025-04-12 20:15:00 -07:00
Timothy Jaeryang Baek 5844779384 refac: styling 2025-04-12 20:14:32 -07:00
Timothy Jaeryang Baek 451465151e refac 2025-04-12 19:31:02 -07:00
Tim Jaeryang Baek 85ef912f6a Merge pull request #12794 from TiancongLx/dev
i18n: update zh-TW
2025-04-12 19:27:26 -07:00
Tiancong Li 2b8cd4dff4 i18n: update zh-TW 2025-04-13 10:00:58 +08:00
Timothy Jaeryang Baek f6c8184a74 fix: model hide issue 2025-04-12 18:49:49 -07:00
Timothy Jaeryang Baek bde89fd29e refac: audio 2025-04-12 18:40:09 -07:00
Timothy Jaeryang Baek daabc188e8 fix: model list hide issue 2025-04-12 18:34:10 -07:00
Timothy Jaeryang Baek d5ee39de21 fix: katex display overflow issue 2025-04-12 18:27:23 -07:00
Timothy Jaeryang Baek cdb4904999 refac 2025-04-12 18:11:22 -07:00
Tim Jaeryang Baek 577406e00b Merge pull request #12788 from TiancongLx/dev
i18n: update zh-TW
2025-04-12 17:58:01 -07:00
Timothy Jaeryang Baek 175919c787 enh: widescreen mode in shared chats 2025-04-12 17:53:23 -07:00
Tiancong Li 03e2e5279f i18n: update zh-TW 2025-04-13 08:50:22 +08:00
Timothy Jaeryang Baek 4ca6247496 chore: format 2025-04-12 17:45:33 -07:00
Timothy Jaeryang Baek 40a3e7786b refac: voice recording 2025-04-12 17:41:53 -07:00
Timothy Jaeryang Baek 79dff685ea feat: multiple models chat user permissions 2025-04-12 17:37:30 -07:00
Timothy Jaeryang Baek 881d81d87f refac: default tool calling behaviour 2025-04-12 17:26:35 -07:00
Timothy Jaeryang Baek db8780fd9c refac: default tool boilerplate 2025-04-12 17:16:27 -07:00
Timothy Jaeryang Baek 0a69db291d enh: iframe sandbox policy setting 2025-04-12 17:09:39 -07:00
Timothy Jaeryang Baek af0d99b2a3 refac: artifacts styling 2025-04-12 17:01:45 -07:00
Tim Jaeryang Baek 540c27c589 Merge pull request #12784 from rgaricano/dev
UPD: Spanish Translation (es-ES)  Rev.0.6.3
2025-04-12 16:51:47 -07:00
_00_ 4106681889 UPD: Spanish Translation (es-ES) Rev.0.6.3
Revision of Spanish Translation (es-ES)
Adapted to Open-WebUI v.0.6.3

Has been done

Revision & Complete.
2025-04-13 01:42:28 +02:00
Timothy Jaeryang Baek 91a455a284 chore: format 2025-04-12 16:35:11 -07:00
Timothy Jaeryang Baek 77b25ae36a refac 2025-04-12 16:34:20 -07:00
Timothy Jaeryang Baek 48a23ce3fe refac: web/rag config 2025-04-12 16:33:36 -07:00
Timothy Jaeryang Baek c3497da5dd enh: only copy text message content 2025-04-12 15:11:03 -07:00
Timothy Jaeryang Baek bdef1001ac refac 2025-04-12 15:10:43 -07:00
Tim Jaeryang Baek 6862d8fba8 Merge pull request #12769 from tth37/feat_frontend_web_loader
feat: Add Frontend Configuration for `RAG_WEB_LOADER_ENGINE`
2025-04-12 14:56:47 -07:00
Tim Jaeryang Baek 02ba7aeb95 Merge pull request #12366 from Ithanil/redis_sentinel_2
chore: adapt websocket redis sentinel code to new native support in python-socketio
2025-04-12 11:41:30 -07:00
Jan Kessler c6755f9151 bump python-socketio to 5.13.0 (to support Redis Sentinel natively) 2025-04-12 19:22:10 +02:00
tth37 5eac5960ef feat: Add frontend configuration for web loader 2025-04-12 17:13:30 +08:00
Timothy Jaeryang Baek 30d02c638c refac: banners 2025-04-11 15:34:21 -07:00
Timothy Jaeryang Baek c5636ff68c refac 2025-04-11 15:27:25 -07:00
Timothy Jaeryang Baek c846a550fa refac 2025-04-11 15:19:47 -07:00
Timothy Jaeryang Baek 59dd798156 refac/security: set ac to private by default 2025-04-11 14:46:02 -07:00
Jarrod Lowe a8bbaa61bd Merge branch 'dev' into main 2025-04-11 22:14:41 +12:00
Timothy Jaeryang Baek 5fea0a2221 refac: styling 2025-04-10 21:52:03 -07:00
Timothy Jaeryang Baek 6d63337ee9 refac 2025-04-10 21:22:14 -07:00
Timothy Jaeryang Baek b97ea72616 refac: tool call result display 2025-04-10 20:06:00 -07:00
Timothy Jaeryang Baekanddulicon 1921420319 refac
Co-Authored-By: dulicon <57261058+dulicon@users.noreply.github.com>
2025-04-10 20:01:07 -07:00
Timothy Jaeryang Baek a47a958edd refac: rename functions 2025-04-10 19:43:26 -07:00
Timothy Jaeryang Baek 53df5d3946 refac: rename hard to understand cryptic function names 2025-04-10 19:41:17 -07:00
Timothy Jaeryang Baek 0f27968ceb fix: tool server session auth 2025-04-10 17:47:07 -07:00
Tim Jaeryang Baek 36ac81b229 Merge pull request #12727 from decent-engineer-decent-datascientist/main
feat: add Azure AI Speech STT provider
2025-04-10 16:50:40 -07:00
priten 9a55257c5b feat: add Azure AI Speech STT provider
- Add Azure STT configuration variables for API key, region and locales
- Implement Azure STT transcription endpoint with 200MB file size limit
- Update Audio settings UI to include Azure STT configuration fields
- Handle Azure API responses and error cases consistently
2025-04-10 15:38:59 -05:00
Timothy Jaeryang Baek 05aa9c6d9c refac 2025-04-10 12:27:11 -07:00
Tim Jaeryang Baek f0efee5de4 Merge pull request #12603 from alpha-pet/fix-convert-ogg-container-openai-transcription
fix: Convert ogg to wav for OpenAI transcription endpoint
2025-04-10 12:25:46 -07:00
Timothy Jaeryang Baek bf0716e85e refac: styling 2025-04-10 12:05:01 -07:00
Timothy Jaeryang Baek f9bd49bf56 refac 2025-04-10 11:18:53 -07:00
Tim Jaeryang Baek 4cbf16c456 Merge pull request #12717 from Kheiden/progressive-webapp-enhancements
feat: Add PWA external manifest URL env var
2025-04-10 10:55:54 -07:00
Timothy Jaeryang BaekandRobert Piosik 1eba6a812e enh: smaller code text size
Co-Authored-By: Robert Piosik <robertpiosik@gmail.com>
2025-04-10 10:50:46 -07:00
Timothy Jaeryang Baek 3f71929a69 refac: styling 2025-04-10 10:46:44 -07:00
Timothy Jaeryang Baek d8780e4de2 feat: detect artifacts toggle 2025-04-10 10:36:57 -07:00
Kurt Heiden c12f8d28b9 Add PWA external manifest URL env var 2025-04-10 11:35:43 -06:00
Timothy Jaeryang Baek d4297a3e3e refac: styling 2025-04-10 10:31:38 -07:00
Timothy Jaeryang Baek fb0ee1329d enh: tool server data timeout 2025-04-10 10:23:14 -07:00
Timothy Jaeryang Baek 23dcae7054 refac: selector 2025-04-10 10:18:56 -07:00
Tim Jaeryang Baek 7aab8b9307 Merge pull request #12567 from aleprj/fix/ms-sso
fix: Make Microsoft SSO work even when custom signing keys. #12475
2025-04-10 10:11:49 -07:00
Timothy Jaeryang BaekandAnthony Durussel f10566f3de feat: allow events from pipelines
Co-Authored-By: Anthony Durussel <87324020+anthonydurussel@users.noreply.github.com>
2025-04-10 09:20:18 -07:00
Timothy Jaeryang Baek 0611eb8ac7 refac: layout load 2025-04-10 09:15:08 -07:00
Tim Jaeryang Baek a3e477e100 Merge pull request #12602 from alpha-pet/fix-tool-server-indexing-mismatch
fix: mismatch between TOOL_SERVERS / TOOL_SERVER_CONNECTIONS indexing
2025-04-10 09:06:30 -07:00
Tim Jaeryang Baek b40b50fb2d Merge pull request #12563 from IONOS-Productivity/oidc-add-support-for-pkce
OIDC add support for PKCE
2025-04-10 09:03:31 -07:00
Tim Jaeryang Baek e065073bea Merge pull request #12689 from asncx/fix-folder-chat-rename
fix: Chat rename not updating inside folders
2025-04-10 08:51:22 -07:00
Tim Jaeryang Baek 33b35b797c Merge pull request #12594 from gaby/search-files
feat: Add support for searching files by name
2025-04-10 08:50:13 -07:00
Tim Jaeryang Baek ef14d0b46d Merge pull request #12562 from almajo/fix/agrimm/correct_knowledge_base_citations
fix: Correct Citations for knowledge base models
2025-04-10 08:48:47 -07:00
Tim Jaeryang Baek 62ef0bad6f Merge pull request #12680 from lucyknada/patch-1
fix #12678
2025-04-10 08:46:41 -07:00
Timothy Jaeryang Baek 63e5200e2f refac 2025-04-10 08:46:12 -07:00
Tim Jaeryang Baek 1865e29bfc Merge pull request #12683 from Youggls/dev
feat: Add sougou web search engine.
2025-04-10 08:45:15 -07:00
Tim Jaeryang Baek f7dc6474ee Merge pull request #12694 from SadmL/dev
[i18n] Russian locale misspelling fix
2025-04-10 08:43:51 -07:00
Timothy Jaeryang Baek 536bc36e36 chore: bump duckduckgo 2025-04-10 08:42:03 -07:00
Taylor Wilsdon 708fcdc6b7 Merge branch 'dev' of github.com:taylorwilsdon/open-webui into dev 2025-04-10 06:32:17 -04:00
SadmL de926a060d [i18n] Russian locale misspelling fix 2025-04-10 13:17:52 +03:00
Thomas Rehn 4731e0d0e3 fix: convert webm to wav for OpenAI transcription endpoint 2025-04-10 09:00:51 +02:00
Youggls 3e2a6df1fb feat: Add sougou web search API for backend, add config panel in for frontend. 2025-04-10 14:51:44 +08:00
lucy bc295546cd fix #12678 2025-04-10 07:23:34 +02:00
Tim Jaeryang Baek 6c9a4d6ce6 Merge pull request #12606 from alpha-pet/feat-openapi-yaml-support
Feat: openapi yaml support
2025-04-09 18:37:09 -07:00
Tim Jaeryang Baek e27c5989bc Merge pull request #12657 from noamtamim/patch-1
docs: Set FastAPI app title to "Open WebUI"
2025-04-09 18:32:26 -07:00
Tim Jaeryang Baek 5f116d69c2 Merge pull request #12664 from Beni34/main
Updated Hungarian language to full. translation.json
2025-04-09 16:43:08 -07:00
Tim Jaeryang Baek a27dcc84a3 Merge pull request #12654 from valckmir/main
feat: disable persistent config
2025-04-09 16:16:14 -07:00
Beni34 7cee0073cf Update translation.json 2025-04-09 21:40:23 +02:00
Miroslav Valcicak a5faaf388e refactor: rename persistent config variable 2025-04-09 21:22:25 +02:00
asncx 87af2692e5 fix: folder chat rename 2025-04-09 20:56:49 +02:00
Noam Tamim 15fd822916 Set FastAPI title to Open WebUI
This affects the generated OpenAPI (`/docs` and `/openapi.json`).
2025-04-09 19:45:17 +03:00
Miroslav Valcicak 68aea6bf10 feat: disable persistent config 2025-04-09 16:18:58 +02:00
Tim Jaeryang Baek 38d5b03685 Merge pull request #12647 from behrmann/multimail
fix: choose the first mail if multiple are returned from LDAP
2025-04-09 03:47:49 -07:00
Jörg Behrmann 2e7a01f30a fix: choose the first mail if multiple are returned from LDAP 2025-04-09 10:53:02 +02:00
Tim Jaeryang Baek a363c0619a Merge pull request #12638 from panda44312/patch-12
i18n: zh-cn
2025-04-09 01:45:41 -07:00
Tim Jaeryang Baek f49d3d09f5 Merge pull request #12637 from TiancongLx/dev
i18n: update zh-TW
2025-04-09 01:45:31 -07:00
Thomas Rehn 17ea20d3ad feat: OpenAPI YAML support for frontend toolserver 2025-04-09 09:46:44 +02:00
Panda 92611b588c i18n: zh-cn 2025-04-09 09:44:10 +02:00
Tiancong Li de1e9f3c0f i18n: update zh-TW 2025-04-09 15:25:37 +08:00
Tim Jaeryang Baek d8c0a1227a Merge pull request #12552 from tth37/dev
i18n: update zh-CN
2025-04-08 22:17:57 -07:00
Tim Jaeryang Baek 84ea9ea011 Merge pull request #12555 from SadmL/dev
[i18n] Russian locale update
2025-04-08 22:17:50 -07:00
Tim Jaeryang Baek b130b55f5b Merge pull request #12571 from hurxxxx/feat/reindex-knowledge-files
feat: reindex knowledge files
2025-04-08 22:10:35 -07:00
Tim Jaeryang Baek 2ff1657a7a Merge pull request #12573 from gem85247/dev
fix: manifest.json cross-origin issues
2025-04-08 22:07:43 -07:00
Tim Jaeryang Baek 2575dac4ed Merge pull request #12604 from maurerle/ddg_improve_stacktrace
**fix** improve stack trace of duckduckgo exception
2025-04-08 13:03:57 -07:00
Tim Jaeryang Baek 8c3146f6f8 Merge pull request #12615 from robert-norberg/additional-RAG-logging
chore: Add debug logging to RAG utils
2025-04-08 13:03:38 -07:00
Tim Jaeryang Baek 1f12023d85 Merge pull request #12617 from Classic298/dev
feat: UVICORN_WORKERS variable and docs
2025-04-08 12:52:47 -07:00
Timothy Jaeryang Baek 63eab42208 refac 2025-04-08 12:51:48 -07:00
Timothy Jaeryang Baek 60d11c1f6f enh: password max length verification 2025-04-08 12:50:25 -07:00
DrMelone f17befc853 Update __init__.py 2025-04-08 18:55:07 +02:00
DrMelone 65b5c6c0c7 Update start_windows.bat 2025-04-08 18:52:12 +02:00
DrMelone 2c1d0e3857 Update start.sh 2025-04-08 18:50:07 +02:00
DrMelone 4c9a791b06 Update env.py 2025-04-08 18:47:48 +02:00
DrMelone f822d89350 Update env.py 2025-04-08 18:38:00 +02:00
Robert Norberg 2337b36609 add debug logging to RAG utils 2025-04-08 12:08:32 -04:00
Thomas Rehn 81af20aa9b refac: use logging instead of print 2025-04-08 15:16:55 +02:00
Thomas Rehn 27e8c6fce4 feat: add support for OpenAPI spec in YAML format 2025-04-08 15:16:52 +02:00
Thomas Rehn d99a883867 fix: convert ogg to wav for OpenAI transcription endpoint 2025-04-08 15:04:04 +02:00
Thomas Rehn f5b2867e45 fix: mismatch between TOOL_SERVERS / TOOL_SERVER_CONNECTIONS indexing 2025-04-08 14:08:08 +02:00
Florian Maurer 760ea3f4af duckduckgo: backend api has been deprecated since december
also increase duckduckgo-search version

see https://github.com/deedy5/duckduckgo_search/commit/3ee8e08b1c8efc9b7356f406db299f1114dc4860
2025-04-08 14:02:06 +02:00
Florian Maurer 337c7caafa improve stack trace of duckduckgo exception
* fix search_results out of scope
* ddgs.text does already always return a list
2025-04-08 13:52:23 +02:00
Haodong Tian d50ca0aa43 Update zh-CN translation.json 2025-04-08 15:49:20 +08:00
Haodong Tian 399e7b1670 Update zh-CN translation.json 2025-04-08 15:47:24 +08:00
Haodong Tian e92d3073bb Update zh-CN translation.json
- Minor fix
2025-04-08 15:37:50 +08:00
Haodong Tian 00f58658f7 i18n: Apply i18n to Web Search proxy tooltips 2025-04-08 07:01:56 +00:00
Haodong Tian b15adc63fe Update zh-CN translation.json
- Standardize Chinese translations for "autocomplete"
2025-04-08 14:24:39 +08:00
Juan Calderon-Perez fed47f2e2b Add content param to /search route 2025-04-08 01:00:06 -04:00
Juan Calderon-Perez 1c60b8d543 Rewrite logic 2025-04-08 00:56:21 -04:00
Juan Calderon-Perez 8609ca3657 Fix formatting again 2025-04-08 00:49:55 -04:00
Juan Calderon-Perez e06ff17a70 Fix formatting 2025-04-08 00:48:54 -04:00
Juan Calderon-Perez 7c1b004687 simplify logic 2025-04-08 00:44:47 -04:00
Juan Calderon-Perez 353b104c77 add support for searching files 2025-04-08 00:42:37 -04:00
Jarrod Lowe b4465987f9 Environment variable to redirect on logout 2025-04-08 13:39:00 +12:00
Tim Jaeryang Baek 66322727e3 Merge pull request #12580 from lainedfles/opentelemetry-requirements-fix
fix: Upgrade OpenTelemetry instrumentation packages to 0.52b1
2025-04-07 14:19:17 -07:00
Self Denial 0e71b96597 fix: Upgrade OpenTelemetry instrumentation packages to 0.52b1
This commit updates all OpenTelemetry instrumentation dependencies (FastAPI, SQLAlchemy, Redis, Requests, Logging, HTTPX, aiohttp-client) from version 0.52b0 to 0.52b1 to satisfy opentelemetry-sdk==1.31.1 dependencies.
2025-04-07 14:49:47 -06:00
Gilles M f3f45209e9 fix: manifest.json cross-origin
When utilizing Cloudflare Zero Trust, fetching the manifest.json file may encounter issues because the request is redirected through the Zero Trust authentication page.
2025-04-07 19:01:18 +02:00
hurxxxx e7715f3760 i18n: add reindex knowledge files dialog 2025-04-08 01:37:50 +09:00
hurxxxx 7c828015d3 fix: ReindexKnowledgeFilesConfirmDialog 2025-04-08 00:53:11 +09:00
hurxxxx 4e545d432b feat: add new admin func - reindex knowledge files 2025-04-08 00:44:10 +09:00
Taylor Wilsdon 66bf6d88bc Merge branch 'dev' of github.com:taylorwilsdon/open-webui into dev 2025-04-07 10:17:57 -04:00
aleprj e8f02328f4 Merge branch 'open-webui:main' into fix/ms-sso 2025-04-07 11:16:21 -03:00
aleprj 818d24e672 fix: add appid to the URL to ensure we fetch the correct parameters in all scenarios 2025-04-07 11:15:47 -03:00
Alexander Grimm 1e7a36478b ~ update to latest change 2025-04-07 15:16:47 +02:00
Alexander Grimm d8a7e9c660 fix: correct document citation 2025-04-07 15:16:47 +02:00
Thomas Lehmann 5c658a4879 feat(config): add config OAUTH_CODE_CHALLENGE_METHOD
Add support to enable OIDC code challenge method (PKCE).
2025-04-07 14:03:52 +02:00
SadmL b81789190e [i18n] Russian locale update 2025-04-07 12:04:58 +03:00
Haodong Tian f172403049 Update zh-CN translation.json 2025-04-07 16:11:54 +08:00
Timothy Jaeryang Baek 9cb1104f09 refac 2025-04-07 00:58:32 -07:00
Timothy Jaeryang Baek d1a77a9110 Merge pull request #12549 from ulagbulag/fix/500-when-unknown-models
fix: internal server error when calling completions API with non-existent model names
2025-04-07 00:58:02 -07:00
Ho Kim 1efae95a36 fix: internal server error when calling completions API with non-existent model names
Signed-off-by: Ho Kim <ho.kim@ulagbulag.io>
2025-04-07 06:48:39 +00:00
Timothy Jaeryang Baek 54a74b2c0a chore: bump 2025-04-06 23:46:59 -07:00
Timothy Jaeryang Baek 908492702a chore: bump 2025-04-06 23:46:40 -07:00
Timothy Jaeryang Baek 5553ec3e51 Merge pull request #12537 from open-webui/dependabot/npm_and_yarn/dev/tiptap/pm-2.11.7
build(deps): bump @tiptap/pm from 2.10.0 to 2.11.7
2025-04-06 23:45:59 -07:00
Timothy Jaeryang Baek ddec6cf0fa Merge pull request #12545 from mogorman/elixir_syntax_highlighting
feat: add Elixir highlighting
2025-04-06 23:45:30 -07:00
Timothy Jaeryang Baek 1857f152c2 Merge pull request #12548 from aleixdorca/dev
i18n: Update Catalan translation.json
2025-04-06 23:45:07 -07:00
Timothy Jaeryang Baek c5deb5cda4 Merge pull request #12541 from open-webui/dependabot/uv/dev/opentelemetry-instrumentation-logging-0.52b0
build(deps): bump opentelemetry-instrumentation-logging from 0.51b0 to 0.52b0
2025-04-06 23:43:48 -07:00
Timothy Jaeryang Baek d3ed20e907 Merge pull request #12535 from open-webui/dependabot/pip/backend/dev/youtube-transcript-api-1.0.3
build(deps): bump youtube-transcript-api from 0.6.3 to 1.0.3 in /backend
2025-04-06 23:43:35 -07:00
Timothy Jaeryang Baek 82252cb760 Merge pull request #12532 from open-webui/dependabot/pip/backend/dev/chromadb-0.6.3
build(deps): bump chromadb from 0.6.2 to 0.6.3 in /backend
2025-04-06 23:43:08 -07:00
Timothy Jaeryang Baek 9e700dc9a2 Merge pull request #12533 from open-webui/dependabot/pip/backend/dev/pgvector-0.4.0
build(deps): bump pgvector from 0.3.5 to 0.4.0 in /backend
2025-04-06 23:42:30 -07:00
Timothy Jaeryang Baek e1f60feb7f Merge pull request #12529 from open-webui/dependabot/pip/backend/dev/azure-identity-1.21.0
build(deps): bump azure-identity from 1.20.0 to 1.21.0 in /backend
2025-04-06 23:41:53 -07:00
Timothy Jaeryang Baek aefb3117db fix: chat completion non-existent model issue 2025-04-06 23:40:48 -07:00
Aleix Dorca 76d8935d0b Update catalan translation.json 2025-04-07 08:31:44 +02:00
dependabot[bot] dbc06084a7 build(deps): bump opentelemetry-instrumentation-logging
Bumps [opentelemetry-instrumentation-logging](https://github.com/open-telemetry/opentelemetry-python-contrib) from 0.51b0 to 0.52b0.
- [Release notes](https://github.com/open-telemetry/opentelemetry-python-contrib/releases)
- [Changelog](https://github.com/open-telemetry/opentelemetry-python-contrib/blob/main/CHANGELOG.md)
- [Commits](https://github.com/open-telemetry/opentelemetry-python-contrib/commits)

---
updated-dependencies:
- dependency-name: opentelemetry-instrumentation-logging
  dependency-version: 0.52b0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-07 03:43:31 +00:00
Matthew O'Gorman 8a81f5f188 add support for elixir code syntax highlighting 2025-04-06 23:42:53 -04:00
dependabot[bot] ba66995532 build(deps): bump @tiptap/pm from 2.10.0 to 2.11.7
Bumps [@tiptap/pm](https://github.com/ueberdosis/tiptap/tree/HEAD/packages/pm) from 2.10.0 to 2.11.7.
- [Release notes](https://github.com/ueberdosis/tiptap/releases)
- [Changelog](https://github.com/ueberdosis/tiptap/blob/@tiptap/pm@2.11.7/packages/pm/CHANGELOG.md)
- [Commits](https://github.com/ueberdosis/tiptap/commits/@tiptap/pm@2.11.7/packages/pm)

---
updated-dependencies:
- dependency-name: "@tiptap/pm"
  dependency-version: 2.11.7
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-07 03:42:44 +00:00
dependabot[bot] 96ecdc37b3 build(deps): bump youtube-transcript-api from 0.6.3 to 1.0.3 in /backend
Bumps [youtube-transcript-api](https://github.com/jdepoix/youtube-transcript-api) from 0.6.3 to 1.0.3.
- [Release notes](https://github.com/jdepoix/youtube-transcript-api/releases)
- [Commits](https://github.com/jdepoix/youtube-transcript-api/compare/v0.6.3...v1.0.3)

---
updated-dependencies:
- dependency-name: youtube-transcript-api
  dependency-version: 1.0.3
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-07 03:42:21 +00:00
dependabot[bot] f187a1c9ef build(deps): bump pgvector from 0.3.5 to 0.4.0 in /backend
Bumps [pgvector](https://github.com/pgvector/pgvector-python) from 0.3.5 to 0.4.0.
- [Changelog](https://github.com/pgvector/pgvector-python/blob/master/CHANGELOG.md)
- [Commits](https://github.com/pgvector/pgvector-python/compare/v0.3.5...v0.4.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-07 03:42:17 +00:00
dependabot[bot] 9e8b7ac611 build(deps): bump chromadb from 0.6.2 to 0.6.3 in /backend
Bumps [chromadb](https://github.com/chroma-core/chroma) from 0.6.2 to 0.6.3.
- [Release notes](https://github.com/chroma-core/chroma/releases)
- [Changelog](https://github.com/chroma-core/chroma/blob/main/RELEASE_PROCESS.md)
- [Commits](https://github.com/chroma-core/chroma/compare/0.6.2...0.6.3)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-07 03:42:14 +00:00
dependabot[bot] 5379c08b9d build(deps): bump azure-identity from 1.20.0 to 1.21.0 in /backend
Bumps [azure-identity](https://github.com/Azure/azure-sdk-for-python) from 1.20.0 to 1.21.0.
- [Release notes](https://github.com/Azure/azure-sdk-for-python/releases)
- [Changelog](https://github.com/Azure/azure-sdk-for-python/blob/main/doc/esrp_release.md)
- [Commits](https://github.com/Azure/azure-sdk-for-python/compare/azure-identity_1.20.0...azure-identity_1.21.0)

---
updated-dependencies:
- dependency-name: azure-identity
  dependency-version: 1.21.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-07 03:42:11 +00:00
Timothy Jaeryang Baek 63533c9e3a Merge pull request #12524 from open-webui/dev
0.6.2
2025-04-06 20:41:10 -07:00
Timothy Jaeryang Baek 8e8bc3125e doc: changelog 2025-04-06 20:41:03 -07:00
Timothy Jaeryang Baek 2c083f58d9 chore: format 2025-04-06 20:36:24 -07:00
Timothy Jaeryang Baek 93962f01cc doc: changelog 2025-04-06 20:34:47 -07:00
Timothy Jaeryang Baek 40d019ff50 refac 2025-04-06 20:23:23 -07:00
Timothy Jaeryang Baek 3885ea4a15 Merge pull request #12526 from gaby/dependabot-update
chore: Dependabot update
2025-04-06 19:46:03 -07:00
Juan Calderon-Perez bd28173de6 Track backend/requirements.txt updates 2025-04-06 22:33:34 -04:00
Timothy Jaeryang Baek 06820e701c refac: citations modal 2025-04-06 19:14:24 -07:00
Timothy Jaeryang Baek 2be08f27ea revert 2025-04-06 19:12:08 -07:00
Timothy Jaeryang Baek fabe5876c0 Merge pull request #12525 from TiancongLx/dev
i18n: update zh-TW
2025-04-06 18:57:19 -07:00
Tiancong Li f1a4afeb8f i18n: update zh-TW 2025-04-07 09:28:20 +08:00
Timothy Jaeryang Baek 914eb49767 chore: include accelerate dependency 2025-04-06 17:44:05 -07:00
Timothy Jaeryang Baek a8bc0d65a0 chore: format 2025-04-06 17:36:16 -07:00
Timothy Jaeryang Baek cbe2056587 fix: audio file upload response issue 2025-04-06 17:31:50 -07:00
Timothy Jaeryang Baek 65ed76abe1 refac: embedding prefix 2025-04-06 17:17:24 -07:00
Timothy Jaeryang Baek bc17511a05 refac 2025-04-06 17:10:09 -07:00
Timothy Jaeryang Baek 3413dd8ae1 refac 2025-04-06 17:02:39 -07:00
Timothy Jaeryang Baek 03759e79a3 refac 2025-04-06 17:00:46 -07:00
Timothy Jaeryang Baek 20211a489f refac 2025-04-06 16:57:36 -07:00
Timothy Jaeryang Baek 5d2e725f81 refac 2025-04-06 16:53:30 -07:00
Timothy Jaeryang Baek 2722613cde refac 2025-04-06 16:43:58 -07:00
Timothy Jaeryang Baek f243e523a6 refac 2025-04-06 15:52:38 -07:00
Timothy Jaeryang Baek 155dbd5a66 refac 2025-04-06 15:45:48 -07:00
Timothy Jaeryang Baek 9825d03602 Merge pull request #12507 from Ithanil/fix_web_result_collection_source_ids
fix: fix web results all getting the same source id when using embedding and retrieval
2025-04-06 15:43:21 -07:00
Timothy Jaeryang Baek 66cd40f959 chore: format 2025-04-06 15:37:46 -07:00
Timothy Jaeryang Baek dc2f8ec8c6 refac 2025-04-06 15:37:27 -07:00
Timothy Jaeryang Baek bf118718b3 Merge pull request #12521 from gaby/optimize-workflow
chore: Only run GitHub workflows when needed
2025-04-06 15:24:20 -07:00
Timothy Jaeryang Baek 64a0b28dab refac 2025-04-06 15:23:40 -07:00
Timothy Jaeryang Baek 6751d68034 Merge pull request #12506 from Ithanil/fix_web_result_source_ids
fix: fix web results all getting the same source id when bypassing embedding and retrieval
2025-04-06 15:21:14 -07:00
Timothy Jaeryang Baek 6274f4d0d3 Merge pull request #12520 from gaby/bump-docker
chore: Bump Python Docker image to python3.12
2025-04-06 15:17:27 -07:00
Juan Calderon-Perez 624c5250b1 Optimize GitHub actions 2025-04-06 18:15:56 -04:00
Timothy Jaeryang Baek c1ff69721a refac 2025-04-06 15:14:57 -07:00
Timothy Jaeryang Baek 1e98ae7608 Merge pull request #12431 from gaby/fix-12237
feat: Allow making content optional when listing all files
2025-04-06 15:13:13 -07:00
Timothy Jaeryang Baek 1bde36e072 Merge pull request #12510 from newnol/patch-1
i18n language pack vietnamese
2025-04-06 15:12:09 -07:00
Juan Calderon-Perez 89e7913ff2 Bump Python base Docker image to 3.12 2025-04-06 18:10:38 -04:00
Timothy Jaeryang Baek 51bf9eaa88 Merge pull request #12493 from TiancongLx/dev
i18n: update zh-TW
2025-04-06 15:09:21 -07:00
Timothy Jaeryang Baek b8cf9b738d Merge pull request #12511 from panda44312/patch-11
i18n: zh-cn
2025-04-06 15:09:13 -07:00
Timothy Jaeryang Baek 635c08a5ab Merge pull request #12517 from Ithanil/only_keep_retrieved_urls
fix: only keep URLs as sources for which the content was actually retrieved
2025-04-06 15:08:47 -07:00
Timothy Jaeryang Baek 6323b9f4f0 Merge pull request #12515 from gaby/fix-dependabot
chore: Fix dependabot configuration
2025-04-06 13:41:18 -07:00
Juan Calderon-Perez 94453839ba Update index.ts 2025-04-06 16:02:16 -04:00
Jan Kessler a506a1a61e only keep URLs as sources for which the content could actually be retrieved 2025-04-06 20:31:12 +02:00
Juan Calderon-Perez d266490862 Fix dependabot configuration 2025-04-06 13:58:17 -04:00
Juan Calderon-Perez ff1d454bdd Fix formatting 2025-04-06 13:32:51 -04:00
Juan Calderon-Perez eda3eba084 Merge branch 'open-webui:main' into fix-12237 2025-04-06 13:30:37 -04:00
Taylor Wilsdon 0a2747bc6a Merge branch 'dev' of github.com:taylorwilsdon/open-webui into dev 2025-04-06 13:01:39 -04:00
Panda 60c6e00d9f i18n: fix 2025-04-06 16:47:06 +02:00
Panda 246c839ee6 i18n: zh-cn 2025-04-06 16:42:09 +02:00
Ngô Tấn Tài 2994c58fd9 Update translation.json 2025-04-06 21:26:58 +07:00
Jan Kessler 4476060044 fix web results all getting the same source id when using embedding and retrieval 2025-04-06 15:51:05 +02:00
Jan Kessler 2729d8aab4 fix web results all getting the same source id when bypassing embedding and retrieval 2025-04-06 13:37:42 +02:00
Tiancong Li 26e1bfc772 Merge remote-tracking branch 'upstream/dev' into dev
* upstream/dev:
  refac
  Fallback from desc to summary to placeholder
2025-04-06 10:33:01 +08:00
Timothy Jaeryang Baek 9ea6cea0ba refac 2025-04-05 14:31:22 -07:00
Timothy Jaeryang Baek 71625663c0 Merge pull request #12496 from dan-sullivan/fix-12479/add-desc-to-openapi-tools
fix: openapi tools should pass description to model not summary
2025-04-05 15:30:19 -06:00
Tiancong Li 33451cf66d i18n: update zh-TW 2025-04-06 04:46:31 +08:00
Timothy Jaeryang Baek 41aca84913 Merge pull request #12491 from open-webui/dev
refac
2025-04-05 10:24:32 -07:00
Timothy Jaeryang Baek 5296ee0f71 refac 2025-04-05 11:24:05 -06:00
Timothy Jaeryang Baek da94835165 Merge pull request #12373 from open-webui/dev
0.6.1
2025-04-05 10:15:32 -07:00
Timothy Jaeryang Baek 13dfca4e76 chore: bump 2025-04-05 11:13:30 -06:00
Timothy Jaeryang Baek d5063f47f2 doc: changelog 2025-04-05 11:11:37 -06:00
Timothy Jaeryang Baek ef787e4a79 Merge pull request #12486 from FabioPolito24/text-file-handling-docling
fix: text file handling with docling
2025-04-05 09:55:51 -07:00
Timothy Jaeryang Baek 48d690c55d Merge pull request #12481 from gaby/generic-errors
fix: Improve auth error messages
2025-04-05 09:47:52 -07:00
Timothy Jaeryang Baek 69c68df34b Merge pull request #12480 from Kylapaallikko/dev
i18n: Update Finnish Translation
2025-04-05 09:47:39 -07:00
Timothy Jaeryang Baek b3110ca291 Merge branch 'dev' into dev 2025-04-05 09:47:30 -07:00
Fabio Polito cd0a1b4852 fix: fix for text file handling with docling 2025-04-05 16:44:08 +00:00
Timothy Jaeryang Baek 32f309b41d chore: format 2025-04-05 10:42:21 -06:00
Timothy Jaeryang Baek d23f757c1f refac 2025-04-05 10:41:46 -06:00
Juan Calderon-Perez 324550423c Fix formatting issues 2025-04-05 10:03:24 -04:00
Juan Calderon-Perez b4277c7d2e Make auth error messages generic 2025-04-05 09:56:11 -04:00
Kylapaallikko 84788b73ce Update translation.json 2025-04-05 16:37:54 +03:00
dan-sullivan 09344bbb80 Fallback from desc to summary to placeholder 2025-04-05 14:18:14 +01:00
Timothy Jaeryang Baek fe4f760b4a refac 2025-04-05 05:57:25 -06:00
Timothy Jaeryang Baek 807b208418 refac 2025-04-05 05:55:56 -06:00
Timothy Jaeryang Baek ae484e8edf refac 2025-04-05 05:45:32 -06:00
Timothy Jaeryang Baek 56dc7c5640 refac 2025-04-05 05:38:46 -06:00
Timothy Jaeryang Baek e570a98bf7 refac: substandard codebase overhauled 2025-04-05 05:31:22 -06:00
Timothy Jaeryang Baek 93bb77ede3 refac 2025-04-05 05:03:15 -06:00
Timothy Jaeryang Baek 66db2e1515 refac: tools removed UNNECESSARY CODE 2025-04-05 04:59:11 -06:00
Timothy Jaeryang Baek c9e9ce931b refac 2025-04-05 04:49:07 -06:00
Timothy Jaeryang Baek 9747a0e1f1 refac: tool servers 2025-04-05 04:40:01 -06:00
Timothy Jaeryang Baek 61778c8f71 Merge pull request #12478 from theredcat/main
Improve FR translation
2025-04-05 03:22:54 -07:00
Timothy Jaeryang Baek 579aca65bb Merge pull request #12477 from Ithanil/improved_rag_template
fix: more coherent default RAG template
2025-04-05 03:22:41 -07:00
Timothy Jaeryang Baek ee44383c83 refac 2025-04-05 04:12:57 -06:00
Timothy Jaeryang Baek 0c0505e1cd refac 2025-04-05 04:05:52 -06:00
Nathan DELHAYE 1b8557ce86 i18n: improve fr translation 2025-04-05 12:04:12 +02:00
Jan Kessler e0da6003f1 tweak default rag template to be more coherent and improve consistency with citations 2025-04-05 11:40:48 +02:00
Timothy Jaeryang Baek 0f310b3509 Merge pull request #12476 from Phlogi/dev-hybrid-search
fix: Avoid secondary error when collection is empty in parallel hybrid search
2025-04-05 02:10:29 -07:00
Phlogi 8cf8121812 Update utils.py
Avoid running any tasks for collections that failed to fetch data (have assigned None)
2025-04-05 10:41:21 +02:00
Timothy Jaeryang Baek a2f2203325 Merge pull request #12426 from silentoplayz/fix-feedback
fix: Conditionally hide export buttons
2025-04-05 01:30:51 -07:00
Timothy Jaeryang Baek 193a927aba fix: temp chat 2025-04-05 02:16:35 -06:00
Timothy Jaeryang Baek 4ad10f0c6e chore: format 2025-04-05 01:31:45 -06:00
Timothy Jaeryang Baek 5e06b6d3f4 refac: styling 2025-04-05 01:24:32 -06:00
Timothy Jaeryang Baek cb94a87cb0 refac: tools styling 2025-04-05 01:05:47 -06:00
Timothy Jaeryang Baek 793aa307ef Merge pull request #12433 from gaby/fix-allowed-endpoints
fix: API Key Endpoint Restrictions for Dynamic Paths
2025-04-04 08:24:10 -07:00
Timothy Jaeryang Baek 7e46cc4562 Merge pull request #12439 from narutopden/i18n-add-Tibetan-translation
i18n: add Tibetan language
2025-04-04 08:20:25 -07:00
Timothy Jaeryang Baek b612af29e9 refac 2025-04-04 09:17:19 -06:00
Timothy Jaeryang Baek feaf434d4e refac: input prompt 2025-04-04 09:11:54 -06:00
Timothy Jaeryang Baek 77fa11098a enh: openapi tool server custom path 2025-04-04 08:31:13 -06:00
Timothy Jaeryang Baek a32bb850fa Merge pull request #12450 from mahenning/fix-missing-parameter-rag
Fix: Add missing parameter for query_doc_with_hybrid_search
2025-04-04 07:00:16 -07:00
Timothy Jaeryang Baek 64b68b3641 Merge pull request #12447 from floriankick/fix-openai-api-empty-message-after-tool-call
fix: make content parameter optional in OpenAI chat completion API endpoint
2025-04-04 06:59:12 -07:00
Marko Henning 3b2b6e183d Added missing parameter for query_doc_with_hybrid_search. 2025-04-04 15:30:57 +02:00
Juan Calderon-Perez 138e985d66 Rename field to include_content 2025-04-04 08:38:24 -04:00
Florian Kick ec3435de00 make content parameter optional in OpenAI chat completion API endpoint 2025-04-04 13:30:51 +02:00
narutopden a25d87607e i18n: add Tibetan language 2025-04-04 14:55:49 +08:00
Juan Calderon-Perez 1c57e3e02c Fix API_KEY_ALLOWED_ENDPOINTS 2025-04-03 23:52:10 -04:00
Silentoplayz 41b9ff9e00 fix: funcs, models, prompts, & tools conditional export button 2025-04-03 23:33:30 -04:00
Juan Calderon-Perez 6d5cb6b04e Add query param to remove content from GET /api/v1/files 2025-04-03 23:02:24 -04:00
silentoplayz 1366822f99 Update Feedbacks.svelte
fix
2025-04-04 02:38:03 +00:00
Silentoplayz 2b0d9c26eb fix: don't show export button if nothing to export 2025-04-03 22:20:40 -04:00
Timothy Jaeryang Baek be20e6dec0 refac: message edit 2025-04-03 13:43:45 -06:00
Timothy Jaeryang Baek a1f3300767 fix: tls cert requirement 2025-04-03 10:01:03 -07:00
Timothy Jaeryang Baek dfdde8bb1f refac 2025-04-03 09:40:26 -07:00
Timothy Jaeryang Baek ba77a72925 refac: styling 2025-04-03 01:00:40 -07:00
Timothy Jaeryang Baek bcf0a8791e refac: styling 2025-04-03 01:00:04 -07:00
Timothy Jaeryang Baek 100f5a57e7 refac 2025-04-02 23:56:15 -07:00
Timothy Jaeryang Baek 911321878f refac 2025-04-02 23:49:42 -07:00
Timothy Jaeryang Baek faa68fcdaa enh: image tool response 2025-04-02 23:46:39 -07:00
Jan Kessler 257ca45456 leave out @ in redis+sentine url when no username/password is provided 2025-04-03 08:24:24 +02:00
Timothy Jaeryang Baek 561b2c0b1a refac: styling 2025-04-02 21:23:45 -07:00
Timothy Jaeryang Baek 436e3ff7de refac 2025-04-02 20:42:23 -07:00
Timothy Jaeryang Baek c0711ba0c9 refac 2025-04-02 20:07:09 -07:00
Timothy Jaeryang Baek 5c5160c294 refac: remove None params 2025-04-02 19:56:39 -07:00
Timothy Jaeryang Baek 2277566ce1 fix: tool server api key not being sent 2025-04-02 19:52:12 -07:00
Timothy Jaeryang Baek 959995c715 refac: use selected model for merge response 2025-04-02 19:33:20 -07:00
Timothy Jaeryang Baek 7a1e10f3a7 refac: rm OAUTH_USE_PICTURE_CLAIM 2025-04-02 19:23:24 -07:00
Timothy Jaeryang Baek b15bf0dc70 refac 2025-04-02 19:17:26 -07:00
Timothy Jaeryang Baek 506950b03a Merge pull request #12376 from MushroomLamp-COB/main
feat: Add option to disable OAuth profile pictures
2025-04-02 19:16:36 -07:00
Timothy Jaeryang Baek 94353458a5 refac: settings ui styling 2025-04-02 19:01:39 -07:00
Timothy Jaeryang Baek 7eea95a48c feat: direct tools user permissions 2025-04-02 18:36:03 -07:00
Timothy Jaeryang Baek 94bf49440d enh: unload hybrid model if set to False 2025-04-02 18:15:14 -07:00
Timothy Jaeryang Baek 0644abe402 fix: admin folder deletion issue 2025-04-02 17:55:24 -07:00
Timothy Jaeryang Baek 9036945361 Merge pull request #12355 from silentoplayz/logging-fix
fix: update datetime and logging imports
2025-04-02 17:44:30 -07:00
silentoplayz dd5bafe8af Update env.py
Revert
2025-04-03 00:36:16 +00:00
CityOfBunbury 548c7f17d7 Added OAUTH_USE_PICTURE_CLAIM env var
Added OAUTH_USE_PICTURE_CLAIM to config.py

Added check to oauth.py on OAUTH_USE_PICTURE_CLAIM, to decide whether to user the profile picture in the claim or the default user.png
2025-04-03 08:24:14 +08:00
Timothy Jaeryang Baek bb7f4d408a Merge pull request #12364 from silentoplayz/archive-chats-option
feat: Added Archived Chats option in Chats settings section
2025-04-02 17:12:34 -07:00
Timothy Jaeryang Baek 6ee30042e7 Merge pull request #12353 from SadmL/dev
[i18n] Russian localization update
2025-04-02 15:47:44 -07:00
Timothy Jaeryang Baek 0554bbb1cb Merge pull request #12307 from paddy313/feature/mistral_ocr
feat: Added support for Mistral OCR for Content Extraction
2025-04-02 15:47:33 -07:00
Timothy Jaeryang Baek 517a57b7ca Merge pull request #12331 from panda44312/patch-10
i18n: zh-cn fix
2025-04-02 15:46:42 -07:00
Jan Kessler 35ea29b184 prepare websocket redis sentinel code for upcoming native support of sentinel in python-socketio 2025-04-02 21:50:00 +02:00
Silentoplayz ee68c9ea55 Update Chats.svelte
Added Archived Chats option in Chats settings section
2025-04-02 14:25:03 -04:00
Silentoplayz d65471c420 fix
my dev environment works again!
2025-04-02 11:28:45 -04:00
SadmL de8f94b008 [i18n] Russian localization update
Fixed typos and translated some lines
2025-04-02 18:13:52 +03:00
Patrick Wachter 0ac00b9256 refactor: update import path for MistralLoader 2025-04-02 13:56:10 +02:00
Timothy Jaeryang Baek d0db4756a6 Merge pull request #12310 from landerrosette/fix_filter_priority
fix: Filter function’s priority valve has no effect
2025-04-02 04:41:00 -07:00
Panda adaa614986 fix 2025-04-02 10:35:05 +02:00
Timothy Jaeryang Baek 5ab783001d Merge pull request #12304 from OriginalSimon/main
18n: Update Ukrainian translation
2025-04-01 16:12:59 -07:00
Timothy Jaeryang Baek 2a163996f9 Merge pull request #12294 from Xelaph/dev
**i18n**: Update Dutch translations
2025-04-01 16:12:48 -07:00
Timothy Jaeryang Baek 1b37bdcec8 Merge pull request #12278 from Saidoua/main
**i18n** Standard Arabic Translation
2025-04-01 16:11:54 -07:00
Timothy Jaeryang Baek 39b0c06630 Merge pull request #12299 from lowlyocean/rpi_onnxruntime
fix: Allow v0.6.0 to run on Raspberry Pi
2025-04-01 16:02:05 -07:00
landerrosette 2b7dd6e399 refactor: standardize filter valve retrieval logic 2025-04-02 02:58:02 +08:00
Patrick Wachter c5a8d2f857 refactor: update MistralLoader documentation and adjust parameters for signed URL retrieval 2025-04-01 20:14:34 +02:00
Patrick Wachter 93d7702e8c refactor: move MistralLoader to a separate module and just use the requests package instead of mistralai 2025-04-01 20:14:34 +02:00
Simon 0447d90951 Update translation.json 2025-04-01 20:01:08 +02:00
Daniel Nowak 8f8c34471e Pin onnxruntime to 1.20.1 to address SIGILL on certain arm64 hosts 2025-04-01 12:03:09 -04:00
Alex 883ad55f5c Update translation.json 2025-04-01 16:12:31 +02:00
Alex 82e5a6410c Update translation.json 2025-04-01 16:09:17 +02:00
Alex 88b93241db Update translation.json 2025-04-01 15:20:04 +02:00
Alex b652b8e5f3 Update translation.json 2025-04-01 14:25:04 +02:00
Patrick Wachter 1ac6879268 Add Mistral OCR integration and configuration support 2025-04-01 14:24:33 +02:00
Said Ouhdachi 825becceb0 Arabic Translation 2025-04-01 13:10:59 +02:00
Timothy Jaeryang Baek fffa793d6d Merge pull request #12270 from TiancongLx/dev
i18n: update zh-TW
2025-04-01 02:29:00 -07:00
Timothy Jaeryang Baek 289d49dbe7 Merge pull request #12269 from panda44312/patch-9
i18n: zh-cn
2025-04-01 02:28:51 -07:00
Tiancong Li fa72c277db i18n: update zh-TW 2025-04-01 17:10:32 +08:00
Panda 8799ff9575 fix 2025-04-01 10:52:05 +02:00
Panda 85c8a9bd68 i18n: zh-cn 2025-04-01 10:47:52 +02:00
Timothy Jaeryang Baek 15f6e3af12 Merge pull request #12259 from weisser-dev/dev
[FEAT] adjust Translations for temporary chat
2025-04-01 00:59:27 -07:00
Timothy Jaeryang Baek c79fa4214f Merge pull request #12262 from lukasz-pekala/fb/fixes-to-polish-translation
i18n: fixes to polish translation
2025-04-01 00:59:08 -07:00
Łukasz Pękala 29d5745335 fix: update Polish translation for "Capture" to improve accuracy 2025-04-01 09:14:29 +02:00
Erik 70bb0562f3 Merge branch 'open-webui:dev' into dev 2025-04-01 09:09:33 +02:00
Erik c8210d4043 upated like in PR discussed 2025-04-01 09:06:15 +02:00
Łukasz Pękala 9f470a4ff5 fix: update Polish translations to sound more natural 2025-04-01 08:53:12 +02:00
Timothy Jaeryang Baek cea5c1a63b Merge pull request #12254 from open-webui/dependabot/pip/backend/dev/einops-0.8.1
build(deps): bump einops from 0.8.0 to 0.8.1 in /backend
2025-03-31 23:45:23 -07:00
Timothy Jaeryang Baek 4ce05ad279 Merge pull request #12255 from open-webui/dependabot/pip/backend/dev/pypandoc-1.15
build(deps): bump pypandoc from 1.13 to 1.15 in /backend
2025-03-31 23:45:15 -07:00
Timothy Jaeryang Baek f3c2614b6c Merge pull request #12253 from open-webui/dependabot/pip/backend/dev/python-multipart-0.0.20
build(deps): bump python-multipart from 0.0.18 to 0.0.20 in /backend
2025-03-31 23:44:40 -07:00
Timothy Jaeryang Baek 79cca06e0c Merge pull request #12260 from weisser-dev/feat-default-value-for-enforce-temp-chat
[improvement] default permission for new groups is false for enforce …
2025-03-31 23:43:08 -07:00
Łukasz Pękala b60beb6ff6 fix: improve Polish translations for clarity and accuracy 2025-04-01 08:39:36 +02:00
Erik 295c7eb4c7 [improvement] default permission for new groups is false for enforce temp chat 2025-04-01 08:27:29 +02:00
Łukasz Pękala 361584b4fd fix: update Polish translations for clarity and accuracy 2025-04-01 08:26:21 +02:00
Erik abba7c128c [FEAT]-Adjust Translations for temporary chat 2025-04-01 08:21:03 +02:00
Timothy Jaeryang Baek e0ec2cdeb0 refac: $user 2025-03-31 20:32:12 -07:00
dependabot[bot] bb0e11bb97 build(deps): bump pypandoc from 1.13 to 1.15 in /backend
Bumps [pypandoc](https://github.com/JessicaTegner/pypandoc) from 1.13 to 1.15.
- [Release notes](https://github.com/JessicaTegner/pypandoc/releases)
- [Changelog](https://github.com/JessicaTegner/pypandoc/blob/master/release.md)
- [Commits](https://github.com/JessicaTegner/pypandoc/compare/v1.13...v1.15)

---
updated-dependencies:
- dependency-name: pypandoc
  dependency-version: '1.15'
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-01 02:22:16 +00:00
dependabot[bot] fc5c8dbe3f build(deps): bump einops from 0.8.0 to 0.8.1 in /backend
Bumps [einops](https://github.com/arogozhnikov/einops) from 0.8.0 to 0.8.1.
- [Release notes](https://github.com/arogozhnikov/einops/releases)
- [Commits](https://github.com/arogozhnikov/einops/compare/v0.8.0...v0.8.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-01 02:22:13 +00:00
dependabot[bot] 1d30d8a13a build(deps): bump python-multipart from 0.0.18 to 0.0.20 in /backend
Bumps [python-multipart](https://github.com/Kludex/python-multipart) from 0.0.18 to 0.0.20.
- [Release notes](https://github.com/Kludex/python-multipart/releases)
- [Changelog](https://github.com/Kludex/python-multipart/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Kludex/python-multipart/compare/0.0.18...0.0.20)

---
updated-dependencies:
- dependency-name: python-multipart
  dependency-version: 0.0.20
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-01 02:22:11 +00:00
Timothy Jaeryang Baek 04799f1f95 Merge pull request #11728 from open-webui/dev
0.6
2025-03-31 18:47:18 -07:00
Timothy Jaeryang Baek 1b7c125f00 refac 2025-03-31 18:47:08 -07:00
Timothy Jaeryang Baek 13f7a4cf56 doc: wording 2025-03-31 18:43:27 -07:00
Timothy Jaeryang Baek 8f8d8ba27d doc: changelog 2025-03-31 18:40:49 -07:00
Timothy Jaeryang Baek dca68871e6 doc: wording 2025-03-31 18:39:30 -07:00
Timothy Jaeryang Baek da561c50d0 doc: wording 2025-03-31 18:36:08 -07:00
Timothy Jaeryang Baek 3662ecdeab doc: changelog 2025-03-31 18:34:42 -07:00
Timothy Jaeryang Baek 391dd33da3 chore: format 2025-03-31 17:59:21 -07:00
Timothy Jaeryang Baek 0bc5441d72 refac: styling 2025-03-31 17:58:48 -07:00
Timothy Jaeryang Baek 5f792d2771 feat: enforced temporary chat 2025-03-31 17:58:43 -07:00
Timothy Jaeryang BaekandTaylor Wilsdon 580965df17 feat: public sharing permissions
Co-Authored-By: Taylor Wilsdon <6508528+taylorwilsdon@users.noreply.github.com>
2025-03-31 17:28:25 -07:00
Timothy Jaeryang Baek 50b3f47f81 feat: public sharing permissions 2025-03-31 17:15:51 -07:00
Timothy Jaeryang Baek 3ba12e7a43 Merge pull request #12239 from Phlogi/dev-threads-on-hybrid
perf: parallelize hybrid search
2025-03-31 17:06:32 -07:00
Timothy Jaeryang Baek def5444ea3 feat: hide base model 2025-03-31 16:51:42 -07:00
Timothy Jaeryang Baek cafc5413f5 refac 2025-03-31 14:13:27 -07:00
Timothy Jaeryang Baek 3dc40030a1 Merge pull request #12236 from Phlogi/fix_prefix
Fix middleware.py missing prefix on embedding function
2025-03-31 14:02:49 -07:00
Timothy Jaeryang Baek efb63fb13f chore: format 2025-03-31 14:02:02 -07:00
Timothy Jaeryang Baek 598222b76f Merge pull request #12238 from rgaricano/dev
PR: Translation (es-ES) - Spanish v0.6.0
2025-03-31 14:01:27 -07:00
Timothy Jaeryang Baek fac848ad33 refac: rm log info 2025-03-31 14:00:40 -07:00
_00_ 098c794de3 Update translation.json
fix X typo
lines 4 & 304
2025-03-31 19:52:15 +02:00
_00_ 1571e3dc16 FIX: Translation (es-ES) - Spanish
Complete Revision of Spanish Translation (es-ES)

Revised spanish translation.
Standardization of terminology, vocabulary, and syntax.
Revision of incorrectly explained or defined terms.
2025-03-31 17:12:55 +02:00
_00_ a65c426e1d FIX: Translation (es-ES) - Spanish rev.
Complete Revision of Spanish Translation (es-ES)

Revised spanish translation.
Standardization of terminology, vocabulary, and syntax.
Revision of incorrectly explained or defined terms.

(added two lost recently updated entries)
2025-03-31 16:59:05 +02:00
Phlogi 9c64310db5 Run hybrid_search in parallel 2025-03-31 16:43:37 +02:00
_00_ 3c507e829f FIX: Translation (es-ES) - Spanish
Complete Revision of Spanish Translation (es-ES)

Revised spanish translation.
Standardization of terminology, vocabulary, and syntax.
Revision of incorrectly explained or defined terms.
2025-03-31 16:42:56 +02:00
Phlogi bc64b2a67f Fix middleware.py missing prefix on embedding function 2025-03-31 15:19:07 +02:00
Timothy Jaeryang Baek 6ac153c989 refac: styling 2025-03-31 03:45:36 -07:00
Timothy Jaeryang Baek 5ce6c8ced3 refac 2025-03-31 01:45:22 -07:00
Timothy Jaeryang Baek 9809ffb095 refac 2025-03-31 01:30:08 -07:00
Timothy Jaeryang Baek a5dbd2e8dd refac: knowledge file ac 2025-03-31 01:10:18 -07:00
Timothy Jaeryang Baek 021e25ade1 Merge pull request #11087 from tarmst/fix-files-access-control
fix: Add access control usage to files APIs
2025-03-31 01:05:08 -07:00
Timothy Jaeryang Baek 05dfb9cecd refac: floating buttons behaviour in shared chat 2025-03-31 00:57:16 -07:00
Timothy Jaeryang Baek effa87638d refac: prompt command behaviour 2025-03-31 00:48:09 -07:00
Timothy Jaeryang Baek 300b7dfcc0 fix: model import/export 2025-03-31 00:39:20 -07:00
Timothy Jaeryang Baek fb875c574c Merge pull request #12218 from aleixdorca/dev
Update catalan translation.json
2025-03-31 00:19:28 -07:00
Aleix Dorca 6e190bebe8 Update catalan translation.json 2025-03-31 09:12:48 +02:00
Timothy Jaeryang Baek e4cc9f2b4f refac: folders 2025-03-30 23:36:15 -07:00
Timothy Jaeryang Baek 337df80c47 refac: styling 2025-03-30 23:17:06 -07:00
Timothy Jaeryang Baek d542881ee4 refac 2025-03-30 21:55:20 -07:00
Timothy Jaeryang Baek 4b75966401 refac: embedding prefix var naming 2025-03-30 21:55:15 -07:00
Timothy Jaeryang Baek 433b5bddc1 Merge pull request #8594 from jayteaftw/main
feat: Support for instruct/prefixing embeddings
2025-03-30 21:54:44 -07:00
Timothy Jaeryang Baek 12101fd26d Merge pull request #11307 from wangtunan/fix/stop_task_func_need_use_async_await_syntax
fix: stopTask func need use async/await syntax
2025-03-30 21:45:32 -07:00
Timothy Jaeryang Baek 33f93371dc feat: user webhooks system settings 2025-03-30 21:31:16 -07:00
Timothy Jaeryang Baek d55735dc1e refac: rm profile image from feedback user object 2025-03-30 21:23:42 -07:00
Timothy Jaeryang Baek d41844c308 feat: prompt autocompletion user setting 2025-03-30 21:19:09 -07:00
Timothy Jaeryang Baek 50b8dec3ac fix/refac: hybrid search 2025-03-30 20:48:22 -07:00
Timothy Jaeryang Baek ce0d82b55f Merge pull request #12132 from Phlogi/dev-fetch-documents-once
Avoid multiple data fetching
2025-03-30 20:44:32 -07:00
Timothy Jaeryang Baek febc85361f Merge pull request #12191 from rgaricano/dev
Fix alignament buttons text
2025-03-30 20:42:21 -07:00
Timothy Jaeryang Baek d9bbdd8dca revert 2025-03-30 20:38:47 -07:00
Timothy Jaeryang Baek 9c00f3caf3 Merge pull request #12192 from Ithanil/avatar_compression
feat: adjust jpeg compression quality to 0.15 for avatar uploads
2025-03-30 20:35:31 -07:00
Timothy Jaeryang Baek ee9ff96c7d Merge pull request #12194 from TiancongLx/dev
i18n: update zh-TW
2025-03-30 17:19:23 -07:00
Tiancong Li 50a0751418 i18n: update zh-TW 2025-03-30 23:24:27 +08:00
Jan Kessler 7f5dc22464 adjust jpeg compression quality to 0.15 for avatar uploads 2025-03-30 14:14:14 +02:00
_00_ 5b8317270e Fix alignament buttons text
Fix alignament buttons text

Fixed align tag on user & admin settings

- correction of some align tag assigned to buttons that are right and
have to be left, this means that although it is not noticeable in
English, in other languages, especially if several lines appear, it is
obvious.
2025-03-30 13:36:07 +02:00
Timothy Jaeryang Baek b5909ffe97 enh: tool args parse json fallback 2025-03-30 02:39:23 -07:00
Timothy Jaeryang Baek 03e61e7a4a refac: styling 2025-03-30 00:47:45 -07:00
Timothy Jaeryang Baek 215f991326 refac 2025-03-30 00:44:09 -07:00
Timothy Jaeryang Baek 2cee5a4a03 chore: format 2025-03-30 00:21:00 -07:00
Timothy Jaeryang Baek 3be626bef3 feat: goto message 2025-03-29 17:48:57 -07:00
Timothy Jaeryang Baek c700126c17 refac: html rendering 2025-03-29 16:52:49 -07:00
Timothy Jaeryang Baek feaa01dc77 fix: ollama requests 2025-03-29 16:52:42 -07:00
Timothy Jaeryang Baek 34607736c6 Merge pull request #12170 from JunaidPinjari/fix/csv-autodetect-encoding
Fix: CSV loader encoding issue using autodetect_encoding=True
2025-03-29 15:23:55 -07:00
Timothy Jaeryang Baek 5b9b802793 refac 2025-03-29 15:23:02 -07:00
Timothy Jaeryang Baek da5ea7acb8 Merge pull request #12176 from JunaidPinjari/feat/file-upload-download-options
Support skipping ingestion and downloading files as attachments
2025-03-29 15:20:47 -07:00
Timothy Jaeryang Baek 08ff1d8d88 refac 2025-03-29 15:03:10 -07:00
Timothy Jaeryang Baek c2ff73c3e1 refac 2025-03-29 14:59:03 -07:00
Junaid Pinjari a805e033a5 Feat: Add optional ingest_file and as_attachment params to upload and download endpoints 2025-03-29 15:42:11 +05:30
Junaid Pinjari e782e7d3a7 Fix: CSV loader encoding issue using autodetect_encoding=True 2025-03-29 13:14:53 +05:30
Timothy Jaeryang Baek 66015bb341 Merge pull request #12168 from yak1ex/fix_inconsistent_value_check_in_onMessageHandler_in_Chat_svelte
fix: Inconsistent value check in onMessageHandler() in Chat.svelte
2025-03-28 22:12:57 -07:00
Timothy Jaeryang Baek 737f41dd2e refac 2025-03-28 13:18:44 -07:00
Timothy Jaeryang Baek 402d32ccfd refac 2025-03-28 13:17:43 -07:00
Timothy Jaeryang Baek 0413c747a9 refac: hide hybrid option with full context mode 2025-03-28 13:16:56 -07:00
Timothy Jaeryang Baek acd5b07fb4 enh: tool servers info modal 2025-03-28 12:40:56 -07:00
Timothy Jaeryang Baek 0a49c366f0 refac 2025-03-28 12:25:59 -07:00
Timothy Jaeryang Baek af2c5f3a18 refac 2025-03-28 12:23:25 -07:00
Timothy Jaeryang Baek 115f34069a refac: tool call display 2025-03-28 12:18:27 -07:00
Timothy Jaeryang Baek 1ac87c55ff chore: format 2025-03-28 11:47:14 -07:00
Timothy Jaeryang Baek b8c1bb0ec5 refac 2025-03-28 02:30:13 -07:00
Timothy Jaeryang Baek f8835d78d9 refac: tool call block display 2025-03-28 02:27:40 -07:00
Timothy Jaeryang Baek fd9641dcd1 refac 2025-03-28 01:20:45 -07:00
Timothy Jaeryang Baek 5656f030c4 refac: error handling 2025-03-28 00:52:13 -07:00
Timothy Jaeryang Baek 2fc8ace46d fix: error message persistence issue 2025-03-28 00:25:00 -07:00
Timothy Jaeryang Baek 2070d1096b refac 2025-03-28 00:07:00 -07:00
Timothy Jaeryang Baek 5f9679253e refac: openapi tool server support 2025-03-27 23:59:16 -07:00
Timothy Jaeryang Baek 359e6f2fd2 Merge pull request #12149 from TiancongLx/dev
i18n: update zh-TW
2025-03-27 23:49:56 -07:00
Tiancong Li f647e86346 i18n: update zh-TW 2025-03-28 14:38:43 +08:00
Timothy Jaeryang Baek 7fce3e2a9c Merge pull request #11148 from Ithanil/redis_sentinel
feat: Support for Redis Sentinel
2025-03-27 20:36:53 -07:00
Timothy Jaeryang Baek c137d3ad17 enh: allow json schema for format 2025-03-27 20:27:16 -07:00
Timothy Jaeryang Baek 424f007b10 fix: ldap certificate path should not be required 2025-03-27 19:55:41 -07:00
Timothy Jaeryang Baek 5e720cd84b refac: ollama response_format support 2025-03-27 19:26:08 -07:00
Timothy Jaeryang Baek 7845b2fbef Merge pull request #12122 from panda44312/patch-8
i18n: zh-cn
2025-03-27 14:48:45 -07:00
Phlogi 04bf9ddab2 Avoid multiple data fetching 2025-03-27 19:05:20 +01:00
Panda 72bef8798f i18n: zh-cn 2025-03-27 11:05:57 +01:00
Timothy Jaeryang Baek 4547453141 refac 2025-03-27 02:57:02 -07:00
Timothy Jaeryang Baek fc6d432c2f refac 2025-03-27 02:53:24 -07:00
Timothy Jaeryang Baek 038df1131e refac 2025-03-27 02:50:53 -07:00
Timothy Jaeryang Baek d1bc2cfa2f refac: external tools server support 2025-03-27 02:27:56 -07:00
Jan Kessler 0615c11a53 fix sentinel connection being attempted for non-sentinel redis 2025-03-27 10:23:35 +01:00
Timothy Jaeryang Baek 69dee19568 refac 2025-03-27 01:42:33 -07:00
Timothy Jaeryang Baek 4a79320253 chore: format 2025-03-27 01:40:28 -07:00
Timothy Jaeryang Baek d9b6d78d5c feat: external tool server support frontend 2025-03-27 01:38:35 -07:00
Jan Kessler d0b13cf388 prefix sentinel envs with redis_ 2025-03-27 09:22:11 +01:00
Timothy Jaeryang Baek 3514a6c5ed Merge pull request #12050 from mahenning/fix-db-order
Fix: Normalize all database distances to score in [0, 1] (needs testing for different DBs)
2025-03-26 20:56:02 -07:00
Timothy Jaeryang Baek 7490bc9100 Merge branch 'dev' into fix-db-order 2025-03-26 20:55:42 -07:00
Timothy Jaeryang Baek eaba9d8a67 Merge pull request #11497 from mahenning/k_reranker
feat: Added new k_reranker parameter
2025-03-26 20:50:43 -07:00
Timothy Jaeryang Baek 9d834a8e90 Merge branch 'dev' into k_reranker 2025-03-26 20:50:31 -07:00
Timothy Jaeryang Baek 79e4f8a7bc refac 2025-03-26 20:47:52 -07:00
Timothy Jaeryang Baek 5119cc47fc refac 2025-03-26 20:46:55 -07:00
Timothy Jaeryang Baek 42636347e2 refac: start source citation from 1 2025-03-26 20:39:39 -07:00
Timothy Jaeryang Baek dd2d757270 Merge pull request #12090 from panda44312/patch-7
i18n: zh-cn
2025-03-26 20:37:27 -07:00
Timothy Jaeryang Baek 08cd749160 refac 2025-03-26 20:28:41 -07:00
Panda f2bc2f704e i18n: zh-cn 2025-03-26 15:14:16 +01:00
Timothy Jaeryang Baek a650d77af4 refac 2025-03-26 01:25:01 -07:00
Timothy Jaeryang Baek c062353a3f refac 2025-03-26 01:17:10 -07:00
Timothy Jaeryang Baek c1a02ec7d8 refac 2025-03-26 01:11:12 -07:00
Timothy Jaeryang Baek 1be6ad1250 feat: /messages chat endpoint support 2025-03-26 01:10:27 -07:00
Timothy Jaeryang Baek 7dcdb1b404 refac 2025-03-26 00:43:51 -07:00
Timothy Jaeryang Baek 5a7efad59c refac: tools 2025-03-26 00:40:24 -07:00
Timothy Jaeryang Baek 82ca88105c Merge pull request #12076 from TiancongLx/dev
i18n: update zh-TW
2025-03-25 23:50:27 -07:00
Tiancong Li ec08043f23 i18n: update zh-TW 2025-03-26 13:34:53 +08:00
Timothy Jaeryang Baek 823d9f0475 Merge pull request #12043 from Espinaydelfin/main
i18n: Agregar idioma Galego (Add Galician Language)
2025-03-25 21:02:16 -07:00
Timothy Jaeryang Baek 1a04028507 Merge pull request #12051 from PeterDaveHello/Update-zh-TW-locale
i18n: minor zh-TW Traditional Chinese translation fix
2025-03-25 21:01:12 -07:00
Timothy Jaeryang Baek 8fe4c51e26 Merge pull request #12054 from philipp-horstenkamp/main
i18n: Fixed typo in german translation
2025-03-25 21:00:57 -07:00
Timothy Jaeryang Baek 9ef5868226 Merge pull request #12056 from ivanbaldo/fix-tika-spaces
**fix**: Tika 3.1.0.0 sends a lot of blank lines which degrades the RAG results and don't look good on the UI, strip them.
2025-03-25 21:00:49 -07:00
Marko Henning 7531b7dcaa Satisfy github format check 2025-03-25 19:09:17 +01:00
Iván Baldo 115e46a6a2 Fix: Tika 3.1.0.0 sends a lot of blank lines which degrades the RAG results, strip them. 2025-03-25 14:53:14 -03:00
Philipp Horstenkamp ee263b2f2b Fixed typo in german translation 2025-03-25 17:19:35 +01:00
Peter Dave Hello ca50e339cd i18n: minor zh-TW Traditional Chinese translation fix 2025-03-26 00:04:33 +08:00
Marko Henning 94d9d3d590 Fix: Normalze all database distances to score in [0, 1] 2025-03-25 16:46:14 +01:00
Espinaydelfin 5cf730bba7 Agregar idioma Galego 2025-03-25 13:31:37 +01:00
Timothy Jaeryang Baek 4906af9319 refac: styling 2025-03-25 00:12:23 -07:00
Timothy Jaeryang Baek 0192b4b468 refac: styling 2025-03-25 00:10:09 -07:00
Timothy Jaeryang Baek 57d1527ce1 refac 2025-03-25 00:07:04 -07:00
Timothy Jaeryang Baek 48b89322fd Merge pull request #12009 from PeterDaveHello/Dockerfile
build: add one missing `--no-cache-dir` for `pip3 install` in Dockerfile
2025-03-24 11:44:25 -07:00
Timothy Jaeryang Baek 16018b75a3 Merge pull request #12016 from OriginalSimon/dev
18n: Update Ukrainian translation
2025-03-24 11:43:24 -07:00
Simon 0418416355 Update translation.json 2025-03-24 19:41:55 +01:00
Simon 1db46c31aa Merge branch 'open-webui:dev' into dev 2025-03-24 19:41:07 +01:00
Simon 4f06771559 Update translation.json 2025-03-24 19:40:30 +01:00
Timothy Jaeryang Baek 6ed617e9f5 Merge pull request #12006 from PeterDaveHello/Update-zh-TW-locale
i18n: Improve zh-TW Traditional Chinese translation
2025-03-24 11:36:54 -07:00
Timothy Jaeryang Baek f5590b2fc0 Merge pull request #12014 from PeterDaveHello/FixPullRequestTemplate
docs: fix spelling and grammatical issues in PR template
2025-03-24 11:36:40 -07:00
Timothy Jaeryang Baek 38d524f6a0 chore: format 2025-03-24 11:35:32 -07:00
Peter Dave Hello ed2ecca475 docs: fix spelling and grammatical issues in PR template 2025-03-25 00:26:21 +08:00
Peter Dave Hello aaf47486da build: add one missing --no-cache-dir for pip3 install in Dockerfile 2025-03-24 20:45:16 +08:00
Peter Dave Hello c1f1af97c1 i18n: Improve zh-TW Traditional Chinese translation 2025-03-24 04:27:14 +08:00
Timothy Jaeryang Baek d81d1333ba Merge pull request #11950 from shirayu/feat_auth_redirect
feat: Adding auth redirect parameter
2025-03-23 11:53:45 -07:00
Timothy Jaeryang Baek 9de3e6d716 Merge pull request #11971 from shirayu/remove_ENABLE_AUDIT_LOGS
Remove `ENABLE_AUDIT_LOGS`
2025-03-23 11:53:12 -07:00
Timothy Jaeryang Baek e5b7188379 refac: ollama only param 2025-03-23 11:50:40 -07:00
Timothy Jaeryang Baek a00e5a0c0e Merge pull request #11988 from binxn/dev
Updated middleware.py to add OpenRouter compatibility
2025-03-23 11:48:21 -07:00
Timothy Jaeryang Baek c94a1ec8f8 Merge pull request #11989 from MaxJa4/dev
i18n: Translation for de-DE German
2025-03-23 11:47:15 -07:00
Timothy Jaeryang Baek c714bd8739 refac 2025-03-23 11:45:55 -07:00
MaxJa4 f2866ed858 Adjust naming 2025-03-23 17:35:28 +01:00
MaxJa4 137f16a160 Rename chats 2025-03-23 17:35:23 +01:00
MaxJa4 73715538ed Fix spelling error 2025-03-23 17:35:23 +01:00
MaxJa4 e4078a6aee Add new translations 2025-03-23 17:35:23 +01:00
binxn efd86e2cb4 Updated middleware.py to add OpenRouter compatibility 2025-03-23 17:14:20 +01:00
Yak! c1f189a602 Fix inconsistent value check. 2025-03-23 17:52:48 +09:00
Yuta Hayashibe d144592660 chore: Remove ENABLE_AUDIT_LOGS and set the AUDIT_LOG_LEVEL NONE 2025-03-23 11:34:04 +09:00
Timothy Jaeryang Baek 75b18f92b9 refac 2025-03-22 14:01:07 -07:00
Timothy Jaeryang Baek 07a15494e5 Merge pull request #11955 from jfbloom22/dev
fix: Improve error handling in ChromaDB delete function for non-existent collections
2025-03-22 12:46:01 -07:00
Jonathan Flower bdd236fa3a improved error handling for deleting collections that do not exist in chromadb 2025-03-22 09:59:06 -04:00
Yuta Hayashibe 966940cb00 feat: Added redirect parameter to /auth 2025-03-22 15:04:46 +09:00
Timothy Jaeryang Baek f872bda19b Merge pull request #11936 from softue/auth-redirect
fix: redirection for users already logged in
2025-03-21 12:33:52 -07:00
Timothy Jaeryang Baek 22f6e0f2f4 refac 2025-03-21 08:08:15 -07:00
Timothy Jaeryang Baek 8aa6dade41 Merge pull request #11876 from mahenning/fix--rag-sorting
Fix: wrong citation order for chromadb, wrong order for hybrid search
2025-03-20 17:54:22 -07:00
Timothy Jaeryang Baek d047eb46cc refac 2025-03-20 17:54:13 -07:00
Timothy Jaeryang Baek 87a06a1976 fix: file delete from knowledge not working with bypass embedding 2025-03-20 17:46:11 -07:00
Timothy Jaeryang Baek a28436237c refac 2025-03-20 17:42:50 -07:00
Timothy Jaeryang Baek 558295f728 Merge pull request #11862 from hurxxxx/feat/auto-edit-new-folder
feat: Automatically enter edit mode when creating a new folder
2025-03-20 17:40:37 -07:00
Timothy Jaeryang Baek ca43a4e97a Merge pull request #11926 from djismgaming/spanish-translation-20250320
i18n: update Spanish translation
2025-03-20 17:24:36 -07:00
djismgaming cbd11cffa0 chore: update translation.json 2025-03-20 18:11:33 -04:00
Timothy Jaeryang Baek 1813bb509b Merge pull request #11830 from hurxxxx/feat/chat-title-rename-enter-submit
feat: submit chat title rename with Enter, cancel with ESC
2025-03-20 14:03:59 -07:00
Timothy Jaeryang Baek 1d305e7b2f chore: format 2025-03-20 14:02:33 -07:00
Timothy Jaeryang Baek 9b20ef4922 refac 2025-03-20 14:01:47 -07:00
Timothy Jaeryang Baek f066eea92e Merge pull request #11899 from genjuro214/set-playwright-timeout
perf: set shorter timeout for playwright and make it configurable
2025-03-20 14:00:59 -07:00
Timothy Jaeryang Baek b96557c46e refac: styling 2025-03-20 13:55:13 -07:00
Timothy Jaeryang Baek 13220991a4 Merge pull request #11846 from hurxxxx/feat/sidebar-chat-search-clear-button
feat: add clear ("X") button to sidebar chat search input
2025-03-20 13:50:58 -07:00
Timothy Jaeryang Baek 132a332ac7 Merge pull request #11915 from Alluuu/i18n-add-estonian-language
i18n: Add Estonian et-EE translations
2025-03-20 13:50:23 -07:00
Timothy Jaeryang Baek 42f3e40065 Merge pull request #11911 from diwakar-s-maurya/patch-1
fix: error message propagation from filter-pipeline
2025-03-20 13:48:36 -07:00
Rômulo Mendes Figueiredo c4c6e02b4c fix: redirection for users already logged in 2025-03-20 16:05:26 -03:00
Alluuu 5b276471b3 Added Estonian language translations.
Tried to organize language list, following existing pattern as best, as I could tell: English first, Alphabetical languages, finished by Chinese and Doge
2025-03-20 18:42:45 +02:00
Diwakar 2bdf77a726 Fix error message propagate from pipelines
Error message returned from pipelines was not being shown on UI. It showed "Connection closed". With this fix it will show the error message on the UI from the pipeline properly.
2025-03-20 22:20:27 +07:00
genjuro 07098c6352 perf: set shorter timeout for playwright and make it configurable 2025-03-20 15:28:09 +08:00
Marko Henning 5f48af5b91 Revert the ordering change with chromadb, not necessary with reranker results 2025-03-19 17:04:45 +01:00
Timothy Jaeryang Baek 70550e41fc enh: user groups/permissions endpoint 2025-03-19 08:47:31 -07:00
Timothy Jaeryang Baek c69d1c86fe enh: apply file size limit to knowledge 2025-03-19 08:36:41 -07:00
Timothy Jaeryang Baek f806ab0bd2 refac 2025-03-19 08:32:31 -07:00
hurxxxx 18a8a375ab fix: Enter edit mode with text pre-selected 2025-03-20 00:27:53 +09:00
Marko Henning ec8fc727b8 Fix wrong order for chromadb 2025-03-19 16:06:10 +01:00
Timothy Jaeryang Baek 6ace00df24 Merge pull request #11839 from tcgumus/patch-2
Turkish language pack updates
2025-03-19 06:24:44 -07:00
Timothy Jaeryang Baek b4c00b2eb2 Merge pull request #11833 from aleixdorca/dev
Update Catalan translation.json
2025-03-19 06:24:23 -07:00
Timothy Jaeryang Baek 4b10051326 Merge pull request #11832 from TiancongLx/dev
i18n: update zh-TW
2025-03-19 06:24:15 -07:00
Timothy Jaeryang Baek 01c236ee59 Merge pull request #11826 from panda44312/patch-6
i18n: zh-cn
2025-03-19 06:24:09 -07:00
Timothy Jaeryang Baek f28bec876e Merge pull request #11853 from genjuro214/fix-issue-11847
fix: correct incorrect usage of log.exception method
2025-03-19 06:22:56 -07:00
hurxxxx 11f2aaf7b1 feat: Automatically enter edit mode when creating a new folder 2025-03-19 21:55:15 +09:00
leilibj 3e8546135d fix: correct incorrect usage of log.exception method 2025-03-19 13:04:34 +08:00
hurxxxx 70610f8343 feat: add clear ("X") button to sidebar chat search input 2025-03-19 11:25:16 +09:00
Timothy Jaeryang Baek 6c4352de07 fix: table cells format 2025-03-18 17:53:11 -07:00
Tuna Çağlar Gümüş d68a6227ad Turkish language pack updates 2025-03-19 00:15:39 +03:00
Aleix Dorca bda5e0af74 Update Catalan translation.json 2025-03-18 20:08:16 +01:00
Tiancong Li 05fa67ae8f i18n: update zh-TW 2025-03-19 02:54:51 +08:00
hurxxxx 2b687e2c06 Use consistent function names. 2025-03-19 02:23:30 +09:00
hurxxxx 3b624f35ac feat: submit chat title rename with Enter, cancel with ESC 2025-03-19 02:00:58 +09:00
Marko Henning 5ab789e83e Add documentation on chroma special case 2025-03-18 16:44:58 +01:00
Marko Henning ba676b7ed6 Use k_reranker also for result merge, and add special sorting use case for ChromaDB 2025-03-18 16:25:24 +01:00
Panda 87a3a893e2 i18n: zh-cn 2025-03-18 15:54:03 +01:00
Timothy Jaeryang Baek 62e63cffe7 Merge pull request #11804 from djismgaming/spanish-translation-20250317
i18n: translated new language pairs to Spanish
2025-03-18 13:44:45 +00:00
Timothy Jaeryang Baek 20128e6aa8 Merge branch 'dev' into spanish-translation-20250317 2025-03-18 13:44:32 +00:00
Timothy Jaeryang Baek 9a9a8a4b28 Merge pull request #11808 from FarisHijazi/dev
FIX #5682 dates not surviving importing
2025-03-18 13:43:41 +00:00
Timothy Jaeryang Baek b609b9d297 chore: format 2025-03-18 06:39:42 -07:00
Timothy Jaeryang Baek 3186aeac08 chore: format 2025-03-18 06:39:37 -07:00
Marko Henning f13948d805 Fixed typo 2025-03-18 12:14:59 +01:00
Marko Henning c877b59cbc Address edge case with k < k_reranker, sort results for cutting off 2025-03-18 11:31:17 +01:00
Jan Kessler e68cd9b671 Redis Sentinel support for AppConfig 2025-03-18 09:30:18 +01:00
Jan Kessler 9167a8bef0 refac as prep for sentinel support in AppConfig 2025-03-18 08:44:50 +01:00
Jan Kessler 9bf663934a fixes & add envs for Sentinel implementation 2025-03-18 07:49:57 +01:00
Jan Kessler 4370332e32 second part of adding Redis Sentinel support 2025-03-18 07:49:57 +01:00
Jan Kessler 3b357746d8 first part of adding Redis Sentinel support 2025-03-18 07:49:56 +01:00
Faris Hijazi eff1a23c19 fixed 5682 dates not surviving importing
Simply replaced the frontend svelte code that does the importing. One of
the keys were wrong, it was `convo['timestamp']` instead of
`convo['create_time']`
2025-03-18 09:23:52 +03:00
djismgaming e2f6cdcf31 translated new languague pairs to Spanish 2025-03-17 23:18:24 -04:00
Timothy Jaeryang Baek f5c5a4119f Merge pull request #11785 from SadmL/dev
[i18n] Almost full Russian localization (rebased)
2025-03-18 01:28:02 +00:00
Timothy Jaeryang Baek 47d5e21061 Merge pull request #11786 from taylorwilsdon/scroll_enh
fix: Better visibility for scroll bar in webkit browsers
2025-03-18 01:25:58 +00:00
SadmL 9a55071d65 Update translation.json 2025-03-17 20:02:22 +03:00
Taylor Wilsdon 1119b06678 Widen scrollbar so that it can be clicked and dragged with a mouse or trackpad 2025-03-17 13:00:55 -04:00
Timothy Jaeryang Baek 54d5281256 refac 2025-03-15 18:41:04 +00:00
Timothy Jaeryang Baek 0777ab7011 refac 2025-03-15 18:28:02 +00:00
Timothy Jaeryang Baek d8eade736f refac 2025-03-15 18:23:40 +00:00
Timothy Jaeryang Baek b6e56c0e5a refac 2025-03-15 18:00:18 +00:00
Timothy Jaeryang Baek cfb2319923 refac: disable autocompletion by default 2025-03-15 17:40:39 +00:00
Timothy Jaeryang Baek 7de88cc4eb refac 2025-03-15 17:19:22 +00:00
Timothy Jaeryang Baek 10b9fa6ed0 refac 2025-03-15 17:16:19 +00:00
Timothy Jaeryang Baek 4f5aba8be7 refac 2025-03-15 17:13:40 +00:00
Timothy Jaeryang Baek d93828e923 enh: client-side pdf generation 2025-03-15 17:11:14 +00:00
Timothy Jaeryang Baek c57db1828f fix 2025-03-15 16:25:21 +00:00
Timothy Jaeryang Baek b5e74f4eae refac 2025-03-15 16:15:37 +00:00
Timothy Jaeryang Baek c8d02aafd9 Merge pull request #11697 from foraxe/fix-keep-alive-top-level
fix: Promote keep_alive to top-level in payload for Ollama API (dev branch)
2025-03-15 14:43:27 +00:00
Timothy Jaeryang Baek f1a84f45c8 Merge pull request #11699 from shaun-gallagher-octane/markdown-alert-renderer
feat: Markdown alert renderer
2025-03-15 02:12:16 +00:00
Timothy Jaeryang Baek 0551b90d47 Merge pull request #11611 from nikes/feat/pip-options
feat: pip options in tools/functions install requirements
2025-03-15 02:07:31 +00:00
Timothy Jaeryang Baek 2de03494a6 Merge pull request #11647 from kaytwo/multiline-valves
feat: allow string valves to include newlines
2025-03-15 02:05:56 +00:00
Timothy Jaeryang Baek aa37866798 chore: pyodide bump 2025-03-15 02:04:18 +00:00
Timothy Jaeryang Baek 7723705707 enh: always collapse code block 2025-03-15 02:01:59 +00:00
Timothy Jaeryang Baek dbf051ff4e enh: always expand details option 2025-03-15 01:56:04 +00:00
Shaun Gallagher 2065580a5f feat: Use AlertRenderer in blockquote evaluation 2025-03-14 15:22:56 -04:00
Shaun Gallagher 8bc797fe6a feat: Add renderer for Markdown alerts 2025-03-14 15:22:27 -04:00
foraxe 04046ed6c8 Alternative Temp Fix: Uncomment to Keep Alive Forever 2025-03-15 00:27:20 +08:00
foraxe 53448b3f0a Fix: Promote keep_alive to top-level in payload for Ollama API on dev branch 2025-03-15 00:08:05 +08:00
Timothy Jaeryang Baek 74da9c4e54 fix: firefox input height issue 2025-03-14 12:50:33 +00:00
Timothy Jaeryang Baek 4b1899bfca chore: dependency 2025-03-14 12:35:33 +00:00
Timothy Jaeryang Baek 8588b52fd6 Merge pull request #11605 from melroy89/update_fake_useragent
dependency: Update fake-useragent to v2.1.0
2025-03-14 11:52:30 +00:00
Timothy Jaeryang Baek 4025d61c33 Merge pull request #11636 from OliveiraHermogenes/fix-api-audio-mimetype-check
fix: audio api endpoint filetype check
2025-03-14 11:52:12 +00:00
Chris Kanich 53292e7d12 allow string valves to include newlines 2025-03-13 12:04:13 -05:00
Nikes b6664f5ae8 feat: pip options in tools/functions install requirements 2025-03-12 23:15:26 +02:00
Melroy van den Berg b02e6c6734 Deps: Update fake-useragent to v2.1.0 2025-03-12 20:41:51 +01:00
Timothy Jaeryang Baek d84e7d13d0 refac 2025-03-11 20:49:14 +00:00
Timothy Jaeryang Baek c309412980 enh: connection tags 2025-03-11 20:37:30 +00:00
Timothy Jaeryang Baek b427f506f6 fix 2025-03-11 20:12:34 +00:00
Timothy Jaeryang Baek ad51b0166c refac 2025-03-11 20:12:28 +00:00
Timothy Jaeryang Baek e1168139a6 refac 2025-03-11 19:30:09 +00:00
Timothy Jaeryang Baek 9e2fb73440 Merge pull request #11550 from silentoplayz/highlight-selected
feat: improve model dropdown highlight
2025-03-11 18:57:20 +00:00
Timothy Jaeryang Baek adfa67d9d2 Merge pull request #11507 from OrenZhang/feat_ot
feat(trace): opentelemetry instrument
2025-03-11 18:55:56 +00:00
Timothy Jaeryang Baek 396c28817c refac 2025-03-11 18:55:30 +00:00
Timothy Jaeryang Baek 7e0c5a44e3 Merge pull request #11552 from icsy7867/dev
Fixed knowledgebase view for decodeURIComponent
2025-03-11 18:53:17 +00:00
root 6fc9c69b9f Fixed knowledgebase view for decodeURIComponent 2025-03-11 14:44:04 -04:00
Timothy Jaeryang Baek 9adc1ebcc8 refac 2025-03-11 18:38:13 +00:00
Timothy Jaeryang Baek 6399aaf4b2 Merge pull request #11515 from davizucon/main
fix: url value when response contains url tag
2025-03-11 18:37:05 +00:00
Timothy Jaeryang Baek 16c383ab44 Merge pull request #11498 from tcgumus/patch-2
Add SSL Integration Comments and WebSocket Auto-Fix in start_windows.bat
2025-03-11 18:34:54 +00:00
Timothy Jaeryang Baek 8905d9e63b Merge pull request #11526 from rragundez/exlude-images-from-embeddings
Exlude images from embeddings
2025-03-11 18:32:38 +00:00
Timothy Jaeryang Baek 64fa37c15d Merge pull request #11545 from hurxxxx/fix/reset-taskId-after-conversation
fix: Reset taskId after completion to prevent incorrect cancellation behavior
2025-03-11 18:29:59 +00:00
Silentoplayz 2c99366543 feat: improve model dropdown highlight 2025-03-11 13:57:09 -04:00
Davi S. Zucon b1224b6839 fix code format 2025-03-11 12:40:31 -03:00
Davi S. Zucon 453200ca1e fix code format
fix code format
2025-03-11 12:39:15 -03:00
hurxxxx 1160e21d45 fix: reset taskId after conversation to prevent incorrect cancellation behavior 2025-03-11 21:18:53 +09:00
Timothy Jaeryang Baek 0e7164b4f5 Merge pull request #11520 from icsy7867/main
Added decodeURIcomponent function to several locations.
2025-03-11 10:33:41 +00:00
Rodrigo Agundez ac321f4b64 Add check if images and avoid trying to calculate embeddings 2025-03-11 12:50:44 +08:00
orenzhang 7bfda6652f feat(trace): optimize for trace env and instrument hooks 2025-03-11 11:53:03 +08:00
root 3fb477618e Added decodeURIcomponent function to several locations. 2025-03-10 17:40:40 -04:00
Tuna Çağlar Gümüş 9e7193b3d2 Update start_windows.bat 2025-03-10 22:37:57 +03:00
Davi S. Zucon 846509bf9f fix url value when response contains url tag
When the response contains b64 json, the "url" tag still exists but comes as null, the logic is to resolve this point where it contains the url tag, but empty, thus directing to b64_json
2025-03-10 15:59:08 -03:00
orenzhang c761e4fd08 feat(trace): opentelemetry instrument 2025-03-10 22:27:31 +08:00
Marko Henning 8b5b3f165a Add translation (partially) 2025-03-10 12:35:44 +01:00
Timothy Jaeryang Baek c2046b9247 refac 2025-03-10 11:16:30 +00:00
Tuna Çağlar Gümüş c5efeb2499 Add SSL Integration Comments and WebSocket Auto-Fix in start_windows.bat
This PR enhances the start_windows.bat script by:

Adding comments for SSL integration, making it easier for users to enable SSL when needed.
Including the -ws auto flag to address WebSocket-related issues, ensuring a smoother experience for users facing connection problems.
These improvements make the script more user-friendly and help troubleshoot common setup challenges.
2025-03-10 13:39:59 +03:00
Timothy Jaeryang Baek 116e0559f6 refac: oauth 2025-03-10 09:42:59 +00:00
Timothy Jaeryang Baek 428d89784b Merge pull request #11484 from xinhai-ai/mobile_touch
fix: mobile touch
2025-03-10 06:27:35 -03:00
星海 077c805880 fix: mobile touch 2025-03-10 15:43:53 +08:00
Timothy Jaeryang Baek 352ed67667 refac: prompt template behaviour 2025-03-10 01:15:45 +00:00
Timothy Jaeryang Baek ec29772068 refac: styling 2025-03-09 23:58:48 +00:00
Timothy Jaeryang Baek 3cc44b9de5 Merge pull request #11460 from silentoplayz/horizontal-scrol-tags2
feat: Horizontal scroll for tags in model dropdown selector
2025-03-09 20:58:05 -03:00
Timothy Jaeryang Baek f8ac44cfbd Merge pull request #11464 from FabioPolito24/docling_context_extraction_engine
feat: Docling context extraction engine
2025-03-09 20:57:48 -03:00
Timothy Jaeryang Baek 0c5a1e84e3 Merge pull request #11472 from thiswillbeyourgithub/better_frontmatter_pip_install3
fix: install all the requirements at the same time
2025-03-09 20:57:06 -03:00
Timothy Jaeryang Baek 1fe4d49ac6 Merge pull request #11466 from captn-hook/dev
fix: opensearch environment variables fix
2025-03-09 20:56:34 -03:00
Timothy Jaeryang Baek 41a83f1dc5 refac: code update behaviour 2025-03-09 23:49:26 +00:00
thiswillbeyourgithub 9e41b8b024 fix: install all the requirements at the same time
Signed-off-by: thiswillbeyourgithub <26625900+thiswillbeyourgithub@users.noreply.github.com>
2025-03-09 23:38:23 +01:00
Tristan H 4c98508c0b Merge pull request #3 from open-webui/dev
Dev
2025-03-09 09:51:31 -07:00
Tristan H 084e2caf6f Update config.py to correctly handle environment strings
As seen in line 1536 just above this, strings need to be converted to bools in order to work.
2025-03-09 09:48:35 -07:00
Timothy Jaeryang Baek a75f82755d Update bug_report.yaml 2025-03-09 09:48:35 -07:00
Timothy Jaeryang Baek c1d2e0d999 refac 2025-03-09 09:48:35 -07:00
Timothy Jaeryang Baek 165e861a1d Create config.yaml 2025-03-09 09:48:35 -07:00
Timothy Jaeryang Baek fc056b1397 Update bug_report.yaml 2025-03-09 09:48:35 -07:00
Fabio Polito de0f158b04 Merge remote-tracking branch 'upstream/dev' into docling_context_extraction_engine
merge upstream dev
2025-03-09 16:12:43 +00:00
Fabio Polito 9d6743824e fix: fix params DoclingLoader 2025-03-09 16:12:14 +00:00
Silentoplayz ae1f0f0a3c feat: horizontal scroll for model dropdown tags 2025-03-09 11:41:14 -04:00
Timothy Jaeryang Baek cdb5eae43a refac 2025-03-09 15:05:13 +00:00
Timothy Jaeryang Baek 26980fb859 refac 2025-03-09 15:01:36 +00:00
Timothy Jaeryang Baekandrecrudesce 53a2acd541 enh: local, external, direct model list filter
Co-Authored-By: recrudesce <6450799+recrudesce@users.noreply.github.com>
2025-03-09 15:00:13 +00:00
Timothy Jaeryang Baek c58f0844a3 refac 2025-03-09 14:48:11 +00:00
Timothy Jaeryang Baek 5cc43ae880 enh: image panzoom 2025-03-09 14:39:54 +00:00
Timothy Jaeryang Baek 1c211e32b3 refac 2025-03-09 11:18:28 +00:00
Timothy Jaeryang Baek 0dce81f646 Merge pull request #11423 from silentoplayz/confirmation-prompts
feat: add more confirmation prompts
2025-03-09 07:40:36 -03:00
Timothy Jaeryang Baek b8863545d5 Merge pull request #11428 from silentoplayz/sticky-tags
feat: Sticky tags
2025-03-09 07:32:05 -03:00
Timothy Jaeryang Baek 36dd630057 Merge pull request #11444 from open-webui/main
dev
2025-03-09 07:31:02 -03:00
Silentoplayz 1de142f435 sticky tags 2025-03-08 18:00:06 -05:00
Hermógenes Oliveira e936d7b53d fix: audio api endpoint filetype check
RFC2046 allows the Content-Type field to have additional parameters
after the main type/subtype information (Section 1).

Following RFC4281, many applications put codec information inside
parameters in the Content-Type. This is especially common for formats
that support many codecs, such as Ogg (RFC5334, Section 4).

The `/api/audio/transcriptions` endpoint is currently rejecting files
that contain parameters in the Content-Type field with a bad request
error.

This commit changes the current check in order to accept any
Content-Type field that begins with a supported type/subtype as listed
in the `supported_filetypes` tuple.

Since Content-Type here is provided by the user, I believe this check
is meant to prevent honest mistakes, like posting a PDF to an audio
processing endpoint, not as a security measure against possibly
malicious use. Therefore, I think it's OK not to validate the rest of
the field.
2025-03-08 18:03:30 -03:00
Fabio Polito 0aa42615f9 Merge remote-tracking branch 'upstream/dev' into docling_context_extraction_engine
merge upstream
2025-03-08 18:52:51 +00:00
Silentoplayz d669932137 add confirmation prompts 2025-03-08 13:42:24 -05:00
Timothy Jaeryang Baek 6b806ae12f Merge pull request #11413 from hurxxxx/fix/global-filter-cannot-disable
fix: Prevent modification of global filter settings in "Admin panel" - "Settings" - "Models"
2025-03-08 14:15:47 -04:00
Timothy Jaeryang Baek b03fc97e28 Update bug_report.yaml 2025-03-08 18:13:28 +00:00
Timothy Jaeryang Baek d7bfa395b0 refac 2025-03-08 18:10:34 +00:00
Timothy Jaeryang Baek 67cd4f2ab1 Create config.yaml 2025-03-08 18:08:51 +00:00
Timothy Jaeryang Baek dc78d2f758 Update bug_report.yaml 2025-03-08 18:06:08 +00:00
Timothy Jaeryang Baek d40e696468 enh: multiple replica app state sync 2025-03-08 17:59:15 +00:00
Timothy Jaeryang Baek 324cd94c53 refac: user message delete 2025-03-08 17:03:08 +00:00
Timothy Jaeryang Baek 4e36b9794f fix: logit bias issue 2025-03-08 16:50:30 +00:00
Timothy Jaeryang Baek 58ff221d1f refac 2025-03-08 16:48:32 +00:00
Timothy Jaeryang Baek 1e36282708 refac 2025-03-08 16:23:20 +00:00
Timothy Jaeryang Baek 22b88f9593 Merge pull request #11324 from kela4/main
fix: opensearch vector db query structures, result mapping, filters, bulk query actions, knn_vector usage
2025-03-08 12:19:38 -04:00
Timothy Jaeryang Baek e4a79a0b0e Merge pull request #11394 from dannyl1u/fix/logit-bias-workspace-models
fix: logit_bias bug in workspace models
2025-03-08 12:11:53 -04:00
Timothy Jaeryang Baek 8375c2c32d Merge pull request #11397 from luke3butler/tavily-extract-depth
feat: Add environment variable to configure tavily extract depth
2025-03-08 12:11:37 -04:00
Timothy Jaeryang Baek e7013d45c5 Merge pull request #11409 from chengscott/patch-1
[feat] anonymous bind when LDAP_APP_DN is not specified
2025-03-08 12:11:13 -04:00
Timothy Jaeryang Baek ac507720c8 Merge pull request #11401 from TiancongLx/dev
i18n: update zh-TW
2025-03-08 12:10:58 -04:00
Timothy Jaeryang Baek d59433bf7e refac 2025-03-08 15:48:09 +00:00
hurxxxx 40257afeed fix: Using disabled attribute for elements is common 2025-03-09 00:12:37 +09:00
hurxxxx 851931fdf6 fix: Global filter cannot be modified in the model (changes have no effect) 2025-03-08 23:24:52 +09:00
Scott Cheng 8bd527be6a anonymous bind when LDAP_APP_DN is not specified 2025-03-08 21:19:21 +08:00
Tiancong Li e5b02f732b i18n: update zh-TW 2025-03-08 16:18:22 +08:00
Luke 7c4a9c2aea fix: correct type handling for TAVILY_EXTRACT_DEPTH configuration 2025-03-08 01:07:06 -05:00
Luke 7917128ed3 enh: enable configuration for tavily extract depth 2025-03-08 00:43:02 -05:00
dannyl1u 3c6a834ff4 fix: logit_bias in workspace models 2025-03-07 19:54:06 -08:00
Timothy Jaeryang Baek dc3abc2bcb refac 2025-03-08 00:13:58 +00:00
Timothy Jaeryang Baek 3ab917cdd0 Merge pull request #11325 from luke3butler/dev
feat: Add `tavily` as a `RAG_WEB_LOADER_ENGINE` option via extract API
2025-03-07 20:11:39 -04:00
Timothy Jaeryang Baek e3116aac76 Merge pull request #11361 from OriginalSimon/dev
18n: Update Ukrainian translation
2025-03-07 19:59:42 -04:00
Timothy Jaeryang Baek e85d69fe60 Merge branch 'dev' into dev 2025-03-07 19:59:33 -04:00
Timothy Jaeryang Baek 027c5c4b72 Merge pull request #11383 from Kylapaallikko/dev
i18n: Update Finnish Translation
2025-03-07 19:59:03 -04:00
Timothy Jaeryang Baek 88303093c0 Merge pull request #11384 from Peter-De-Ath/hotfix/tool-calls-params
fix: bug where default params in tools calls always used
2025-03-07 19:58:05 -04:00
Peter De-Ath 7e3be60f0e formating 2025-03-07 20:37:22 +00:00
Peter De-Ath 3b39807377 fix: updatepost_response_handler nativ tools handler to use parameters from properties fixing defaults always used 2025-03-07 20:07:36 +00:00
Kylapaallikko 17a4360566 Update translation.json 2025-03-07 19:44:56 +02:00
Timothy Jaeryang Baek 7a1cf1095a Merge pull request #11358 from OrenZhang/i18n_translation
i18n(common): add i18n translation
2025-03-07 13:33:59 -04:00
Timothy Jaeryang Baek ab92737a9a refac 2025-03-07 17:24:52 +00:00
Simon 27a6d1917d Update translation.json 2025-03-07 13:48:56 +01:00
Simon 25544b38bd Merge branch 'open-webui:dev' into dev 2025-03-07 13:42:46 +01:00
Simon cf449d1c7e Update translation.json 2025-03-07 13:42:05 +01:00
Simon 20826e15b3 Update translation.json 2025-03-07 13:31:56 +01:00
Timothy Jaeryang Baek d7a0437438 refac: model sort list 2025-03-07 12:16:16 +00:00
orenzhang b61ea393b4 refactor(lint): code lint 2025-03-07 20:03:53 +08:00
orenzhang dc04123330 Merge branch 'dev' into i18n_translation 2025-03-07 20:03:33 +08:00
orenzhang 72ea6dd9f1 refactor(lint): code lint 2025-03-07 19:59:09 +08:00
Timothy Jaeryang Baek f8f54237c6 Merge pull request #11290 from panda44312/patch-5
i18n: Update zh-cn
2025-03-07 06:06:40 -04:00
Timothy Jaeryang Baek 04921be9f1 Merge pull request #11287 from Youggls/dev
fix(chat): resolve duplicate collapsible IDs causing citation modal failures
2025-03-07 06:05:13 -04:00
Fabio Polito 1a066c0357 fix: fixed lock and pyproject 2025-03-07 00:32:02 +00:00
Fabio Polito 09ccd000d8 fix: fixing lock and pyproject 2025-03-07 00:27:59 +00:00
Fabio Polito e3eef58310 feat: merge with dev 2025-03-07 00:22:47 +00:00
Fabio Polito 17dbb3ec57 fix: fix typo 2025-03-07 00:19:26 +00:00
Peter De-Ath d862295a05 fix: update chat completion tools handler to use parameters from spec fixing defaults always used 2025-03-06 23:27:52 +00:00
Luke 987954c817 feat: Add Tavily extract web loader integration 2025-03-06 18:15:18 -05:00
Katharina 6cb0c0339a fix: opensearch vector db query structures, result mapping, filters, bulk query actions, knn_vector usage 2025-03-06 23:49:54 +01:00
wangtunan 7d1a094f9b fix: stopTask func need use async/await syntax 2025-03-07 00:07:04 +08:00
wangtunan 533c99e384 fix: stopTask func need use async/await syntax 2025-03-06 23:56:41 +08:00
orenzhang 92fb1109b6 i18n(common): add i18n translation 2025-03-06 20:16:34 +08:00
Fabio Polito 98857184ff Merge remote-tracking branch 'upstream/dev' into docling_context_extraction_engine
merge with dev branch
2025-03-06 12:12:50 +00:00
Panda 98376fbbce i18n: zh-cn 2025-03-06 13:08:35 +01:00
Panda 561f4d5d69 i18n: zh-cn 2025-03-06 11:26:04 +01:00
Perry Li 9cc9df3018 fix(chat): resolve duplicate collapsible IDs causing citation modal failures
Fix an issue where clicking inline citations in subsequent chat messages failed to open the citation modal when multiple collapsible sections are present.

The root cause was duplicate "collapsible-sources" IDs assigned to all Collapsible components. This led document.getElementById() to always return the first instance, preventing subsequent messages from opening their CitationModal.

Changes:
- Modify Collapsible ID generation in Citations.svelte to use unique IDs with "collapsible-${message.id}" pattern
- Update ResponseMessage.svelte's onSourceClick handler to reference the dynamic collapsible IDs
- Ensure proper citation modal binding for each chat message's sources

Affected components:
- Collapsible (expandable content sections)
- CitationsModal (citation detail popup)

This ensures each chat message's sources are independently collapsible and maintains proper citation modal binding throughout message history.
2025-03-06 10:10:53 +00:00
Marko Henning 41a4cf7106 Added new k_reranker parameter 2025-03-06 10:47:57 +01:00
Timothy Jaeryang Baek 3b70cd64d7 Merge pull request #11257 from open-webui/dev
0.5.20
2025-03-05 19:44:45 -08:00
Timothy Jaeryang Baek 1173459eee doc: changelog 2025-03-05 19:42:41 -08:00
Timothy Jaeryang Baek c0ecff9d70 fix: pinyin keyboard 2025-03-05 19:36:30 -08:00
Timothy Jaeryang Baek d4fca9dabf chore: format 2025-03-05 19:17:41 -08:00
Timothy Jaeryang Baek aaaebfabbe chore: format 2025-03-05 19:16:59 -08:00
Timothy Jaeryang Baek 6eccf8668e fix: non-root container issue 2025-03-05 19:14:43 -08:00
Timothy Jaeryang Baekandrecrudesce 5e78a5c510 enh: enable_code_execution toggle
Co-Authored-By: recrudesce <6450799+recrudesce@users.noreply.github.com>
2025-03-05 19:06:28 -08:00
Timothy Jaeryang Baek dce24225e0 Merge pull request #11249 from TiancongLx/dev
i18n: update zh-TW
2025-03-05 18:52:34 -08:00
Timothy Jaeryang Baek f9b44c6bf2 refac 2025-03-05 18:39:32 -08:00
Timothy Jaeryang Baek f573a90a56 Merge pull request #11254 from open-webui/main
dev
2025-03-05 18:11:18 -08:00
Timothy Jaeryang Baek 23bb0d927f chore: format 2025-03-05 18:10:24 -08:00
Fabio Polito 2982893d0d fix: format fixes 2025-03-06 00:39:00 +00:00
Tiancong Li 6b0af942db i18n: update zh-TW 2025-03-06 07:23:55 +08:00
Fabio Polito 0716f96da8 style: change style in DoclingLoader 2025-03-05 23:15:55 +00:00
Timothy Jaeryang Baek f95a482c24 Merge pull request #11209 from aleixdorca/dev
Update catalan translation.json
2025-03-05 14:56:37 -08:00
Timothy Jaeryang Baek edf94d732b refac 2025-03-05 14:54:48 -08:00
Fabio Polito 9aa407dbd2 feat: merge with main 2025-03-05 22:04:34 +00:00
Timothy Jaeryang Baek 73a77abd20 Merge pull request #11245 from tupe2009/kleqon.fix-es-bugs
fix: ElasticSearch indexes delete and upsert bugs(Post 0.5.19 release)
2025-03-05 13:36:55 -08:00
ofek a8f205213c fixed es bugs 2025-03-05 23:19:56 +02:00
Fabio Polito a44b35e99e fix: fix DoclingLoader input params 2025-03-05 17:53:45 +00:00
Timothy Jaeryang Baek 4770285c04 Merge pull request #11211 from open-webui/dev
fix: site.webmanifest
2025-03-05 00:45:21 -08:00
Timothy Jaeryang Baek 1639fbb544 fix: site.webmanifest 2025-03-05 00:45:04 -08:00
Aleix Dorca 2dc5f3c30c Update catalan translation.json 2025-03-05 08:42:16 +01:00
Timothy Jaeryang Baek 1a51584fe0 Merge pull request #10939 from open-webui/dev
0.5.19
2025-03-04 22:22:20 -08:00
Timothy Jaeryang Baek 976c94ba5a chore: pyproject 2025-03-04 22:13:51 -08:00
Timothy Jaeryang Baek 4df74690e1 doc: changelog 2025-03-04 22:10:51 -08:00
Timothy Jaeryang Baek e2d60bd92e chore: format 2025-03-04 22:10:47 -08:00
Timothy Jaeryang Baek c2eada36f1 Merge pull request #10898 from hurxxxx/fix/update-msal-browser-version
fix: update msal browser version
2025-03-04 21:56:22 -08:00
Timothy Jaeryang Baek 0ce6975ec8 chore: bump 2025-03-04 21:49:42 -08:00
Timothy Jaeryang Baek 1ddc56fcf8 Merge pull request #11201 from open-webui/main
dev
2025-03-04 21:43:33 -08:00
Timothy Jaeryang Baek 7f7365db4f Merge pull request #11132 from dongs0104/dev
fix: email claim constant
2025-03-04 21:39:28 -08:00
Timothy Jaeryang Baek c9e2ba56c6 Merge pull request #11198 from xinhai-ai/refa_filters
chore: move the filter_type check earlier to avoid unnecessary valve reads.
2025-03-04 21:27:36 -08:00
Timothy Jaeryang Baek b01c9184c2 chore: format 2025-03-04 21:24:17 -08:00
星海 3ee1ae8c95 refac: filters 2025-03-05 13:05:14 +08:00
星海 8ce6c8cf78 refac: filters 2025-03-05 13:00:45 +08:00
Timothy Jaeryang Baek fbf4f5eb30 refac 2025-03-04 18:19:05 -08:00
Timothy Jaeryang Baek 6c77e6fdb3 refac 2025-03-04 18:08:43 -08:00
Timothy Jaeryang Baek 3b74431ea3 refac: filters 2025-03-04 18:04:55 -08:00
Timothy Jaeryang Baek 53fe7c460b Merge pull request #11178 from silentoplayz/fix
chore: Update ToolkitEditor.svelte
2025-03-04 17:53:47 -08:00
Timothy Jaeryang Baek f39556b933 Merge pull request #11163 from tidely/pathfix
chore: Use platform specific path separators
2025-03-04 17:53:21 -08:00
Timothy Jaeryang Baek cffd02defe Merge pull request #11153 from panda44312/patch-4
i18n: update ZH-CN
2025-03-04 17:42:05 -08:00
Timothy Jaeryang Baek bdc6088159 Merge pull request #11151 from TiancongLx/dev
i18n: update zh-TW
2025-03-04 17:41:57 -08:00
Timothy Jaeryang Baek 2a75a85556 refac 2025-03-04 17:40:32 -08:00
Silentoplayz 94c025c6d7 Update ToolkitEditor.svelte
fix
2025-03-04 17:46:24 -05:00
Timothy Jaeryang Baek 8961bc2453 Merge pull request #11173 from TFWol/patch-2
chore: Revamp Feature Request template
2025-03-04 13:49:07 -08:00
TFWol cb82c7062a Revamp Feature Request template 2025-03-04 11:18:50 -08:00
tidely b15814c42f chore: remove unnecessary Path conversions
Remove unnecessary `pathlib.Path` conversions. (CACHE_DIR and DATA_DIR)

Use `/` Path joining shorthand to ensure using platform specific Path separators (Windows: \\, Unix: /)
2025-03-04 19:53:52 +02:00
Panda 023c8bb5b4 i18n: zh-cn Update 2025-03-04 16:08:06 +01:00
Tiancong Li 500440ebec i18n: update zh-TW 2025-03-04 22:51:24 +08:00
Timothy Jaeryang Baek b94de4f002 refac 2025-03-04 02:45:05 -08:00
Timothy Jaeryang Baek 039a1e1f14 refac: assets 2025-03-04 01:47:17 -08:00
Timothy Jaeryang Baek 14a6c1f496 refac: favicon 2025-03-04 01:30:22 -08:00
Timothy Jaeryang Baek 0a295ff56d refac: icons 2025-03-04 01:25:47 -08:00
Timothy Jaeryang Baek 36ffa9824b refac 2025-03-04 01:16:25 -08:00
Timothy Jaeryang Baek e3769c1073 refac 2025-03-04 01:16:08 -08:00
Timothy Jaeryang Baek d78fe4decc Merge pull request #11073 from vincent-thevenin/dev
fix: fix issue with call voice recording starting before voice detection
2025-03-04 00:55:03 -08:00
Timothy Jaeryang Baek 7b442e4be0 Merge pull request #11141 from Youggls/dev
fix: correct parameter name for MilvusClient instantiation
2025-03-04 00:54:49 -08:00
Timothy Jaeryang Baek d17ac95f95 Merge pull request #11143 from panda44312/patch-3
i18n: zh-cn
2025-03-04 00:53:31 -08:00
Panda 59c3203990 IUpdate translation.json 2025-03-04 09:48:03 +01:00
Timothy Jaeryang Baek a4747c88e0 refac 2025-03-04 00:33:19 -08:00
Timothy Jaeryang Baek 39ea59edc8 chore: format 2025-03-04 00:32:27 -08:00
Perry Li 67ed61d022 fixbug: correct parameter name for MilvusClient instantiation
Replace incorrect parameter 'database=MILVUS_DB' with valid 'db_name=MILVUS_DB'
2025-03-04 16:02:19 +08:00
Dong Shin b8f3abda5a fix: email claim constant 2025-03-04 15:50:04 +09:00
Timothy Jaeryang Baek 8697f72068 refac: styling 2025-03-03 22:44:03 -08:00
Timothy Jaeryang Baek 3e7077bb73 refac 2025-03-03 22:24:19 -08:00
Timothy Jaeryang Baek 5f89c1b137 enh: model selector tag filter 2025-03-03 21:47:27 -08:00
Timothy Jaeryang Baek 811e1f92b1 refac 2025-03-03 21:27:48 -08:00
Timothy Jaeryang Baek 15cbccc8f5 enh: code block collapse 2025-03-03 21:10:15 -08:00
Timothy Jaeryang Baek 1cfa491179 Merge pull request #10868 from tidely/loggingnamemap
chore: use logging.getLevelNamesMapping() for validating log level
2025-03-03 20:55:22 -08:00
Timothy Jaeryang Baek 35e7e07821 refac: cuda error gc 2025-03-03 20:55:07 -08:00
Timothy Jaeryang Baek 9ff54288ef refac 2025-03-03 20:53:14 -08:00
Timothy Jaeryang Baek baca6db680 Merge pull request #10987 from alpha-pet/feat-submit-on-ctrl-enter
feat: add alternative input configuration where Ctrl-Enter is required to send chat messages
2025-03-03 20:39:53 -08:00
Timothy Jaeryang Baek 6bd2bc5683 refac 2025-03-03 20:34:45 -08:00
Timothy Jaeryang Baek 029625ec4e refac 2025-03-03 20:34:17 -08:00
Timothy Jaeryang Baek 7e65f7fa4d fix: chat event handler not being registered on sign in 2025-03-03 20:31:35 -08:00
Timothy Jaeryang Baek 80f5573cf3 refac: AIOHTTP_CLIENT_TIMEOUT_MODEL_LIST 2025-03-03 20:24:10 -08:00
Timothy Jaeryang Baek 1236157800 fix: timestamp missing in edited user message 2025-03-03 20:21:39 -08:00
Timothy Jaeryang Baek e628bfe6ff fix 2025-03-03 20:16:40 -08:00
Timothy Jaeryang Baek bb2bd7d721 Merge pull request #11120 from OrenZhang/fix_jupyter
fix(jupyter): fix kernel_id not set and optimize code
2025-03-03 20:15:09 -08:00
Timothy Jaeryang Baek 9c107f9d2d refac: images "url" fallback 2025-03-03 20:07:59 -08:00
orenzhang fafd847f18 refactor(jupyter): change log message for execution failed 2025-03-04 12:01:08 +08:00
orenzhang 3a7e5a5f31 feat(jupyter): check response status for destroy kernel 2025-03-04 12:00:04 +08:00
orenzhang 613d278afc refactor(jupyter): change log level 2025-03-04 11:58:32 +08:00
orenzhang 96e0c4d7b8 refactor(jupyter): replace httpx with aiohttp 2025-03-04 11:56:11 +08:00
Timothy Jaeryang Baek 46cea1f904 fix: ldap email case sensitive 2025-03-03 19:52:27 -08:00
Timothy Jaeryang Baek d844fc7edb refac: inline citation handling 2025-03-03 19:48:00 -08:00
Timothy Jaeryang Baek 3468dda556 refac: rm unused api endpoint 2025-03-03 19:33:55 -08:00
Timothy Jaeryang Baek e6ff4169e1 Merge pull request #11066 from NibbinNone/dev
feat: add support for reasoning_content
2025-03-03 16:37:28 -08:00
Timothy Jaeryang Baek 6f8c1a8f0d Merge pull request #11089 from tupe2009/kleqon.feat-add-elasticsearch-support
feat: Elasticsearch as a vector store support
2025-03-03 16:34:39 -08:00
Timothy Jaeryang Baek d529be86fe Merge pull request #11109 from panda44312/patch-2
i18n: Update zh-cn
2025-03-03 16:34:21 -08:00
Panda 3ad4b10470 i18n: Update zh-cn 2025-03-04 00:17:02 +01:00
Timothy Jaeryang Baek 376fce273e Merge pull request #11079 from MeteorSkyOne/dev
fix: allow error returns None
2025-03-03 14:57:54 -08:00
Timothy Jaeryang Baek c19960002b Merge pull request #11086 from aindriu80/main
(i18n)Updated Irish translations
2025-03-03 14:57:01 -08:00
Timothy Jaeryang Baek dc2b8fd327 Merge branch 'dev' into main 2025-03-03 14:56:48 -08:00
ofek 737dfd2763 added elasticsearch support 2025-03-03 23:39:42 +02:00
tarmst 1ad80490de Add read/write access control for files from knowledge 2025-03-03 20:03:21 +00:00
Aindriú Mac Giolla Eoin 3fa323d1a1 Updated Irish translations 2025-03-03 18:41:11 +00:00
MeteorSky a01ef6cfa0 fix: allow error returns None 2025-03-04 00:08:49 +08:00
Timothy Jaeryang Baek c7d4d2e41f Merge pull request #11067 from TiancongLx/dev
i18n: update zh-TW (fix typo)
2025-03-03 06:49:27 -08:00
orenzhang 744ffbb1fb fix(jupyter): fix kernel_id not set and optimize code 2025-03-03 22:18:02 +08:00
vincent-thevenin 4d6132b9de fix: fix issue with call voice recording starting before voice detection 2025-03-03 13:59:28 +01:00
Tiancong Li 7a31ff6a2f i18n: update zh-TW (fix typo) 2025-03-03 16:55:37 +08:00
CorbinChen 516f1cf67b feat: add support for reasoning_content 2025-03-03 16:47:35 +08:00
Timothy Jaeryang Baek 3d6e48b05e Merge pull request #11043 from TiancongLx/dev
i18n: update zh-TW
2025-03-02 12:16:56 -08:00
Tiancong Li 3dd492627e i18n: update zh-TW 2025-03-02 17:04:58 +08:00
Timothy Jaeryang Baek 66210b95fc Merge pull request #11038 from satlus/pwa-fix-linkrel
fixed manifest in app.html restoring PWA
2025-03-01 19:55:08 -08:00
satlus 6e58d99920 fixed manifest link rel, restoring PWA 2025-03-01 19:43:40 -05:00
Timothy Jaeryang Baek 6471f12668 Merge pull request #11033 from dtaivpp/main
fix: Changed to use collection_name and fixed bulk indexing missing index.
2025-03-01 16:00:13 -08:00
David Tippett f3c4c2b8e3 Changed to use colleciton name and fixed bulk indexing missing index. 2025-03-01 13:26:19 -05:00
Timothy Jaeryang Baek a73b6448c5 Merge pull request #11032 from cheahjs/chore/build-arm-on-arm
ci: Update GitHub Actions runner selection for multi-platform builds
2025-03-01 08:23:54 -08:00
Jun Siang Cheah 3238981202 ci: Update GitHub Actions runner selection for multi-platform builds 2025-03-01 16:04:26 +00:00
Timothy Jaeryang Baek 59ddce1ea3 chore: bump 2025-03-01 08:00:40 -08:00
Timothy Jaeryang Baek 2b025b267a chore: bump 2025-03-01 07:57:08 -08:00
Timothy Jaeryang Baek efe8c4ca69 chore: format 2025-03-01 07:28:00 -08:00
Timothy Jaeryang Baek d7088efe73 fix: "stream" hook not working 2025-03-01 06:56:24 -08:00
Timothy Jaeryang Baek 05c5e73304 Merge pull request #10373 from dannyl1u/logit_bias
feat: logit bias
2025-03-01 06:13:19 -08:00
Timothy Jaeryang Baek f00f518abe Merge pull request #11011 from open-webui/dependabot/pip/backend/dev/sqlalchemy-2.0.38
chore(deps): bump sqlalchemy from 2.0.32 to 2.0.38 in /backend
2025-02-28 18:44:20 -08:00
Timothy Jaeryang Baek 639f4a44e0 Merge pull request #11013 from open-webui/dependabot/pip/backend/dev/black-25.1.0
chore(deps): bump black from 24.8.0 to 25.1.0 in /backend
2025-02-28 18:44:14 -08:00
Timothy Jaeryang Baek 92e1c654ce Merge pull request #11014 from open-webui/dependabot/pip/backend/dev/peewee-3.17.9
chore(deps): bump peewee from 3.17.8 to 3.17.9 in /backend
2025-02-28 18:44:07 -08:00
Timothy Jaeryang Baek 81d2df4df9 Merge pull request #11015 from open-webui/dependabot/pip/backend/dev/bcrypt-4.3.0
chore(deps): bump bcrypt from 4.2.0 to 4.3.0 in /backend
2025-02-28 18:43:57 -08:00
Timothy Jaeryang Baek 65949dbcbc Merge pull request #11012 from open-webui/dependabot/pip/backend/dev/uvicorn-standard--0.34.0
chore(deps): bump uvicorn[standard] from 0.30.6 to 0.34.0 in /backend
2025-02-28 18:43:47 -08:00
dependabot[bot] eb97e30b0a chore(deps): bump bcrypt from 4.2.0 to 4.3.0 in /backend
Bumps [bcrypt](https://github.com/pyca/bcrypt) from 4.2.0 to 4.3.0.
- [Changelog](https://github.com/pyca/bcrypt/blob/main/release.py)
- [Commits](https://github.com/pyca/bcrypt/compare/4.2.0...4.3.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-01 02:37:41 +00:00
dependabot[bot] 84518490c5 chore(deps): bump peewee from 3.17.8 to 3.17.9 in /backend
Bumps [peewee](https://github.com/coleifer/peewee) from 3.17.8 to 3.17.9.
- [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.8...3.17.9)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-01 02:37:36 +00:00
dependabot[bot] dd73ecbdc9 chore(deps): bump black from 24.8.0 to 25.1.0 in /backend
Bumps [black](https://github.com/psf/black) from 24.8.0 to 25.1.0.
- [Release notes](https://github.com/psf/black/releases)
- [Changelog](https://github.com/psf/black/blob/main/CHANGES.md)
- [Commits](https://github.com/psf/black/compare/24.8.0...25.1.0)

---
updated-dependencies:
- dependency-name: black
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-01 02:37:32 +00:00
dependabot[bot] 588a179b7f chore(deps): bump uvicorn[standard] from 0.30.6 to 0.34.0 in /backend
Bumps [uvicorn[standard]](https://github.com/encode/uvicorn) from 0.30.6 to 0.34.0.
- [Release notes](https://github.com/encode/uvicorn/releases)
- [Changelog](https://github.com/encode/uvicorn/blob/master/docs/release-notes.md)
- [Commits](https://github.com/encode/uvicorn/compare/0.30.6...0.34.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-01 02:37:27 +00:00
dependabot[bot] 244915cd1e chore(deps): bump sqlalchemy from 2.0.32 to 2.0.38 in /backend
Bumps [sqlalchemy](https://github.com/sqlalchemy/sqlalchemy) from 2.0.32 to 2.0.38.
- [Release notes](https://github.com/sqlalchemy/sqlalchemy/releases)
- [Changelog](https://github.com/sqlalchemy/sqlalchemy/blob/main/CHANGES.rst)
- [Commits](https://github.com/sqlalchemy/sqlalchemy/commits)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-01 02:37:24 +00:00
Timothy Jaeryang Baek 094d777e55 Merge pull request #11009 from amuwall/fix-typing-error
fix: typing error in replace_messages_variable func args
2025-02-28 18:34:24 -08:00
amuwall b430deab15 fix: fix typing error in args 2025-03-01 10:20:29 +08:00
Timothy Jaeryang Baek fe44e4d344 i18n(html): sync html language with i18n language 2025-02-28 16:06:28 -08:00
Timothy Jaeryang Baek 88c02d5a14 refac 2025-02-28 16:02:15 -08:00
Timothy Jaeryang Baek b75b891de1 Merge pull request #10983 from NovoNordisk-OpenSource/yvedeng/fix-redis-timeout-config
fix: add redis lock timeout config
2025-02-28 16:01:59 -08:00
Timothy Jaeryang Baek f1ce653830 Merge pull request #10992 from softue/i18n-floating-buttons
i18n floating buttons (en-US and pt-BR)
2025-02-28 15:59:49 -08:00
Rômulo Mendes Figueiredo c06484297b i18n: ask and explain floating buttons 2025-02-28 12:39:57 -03:00
Timothy Jaeryang Baek 331caad5b8 fix 2025-02-28 07:36:56 -08:00
Thomas Rehn 8b3fcfea13 feat: add alternative input configuration where Ctrl-Enter is required to send chat messages 2025-02-28 15:23:03 +01:00
Timothy Jaeryang Baek 05599e1bb5 Merge pull request #10967 from OrenZhang/i18n_zh_cn
i18n(zh-cn): add chinese translation
2025-02-28 03:21:51 -08:00
orenzhang bcdbc4fb8a i18n(zh-cn): add chinese translation 2025-02-28 17:47:27 +08:00
Yifang Deng 41a2b86e70 fix: add redis lock timeout config 2025-02-28 10:12:51 +01:00
Danny Liu f9292ab4d2 Merge branch 'dev' into logit_bias 2025-02-27 23:51:13 -08:00
dannyl1u f4bd094128 Merge remote-tracking branch 'origin' into logit_bias 2025-02-27 23:48:22 -08:00
dannyl1u 90aa29528c logit_bias: handle comma seperated values 2025-02-27 23:13:30 -08:00
dannyl1u 34e3cb6881 logit bias: update tooltip message 2025-02-27 23:13:09 -08:00
Timothy Jaeryang Baek d0ddb0637e enh: web embed bypass embedding and retrieval support 2025-02-27 16:34:05 -08:00
hurxxxx 2405809f92 Merge branch 'main' into fix/update-msal-browser-version 2025-02-28 08:44:06 +09:00
hurxxxx 77579f5509 chore: cleanup 2025-02-28 08:42:02 +09:00
Timothy Jaeryang Baek 5e33955566 Merge pull request #10940 from TheMasterFX/update-de-DE-translation
i18n: Update de-DE translation
2025-02-27 15:17:59 -08:00
Timothy Jaeryang Baek 73c0262345 Merge branch 'dev' into update-de-DE-translation 2025-02-27 15:17:51 -08:00
Timothy Jaeryang Baek a3ea924f0a Merge pull request #10941 from TiancongLx/dev
i18n: update zh-TW
2025-02-27 15:17:03 -08:00
Tiancong Li 01435997b9 i18n: update zh-TW 2025-02-28 06:29:53 +08:00
Timmo 90fe437e29 i18n: Update de-DE translation - fix typos 2025-02-27 23:23:05 +01:00
Timmo 43077b82b7 i18n: Update de-DE translation 2025-02-27 23:09:02 +01:00
Timothy Jaeryang Baek 1b56a8f3cb Merge pull request #10864 from kurtdami/perplexity_integration
feat: add perplexity integration to web search
2025-02-27 13:51:03 -08:00
Timothy Jaeryang Baek 1d27402dd0 Merge pull request #10910 from saraangelmurphy/awsworkloadidentity
feat: add AWS workload identity support
2025-02-27 13:50:36 -08:00
Timothy Jaeryang Baek 6f7161acf8 chore: format 2025-02-27 13:04:39 -08:00
Timothy Jaeryang Baek 54e3ca8e6c refac: rm confusing defaults 2025-02-27 13:03:28 -08:00
Timothy Jaeryang Baek 95cadaca72 Merge pull request #10933 from open-webui/dev
0.5.18
2025-02-27 12:00:52 -08:00
Timothy Jaeryang Baek e26c443815 0.5.18 2025-02-27 12:00:23 -08:00
Timothy Jaeryang Baek 046f1fb30a Merge pull request #10927 from open-webui/dev
0.5.18
2025-02-27 11:50:08 -08:00
Timothy Jaeryang Baek 63d825692e doc: changelog 2025-02-27 11:49:59 -08:00
Timothy Jaeryang Baek 70667d5cc8 refac 2025-02-27 11:45:25 -08:00
Timothy Jaeryang Baek 2ac0eae99e Merge pull request #10925 from SleepyYui/fix-10905
fix: Fix OpenAI connection not actually deleting
2025-02-27 11:44:20 -08:00
Timothy Jaeryang Baek 1dd442f38b Merge pull request #10919 from df-cgdm/main
**fix** Resolve a bug in /api/models/base which was not returning openai models when ENABLE_FORWARD_USER_INFO_HEADERS is true
2025-02-27 11:42:51 -08:00
Yui 94c19f73b0 add config update when deleting openai model 2025-02-27 20:41:30 +01:00
Timothy Jaeryang Baek ed0b9be4e3 fix 2025-02-27 11:39:59 -08:00
Timothy Jaeryang Baek 866d02bbae refac 2025-02-27 11:39:00 -08:00
Timothy Jaeryang Baek f7c5cd486b Merge pull request #10908 from barnabehvrd/main
i18n: Updated translations for fr-FR
2025-02-27 11:37:58 -08:00
Timothy Jaeryang Baek 660a44c918 fix: insecure connection over LAN 2025-02-27 11:37:44 -08:00
Didier FOURNOUT b6873153c1 resolve a bug in /api/models/base not returning openai models when ENABLE_FORWARD_USER_INFO_HEADERS is true 2025-02-27 19:32:15 +00:00
df-cgdm 24a2e84692 Merge branch 'open-webui:main' into main 2025-02-27 19:13:00 +00:00
Sara Angel-Murphy 5e873bc643 feat: add AWS workload identity support 2025-02-27 13:12:54 -05:00
v0ltis f643182eb0 Updated french translation 2025-02-27 19:04:53 +01:00
hurxxxx c5cfcc1229 chore: cleanup 2025-02-27 23:16:52 +09:00
hurxxxx 203dfdedf1 Update deprecated msal-browser version to the latest 2025-02-27 23:12:09 +09:00
hurxxxx febc9ab885 Merge remote-tracking branch 'upstream/main' 2025-02-27 21:08:20 +09:00
Timothy Jaeryang Baek 38fb9d5fd8 chore: jspdf depedency 2025-02-27 03:54:16 -08:00
Timothy Jaeryang Baek 15485e7c5d Merge pull request #10469 from open-webui/dev
0.5.17
2025-02-27 03:46:08 -08:00
Timothy Jaeryang Baek 8241fa2e12 doc: changelog 2025-02-27 03:45:33 -08:00
Timothy Jaeryang Baek 37a7dd6d33 chore: format 2025-02-27 02:18:44 -08:00
Timothy Jaeryang Baek 85b7ec9387 Merge pull request #10873 from TiancongLx/dev
i18n: update zh-TW
2025-02-27 02:17:33 -08:00
Tiancong Li b838a1df99 i18n: update zh-TW 2025-02-27 17:57:10 +08:00
tidely d7b18b662b chore: use logging.getLevelNamesMapping()
Use `logging.getLevelNamesMapping()` for getting all valid logging levels. This also allows adding new ones using `logging.addLevel()`. This feature was [added](https://docs.python.org/3.11/library/logging.html#logging.getLevelNamesMapping) in Python 3.11 which is above the minimum supported Python version for open-webui.
2025-02-27 11:19:27 +02:00
kurtdami b061775932 feat: add perplexity integration to web search 2025-02-27 00:30:48 -08:00
Timothy Jaeryang Baek 8c4d967ef4 refac: evaluations settings ui 2025-02-26 23:58:43 -08:00
Timothy Jaeryang Baek ce7cf62a55 refac: dedup 2025-02-26 23:51:39 -08:00
Timothy Jaeryang Baek 0a4dbf7cf0 refac 2025-02-26 23:41:09 -08:00
Timothy Jaeryang Baek fcbdfbd744 refac 2025-02-26 23:35:09 -08:00
Timothy Jaeryang Baek 1ae702b8a6 Merge pull request #10860 from open-webui/audit-log-dev
feat: add audit logging feature
2025-02-26 23:19:37 -08:00
Timothy Jaeryang Baek 2d379cb35f chore: pyproject 2025-02-26 23:19:19 -08:00
Timothy Jaeryang Baek 76e90d9f3f Merge pull request #10436 from victorstevansuse/feat/audits
feat: add audit logging feature
2025-02-26 23:15:10 -08:00
Timothy Jaeryang Baekandsilentoplayz da8c42ee49 feat: Sort models by name in ascending/descending order
Co-Authored-By: silentoplayz <50341825+silentoplayz@users.noreply.github.com>
2025-02-26 23:12:46 -08:00
Timothy Jaeryang Baek ddb30589e3 chore: format
HIDE MODELS
2025-02-26 22:18:18 -08:00
Timothy Jaeryang Baek ef734833a5 fix 2025-02-26 21:22:51 -08:00
Timothy Jaeryang Baek 40ddd172e0 refac: web search settings ui 2025-02-26 15:56:45 -08:00
Timothy Jaeryang Baek 57010901e6 enh: bypass embedding and retrieval 2025-02-26 15:42:19 -08:00
Timothy Jaeryang Baek 1c2e36f1b7 refac 2025-02-26 13:59:08 -08:00
Timothy Jaeryang Baek 34aeaaf020 refac 2025-02-26 13:54:26 -08:00
Timothy Jaeryang Baek fa91d83ac3 refac: documents settings ui 2025-02-26 13:48:56 -08:00
Timothy Jaeryang Baek 78a8ef8e66 refac: audio file handling 2025-02-26 13:09:52 -08:00
Timothy Jaeryang Baek 46ac6f2b29 fix 2025-02-26 12:53:07 -08:00
Timothy Jaeryang Baek 33d3558ca9 Merge pull request #10817 from NovoNordisk-OpenSource/ivaroli/adding-json-as-supported-file-type
fix: Using the TextLoader instead of Tika for JSON files
2025-02-26 12:49:29 -08:00
Timothy Jaeryang Baek c1c92b0c03 Merge pull request #10820 from oyve/dev
i18n: Update translation.json for nb-NO
2025-02-26 12:49:02 -08:00
Øyvind 618307f35b Update translation.json
Fill all empty translation
2025-02-26 16:29:47 +01:00
Ívar Óli Sigurðsson c5a09cdd21 adding a comma 2025-02-26 15:27:03 +01:00
Ívar Óli Sigurðsson 661711164a Adding json as a known source for Tika 2025-02-26 15:11:21 +01:00
Timothy Jaeryang Baek 80efaaffdd Merge pull request #10810 from panda44312/patch-1
i18n: Update zh-cn translation
2025-02-26 04:29:41 -08:00
Panda 46f2dc0d11 Update zh-cn 2025-02-26 12:24:52 +01:00
Timothy Jaeryang Baek 674d6e08fc Merge pull request #10809 from TobiasGoerke/feat/update_timestamp_asynchronously
feat: update get_current_user to refresh last active timestamp asynchronously
2025-02-26 02:38:06 -08:00
Tobias Goerke 76891f4760 feat: update get_current_user to refresh last active timestamp asynchronously 2025-02-26 10:53:47 +01:00
Timothy Jaeryang Baek 20f0b02b38 Merge pull request #10755 from softue/check-if-enable-ldap-chroma
Conditional import of ldap3 and chromadb
2025-02-25 16:02:40 -08:00
Timothy Jaeryang Baek bef7a532cc refac 2025-02-25 16:01:29 -08:00
Timothy Jaeryang Baek ced508c912 Merge pull request #10783 from silentoplayz/share-fix
fix: community sharing for prompts and tools
2025-02-25 15:35:11 -08:00
Timothy Jaeryang Baek c883368842 Merge pull request #10786 from silentoplayz/confirm-clear-for-memories
feat: Confirmation prompt on 'Clear' for memories
2025-02-25 15:34:14 -08:00
Silentoplayz 8097b6a3ff Update ManageModal.svelte
no confirmation when no memories exist
2025-02-25 18:00:59 -05:00
Silentoplayz 7cfbf6489a Update ManageModal.svelte
feat: Add ConfirmDialog to 'Clear Memory' button
2025-02-25 17:53:13 -05:00
Silentoplayz 11967a780d Share fix
Fix
2025-02-25 17:05:05 -05:00
Timothy Jaeryang Baek 6cf0ceedba refac 2025-02-25 11:11:36 -08:00
Timothy Jaeryang Baek ec72dcba75 Merge pull request #10742 from hjer/improve-swedish-translation
i18n: Add and improve Swedish translation
2025-02-25 10:54:19 -08:00
Timothy Jaeryang Baek 54d7bf8f28 Merge branch 'dev' into improve-swedish-translation 2025-02-25 10:54:08 -08:00
Timothy Jaeryang Baek 3be5e3129b Merge pull request #10752 from NovoNordisk-OpenSource/yvedeng/standardize-logging
refactor: replace print statements with logging
2025-02-25 10:53:02 -08:00
Rômulo Mendes Figueiredo 2298bfbd7e refac: conditional import of ldap3 2025-02-25 13:07:53 -03:00
Yifang Deng 0e5d5ecb81 refactor: replace print statements with logging for better error tracking 2025-02-25 15:53:55 +01:00
Rômulo Mendes Figueiredo b52a7e3543 refac: conditional import of chromadb 2025-02-25 11:35:36 -03:00
hjer df1238229c add and improve swedish translation 2025-02-25 13:58:09 +01:00
Timothy Jaeryang Baek eafefcf838 chore: bump 2025-02-25 01:46:57 -08:00
Timothy Jaeryang Baek 9f27d7710b chore: format 2025-02-25 01:46:08 -08:00
Timothy Jaeryang Baek 7c68a424f8 refac 2025-02-25 01:44:39 -08:00
Timothy Jaeryang Baek 5d3249848d refac: allow image only message via enter 2025-02-25 01:40:17 -08:00
Timothy Jaeryang Baek 7e2b2ec761 fix: openai usage display issue 2025-02-25 01:35:59 -08:00
Timothy Jaeryang Baek b964b175d4 refac 2025-02-25 01:03:15 -08:00
Timothy Jaeryang Baek 46c4da4864 enh: "stream" hook 2025-02-25 01:00:29 -08:00
df-cgdm 126045318f Merge branch 'open-webui:main' into main 2025-02-25 07:37:57 +00:00
Timothy Jaeryang Baek 205013da2f Merge pull request #10683 from grandtele/fix/openai-o1-legacy-roles
fix: restore compatibility for older o1 models (o1-mini, o1-preview)
2025-02-24 23:35:18 -08:00
Timothy Jaeryang Baek abf36c0645 Merge pull request #10711 from jasonpnnl/send-usage-to-pipeline-outlet
fix: Include usage in chatCompleted handler for pipeline outlet functions
2025-02-24 23:34:18 -08:00
Timothy Jaeryang Baek e06111a362 refac 2025-02-24 23:21:03 -08:00
Timothy Jaeryang Baek cd3904046d refac 2025-02-24 20:19:32 -08:00
Jason E. Jensen 89aaf64209 add optional usage to chatCompleted messages 2025-02-24 22:32:08 +00:00
Timothy Jaeryang Baek 95ae2aeef3 Merge pull request #10704 from TiancongLx/dev
i18n: update zh-TW
2025-02-24 12:11:27 -08:00
Tiancong Li cefe274f74 i18n: update zh-TW 2025-02-25 04:03:16 +08:00
Timothy Jaeryang Baek d8bc3098db Merge pull request #9918 from df-cgdm/main
feat: Add  X-OpenWebUI when forwarding to ollama servers
2025-02-24 11:55:04 -08:00
Timothy Jaeryang Baek 628b89009c Merge pull request #10690 from hurxxxx/feat/onedrive-file-attach
feat: OneDrive file picker integration
2025-02-24 11:52:37 -08:00
Timothy Jaeryang Baek 23ff2988bf Merge branch 'dev' into feat/onedrive-file-attach 2025-02-24 11:51:59 -08:00
Timothy Jaeryang Baek e0c199255f Merge pull request #10666 from EkaterinePapava/main
i18n: Update Georgian translation
2025-02-24 11:37:18 -08:00
hurxxxx b2422b3c8f i18n: onedrive related 2025-02-25 01:56:33 +09:00
hurxxxx 4cc3102758 feat: onedrive file picker integration 2025-02-25 01:47:07 +09:00
grand 8c020488dd * fix: restore compatibility for older o1 models (o1-mini, o1-preview) 2025-02-24 12:04:06 +01:00
Gunwoo Hur 0335d479f9 feat: add onedrive file picker 2025-02-24 17:27:37 +09:00
Ekaterine Papava dcaab9d6b5 Update Georgian translation 2025-02-24 09:07:45 +01:00
Timothy Jaeryang Baek 0ba45ad82b Merge pull request #10617 from grandtele/fix/openai-o1-o3-role
fix: replace "system" with "developer" for o1 and o3 models
2025-02-23 22:33:59 -08:00
Timothy Jaeryang Baek 802f8809dd fix: codeblock 2025-02-23 21:39:34 -08:00
Timothy Jaeryang Baek 7a63947b94 fix: tailwind v4 ios 16.4 compatibility issue 2025-02-23 18:41:33 -08:00
Timothy Jaeryang Baek 737b1723c7 refac 2025-02-23 14:12:41 -08:00
Timothy Jaeryang Baek e90e254575 Merge pull request #10605 from silentoplayz/shortcuts-modal-update
feat: Add more keyboard shortcuts
2025-02-23 13:48:55 -08:00
Timothy Jaeryang Baek f8ad74fc42 refac 2025-02-23 13:32:19 -08:00
Timothy Jaeryang Baek 6c862b8fbf Merge pull request #10619 from OrenZhang/feat_s3_virtual_path
feat(s3): support for s3 virtual path style
2025-02-23 13:27:22 -08:00
Timothy Jaeryang Baek 4b908ea626 Merge pull request #10607 from TiancongLx/dev
i18n: update zh-TW
2025-02-23 13:24:04 -08:00
Timothy Jaeryang Baek b77937dfad Merge pull request #10634 from sebdanielsson/handle-no-location-access
fix: Handle no location permission
2025-02-23 13:23:47 -08:00
Sebastian b00e14eb3f Handle no location permission 2025-02-23 20:27:55 +01:00
orenzhang 9748a030f7 Merge remote-tracking branch 'oui/dev' into feat_s3_virtual_path 2025-02-23 20:54:04 +08:00
orenzhang 1060d62add refactor(s3): code lint 2025-02-23 20:52:22 +08:00
orenzhang 4c3dd84b32 feat(s3): support for s3 virtual path style 2025-02-23 20:31:08 +08:00
grand 82657acdce * fix: adjust role mapping for o1 and o3 models in openai_o1_o3_handler 2025-02-23 13:20:45 +01:00
Tiancong Li c96cc831d5 i18n: update zh-TW 2025-02-23 14:29:51 +08:00
Silentoplayz e41a5278f7 Update ShortcutsModal.svelte
fix
2025-02-22 23:00:06 -05:00
Silentoplayz b5aa562039 Update ShortcutsModal.svelte
Added more shortcuts
2025-02-22 22:50:37 -05:00
Silentoplayz 5281aeb07b Merge branch 'dev' of https://github.com/silentoplayz/open-webui into dev 2025-02-22 21:17:56 -05:00
Timothy Jaeryang Baek 39717812ee Merge pull request #10572 from Kylapaallikko/dev
i18n: Update Finnish Translation
2025-02-22 14:31:24 -08:00
Timothy Jaeryang Baek 9f6e182400 Merge pull request #10573 from dom133/dev
i18n: Update Polish Translation
2025-02-22 14:30:27 -08:00
Timothy Jaeryang Baek e4ba8fea8a Merge pull request #10583 from hurxxxx/feat/show_at_model_suggestions_to_placeholder
feat: Show atSelectedModel suggestions in Placeholder
2025-02-22 14:29:52 -08:00
hurxxxx f80aea60c7 fix: Fix incorrect object property usage 2025-02-23 00:19:51 +09:00
hurxxxx a407558375 feat: Show suggestions when selecting the atModel. 2025-02-22 23:27:13 +09:00
dom133 65aa41ab81 i18n: Update Polish Translation 2025-02-22 13:10:30 +01:00
Kylapaallikko 6331963e66 Update translation.json 2025-02-22 13:34:35 +02:00
Timothy Jaeryang Baek 32fa8d5143 Merge pull request #10566 from oloflarsson/feat/async-pipes
feat: add optional support for async pipes
2025-02-22 02:47:08 -08:00
Timothy Jaeryang Baek 8f3fcdcf5c refac 2025-02-22 02:00:06 -08:00
Timothy Jaeryang Baek 794919e91d refac 2025-02-22 01:22:17 -08:00
Timothy Jaeryang Baek 667d26ca12 refac 2025-02-22 01:16:58 -08:00
Timothy Jaeryang Baek 50dec12072 refac 2025-02-21 22:15:22 -08:00
Timothy Jaeryang Baek 8fb6b03ddc Merge pull request #10555 from pwnless/dev
fix: ollama backend native tool calling
2025-02-21 21:09:51 -08:00
hopeless 7bfa29fa81 Update payload.py
Fixes ollama native tool calling because native tool calling content will be str '', and tool call processing will be completely ignored.
2025-02-22 12:13:14 +08:00
Timothy Jaeryang Baek 9bada6421e refac: code block image styling 2025-02-21 16:39:56 -08:00
Timothy Jaeryang Baekandharry zhou b14e75dd6c feat: added Trust Proxy Environment switch in Web Search admin settings tab.
Co-Authored-By: harry zhou <67385896+harryzhou2000@users.noreply.github.com>
2025-02-21 13:40:11 -08:00
Timothy Jaeryang Baek 6623583004 Merge pull request #10549 from jeannotdamoiseaux/fix/oauth-groups-default-typeerror
Fix: Ensure `user_oauth_groups` defaults to an empty list to prevent TypeError
2025-02-21 13:37:35 -08:00
Jeannot Damoiseaux d50098b622 Fix: Ensure user_oauth_groups defaults to an empty list to prevent TypeError
When the OAuth groups claim does not yield a list, `user_oauth_groups` was previously
set to None, causing a TypeError during membership checks. Changed this default to
an empty list (`[]`) to ensure the variable is always iterable, preventing errors
for non-admin users while logging in.

This fix ensures stability in the `update_user_groups` function.
2025-02-21 22:25:22 +01:00
Timothy Jaeryang Baek 642dcd4b70 fix: model import 2025-02-21 13:19:11 -08:00
Timothy Jaeryang Baek a7d8ed0c6d refac 2025-02-21 12:11:21 -08:00
Timothy Jaeryang Baek ab1b910d80 Merge pull request #10486 from Micca/feature/document_intelligence_support
Feat: Adding Support for Azure AI Document Intelligence for Content Extraction (Revised)
2025-02-21 10:56:18 -08:00
Timothy Jaeryang Baek a3c2ff61ed Merge pull request #10483 from KarlLee830/translate
i18n: Update Chinese Translation
2025-02-21 10:55:55 -08:00
Timothy Jaeryang Baek b111434fa9 Merge pull request #10488 from glimpse-0201/dev
fix:Quick selection tool lost
2025-02-21 10:55:44 -08:00
Timothy Jaeryang Baek 613a087387 refac 2025-02-21 10:55:03 -08:00
Timothy Jaeryang Baek b0a19a9801 Merge pull request #10501 from Synergyst/feature/openai-tts-custom-url-fix-dev
fix: Custom OpenAI-TTS URL to fetch actual voices and models
2025-02-21 10:52:41 -08:00
Timothy Jaeryang Baek 086a78f863 Merge pull request #10521 from Seniorsimo/add-stop-parameter
**fix** Added support for stop parameter in OpenAI to Ollama conversion
2025-02-21 10:51:49 -08:00
Timothy Jaeryang Baek b4c64a21b3 Merge pull request #10513 from mcelrath/dev
Support thinking/solution tags used by Openthinker
2025-02-21 10:49:45 -08:00
Simone fb3886cf04 Added support for stop parameter 2025-02-21 18:46:10 +01:00
Bob McElrath c9079d4b4d Merge branch 'open-webui:dev' into dev 2025-02-21 09:13:53 -05:00
Bob McElrath c4b441de65 Support thinking tags used by Openthinker 2025-02-21 09:12:34 -05:00
Synergyst f789ad59a9 Update audio.py
Removed original code that was commented out
2025-02-21 04:47:46 -06:00
Coleton M cdf620e6ee Update audio.py to fetch custom URL voices and models 2025-02-21 04:41:45 -06:00
huanght 2993332b38 fix:Quick selection tool lost 2025-02-21 16:10:11 +08:00
Olof Larsson ab1f2ae914 feat/async-pipes 2025-02-21 08:24:48 +01:00
Karl Lee 68e33b5386 i18n: Update Chinese Translation 2025-02-21 14:58:40 +08:00
Timothy Jaeryang Baek e31f680788 refac 2025-02-20 20:46:00 -08:00
Timothy Jaeryang Baek 1bf16ec23d Merge pull request #10462 from Seniorsimo/fix-ollama-stream-conversion
**fix** ollama to openai conversion on one shot streamed response
2025-02-20 13:30:29 -08:00
Timothy Jaeryang Baek 2697a4d7f8 Merge pull request #10460 from aleixdorca/dev
Update catalan translation.json
2025-02-20 13:30:00 -08:00
Timothy Jaeryang Baek 8629f6b0f3 Merge pull request #10466 from HuangruiChu/main
i18n: Update zh-Chinese translation
2025-02-20 13:29:49 -08:00
Richard (Huangrui) Chu 1332a0d381 Update zh-CN translation
1. remove the typo ”‘’"  for -1 表示无限制,正整数表示具体限制”
2. Token should be kept rather than translated as "标记"
3. Max Tokens (num_predict) should be "最大Token数量 (num_predict)"
4. "Enter Jupyter Token" here “Token" could be translated as ”令牌“ just as 	"JWT Token": "JWT 令牌", (line 582)
5. "TLS" which means "Transport Layer Security" should be translated to "传输层安全协议"
6. "Tokens To Keep On Context Refresh (num_keep)" "在语境刷新时需保留的 Token 数量"
7. change token to "Token" in the Chinese translation.
2025-02-20 16:07:32 -05:00
Simone a8859a8145 Fix on ollama to openai conversion - stream can return a single message with content 2025-02-20 21:25:32 +01:00
Timothy Jaeryang Baek 6fedd72e39 Merge pull request #10459 from open-webui/dev
0.5.16
2025-02-20 11:26:36 -08:00
Timothy Jaeryang Baek 472a291c24 doc: changelog 2025-02-20 11:25:17 -08:00
Aleix Dorca 08df5f6d7c Update catalan translation.json 2025-02-20 20:24:58 +01:00
Timothy Jaeryang Baek b124c15018 Merge pull request #10431 from EntropyYue/dev
i18n: Update Chinese translation
2025-02-20 11:19:18 -08:00
Timothy Jaeryang Baek 0a7a265ff5 Merge pull request #10445 from PkmX/pr-fix-web-search-proxy
fix: correctly interpret RAG_WEB_SEARCH_TRUST_ENV as bool
2025-02-20 11:16:47 -08:00
Timothy Jaeryang Baek 93d486d50e revert: faulty dedup code 2025-02-20 11:02:45 -08:00
PkmX af10aba805 fix: correctly interpret RAG_WEB_SEARCH_TRUST_ENV as bool 2025-02-21 01:46:17 +08:00
Victor Ribeiro 39c6ecb50d feat: add audit logger middleware and custom logger using loguru 2025-02-20 11:15:38 -03:00
hurxxxx f865a23a18 Merge remote-tracking branch 'upstream/main' 2025-02-20 23:08:47 +09:00
EntropyYue 89b4627e9a Update translation.json 2025-02-20 21:47:21 +08:00
EntropyYue e920f96b17 Update translation.json 2025-02-20 21:12:04 +08:00
Timothy Jaeryang Baek cf4bbcde14 Merge pull request #10421 from open-webui/dev
fix: workflow
2025-02-20 02:10:02 -08:00
Timothy Jaeryang Baek c882aacc23 fix: workflow 2025-02-20 02:09:44 -08:00
Timothy Jaeryang Baek 624f2ebcff Merge pull request #10420 from open-webui/dependabot/pip/pip-e8a89e233e
build(deps): bump the pip group across 2 directories with 1 update
2025-02-20 02:03:07 -08:00
dependabot[bot] eb218f6674 build(deps): bump the pip group across 2 directories with 1 update
Bumps the pip group with 1 update in the / directory: [python-jose](https://github.com/mpdavis/python-jose).
Bumps the pip group with 1 update in the /backend directory: [python-jose](https://github.com/mpdavis/python-jose).


Updates `python-jose` from 3.3.0 to 3.4.0
- [Release notes](https://github.com/mpdavis/python-jose/releases)
- [Changelog](https://github.com/mpdavis/python-jose/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mpdavis/python-jose/compare/3.3.0...3.4.0)

Updates `python-jose` from 3.3.0 to 3.4.0
- [Release notes](https://github.com/mpdavis/python-jose/releases)
- [Changelog](https://github.com/mpdavis/python-jose/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mpdavis/python-jose/compare/3.3.0...3.4.0)

---
updated-dependencies:
- dependency-name: python-jose
  dependency-type: direct:production
  dependency-group: pip
- dependency-name: python-jose
  dependency-type: direct:production
  dependency-group: pip
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-20 10:02:35 +00:00
Timothy Jaeryang Baek 9fdf2cd16c Merge pull request #10330 from open-webui/dev
0.5.15
2025-02-20 02:01:29 -08:00
Timothy Jaeryang Baek 385a894b3c chore: pyproject 2025-02-20 01:42:11 -08:00
Timothy Jaeryang Baek 2d5b685429 doc: changelog 2025-02-20 01:39:50 -08:00
Timothy Jaeryang Baek 900dc1f0a3 chore: bump 2025-02-20 01:28:46 -08:00
Timothy Jaeryang Baek eeb00a5ca2 chore: format 2025-02-20 01:01:29 -08:00
Timothy Jaeryang Baek 2b913a99a3 Merge pull request #10417 from hangxingliu/liu/fix-build-proxy
build: load the proxy from the system env for Pyodide to download packages
2025-02-20 00:58:27 -08:00
Timothy Jaeryang Baek 0994a07874 Merge pull request #10415 from labanzu/better-pdf-preview
feat: better pdf preview
2025-02-20 00:57:11 -08:00
Timothy Jaeryang Baek a818d8e3b7 Merge pull request #10413 from dom133/dev
i18n: Improve Polish translation
2025-02-20 00:55:52 -08:00
Liu Yue 3ae7302f7b build: load the proxy from the system env for Pyodide to download packages #6234 2025-02-20 16:40:31 +08:00
dom133 9ba03523e7 i18n: Improve Polish translation 2025-02-20 09:26:07 +01:00
labanzu f4e67bf2d3 update 2025-02-20 16:10:29 +08:00
labanzu a3d3ca293e chore: optimize pdf view 2025-02-20 15:55:18 +08:00
Timothy Jaeryang Baek d6f3444141 fix: katex issue 2025-02-19 23:37:11 -08:00
Timothy Jaeryang Baek 0e20b15afe Merge pull request #10410 from xinhai-ai/dev
fix: GitHub OAuth email retrieval when public email is not set
2025-02-19 23:16:46 -08:00
Timothy Jaeryang Baek e1cc104805 Merge pull request #10408 from hangxingliu/liu/fix-proxy
fix: respect proxy and timeout settings in audio-related aiohttp requests
2025-02-19 23:16:15 -08:00
星海 de8492de34 fix: GitHub OAuth email retrieval when public email is not set 2025-02-20 15:06:07 +08:00
Liu Yue 90d9cdacfa fix: respect proxy and timeout settings in audio-related aiohttp requests 2025-02-20 14:55:45 +08:00
Timothy Jaeryang Baek 13e58c1b64 Merge pull request #10360 from ferret99gt/ollama-option-conversion-fixes
fix: Update Ollama option handling in payload.py's convert_payload_openai_to_ollama
2025-02-19 22:44:07 -08:00
Timothy Jaeryang Baek d5a049dc54 Merge pull request #10401 from xinhai-ai/main
fix: email claim doesn't effect
2025-02-19 20:43:43 -08:00
星海 dec44e4bcd Fix: email claim doesn't effect 2025-02-20 11:32:48 +08:00
Timothy Jaeryang Baek ae0554224a refac 2025-02-19 18:22:31 -08:00
Timothy Jaeryang Baek fe5c4b95d5 enh: configurable jupyter execution timeout 2025-02-19 17:05:37 -08:00
Timothy J. Baek 90fca993f3 wip: jupyter code excution timeout 2025-02-19 16:41:54 -08:00
dannyl1u 8aa6415500 include logit_bias in form_data 2025-02-19 16:23:58 -08:00
Timothy Jaeryang Baek efefff71d1 Merge pull request #10363 from ferret99gt/ollama-model-option-conversion-updates
feat: Update Payload's apply_model_params_to_body_ollama with full Ollama supported options
2025-02-19 12:32:46 -08:00
Timothy Jaeryang Baek 5da47de6eb Merge pull request #10366 from tarmst/fix-no-nested-claims-for-group-oauth
Fix: Add nested claim search for group oauth management
2025-02-19 12:23:54 -08:00
Timothy Jaeryang Baek b032f34831 Merge pull request #10364 from Lutherwaves/translations
i18n: Add bulgarian translations
2025-02-19 12:23:30 -08:00
Timothy Jaeryang Baek ea4ad3944c Merge pull request #10378 from Seniorsimo/message-conversion
**fix** Add support for tool message in openai to Ollama message conversion
2025-02-19 12:23:11 -08:00
Timothy Jaeryang Baek ea3f873ae9 Merge pull request #10377 from Seniorsimo/chat-message-validator
**fix** ChatMessage validator: content can be null when using tools
2025-02-19 12:22:31 -08:00
Timothy Jaeryang Baek de7e8fd918 Merge pull request #10362 from Seniorsimo/usage-openai-compatible
**fix** Added OpenAI usage standard keys to API signature
2025-02-19 12:20:41 -08:00
Timothy Jaeryang Baek 17560967c7 Merge pull request #10347 from Youggls/dev
fix(deps): upgrade pydantic from v2.9.2 to v2.10.3+ in requirements.txt and pyproject.toml
2025-02-19 12:18:51 -08:00
Timothy Jaeryang Baek 9a4f2b9aa3 Merge pull request #10354 from TiancongLx/dev
i18n: update zh-TW
2025-02-19 12:18:32 -08:00
Simone 6f698073bb Add support for tool message in openai to Ollama message conversion 2025-02-19 21:11:39 +01:00
Simone 8662108344 Fix on ChatMessage validator: content can be null when using tools 2025-02-19 21:03:23 +01:00
dannyl1u 4a2a12fd21 feat: scaffolding for logit_bias 2025-02-19 10:33:49 -08:00
tarmst efe3bca19e Add nested claim search for groups oauth claim 2025-02-19 16:47:52 +00:00
lutherwaves 6898fd7d0f chore: Add bulgarian translations 2025-02-19 17:35:56 +02:00
ferret99gt 5701d6d333 Change the opt dictionary to a mappings dictionary with appropriate casts
This is to bring consistency with apply_model_params_to_body_openai. Both now use a mapping dictionary then call and return apply_model_params_to_body directly.
2025-02-19 09:30:16 -05:00
Simone 074ce356de Added OpenAI usagerequested keys 2025-02-19 15:28:39 +01:00
ferret99gt fa885c3346 Update remapping logic
We copy the params from from the original key to the new key, then delete it. This is to ensure Ollama only gets valid options.

(Add a comment as well)
2025-02-19 09:25:47 -05:00
ferret99gt a4249a6351 Remove remapping of frequency_penalty to repeat_penalty
1) Ollama natively supports frequency_penalty, so this is not necessary.
2) Repeat_penalty is being added to Open WebUI in PR #10016, allowing Ollama users to pick which penalty methods they want.
2025-02-19 09:24:38 -05:00
ferret99gt 877d21a029 Move parameter remapping above the opt dictionary.
This is so that any remappings are handled before options are handled by apply_model_params_to_body
2025-02-19 09:23:33 -05:00
ferret99gt 6b2ba73701 Remove tfs_z
See https://github.com/ollama/ollama/blob/main/docs/api.md#request-8

tfs_z was removed from Llama.cpp and Ollama in January 2025.
2025-02-19 09:21:36 -05:00
ferret99gt cee08e316d Update Ollama request option list with full supported options
See https://github.com/ollama/ollama/blob/main/docs/api.md#request-8

This adds the full suite of supported Ollama options.
2025-02-19 09:21:05 -05:00
ferret99gt 8125b0499b Remove empty ollama_options
1) The empty dictionary from line 176 is never used.
2) Lines 193-194 are not necessary as they were already done at line 177
2025-02-19 08:57:05 -05:00
ferret99gt 57b01cf8fb Fix for system prompt setting
1) Ollama supports sending the system prompt as a parameter, not as an option. (See https://github.com/ollama/ollama/blob/main/docs/api.md#request-8) However, it is in the options dictionary and needs moved to the payload dictionary.
2) After moving the system parameter from ollama_options to ollama_payload, delete it from ollama_options. This is to prevent Ollama throwing a warning about invalid options.
2025-02-19 08:55:11 -05:00
ferret99gt fea169a9c0 Core fix for num_predict not working.
1) max_tokens was being looked for in openai_payload, but is present in openai_payload['options'], so is never found.
2) After copying the value for max_tokens to num_predict, delete max_tokens from the dictionary. This is to prevent Ollama throwing a warning about invalid option (max_tokens)
2025-02-19 08:52:34 -05:00
ferret99gt adde37394b Remove parameters that map directly, as they are part of options
1) This may be legacy code?
2) All three of these parameters, temperature, top_p and seed, are found in openai_payload["options"], not openai_payload. They do not need remapped any longer.
2025-02-19 08:44:59 -05:00
ferret99gt aea8977d05 Remove mapping of max_completion_tokens
1) max_completion_tokens is being looked for in openai_payload, but would be located in openai_payload['options'], so is never found. (This applies to the prior two commits as well).
2) max_completion_tokens is not sent from the frontend, only max_tokens. It does not appear in AdvancedParams.svelte.
2b) Openai.py does use max_completion_tokens, but for o1,o3 models and converts it from max_tokens.
2025-02-19 08:39:33 -05:00
ferret99gt e6919c3242 Remove mapping of frequency_penalty to repeat_penalty
1) Ollama natively supports frequency_penalty.
2) repeat_penaltywas added to Open Webui in PR #10016 and is not merged to main yet at this time. Once both changes go live, Ollama users can freely choose between frequency/presence penalty, or repeat penalty, as they choose.
2025-02-19 08:33:29 -05:00
ferret99gt a560f789e4 Remove mapping of presence_penalty to new_topix_penalty
1) Ollama natively supports presence_penalty.
2) new_topic_penalty is not a valid option in Ollama. (See https://github.com/ollama/ollama/blob/main/docs/api.md#request-8)
3) Presence_penalty was added to Open Webui in PR #10016 and is not merged to main yet at this time.
2025-02-19 08:31:57 -05:00
Tiancong Li 61c6048b45 i18n: update zh-TW 2025-02-19 20:06:03 +08:00
Youggls 1692a52a6a fix(deps): upgrade pydantic from v2.9.2 to v2.10.3+ in requirements.txt and pyproject.toml 2025-02-19 19:08:17 +08:00
Timothy Jaeryang Baek 3e1337d753 Merge pull request #10341 from Youggls/dev
feat: Add Firecrawl web loader integration
2025-02-19 02:07:19 -08:00
Youggls 0fb3c08181 feat: Add Firecrawl web loader integration 2025-02-19 16:54:44 +08:00
Timothy Jaeryang Baek dab6396ebe fix: inline citations 2025-02-19 00:35:01 -08:00
Timothy Jaeryang Baek c073b8b4ee refac 2025-02-18 23:49:27 -08:00
Timothy Jaeryang Baek 8f72f8def9 fix: styling 2025-02-18 23:44:54 -08:00
Timothy Jaeryang Baek 9ca4727573 enh: web search behaviour 2025-02-18 21:29:27 -08:00
Timothy Jaeryang Baek 5465cabd40 refac 2025-02-18 21:17:09 -08:00
Timothy Jaeryang Baek 81715f6553 enh: RAG full context mode 2025-02-18 21:14:58 -08:00
Timothy Jaeryang Baek a6a7c548d5 refac: code block styling 2025-02-18 20:24:04 -08:00
Timothy Jaeryang Baek 003968f06a enh: jupyter matplotlib support 2025-02-18 20:15:16 -08:00
Timothy Jaeryang Baek 2ee09d9f7d fix: prompt suggestions settings 2025-02-18 20:07:59 -08:00
Timothy Jaeryang Baek 9380fcd09a refac 2025-02-18 20:01:24 -08:00
Timothy Jaeryang Baek 32432d6df1 fix: do NOT update changelog 2025-02-18 20:00:24 -08:00
Timothy Jaeryang Baek 1bbecd46c8 Merge pull request #10052 from roryeckel/playwright
Support Playwright RAG Web Loader: Revised
2025-02-18 19:57:48 -08:00
Timothy Jaeryang Baek c658781995 Merge pull request #10268 from hurxxxx/feat/hide-citations-in-message
feat: citations disabled model to exclude source citations in messages
2025-02-18 19:37:12 -08:00
Timothy Jaeryang Baek 84af508525 Merge branch 'dev' into feat/hide-citations-in-message 2025-02-18 19:37:03 -08:00
Timothy Jaeryang Baek 6f792e0558 Merge pull request #10271 from juquxiang/feat_user_query
Added user filtering by email and username
2025-02-18 19:36:18 -08:00
Timothy Jaeryang Baek 4ef7aff663 refac 2025-02-18 19:35:22 -08:00
Timothy Jaeryang Baek 8f7528a0bc Merge pull request #10272 from mkhludnev/dedupe-rag-docs
fix: dedupe results from multiple queries
2025-02-18 19:34:33 -08:00
Timothy Jaeryang Baek 5a7f9c81e3 Merge pull request #10308 from crpietschmann/azure-storage
feat: Add AzureStorageProvider for Azure Blob Storage support
2025-02-18 19:32:17 -08:00
Timothy Jaeryang Baek 886d756200 Merge pull request #10285 from the-c0d3br34k3r/issue8885_auth
fix: Fixed an issue with clearing application cookies during OAuth signout
2025-02-18 19:31:24 -08:00
Timothy Jaeryang Baek a33214ab6b Merge pull request #10304 from ttv20/dev
i18n: Improve RTL text handling in chat and sidebar with auto-direction #2
2025-02-18 19:31:12 -08:00
Timothy Jaeryang Baek 32a90deeaf Merge pull request #10309 from JoaoCostaIFG/gemini_image_gen
feat: add Google Imagen/Gemini API image generation
2025-02-18 19:30:20 -08:00
Timothy Jaeryang Baek 0b271d24d1 Merge pull request #10311 from alexgleason/fix-undefined-title
Fix "Cannot read properties of undefined (reading 'startsWith')"
2025-02-18 19:29:42 -08:00
Timothy Jaeryang Baek ea759c4742 Merge pull request #10323 from iamobservable/feature/frontend-authentication-redirection
feat: Feature/frontend authentication redirection
2025-02-18 19:29:23 -08:00
= 7837843f82 Add redirect capability
This feature allows the authentication process to redirect to a
route passed in the querystring. This allows the /auth route
a means of bringing the user to an expected route instead of the
main page (root).
2025-02-18 21:16:54 -06:00
Alex Gleason 5639ba423b Fix "Cannot read properties of undefined (reading 'startsWith')" 2025-02-18 18:47:56 -06:00
JoaoCostaIFG 918764a4f7 fix: Use x-goog-api-key header for Gemini image generation
Place the API key in a header instead of a query parameter. This avoids leaking the API key in logs on request failure, etc...
2025-02-19 00:00:54 +00:00
JoaoCostaIFG e56b5c063c feat: add Google Imagen/Gemini API image generation
Adds support for Gemini API as an image generation backend. By setting the API Base URL to something like 'https://generativelanguage.googleapis.com/v1beta' and providing their API Key, users should be able to start generating images using models like 'imagen-3.0-generate-002'.
2025-02-18 22:39:32 +00:00
Chris Pietschmann a232f1f34e Update test_provider.py 2025-02-18 15:53:54 -05:00
Chris Pietschmann 9864185b57 Update test_provider.py 2025-02-18 15:49:44 -05:00
Chris Pietschmann 888ae00867 Update test_provider.py 2025-02-18 15:39:47 -05:00
Chris Pietschmann 7b5f82ffc7 Update test_provider.py 2025-02-18 15:26:04 -05:00
Chris Pietschmann 7404494772 formatting 2025-02-18 15:19:35 -05:00
Chris Pietschmann a29f83c4e7 updates to formatting 2025-02-18 15:17:49 -05:00
Chris Pietschmann 4c352ff974 Update test_provider.py 2025-02-18 15:14:46 -05:00
Chris Pietschmann 55bd7a1c65 Update test_provider.py 2025-02-18 15:13:30 -05:00
Chris Pietschmann 9c8c837ab9 Update test_provider.py 2025-02-18 15:12:35 -05:00
Chris Pietschmann 2c328cc7c9 Update test_provider.py 2025-02-18 15:04:49 -05:00
Chris Pietschmann 56060db29d Update test_provider.py 2025-02-18 15:01:26 -05:00
Chris Pietschmann 7d1ec20429 Update test_provider.py 2025-02-18 14:57:51 -05:00
Chris Pietschmann ff5f0c3e39 Update test_provider.py 2025-02-18 14:51:17 -05:00
Chris Pietschmann 9a2e81f5f0 Update test_provider.py 2025-02-18 14:49:03 -05:00
Chris Pietschmann f674e28263 Update test_provider.py 2025-02-18 14:45:13 -05:00
Chris Pietschmann 4a9a88b683 Update test_provider.py 2025-02-18 14:41:42 -05:00
Chris Pietschmann b86f8df29f Update test_provider.py 2025-02-18 14:37:10 -05:00
Elkana Bardugo 61644f216e Update CHANGELOG.md 2025-02-18 21:30:25 +02:00
Chris Pietschmann cb0666ac21 update 2025-02-18 14:13:54 -05:00
Chris Pietschmann 2f4f4c2376 add tests 2025-02-18 14:09:00 -05:00
Elkana Bardugo 0b1e30988a Update MarkdownTokens.svelte
More dir="auto" to auto direction on RTL
2025-02-18 21:08:25 +02:00
Chris Pietschmann 13227fc017 Merge branch 'azure-storage' of https://github.com/crpietschmann/open-webui into azure-storage 2025-02-18 13:39:37 -05:00
Chris Pietschmann cc4598c41b Update build-release.yml 2025-02-18 13:39:27 -05:00
Timothy Jaeryang Baek e7560a5acf Merge pull request #10269 from KarlLee830/translate
i18n: Update Chinese Translation
2025-02-18 10:37:16 -08:00
Chris Pietschmann 745b24f13a Merge branch 'open-webui:main' into azure-storage 2025-02-18 13:36:56 -05:00
Chris Pietschmann aee57107bc Update config.py 2025-02-18 13:27:37 -05:00
Chris Pietschmann e4febfa097 Add AzureStorageProvider config options 2025-02-18 13:25:49 -05:00
Chris Pietschmann fd3c24af4e Add AzureStorageProvider 2025-02-18 13:25:31 -05:00
Timothy Jaeryang Baek d0114e0703 fix: temp chat issue 2025-02-18 09:57:12 -08:00
Timothy Jaeryang Baek 359f8b67f8 fix: mobile hover issue 2025-02-18 09:54:31 -08:00
Ranjan Mohan 6c6be5de88 Fixed an issue with clearing application cookies during OAuth signout
Closes #8885.

During the OAuth signout flow, although the `token` and `oauth_id_token`
cookies were marked for deletion, a new RedirectResponse is created and
returned. This does not contain the header info from the he Response object
used to mark the cookies to be deleted. Hence the cookies remained.
Fixed this by re-using the headers from the other Response object.
2025-02-18 12:44:14 -05:00
mikhail-khludnev 925bfe840b dedupe results from multiple queries 2025-02-18 20:10:57 +03:00
juxiang 55b0ac85d1 Added user filtering by email and username
Added user filtering by email and username
2025-02-19 00:53:38 +08:00
KarlLee830 d4743b1a17 i18n: Update Chinese Translation 2025-02-18 23:42:22 +08:00
KarlLee830 4939d6871b i18n: Update Chinese Translation 2025-02-18 23:40:25 +08:00
hurxxxx a381ffc585 revert 2025-02-18 23:17:06 +09:00
hurxxxx cdc13e9960 chore: Fix unnecessary whitespace issues 2025-02-18 23:15:57 +09:00
hurxxxx 9d06e3b2cd feat: chat responses using the citations-disabled model to exclude source citations 2025-02-18 21:56:16 +09:00
Timothy Jaeryang Baek 3f3a5bb0ab Merge pull request #10238 from open-webui/dev
0.5.14
2025-02-17 21:48:39 -08:00
Timothy Jaeryang Baek 0c3ba5123e doc: changelog 2025-02-17 21:48:00 -08:00
Timothy Jaeryang Baek c513308ded Merge pull request #10236 from open-webui/dev
refac
2025-02-17 21:34:36 -08:00
Timothy Jaeryang Baek 1764170307 refac 2025-02-17 21:34:06 -08:00
Timothy Jaeryang Baek e4c9734fcb Merge pull request #10038 from open-webui/dev
0.5.13
2025-02-17 20:36:50 -08:00
Timothy Jaeryang Baek 188b928548 doc: changelog 2025-02-17 20:28:13 -08:00
Timothy Jaeryang Baek e8b11a78d1 chore: format 2025-02-17 20:18:03 -08:00
Rory 10e0c81de9 Merge remote-tracking branch 'upstream/dev' into playwright
# Conflicts:
#	backend/open_webui/retrieval/web/utils.py
#	backend/open_webui/routers/retrieval.py
2025-02-17 21:53:39 -06:00
Timothy Jaeryang Baek d5ab2c6891 refac: readme 2025-02-17 19:52:34 -08:00
Timothy Jaeryang Baek fdaa6a9ee5 doc: readme 2025-02-17 19:51:41 -08:00
Timothy Jaeryang Baek c657e2a1bb doc: readme 2025-02-17 19:51:10 -08:00
Rory bc82f48ebf refac: RAG_WEB_LOADER -> RAG_WEB_LOADER_ENGINE 2025-02-17 21:43:32 -06:00
Timothy Jaeryang Baek 658944e756 refac 2025-02-17 19:29:28 -08:00
Timothy Jaeryang Baek ba6cde8a87 fix: include_domain does NOT exist 2025-02-17 19:20:49 -08:00
Timothy Jaeryang Baek 9bd26d6faa enh: avif support 2025-02-17 18:55:48 -08:00
Timothy Jaeryang Baek a79a6a5c34 chore: format 2025-02-17 18:51:40 -08:00
Timothy Jaeryang Baek 0c461023fe enh: svg diagram download button 2025-02-17 18:50:23 -08:00
Timothy Jaeryang Baek 93731e4ca9 fix: temp chat message continue 2025-02-17 18:40:40 -08:00
Timothy Jaeryang Baek f72e28a56c enh: message delete confirm dialog 2025-02-17 18:33:21 -08:00
Timothy Jaeryang Baek dbe5d1ca08 refac 2025-02-17 18:16:23 -08:00
Timothy Jaeryang Baek ca0b7217d2 enh: full context web search 2025-02-17 18:14:26 -08:00
Timothy Jaeryang Baek 16ce8ab16c refac 2025-02-17 17:41:58 -08:00
Timothy Jaeryang Baek 70a5be08c7 refac 2025-02-17 16:33:14 -08:00
Timothy Jaeryang Baek b850b8a5a4 refac: styling 2025-02-17 16:33:01 -08:00
Timothy Jaeryang Baek 05af00305d enh: warning 2025-02-17 16:30:13 -08:00
Timothy Jaeryang Baek 2f75eef499 enh: code execution settings 2025-02-17 16:25:50 -08:00
Timothy Jaeryang Baek 3df6fa7ccb Merge pull request #10206 from ttv20/patch-1
i18n: Improve RTL text handling in chat and sidebar with auto-direction
2025-02-17 15:24:59 -08:00
Timothy Jaeryang Baek a5fa1cd835 Merge pull request #10209 from i-infra/iinf/fix-for-openrouter
[fix] no unambiguous indexing on "owned_by" - fix OpenRouter.ai
2025-02-17 15:24:21 -08:00
Elkana Bardugo 8d149348a0 Update MarkdownTokens.svelte: Revert text-align for download button in rtl
prevent button overriding because the download button is in absolute position and it doesn't have start/end properties
2025-02-17 22:43:34 +02:00
Elkana Bardugo d26569f636 Update ChatItem.svelte: Revert text-align for download button in rtl
prevent button overriding because the menu button is in absolute position and it doesn't have start/end properties
2025-02-17 22:42:37 +02:00
Elkana Bardugo 93590d224b Merge branch 'dev' into patch-1 2025-02-17 22:35:36 +02:00
Elkana Bardugo 0888ddde7c Fix card title direction and alignment (for RTL) 2025-02-17 22:03:03 +02:00
Elkana Bardugo 834617ab91 fix blockquote border line direction in RTL 2025-02-17 21:57:47 +02:00
Elkana Bardugo b73b8343d5 fix table header align on rtl 2025-02-17 21:40:11 +02:00
Elkana Bardugo ab94017e3a Auto text direction (fix for RTL) in most cases
to test it use the prompt:
"write please a sample headers (level 1,2,3), text (bold/italic), list, numbered list, quetes, table, code
write each example in hebrew
dont output markdown in code block"

need to be fixed:
* Redundant border properties in quotes:
Removed border-left as border-inline-start properly handles both LTR/RTL and by this prevents double borders in RTL layouts

* table header have `text-align: left` instead of start
e.g.
text-align and direction is not the save thing
the text direction is ok. the `dir="auto"` is fixing the direction שמג the text-align by default is set by the direction, if it set manually is should be start/end to respect the direction attribute
2025-02-17 21:27:05 +02:00
Timothy Jaeryang Baek 82189066e8 refac 2025-02-16 18:35:09 -08:00
Timothy Jaeryang Baek 3b856b64ed refac 2025-02-16 02:33:25 -08:00
Timothy Jaeryang Baek 63cf80a456 refac 2025-02-16 00:11:18 -08:00
Timothy Jaeryang Baek 91de8e082e refac: styling 2025-02-15 22:35:42 -08:00
Timothy Jaeryang Baek 19c340d3fb refac: pipelines 2025-02-15 22:25:18 -08:00
Timothy Jaeryang Baek ea15d91e29 Merge pull request #10016 from ferret99gt/tweak-and-add-advanced-parameters-for-ollama
feat: Tweak and add advanced parameters for ollama
2025-02-15 22:07:59 -08:00
Timothy Jaeryang Baek 5af926bac8 refac 2025-02-15 21:14:03 -08:00
Timothy Jaeryang Baek e4d6fc65ca refac: theme 2025-02-15 21:04:07 -08:00
Timothy Jaeryang Baek 87ff1a9038 refac: styling 2025-02-15 20:35:10 -08:00
Timothy Jaeryang Baek f2006c7efe refac: styling 2025-02-15 20:22:57 -08:00
Rory 66c2acc08d Merge branch 'dev' into playwright 2025-02-15 22:14:16 -06:00
Timothy Jaeryang Baek fab093395b Merge pull request #10065 from LuyiTian/dev
fix:Update Chat.svelte error handling of previous message
2025-02-15 20:11:40 -08:00
Timothy Jaeryang Baek b0ad5cd863 Merge pull request #10076 from crizCraig/local_date
fix: return local date from `getFormattedDate`
2025-02-15 20:10:56 -08:00
Timothy Jaeryang Baek fd8998a38f refac 2025-02-15 19:50:40 -08:00
Timothy Jaeryang Baek 052531ac13 refac 2025-02-15 19:41:09 -08:00
Timothy Jaeryang Baek 60e322962e refac 2025-02-15 19:35:12 -08:00
Timothy Jaeryang Baek e3fa48b6ce chore: tailwind v4 migration 2025-02-15 19:27:25 -08:00
Timothy Jaeryang Baek 30182d77cc refac 2025-02-15 19:08:07 -08:00
Timothy Jaeryang Baek a0126f371e refac: general admin settings 2025-02-15 18:24:13 -08:00
Timothy Jaeryang Baek ff60754091 refac: general admin settings 2025-02-15 18:15:50 -08:00
Timothy Jaeryang Baek b99f296494 Merge pull request #10075 from TiancongLx/dev
i18n: update zh-TW
2025-02-15 17:28:52 -08:00
Timothy Jaeryang Baek bbda717b69 refac: citations 2025-02-15 17:24:29 -08:00
Timothy Jaeryang Baek 3d0c06ccee refac: duckduckgo 2025-02-15 16:45:56 -08:00
i-infra 5e3742f899 and one last edit 2025-02-15 19:42:58 -05:00
i-infra fb12ee3f52 fix exception where openrouter doesn't populate - no longer index without fallback 2025-02-15 19:41:41 -05:00
Timothy Jaeryang Baek 38291e9af2 refac 2025-02-15 16:21:19 -08:00
Timothy Jaeryang Baek f0feb7bd35 refac 2025-02-15 16:10:35 -08:00
Craig Quiter e67eb89e05 style: black format 2025-02-15 10:53:16 -08:00
Craig Quiter 0dae8ded13 fix: return local date from getFormattedDate 2025-02-15 10:37:40 -08:00
Tiancong Li 4045e96e96 i18n: update zh-TW 2025-02-16 01:54:58 +08:00
Luyi Tian 1aa963a2fe Update Chat.svelte error handling of previous message
related to this discussion: https://github.com/open-webui/open-webui/discussions/10034. in some cases the previous message have error but it still generate a response. in such case we should also next round chat. so I update the if condition to add another checking of the content in previous message.
2025-02-15 21:25:12 +08:00
Rory 8e9b00a017 Fix docstring 2025-02-14 22:48:15 -06:00
Rory b1bab2ece8 Remove duplicate loader.alazy_load line from merge 2025-02-14 22:43:46 -06:00
Rory aa2b764d74 Finalize incomplete merge to update playwright branch
Introduced feature parity for trust_env
2025-02-14 22:32:45 -06:00
Rory 4da220c513 Merge remote-tracking branch 'upstream/dev' into playwright
# Conflicts:
#	backend/open_webui/config.py
#	backend/open_webui/main.py
#	backend/open_webui/retrieval/web/utils.py
#	backend/open_webui/routers/retrieval.py
#	backend/open_webui/utils/middleware.py
#	pyproject.toml
2025-02-14 20:48:22 -06:00
Timothy Jaeryang Baek 74c8690cd1 Merge pull request #9989 from Yimi81/feate-webloader-support-proxy
feat: web loader support proxy
2025-02-14 18:08:51 -08:00
Guofeng Yi b38acc8559 Merge branch 'dev' into feate-webloader-support-proxy 2025-02-15 09:50:02 +08:00
ferret99gt bb72957535 Update field label for Ollama convention 2025-02-14 18:02:30 -05:00
Timothy Jaeryang Baek 3e543691a4 Merge pull request #9988 from Yimi81/feat-support-async-load
feat: websearch support async docs load
2025-02-14 14:10:46 -08:00
Timothy Jaeryang Baek 2a67d3d6cd Merge pull request #10005 from bogdanr/main
Added Romanian translations
2025-02-14 14:09:35 -08:00
Timothy Jaeryang Baek a13f90fc60 Merge pull request #10002 from alpha-pet/fix-markdown-inline-whitespace
fix: remove whitespace to improve typesetting for inline Markdown
2025-02-14 13:28:18 -08:00
Timothy Jaeryang Baek c797ef3357 Merge pull request #9990 from panda44312/patch-4
i18n Update zh-cn
2025-02-14 13:27:55 -08:00
Timothy Jaeryang Baek 0746e2f682 Merge pull request #10021 from silentoplayz/ASCII-font-change
enh: "Open WebUI" ASCII Art with ANSI Shadow Font
2025-02-14 13:27:32 -08:00
Timothy Jaeryang Baek 8d63ee55f3 Merge pull request #10019 from liucoj/dev
fix: Domain filter list in Tavily search
2025-02-14 13:27:13 -08:00
Timothy Jaeryang Baek 7705ba16e4 Merge pull request #10024 from Kylapaallikko/main
18n: Update Finnish translation
2025-02-14 13:26:55 -08:00
Timothy Jaeryang Baek 3d26bca7c5 refac: deprecate [ ] prompt variables 2025-02-14 12:40:42 -08:00
Kylapaallikko 7037ae2f55 Update translation.json 2025-02-14 20:06:59 +02:00
Kylapaallikko 2448c4e290 Update translation.json 2025-02-14 20:01:14 +02:00
Kylapaallikko fcb1178dc7 Update translation.json 2025-02-14 19:57:58 +02:00
silentoplayz 665b67ff35 Update main.py
Change ASCII font for "Open WebUI" from "Standard" to "ANSI Shadow"
2025-02-14 12:52:57 -05:00
Kylapaallikko c70947c967 Update translation.json 2025-02-14 19:52:20 +02:00
silentoplayz 1a2d81bc01 Update main.py
Change ASCII font for "Open WebUI" from "Standard" to "ANSI Shadow"
2025-02-14 12:48:33 -05:00
Kylapaallikko 6b853ec36b Update translation.json 2025-02-14 19:47:48 +02:00
Kylapaallikko 9a170790ad Update translation.json 2025-02-14 19:31:05 +02:00
LiuC0j ca8458024e Merge pull request #1 from liucoj/liucoj-patch-1
fix: Domain Filter list in tavily.py
2025-02-14 18:21:38 +01:00
ferret99gt 941c787806 Add presence penalty (openAi/ollama/others) and repeat penalty (ollama only?)
- Add Presence Penalty, which I believe most providers have.
- Add repeat_penalty, an Ollama / Llama.cpp only parameter
- Widen temperature range to 2 (supported by many providers and similar front ends)
- Widen Top K range (supported by many providers and similar front ends)
- Adjust description of freqency_penalty in line with OpenAI documentation
- Add presence_penalty with an OpenAI documentation based description
- Add repeat_penalty with an Ollama documentation based description
2025-02-14 12:02:55 -05:00
hdnh2006 0afe972bc6 embeddings function added 100% OpenAI compatible 2025-02-14 17:57:47 +01:00
LiuC0j a8e310429c FIx: Domain Filter list in tavily.py 2025-02-14 14:57:16 +01:00
LiuC0j 5ca39eb9fd Update tavily.py 2025-02-14 14:56:01 +01:00
Bogdan Radulescu 8d898f2d12 Added romanian translations 2025-02-14 15:17:25 +02:00
Thomas Rehn 9072959858 fix: remove whitespace to improve typesetting for inline Markdown 2025-02-14 13:16:03 +01:00
Fabio Polito 2419ef06a0 feat: docling support for document preprocessing 2025-02-14 12:08:03 +00:00
Panda 42119e2c52 Update translation.json 2025-02-14 09:04:48 +01:00
Panda f376a61578 Merge branch 'open-webui:main' into patch-4 2025-02-14 09:02:45 +01:00
Panda 85c22889da Update translation.json 2025-02-14 09:00:58 +01:00
Yimi81 d3f71930f0 web loader support proxy 2025-02-14 07:15:09 +00:00
Timothy Jaeryang Baek 2017856791 Merge pull request #9945 from open-webui/dev
0.5.12
2025-02-13 23:12:46 -08:00
Timothy Jaeryang Baek 893bfe9d3a doc: changelog 2025-02-13 23:11:58 -08:00
Yimi81 ceef600223 support async load for websearch 2025-02-14 07:05:10 +00:00
Timothy Jaeryang Baek 99b50b39fe refac 2025-02-13 22:57:12 -08:00
Timothy Jaeryang Baek 304aed0f13 chore: format 2025-02-13 22:54:45 -08:00
Timothy Jaeryang Baek 7b37cdcebb Merge pull request #9980 from xring/web_search_serpapi
feat: add web search via SerpApi
2025-02-13 22:51:14 -08:00
Timothy Jaeryang Baek d9ee53b504 refac: placeholder performance 2025-02-13 22:45:03 -08:00
Timothy Jaeryang Baek fa92abce31 refac 2025-02-13 22:37:01 -08:00
Timothy Jaeryang Baek b7aeb432ed refac 2025-02-13 22:11:56 -08:00
Timothy Jaeryang Baek c9a8808b0d refac 2025-02-13 21:45:29 -08:00
xring 27d395ba06 feat: add web search via SerpApi 2025-02-14 12:24:58 +08:00
Timothy Jaeryang Baek da757069de refac 2025-02-13 17:06:55 -08:00
Timothy Jaeryang Baek e1435501aa fix 2025-02-13 15:17:41 -08:00
Timothy Jaeryang Baek 68519d6ca7 enh: multiple tool calls support 2025-02-13 14:50:46 -08:00
Timothy Jaeryang Baek f20b7c2f33 fix: user direct connections 2025-02-13 14:21:34 -08:00
Timothy Jaeryang Baek deeb04e695 Merge pull request #9942 from SleepyYui/bugfix-9635
fix: Fix text completion on playground page
2025-02-13 13:14:11 -08:00
Timothy Jaeryang Baek cd27845c75 fix: direct connections 2025-02-13 13:05:57 -08:00
SleepyYui ba4b0db462 fix playground text completion 2025-02-13 22:05:41 +01:00
Timothy Jaeryang Baek 95d56c737d Merge pull request #9907 from smonux/dev
fix: re-enable tools in native function calls after first invocation
2025-02-13 12:52:47 -08:00
Timothy Jaeryang Baek df1ff8f994 chore: remove flask 2025-02-13 12:52:17 -08:00
Timothy Jaeryang Baek c315634365 Merge pull request #9917 from nachogmd/dev
feat: Optional title generation
2025-02-13 12:51:54 -08:00
Kylapaallikko 70e8337536 Update translation.json 2025-02-13 22:36:45 +02:00
Didier FOURNOUT 06062568c7 black formatting 2025-02-13 16:12:46 +00:00
Didier FOURNOUT 6d62e71c34 Add x-Open-Webui headers for ollama + more for openai 2025-02-13 15:29:26 +00:00
Nacho G. Mac Dowell c47eddce32 Optional title generation
The boolean configuration var ENABLE_TITLE_GENERATION makes title generation optionaL
2025-02-13 16:28:39 +01:00
Samuel e98f859a14 format 2025-02-13 12:19:24 +00:00
Samuel 86074cff6c fix: re-enable tool use when sending tool output 2025-02-13 12:18:21 +00:00
Timothy Jaeryang Baek 3ac3615ecd Merge pull request #9890 from OriginalSimon/dev
18n: Update Ukrainian translation
2025-02-13 02:22:36 -08:00
Simon d590647d09 Update translation.json 2025-02-13 11:21:18 +01:00
Timothy Jaeryang Baek e4d7d41df6 Merge pull request #9889 from open-webui/dev
doc: changelog
2025-02-13 02:11:00 -08:00
Timothy Jaeryang Baek a461861030 doc: changelog 2025-02-13 02:10:36 -08:00
Timothy Jaeryang Baek 4d667e447d Merge pull request #9480 from open-webui/dev
0.5.11
2025-02-13 02:06:04 -08:00
Timothy Jaeryang Baek 57e256be3e chore: bump 2025-02-13 02:05:26 -08:00
Timothy Jaeryang Baek f831104708 doc: changelog 2025-02-13 02:03:13 -08:00
Timothy Jaeryang Baek acb3eef619 refac 2025-02-13 01:57:02 -08:00
Timothy Jaeryang Baek 6acda2e6ec refac: code interpreter 2025-02-13 00:40:04 -08:00
Timothy Jaeryang Baek 6d899b80d0 refac: direct connections 2025-02-13 00:34:45 -08:00
Timothy Jaeryang Baek eb568695e7 chore: format 2025-02-13 00:13:33 -08:00
Timothy Jaeryang Baek 7ff719938a refac: citations 2025-02-12 23:55:14 -08:00
Timothy Jaeryang Baek a1dc2664c2 refac 2025-02-12 23:49:00 -08:00
Timothy Jaeryang Baek c28d82b10d Merge branch 'dev' of https://github.com/open-webui/open-webui into dev 2025-02-12 23:38:53 -08:00
Timothy Jaeryang Baek c5b92dbffa chore: bump 2025-02-12 23:38:48 -08:00
Timothy Jaeryang Baek c0dfafca70 Merge pull request #9844 from Seniorsimo/bug-9773
Fix - Added support for API tool_calls when stream false
2025-02-12 23:37:24 -08:00
Timothy Jaeryang Baek 7e73790d6c refac 2025-02-12 23:33:53 -08:00
Timothy Jaeryang Baek 5626426c31 chore: format 2025-02-12 23:28:57 -08:00
Timothy Jaeryang Baek 83e5db7be7 refac 2025-02-12 23:26:47 -08:00
Timothy Jaeryang Baek 2b7f9d14d0 refac 2025-02-12 23:21:16 -08:00
Timothy Jaeryang Baek c83e68282d feat: direct connections integration 2025-02-12 22:56:33 -08:00
Simone b0ade6c04c Fixed typo 2025-02-13 07:04:02 +01:00
Rory 40d4db97e6 Merge remote-tracking branch 'upstream/dev' into playwright 2025-02-12 22:32:44 -06:00
Timothy Jaeryang Baek 304ce2a14d Merge pull request #9865 from feynmanliang/fix-9864
fix - Fixes citation modal toggle when clicking inliine citations and # citations > 3
2025-02-12 14:32:02 -08:00
Timothy Jaeryang Baek 67958c02b4 refac 2025-02-12 14:29:43 -08:00
Timothy Jaeryang Baek 9f9adce72c fix 2025-02-12 14:23:53 -08:00
Feynman Liang 361a98980e Retab collapsible 2025-02-12 13:49:37 -08:00
Feynman Liang 113addef46 Merge branch 'dev' into fix-9864 2025-02-12 13:47:54 -08:00
Feynman Liang 08bc7d4cfe Uncollapse so all source buttons visible 2025-02-12 13:46:42 -08:00
Feynman Liang 3f24062416 Adds source-* ids when citations > 3 2025-02-12 12:30:23 -08:00
Timothy Jaeryang Baek a0df6cce40 refac 2025-02-12 01:41:59 -08:00
Timothy Jaeryang Baek 2e77d5ef0e refac 2025-02-12 01:32:49 -08:00
Timothy Jaeryang Baek 0bec9122c1 refac 2025-02-12 01:22:53 -08:00
Timothy Jaeryang Baek 431e97b03a wip: direct models 2025-02-12 01:17:30 -08:00
Simone 7dc000a6b9 added support for API tool_calls if stream false 2025-02-12 09:11:26 +01:00
Timothy Jaeryang Baek 982b1fb7e2 wip: direct connections 2025-02-12 00:08:51 -08:00
Timothy Jaeryang Baek cd2f4142d5 fix: user settings save issue 2025-02-11 23:42:31 -08:00
Timothy Jaeryang Baek 862b5a947a refac: connections 2025-02-11 23:21:09 -08:00
Timothy Jaeryang Baek 689317c5b5 refac 2025-02-11 23:13:48 -08:00
Timothy Jaeryang Baek 8daa549146 refac 2025-02-11 23:12:00 -08:00
Timothy Jaeryang Baek 153413dc54 refac 2025-02-11 22:33:03 -08:00
Timothy Jaeryang Baek afe92fd227 refac 2025-02-11 22:31:27 -08:00
Timothy Jaeryang Baek 3891161173 feat: direct api settings backend 2025-02-11 22:29:45 -08:00
Timothy Jaeryang Baek 24cbc469cc enh: allow image only message 2025-02-11 21:52:31 -08:00
Timothy Jaeryang Baek a5bba20915 Merge pull request #9837 from silverriver/patch-1
feat Make Google PSE search return more than 10 google search results
2025-02-11 21:36:53 -08:00
Timothy Jaeryang Baek f916fbba56 enh: custom code interpreter prompt 2025-02-11 21:36:16 -08:00
Timothy Jaeryang Baek 953e408077 refac 2025-02-11 21:13:42 -08:00
Timothy Jaeryang Baek ab70f1bb50 Merge pull request #9486 from rragundez/store-images
Use DB for generated images
2025-02-11 21:12:17 -08:00
Timothy Jaeryang Baek 627ed7c9ce refac 2025-02-11 21:03:38 -08:00
Silver 7e08373ae5 Update google_pse.py to return results more than 10 2025-02-12 13:01:09 +08:00
Timothy Jaeryang Baek 8906a2e260 Merge pull request #9803 from BochaAI/main
add Bocha
2025-02-11 21:01:04 -08:00
Timothy Jaeryang Baek 8199281eee Merge pull request #9784 from aleixdorca/dev
Update catalan translation.json
2025-02-11 18:58:01 -08:00
Timothy Jaeryang Baek a1554559c4 Merge pull request #9800 from rragundez/404-non-html
WIP Return 404 for non html files
2025-02-11 18:57:51 -08:00
Timothy Jaeryang Baek 591ca35275 Merge pull request #9827 from TiancongLx/dev
i18n: update zh-TW
2025-02-11 18:55:18 -08:00
Tiancong Li 7057814c3b i18n: update zh-TW 2025-02-12 05:37:15 +08:00
Rodrigo Agundez 31ee7a68a2 Only javascript files 2025-02-11 21:21:27 +08:00
Rodrigo Agundez 5d68737b31 Return 404 for non html files 2025-02-11 18:49:36 +08:00
Aleix Dorca 92a584bf3c Update catalan translation.json 2025-02-11 06:45:03 +01:00
Timothy Jaeryang Baek 16bae8f33a refac 2025-02-10 13:53:16 -08:00
Timothy Jaeryang Baek 7ebb07c04c refac 2025-02-10 13:44:25 -08:00
Timothy Jaeryang Baek a273cba0fb refac: code intepreter 2025-02-10 13:12:05 -08:00
Timothy Jaeryang Baek 610f9d039a fix: account page issue 2025-02-10 13:00:44 -08:00
Timothy Jaeryang BaekandSimone 0f12c4d14f fix: ollama tool calling
Co-Authored-By: Simone <6941100+seniorsimo@users.noreply.github.com>
2025-02-10 12:18:49 -08:00
Timothy Jaeryang Baek 293f64353d Merge pull request #9751 from pseudorm/bug/user-signup/fix-oauth-username-claim-has-no-effect
Fix: Setting OAUTH_USERNAME_CLAIM has no effect on username for user during oauth signup
2025-02-10 11:26:56 -08:00
Timothy Jaeryang Baek 63a5ee3adb refac 2025-02-10 11:25:38 -08:00
Timothy Jaeryang Baek b935a839fe Merge pull request #9744 from hurxxxx/fix/title-tag-gen-at-model
fix: title and tag generation did not work when selecting "atSelectedModel"
2025-02-10 11:16:03 -08:00
Timothy Jaeryang Baek 54e0299dda chore: bump 2025-02-10 11:14:04 -08:00
pseudorm 336d1d95c5 Merge branch 'dev' into bug/user-signup/fix-oauth-username-claim-has-no-effect 2025-02-10 22:00:20 +08:00
chester.cheng 1b6e12a255 add warning 2025-02-10 20:49:55 +08:00
chester.cheng db0a12f9f1 check name is none 2025-02-10 20:36:01 +08:00
Timothy Jaeryang Baek abfe868732 enh: code interpreter global toggle 2025-02-10 02:28:01 -08:00
Timothy Jaeryang Baek f9c5819314 enh: code interpreter jupyter support 2025-02-10 02:25:02 -08:00
luckyman-yan 31360fe991 add Bocha 2025-02-10 16:44:47 +08:00
Gunwoo Hur 91d0632bf4 fix: Fix issue where title and tag generation did not work when selecting the At model 2025-02-10 17:06:22 +09:00
Timothy Jaeryang Baek 29c781875d refac 2025-02-10 00:02:23 -08:00
Timothy Jaeryang Baek d95e5e0ba5 enh: kokorojs call support 2025-02-09 23:54:24 -08:00
Timothy Jaeryang Baek 205ce635f6 feat: Kokoro-js TTS support 2025-02-09 23:42:27 -08:00
Timothy Jaeryang Baek a22d1d5410 refac: code block 2025-02-09 22:43:32 -08:00
Timothy Jaeryang Baek 60095598ec chore: format 2025-02-09 22:20:47 -08:00
Timothy Jaeryang Baek 426f8f29ad refac 2025-02-09 22:19:02 -08:00
Timothy Jaeryang Baek 5551a4bff5 Merge pull request #9739 from yukiteruamano/fix-spanish
i18n: fix Spanish (es_ES) translations
2025-02-09 22:15:39 -08:00
Timothy Jaeryang Baek de2026b5cc Merge pull request #9733 from rragundez/patch-ssrf
Prevent SSRF and HTML injection
2025-02-09 22:15:03 -08:00
Rory 2c711d8365 Merge remote-tracking branch 'upstream/dev' into playwright
# Conflicts:
#	backend/requirements.txt
2025-02-09 23:52:21 -06:00
Jose Maldonado aka Yukiteru b1711e9491 i18n: fix a bad (badword: propmt) translation in es_ES (Spanish) 2025-02-10 01:07:32 -04:00
Jose Maldonado aka Yukiteru a756adfaee i18n: fix translations for es_ES (Spanish) 2025-02-10 00:37:59 -04:00
Rodrigo Agundez 167c8bf00d Prevent SSRF and HTML injection 2025-02-10 10:35:10 +08:00
Timothy Jaeryang Baek 3e1452902f chore: bump 2025-02-09 16:02:09 -08:00
Timothy Jaeryang Baek 790a747647 fix 2025-02-09 13:18:26 -08:00
Timothy Jaeryang Baek a1b31f99ae Merge pull request #9688 from yfzhou0904/main
feat: if autocomplete-generation is turned off, frontend should not attempt autocomplete request
2025-02-09 13:07:43 -08:00
Timothy Jaeryang Baek d5a815b19c Merge pull request #9693 from vinsdragonis/main
fix: Fixed error occurring when using OpenSearch as a vector db
2025-02-09 13:06:19 -08:00
Timothy Jaeryang Baek 40bba83cee Delete docs/OpenSearch docker setup.md 2025-02-09 13:06:05 -08:00
Timothy Jaeryang Baek f25df15997 Merge pull request #9596 from engineeringpatrick/main
feat: add s3 key prefix support
2025-02-09 13:05:41 -08:00
Timothy Jaeryang Baek b7f676311f Merge pull request #9675 from manwallet/patch-1
Update translation.json
2025-02-09 13:05:15 -08:00
Timothy Jaeryang Baek ae6ca4f16c Merge pull request #9704 from s1adem4n/main
i18n: Add missing German translations
2025-02-09 13:05:02 -08:00
Jonathan 7ab674991e add missing german translations 2025-02-09 17:19:21 +01:00
Vineeth B V b9d049cb05 Create OpenSearch docker setup.md 2025-02-09 16:43:34 +05:30
Vineeth B V 5a1652bc63 Update requirements.txt 2025-02-09 16:14:41 +05:30
yfzhou 11f0c48434 frontend stores ENABLE_AUTOCOMPLETE_GENERATION state, prevents making autocomplete request if turned off 2025-02-09 17:13:54 +08:00
btcman bd9d60b5a0 Update translation.json
Some Chinese translation issues
2025-02-09 10:45:19 +08:00
Timothy Jaeryang Baek 43df7e1424 fix: sensitive input button type 2025-02-08 14:02:59 -08:00
Timothy Jaeryang Baek 425a8a9178 fix: connection config shifting 2025-02-08 14:01:56 -08:00
Timothy Jaeryang Baek 338a34563a fix: web search config 2025-02-08 13:44:08 -08:00
Rodrigo Agundez 2b05c9d944 Move file metadata into the [meta][data] key 2025-02-08 19:35:27 +09:00
Timothy Jaeryang Baek 181fca4707 refac: transformer.js 2025-02-08 02:34:30 -08:00
Timothy Jaeryang Baek 9be8bea6f4 fix: filter 2025-02-08 01:07:05 -08:00
Timothy Jaeryang Baek ee0152c1fa Merge pull request #9634 from zoupingshi/dev
chore: fix some typos
2025-02-07 23:07:25 -08:00
Timothy Jaeryang Baek 8c2164928a Merge pull request #9242 from NachoNoCheese/dev
feat: Add Deepgram STT Support
2025-02-07 23:06:57 -08:00
Timothy Jaeryang Baek 79c0b45543 Merge pull request #9631 from XingjianXie/remove_inlet_outlet_duplication
Refactor common code between inlet and outlet
2025-02-07 22:57:49 -08:00
Timothy Jaeryang Baek 3dde2f67cf refac 2025-02-07 22:57:39 -08:00
Timothy Jaeryang Baek dee07a6260 Merge pull request #9629 from rragundez/handle-no-picture
Handle no picture when retrieving from Microsoft EntraID
2025-02-07 22:52:35 -08:00
Timothy Jaeryang Baek 6862081d6b Merge pull request #9641 from SentinalMax/bugfix/GGUF-upload-issue
Fix: GGUF model upload instability
2025-02-07 22:51:44 -08:00
SentinalMax 95aaacfeb4 fixed GGUF model upload instability 2025-02-07 22:52:24 -06:00
zoupingshi d39a274ef8 chore: fix some typos
Signed-off-by: zoupingshi <hangfachang@outlook.com>
2025-02-08 12:14:01 +08:00
Rodrigo Agundez 546ef6ab42 Check is response is OK from retrieve the picture if not then default 2025-02-08 09:49:16 +09:00
Timothy Jaeryang Baek 4271b652a5 Merge pull request #9619 from XingjianXie/fix_after_tag
Fix tag_content_handler issue
2025-02-07 14:42:14 -08:00
Timothy Jaeryang Baek febc5d392f Merge pull request #9620 from tarmst/add-oauth-debug-logs
feat: Adding debug logs for oauth role & group management
2025-02-07 14:41:43 -08:00
Xingjian Xie c56bedc5ff Fix tag_content_handler issue: after_tag should be remove from the current content_blocks 2025-02-07 20:15:54 +00:00
tarmst 85912d726e Adding debug logs for oauth role & group management 2025-02-07 19:53:25 +00:00
Timothy Jaeryang Baek 4b4a86d4e7 chore: dependencies 2025-02-07 11:51:27 -08:00
Patrick Deniso f8a8218149 fix bug where '/' was not properly inserted in s3 key strings 2025-02-07 14:42:16 -05:00
Timothy Jaeryang Baek 3c5ac4ace5 Merge pull request #9416 from abdalrohman/fix_filter_domains
feat(ui): implement domain filter list for web search settings
2025-02-07 11:23:15 -08:00
Timothy Jaeryang Baek c092db379e fix 2025-02-07 11:23:04 -08:00
Timothy Jaeryang Baek 8a54df1ed2 Merge pull request #9516 from cloudron-io/oauth_username
oidc: pick up username correctly
2025-02-07 11:18:53 -08:00
Timothy Jaeryang Baek 65cef7c3e4 Merge pull request #9541 from EntropyYue/dev
feat: optimize time display
2025-02-07 11:17:39 -08:00
Timothy Jaeryang Baek 035330f70e Merge pull request #9505 from binxn/patch-1
Update jina_search.py
2025-02-07 11:17:13 -08:00
Timothy Jaeryang Baek 897c9b2616 Merge pull request #9588 from TiancongLx/dev
i18n: update zh-TW
2025-02-07 11:15:54 -08:00
Timothy Jaeryang Baek 4ed544a4b5 Merge pull request #9598 from Mistrick/patch
fix: correct max seed for comfyui
2025-02-07 11:15:41 -08:00
Patrick Deniso 7f82476926 use key_prefix in rest of S3StorageProvider 2025-02-07 13:56:57 -05:00
Mistrick 94f56db5ee fix max seed for comfyui 2025-02-08 01:10:18 +07:00
Patrick Deniso 5ca6afc0fc add s3 key prefix support 2025-02-07 12:15:54 -05:00
Mazurek Michal 35f3824932 feat: Implement Document Intelligence as Content Extraction Engine 2025-02-07 13:44:47 +01:00
Tiancong Li 5ef00dece9 i18n: update zh-TW 2025-02-07 19:13:51 +08:00
EntropyYue 3a2d964d39 enh: optimize time display 2025-02-07 07:43:39 +08:00
Rodrigo Agundez ffb9e73975 Save image metadata to DB 2025-02-07 08:32:06 +09:00
Rodrigo Agundez 312f273a1b Add extension to image filename 2025-02-07 08:22:20 +09:00
Rodrigo Agundez 4974c9cbb0 Refactor upload function 2025-02-07 08:12:04 +09:00
Xingjian Xie 89669a21fc Refactor common code between inlet and outlet 2025-02-06 23:07:47 +00:00
Rodrigo Agundez 7e97e9dcc9 Improve style 2025-02-07 07:37:18 +09:00
Rodrigo Agundez ac3338265d Set get_config as the name of the function 2025-02-07 07:30:58 +09:00
Girish Ramakrishnan 8215aa36d0 oidc: pick up username correctly 2025-02-06 17:59:16 +01:00
binxn 88db4ca7ba Update jina_search.py
Updated Jina's search function in order to use POST and make use of the result count passed by the user

Note: Jina supports a max of 10 result count
2025-02-06 14:30:27 +01:00
Timothy Jaeryang Baek 14398ab628 refac: styling 2025-02-06 01:28:33 -08:00
Rodrigo Agundez 8d43fdadc1 Add functionality in other image generation types 2025-02-06 18:24:57 +09:00
Timothy Jaeryang Baek 8ca21ea838 refac: styling 2025-02-06 01:07:01 -08:00
Rodrigo Agundez 159578dfd4 Enable usage of the DB to store generated images 2025-02-06 17:59:59 +09:00
Timothy Jaeryang Baek 4a33956e77 Merge pull request #9378 from open-webui/dependabot/npm_and_yarn/npm_and_yarn-4be97f86df
build(deps-dev): bump vitest from 1.6.0 to 1.6.1 in the npm_and_yarn group across 1 directory
2025-02-06 00:55:18 -08:00
Timothy Jaeryang Baek a1e26016bb fix: new connections config 2025-02-06 00:52:22 -08:00
Timothy Jaeryang Baek feffdf197f doc: readme 2025-02-06 00:38:06 -08:00
Timothy Jaeryang Baek a023667e1e fix: user params save issue 2025-02-06 00:37:10 -08:00
Timothy Jaeryang Baek b3a7cb938f Merge pull request #9463 from roryeckel/cleanup-code-interpreter-markdown
fix: Improve automatic cleanup of code_interpreter formatting
2025-02-06 00:32:55 -08:00
Timothy Jaeryang Baek 10e2b3c055 Merge pull request #9471 from hurxxxx/fix/o3_not_support_max_tokens
fix: o3 does not support max_tokens parameter
2025-02-06 00:31:48 -08:00
Vineeth B V 7c78facfd9 Update opensearch.py 2025-02-06 13:36:11 +05:30
hurxxxx b9480c0e8a fix : o1 should also be applied 2025-02-06 16:53:04 +09:00
hurxxxx 80e123f58f fix : O3 also does not support the max_tokens parameter, so title generation is not possible when using the O3 model 2025-02-06 16:41:24 +09:00
Vineeth B V fd6b039859 Added a query method for OpenSearch vector db.
- This PR aims to address the error 400: "**'OpenSearchClient' object has no attribute 'query'**".
- With the implemented query() method, this issue should be resolved and allow uploaded documents to be vectorized and retrieved based on the given query.
2025-02-06 12:04:14 +05:30
Rory 74b971b888 refac: clean up solution for correcting code_interpreter backticks 2025-02-05 23:38:35 -06:00
Rory c676303a55 enh: automatically remove incorrect backticks before code_interpreter tags 2025-02-05 23:26:13 -06:00
Timothy Jaeryang Baek 397595de9d Merge pull request #9456 from mitomac/fix-oidc-email-claim-new
fix: check for email claim before skipping userinfo endpoint
2025-02-05 20:00:35 -08:00
D. MacAlpine 34b62e71cc fix: check for email claim before skipping userinfo endpoint 2025-02-05 21:31:55 -05:00
Rory ec6fe9939b Merge remote-tracking branch 'upstream/dev' into playwright 2025-02-05 17:47:58 -06:00
JT 40dea3fbe1 Merge branch 'dev' into main 2025-02-05 15:15:24 -08:00
Timothy Jaeryang Baek e9d6ada25c Merge pull request #9445 from open-webui/dev
0.5.10
2025-02-05 14:46:41 -08:00
Timothy Jaeryang Baek b8fe9497fb refac 2025-02-05 14:46:25 -08:00
Timothy Jaeryang Baek ed49c2e75a doc: changelog 2025-02-05 14:42:28 -08:00
Timothy Jaeryang Baek 7ba717d171 refac: system prompt template 2025-02-05 14:35:18 -08:00
Timothy Jaeryang Baek fb92694d61 Merge pull request #9415 from aindriu80/main
i18n Updated Irish translations
2025-02-05 14:29:26 -08:00
Timothy Jaeryang Baek d9f17225ef refac 2025-02-05 14:26:09 -08:00
Timothy Jaeryang Baek 1e67956db9 refac 2025-02-05 14:20:51 -08:00
Timothy Jaeryang Baek 648878782b refac: response parse 2025-02-05 14:10:53 -08:00
jayteaftw 157c781b0a Merge branch 'main' of https://github.com/jayteaftw/open-webui 2025-02-05 14:07:59 -08:00
jayteaftw 6d2f87e904 Added server side Prefixing 2025-02-05 14:03:16 -08:00
Timothy Jaeryang Baek ff84c120f5 fix: api usage 2025-02-05 13:18:17 -08:00
M.Abdulrahman Alnaseer 68703951e8 feat(ui): implement domain filter list for web search settings 2025-02-05 19:14:40 +03:00
Aindriú Mac Giolla Eoin e56b8d99ee Updated Irish translations from 0.5.9 2025-02-05 15:50:52 +00:00
Timothy Jaeryang Baek ab94468ffa Merge pull request #9387 from open-webui/dev
0.5.9
2025-02-05 02:38:21 -08:00
Timothy Jaeryang Baek 13c7d96515 refac 2025-02-05 02:38:05 -08:00
Timothy Jaeryang Baek bffbf7e238 doc: changelog 2025-02-05 02:35:16 -08:00
Timothy Jaeryang Baek 90cd6f272f fix: tag support 2025-02-05 02:33:40 -08:00
Timothy Jaeryang Baek c36c63f1e8 fix: <think> tag 2025-02-05 02:10:28 -08:00
dependabot[bot] 98ba0c37b9 build(deps-dev): bump vitest
Bumps the npm_and_yarn group with 1 update in the / directory: [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest).


Updates `vitest` from 1.6.0 to 1.6.1
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Commits](https://github.com/vitest-dev/vitest/commits/v1.6.1/packages/vitest)

---
updated-dependencies:
- dependency-name: vitest
  dependency-type: direct:development
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-05 09:25:26 +00:00
Timothy Jaeryang Baek dc3b2f1f1e Merge pull request #9190 from open-webui/dev
0.5.8
2025-02-05 01:16:35 -08:00
Timothy Jaeryang Baek 1ab66e83c6 refac: styling 2025-02-05 01:14:46 -08:00
Timothy Jaeryang Baek 3b7926f00d doc: changelog 2025-02-05 01:09:23 -08:00
Timothy Jaeryang Baek e27de61318 Merge pull request #9377 from OriginalSimon/dev
18n: Update Ukrainian translation
2025-02-05 01:08:39 -08:00
Timothy Jaeryang Baek cda6b5ad17 refac: styling 2025-02-05 01:07:38 -08:00
Simon 3f188b0b86 Update translation.json 2025-02-05 10:05:38 +01:00
Timothy Jaeryang Baek b33b49789e enh: responsive styling 2025-02-05 01:03:40 -08:00
Timothy Jaeryang Baek cce1762cb8 refac: tool calling 2025-02-05 01:03:16 -08:00
Simon 1fbbd36433 Update translation.json 2025-02-05 10:02:59 +01:00
Timothy Jaeryang Baek f6b955e6a0 chore: format 2025-02-05 00:44:07 -08:00
Timothy Jaeryang Baek 41ca399dfd chore: format 2025-02-05 00:42:51 -08:00
Timothy Jaeryang Baek 5385d39420 Merge pull request #9374 from KarlLee830/translate
i18n: Update Chinese translation
2025-02-05 00:38:18 -08:00
Timothy Jaeryang Baek d4a18a5765 refac: always on web search 2025-02-05 00:37:47 -08:00
KarlLee830 3f547eb395 i18n: Update Chinese translation 2025-02-05 16:34:51 +08:00
Timothy Jaeryang Baek 336984c254 Merge pull request #9370 from hurxxxx/feat/always-web-search
feat: Add "Always-On Web Search" configuration.
2025-02-05 00:27:29 -08:00
Timothy Jaeryang Baek 58bb4758df chore: bump 2025-02-05 00:25:11 -08:00
Timothy Jaeryang Baek 102b56b938 doc: changelog 2025-02-05 00:23:30 -08:00
Timothy Jaeryang Baek e41a2682f5 chore: format 2025-02-05 00:07:45 -08:00
Timothy Jaeryang Baek f6f8c08cb0 Merge pull request #9068 from df-cgdm/main
**feat** Add user related headers when calling an external embedding api
2025-02-05 00:05:44 -08:00
Timothy Jaeryang Baek 8e831a5433 Merge pull request #9358 from KarlLee830/translate
i18n: Update Chinese translation
2025-02-05 00:04:12 -08:00
Timothy Jaeryang Baek c778345e84 refac 2025-02-05 00:01:24 -08:00
hurxxxx 0e3c1ac392 Merge remote-tracking branch 'upstream/dev' into feat/always-web-search
# Conflicts:
#	src/lib/components/chat/Chat.svelte
2025-02-05 16:56:34 +09:00
Timothy Jaeryang Baek 2b0af33274 refac 2025-02-04 23:48:01 -08:00
Timothy Jaeryang Baek 9624493b55 refac 2025-02-04 23:44:51 -08:00
Timothy Jaeryang Baek e349e26cd8 refac 2025-02-04 23:20:09 -08:00
Timothy Jaeryang Baek 314b674f32 feat: native tool calling support 2025-02-04 23:05:14 -08:00
Timothy Jaeryang Baek 7766a08b70 refac: ollama tool calls 2025-02-04 21:42:49 -08:00
Timothy Jaeryang Baek c5a9cfacf1 refac 2025-02-04 21:20:03 -08:00
Timothy Jaeryang Baek 8d520eeecd fix: ollama native tool calling 2025-02-04 21:08:26 -08:00
Timothy Jaeryang Baek f88a80ac47 wip: pyodide kernel 2025-02-04 21:02:11 -08:00
Timothy Jaeryang Baek e7da506add refac: middleware 2025-02-04 21:01:53 -08:00
Timothy Jaeryang Baek 2e61ea7cc9 refac: chat 2025-02-04 20:56:13 -08:00
KarlLee830 0a5b421ac1 i18n: Update Chinese translation 2025-02-05 12:53:06 +08:00
Timothy Jaeryang Baek a4ea2e0996 fix: multi response message 2025-02-04 20:33:02 -08:00
Timothy Jaeryang Baekandsmonux 23df351239 refac: ollama tool calling support
Co-Authored-By: smonux <85928277+smonux@users.noreply.github.com>
2025-02-04 19:22:08 -08:00
Timothy Jaeryang Baek ec9be0d20d feat: native tool calling frontend 2025-02-04 19:14:59 -08:00
Timothy Jaeryang Baek 533b62f062 refac: deprecate non web worker pyodide 2025-02-04 18:41:53 -08:00
Timothy Jaeryang Baek fba25c6cec refac 2025-02-04 18:36:22 -08:00
Timothy Jaeryang Baek 6ee924924e refac: code interpreter 2025-02-04 18:33:22 -08:00
Timothy Jaeryang Baek 9c0a783991 refac: pyodide 2025-02-04 17:29:10 -08:00
Timothy Jaeryang Baek 266899acc0 refac 2025-02-04 14:45:47 -08:00
Timothy Jaeryang Baek 2b0c5f322f fix: suggestions 2025-02-04 14:41:42 -08:00
Timothy Jaeryang Baek 08ce91ad86 Merge pull request #9325 from Mavyre/patch-1
fix: Corrected chat generation error after failed web search query generation
2025-02-04 14:02:10 -08:00
Timothy Jaeryang Baek d062af4129 Merge pull request #9332 from le-ross/main
fixing french typo
2025-02-04 14:01:38 -08:00
Timothy Jaeryang Baek 5cda8a57e7 Merge pull request #9337 from abdalrohman/exa_integration
feat: implement Exa search engine integration
2025-02-04 14:00:06 -08:00
Timothy Jaeryang Baek b02a38487c Merge pull request #9328 from kahghi/fix-unstructured-pkg-version
fix: increment unstructured package version to fix UnstructuredExcelLoader
2025-02-04 13:59:39 -08:00
JT 81102f4be2 Merge branch 'open-webui:main' into main 2025-02-04 13:06:04 -08:00
jvinolus 7b8e5d4e7c Fixed errors and added more support 2025-02-04 13:04:36 -08:00
M.Abdulrahman Alnaseer 2bb6b49f11 feat: implement Exa search engine integration 2025-02-04 21:13:16 +03:00
rossm d6b88c7ef7 fixing french typo 2025-02-04 10:43:19 -05:00
kahghi 1868cf0a91 increment unstructured package version 2025-02-04 22:40:49 +08:00
Mavyre bbffdeb758 Corrected chat generation error after failed web search query generation 2025-02-04 12:13:54 +01:00
Timothy Jaeryang Baek ce08ea5f6c refac 2025-02-04 01:06:03 -08:00
Timothy Jaeryang Baek 12a7f4d43b refac: styling 2025-02-04 01:03:41 -08:00
Timothy Jaeryang Baek 6ba9ccdd79 refac: styling 2025-02-04 00:55:55 -08:00
Timothy Jaeryang Baek 0b01fd9d6f Merge pull request #9322 from jannikstdl/smart-suggestions
feat: smart suggestions
2025-02-04 00:38:56 -08:00
Jannik Streidl 17c1c2f0f3 fix: only animate on change 2025-02-04 09:36:11 +01:00
Jannik Streidl b8b82b9156 i18n 2025-02-04 09:17:55 +01:00
Jannik Streidl 43a490457d feat: smart suggestions 2025-02-04 09:14:02 +01:00
Timothy Jaeryang Baek f58ae6bd17 refac: styling 2025-02-03 22:11:01 -08:00
Timothy Jaeryang Baek 49e5d01213 refac: pyodide 2025-02-03 22:07:59 -08:00
Timothy Jaeryang Baek b20603e01a refac 2025-02-03 22:05:52 -08:00
Timothy Jaeryang Baek 3adfa29f7d chore: format 2025-02-03 21:56:35 -08:00
Timothy Jaeryang Baek a38ce75eda refac: styling 2025-02-03 21:25:16 -08:00
Timothy Jaeryang Baek 7e971f9dd1 refac 2025-02-03 21:13:27 -08:00
Timothy Jaeryang Baek 074a443790 refac 2025-02-03 21:10:49 -08:00
Timothy Jaeryang BaekandJannik S. 454294a101 refac: design
thanks @jannikstdl for nudging me to redesign 🙌

Co-Authored-By: Jannik S. <jannik@streidl.dev>
2025-02-03 20:53:46 -08:00
Timothy Jaeryang Baek d1c7a3cff3 enh: code interpreter prompt 2025-02-03 20:49:54 -08:00
Rory 7bac1a170d Merge remote-tracking branch 'upstream/dev' into playwright
# Conflicts:
#	backend/open_webui/retrieval/web/utils.py
2025-02-03 22:32:46 -06:00
Timothy Jaeryang Baek 1b8dc673e7 Merge pull request #9314 from roryeckel/validate-rag-urls
Validate URLs returned by search engine
2025-02-03 20:26:34 -08:00
Timothy Jaeryang Baek 71039b00a8 chore: format 2025-02-03 20:21:49 -08:00
Timothy Jaeryang Baek 16d62d7869 refac: tooltip 2025-02-03 20:21:11 -08:00
Timothy Jaeryang Baek 0ae7d12343 refac 2025-02-03 20:15:19 -08:00
Timothy Jaeryang Baek 1c518ab688 refac: styling 2025-02-03 20:13:14 -08:00
Timothy Jaeryang Baek ebde5c47d9 refac: styling 2025-02-03 20:06:58 -08:00
Timothy Jaeryang Baek 2bf68593af refac: styling 2025-02-03 20:06:17 -08:00
Timothy Jaeryang Baek b61138e676 refac: message input 2025-02-03 19:54:20 -08:00
Timothy Jaeryang Baek 2517a2b653 refac: styling 2025-02-03 19:34:36 -08:00
Timothy Jaeryang Baek 6d797820f5 refac: input ui 2025-02-03 19:18:31 -08:00
Timothy Jaeryang Baek f527f31d2b refac 2025-02-03 19:11:23 -08:00
Timothy Jaeryang Baek 94c6428ae2 refac: chat 2025-02-03 19:06:15 -08:00
Rory 1a1cc1514f Merge branch 'dev' into validate-rag-urls 2025-02-03 20:44:59 -06:00
Rory f85d7e3686 Merge branch 'dev' into playwright 2025-02-03 20:44:39 -06:00
Timothy Jaeryang Baek 8fdd3024f7 refac 2025-02-03 18:36:49 -08:00
Timothy Jaeryang Baek aa7184ae0d refac 2025-02-03 18:17:38 -08:00
Timothy Jaeryang Baek 51de2ffcc0 fix: ff 2025-02-03 18:03:38 -08:00
Timothy Jaeryang Baek e5bb0f014a refac 2025-02-03 17:19:33 -08:00
Rory 93cc1a88ee Merge branch 'dev' into playwright 2025-02-03 19:09:26 -06:00
Rory 310a18eef2 Merge branch 'dev' into validate-rag-urls 2025-02-03 19:09:11 -06:00
Rory 1b581b714f Moving code out of playwright branch 2025-02-03 18:47:26 -06:00
Timothy Jaeryang Baek df07d671ce refac 2025-02-03 16:21:44 -08:00
Rory 3db6b4352f fix: Filter out invalid RAG web URLs (continued) 2025-02-03 18:18:49 -06:00
Timothy Jaeryang Baek 31c176a485 refac 2025-02-03 16:18:07 -08:00
Timothy Jaeryang Baek 943a57474f refac 2025-02-03 16:14:00 -08:00
Timothy Jaeryang Baek 1635dcb69b refac 2025-02-03 16:07:43 -08:00
Rory 121a13d4ed fix: Filter to valid RAG web search URLs 2025-02-03 17:37:20 -06:00
Rory 22746c7a3f Merge remote-tracking branch 'upstream/dev' 2025-02-03 17:28:53 -06:00
Timothy Jaeryang Baek e3214d08b5 refac 2025-02-03 15:20:27 -08:00
Timothy Jaeryang Baek db0ff839dd refac 2025-02-03 14:24:30 -08:00
Timothy Jaeryang Baek d87a7b2f8b refac: styling 2025-02-03 14:16:22 -08:00
Timothy Jaeryang Baek b891a398fd refac 2025-02-03 13:50:57 -08:00
Timothy Jaeryang Baek c85ce07f92 refac 2025-02-03 13:42:03 -08:00
Timothy Jaeryang Baek 5c0854c6b3 Merge pull request #9287 from taylorwilsdon/authenticate_gooogle_settings
fix: Restrict Google Drive credentials to authenticated users
2025-02-03 13:40:39 -08:00
Timothy Jaeryang Baek 3061d4bd10 Merge pull request #9291 from moblangeois/french-translation
i18n: Update French translation
2025-02-03 13:38:26 -08:00
Timothy Jaeryang Baek d37a7a1fe1 Merge branch 'dev' into french-translation 2025-02-03 13:38:08 -08:00
Timothy Jaeryang Baek 70b8199030 chore: format 2025-02-03 13:37:29 -08:00
Timothy Jaeryang Baek 9b78dde8a9 Merge pull request #9295 from OriginalSimon/dev
18n: Update Ukrainian translation
2025-02-03 13:36:42 -08:00
Simon bc56f442c1 Update translation.json 2025-02-03 21:04:17 +01:00
Morgan Blangeois 6c81cf9795 i18n: Add French translation 2025-02-03 20:16:53 +01:00
Taylor Wilsdon 74cf5e2a2e fix: Restrict Google Drive credentials to authenticated users 2025-02-03 11:55:52 -05:00
Matteo Sirri 22c100bb6b feat: add contributing guide 2025-02-03 16:45:25 +00:00
Matteo Sirri e6715ce8b8 docs: fix readme 2025-02-03 16:43:59 +00:00
Matteo Sirri 65443a3a66 feat: initial commit 2025-02-03 16:35:46 +00:00
Timothy Jaeryang Baek 70116e7251 refac: styling 2025-02-03 01:18:16 -08:00
Timothy Jaeryang Baek 95c6d0e78c enh: code interpreter toggle 2025-02-03 01:14:38 -08:00
Timothy Jaeryang Baek ca4b839e6d enh: code interpreter 2025-02-03 00:24:09 -08:00
Timothy Jaeryang Baek 58d2fd9ac1 refac: styling 2025-02-03 00:03:41 -08:00
Timothy Jaeryang Baek 78853a67e4 refac 2025-02-02 23:35:58 -08:00
Timothy Jaeryang Baek 09cd95bffe enh: pyodide 2025-02-02 23:08:37 -08:00
Timothy Jaeryang Baek 8685256002 feat: code interpreter 2025-02-02 22:38:19 -08:00
Timothy Jaeryang Baek 0d33725d21 enh: pyodide 2025-02-02 21:18:52 -08:00
Timothy Jaeryang Baek eb1ede119e refac: reasoning tag 2025-02-02 20:50:54 -08:00
Timothy Jaeryang Baek e4fc2e0e51 refac 2025-02-02 19:24:07 -08:00
Rory f837d2cdbb Merge branch 'dev' of https://github.com/open-webui/open-webui
# Conflicts:
#	src/lib/i18n/locales/sr-RS/translation.json
2025-02-02 20:31:27 -06:00
Rory c3df481b22 Introduce docker-compose.playwright.yaml + run-compose update 2025-02-02 19:44:40 -06:00
Timothy Jaeryang Baek 74172461c7 enh: pyodide python result handling 2025-02-02 16:56:21 -08:00
Rory 8da33721d5 Support PLAYWRIGHT_WS_URI 2025-02-02 17:58:09 -06:00
Timothy Jaeryang Baek b94b691993 enh: utils 2025-02-02 15:11:50 -08:00
Tristan Morris a004bf2a6d Merge branch into dev 2025-02-02 08:44:57 -06:00
Tristan Morris 5df474abb9 Add support for Deepgram STT 2025-02-02 08:12:13 -06:00
Timothy Jaeryang Baek fc1cec10be chore: bump 2025-02-01 21:05:08 -08:00
Timothy Jaeryang Baek 95c94d8a85 Merge pull request #9191 from NYU-ITS/milvus_auth_token
[feat] Milvus: new optional config var, MILVUS_TOKEN
2025-02-01 21:04:30 -08:00
Timothy Jaeryang Baek 5ce4b1c570 Merge pull request #9173 from KarlLee830/fix-duckduckgo
Fix DuckDuckGo's 202 Error RateLimit
2025-02-01 21:02:31 -08:00
Timothy Jaeryang Baek af6f0641cb chore: bump 2025-02-01 21:02:12 -08:00
Timothy Jaeryang Baek 642a093d02 refac: tool calls 2025-02-01 21:01:06 -08:00
Rory a84e488a4e Fix playwright in docker by updating unstructured 2025-02-01 22:58:28 -06:00
Timothy Jaeryang Baek 28cf616147 Merge pull request #9200 from open-webui/dependabot/pip/backend/dev/opencv-python-headless-4.11.0.86
build(deps): bump opencv-python-headless from 4.10.0.84 to 4.11.0.86 in /backend
2025-02-01 10:04:26 -08:00
Timothy Jaeryang Baek ffe1abfda9 Merge pull request #9198 from open-webui/dependabot/pip/backend/dev/aiohttp-3.11.11
build(deps): bump aiohttp from 3.11.8 to 3.11.11 in /backend
2025-02-01 10:04:18 -08:00
Timothy Jaeryang Baek 6b879abdb9 Merge pull request #9199 from open-webui/dependabot/pip/backend/dev/soundfile-0.13.1
build(deps): bump soundfile from 0.12.1 to 0.13.1 in /backend
2025-02-01 10:04:11 -08:00
Timothy Jaeryang Baek a4b8e3d958 Merge pull request #9201 from open-webui/dependabot/pip/backend/dev/authlib-1.4.1
build(deps): bump authlib from 1.3.2 to 1.4.1 in /backend
2025-02-01 10:04:02 -08:00
Timothy Jaeryang Baek 442ad41d2b Merge pull request #9202 from open-webui/dependabot/pip/backend/dev/pymdown-extensions-10.14.2
build(deps): bump pymdown-extensions from 10.11.2 to 10.14.2 in /backend
2025-02-01 10:03:53 -08:00
Timothy Jaeryang Baek 3502e09d9f fix: image prompt gen template 2025-01-31 23:50:58 -08:00
Timothy Jaeryang Baek af10f87075 refac: textarea 2025-01-31 23:49:25 -08:00
Timothy Jaeryang Baek 4e375c892a refac 2025-01-31 23:15:49 -08:00
Timothy Jaeryang Baek bc5452ea41 Merge pull request #9195 from rragundez/default-picture
[EASY] Set default picture to user.png
2025-01-31 19:35:52 -08:00
dependabot[bot] aa2eb37e10 build(deps): bump pymdown-extensions from 10.11.2 to 10.14.2 in /backend
Bumps [pymdown-extensions](https://github.com/facelessuser/pymdown-extensions) from 10.11.2 to 10.14.2.
- [Release notes](https://github.com/facelessuser/pymdown-extensions/releases)
- [Commits](https://github.com/facelessuser/pymdown-extensions/compare/10.11.2...10.14.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-01 02:36:20 +00:00
dependabot[bot] c00d1a2f87 build(deps): bump authlib from 1.3.2 to 1.4.1 in /backend
Bumps [authlib](https://github.com/lepture/authlib) from 1.3.2 to 1.4.1.
- [Release notes](https://github.com/lepture/authlib/releases)
- [Changelog](https://github.com/lepture/authlib/blob/master/docs/changelog.rst)
- [Commits](https://github.com/lepture/authlib/compare/v1.3.2...v1.4.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-01 02:36:17 +00:00
dependabot[bot] 824aad4703 build(deps): bump opencv-python-headless in /backend
Bumps [opencv-python-headless](https://github.com/opencv/opencv-python) from 4.10.0.84 to 4.11.0.86.
- [Release notes](https://github.com/opencv/opencv-python/releases)
- [Commits](https://github.com/opencv/opencv-python/commits)

---
updated-dependencies:
- dependency-name: opencv-python-headless
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-01 02:36:14 +00:00
dependabot[bot] f661bfde7d build(deps): bump soundfile from 0.12.1 to 0.13.1 in /backend
Bumps [soundfile](https://github.com/bastibe/python-soundfile) from 0.12.1 to 0.13.1.
- [Release notes](https://github.com/bastibe/python-soundfile/releases)
- [Commits](https://github.com/bastibe/python-soundfile/compare/0.12.1...0.13.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-01 02:36:11 +00:00
dependabot[bot] 9d52120c62 build(deps): bump aiohttp from 3.11.8 to 3.11.11 in /backend
---
updated-dependencies:
- dependency-name: aiohttp
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-01 02:36:08 +00:00
Rodrigo Agundez 30e4b32a5b Set default picture to user.png 2025-02-01 08:32:04 +09:00
Sajid Ali 7b31c75271 Milvus: new optional config var, MILVUS_TOKEN
modified:   backend/open_webui/config.py
	modified:   backend/open_webui/retrieval/vector/dbs/milvus.py
2025-01-31 17:01:00 -05:00
Timothy Jaeryang Baek 9b640b0ac2 Merge pull request #9163 from rragundez/default-role
Bug fix, configurable default if using oauth via the `DEFAULT_USER_ROLE` env variable
2025-01-31 12:38:32 -08:00
KarlLee830 e7de41499a fix: DuckDuckGo's RateLimit exception 2025-02-01 02:01:22 +08:00
Rodrigo Agundez 1f2b5fa68f move comment to top 2025-01-31 23:05:33 +09:00
Rodrigo Agundez 681851ca6b Configurable default role for oauth 2025-01-31 23:00:24 +09:00
Timothy Jaeryang Baek 74aec6bdf9 Merge pull request #9143 from kostich/dev
i18n: Update Serbian translation
2025-01-31 00:47:50 -08:00
Timothy Jaeryang Baek e3e7176b0b Merge pull request #9142 from dannyl1u/feat/delete-unused-response-message
feat: delete unused response message from other "branches"
2025-01-30 21:28:10 -08:00
Rory 77ae73e659 Adjust search event messages + translations 2025-01-30 23:18:11 -06:00
Марко М. Костић (Marko M. Kostić) 968787ac3e Update Serbian translation 2025-01-31 06:16:08 +01:00
dannyl1u e9f05b6cd7 feat: delete message responses 2025-01-30 20:48:06 -08:00
Rory 2452e271cd Refine RAG_WEB_LOADER 2025-01-30 20:31:31 -06:00
Rory 8dafe3cba8 Merge branch 'dev' of https://github.com/open-webui/open-webui 2025-01-30 18:26:55 -06:00
Timothy Jaeryang Baek 8fdb37a17f Merge pull request #9131 from 0xThresh/dev
fix: Add error catching for function pip install issues
2025-01-30 15:02:47 -08:00
Timothy Jaeryang Baek 4d376c011a Merge pull request #9129 from imJack6/dev
i18n: Corrected localization typos in Simplified Chinese
2025-01-30 15:00:21 -08:00
Timothy Jaeryang Baek 5ebcd44163 Merge pull request #9110 from muhac/dev
i18n: improved Chinese translations of think tag
2025-01-30 15:00:04 -08:00
James W. 124fdcc48c Merge branch 'open-webui:dev' into dev 2025-01-30 13:34:01 -07:00
James Westbrook 48c2fb0d24 fix: Add error catching for function pip install issues 2025-01-30 13:32:11 -07:00
Jack Lei 0d4d81e012 i18n: Corrected localization typos in Simplified Chinese 2025-01-31 03:47:37 +08:00
Muhan Li 14bbcd7046 i18n: improved Chinese translations of think tag 2025-01-30 05:22:59 -05:00
Timothy Jaeryang Baek cc99673906 refac: prompt variables 2025-01-29 21:56:51 -08:00
Timothy Jaeryang Baek d6c82939e6 refac 2025-01-29 21:56:28 -08:00
Timothy Jaeryang Baek 33fffd6b1d refac: rm print statement 2025-01-29 21:36:05 -08:00
Timothy Jaeryang Baek cd088b2f71 fix 2025-01-29 21:32:07 -08:00
Timothy Jaeryang Baek a8f2919e9e fix: #9003 2025-01-29 21:31:18 -08:00
Timothy Jaeryang Baek be665f2a3e Merge pull request #8493 from kyunwang/fix/oidc-500-error-name-field
fix: Check OAuth name type with fallback
2025-01-29 21:08:21 -08:00
Timothy Jaeryang Baek 8727b91664 fix: display usage for non-streaming ollama response 2025-01-29 21:07:22 -08:00
Timothy Jaeryang Baek 248fcf1636 refac: styling 2025-01-29 21:06:01 -08:00
Timothy Jaeryang Baek 7f61d01fde refac: playground 2025-01-29 20:35:37 -08:00
Timothy Jaeryang Baek 52010accc9 refac 2025-01-29 20:11:37 -08:00
Timothy Jaeryang Baek 6658e67113 fix: title gen 2025-01-29 20:03:46 -08:00
Timothy Jaeryang Baek 08ad4ee018 enh: check for reasoning tags 2025-01-29 14:59:23 -08:00
Timothy Jaeryang Baek 5420c165c6 refac: title generation 2025-01-29 14:40:36 -08:00
Timothy Jaeryang Baek 4abede9a2b fix: uploaded file should not be deleted 2025-01-29 14:20:51 -08:00
Timothy Jaeryang Baek 40a4443949 Merge pull request #9082 from Alex1607/main
FIX max_tokens not being set properly
2025-01-29 11:48:05 -08:00
Timothy Jaeryang Baek 84c700b92c Merge pull request #9059 from jrespeto/jrespeto-patch-1
fix:  Update ollama.py - Missing await in coroutine
2025-01-29 11:39:42 -08:00
Timothy Jaeryang Baek 5fef92c95e Merge pull request #9064 from iidx/i18n-typo
i18n: update ko-KR
2025-01-29 11:39:29 -08:00
Alexander c2e742afe1 Fix max_tokens not being set properly 2025-01-29 19:28:09 +01:00
Jonathan Respeto a32782e527 fix: Update openai.py
need to await get_filtered_models
2025-01-29 08:47:54 -05:00
Didier FOURNOUT 6ca295ec59 Add user related headers when calling an external embedding api 2025-01-29 10:55:52 +00:00
iidx 938a151f12 i18n: some korean update 2025-01-29 17:30:53 +09:00
iidx f502e7db51 i18n: some korean update 2025-01-29 17:18:13 +09:00
iidx bd24ed953a i18n: Corrected typos in korean 2025-01-29 15:57:44 +09:00
Rory 4e8b390682 Add RAG_WEB_LOADER + Playwright mode + improve stability of search 2025-01-28 23:03:15 -06:00
Timothy Jaeryang Baek 9418364062 chore: fastapi bump 2025-01-28 18:36:23 -08:00
Jonathan Respeto b4be58f6b6 Update ollama.py
Missing await in coroutine

causing 500 errors on /ollama/api/tags since v0.5.0
2025-01-28 18:27:41 -05:00
Timothy Jaeryang Baek c5b5303a55 Merge pull request #9031 from bunnerz-king/main
LDAP auth, return user permissions in response
2025-01-28 14:50:04 -08:00
Timothy Jaeryang Baek c021aba094 enh: chat "clone" i18n 2025-01-28 12:49:06 -08:00
hurxxxx 8e0c0b4ae3 fix : Infinite loading issue occurs. 2025-01-29 04:42:41 +09:00
hurxxxx 857b3f0da8 Merge remote-tracking branch 'upstream/dev' into feat/rag-status 2025-01-29 02:01:50 +09:00
hurxxxx af979ce49a feat: Add user setting for "Always Enable Search" 2025-01-29 02:01:46 +09:00
Andrew King a1b5c18ef7 ldap pass user permissions into response 2025-01-28 09:51:21 -05:00
Timothy Jaeryang Baek 8c7e52e5a1 Merge pull request #9010 from Shadowfita/patch-1
fix: Include empty delta object on openai_chat_chunk_message_template per OpenAI API documentation
2025-01-27 17:51:09 -08:00
Orion 95f4d99e3b Update misc.py
Include empty delta object on openai_chat_chunk_message_template per OpenAI API documentation. 

https://platform.openai.com/docs/api-reference/chat/streaming#chat/streaming
2025-01-28 09:53:22 +10:00
Timothy Jaeryang Baek ce6e8d1264 Merge pull request #9006 from TiancongLx/dev
i18n: update zh-TW
2025-01-27 15:15:32 -08:00
Tiancong Li 45e19fb9bd i18n: update zh-TW 2025-01-28 05:08:19 +08:00
Timothy Jaeryang Baek cd560a359c Merge pull request #8946 from zeroxs/feat/localize-dates
feat: Localized dates and times
2025-01-27 10:33:59 -08:00
Timothy Jaeryang Baek ec62104211 Merge pull request #8978 from antpyykk-kone/feature/separate-auth-cookie-config
fix: Separate cookie configuration between session & auth cookies to prevent oauth flow from breaking
2025-01-27 10:32:13 -08:00
Timothy Jaeryang Baek acdcb32ac5 Merge pull request #9003 from tarmst/fix-no-file-upload-for-write-groups
Fix: Users with write adding docs to knowledge, deleting, and fixing read/write toggle on model & knowledge creation
2025-01-27 10:30:18 -08:00
tarmst 751a61a364 Adding more checks for write access. Adding accessRoles to Model & Knowledge creation 2025-01-27 18:11:52 +00:00
Kangyun Wang 564c0fed95 Fallback using email
- Use Email ass fallback for missing "name" field
- "email" because the email scope is required unlike the profile scope
2025-01-27 13:11:20 +01:00
Kevin Wang 9eaf01c323 Merge branch 'open-webui:main' into fix/oidc-500-error-name-field 2025-01-27 13:10:08 +01:00
Timothy Jaeryang Baek 6eb51ab62e enh: file upload permission indicator 2025-01-26 23:30:46 -08:00
Timothy Jaeryang Baek 6f3c92f6d5 enh: chat loading screen 2025-01-26 23:17:58 -08:00
Timothy Jaeryang Baek 91221cd4b1 Merge pull request #8948 from kokutaro/i18n/japanese-translation
Fix typo on Japanese
2025-01-26 20:11:14 -08:00
kokutaro 2d562ed317 Fixed the type on translation.json
Fixed the typo on Japanese translation file
2025-01-26 17:51:20 +09:00
Sharon Fox dda945f4ad feat: Localized dates and times 2025-01-26 02:47:23 -05:00
Timothy Jaeryang Baek 24ab79f5e9 Merge pull request #8857 from KarlLee830/translate
i18n: Update Chinese Translation
2025-01-24 08:41:02 -08:00
KarlLee830 6e306beaa2 i18n: Update Chinese Translation 2025-01-24 16:02:35 +08:00
Timothy Jaeryang Baek b72150c881 Merge pull request #8835 from open-webui/dev
0.5.7
2025-01-23 13:47:40 -08:00
Timothy Jaeryang Baek ceaefd8053 refac 2025-01-23 13:45:45 -08:00
Timothy Jaeryang Baek 2d84db2621 doc: changelog 2025-01-23 13:36:38 -08:00
Timothy Jaeryang Baek 3527023d88 refac: think tag 2025-01-23 13:04:37 -08:00
Timothy Jaeryang Baek e99453219a chore: format 2025-01-23 12:58:39 -08:00
Timothy Jaeryang Baek 45f88b80ad refac: think status 2025-01-23 12:53:17 -08:00
Timothy Jaeryang Baek ba81b47800 refac 2025-01-23 12:06:25 -08:00
Timothy Jaeryang Baek 646671c576 Merge pull request #8837 from TiancongLx/dev
i18n: update zh-TW
2025-01-23 11:23:40 -08:00
Tiancong Li 3d5e361a21 i18n: update zh-TW 2025-01-24 03:13:10 +08:00
Timothy Jaeryang Baek bb45d35a36 fix: ollama prefix id 2025-01-23 11:04:50 -08:00
Timothy Jaeryang Baek 6a9978dd12 Merge pull request #8801 from aleixdorca/dev
i18n: Update catalan translation.json
2025-01-23 10:53:24 -08:00
Timothy Jaeryang Baek 1dd8e5fafd Merge pull request #8821 from panda44312/patch-3
i18n - Update zh-cn Updated translation
2025-01-23 10:52:26 -08:00
Timothy Jaeryang Baek dd6de749d5 fix: model update access 2025-01-23 10:40:49 -08:00
Timothy Jaeryang Baek 8fc5532e2f fix: tools valves access 2025-01-23 10:37:44 -08:00
Panda 863f73de20 Update zh-cn 2025-01-23 18:44:52 +01:00
Antti Pyykkönen 412923dc91 feat: separate cookie settings between session & auth cookies
Introducing two new env config options to control cookies settings regarding
authentication. These values are taken into use when setting 'token' and 'oauth_id_token'.
To maintain backwards compatibility, the original session cookie values are used as
fallback.

Separation is done to prevent issues with the session cookie. When the config value was
set as 'strict', the oauth flow was broken (since the session cookie was not provided
after the callback).

Providing a separate config for auth & session cookies allows us to keep the 'strict'
settings for auth related cookies, while also allowing the session cookie to behave as
intended (e.g., by configuring it as 'lax').

The original config was added in commit #af4f8aa. However a later commit #a2e889c reused
this config option for other type of cookies, which was not the original intent.
2025-01-23 16:16:50 +02:00
Aleix Dorca 6f17c29d93 Update catalan translation.json 2025-01-23 08:39:02 +01:00
Timothy Jaeryang Baek 6c8d68b6fc Merge pull request #8793 from open-webui/dev
fix: model ids not being applied
2025-01-22 19:01:31 -08:00
Timothy Jaeryang Baek 4a2792b4da fix: model ids not being applied 2025-01-22 19:00:46 -08:00
Timothy Jaeryang Baek 9dd45ddf7c Merge pull request #8779 from open-webui/dev
fix: changelog
2025-01-22 14:13:56 -08:00
Timothy Jaeryang Baek dcc57500dd fix: changelog 2025-01-22 14:13:06 -08:00
Timothy Jaeryang Baek e3ae30e42f Merge pull request #8776 from open-webui/dev
refac: image gen
2025-01-22 12:49:53 -08:00
Timothy Jaeryang Baek 14e650077a refac 2025-01-22 12:49:29 -08:00
Timothy Jaeryang Baek 36b9bcee0f Merge pull request #8770 from open-webui/dev
0.5.6
2025-01-22 12:47:05 -08:00
Timothy Jaeryang Baek 6186dec781 doc: changelog 2025-01-22 12:43:46 -08:00
Timothy Jaeryang Baek 667928efb0 chore: format 2025-01-22 12:38:42 -08:00
Timothy Jaeryang Baek f4b5039adf enh: new ollama create model method 2025-01-22 12:36:18 -08:00
Timothy Jaeryang Baek 8380d3f5ae refac 2025-01-22 12:19:11 -08:00
Timothy Jaeryang Baek 419005a578 refac: manage ollama 2025-01-22 12:19:01 -08:00
Timothy Jaeryang Baek 7593d11b97 refac: wording 2025-01-22 12:08:08 -08:00
Timothy Jaeryang Baek aaf97b85dc enh: reasoning_effort param support for openai 2025-01-22 12:07:04 -08:00
Timothy Jaeryang Baek ea7d4ec6ea refac: styling 2025-01-22 11:56:39 -08:00
jvinolus 47b8412695 Initialize support for prefixing embeddings 2025-01-15 17:05:04 -08:00
Kangyun Wang 1ad9be9c07 Check OAuth name type with fallback 2025-01-12 12:21:53 +01:00
643 changed files with 114422 additions and 34325 deletions
+9
View File
@@ -7,6 +7,15 @@ OPENAI_API_KEY=''
# AUTOMATIC1111_BASE_URL="http://localhost:7860"
# For production, you should only need one host as
# fastapi serves the svelte-kit built frontend and backend from the same host and port.
# To test with CORS locally, you can set something like
# CORS_ALLOW_ORIGIN='http://localhost:5173;http://localhost:8080'
CORS_ALLOW_ORIGIN='*'
# For production you should set this to match the proxy configuration (127.0.0.1)
FORWARDED_ALLOW_IPS='*'
# DO NOT TRACK
SCARF_NO_ANALYTICS=true
DO_NOT_TRACK=true
+49 -1
View File
@@ -1 +1,49 @@
*.sh text eol=lf
# TypeScript
*.ts text eol=lf
*.tsx text eol=lf
# JavaScript
*.js text eol=lf
*.jsx text eol=lf
*.mjs text eol=lf
*.cjs text eol=lf
# Svelte
*.svelte text eol=lf
# HTML/CSS
*.html text eol=lf
*.css text eol=lf
*.scss text eol=lf
*.less text eol=lf
# Config files and JSON
*.json text eol=lf
*.jsonc text eol=lf
*.yml text eol=lf
*.yaml text eol=lf
*.toml text eol=lf
# Shell scripts
*.sh text eol=lf
# Markdown & docs
*.md text eol=lf
*.mdx text eol=lf
*.txt text eol=lf
# Git-related
.gitattributes text eol=lf
.gitignore text eol=lf
# Prettier and other dotfiles
.prettierrc text eol=lf
.prettierignore text eol=lf
.eslintrc text eol=lf
.eslintignore text eol=lf
.stylelintrc text eol=lf
.editorconfig text eol=lf
# Misc
*.env text eol=lf
*.lock text eol=lf
-80
View File
@@ -1,80 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
# Bug Report
## Important Notes
- **Before submitting a bug report**: Please check the Issues or Discussions section to see if a similar issue or feature request has already been posted. It's likely we're already tracking it! If you’re unsure, start a discussion post first. This will help us efficiently focus on improving the project.
- **Collaborate respectfully**: We value a constructive attitude, so please be mindful of your communication. If negativity is part of your approach, our capacity to engage may be limited. We’re here to help if you’re open to learning and communicating positively. Remember, Open WebUI is a volunteer-driven project managed by a single maintainer and supported by contributors who also have full-time jobs. We appreciate your time and ask that you respect ours.
- **Contributing**: If you encounter an issue, we highly encourage you to submit a pull request or fork the project. We actively work to prevent contributor burnout to maintain the quality and continuity of Open WebUI.
- **Bug reproducibility**: If a bug cannot be reproduced with a `:main` or `:dev` Docker setup, or a pip install with Python 3.11, it may require additional help from the community. In such cases, we will move it to the "issues" Discussions section due to our limited resources. We encourage the community to assist with these issues. Remember, it’s not that the issue doesn’t exist; we need your help!
Note: Please remove the notes above when submitting your post. Thank you for your understanding and support!
---
## Installation Method
[Describe the method you used to install the project, e.g., git clone, Docker, pip, etc.]
## Environment
- **Open WebUI Version:** [e.g., v0.3.11]
- **Ollama (if applicable):** [e.g., v0.2.0, v0.1.32-rc1]
- **Operating System:** [e.g., Windows 10, macOS Big Sur, Ubuntu 20.04]
- **Browser (if applicable):** [e.g., Chrome 100.0, Firefox 98.0]
**Confirmation:**
- [ ] I have read and followed all the instructions provided in the README.md.
- [ ] I am on the latest version of both Open WebUI and Ollama.
- [ ] I have included the browser console logs.
- [ ] I have included the Docker container logs.
- [ ] I have provided the exact steps to reproduce the bug in the "Steps to Reproduce" section below.
## Expected Behavior:
[Describe what you expected to happen.]
## Actual Behavior:
[Describe what actually happened.]
## Description
**Bug Summary:**
[Provide a brief but clear summary of the bug]
## Reproduction Details
**Steps to Reproduce:**
[Outline the steps to reproduce the bug. Be as detailed as possible.]
## Logs and Screenshots
**Browser Console Logs:**
[Include relevant browser console logs, if applicable]
**Docker Container Logs:**
[Include relevant Docker container logs, if applicable]
**Screenshots/Screen Recordings (if applicable):**
[Attach any relevant screenshots to help illustrate the issue]
## Additional Information
[Include any additional details that may help in understanding and reproducing the issue. This could include specific configurations, error messages, or anything else relevant to the bug.]
## Note
If the bug report is incomplete or does not follow the provided instructions, it may not be addressed. Please ensure that you have followed the steps outlined in the README.md and troubleshooting.md documents, and provide all necessary information for us to reproduce and address the issue. Thank you!
+167
View File
@@ -0,0 +1,167 @@
name: Bug Report
description: Create a detailed bug report to help us improve Open WebUI.
title: 'issue: '
labels: ['bug', 'triage']
assignees: []
body:
- type: markdown
attributes:
value: |
# Bug Report
## Important Notes
- **Before submitting a bug report**: Please check the [Issues](https://github.com/open-webui/open-webui/issues) or [Discussions](https://github.com/open-webui/open-webui/discussions) sections to see if a similar issue has already been reported. If unsure, start a discussion first, as this helps us efficiently focus on improving the project.
- **Respectful collaboration**: Open WebUI is a volunteer-driven project with a single maintainer and contributors who also have full-time jobs. Please be constructive and respectful in your communication.
- **Contributing**: If you encounter an issue, consider submitting a pull request or forking the project. We prioritize preventing contributor burnout to maintain Open WebUI's quality.
- **Bug Reproducibility**: If a bug cannot be reproduced using a `:main` or `:dev` Docker setup or with `pip install` on Python 3.11, community assistance may be required. In such cases, we will move it to the "[Issues](https://github.com/open-webui/open-webui/discussions/categories/issues)" Discussions section. Your help is appreciated!
- type: checkboxes
id: issue-check
attributes:
label: Check Existing Issues
description: Confirm that you’ve checked for existing reports before submitting a new one.
options:
- label: I have searched the existing issues and discussions.
required: true
- label: I am using the latest version of Open WebUI.
required: true
- type: dropdown
id: installation-method
attributes:
label: Installation Method
description: How did you install Open WebUI?
options:
- Git Clone
- Pip Install
- Docker
- Other
validations:
required: true
- type: input
id: open-webui-version
attributes:
label: Open WebUI Version
description: Specify the version (e.g., v0.3.11)
validations:
required: true
- type: input
id: ollama-version
attributes:
label: Ollama Version (if applicable)
description: Specify the version (e.g., v0.2.0, or v0.1.32-rc1)
validations:
required: false
- type: input
id: operating-system
attributes:
label: Operating System
description: Specify the OS (e.g., Windows 10, macOS Sonoma, Ubuntu 22.04)
validations:
required: true
- type: input
id: browser
attributes:
label: Browser (if applicable)
description: Specify the browser/version (e.g., Chrome 100.0, Firefox 98.0)
validations:
required: false
- type: checkboxes
id: confirmation
attributes:
label: Confirmation
description: Ensure the following prerequisites have been met.
options:
- label: I have read and followed all instructions in `README.md`.
required: true
- label: I am using the latest version of **both** Open WebUI and Ollama.
required: true
- label: I have included the browser console logs.
required: true
- label: I have included the Docker container logs.
required: true
- label: I have **provided every relevant configuration, setting, and environment variable used in my setup.**
required: true
- label: I have clearly **listed every relevant configuration, custom setting, environment variable, and command-line option that influences my setup** (such as Docker Compose overrides, .env values, browser settings, authentication configurations, etc).
required: true
- label: |
I have documented **step-by-step reproduction instructions that are precise, sequential, and leave nothing to interpretation**. My steps:
- Start with the initial platform/version/OS and dependencies used,
- Specify exact install/launch/configure commands,
- List URLs visited, user input (incl. example values/emails/passwords if needed),
- Describe all options and toggles enabled or changed,
- Include any files or environmental changes,
- Identify the expected and actual result at each stage,
- Ensure any reasonably skilled user can follow and hit the same issue.
required: true
- type: textarea
id: expected-behavior
attributes:
label: Expected Behavior
description: Describe what should have happened.
validations:
required: true
- type: textarea
id: actual-behavior
attributes:
label: Actual Behavior
description: Describe what actually happened.
validations:
required: true
- type: textarea
id: reproduction-steps
attributes:
label: Steps to Reproduce
description: |
Please provide a **very detailed, step-by-step guide** to reproduce the issue. Your instructions should be so clear and precise that anyone can follow them without guesswork. Include every relevant detail—settings, configuration options, exact commands used, values entered, and any prerequisites or environment variables.
**If full reproduction steps and all relevant settings are not provided, your issue may not be addressed.**
placeholder: |
Example (include every detail):
1. Start with a clean Ubuntu 22.04 install.
2. Install Docker v24.0.5 and start the service.
3. Clone the Open WebUI repo (git clone ...).
4. Use the Docker Compose file without modifications.
5. Open browser Chrome 115.0 in incognito mode.
6. Go to http://localhost:8080 and log in with user "test@example.com".
7. Set the language to "English" and theme to "Dark".
8. Attempt to connect to Ollama at "http://localhost:11434".
9. Observe that the error message "Connection refused" appears at the top right.
Please list each step carefully and include all relevant configuration, settings, and options.
validations:
required: true
- type: textarea
id: logs-screenshots
attributes:
label: Logs & Screenshots
description: Include relevant logs, errors, or screenshots to help diagnose the issue.
placeholder: 'Attach logs from the browser console, Docker logs, or error messages.'
validations:
required: true
- type: textarea
id: additional-info
attributes:
label: Additional Information
description: Provide any extra details that may assist in understanding the issue.
validations:
required: false
- type: markdown
attributes:
value: |
## Note
If the bug report is incomplete or does not follow instructions, it may not be addressed. Ensure that you've followed all the **README.md** and **troubleshooting.md** guidelines, and provide all necessary information for us to reproduce the issue.
Thank you for contributing to Open WebUI!
+1
View File
@@ -0,0 +1 @@
blank_issues_enabled: false
-35
View File
@@ -1,35 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
# Feature Request
## Important Notes
- **Before submitting a report**: Please check the Issues or Discussions section to see if a similar issue or feature request has already been posted. It's likely we're already tracking it! If you’re unsure, start a discussion post first. This will help us efficiently focus on improving the project.
- **Collaborate respectfully**: We value a constructive attitude, so please be mindful of your communication. If negativity is part of your approach, our capacity to engage may be limited. We’re here to help if you’re open to learning and communicating positively. Remember, Open WebUI is a volunteer-driven project managed by a single maintainer and supported by contributors who also have full-time jobs. We appreciate your time and ask that you respect ours.
- **Contributing**: If you encounter an issue, we highly encourage you to submit a pull request or fork the project. We actively work to prevent contributor burnout to maintain the quality and continuity of Open WebUI.
- **Bug reproducibility**: If a bug cannot be reproduced with a `:main` or `:dev` Docker setup, or a pip install with Python 3.11, it may require additional help from the community. In such cases, we will move it to the "issues" Discussions section due to our limited resources. We encourage the community to assist with these issues. Remember, it’s not that the issue doesn’t exist; we need your help!
Note: Please remove the notes above when submitting your post. Thank you for your understanding and support!
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
@@ -0,0 +1,64 @@
name: Feature Request
description: Suggest an idea for this project
title: 'feat: '
labels: ['triage']
body:
- type: markdown
attributes:
value: |
## Important Notes
### Before submitting
Please check the [Issues](https://github.com/open-webui/open-webui/issues) or [Discussions](https://github.com/open-webui/open-webui/discussions) to see if a similar request has been posted.
It's likely we're already tracking it! If you’re unsure, start a discussion post first.
This will help us efficiently focus on improving the project.
### Collaborate respectfully
We value a **constructive attitude**, so please be mindful of your communication. If negativity is part of your approach, our capacity to engage may be limited. We're here to help if you're **open to learning** and **communicating positively**.
Remember:
- Open WebUI is a **volunteer-driven project**
- It's managed by a **single maintainer**
- It's supported by contributors who also have **full-time jobs**
We appreciate your time and ask that you **respect ours**.
### Contributing
If you encounter an issue, we highly encourage you to submit a pull request or fork the project. We actively work to prevent contributor burnout to maintain the quality and continuity of Open WebUI.
### Bug reproducibility
If a bug cannot be reproduced with a `:main` or `:dev` Docker setup, or a `pip install` with Python 3.11, it may require additional help from the community. In such cases, we will move it to the "[issues](https://github.com/open-webui/open-webui/discussions/categories/issues)" Discussions section due to our limited resources. We encourage the community to assist with these issues. Remember, it’s not that the issue doesn’t exist; we need your help!
- type: checkboxes
id: existing-issue
attributes:
label: Check Existing Issues
description: Please confirm that you've checked for existing similar requests
options:
- label: I have searched the existing issues and discussions.
required: true
- type: textarea
id: problem-description
attributes:
label: Problem Description
description: Is your feature request related to a problem? Please provide a clear and concise description of what the problem is.
placeholder: "Ex. I'm always frustrated when..."
validations:
required: true
- type: textarea
id: solution-description
attributes:
label: Desired Solution you'd like
description: Clearly describe what you want to happen.
validations:
required: true
- type: textarea
id: alternatives-considered
attributes:
label: Alternatives Considered
description: A clear and concise description of any alternative solutions or features you've considered.
- type: textarea
id: additional-context
attributes:
label: Additional Context
description: Add any other context or screenshots about the feature request here.
+14
View File
@@ -1,12 +1,26 @@
version: 2
updates:
- package-ecosystem: uv
directory: '/'
schedule:
interval: monthly
target-branch: 'dev'
- package-ecosystem: pip
directory: '/backend'
schedule:
interval: monthly
target-branch: 'dev'
- package-ecosystem: npm
directory: '/'
schedule:
interval: monthly
target-branch: 'dev'
- package-ecosystem: 'github-actions'
directory: '/'
schedule:
# Check for updates to GitHub Actions every week
interval: monthly
target-branch: 'dev'
+7 -3
View File
@@ -9,9 +9,9 @@
- [ ] **Changelog:** Ensure a changelog entry following the format of [Keep a Changelog](https://keepachangelog.com/) is added at the bottom of the PR description.
- [ ] **Documentation:** Have you updated relevant documentation [Open WebUI Docs](https://github.com/open-webui/docs), or other documentation sources?
- [ ] **Dependencies:** Are there any new dependencies? Have you updated the dependency versions in the documentation?
- [ ] **Testing:** Have you written and run sufficient tests for validating the changes?
- [ ] **Testing:** Have you written and run sufficient tests to validate the changes?
- [ ] **Code review:** Have you performed a self-review of your code, addressing any coding standard issues and ensuring adherence to the project's coding standards?
- [ ] **Prefix:** To cleary categorize this pull request, prefix the pull request title, using one of the following:
- [ ] **Prefix:** To clearly categorize this pull request, prefix the pull request title using one of the following:
- **BREAKING CHANGE**: Significant changes that may affect compatibility
- **build**: Changes that affect the build system or external dependencies
- **ci**: Changes to our continuous integration processes or workflows
@@ -22,7 +22,7 @@
- **i18n**: Internationalization or localization changes
- **perf**: Performance improvement
- **refactor**: Code restructuring for better maintainability, readability, or scalability
- **style**: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc.)
- **style**: Changes that do not affect the meaning of the code (white space, formatting, missing semi-colons, etc.)
- **test**: Adding missing tests or correcting existing tests
- **WIP**: Work in progress, a temporary label for incomplete or ongoing work
@@ -70,3 +70,7 @@
### Screenshots or Videos
- [Attach any relevant screenshots or videos demonstrating the changes]
### Contributor License Agreement
By submitting this pull request, I confirm that I have read and fully agree to the [Contributor License Agreement (CLA)](/CONTRIBUTOR_LICENSE_AGREEMENT), and I am providing my contributions under its terms.
+178 -13
View File
@@ -14,16 +14,18 @@ env:
jobs:
build-main-image:
runs-on: ubuntu-latest
runs-on: ${{ matrix.runner }}
permissions:
contents: read
packages: write
strategy:
fail-fast: false
matrix:
platform:
- linux/amd64
- linux/arm64
include:
- platform: linux/amd64
runner: ubuntu-latest
- platform: linux/arm64
runner: ubuntu-24.04-arm
steps:
# GitHub Packages requires the entire repository name to be in lowercase
@@ -111,16 +113,18 @@ jobs:
retention-days: 1
build-cuda-image:
runs-on: ubuntu-latest
runs-on: ${{ matrix.runner }}
permissions:
contents: read
packages: write
strategy:
fail-fast: false
matrix:
platform:
- linux/amd64
- linux/arm64
include:
- platform: linux/amd64
runner: ubuntu-latest
- platform: linux/arm64
runner: ubuntu-24.04-arm
steps:
# GitHub Packages requires the entire repository name to be in lowercase
@@ -210,17 +214,122 @@ jobs:
if-no-files-found: error
retention-days: 1
build-ollama-image:
runs-on: ubuntu-latest
build-cuda126-image:
runs-on: ${{ matrix.runner }}
permissions:
contents: read
packages: write
strategy:
fail-fast: false
matrix:
platform:
- linux/amd64
- linux/arm64
include:
- platform: linux/amd64
runner: ubuntu-latest
- platform: linux/arm64
runner: ubuntu-24.04-arm
steps:
# GitHub Packages requires the entire repository name to be in lowercase
# although the repository owner has a lowercase username, this prevents some people from running actions after forking
- name: Set repository and image name to lowercase
run: |
echo "IMAGE_NAME=${IMAGE_NAME,,}" >>${GITHUB_ENV}
echo "FULL_IMAGE_NAME=ghcr.io/${IMAGE_NAME,,}" >>${GITHUB_ENV}
env:
IMAGE_NAME: '${{ github.repository }}'
- name: Prepare
run: |
platform=${{ matrix.platform }}
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to the Container registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata for Docker images (cuda126 tag)
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.FULL_IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=tag
type=sha,prefix=git-
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=raw,enable=${{ github.ref == 'refs/heads/main' }},prefix=,suffix=,value=cuda126
flavor: |
latest=${{ github.ref == 'refs/heads/main' }}
suffix=-cuda126,onlatest=true
- name: Extract metadata for Docker cache
id: cache-meta
uses: docker/metadata-action@v5
with:
images: ${{ env.FULL_IMAGE_NAME }}
tags: |
type=ref,event=branch
${{ github.ref_type == 'tag' && 'type=raw,value=main' || '' }}
flavor: |
prefix=cache-cuda126-${{ matrix.platform }}-
latest=false
- name: Build Docker image (cuda126)
uses: docker/build-push-action@v5
id: build
with:
context: .
push: true
platforms: ${{ matrix.platform }}
labels: ${{ steps.meta.outputs.labels }}
outputs: type=image,name=${{ env.FULL_IMAGE_NAME }},push-by-digest=true,name-canonical=true,push=true
cache-from: type=registry,ref=${{ steps.cache-meta.outputs.tags }}
cache-to: type=registry,ref=${{ steps.cache-meta.outputs.tags }},mode=max
build-args: |
BUILD_HASH=${{ github.sha }}
USE_CUDA=true
USE_CUDA_VER=cu126
- name: Export digest
run: |
mkdir -p /tmp/digests
digest="${{ steps.build.outputs.digest }}"
touch "/tmp/digests/${digest#sha256:}"
- name: Upload digest
uses: actions/upload-artifact@v4
with:
name: digests-cuda126-${{ env.PLATFORM_PAIR }}
path: /tmp/digests/*
if-no-files-found: error
retention-days: 1
build-ollama-image:
runs-on: ${{ matrix.runner }}
permissions:
contents: read
packages: write
strategy:
fail-fast: false
matrix:
include:
- platform: linux/amd64
runner: ubuntu-latest
- platform: linux/arm64
runner: ubuntu-24.04-arm
steps:
# GitHub Packages requires the entire repository name to be in lowercase
@@ -420,6 +529,62 @@ jobs:
run: |
docker buildx imagetools inspect ${{ env.FULL_IMAGE_NAME }}:${{ steps.meta.outputs.version }}
merge-cuda126-images:
runs-on: ubuntu-latest
needs: [build-cuda126-image]
steps:
# GitHub Packages requires the entire repository name to be in lowercase
# although the repository owner has a lowercase username, this prevents some people from running actions after forking
- name: Set repository and image name to lowercase
run: |
echo "IMAGE_NAME=${IMAGE_NAME,,}" >>${GITHUB_ENV}
echo "FULL_IMAGE_NAME=ghcr.io/${IMAGE_NAME,,}" >>${GITHUB_ENV}
env:
IMAGE_NAME: '${{ github.repository }}'
- name: Download digests
uses: actions/download-artifact@v4
with:
pattern: digests-cuda126-*
path: /tmp/digests
merge-multiple: true
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to the Container registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata for Docker images (default latest tag)
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.FULL_IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=tag
type=sha,prefix=git-
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=raw,enable=${{ github.ref == 'refs/heads/main' }},prefix=,suffix=,value=cuda126
flavor: |
latest=${{ github.ref == 'refs/heads/main' }}
suffix=-cuda126,onlatest=true
- name: Create manifest list and push
working-directory: /tmp/digests
run: |
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
$(printf '${{ env.FULL_IMAGE_NAME }}@sha256:%s ' *)
- name: Inspect image
run: |
docker buildx imagetools inspect ${{ env.FULL_IMAGE_NAME }}:${{ steps.meta.outputs.version }}
merge-ollama-images:
runs-on: ubuntu-latest
needs: [build-ollama-image]
+12 -2
View File
@@ -5,10 +5,18 @@ on:
branches:
- main
- dev
paths:
- 'backend/**'
- 'pyproject.toml'
- 'uv.lock'
pull_request:
branches:
- main
- dev
paths:
- 'backend/**'
- 'pyproject.toml'
- 'uv.lock'
jobs:
build:
@@ -17,7 +25,9 @@ jobs:
strategy:
matrix:
python-version: [3.11]
python-version:
- 3.11.x
- 3.12.x
steps:
- uses: actions/checkout@v4
@@ -25,7 +35,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
python-version: '${{ matrix.python-version }}'
- name: Install dependencies
run: |
+11 -3
View File
@@ -5,10 +5,18 @@ on:
branches:
- main
- dev
paths-ignore:
- 'backend/**'
- 'pyproject.toml'
- 'uv.lock'
pull_request:
branches:
- main
- dev
paths-ignore:
- 'backend/**'
- 'pyproject.toml'
- 'uv.lock'
jobs:
build:
@@ -21,10 +29,10 @@ jobs:
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '22' # Or specify any other version you want to use
node-version: '22'
- name: Install Dependencies
run: npm install
run: npm install --force
- name: Format Frontend
run: npm run format
@@ -51,7 +59,7 @@ jobs:
node-version: '22'
- name: Install Dependencies
run: npm ci
run: npm ci --force
- name: Run vitest
run: npm run test:frontend
+5 -1
View File
@@ -17,9 +17,13 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install Git
run: sudo apt-get update && sudo apt-get install -y git
- uses: actions/setup-node@v4
with:
node-version: 18
node-version: 22
- uses: actions/setup-python@v5
with:
python-version: 3.11
+4 -1
View File
@@ -1,3 +1,5 @@
x.py
yarn.lock
.DS_Store
node_modules
/build
@@ -12,7 +14,8 @@ vite.config.ts.timestamp-*
__pycache__/
*.py[cod]
*$py.class
.nvmrc
CLAUDE.md
# C extensions
*.so
+2 -1
View File
@@ -5,5 +5,6 @@
"printWidth": 100,
"plugins": ["prettier-plugin-svelte"],
"pluginSearchDirs": ["."],
"overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
"overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }],
"endOfLine": "lf"
}
+899
View File
@@ -5,6 +5,905 @@ 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.6.19] - 2025-08-09
### Added
- ✨ **Modernized Sidebar and Major UI Refinements**: The main navigation sidebar has been completely redesigned with a modern, cleaner aesthetic, featuring a sticky header and footer to keep key controls accessible. Core sidebar logic, like the pinned models list, was also refactored into dedicated components for better performance and maintainability.
- 🪄 **Guided Response Regeneration**: The "Regenerate" button has been transformed into a powerful new menu. You can now guide the AI's next attempt by suggesting changes in a text prompt, or use one-click options like "Try Again," "Add Details," or "More Concise" to instantly refine and reshape the response to better fit your needs.
- 🛠️ **Improved Tool Call Handling for GPT-OSS Models**: Implemented robust handling for tool calls specifically for GPT-OSS models, ensuring proper function execution and integration.
- 🛑 **Stop Button for Merge Responses**: Added a dedicated stop button to immediately halt the generation of merged AI responses, providing users with more control over ongoing outputs.
- 🔄 **Experimental SCIM 2.0 Support**: Implemented SCIM 2.0 (System for Cross-domain Identity Management) protocol support, enabling enterprise-grade automated user and group provisioning from identity providers like Okta, Azure AD, and Google Workspace for seamless user lifecycle management. Configuration is managed securely via environment variables.
- 🗂️ **Amazon S3 Vector Support**: You can now use Amazon S3 Vector as a high-performance vector database for your Retrieval-Augmented Generation (RAG) workflows. This provides a scalable, cloud-native storage option for users deeply integrated into the AWS ecosystem, simplifying infrastructure and enabling enterprise-scale knowledge management.
- 🗄️ **Oracle 23ai Vector Search Support**: Added support for Oracle 23ai's new vector search capabilities as a supported vector database, providing a robust and scalable option for managing large-scale documents and integrating vector search with existing business data at the database level.
- ⚡ **Qdrant Performance and Configuration Enhancements**: The Qdrant client has been significantly improved with faster data retrieval logic for 'get' and 'query' operations. New environment variables ('QDRANT_TIMEOUT', 'QDRANT_HNSW_M') provide administrators with finer control over query timeouts and HNSW index parameters, enabling better performance tuning for large-scale deployments.
- 🔐 **Encrypted SQLite Database with SQLCipher**: You can now encrypt your entire SQLite database at rest using SQLCipher. By setting the 'DATABASE_TYPE' to 'sqlite+sqlcipher' and providing a 'DATABASE_PASSWORD', all data is transparently encrypted, providing an essential security layer for protecting sensitive information in self-hosted deployments. Note that this requires additional system libraries and the 'sqlcipher3-wheels' Python package.
- 🚀 **Efficient Redis Connection Management**: Implemented a shared connection pool cache to reuse Redis connections, dramatically reducing the number of active clients. This prevents connection exhaustion errors, improves performance, and ensures greater stability in high-concurrency deployments and those using Redis Sentinel.
- ⚡ **Batched Response Streaming for High Performance**: Dramatically improve performance and stability during high-speed response streaming by batching multiple tokens together before sending them to the client. A new 'Stream Delta Chunk Size' advanced parameter can be set per-model or in user/chat settings, significantly reducing CPU load on the server, Redis, and client, and preventing connection issues in high-concurrency environments.
- ⚙️ **Global Batched Streaming Configuration**: Administrators can now set a system-wide default for response streaming using the new 'CHAT_RESPONSE_STREAM_DELTA_CHUNK_SIZE' environment variable. This allows for global performance tuning, while still letting per-model or per-chat settings override the default for more granular control.
- 🔎 **Advanced Chat Search with Status Filters**: Quickly find any conversation with powerful new search filters. You can now instantly narrow down your chats using prefixes like 'pinned:true', 'shared:true', and 'archived:true' directly in the search bar. An intelligent dropdown menu assists you by suggesting available filter options as you type, streamlining your workflow and making chat management more efficient than ever.
- 🛂 **Granular Chat Controls Permissions**: Administrators can now manage chat settings with greater detail. The main "Chat Controls" permission now acts as a master switch, while new granular toggles for "Valves", "System Prompts", and "Advanced Parameters" allow for more specific control over which sections are visible to users inside the panel.
- ✍️ **Formatting Toolbar for Chat Input**: Introduced a dedicated formatting toolbar for the rich text chat input field, providing users with more accessible options for text styling and editing, configurable via interface settings.
- 📑 **Tabbed View for Multi-Model Responses**: You can now enable a new tabbed interface to view responses from multiple models. Instead of side-scrolling cards, this compact view organizes each model's response into its own tab, making it easier to compare outputs and saving vertical space. This feature can be toggled on or off in Interface settings.
- ↕️ **Reorder Pinned Models via Drag-and-Drop**: You can now organize your pinned models in the sidebar by simply dragging and dropping them into your preferred order. This custom layout is saved automatically, giving you more flexible control over your workspace.
- 📌 **Quick Model Unpin Shortcut**: You can now quickly unpin a model by holding the Shift key and hovering over it to reveal an instant unpin button, streamlining your workspace customization.
- ⚡ **Improved Chat Input Performance**: The chat input is now significantly more responsive, especially when pasting or typing large amounts of text. This was achieved by implementing a debounce mechanism for the auto-save feature, which prevents UI lag and ensures a smooth, uninterrupted typing experience.
- ✍️ **Customizable Floating Quick Actions with Tool Support**: Take full control of your text interaction workflow with new customizable floating quick actions. In Settings, you can create, edit, or disable these actions and even integrate tools using the '{{TOOL:tool_id}}' syntax in your prompts, enabling powerful one-click automations on selected text. This is in addition to using placeholders like '{{CONTENT}}' and '{{INPUT_CONTENT}}' for custom text transformations.
- 🔒 **Admin Workspace Privacy Control**: Introduced the 'ENABLE_ADMIN_WORKSPACE_CONTENT_ACCESS' environment variable (defaults to 'True') allowing administrators to control their access privileges to workspace items (Knowledge, Models, Prompts, Tools). When disabled, administrators adhere to the same access control rules as regular users, enhancing data separation for multi-tenant deployments.
- 🗄️ **Comprehensive Model Configuration Management**: Administrators can now export the entire model configuration to a file and use a new declarative sync endpoint to manage models in bulk. This powerful feature enables seamless backups, migrations, and state replication across multiple instances.
- 📦 **Native Redis Cluster Mode Support**: Added full support for connecting to Redis in cluster mode, allowing for scalable and highly available Redis deployments beyond Sentinel-managed setups. New environment variables 'REDIS_CLUSTER' and 'WEBSOCKET_REDIS_CLUSTER' enable the use of 'redis.cluster.RedisCluster' clients.
- 📊 **Granular OpenTelemetry Metrics Configuration**: Introduced dedicated environment variables and enhanced configuration options for OpenTelemetry metrics, allowing for separate OTLP endpoints, basic authentication credentials, and protocol (HTTP/gRPC) specifically for metrics export, independent of trace settings. This provides greater flexibility for integrating with diverse observability stacks.
- 🪵 **Granular OpenTelemetry Logging Configuration**: Enhanced the OpenTelemetry logging integration by introducing dedicated environment variables for logs, allowing separate OTLP endpoints, basic authentication credentials, and protocol (HTTP/gRPC) specifically for log export, independent of general OTel settings. The application's default Python logger now leverages this configuration to automatically send logs to your OTel endpoint when enabled via 'ENABLE_OTEL_LOGS'.
- 📁 **Enhanced Folder Chat Management with Sorting and Time Blocks**: The chat list within folders now supports comprehensive sorting options by title and updated time, along with intelligent time-based grouping (e.g., "Today," "Yesterday") similar to the main chat view, making navigation and organization of project-specific conversations significantly easier.
- ⚙️ **Configurable Datalab Marker API & Advanced Processing Options**: Enhanced Datalab Marker API integration, allowing administrators to configure custom API base URLs for self-hosting and to specify comprehensive processing options via a new 'additional_config' JSON parameter. This replaces the deprecated language selection feature and provides granular control over document extraction, with streamlined API endpoint resolution for more robust self-hosted deployments.
- 🧑‍💼 **Export All Users to CSV**: Administrators can now export a complete list of all users to a CSV file directly from the Admin Panel's database settings. This provides a simple, one-click way to generate user data for auditing, reporting, or management purposes.
- 🛂 **Customizable OAuth 'sub' Claim**: Administrators can now use the 'OAUTH_SUB_CLAIM_OVERRIDE' environment variable to specify which claim from the identity provider should be used as the unique user identifier ('sub'). This provides greater flexibility and control for complex enterprise authentication setups where modifying the IDP's default claims is not possible.
- 👁️ **Password Visibility Toggle for Input Fields**: Password fields across the application (login, registration, user management, and account settings) now utilize a new 'SensitiveInput' component, providing a consistent toggle to reveal/hide passwords for improved usability and security.
- 🛂 **Optional "Confirm Password" on Sign-Up**: To help prevent password typos during account creation, administrators can now enable a "Confirm Password" field on the sign-up page. This feature is disabled by default and can be activated via an environment variable for enhanced user experience.
- 💬 **View Full Chat from User Feedback**: Administrators can now easily navigate to the full conversation associated with a user feedback entry directly from the feedback modal, streamlining the review and troubleshooting process.
- 🎚️ **Intuitive Hybrid Search BM25-Weight Slider**: The numerical input for the BM25-Weight parameter in Hybrid Search has been replaced with an interactive slider, offering a more intuitive way to adjust the balance between lexical and semantic search. A "Default/Custom" toggle and clearer labels enhance usability and understanding of this key parameter.
- ⚙️ **Enhanced Bulk Function Synchronization**: The API endpoint for synchronizing functions has been significantly improved to reliably handle bulk updates. This ensures that importing and managing large libraries of functions is more robust and error-free for administrators.
- 🖼️ **Option to Disable Image Compression in Channels**: Introduced a new setting under Interface options to allow users to force-disable image compression specifically for images posted in channels, ensuring higher resolution for critical visual content.
- 🔗 **Custom CORS Scheme Support**: Introduced a new environment variable 'CORS_ALLOW_CUSTOM_SCHEME' that allows administrators to define custom URL schemes (e.g., 'app://') for CORS origins, enabling greater flexibility for local development or desktop client integrations.
- ♿ **Translatable and Accessible Banners**: Enhanced banner elements with translatable badge text and proper ARIA attributes (aria-label, aria-hidden) for SVG icons, significantly improving accessibility and screen reader compatibility.
- ⚠️ **OAuth Configuration Warning for Missing OPENID_PROVIDER_URL**: Added a proactive startup warning that notifies administrators when OAuth providers (Google, Microsoft, or GitHub) are configured but the essential 'OPENID_PROVIDER_URL' environment variable is missing. This prevents silent OAuth logout failures and guides administrators to complete their setup correctly.
- ♿ **Major Accessibility Enhancements**: Key parts of the interface have been made significantly more accessible. The user profile menu is now fully navigable via keyboard, essential controls in the Playground now include proper ARIA labels for screen readers, and decorative images have been hidden from assistive technologies to reduce audio clutter. Menu buttons also feature enhanced accessibility with 'aria-label', 'aria-hidden' for SVGs, and 'aria-pressed' for toggle buttons.
- ⚙️ **General Backend Refactoring**: Implemented various backend improvements to enhance performance, stability, and security, ensuring a more resilient and reliable platform for all users, including refining logging output to be cleaner and more efficient by conditionally including 'extra_json' fields and improving consistent metadata handling in vector database operations, and laying preliminary scaffolding for future analytics features.
- 🌐 **Localization & Internationalization Improvements**: Refined and expanded translations for Catalan, Danish, Korean, Persian, Polish, Simplified Chinese, and Spanish, ensuring a more fluent and native experience for global users across all supported languages.
### Fixed
- 🛡️ **Hardened Channel Message Security**: Fixed a key permission flaw that allowed users with channel access to edit or delete messages belonging to others. The system now correctly enforces that users can only modify their own messages, protecting data integrity in shared channels.
- 🛡️ **Hardened OAuth Security by Removing JWT from URL**: Fixed a critical security vulnerability where the authentication token was exposed in the URL after a successful OAuth login. The token is now transferred via a browser cookie, preventing potential leaks through browser history or server logs and protecting user sessions.
- 🛡️ **Hardened Chat Completion API Security**: The chat completion API endpoint now includes an explicit ownership check, ensuring non-admin users cannot access chats that do not belong to them and preventing potential unauthorized access.
- 🛠️ **Resilient Model Loading**: Fixed an issue where a failure in loading the model list (e.g., from a misconfigured provider) would prevent the entire user interface, including the admin panel, from loading. The application now gracefully handles these errors, ensuring the UI remains accessible.
- 🔒 **Resolved FIPS Self-Test Failure**: Fixed a critical issue that prevented Open WebUI from running on FIPS-compliant systems, specifically resolving the "FATAL FIPS SELFTEST FAILURE" error related to OpenSSL and SentenceTransformers, restoring compatibility with secure environments.
- 📦 **Redis Cluster Connection Restored**: Fixed an issue where the backend was unable to connect to Redis in cluster mode, now ensuring seamless integration with scalable Redis cluster deployments.
- 📦 **PGVector Connection Stability**: Fixed an issue where read-only operations could leave database transactions idle, preventing potential connection errors and improving overall database stability and resource management.
- 🛠️ **OpenAPI Tool Integration for Array Parameters Fixed**: Resolved a critical bug where external tools using array parameters (e.g., for tags) would fail when used with OpenAI models. The system now correctly generates the required 'items' property in the function schema, restoring functionality and preventing '400 Bad Request' errors.
- 🛠️ **Tool Creation for Users Restored**: Fixed a bug in the code editor where status messages were incorrectly prepended to tool scripts, causing a syntax error upon saving. All authorized users can now reliably create and save new tools.
- 📁 **Folder Knowledge Processing Restored**: Fixed a bug where files uploaded to folder and model knowledge bases were not being extracted or analyzed for Retrieval-Augmented Generation (RAG) when the 'Max Upload Count' setting was empty, ensuring seamless document processing and knowledge augmentation.
- 🧠 **Custom Model Knowledge Base Updates Recognized**: Fixed a bug where custom models linked to to knowledge bases did not automatically recognize newly added files to those knowledge bases. Models now correctly incorporate the latest information from updated knowledge collections.
- 📦 **Comprehensive Redis Key Prefixing**: Corrected hardcoded prefixes to ensure the REDIS_KEY_PREFIX is now respected across all WebSocket and task management keys. This prevents data collisions in multi-instance deployments and improves compatibility with Redis cluster mode.
- ✨ **More Descriptive OpenAI Router Errors**: The OpenAI-compatible API router now propagates detailed upstream error messages instead of returning a generic 'Bad Request'. This provides clear, actionable feedback for developers and API users, making it significantly easier to debug and resolve issues with model requests.
- 🔐 **Hardened OIDC Signout Flow**: The OpenID Connect signout process now verifies that the 'OPENID_PROVIDER_URL' is configured before attempting to communicate with it, preventing potential errors and ensuring a more reliable logout experience.
- 🍓 **Raspberry Pi Compatibility Restored**: Pinned the pyarrow library to version 20.0.0, resolving an "Illegal Instruction" crash on ARM-based devices like the Raspberry Pi and ensuring stable operation on this hardware.
- 📁 **Folder System Prompt Variables Restored**: Fixed a bug where prompt variables (e.g., '{{CURRENT_DATETIME}}') were not being rendered in Folder-level System Prompts. This restores an important capability for creating dynamic, context-aware instructions for all chats within a project folder.
- 📝 **Note Access in Knowledge Retrieval Fixed**: Corrected a permission oversight in knowledge retrieval, ensuring users can always use their own notes as a source for RAG without needing explicit sharing permissions.
- 🤖 **Title Generation Compatibility for GPT-5 Models**: Added support for 'gpt-5' models in the payload handler, which correctly converts the deprecated 'max_tokens' parameter to 'max_completion_tokens'. This resolves title generation failures and ensures seamless operation with the latest generation of models.
- ⚙️ **Correct API 'finish_reason' in Streaming Responses**: Fixed an issue where intermediate 'reasoning_content' chunks in streaming API responses incorrectly reported a 'finish_reason' of 'stop'. The 'finish_reason' is now correctly set to 'null' for these chunks, ensuring compatibility with third-party applications that rely on this field.
- 📈 **Evaluation Pages Stability**: Resolved a crash on the Leaderboard and Feedbacks pages when processing legacy feedback entries that were missing a 'rating' field. The system now gracefully handles this older data, ensuring both pages load reliably for all users.
- 🤝 **Reliable Collaborative Session Cleanup**: Fixed an asynchronous bug in the real-time collaboration engine that prevented document sessions from being properly cleaned up after all users had left. This ensures greater stability and resource management for features like Collaborative Notes.
- 🧠 **Enhanced Memory Stability and Security**: Refactored memory update and delete operations to strictly enforce user ownership, preventing potential data integrity issues. Additionally, improved error handling for memory queries now provides clearer feedback when no memories exists.
- 🧑‍⚖️ **Restored Admin Access to User Feedback**: Fixed a permission issue that blocked administrators from viewing or editing user feedback they didn't create, ensuring they can properly manage all evaluations across the platform.
- 🔐 **PGVector Encryption Fix for Metadata**: Corrected a SQL syntax error in the experimental 'PGVECTOR_PGCRYPTO' feature that prevented encrypted metadata from being saved. Document uploads to encrypted PGVector collections now work as intended.
- 🔍 **Serply Web Search Integration Restored**: Fixed an issue where incorrect parameters were passed to the Serply web search engine, restoring its functionality for RAG and web search workflows.
- 🔍 **Resilient Web Search Processing**: Web search retrieval now gracefully handles search results that are missing a 'snippet', preventing crashes and ensuring that RAG workflows complete successfully even with incomplete data from search engines.
- 🖼️ **Table Pasting in Rich Text Input Displayed Correctly**: Fixed an issue where pasting table text into the rich text input would incorrectly display it as code. Tables are now properly rendered as expected, improving content formatting and user experience.
- ✍️ **Rich Text Input TypeError Resolution**: Addressed a potential 'TypeError: ue.getWordAtDocPos is not a function' in 'MessageInput.svelte' by refactoring how the 'getWordAtDocPos' function is accessed and referenced from 'RichTextInput.svelte', ensuring stable rich text input behavior, especially after production restarts.
- ✏️ **Manual Code Block Creation in Chat Restored**: Fixed an issue where typing three backticks and then pressing Shift+Enter would incorrectly remove the backticks when "Enter to Send" mode was active. This ensures users can reliably create multi-line code blocks manually.
- 🎨 **Consistent Dark Mode Background**: Fixed an issue where the application background could incorrectly flash or remain white during page loads and refreshes in dark mode, ensuring a seamless and consistent visual experience.
- 🎨 **'Her' Theme Rendering Fixed**: Corrected a bug that caused the "Her" theme to incorrectly render as a dark theme in some situations. The theme now reliably applies its intended light appearance across all sessions.
- 📜 **Corrected Markdown Table Line Break Rendering**: Fixed an issue where line breaks ('<br>') within Markdown tables were displayed as raw HTML instead of being rendered correctly. This ensures that tables with multi-line cell content are now displayed as intended.
- 🚦 **Corrected App Configuration for Pending Users**: Fixed an issue where users awaiting approval could incorrectly load the full application interface, leading to a confusing or broken UI. This ensures that only fully approved users receive the standard app 'config', resulting in a smoother and more reliable onboarding experience.
- 🔄 **Chat Cloning Now Includes Tags, Folder Status, and Pinned Status**: When cloning a chat or shared chat, its associated tags, folder organization, and pinned status are now correctly replicated, ensuring consistent chat management.
- ⚙️ **Enhanced Backend Reliability**: Resolved a potential crash in knowledge base retrieval when referencing a deleted note. Additionally, chat processing was refactored to ensure model information is saved more reliably, enhancing overall system stability.
- ⚙️ **Floating 'Ask/Explain' Modal Stability**: Fixed an issue that spammed the console with errors when navigating away while a model was generating a response in the floating 'Ask' or 'Explain' modals. In-flight requests are now properly cancelled, improving application stability.
- ⚡ **Optimized User Count Checks**: Improved performance for user count and existence checks across the application by replacing resource-intensive 'COUNT' queries with more efficient 'EXISTS' queries, reducing database load.
- 🔐 **Hardened OpenTelemetry Exporter Configuration**: The OTLP HTTP exporter no longer uses a potentially insecure explicit flag, improving security by relying on the connection URL's protocol (HTTP/HTTPS) to ensure transport safety.
- 📱 **Mobile User Menu Closing Behavior Fixed**: Resolved an issue where the user menu would remain open on mobile devices after selecting an option, ensuring the menu correctly closes and returns focus to the main interface for a smoother mobile experience.
- 📱 **OnBoarding Page Display Fixed on Mobile**: Resolved an issue where buttons on the OnBoarding page were not consistently visible on certain mobile browsers, ensuring a functional and complete user experience across devices.
- ↕️ **Improved Pinned Models Drag-and-Drop Behavior**: The drag-and-drop functionality for reordering pinned models is now explicitly disabled on mobile devices, ensuring better usability and preventing potential UI conflicts or unexpected behavior.
- 📱 **PWA Rotation Behavior Corrected**: The Progressive Web App now correctly respects the device's screen orientation lock, preventing unwanted rotation and ensuring a more native mobile experience.
- ✏️ **Improved Chat Title Editing Behavior**: Changes to a chat title are now reliably saved when the user clicks away or presses Enter, replacing a less intuitive behavior that could accidentally discard edits. This makes renaming chats a smoother and more predictable experience.
- ✏️ **Underscores Allowed in Prompt Commands**: Fixed the validation for prompt commands to correctly allow the use of underscores ('\_'), aligning with documentation examples and improving flexibility in naming custom prompts.
- 💡 **Title Generation Button Behavior Fixed**: Resolved an issue where clicking the "Generate Title" button while editing a chat or note title would incorrectly save the title before generation could start. The focus is now managed correctly, ensuring a smooth and predictable user experience.
- ✏️ **Consistent Chat Input Height**: Fixed a minor visual bug where the chat input field's height would change slightly when toggling the "Rich Text Input for Chat" setting, ensuring a more stable and consistent layout.
- 🙈 **Admin UI Toggle Stability**: Fixed a visual glitch in the Admin settings where toggle switches could briefly display an incorrect state on page load, ensuring the UI always accurately reflects the saved settings.
- 🙈 **Community Sharing Button Visibility**: The "Share to Community" button on the feedback page is now correctly hidden when the Enable Community Sharing feature is disabled in the admin settings, ensuring the UI respects the configured sharing policy.
- 🙈 **"Help Us Translate" Link Visibility**: The "Help us translate" link in settings is now correctly hidden in deployments with specific license configurations, ensuring a cleaner interface for enterprise users.
- 🔗 **Robust Tool Server URL Handling**: Fixed an issue where providing a full URL for a tool server's OpenAPI specification resulted in an invalid path. The system now correctly handles both absolute URLs and relative paths, improving configuration flexibility.
- 🔧 **Improved Azure URL Detection**: The logic for identifying Azure OpenAI endpoints has been made more robust, ensuring all valid Azure URLs are now correctly detected for a smoother connection setup.
- ⚙️ **Corrected Direct Connection Save Logic**: Fixed a bug in the Admin Connections settings page by removing a redundant save action for 'Direct Connections', leading to more reliable and predictable behavior when updating settings.
- 🔗 **Corrected "Discover" Links**: The "Discover" links for models, prompts, tools, and functions now point to their specific, relevant pages on openwebui.com, improving content discovery for users.
- ⏱️ **Refined Display of AI Thought Duration**: Adjusted the display logic for AI thought (reasoning) durations to more accurately show very short thought times as "less than a second," improving clarity in AI process feedback.
- 📜 **Markdown Line Break Rendering Refinement**: Improved handling of line breaks within Markdown rendering for better visual consistency.
- 🛠️ **Corrected OpenTelemetry Docker Compose Example**: The docker-compose.otel.yaml file has been fixed and enhanced by removing duplicates, adding necessary environment variables, and hardening security settings, ensuring a more reliable out-of-box observability setup.
- 🛠️ **Development Script CORS Fix**: Corrected the CORS origin URL in the local development script (dev.sh) by removing the trailing slash, ensuring a more reliable and consistent setup for developers.
- ⬆️ **OpenTelemetry Libraries Updated**: Upgraded all OpenTelemetry-related libraries to their latest versions, ensuring better performance, stability, and compatibility for observability.
### Changed
- ❗ **Docling Integration Upgraded to v1 API (Breaking Change)**: The integration with the Docling document processing engine has been updated to its new, stable '/v1' API. This is required for compatibility with Docling version 1.0.0 and newer. As a result, older versions of Docling are no longer supported. Users who rely on Docling for document ingestion **must upgrade** their docling-serve instance to ensure continued functionality.
- 🗣️ **Admin-First Whisper Language Priority**: The global WHISPER_LANGUAGE setting now acts as a strict override for audio transcriptions. If set, it will be used for all speech-to-text tasks, ignoring any language specified by the user on a per-request basis. This gives administrators more control over transcription consistency.
- ✂️ **Datalab Marker API Language Selection Removed**: The separate language selection option for the Datalab Marker API has been removed, as its functionality is now integrated and superseded by the more comprehensive 'additional_config' parameter. Users should transition to using 'additional_config' for relevant language and processing settings.
- 📄 **Documentation and Releases Links Visibility**: The "Documentation" and "Releases" links in the user menu are now visible only to admin users, streamlining the user interface for non-admin roles.
## [0.6.18] - 2025-07-19
### Fixed
- 🚑 **Users Not Loading in Groups**: Resolved an issue where user list was not displaying within user groups, restoring full visibility and management of group memberships for teams and admins.
## [0.6.17] - 2025-07-19
### Added
- 📂 **Dedicated Folder View with Chat List**: Clicking a folder now reveals a brand-new landing page showcasing a list of all chats within that folder, making navigation simpler and giving teams immediate visibility into project-specific conversations.
- 🆕 **Streamlined Folder Creation Modal**: Creating a new folder is now a seamless, unified experience with a dedicated modal that visually and functionally matches the edit folder flow, making workspace organization more intuitive and error-free for all users.
- 🗃️ **Direct File Uploads to Folder Knowledge**: You can now upload files straight to a folder’s knowledge—empowering you to enrich project spaces by adding resources and documents directly, without the need to pre-create knowledge bases beforehand.
- 🔎 **Chat Preview in Search**: When searching chats, instantly preview results in context without having to open them—making discovery, auditing, and recall dramatically quicker, especially in large, active teams.
- 🖼️ **Image Upload and Inline Insertion in Notes**: Notes now support inserting images directly among your text, letting you create rich, visually structured documentation, brainstorms, or reports in a more natural and engaging way—no more images just as attachments.
- 📱 **Enhanced Note Selection Editing and Q&A**: Select any portion of your notes to either edit just the highlighted part or ask focused questions about that content—streamlining workflows, boosting productivity, and making reviews or AI-powered enhancements more targeted.
- 📝 **Copy Notes as Rich Text**: Copy entire notes—including all formatting, images, and structure—directly as rich text for seamless pasting into emails, reports, or other tools, maintaining clarity and consistency outside the WebUI.
- ⚡ **Fade-In Streaming Text Experience**: Live-generated responses now elegantly fade in as the AI streams them, creating a more natural and visually engaging reading experience; easily toggled off in Interface settings if you prefer static displays.
- 🔄 **Settings for Follow-Up Prompts**: Fine-tune your follow-up prompt experience—with new controls, you can choose to keep them visible or have them inserted directly into the message input instead of auto-submitting, giving you more flexibility and control over your workflow.
- 🔗 **Prompt Variable Documentation Quick Link**: Access documentation for prompt variables in one click from the prompt editor modal—shortening the learning curve and making advanced prompt-building more accessible.
- 📈 **Active and Total User Metrics for Telemetry**: Gain valuable insights into usage patterns and platform engagement with new metrics tracking active and total users—enhancing auditability and planning for large organizations.
- 🏷️ **Traceability with Log Trace and Span IDs**: Each log entry now carries detailed trace and span IDs, making it much easier for admins to pinpoint and resolve issues across distributed systems or in complex troubleshooting.
- 👥 **User Group Add/Remove Endpoints**: Effortlessly add or remove users from groups with new, improved endpoints—giving admins and team leads faster, clearer control over collaboration and permissions.
- ⚙️ **Note Settings and Controls Streamlined**: The main “Settings” for notes are now simply called “Controls”, and note files now reside in a dedicated controls section, decluttering navigation and making it easier to find and configure note-related options.
- 🚀 **Faster Admin User Page Loads**: The user list endpoint for admins has been optimized to exclude heavy profile images, speeding up load times for large teams and reducing waiting during administrative tasks.
- 📡 **Chat ID Header Forwarding**: Ollama and OpenAI router requests now include the chat ID in request headers, enabling better request correlation and debugging capabilities across AI model integrations.
- 🧠 **Enhanced Reasoning Tag Processing**: Improved and expanded reasoning tag parsing to handle various tag formats more robustly, including standard XML-style tags and custom delimiters, ensuring better AI reasoning transparency and debugging capabilities.
- 🔐 **OAuth Token Endpoint Authentication Method**: Added configurable OAuth token endpoint authentication method support, providing enhanced flexibility and security options for enterprise OAuth integrations and identity provider compatibility.
- 🛡️ **Redis Sentinel High Availability Support**: Comprehensive Redis Sentinel failover implementation with automatic master discovery, intelligent retry logic for connection failures, and seamless operation during master node outages—eliminating single points of failure and ensuring continuous service availability in production deployments.
- 🌐 **Localization & Internationalization Improvements**: Refined and expanded translations for Simplified Chinese, Traditional Chinese, French, German, Korean, and Polish, ensuring a more fluent and native experience for global users across all supported languages.
### Fixed
- 🏷️ **Hybrid Search Functionality Restored**: Hybrid search now works seamlessly again—enabling more accurate, relevant, and comprehensive knowledge discovery across all RAG-powered workflows.
- 🚦 **Note Chat - Edit Button Disabled During AI Generation**: The edit button when chatting with a note is now disabled while the AI is responding—preventing accidental edits and ensuring workflow clarity during chat sessions.
- 🧹 **Cleaner Database Credentials**: Database connection no longer duplicates ‘@’ in credentials, preventing potential connection issues and ensuring smoother, more reliable integrations.
- 🧑‍💻 **File Deletion Now Removes Related Vector Data**: When files are deleted from storage, they are now purged from the vector database as well, ensuring clean data management and preventing clutter or stale search results.
- 📁 **Files Modal Translation Issues Fixed**: All modal dialog strings—including “Using Entire Document” and “Using Focused Retrieval”—are now fully translated for a more consistent and localized UI experience.
- 🚫 **Drag-and-Drop File Upload Disabled for Unsupported Models**: File upload by drag-and-drop is disabled when using models that do not support attachments—removing confusion and preventing workflow interruptions.
- 🔑 **Ollama Tool Calls Now Reliable**: Fixed issues with Ollama-based tool calls, ensuring uninterrupted AI augmentation and tool use for every chat.
- 📄 **MIME Type Help String Correction**: Cleaned up mimetype help text by removing extraneous characters, providing clearer guidance for file upload configurations.
- 📝 **Note Editor Permission Fix**: Removed unnecessary admin-only restriction from note chat functionality, allowing all authorized users to access note editing features as intended.
- 📋 **Chat Sources Handling Improved**: Fixed sources handling logic to prevent duplicate source assignments in chat messages, ensuring cleaner and more accurate source attribution during conversations.
- 😀 **Emoji Generation Error Handling**: Improved error handling in audio router and fixed metadata structure for emoji generation tasks, preventing crashes and ensuring more reliable emoji generation functionality.
- 🔒 **Folder System Prompt Permission Enforcement**: System prompt fields in folder edit modal are now properly hidden for users without system prompt permissions, ensuring consistent security policy enforcement across all folder management interfaces.
- 🌐 **WebSocket Redis Lock Timeout Type Conversion**: Fixed proper integer type conversion for WebSocket Redis lock timeout configuration with robust error handling, preventing potential configuration errors and ensuring stable WebSocket connections.
- 📦 **PostHog Dependency Added**: Added PostHog 5.4.0 library to resolve ChromaDB compatibility issues, ensuring stable vector database operations and preventing library version conflicts during deployment.
### Changed
- 👀 **Tiptap Editor Upgraded to v3**: The underlying rich text editor has been updated for future-proofing, though some supporting libraries remain on v2 for compatibility. For now, please install dependencies using 'npm install --force' to avoid installation errors.
- 🚫 **Removed Redundant or Unused Strings and Elements**: Miscellaneous unused, duplicate, or obsolete code and translations have been cleaned up to maintain a streamlined and high-performance experience.
## [0.6.16] - 2025-07-14
### Added
- 🗂️ **Folders as Projects**: Organize your workflow with folder-based projects—set folder-level system prompts and associate custom knowledge, bringing seamless, context-rich management to teams and users handling multiple initiatives or clients.
- 📁 **Instant Folder-Based Chat Creation**: Start a new chat directly from any folder; just click and your new conversation is automatically embedded in the right project context—no more manual dragging or setup, saving time and eliminating mistakes.
- 🧩 **Prompt Variables with Automatic Input Modal**: Prompts containing variables now display a clean, auto-generated input modal that **autofocuses on the first field** for instant value entry—just select the prompt and fill in exactly what’s needed, reducing friction and guesswork.
- 🔡 **Variable Input Typing in Prompts**: Define input types for prompt variables (e.g., text, textarea, number, select, color, date, map and more), giving everyone a clearer and more precise prompt-building experience for advanced automation or workflows.
- 🚀 **Base Model List Caching**: Cache your base model list to speed up model selection and reduce repeated API calls; toggle this in Admin Settings > Connections for responsive model management even in large or multi-provider setups.
- ⏱️ **Configurable Model List Cache TTL**: Take control over model list caching with the new MODEL_LIST_CACHE_TTL environment variable. Set a custom cache duration in seconds to balance performance and freshness, reducing API requests in stable environments or ensuring rapid updates when models change frequently.
- 🔖 **Reference Notes as Knowledge or in Chats**: Use any note as knowledge for a model or folder, or reference it directly from chat—integrate living documentation into your Retrieval Augmented Generation workflows or discussions, bridging knowledge and action.
- 📝 **Chat Directly with Notes (Experimental)**: Ask questions about any note, and directly edit or update notes from within a chat—unlock direct AI-powered brainstorming, summarization, and cleanup, like having your own collaborative AI canvas.
- 🤝 **Collaborative Notes with Multi-User Editing**: Share notes with others and collaborate live—multiple users can edit a note in real-time, boosting cooperative knowledge building and workflow documentation.
- 🛡️ **Collaborative Note Permissions**: Control who can view or edit each note with robust sharing permissions, ensuring privacy or collaboration per your organizational needs.
- 🔗 **Copy Link to Notes**: Quickly copy and share direct links to notes for easier knowledge transfer within your team or external collaborators.
- 📋 **Task List Support in Notes**: Add, organize, and manage checklists or tasks inside your notes—plan projects, track to-dos, and keep everything actionable in a single space.
- 🧠 **AI-Generated Note Titles**: Instantly generate relevant and concise titles for your notes using AI—keep your knowledge library organized without tedious manual editing.
- 🔄 **Full Undo/Redo Support in Notes**: Effortlessly undo or redo your latest note changes—never fear mistakes or accidental edits while collaborating or writing.
- 📝 **Enhanced Note Word/Character Counter**: Always know the size of your notes with built-in counters, making it easier to adhere to length guidelines for shared or published content.
- 🖊️ **Floating & Bubble Formatting Menus in Note Editor**: Access text formatting tools through both a floating menu and an intuitive bubble menu directly in the note editor—making rich text editing faster, more discoverable, and easier than ever.
- ✍️ **Rich Text Prompt Insertion**: A new setting allows prompts to be inserted directly into the chat box as fully-formatted rich text, preserving Markdown elements like headings, lists, and bold text for a more intuitive and visually consistent editing experience.
- 🌐 **Configurable Database URL**: WebUI now supports more flexible database configuration via new environment variables—making deployment and scaling simpler across various infrastructure setups.
- 🎛️ **Completely Frontend-Handled File Upload in Temporary Chats**: When using temporary chats, file extraction now occurs fully in your browser with zero files sent to the backend, further strengthening privacy and giving you instant feedback.
- 🔄 **Enhanced Banner and Chat Command Visibility**: Banner handling and command feedback in chat are now clearer and more contextually visible, making alerts, suggestions, and automation easier to spot and interact with for all users.
- 📱 **Mobile Experience Polished**: The "new chat" button is back in mobile, plus core navigation and input controls have been smoothed out for better usability on phones and tablets.
- 📄 **OpenDocument Text (.odt) Support**: Seamlessly upload and process .odt files from open-source office suites like LibreOffice and OpenOffice, expanding your ability to build knowledge from a wider range of document formats.
- 📑 **Enhanced Markdown Document Splitting**: Improve knowledge retrieval from Markdown files with a new header-aware splitting strategy. This method intelligently chunks documents based on their header structure, preserving the original context and hierarchy for more accurate and relevant RAG results.
- 📚 **Full Context Mode for Knowledge Bases**: When adding a knowledge base to a folder or custom model, you can now toggle full context mode for the entire knowledge base. This bypasses the usual chunking and retrieval process, making it perfect for leaner knowledge bases.
- 🕰️ **Configurable OAuth Timeout**: Enhance login reliability by setting a custom timeout (OAUTH_TIMEOUT) for all OAuth providers (Google, Microsoft, GitHub, OIDC), preventing authentication failures on slow or restricted networks.
- 🎨 **Accessibility & High-Contrast Theme Enhancements**: Major accessibility overhaul with significant updates to the high-contrast theme. Improved focus visibility, ARIA labels, and semantic HTML ensure core components like the chat interface and model selector are fully compliant and readable for visually impaired users.
- ↕️ **Resizable System Prompt Fields**: Conveniently resize system prompt input fields to comfortably view and edit lengthy or complex instructions, improving the user experience for advanced model configuration.
- 🔧 **Granular Update Check Control**: Gain finer control over outbound connections with the new ENABLE_VERSION_UPDATE_CHECK flag. This allows administrators to disable version update checks independently of the full OFFLINE_MODE, perfect for environments with restricted internet access that still need to download embedding models.
- 🗃️ **Configurable Qdrant Collection Prefix**: Enhance scalability by setting a custom QDRANT_COLLECTION_PREFIX. This allows multiple Open WebUI instances to share a single Qdrant cluster safely, ensuring complete data isolation between separate deployments without conflicts.
- ⚙️ **Improved Default Database Performance**: Enhanced out-of-the-box performance by setting smarter database connection pooling defaults, reducing API response times for users on non-SQLite databases without requiring manual configuration.
- 🔧 **Configurable Redis Key Prefix**: Added support for the REDIS_KEY_PREFIX environment variable, allowing multiple Open WebUI instances to share a Redis cluster with isolated key namespaces for improved multi-tenancy.
- ➡️ **Forward User Context to Reranker**: For advanced RAG integrations, user information (ID, name, email, role) can now be forwarded as HTTP headers to external reranking services, enabling personalized results or per-user access control.
- ⚙️ **PGVector Connection Pooling**: Enhance performance and stability for PGVector-based RAG by enabling and configuring the database connection pool. New environment variables allow fine-tuning of pool size, timeout, and overflow settings to handle high-concurrency workloads efficiently.
- ⚙️ **General Backend Refactoring**: Extensive refactoring delivers a faster, more reliable, and robust backend experience—improving chat speed, model management, and day-to-day reliability.
- 🌍 **Expanded & Improved Translations**: Enjoy a more accessible and intuitive experience thanks to comprehensive updates and enhancements for Chinese (Simplified and Traditional), German, French, Catalan, Irish, and Spanish translations throughout the interface.
### Fixed
- 🛠️ **Rich Text Input Stability and Performance**: Multiple improvements ensure faster, cleaner text editing and rendering with reduced glitches—especially supporting links, color picking, checkbox controls, and code blocks in notes and chats.
- 📷 **Seamless iPhone Image Uploads**: Effortlessly upload photos from iPhones and other devices using HEIC format—images are now correctly recognized and processed, eliminating compatibility issues.
- 🔄 **Audio MIME Type Registration**: Issues with audio file content types have been resolved, guaranteeing smoother, error-free uploads and playback for transcription or note attachments.
- 🖍️ **Input Commands Now Always Visible**: Input commands (like prompts or knowledge) dynamically adjust their height on small screens, ensuring nothing is cut off and every tool remains easily accessible.
- 🛑 **Tool Result Rendering**: Fixed display problems with tool results, providing fast, clear feedback when using external or internal tools.
- 🗂️ **Table Alignment in Markdown**: Markdown tables are now rendered and aligned as expected, keeping reports and documentation readable.
- 🖼️ **Thread Image Handling**: Fixed an issue where messages containing only images in threads weren’t displayed correctly.
- 🗝️ **Note Access Control Security**: Tightened access control logic for notes to guarantee that shared or collaborative notes respect all user permissions and privacy safeguards.
- 🧾 **Ollama API Compatibility**: Fixed model parameter naming in the API to ensure uninterrupted compatibility for all Ollama endpoints.
- 🛠️ **Detection for 'text/html' Files**: Files loaded with docling/tika are now reliably detected as the correct type, improving knowledge ingestion and document parsing.
- 🔐 **OAuth Login Stability**: Resolved a critical OAuth bug that caused login failures on subsequent attempts after logging out. The user session is now completely cleared on logout, ensuring reliable and secure authentication across all supported providers (Google, Microsoft, GitHub, OIDC).
- 🚪 **OAuth Logout and Redirect Reliability**: The OAuth logout process has been made more robust. Logout requests now correctly use proxy environment variables, ensuring they succeed in corporate networks. Additionally, the custom WEBUI_AUTH_SIGNOUT_REDIRECT_URL is now properly respected for all OAuth/OIDC configurations, ensuring a seamless sign-out experience.
- 📜 **Banner Newline Rendering**: Banners now correctly render newline characters, ensuring that multi-line announcements and messages are displayed with their intended formatting.
- ℹ️ **Consistent Model Description Rendering**: Model descriptions now render Markdown correctly in the main chat interface, matching the formatting seen in the model selection dropdown for a consistent user experience.
- 🔄 **Offline Mode Update Check Display**: Corrected a UI bug where the "Checking for Updates..." message would display indefinitely when the application was set to offline mode.
- 🛠️ **Tool Result Encoding**: Fixed a bug where tool calls returning non-ASCII characters would fail, ensuring robust handling of international text and special characters in tool outputs.
## [0.6.15] - 2025-06-16
### Added
- 🖼️ **Global Image Compression Option**: Effortlessly set image compression globally so all image uploads and outputs are optimized, speeding up load times and saving bandwidth—perfect for teams dealing with large files or limited network resources.
- 🎤 **Custom Speech-to-Text Content-Type for Transcription**: Define custom content types for audio transcription, ensuring compatibility with diverse audio sources and unlocking smoother, more accurate transcriptions in advanced setups.
- 🗂️ **LDAP Group Synchronization (Experimental)**: Automatically sync user groups from your LDAP directory directly into Open WebUI for seamless enterprise access management—simplifies identity integration and governance across your organization.
- 📈 **OpenTelemetry Metrics via OTLP Exporter (Experimental)**: Gain enterprise-grade analytics and monitor your AI usage in real time with experimental OpenTelemetry Metrics support—connect to any OTLP-compatible backend for instant insights into performance, load, and user interactions.
- 🕰️ **See User Message Timestamps on Hover (Chat Bubble UI)**: Effortlessly check when any user message was sent by hovering over it in Chat Bubble mode—no more switching screens or digging through logs for context.
- 🗂️ **Leaderboard Sorting Options**: Sort the leaderboard directly in the UI for a clearer, more actionable view of top performers, models, or tools—making analysis and recognition quick and easy for teams.
- 🏆 **Evaluation Details Modal in Feedbacks and Leaderboard**: Dive deeper with new modals that display detailed evaluation information when reviewing feedbacks and leaderboard rankings—accelerates learning, progress tracking, and quality improvement.
- 🔄 **Support for Multiple Pages in External Document Loaders**: Effortlessly extract and work with content spanning multiple pages in external documents, giving you complete flexibility for in-depth research and document workflows.
- 🌐 **New Accessibility Enhancements Across the Interface**: Benefit from significant accessibility improvements—tab navigation, ARIA roles/labels, better high-contrast text/modes, accessible modals, and more—making Open WebUI more usable and equitable for everyone, including those using assistive technologies.
- ⚡ **Performance & Stability Upgrades Across Frontend and Backend**: Enjoy a smoother, more reliable experience with numerous behind-the-scenes optimizations and refactoring on both frontend and backend—resulting in faster load times, fewer errors, and even greater stability throughout your workflows.
- 🌏 **Updated and Expanded Localizations**: Enjoy improved, up-to-date translations for Finnish, German (now with model pinning features), Korean, Russian, Simplified Chinese, Spanish, and more—making every interaction smoother, clearer, and more intuitive for international users.
### Fixed
- 🦾 **Ollama Error Messages More Descriptive**: Receive clearer, more actionable error messages when something goes wrong with Ollama models—making troubleshooting and user support faster and more effective.
- 🌐 **Bypass Webloader Now Works as Expected**: Resolved an issue where the "bypass webloader" feature failed to function correctly, ensuring web search bypasses operate smoothly and reliably for lighter, faster query results.
- 🔍 **Prevent Redundant Documents in Citation List**: The expanded citation list no longer shows duplicate documents, offering a cleaner, easier-to-digest reference experience when reviewing sources in knowledge and research workflows.
- 🛡️ **Trusted Header Email Matching is Now Case-Insensitive**: Fixed a critical authentication issue where email case sensitivity could cause secure headers to mismatch, ensuring robust, seamless login and session management in all environments.
- ⚙️ **Direct Tool Server Input Accepts Empty Strings**: You can now submit direct tool server commands without unexpected errors when passing empty-string values, improving integration and automation efficiency.
- 📄 **Citation Page Number for Page 1 is Now Displayed**: Corrected an oversight where references for page 1 documents were missing the page number; citations are now always accurate and fully visible.
- 📒 **Notes Access Restored**: Fixed an issue where some users could not access their notes—everyone can now view and manage their notes reliably, ensuring seamless documentation and workflow continuity.
- 🛑 **OAuth Callback Double-Slash Issue Resolved**: Fixed rare cases where an extra slash in OAuth callbacks caused failed logins or redirects, making third-party login integrations more reliable.
### Changed
- 🔑 **Dedicated Permission for System Prompts**: System prompt access is now controlled by its own specific permission instead of being grouped with general chat controls, empowering admins with finer-grained management over who can view or modify system prompts for enhanced security and workflow customization.
- 🛠️ **YouTube Transcript API and python-pptx Updated**: Enjoy better performance, reliability, and broader compatibility thanks to underlying library upgrades—less friction with media-rich and presentation workflows.
### Removed
- 🗑️ **Console Logging Disabled in Production**: All 'console.log' and 'console.debug' statements are now disabled in production, guaranteeing improved security and cleaner browser logs for end users by removing extraneous technical output.
## [0.6.14] - 2025-06-10
### Added
- 🤖 **Automatic "Follow Up" Suggestions**: Open WebUI now intelligently generates actionable "Follow Up" suggestions automatically with each message you send, helping you stay productive and inspired without interrupting your flow; you can always disable this in Settings if you prefer a distraction-free experience.
- 🧩 **OpenAI-Compatible Embeddings Endpoint**: Introducing a fully OpenAI-style '/api/embeddings' endpoint—now you can plug in OpenAI-style embeddings workflows with zero hassle, making integrations with external tools and platforms seamless and familiar.
- ↗️ **Model Pinning for Quick Access**: Pin your favorite or most-used models to the sidebar for instant selection—no more scrolling through long model lists; your go-to models are always visible and ready for fast access.
- 📌 **Selector Model Item Menu**: Each model in the selector now features a menu where you can easily pin/unpin to the sidebar and copy a direct link—simplifying collaboration and staying organized in even the busiest environments.
- 🛑 **Reliable Stop for Ongoing Chats in Multi-Replica Setups**: Stopping or cancelling an in-progress chat now works reliably even in clustered deployments—ensuring every user can interrupt AI output at any time, no matter your scale.
- 🧠 **'Think' Parameter for Ollama Models**: Leverage new 'think' parameter support for Ollama—giving you advanced control over AI reasoning process and further tuning model behavior for your unique use cases.
- 💬 **Picture Description Modes for Docling**: Customize how images are described/extracted by Docling Loader for smarter, more detailed, and workflow-tailored image understanding in your document pipelines.
- 🛠 **Settings Modal Deep Linking**: Every tab in Settings now has its own route—making direct navigation and sharing of precise settings faster and more intuitive.
- 🎤 **Audio HTML Component Token**: Easily embed and play audio directly in your chats, improving voice-based workflows and making audio content instantly accessible and manageable from any conversation.
- 🔑 **Support for Secret Key File**: Now you can specify 'WEBUI_SECRET_KEY_FILE' for more secure and flexible key management—ideal for advanced deployments and tighter security standards.
- 💡 **Clarity When Cloning Prompts**: Cloned workspace prompts are clearly labelled with "(Clone)" and IDs have "-clone", keeping your prompt library organized and preventing accidental overwrites.
- 📝 **Dedicated User Role Edit Modal**: Updating user roles now reliably opens a dedicated edit user modal instead of cycling through roles—making it safer and more clear to manage team permissions.
- 🏞️ **Better Handling & Storage of Interpreter-Generated Images**: Code interpreter-generated images are now centrally stored and reliably loaded from the database or cloud storage, ensuring your artifacts are always available.
- 🚀 **Pinecone & Vector Search Optimizations**: Applied latest best practices from Pinecone for smarter timeouts, intelligent retry control, improved connection pooling, faster DNS, and concurrent batch handling—giving you more reliable, faster document search and RAG performance without manual tweaks.
- ⚙️ **Ollama Advanced Parameters Unified**: 'keep_alive' and 'format' options are now integrated into the advanced params section—edit everything from the model editor for flexible model control.
- 🛠️ **CUDA 12.6 Docker Image Support**: Deploy to NVIDIA GPUs with capability 7.0 and below (e.g., V100, GTX1080) via new cuda126 image—broadening your hardware options for scalable AI workloads.
- 🔒 **Experimental Table-Level PGVector Data Encryption**: Activate pgcrypto encryption support for pgvector to secure your vector search table contents, giving organizations enhanced compliance and data protection—perfect for enterprise or regulated environments.
- 👁 **Accessibility Upgrades Across Interface**: Chat buttons and close controls are now labelled and structured for optimal accessibility support, ensuring smoother operation with assistive technologies.
- 🎨 **High-Contrast Mode Expansions**: High-contrast accessibility mode now also applies to menu items, tabs, and search input fields, offering a more readable experience for all users.
- 🛠️ **Tooltip & Translation Clarity**: Improved translation and tooltip clarity, especially over radio buttons, making the UI more understandable for all users.
- 🔠 **Global Localization & Translation Improvements**: Hefty upgrades to Traditional Chinese, Simplified Chinese, Hebrew, Russian, Irish, German, and Danish translation packs—making the platform feel native and intuitive for even more users worldwide.
- ⚡ **General Backend Stability & Security Enhancements**: Refined numerous backend routines to minimize memory use, improve performance, and streamline integration with external APIs—making the entire platform more robust and secure for daily work.
### Fixed
- 🏷 **Feedback Score Display Improved**: Addressed overflow and visibility issues with feedback scores for more readable and accessible evaluations.
- 🗂 **Admin Settings Model Edits Apply Immediately**: Changes made in the Model Editor within Admin Settings now take effect instantly, eliminating confusion during model management.
- 🔄 **Assigned Tools Update Instantly on New Chats**: Models assigned with specific tools now consistently update and are available in every new chat—making tool workflows more predictable and robust.
- 🛠 **Document Settings Saved Only on User Action**: Document settings now save only when you press the Save button, reducing accidental changes and ensuring greater control.
- 🔊 **Voice Recording on Older iOS Devices Restored**: Voice input is now fully functional on older iOS devices, keeping voice workflows accessible to all users.
- 🔒 **Trusted Email Header Session Security**: User sessions now strictly verify the trusted email header matches the logged-in user's email, ensuring secure authentication and preventing accidental session switching.
- 🔒 **Consistent User Signout on Email Mismatch**: When the trusted email in the header changes, you will now be properly signed out and redirected, safeguarding your session's integrity.
- 🛠 **General Error & Content Validation Improvements**: Smarter error handling means clearer messages and fewer unnecessary retries—making batch uploads, document handling, and knowledge indexing more resilient.
- 🕵️ **Better Feedback on Chat Title Edits**: Error messages now show clearly if problems occur while editing chat titles.
## [0.6.13] - 2025-05-30
### Added
- 🟦 **Azure OpenAI Embedding Support**: You can now select Azure OpenAI endpoints for text embeddings, unlocking seamless integration with enterprise-scale Azure AI for powerful RAG and knowledge workflows—no more workarounds, connect and scale effortlessly.
- 🧩 **Smarter Custom Parameter Handling**: Instantly enjoy more flexible model setup—any JSON pasted into custom parameter fields is now parsed automatically, so you can define rich, nested parameters without tedious manual adjustment. This streamlines advanced configuration for all models and accelerates experimentation.
- ⚙️ **General Backend Refactoring**: Significant backend improvements deliver a cleaner codebase for better maintainability, faster performance, and even greater platform reliability—making all your workflows run more smoothly.
- 🌏 **Localization Upgrades**: Experience highly improved user interface translations and clarity in Simplified, Traditional Chinese, Korean, and Finnish, offering a more natural, accurate, and accessible experience for global users.
### Fixed
- 🛡️ **Robust Message Handling on Chat Load**: Fixed an issue where chat pages could fail to load if a referenced message was missing or undefined; now, chats always load smoothly and missing IDs no longer disrupt your workflow.
- 📝 **Correct Prompt Access Control**: Ensured that the prompt access controls register properly, restoring reliable permissioning and safeguarding your prompt workflows.
- 🛠 **Open WebUI-Specific Params No Longer Sent to Models**: Fixed a bug that sent internal WebUI parameters to APIs, ensuring only intended model options are transmitted—restoring predictable, error-free model operation.
- 🧠 **Refined Memory Error Handling**: Enhanced stability during memory-related operations, so even uncommon memory errors are gracefully managed without disrupting your session—resulting in a more reliable, worry-free experience.
## [0.6.12] - 2025-05-29
### Added
- 🧩 **Custom Advanced Model Parameters**: You can now add your own tailor-made advanced parameters to any model, empowering you to fine-tune behavior and unlock greater flexibility beyond just the built-in options—accelerate your experimentation.
- 🪧 **Datalab Marker API Content Extraction Support**: Seamlessly extract content from files and documents using the Datalab Marker API directly in your workflows, enabling more robust structured data extraction for RAG and document processing with just a simple engine switch in the UI.
- ⚡ **Parallelized Base Model Fetching**: Experience noticeably faster startup and model refresh times—base model data now loads in parallel, drastically shortening delays in busy or large-scale deployments.
- 🧠 **Efficient Function Loading and Caching**: Functions are now only reloaded if their content changes, preventing unnecessary duplicate loads, saving bandwidth, and boosting performance.
- 🌍 **Localization & Translation Enhancements**: Improved and expanded Simplified, Traditional Chinese, and Russian translations, providing smoother, more accurate, and context-aware experiences for global users.
### Fixed
- 💬 **Stable Message Input Box**: Fixed an issue where the message input box would shift unexpectedly (especially on mobile or with screen reader support), ensuring a smooth and reliable typing experience for every user.
- 🔊 **Reliable Read Aloud (Text-to-Speech)**: Read aloud now works seamlessly across messages, so users depending on TTS for accessibility or multitasking will experience uninterrupted and clear voice playback.
- 🖼 **Image Preview and Download Restored**: Fixed problems with image preview and downloads, ensuring frictionless creation, previewing, and downloading of images in your chats—no more interruptions in creative or documentation workflows.
- 📱 **Improved Mobile Styling for Workspace Capabilities**: Capabilities management is now readable and easy-to-use even on mobile devices, empowering admins and users to manage access quickly on the go.
- 🔁 **/api/v1/retrieval/query/collection Endpoint Reliability**: Queries to retrieval collections now return the expected results, bolstering the reliability of your knowledge workflows and citation-ready responses.
### Removed
- 🧹 **Duplicate CSS Elements**: Streamlined the UI by removing redundant CSS, reducing clutter and improving load times for a smoother visual experience.
## [0.6.11] - 2025-05-27
### Added
- 🟢 **Ollama Model Status Indicator in Model Selector**: Instantly see which Ollama models are currently loaded with a clear indicator in the model selector, helping you stay organized and optimize local model usage.
- 🗑️ **Unload Ollama Model Directly from Model Selector**: Easily release memory and resources by unloading any loaded Ollama model right in the model selector—streamline hardware management without switching pages.
- 🗣️ **User-Configurable Speech-to-Text Language Setting**: Improve transcription accuracy by letting individual users explicitly set their preferred STT language in their settings—ideal for multilingual teams and clear audio capture.
- ⚡ **Granular Audio Playback Speed Control**: Instead of just presets, you can now choose granular audio speed using a numeric input, giving you complete control over playback pace in transcriptions and media reviews.
- 📦 **GZip, Brotli, ZStd Compression Middleware**: Enjoy significantly faster page loads and reduced bandwidth usage with new server-side compression—giving users a snappier, more efficient experience.
- 🏷️ **Configurable Weight for BM25 in Hybrid Search**: Fine-tune search relevance by adjusting the weight for BM25 inside hybrid search from the UI, letting you tailor knowledge search results to your workflow.
- 🧪 **Bypass File Creation with CTRL + SHIFT + V**: When “Paste Large Text as File” is enabled, use CTRL + SHIFT + V to skip the file creation dialog and instantly upload text as a file—perfect for rapid document prep.
- 🌐 **Bypass Web Loader in Web Search**: Choose to bypass web content loading and use snippets directly in web search for faster, more reliable results when page loads are slow or blocked.
- 🚀 **Environment Variable: WEBUI_AUTH_TRUSTED_GROUPS_HEADER**: Now sync and manage user groups directly via trusted HTTP header, unlocking smoother single sign-on and identity integrations for organizations.
- 🏢 **Workspace Models Visibility Controls**: You can now hide workspace-level models from both the model selector and shared environments—keep your team focused and reduce clutter from rarely-used endpoints.
- 🛡️ **Copy Model Link**: You can now copy a direct link to any model—including those hidden from the selector—making sharing and onboarding others more seamless.
- 🔗 **Load Function Directly from URL**: Simplify custom function management—just paste any GitHub function URL into Open WebUI and import new functions in seconds.
- ⚙️ **Custom Name/Description for External Tool Servers**: Personalize and clarify external tool servers by assigning custom names and descriptions, making it easier to manage integrations in large-scale workspaces.
- 🌍 **Custom OpenAPI JSON URL Support for Tool Servers**: Supports specifying any custom OpenAPI JSON URL, unlocking more flexible integration with any backend for tool calls.
- 📊 **Source Field Now Displays in Non-Streaming Responses with Attachments**: When files or knowledge are attached, the "source" field now appears for all responses, even in non-streaming mode—enabling improved citation workflow.
- 🎛 **Pinned Chats**: Reduced payload size on pinned chat requests—leading to faster load times and less data usage, especially on busy warehouses.
- 🛠 **Import/Export Default Prompt Suggestions**: Enjoy one-click import/export of prompt suggestions, making it much easier to share, reuse, and manage best practices across teams or deployments.
- 🍰 **Banners Now Sortable from Admin Settings**: Quickly re-order or prioritize banners, letting you highlight the most critical info for your team.
- 🛠 **Advanced Chat Parameters—Clearer Ollama Support Labels**: Parameters and advanced settings now explicitly indicate if they are Ollama-specific, reducing confusion and improving setup accuracy.
- 🤏 **Scroll Bar Thumb Improved for Better Visibility**: Enhanced scrollbar styling makes navigation more accessible and visually intuitive.
- 🗄️ **Modal Redesign for Archived and User Chat Listings**: Clean, modern modal interface for browsing archived and user-specific chats makes locating conversations faster and more pleasant.
- 📝 **Add/Edit Memory Modal UX**: Memory modals are now larger and have resizable input fields, supporting easier editing of long or complex memory content.
- 🏆 **Translation & Localization Enhancements**: Major upgrades to Chinese (Simplified & Traditional), Korean, Russian, German, Danish, Finnish—not just fixing typos, but consistency, tone, and terminology for a more natural native-language experience.
- ⚡ **General Backend Stability & Security Enhancements**: Various backend refinements ensure a more resilient, reliable, and secure platform for smoother operation and peace of mind.
### Fixed
- 🖼️ **Image Generation with Allowed File Extensions Now Works Reliably**: Ensure seamless image generation even when strict file extension rules are set—no more blocked creative workflows due to technical hiccups.
- 🗂 **Remove Leading Dot for File Extension Check**: Fixed an issue where file validation failed because of a leading dot, making file uploads and knowledge management more robust.
- 🏷️ **Correct Local/External Model Classification**: The platform now accurately distinguishes between local and external models—preventing local models from showing up as external (and vice versa)—ensuring seamless setup, clarity, and management of your AI model endpoints.
- 📄 **External Document Loader Now Functions as Intended**: External document loaders are reliably invoked, ensuring smoother knowledge ingestion from external sources—expanding your RAG and knowledge workflows.
- 🎯 **Correct Handling of Toggle Filters**: Toggle filters are now robustly managed, preventing accidental auto-activation and ensuring user preferences are always respected.
- 🗃 **S3 Tagging Character Restrictions Fixed**: Tags for files in S3 now automatically meet Amazon’s allowed character set, avoiding upload errors and ensuring cross-cloud compatibility.
- 🛡️ **Authentication Now Uses Password Hash When Duplicate Emails Exist**: Ensures account security and prevents access issues if duplicate emails are present in your system.
### Changed
- 🧩 **Admin Settings: OAuth Redirects Now Use WEBUI_URL**: The OAuth redirect URL is now based on the explicitly set WEBUI_URL, ensuring single sign-on and identity provider integrations always send users to the correct frontend.
### Removed
- 💡 **Duplicate/Typo Component Removals**: Obsolete components have been cleaned up, reducing confusion and improving overall code quality for the team.
- 🚫 **Streaming Upsert in Pinecone Removed**: Removed streaming upsert references for better compatibility and future-proofing with latest Pinecone SDK updates.
## [0.6.10] - 2025-05-19
### Added
- 🧩 **Experimental Azure OpenAI Support**: Instantly connect to Azure OpenAI endpoints by simply pasting your Azure OpenAI URL into the model connections—bringing flexible, enterprise-grade AI integration directly to your workflow.
- 💧 **Watermark AI Responses**: Easily add a visible watermark to AI-generated responses for clear content provenance and compliance with EU AI regulations—perfect for regulated environments and transparent communication.
- 🔍 **Enhanced Search Experience with Dedicated Modal**: Enjoy a modern, powerful search UI in a dedicated modal (open with Ctrl/Cmd + K) accessible from anywhere—quickly find chats, models, or content and boost your productivity.
- 🔲 **"Toggle" Filter Type for Chat Input**: Add interactive toggle filters (e.g. Web Search, Image, Code Interpreter) right into the chat input—giving you one-click control to activate features and simplifying the chat configuration process.
- 🧰 **Granular Model Capabilities Editor**: Define detailed capabilities and feature access for each AI model directly from the model editor—enabling tailored behavior, modular control, and a more customized AI environment for every team or use case.
- 🌐 **Flexible Local and External Connection Support**: Now you can designate any AI connection—whether OpenAI, Ollama, or others—as local or external, enabling seamless setup for on-premise, self-hosted, or cloud configurations and giving you maximum control and flexibility.
- 🗂️ **Allowed File Extensions for RAG**: Gain full control over your Retrieval-Augmented Generation (RAG) workflows by specifying exactly which file extensions are permitted for upload, improving security and relevance of indexed documents.
- 🔊 **Enhanced Audio Transcription Logic**: Experience smoother, more reliable audio transcription—very long audio files are now automatically split and processed in segments, preventing errors and ensuring even challenging files are transcribed seamlessly, all part of a broader stability upgrade for robust media workflows.
- 🦾 **External Document Loader Support**: Enhance knowledge base building by integrating documents using external loaders from a wide range of data sources, expanding what your AI can read and process.
- 📝 **Preview Button for Code Artifacts**: Instantly jump from an HTML code block to its associated artifacts page with the click of a new preview button—speeding up review and streamlining analysis.
- 🦻 **Screen Reader Support for Response Messages**: All chat responses are now fully compatible with screen readers, making the platform more inclusive and accessible for everyone.
- 🧑‍💼 **Customizable Pending User Overlay**: You can now tailor the overlay title and content shown to pending users, ensuring onboarding messaging is perfectly aligned with your organization’s tone and requirements.
- 🔐 **Option to Disable LDAP Certificate Validation**: You can now disable LDAP certificate validation for maximum flexibility in diverse IT environments—making integrations and troubleshooting much easier.
- 🎯 **Workspace Search by Username or Email**: Easily search across workspace pages using any username or email address, streamlining user and resource management.
- 🎨 **High Contrast & Dark Mode Enhancements**: Further improved placeholder, input, suggestion, toast, and model selector contrasts—including a dedicated placeholder dark mode—for more comfortable viewing in all lighting conditions.
- 🛡️ **Refined Security for Pipelines & Model Uploads**: Strengthened safeguards against path traversal vulnerabilities during uploads—ensuring your platform’s document and model management remains secure.
- 🌏 **Major Localization Upgrades**: Comprehensive translation updates and improvements across Korean, Bulgarian, Catalan, Japanese, Italian, Traditional Chinese, and Spanish—including more accurate AI terminology for clarity; your experience is now more natural, inclusive, and professional everywhere.
- 🦾 **General Backend Stability & Security**: Multiple backend improvements (including file upload, command navigation, and logging refactorings) deliver increased resilience, better error handling, and a more robust platform for all users.
### Fixed
- ✅ **Evaluation Feedback Endpoint Reliability**: Addressed issues with feedback submission endpoints to ensure seamless user feedback collection on model responses.
- 🫰 **Model List State Fixes**: Resolved issues where model status toggles in the workspace page might inadvertently switch or confuse state, making the management of active/inactive models more dependable.
- ✍️ **Admin Signup Logic**: Admin self-signup experience and validation flow is smoother and more robust.
- 🔁 **Signout Redirect Flow Improved**: Logging out now redirects more reliably, reducing confusion and making session management seamless.
## [0.6.9] - 2025-05-10
### Added
- 📝 **Edit Attached Images/Files in Messages**: You can now easily edit your sent messages by removing attached files—streamlining document management, correcting mistakes on the fly, and keeping your chats clutter-free.
- 🚨 **Clear Alerts for Private Task Models**: When interacting with private task models, the UI now clearly alerts you—making it easier to understand resource availability and access, reducing confusion during workflow setup.
### Fixed
- 🛡️ **Confirm Dialog Focus Trap Reliability**: The focus now stays correctly within confirmation dialogs, ensuring keyboard navigation and accessibility is seamless and preventing accidental operations—especially helpful during critical or rapid workflows.
- 💬 **Temporary Chat Admin Controls & Session Cleanliness**: Admins are now able to properly enable temporary chat mode without errors, and previous session prompts or tool selections no longer carry over—delivering a fresh, predictable, and consistent temporary chat experience every time.
- 🤖 **External Reranker Integration Functionality Restored**: External reranker integrations now work correctly, allowing you to fully leverage advanced ranking services for sharper, more relevant search results in your RAG and knowledge base workflows.
## [0.6.8] - 2025-05-10
### Added
- 🏆 **External Reranker Support for Knowledge Base Search**: Supercharge your Retrieval-Augmented Generation (RAG) workflows with the new External Reranker integration; easily plug in advanced reranking services via the UI to deliver sharper and more relevant search results, accelerating research and insight discovery.
- 📤 **Unstylized PDF Export Option (Reduced File Size)**: When exporting chat transcripts or documents, you can now choose an unstylized PDF export for snappier downloads, minimal file size, and clean data archiving—perfect for large-scale storage or sharing.
- 📝 **Vazirmatn Font for Persian & Arabic**: Arabic and Persian users will now see their text beautifully rendered with the specialized Vazirmatn font for an improved localized reading experience.
- 🏷️ **SharePoint Tenant ID Support for OneDrive**: You can now specify a SharePoint tenant ID in OneDrive settings for seamless authentication and granular enterprise integration.
- 👤 **Refresh OAuth Profile Picture**: Your OAuth profile picture now updates in real-time, ensuring your presence and avatar always match your latest identity across integrated platforms.
- 🔧 **Milvus Configuration Improvements**: Configure index and metric types for Milvus directly within settings; take full control of your vector database for more accurate and robust AI search experiences.
- 🛡️ **S3 Tagging Toggle for Compatibility**: Optional S3 tagging via an environment toggle grants full compatibility with all storage backends—including those that don’t support tagging like Cloudflare R2—ensuring error-free attachment and document management.
- 👨‍🦯 **Icon Button Accessibility Improvements**: Key interactive icon-buttons now include aria-labels and ARIA descriptions, so screen readers provide precise guidance about what action each button performs for improved accessibility.
- ♿ **Enhanced Accessibility with Modal Focus Trap**: Modal dialogs and pop-ups now feature a focus trap and improved ARIA roles, ensuring seamless navigation and screen reader support—making the interface friendlier for everyone, including keyboard and assistive tech users.
- 🏃 **Improved Admin User List Loading Indicator**: The user list loading experience is now clearer and more responsive in the admin panel.
- 🧑‍🤝‍🧑 **Larger Admin User List Page Size**: Admins can now manage up to 30 users per page in the admin interface, drastically reducing pagination and making large user teams easier and faster to manage.
- 🌠 **Default Code Interpreter Prompt Clarified**: The built-in code interpreter prompt is now more explicit, preventing AI from wrapping code in Markdown blocks when not needed—ensuring properly formatted code runs as intended every time.
- 🧾 **Improved Default Title Generation Prompt Template**: Title generation now uses a robust template for reliable JSON output, improving chat organization and searchability.
- 🔗 **Support Jupyter Notebooks with Non-Root Base URLs**: Notebook-based code execution now supports non-root deployed Jupyter servers, granting full flexibility for hybrid or multi-user setups.
- 📰 **UI Scrollbar Always Visible for Overflow Tools**: When available tools overflow the display, the scrollbar is now always visible and there’s a handy "show all" toggle, making navigation of large toolsets snappier and more intuitive.
- 🛠️ **General Backend Refactoring for Stability**: Multiple under-the-hood improvements have been made across backend components, ensuring smoother performance, fewer errors, and a more reliable overall experience for all users.
- 🚀 **Optimized Web Search for Faster Results**: Web search speed and performance have been significantly enhanced, delivering answers and sources in record time to accelerate your research-heavy workflows.
- 💡 **More Supported Languages**: Expanded language support ensures an even wider range of users can enjoy an intuitive and natural interface in their native tongue.
### Fixed
- 🏃‍♂️ **Exhausting Workers in Nginx Reverse Proxy Due to Websocket Fix**: Websocket sessions are now fully compatible behind Nginx, eliminating worker exhaustion and restoring 24/7 reliability for real-time chats even in complex deployments.
- 🎤 **Audio Transcription Issue with OpenAI Resolved**: OpenAI-based audio transcription now handles WebM and newer formats without error, ensuring seamless voice-to-text workflows every time.
- 👉 **Message Input RTL Issue Fixed**: The chat message input now displays correctly for right-to-left languages, creating a flawless typing and reading experience for Arabic, Hebrew, and more.
- 🀄 **Katex: Proper Rendering of Chinese Characters Next to Math**: Math formulas now render perfectly even when directly adjacent to Chinese (CJK) characters, improving visual clarity for multilingual teams and cross-language documents.
- 🔂 **Duplicate Web Search URLs Eliminated**: Search results now reliably filter out URL duplicates, so your knowledge and search citations are always clean, trimmed, and easy to review.
- 📄 **Markdown Rendering Fixed in Knowledge Bases**: Markdown is now displayed correctly within knowledge bases, enabling better formatting and clarity of information-rich files.
- 🗂️ **LDAP Import/Loading Issue Resolved**: LDAP user imports process correctly, ensuring smooth onboarding and access without interruption.
- 🌎 **Pinecone Batch Operations and Async Safety**: All Pinecone operations (batch insert, upsert, delete) now run efficiently and safely in an async environment, boosting performance and preventing slowdowns in large-scale RAG jobs.
## [0.6.7] - 2025-05-07
### Added
- 🌐 **Custom Azure TTS API URL Support Added**: You can now define a custom Azure Text-to-Speech endpoint—enabling flexibility for enterprise deployments and regional compliance.
- ⚙️ **TOOL_SERVER_CONNECTIONS Environment Variable Suppor**: Easily configure and deploy tool servers via environment variables, streamlining setup and enabling faster enterprise provisioning.
- 👥 **Enhanced OAuth Group Handling as String or List**: OAuth group data can now be passed as either a list or a comma-separated string, improving compatibility with varied identity provider formats and reducing onboarding friction.
### Fixed
- 🧠 **Embedding with Ollama Proxy Endpoints Restored**: Fixed an issue where missing API config broke embedding for proxied Ollama models—ensuring consistent performance and compatibility.
- 🔐 **OIDC OAuth Login Issue Resolved**: Users can once again sign in seamlessly using OpenID Connect-based OAuth, eliminating login interruptions and improving reliability.
- 📝 **Notes Feature Access Fixed for Non-Admins**: Fixed an issue preventing non-admin users from accessing the Notes feature, restoring full cross-role collaboration capabilities.
- 🖼️ **Tika Loader Image Extraction Problem Resolved**: Ensured TikaLoader now processes 'extract_images' parameter correctly, restoring complete file extraction functionality in document workflows.
- 🎨 **Automatic1111 Image Model Setting Applied Properly**: Fixed an issue where switching to a specific image model via the UI wasn’t reflected in generation, re-enabling full visual creativity control.
- 🏷️ **Multiple XML Tags in Messages Now Parsed Correctly**: Fixed parsing issues when messages included multiple XML-style tags, ensuring clean and unbroken rendering of rich content in chats.
- 🖌️ **OpenAI Image Generation Issues Resolved**: Resolved broken image output when using OpenAI’s image generation, ensuring fully functional visual creation workflows.
- 🔎 **Tool Server Settings UI Privacy Restored**: Prevented restricted users from accessing tool server settings via search—restoring tight permissions control and safeguarding sensitive configurations.
- 🎧 **WebM Audio Transcription Now Supported**: Fixed an issue where WebM files failed during audio transcription—these formats are now fully supported, ensuring smoother voice note workflows and broader file compatibility.
## [0.6.6] - 2025-05-05
### Added
- 📝 **AI-Enhanced Notes (With Audio Transcription)**: Effortlessly create notes, attach meeting or voice audio, and let the AI instantly enhance, summarize, or refine your notes using audio transcriptions—making your documentation smarter, cleaner, and more insightful with minimal effort.
- 🔊 **Meeting Audio Recording & Import**: Seamlessly record audio from your meetings or capture screen audio and attach it to your notes—making it easier to revisit, annotate, and extract insights from important discussions.
- 📁 **Import Markdown Notes Effortlessly**: Bring your existing knowledge library into Open WebUI by importing your Markdown notes, so you can leverage all advanced note management and AI features right away.
- 👥 **Notes Permissions by User Group**: Fine-tune access and editing rights for notes based on user roles or groups, so you can delegate writing or restrict sensitive information as needed.
- ☁️ **OneDrive & SharePoint Integration**: Keep your content in sync by connecting notes and files directly with OneDrive or SharePoint—unlocking fast enterprise import/export and seamless collaboration with your existing workflows.
- 🗂️ **Paginated User List in Admin Panel**: Effortlessly manage and search through large teams via the new paginated user list—saving time and streamlining user administration in big organizations.
- 🕹️ **Granular Chat Share & Export Permissions**: Enjoy enhanced control over who can share or export chats, enabling tighter governance and privacy in team and enterprise settings.
- 🛑 **User Role Change Confirmation Dialog**: Reduce accidental privilege changes with a required confirmation step before updating user roles—improving security and preventing costly mistakes in team management.
- 🚨 **Audit Log for Failed Login Attempts**: Quickly detect unauthorized access attempts or troubleshoot user login problems with detailed logs of failed authentication right in the audit trail.
- 💡 **Dedicated 'Generate Title' Button for Chats**: Swiftly organize every conversation—tap the new button to let AI create relevant, clear titles for all your chats, saving time and reducing clutter.
- 💬 **Notification Sound Always-On Option**: Take control of your notifications by setting sound alerts to always play—helping you stay on top of important updates in busy environments.
- 🆔 **S3 File Tagging Support**: Uploaded files to S3 now include tags for better organization, searching, and integration with your file management policies.
- 🛡️ **OAuth Blocked Groups Support**: Gain more control over group-based access by explicitly blocking specified OAuth groups—ideal for complex identity or security requirements.
- 🚀 **Optimized Faster Web Search & Multi-Threaded Queries**: Enjoy dramatically faster web search and RAG (retrieval augmented generation) with revamped multi-threaded search—get richer, more accurate results in less time.
- 🔍 **All-Knowledge Parallel Search**: Searches across your entire knowledge base now happen in parallel even in non-hybrid mode, speeding up responses and improving knowledge accuracy for every question.
- 🌐 **New Firecrawl & Yacy Web Search Integrations**: Expand your world of information with two new advanced search engines—Firecrawl for deeper web insight and Yacy for decentralized, privacy-friendly search capabilities.
- 🧠 **Configurable Docling OCR Engine & Language**: Use environment variables to fine-tune Docling OCR engine and supported languages for smarter, more tailored document extraction and RAG workflows.
- 🗝️ **Enhanced Sentence Transformers Configuration**: Added new environment variables for easier set up and advanced customization of Sentence Transformers—ensuring best fit for your embedding needs.
- 🌲 **Pinecone Vector Database Integration**: Index, search, and manage knowledge at enterprise scale with full native support for Pinecone as your vector database—effortlessly handle even the biggest document sets.
- 🔄 **Automatic Requirements Installation for Tools & Functions**: Never worry about lost dependencies on restart—external function and tool requirements are now auto-installed at boot, ensuring tools always “just work.”
- 🔒 **Automatic Sign-Out on Token Expiry**: Security is smarter—users are now automatically logged out if their authentication token expires, protecting sensitive content and ensuring compliance without disruption.
- 🎬 **Automatic YouTube Embed Detection**: Paste YouTube links and see instant in-chat video embeds—no more manual embedding, making knowledge sharing and media consumption even easier for every team.
- 🔄 **Expanded Language & Locale Support**: Translations for Danish, French, Russian, Traditional Chinese, Simplified Chinese, Thai, Catalan, German, and Korean have been upgraded, offering smoother, more natural user experiences across the platform.
### Fixed
- 🔒 **Tighter HTML Token Security**: HTML rendering is now restricted to admin-uploaded tokens only, reducing any risk of XSS and keeping your data safe.
- 🔐 **Refined HTML Security and Token Handling**: Further hardened how HTML tokens and content are handled, guaranteeing even stronger resistance to security vulnerabilities and attacks.
- 🔏 **Correct Model Usage with Ollama Proxy Prefixes**: Enhanced model reference handling so proxied models in Ollama always download and run correctly—even when using custom prefixes.
- 📥 **Video File Upload Handling**: Prevented video files from being misclassified as text, fixing bugs with uploads and ensuring media files work as expected.
- 🔄 **No More Dependent WebSocket Sequential Delays**: Streamlined WebSocket operation to prevent delays and maintain snappy real-time collaboration, especially in multi-user environments.
- 🛠️ **More Robust Action Module Execution**: Multiple actions in a module now trigger as designed, increasing automation and scripting flexibility.
- 📧 **Notification Webhooks**: Ensured that notification webhooks are always sent for user events, even when the user isn’t currently active.
- 🗂️ **Smarter Knowledge Base Reindexing**: Knowledge reindexing continues even when corrupt or missing collections are encountered, keeping your search features running reliably.
- 🏷️ **User Import with Profile Images**: When importing users, their profile images now come along—making onboarding and collaboration visually clearer from day one.
- 💬 **OpenAI o-Series Universal Support**: All OpenAI o-series models are now seamlessly recognized and supported, unlocking more advanced capabilities and model choices for every workflow.
### Changed
- 📜 **Custom License Update & Contributor Agreement**: Open WebUI now operates under a custom license with Contributor License Agreement required by default—see https://docs.openwebui.com/license/ for details, ensuring sustainable open innovation for the community.
- 🔨 **CUDA Docker Images Updated to 12.8**: Upgraded CUDA image support for faster, more compatible model inference and futureproof GPU performance in your AI infrastructure.
- 🧱 **General Backend Refactoring for Reliability**: Continuous stability improvements streamline backend logic, reduce errors, and lay a stronger foundation for the next wave of feature releases—all under the hood for a more dependable WebUI.
## [0.6.5] - 2025-04-14
### Added
- 🛂 **Granular Voice Feature Permissions Per User Group**: Admins can now separately manage access to Speech-to-Text (record voice), Text-to-Speech (read aloud), and Tool Calls for each user group—giving teams tighter control over voice features and enhanced governance across roles.
- 🗣️ **Toggle Voice Activity Detection (VAD) for Whisper STT**: New environment variable lets you enable/disable VAD filtering with built-in Whisper speech-to-text, giving you flexibility to optimize for different audio quality and response accuracy levels.
- 📋 **Copy Formatted Response Mode**: You can now enable “Copy Formatted” in Settings > Interface to copy AI responses exactly as styled (with rich formatting, links, and structure preserved), making it faster and cleaner to paste into documents, emails, or reports.
- ⚙️ **Backend Stability and Performance Enhancements**: General backend refactoring improves system resilience, consistency, and overall reliability—offering smoother performance across workflows whether chatting, generating media, or using external tools.
- 🌎 **Translation Refinements Across Multiple Languages**: Updated translations deliver smoother language localization, clearer labels, and improved international usability throughout the UI—ensuring a better experience for non-English speakers.
### Fixed
- 🛠️ **LDAP Login Reliability Restored**: Resolved a critical issue where some LDAP setups failed due to attribute parsing—ensuring consistent, secure, and seamless user authentication across enterprise deployments.
- 🖼️ **Image Generation in Temporary Chats Now Works Properly**: Fixed a bug where image outputs weren’t generated during temporary chats—visual content can now be used reliably in all chat modes without interruptions.
## [0.6.4] - 2025-04-12
### Fixed
- 🛠️ **RAG_TEMPLATE Display Issue Resolved**: Fixed a formatting problem where the custom RAG_TEMPLATE wasn't correctly rendered in the interface—ensuring that custom retrieval prompts now appear exactly as intended for more reliable prompt engineering.
## [0.6.3] - 2025-04-12
### Added
- 🧪 **Auto-Artifact Detection Toggle**: Automatically detects artifacts in results—but now you can disable this behavior under advanced settings for full control.
- 🖼️ **Widescreen Mode for Shared Chats**: Shared link conversations now support widescreen layouts—perfect for presentations or easier review across wider displays.
- 🔁 **Reindex Knowledge Files on Demand**: Admins can now trigger reindexing of all knowledge files after changing embeddings—ensuring immediate alignment with new models for optimal RAG performance.
- 📄 **OpenAPI YAML Format Support**: External tools can now use YAML-format OpenAPI specs—making integration simpler for developers familiar with YAML-based configurations.
- 💬 **Message Content Copy Behavior**: Copy action now excludes 'details' tags—streamlining clipboard content when sharing or pasting summaries elsewhere.
- 🧭 **Sougou Web Search Integration**: New search engine option added—enhancing global relevance and diversity of search sources for multilingual users.
- 🧰 **Frontend Web Loader Engine Configuration**: Admins can now set preferred web loader engine for RAG workflows directly from the frontend—offering more control across setups.
- 👥 **Multi-Model Chat Permission Control**: Admins can manage access to multi-model chats per user group—allowing tighter governance in team environments.
- 🧱 **Persistent Configuration Can Be Disabled**: New environment variable lets advanced users and hosts turn off persistent configs—ideal for volatile or stateless deployments.
- 🧠 **Elixir Code Highlighting Support**: Elixir syntax is now beautifully rendered in code blocks—perfect for developers using this language in AI or automation projects.
- 🌐 **PWA External Manifest URL Support**: You can now define an external manifest.json—integrate Open WebUI seamlessly in managed or proxy-based PWA environments like Cloudflare Zero Trust.
- 🧪 **Azure AI Speech-to-Text Provider Integration**: Easily transcribe large audio files (up to 200MB) with high accuracy using Microsoft's Azure STT—fully configurable in Audio Settings.
- 🔏 **PKCE (Code Challenge Method) Support for OIDC**: Enhance your OIDC login security with Proof Key for Code Exchange—ideal for zero-trust and native client apps.
- ✨ **General UI/UX Enhancements**: Numerous refinements across layout, styling, and tool interactions—reducing visual noise and improving overall usability across key workflows.
- 🌍 **Translation Updates Across Multiple Languages**: Refined Catalan, Russian, Chinese (Simplified & Traditional), Hungarian, and Spanish translations for clearer navigation and instructions globally.
### Fixed
- 💥 **Chat Completion Error with Missing Models Resolved**: Fixed internal server error when referencing a model that doesn’t exist—ensuring graceful fallback and clear error guidance.
- 🔧 **Correct Knowledge Base Citations Restored**: Citations generated by RAG workflows now show accurate references—ensuring verifiability in outputs from sourced content.
- 🎙️ **Broken OGG/WebM Audio Upload Handling for OpenAI Fixed**: Uploading OGG or WebM files now converts properly to WAV before transcription—restoring accurate AI speech recognition workflows.
- 🔐 **Tool Server 'Session' Authentication Restored**: Previously broken session auth on external tool servers is now fully functional—ensuring secure and seamless access to connected tools.
- 🌐 **Folder-Based Chat Rename Now Updates Correctly**: Renaming chats in folders now reflects instantly everywhere—improving chat organization and clarity.
- 📜 **KaTeX Overflow Displays Fixed**: Math expressions now stay neatly within message bounds—preserving layout consistency even with long formulas.
- 🚫 **Stopping Ongoing Chat Fixed**: You can now return to an active (ongoing) chat and stop generation at any time—ensuring full control over sessions.
- 🔧 **TOOL_SERVERS / TOOL_SERVER_CONNECTIONS Indexing Issue Fixed**: Fixed a mismatch between tool lists and their access paths—restoring full function and preventing confusion in tool management.
- 🔐 **LDAP Login Handles Multiple Emails**: When LDAP returns multiple email attributes, the first valid one is now used—ensuring login success and account consistency.
- 🧩 **Model Visibility Toggle Fix**: Toggling model visibility now works even for untouched models—letting admins smoothly manage user access across base models.
- ⚙️ **Cross-Origin manifest.json Now Loads Properly**: Compatibility issues with Cloudflare Zero Trust (and others) resolved, allowing manifest.json to load behind authenticated proxies.
### Changed
- 🔒 **Default Access Scopes Set to Private for All Resources**: Models, tools, and knowledge are now private by default when created—ensuring better baseline security and visibility controls.
- 🧱 **General Backend Refactoring for Stability**: Numerous invisible improvements enhance backend scalability, security, and maintainability—powering upcoming features with a stronger foundation.
- 🧩 **Stable Dependency Upgrades**: Updated key platform libraries—Chromadb (0.6.3), pgvector (0.4.0), Azure Identity (1.21.0), and Youtube Transcript API (1.0.3)—for improved compatibility, functionality, and security.
## [0.6.2] - 2025-04-06
### Added
- 🌍 **Improved Global Language Support**: Expanded and refined translations across multiple languages to enhance clarity and consistency for international users.
### Fixed
- 🛠️ **Accurate Tool Descriptions from OpenAPI Servers**: External tools now use full endpoint descriptions instead of summaries when generating tool specifications—helping AI models understand tool purpose more precisely and choose the right tool more accurately in tool workflows.
- 🔧 **Precise Web Results Source Attribution**: Fixed a key issue where all web search results showed the same source ID—now each result gets its correct and distinct source, ensuring accurate citations and traceability.
- 🔍 **Clean Web Search Retrieval**: Web search now retains only results from URLs where real content was successfully fetched—improving accuracy and removing empty or broken links from citations.
- 🎵 **Audio File Upload Response Restored**: Resolved an issue where uploading audio files did not return valid responses, restoring smooth file handling for transcription and audio-based workflows.
### Changed
- 🧰 **General Backend Refactoring**: Multiple behind-the-scenes improvements streamline backend performance, reduce complexity, and ensure a more stable, maintainable system overall—making everything smoother without changing your workflow.
## [0.6.1] - 2025-04-05
### Added
- 🛠️ **Global Tool Servers Configuration**: Admins can now centrally configure global external tool servers from Admin Settings > Tools, allowing seamless sharing of tool integrations across all users without manual setup per user.
- 🔐 **Direct Tool Usage Permission for Users**: Introduced a new user-level permission toggle that grants non-admin users access to direct external tools, empowering broader team collaboration while maintaining control.
- 🧠 **Mistral OCR Content Extraction Support**: Added native support for Mistral OCR as a high-accuracy document loader, drastically improving text extraction from scanned documents in RAG workflows.
- 🖼️ **Tools Indicator UI Redesign**: Enhanced message input now smartly displays both built-in and external tools via a unified dropdown, making it simpler and more intuitive to activate tools during conversations.
- 📄 **RAG Prompt Improved and More Coherent**: Default RAG system prompt has been revised to be more clear and citation-focused—admins can leave the template field empty to use this new gold-standard prompt.
- 🧰 **Performance & Developer Improvements**: Major internal restructuring of several tool-related components, simplifying styling and merging external/internal handling logic, resulting in better maintainability and performance.
- 🌍 **Improved Translations**: Updated translations for Tibetan, Polish, Chinese (Simplified & Traditional), Arabic, Russian, Ukrainian, Dutch, Finnish, and French to improve clarity and consistency across the interface.
### Fixed
- 🔑 **External Tool Server API Key Bug Resolved**: Fixed a critical issue where authentication headers were not being sent when calling tools from external OpenAPI tool servers, ensuring full security and smooth tool operations.
- 🚫 **Conditional Export Button Visibility**: UI now gracefully hides export buttons when there's nothing to export in models, prompts, tools, or functions, improving visual clarity and reducing confusion.
- 🧪 **Hybrid Search Failure Recovery**: Resolved edge case in parallel hybrid search where empty or unindexed collections caused backend crashes—these are now cleanly skipped to ensure system stability.
- 📂 **Admin Folder Deletion Fix**: Addressed an issue where folders created in the admin workspace couldn't be deleted, restoring full organizational flexibility for admins.
- 🔐 **Improved Generic Error Feedback on Login**: Authentication errors now show simplified, non-revealing messages for privacy and improved UX, especially with federated logins.
- 📝 **Tool Message with Images Improved**: Enhanced how tool-generated messages with image outputs are shown in chat, making them more readable and consistent with the overall UI design.
- ⚙️ **Auto-Exclusion for Broken RAG Collections**: Auto-skips document collections that fail to fetch data or return "None", preventing silent errors and streamlining retrieval workflows.
- 📝 **Docling Text File Handling Fix**: Fixed file parsing inconsistency that broke docling-based RAG functionality for certain plain text files, ensuring wider file compatibility.
## [0.6.0] - 2025-03-31
### Added
- 🧩 **External Tool Server Support via OpenAPI**: Connect Open WebUI to any OpenAPI-compatible REST server instantly—offering immediate integration with thousands of developer tools, SDKs, and SaaS systems for powerful extensibility. Learn more: https://github.com/open-webui/openapi-servers
- 🛠️ **MCP Server Support via MCPO**: You can now convert and expose your internal MCP tools as interoperable OpenAPI HTTP servers within Open WebUI for seamless, plug-n-play AI toolchain creation. Learn more: https://github.com/open-webui/mcpo
- 📨 **/messages Chat API Endpoint Support**: For power users building external AI systems, new endpoints allow precise control of messages asynchronously—feed long-running external responses into Open WebUI chats without coupling with the frontend.
- 📝 **Client-Side PDF Generation**: PDF exports are now generated fully client-side for drastically improved output quality—perfect for saving conversations or documents.
- 💼 **Enforced Temporary Chats Mode**: Admins can now enforce temporary chat sessions by default to align with stringent data retention and compliance requirements.
- 🌍 **Public Resource Sharing Permission Controls**: Fine-grained user group permissions now allow enabling/disabling public sharing for models, knowledge, prompts, and tools—ideal for privacy, team control, and internal deployments.
- 📦 **Custom pip Options for Tools/Functions**: You can now specify custom pip installation options with "PIP_OPTIONS", "PIP_PACKAGE_INDEX_OPTIONS" environment variables—improving compatibility, support for private indexes, and better control over Python environments.
- 🔢 **Editable Message Counter**: You can now double-click the message count number and jump straight to editing the index—quickly navigate complex chats or regenerate specific messages precisely.
- 🧠 **Embedding Prefix Support Added**: Add custom prefixes to your embeddings for instruct-style tokens, enabling stronger model alignment and more consistent RAG performance.
- 🙈 **Ability to Hide Base Models**: Optionally hide base models from the UI, helping users streamline model visibility and limit access to only usable endpoints..
- 📚 **Docling Content Extraction Support**: Open WebUI now supports Docling as a content extraction engine, enabling smarter and more accurate parsing of complex file formats—ideal for advanced document understanding and Retrieval-Augmented Generation (RAG) workflows.
- 🗃️ **Redis Sentinel Support Added**: Enhance deployment redundancy with support for Redis Sentinel for highly available, failover-safe Redis-based caching or pub/sub.
- 📚 **JSON Schema Format for Ollama**: Added support for defining the format using JSON schema in Ollama-compatible models, improving flexibility and validation of model outputs.
- 🔍 **Chat Sidebar Search "Clear” Button**: Quickly clear search filters in chat sidebar using the new ✖️ button—streamline your chat navigation with one click.
- 🗂️ **Auto-Focus + Enter Submit for Folder Name**: When creating a new folder, the system automatically enters rename mode with name preselected—simplifying your org workflow.
- 🧱 **Markdown Alerts Rendering**: Blockquotes with syntax hinting (e.g. ⚠️, ℹ️, ✅) now render styled Markdown alert banners, making messages and documentation more visually structured.
- 🔁 **Hybrid Search Runs in Parallel Now**: Hybrid (BM25 + embedding) search components now run in parallel—dramatically reducing response times and speeding up document retrieval.
- 📋 **Cleaner UI for Tool Call Display**: Optimized the visual layout of called tools inside chat messages for better clarity and reduced visual clutter.
- 🧪 **Playwright Timeout Now Configurable**: Default timeout for Playwright processes is now shorter and adjustable via environment variables—making web scraping more robust and tunable to environments.
- 📈 **OpenTelemetry Support for Observability**: Open WebUI now integrates with OpenTelemetry, allowing you to connect with tools like Grafana, Jaeger, or Prometheus for detailed performance insights and real-time visibility—entirely opt-in and fully self-hosted. Even if enabled, no data is ever sent to us, ensuring your privacy and ownership over all telemetry data.
- 🛠 **General UI Enhancements & UX Polish**: Numerous refinements across sidebar, code blocks, modal interactions, button alignment, scrollbar visibility, and folder behavior improve overall fluidity and usability of the interface.
- 🧱 **General Backend Refactoring**: Numerous backend components have been refactored to improve stability, maintainability, and performance—ensuring a more consistent and reliable system across all features.
- 🌍 **Internationalization Language Support Updates**: Added Estonian and Galician languages, improved Spanish (fully revised), Traditional Chinese, Simplified Chinese, Turkish, Catalan, Ukrainian, and German for a more localized and inclusive interface.
### Fixed
- 🧑‍💻 **Firefox Input Height Bug**: Text input in Firefox now maintains proper height, ensuring message boxes look consistent and behave predictably.
- 🧾 **Tika Blank Line Bug**: PDFs processed with Apache Tika 3.1.0.0 no longer introduce excessive blank lines—improving RAG output quality and visual cleanliness.
- 🧪 **CSV Loader Encoding Issues**: CSV files with unknown encodings now automatically detect character sets, resolving import errors in non-UTF-8 datasets.
- ✅ **LDAP Auth Config Fix**: Path to certificate file is now optional for LDAP setups, fixing authentication trouble for users without preconfigured cert paths.
- 📥 **File Deletion in Bypass Mode**: Resolved issue where files couldn’t be deleted from knowledge when “bypass embedding” mode was enabled.
- 🧩 **Hybrid Search Result Sorting & Deduplication Fixed**: Fixed citation and sorting issues in RAG hybrid and reranker modes, ensuring retrieved documents are shown in correct order per score.
- 🧷 **Model Export/Import Broken for a Single Model**: Fixed bug where individual models couldn’t be exported or re-imported, restoring full portability.
- 📫 **Auth Redirect Fix**: Logged-in users are now routed properly without unnecessary login prompts when already authenticated.
### Changed
- 🧠 **Prompt Autocompletion Disabled By Default**: Autocomplete suggestions while typing are now disabled unless explicitly re-enabled in user preferences—reduces distractions while composing prompts for advanced users.
- 🧾 **Normalize Citation Numbering**: Source citations now properly begin from "1" instead of "0"—improving consistency and professional presentation in AI outputs.
- 📚 **Improved Error Handling from Pipelines**: Pipelines now show the actual returned error message from failed tasks rather than generic "Connection closed"—making debugging far more user-friendly.
### Removed
- 🧾 **ENABLE_AUDIT_LOGS Setting Removed**: Deprecated setting “ENABLE_AUDIT_LOGS” has been fully removed—now controlled via “AUDIT_LOG_LEVEL” instead.
## [0.5.20] - 2025-03-05
### Added
- **⚡ Toggle Code Execution On/Off**: You can now enable or disable code execution, providing more control over security, ensuring a safer and more customizable experience.
### Fixed
- **📜 Pinyin Keyboard Enter Key Now Works Properly**: Resolved an issue where the Enter key for Pinyin keyboards was not functioning as expected, ensuring seamless input for Chinese users.
- **🖼️ Web Manifest Loading Issue Fixed**: Addressed inconsistencies with 'site.webmanifest', guaranteeing proper loading and representation of the app across different browsers and devices.
- **📦 Non-Root Container Issue Resolved**: Fixed a critical issue where the UI failed to load correctly in non-root containers, ensuring reliable deployment in various environments.
## [0.5.19] - 2025-03-04
### Added
- **📊 Logit Bias Parameter Support**: Fine-tune conversation dynamics by adjusting the Logit Bias parameter directly in chat settings, giving you more control over model responses.
- **⌨️ Customizable Enter Behavior**: You can now configure Enter to send messages only when combined with Ctrl (Ctrl+Enter) via Settings > Interface, preventing accidental message sends.
- **📝 Collapsible Code Blocks**: Easily collapse long code blocks to declutter your chat, making it easier to focus on important details.
- **🏷️ Tag Selector in Model Selector**: Quickly find and categorize models with the new tag filtering system in the Model Selector, streamlining model discovery.
- **📈 Experimental Elasticsearch Vector DB Support**: Now supports Elasticsearch as a vector database, offering more flexibility for data retrieval in Retrieval-Augmented Generation (RAG) workflows.
- **⚙️ General Reliability Enhancements**: Various stability improvements across the WebUI, ensuring a smoother, more consistent experience.
- **🌍 Updated Translations**: Refined multilingual support for better localization and accuracy across various languages.
### Fixed
- **🔄 "Stream" Hook Activation**: Fixed an issue where the "Stream" hook only worked when globally enabled, ensuring reliable real-time filtering.
- **📧 LDAP Email Case Sensitivity**: Resolved an issue where LDAP login failed due to email case sensitivity mismatches, improving authentication reliability.
- **💬 WebSocket Chat Event Registration**: Fixed a bug preventing chat event listeners from being registered upon sign-in, ensuring real-time updates work properly.
## [0.5.18] - 2025-02-27
### Fixed
- **🌐 Open WebUI Now Works Over LAN in Insecure Context**: Resolved an issue preventing Open WebUI from functioning when accessed over a local network in an insecure context, ensuring seamless connectivity.
- **🔄 UI Now Reflects Deleted Connections Instantly**: Fixed an issue where deleting a connection did not update the UI in real time, ensuring accurate system state visibility.
- **🛠️ Models Now Display Correctly with ENABLE_FORWARD_USER_INFO_HEADERS**: Addressed a bug where models were not visible when ENABLE_FORWARD_USER_INFO_HEADERS was set, restoring proper model listing.
## [0.5.17] - 2025-02-27
### Added
- **🚀 Instant Document Upload with Bypass Embedding & Retrieval**: Admins can now enable "Bypass Embedding & Retrieval" in Admin Settings > Documents, significantly speeding up document uploads and ensuring full document context is retained without chunking.
- **🔎 "Stream" Hook for Real-Time Filtering**: The new "stream" hook allows dynamic real-time message filtering. Learn more in our documentation (https://docs.openwebui.com/features/plugin/functions/filter).
- **☁️ OneDrive Integration**: Early support for OneDrive storage integration has been introduced, expanding file import options.
- **📈 Enhanced Logging with Loguru**: Backend logging has been improved with Loguru, making debugging and issue tracking far more efficient.
- **⚙️ General Stability Enhancements**: Backend and frontend refactoring improves performance, ensuring a smoother and more reliable user experience.
- **🌍 Updated Translations**: Refined multilingual support for better localization and accuracy across various languages.
### Fixed
- **🔄 Reliable Model Imports from the Community Platform**: Resolved import failures, allowing seamless integration of community-shared models without errors.
- **📊 OpenAI Usage Statistics Restored**: Fixed an issue where OpenAI usage metrics were not displaying correctly, ensuring accurate tracking of usage data.
- **🗂️ Deduplication for Retrieved Documents**: Documents retrieved during searches are now intelligently deduplicated, meaning no more redundant results—helping to keep information concise and relevant.
### Changed
- **📝 "Full Context Mode" Renamed for Clarity**: The "Full Context Mode" toggle in Web Search settings is now labeled "Bypass Embedding & Retrieval" for consistency across the UI.
## [0.5.16] - 2025-02-20
### Fixed
- **🔍 Web Search Retrieval Restored**: Resolved a critical issue that broke web search retrieval by reverting deduplication changes, ensuring complete and accurate search results once again.
## [0.5.15] - 2025-02-20
### Added
- **📄 Full Context Mode for Local Document Search (RAG)**: Toggle full context mode from Admin Settings > Documents to inject entire document content into context, improving accuracy for models with large context windows—ideal for deep context understanding.
- **🌍 Smarter Web Search with Agentic Workflows**: Web searches now intelligently gather and refine multiple relevant terms, similar to RAG handling, delivering significantly better search results for more accurate information retrieval.
- **🔎 Experimental Playwright Support for Web Loader**: Web content retrieval is taken to the next level with Playwright-powered scraping for enhanced accuracy in extracted web data.
- **☁️ Experimental Azure Storage Provider**: Early-stage support for Azure Storage allows more cloud storage flexibility directly within Open WebUI.
- **📊 Improved Jupyter Code Execution with Plots**: Interactive coding now properly displays inline plots, making data visualization more seamless inside chat interactions.
- **⏳ Adjustable Execution Timeout for Jupyter Interpreter**: Customize execution timeout (default: 60s) for Jupyter-based code execution, allowing longer or more constrained execution based on your needs.
- **▶️ "Running..." Indicator for Jupyter Code Execution**: A visual indicator now appears while code execution is in progress, providing real-time status updates on ongoing computations.
- **⚙️ General Backend & Frontend Stability Enhancements**: Extensive refactoring improves reliability, performance, and overall user experience for a more seamless Open WebUI.
- **🌍 Translation Updates**: Various international translation refinements ensure better localization and a more natural user interface experience.
### Fixed
- **📱 Mobile Hover Issue Resolved**: Users can now edit responses smoothly on mobile without interference, fixing a longstanding hover issue.
- **🔄 Temporary Chat Message Duplication Fixed**: Eliminated buggy behavior where messages were being unnecessarily repeated in temporary chat mode, ensuring a smooth and consistent conversation flow.
## [0.5.14] - 2025-02-17
### Fixed
- **🔧 Critical Import Error Resolved**: Fixed a circular import issue preventing 'override_static' from being correctly imported in 'open_webui.config', ensuring smooth system initialization and stability.
## [0.5.13] - 2025-02-17
### Added
- **🌐 Full Context Mode for Web Search**: Enable highly accurate web searches by utilizing full context mode—ideal for models with large context windows, ensuring more precise and insightful results.
- **⚡ Optimized Asynchronous Web Search**: Web searches now load significantly faster with optimized async support, providing users with quicker, more efficient information retrieval.
- **🔄 Auto Text Direction for RTL Languages**: Automatic text alignment based on language input, ensuring seamless conversation flow for Arabic, Hebrew, and other right-to-left scripts.
- **🚀 Jupyter Notebook Support for Code Execution**: The "Run" button in code blocks can now use Jupyter for execution, offering a powerful, dynamic coding experience directly in the chat.
- **🗑️ Message Delete Confirmation Dialog**: Prevent accidental deletions with a new confirmation prompt before removing messages, adding an additional layer of security to your chat history.
- **📥 Download Button for SVG Diagrams**: SVG diagrams generated within chat can now be downloaded instantly, making it easier to save and share complex visual data.
- **✨ General UI/UX Improvements and Backend Stability**: A refined interface with smoother interactions, improved layouts, and backend stability enhancements for a more reliable, polished experience.
### Fixed
- **🛠️ Temporary Chat Message Continue Button Fixed**: The "Continue Response" button for temporary chats now works as expected, ensuring an uninterrupted conversation flow.
### Changed
- **📝 Prompt Variable Update**: Deprecated square bracket '[]' indicators for prompt variables; now requires double curly brackets '{{}}' for consistency and clarity.
- **🔧 Stability Enhancements**: Error handling improved in chat history, ensuring smoother operations when reviewing previous messages.
## [0.5.12] - 2025-02-13
### Added
- **🛠️ Multiple Tool Calls Support for Native Function Mode**: Functions now can call multiple tools within a single response, unlocking better automation and workflow flexibility when using native function calling.
### Fixed
- **📝 Playground Text Completion Restored**: Addressed an issue where text completion in the Playground was not functioning.
- **🔗 Direct Connections Now Work for Regular Users**: Fixed a bug where users with the 'user' role couldn't establish direct API connections, enabling seamless model usage for all user tiers.
- **⚡ Landing Page Input No Longer Lags with Long Text**: Improved input responsiveness on the landing page, ensuring fast and smooth typing experiences even when entering long messages.
- **🔧 Parameter in Functions Fixed**: Fixed an issue where the reserved parameters wasn’t recognized within functions, restoring full functionality for advanced task-based automation.
## [0.5.11] - 2025-02-13
### Added
- **🎤 Kokoro-JS TTS Support**: A new on-device, high-quality text-to-speech engine has been integrated, vastly improving voice generation quality—everything runs directly in your browser.
- **🐍 Jupyter Notebook Support in Code Interpreter**: Now, you can configure Code Interpreter to run Python code not only via Pyodide but also through Jupyter, offering a more robust coding environment for AI-driven computations and analysis.
- **🔗 Direct API Connections for Private & Local Inference**: You can now connect Open WebUI to your private or localhost API inference endpoints. CORS must be enabled, but this unlocks direct, on-device AI infrastructure support.
- **🔍 Advanced Domain Filtering for Web Search**: You can now specify which domains should be included or excluded from web searches, refining results for more relevant information retrieval.
- **🚀 Improved Image Generation Metadata Handling**: Generated images now retain metadata for better organization and future retrieval.
- **📂 S3 Key Prefix Support**: Fine-grained control over S3 storage file structuring with configurable key prefixes.
- **📸 Support for Image-Only Messages**: Send messages containing only images, facilitating more visual-centric interactions.
- **🌍 Updated Translations**: German, Spanish, Traditional Chinese, and Catalan translations updated for better multilingual support.
### Fixed
- **🔧 OAuth Debug Logs & Username Claim Fixes**: Debug logs have been added for OAuth role and group management, with fixes ensuring proper OAuth username retrieval and claim handling.
- **📌 Citations Formatting & Toggle Fixes**: Inline citation toggles now function correctly, and citations with more than three sources are now fully visible when expanded.
- **📸 ComfyUI Maximum Seed Value Constraint Fixed**: The maximum allowed seed value for ComfyUI has been corrected, preventing unintended behavior.
- **🔑 Connection Settings Stability**: Addressed connection settings issues that were causing instability when saving configurations.
- **📂 GGUF Model Upload Stability**: Fixed upload inconsistencies for GGUF models, ensuring reliable local model handling.
- **🔧 Web Search Configuration Bug**: Fixed issues where web search filters and settings weren't correctly applied.
- **💾 User Settings Persistence Fix**: Ensured user-specific settings are correctly saved and applied across sessions.
- **🔄 OpenID Username Retrieval Enhancement**: Usernames are now correctly picked up and assigned for OpenID Connect (OIDC) logins.
## [0.5.10] - 2025-02-05
### Fixed
- **⚙️ System Prompts Now Properly Templated via API**: Resolved an issue where system prompts were not being correctly processed when used through the API, ensuring template variables now function as expected.
- **📝 '<thinking>' Tag Display Issue Fixed**: Fixed a bug where the 'thinking' tag was disrupting content rendering, ensuring clean and accurate text display.
- **💻 Code Interpreter Stability with Custom Functions**: Addressed failures when using the Code Interpreter with certain custom functions like Anthropic, ensuring smoother execution and better compatibility.
## [0.5.9] - 2025-02-05
### Fixed
- **💡 "Think" Tag Display Issue**: Resolved a bug where the "Think" tag was not functioning correctly, ensuring proper visualization of the model's reasoning process before delivering responses.
## [0.5.8] - 2025-02-05
### Added
- **🖥️ Code Interpreter**: Models can now execute code in real time to refine their answers dynamically, running securely within a sandboxed browser environment using Pyodide. Perfect for calculations, data analysis, and AI-assisted coding tasks!
- **💬 Redesigned Chat Input UI**: Enjoy a sleeker and more intuitive message input with improved feature selection, making it easier than ever to toggle tools, enable search, and interact with AI seamlessly.
- **🛠️ Native Tool Calling Support (Experimental)**: Supported models can now call tools natively, reducing query latency and improving contextual responses. More enhancements coming soon!
- **🔗 Exa Search Engine Integration**: A new search provider has been added, allowing users to retrieve up-to-date and relevant information without leaving the chat interface.
- **🌍 Localized Dates & Times**: Date and time formats now match your system locale, ensuring a more natural, region-specific experience.
- **📎 User Headers for External Embedding APIs**: API calls to external embedding services now include user-related headers.
- **🌍 "Always On" Web Search Toggle**: A new option under Settings > Interface allows users to enable Web Search by default—transform Open WebUI into your go-to search engine, ensuring AI-powered results with every query.
- **🚀 General Performance & Stability**: Significant improvements across the platform for a faster, more reliable experience.
- **🖼️ UI/UX Enhancements**: Numerous design refinements improving readability, responsiveness, and accessibility.
- **🌍 Improved Translations**: Chinese, Korean, French, Ukrainian and Serbian translations have been updated with refined terminologies for better clarity.
### Fixed
- **🔄 OAuth Name Field Fallback**: Resolves OAuth login failures by using the email field as a fallback when a name is missing.
- **🔑 Google Drive Credentials Restriction**: Ensures only authenticated users can access Google Drive credentials for enhanced security.
- **🌐 DuckDuckGo Search Rate Limit Handling**: Fixes issues where users would encounter 202 errors due to rate limits when using DuckDuckGo for web search.
- **📁 File Upload Permission Indicator**: Users are now notified when they lack permission to upload files, improving clarity on system restrictions.
- **🔧 Max Tokens Issue**: Fixes cases where 'max_tokens' were not applied correctly, ensuring proper model behavior.
- **🔍 Validation for RAG Web Search URLs**: Filters out invalid or unsupported URLs when using web-based retrieval augmentation.
- **🖋️ Title Generation Bug**: Fixes inconsistencies in title generation, ensuring proper chat organization.
### Removed
- **⚡ Deprecated Non-Web Worker Pyodide Execution**: Moves entirely to browser sandboxing for better performance and security.
## [0.5.7] - 2025-01-23
### Added
- **🌍 Enhanced Internationalization (i18n)**: Refined and expanded translations for greater global accessibility and a smoother experience for international users.
### Fixed
- **🔗 Connection Model ID Resolution**: Resolved an issue preventing model IDs from registering in connections.
- **💡 Prefix ID for Ollama Connections**: Fixed a bug where prefix IDs in Ollama connections were non-functional.
- **🔧 Ollama Model Enable/Disable Functionality**: Addressed the issue of enable/disable toggles not working for Ollama base models.
- **🔒 RBAC Permissions for Tools and Models**: Corrected incorrect Role-Based Access Control (RBAC) permissions for tools and models, ensuring that users now only access features according to their assigned privileges, enhancing security and role clarity.
## [0.5.6] - 2025-01-22
### Added
- **🧠 Effortful Reasoning Control for OpenAI Models**: Introduced the reasoning_effort parameter in chat controls for supported OpenAI models, enabling users to fine-tune how much cognitive effort a model dedicates to its responses, offering greater customization for complex queries and reasoning tasks.
### Fixed
- **🔄 Chat Controls Loading UI Bug**: Resolved an issue where collapsible chat controls appeared as "loading," ensuring a smoother and more intuitive user experience for managing chat settings.
### Changed
- **🔧 Updated Ollama Model Creation**: Revamped the Ollama model creation method to align with their new JSON payload format, ensuring seamless compatibility and more efficient model setup workflows.
## [0.5.5] - 2025-01-22
### Added
+3 -3
View File
@@ -2,13 +2,13 @@
## 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, socioeconomic 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 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.
## Why These Standards Are Important
Open-source projects rely on a community of volunteers dedicating their time, expertise, and effort toward a shared goal. These projects are inherently collaborative but also fragile, as the success of the project depends on the goodwill, energy, and productivity of those involved.
Projects rely on a community of volunteers dedicating their time, expertise, and effort toward a shared goal. These projects are inherently collaborative but also fragile, as the success of the project depends on the goodwill, energy, and productivity of those involved.
Maintaining a positive and respectful environment is essential to safeguarding the integrity of this project and protecting contributors' efforts. Behavior that disrupts this atmosphere—whether through hostility, entitlement, or unprofessional conduct—can severely harm the morale and productivity of the community. **Strict enforcement of these standards ensures a safe and supportive space for meaningful collaboration.**
@@ -79,7 +79,7 @@ This approach ensures that disruptive behaviors are addressed swiftly and decisi
## Why Zero Tolerance Is Necessary
Open-source projects thrive on collaboration, goodwill, and mutual respect. Toxic behaviors—such as entitlement, hostility, or persistent negativity—threaten not just individual contributors but the health of the project as a whole. Allowing such behaviors to persist robs contributors of their time, energy, and enthusiasm for the work they do.
Projects thrive on collaboration, goodwill, and mutual respect. Toxic behaviors—such as entitlement, hostility, or persistent negativity—threaten not just individual contributors but the health of the project as a whole. Allowing such behaviors to persist robs contributors of their time, energy, and enthusiasm for the work they do.
By enforcing a zero-tolerance policy, we ensure that the community remains a safe, welcoming space for all participants. These measures are not about harshness—they are about protecting contributors and fostering a productive environment where innovation can thrive.
+7
View File
@@ -0,0 +1,7 @@
# Open WebUI Contributor License Agreement
By submitting my contributions to Open WebUI, I grant Open WebUI full freedom to use my work in any way they choose, under any terms they like, both now and in the future. This approach helps ensure the project remains unified, flexible, and easy to maintain, while empowering Open WebUI to respond quickly to the needs of its users and the wider community.
Taking part in this process means my work can be seamlessly integrated and combined with others, ensuring longevity and adaptability for everyone who benefits from the Open WebUI project. This collaborative approach strengthens the project’s future and helps guarantee that improvements can always be shared and distributed in the most effective way possible.
**_To the fullest extent permitted by law, my contributions are provided on an “as is” basis, with no warranties or guarantees of any kind, and I disclaim any liability for any issues or damages arising from their use or incorporation into the project, regardless of the type of legal claim._**
-64
View File
@@ -1,64 +0,0 @@
# Run with
# caddy run --envfile ./example.env --config ./Caddyfile.localhost
#
# This is configured for
# - Automatic HTTPS (even for localhost)
# - Reverse Proxying to Ollama API Base URL (http://localhost:11434/api)
# - CORS
# - HTTP Basic Auth API Tokens (uncomment basicauth section)
# CORS Preflight (OPTIONS) + Request (GET, POST, PATCH, PUT, DELETE)
(cors-api) {
@match-cors-api-preflight method OPTIONS
handle @match-cors-api-preflight {
header {
Access-Control-Allow-Origin "{http.request.header.origin}"
Access-Control-Allow-Methods "GET, POST, PUT, PATCH, DELETE, OPTIONS"
Access-Control-Allow-Headers "Origin, Accept, Authorization, Content-Type, X-Requested-With"
Access-Control-Allow-Credentials "true"
Access-Control-Max-Age "3600"
defer
}
respond "" 204
}
@match-cors-api-request {
not {
header Origin "{http.request.scheme}://{http.request.host}"
}
header Origin "{http.request.header.origin}"
}
handle @match-cors-api-request {
header {
Access-Control-Allow-Origin "{http.request.header.origin}"
Access-Control-Allow-Methods "GET, POST, PUT, PATCH, DELETE, OPTIONS"
Access-Control-Allow-Headers "Origin, Accept, Authorization, Content-Type, X-Requested-With"
Access-Control-Allow-Credentials "true"
Access-Control-Max-Age "3600"
defer
}
}
}
# replace localhost with example.com or whatever
localhost {
## HTTP Basic Auth
## (uncomment to enable)
# basicauth {
# # see .example.env for how to generate tokens
# {env.OLLAMA_API_ID} {env.OLLAMA_API_TOKEN_DIGEST}
# }
handle /api/* {
# Comment to disable CORS
import cors-api
reverse_proxy localhost:11434
}
# Same-Origin Static Web Server
file_server {
root ./build/
}
}
+6 -3
View File
@@ -4,7 +4,7 @@
ARG USE_CUDA=false
ARG USE_OLLAMA=false
# Tested with cu117 for CUDA 11 and cu121 for CUDA 12 (default)
ARG USE_CUDA_VER=cu121
ARG USE_CUDA_VER=cu128
# any sentence transformer model; models to use can be found at https://huggingface.co/models?library=sentence-transformers
# Leaderboard: https://huggingface.co/spaces/mteb/leaderboard
# for better performance and multilangauge support use "intfloat/multilingual-e5-large" (~2.5GB) or "intfloat/multilingual-e5-base" (~1.5GB)
@@ -26,8 +26,11 @@ ARG BUILD_HASH
WORKDIR /app
# to store git revision in build
RUN apk add --no-cache git
COPY package.json package-lock.json ./
RUN npm ci
RUN npm ci --force
COPY . .
ENV APP_BUILD_HASH=${BUILD_HASH}
@@ -132,7 +135,7 @@ RUN if [ "$USE_OLLAMA" = "true" ]; then \
# install python dependencies
COPY --chown=$UID:$GID ./backend/requirements.txt ./requirements.txt
RUN pip3 install uv && \
RUN pip3 install --no-cache-dir uv && \
if [ "$USE_CUDA" = "true" ]; then \
# If you use CUDA the whisper and embedding model will be downloaded on first use
pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/$USE_CUDA_DOCKER_VER --no-cache-dir && \
+7 -1
View File
@@ -1,4 +1,4 @@
Copyright (c) 2023-2025 Timothy Jaeryang Baek
Copyright (c) 2023-2025 Timothy Jaeryang Baek (Open WebUI)
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -15,6 +15,12 @@ modification, are permitted provided that the following conditions are met:
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
4. Notwithstanding any other provision of this License, and as a material condition of the rights granted herein, licensees are strictly prohibited from altering, removing, obscuring, or replacing any "Open WebUI" branding, including but not limited to the name, logo, or any visual, textual, or symbolic identifiers that distinguish the software and its interfaces, in any deployment or distribution, regardless of the number of users, except as explicitly set forth in Clauses 5 and 6 below.
5. The branding restriction enumerated in Clause 4 shall not apply in the following limited circumstances: (i) deployments or distributions where the total number of end users (defined as individual natural persons with direct access to the application) does not exceed fifty (50) within any rolling thirty (30) day period; (ii) cases in which the licensee is an official contributor to the codebase—with a substantive code change successfully merged into the main branch of the official codebase maintained by the copyright holder—who has obtained specific prior written permission for branding adjustment from the copyright holder; or (iii) where the licensee has obtained a duly executed enterprise license expressly permitting such modification. For all other cases, any removal or alteration of the "Open WebUI" branding shall constitute a material breach of license.
6. All code, modifications, or derivative works incorporated into this project prior to the incorporation of this branding clause remain licensed under the BSD 3-Clause License, and prior contributors retain all BSD-3 rights therein; if any such contributor requests the removal of their BSD-3-licensed code, the copyright holder will do so, and any replacement code will be licensed under the project's primary license then in effect. By contributing after this clause's adoption, you agree to the project's Contributor License Agreement (CLA) and to these updated terms for all new contributions.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+53
View File
@@ -0,0 +1,53 @@
All code and materials created before commit `60d84a3aae9802339705826e9095e272e3c83623` are subject to the following copyright and license:
Copyright (c) 2023-2025 Timothy Jaeryang Baek
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
All code and materials created before commit `a76068d69cd59568b920dfab85dc573dbbb8f131` are subject to the following copyright and license:
MIT License
Copyright (c) 2023 Timothy Jaeryang Baek
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+43 -6
View File
@@ -7,16 +7,22 @@
![GitHub language count](https://img.shields.io/github/languages/count/open-webui/open-webui)
![GitHub top language](https://img.shields.io/github/languages/top/open-webui/open-webui)
![GitHub last commit](https://img.shields.io/github/last-commit/open-webui/open-webui?color=red)
![Hits](https://hits.seeyoufarm.com/api/count/incr/badge.svg?url=https%3A%2F%2Fgithub.com%2Follama-webui%2Follama-wbui&count_bg=%2379C83D&title_bg=%23555555&icon=&icon_color=%23E7E7E7&title=hits&edge_flat=false)
[![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://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/).
Passionate about open-source AI? [Join our team →](https://careers.openwebui.com/)
![Open WebUI Demo](./demo.gif)
> [!TIP]
> **Looking for an [Enterprise Plan](https://docs.openwebui.com/enterprise)?** – **[Speak with Our Sales Team Today!](mailto:sales@openwebui.com)**
>
> Get **enhanced capabilities**, including **custom theming and branding**, **Service Level Agreement (SLA) support**, **Long-Term Support (LTS) versions**, and **more!**
For more information, be sure to check out our [Open WebUI Documentation](https://docs.openwebui.com/).
## Key Features of Open WebUI ⭐
- 🚀 **Effortless Setup**: Install seamlessly using Docker or Kubernetes (kubectl, kustomize or helm) for a hassle-free experience with support for both `:ollama` and `:cuda` tagged images.
@@ -25,6 +31,8 @@ For more information, be sure to check out our [Open WebUI Documentation](https:
- 🛡️ **Granular Permissions and User Groups**: By allowing administrators to create detailed user roles and permissions, we ensure a secure user environment. This granularity not only enhances security but also allows for customized user experiences, fostering a sense of ownership and responsibility amongst users.
- 🔄 **SCIM 2.0 Support**: Enterprise-grade user and group provisioning through SCIM 2.0 protocol, enabling seamless integration with identity providers like Okta, Azure AD, and Google Workspace for automated user lifecycle management.
- 📱 **Responsive Design**: Enjoy a seamless experience across Desktop PC, Laptop, and Mobile devices.
- 📱 **Progressive Web App (PWA) for Mobile**: Enjoy a native app-like experience on your mobile device with our PWA, providing offline access on localhost and a seamless user interface.
@@ -57,9 +65,36 @@ For more information, be sure to check out our [Open WebUI Documentation](https:
Want to learn more about Open WebUI's features? Check out our [Open WebUI documentation](https://docs.openwebui.com/features) for a comprehensive overview!
## 🔗 Also Check Out Open WebUI Community!
## Sponsors 🙌
Don't forget to explore our sibling project, [Open WebUI Community](https://openwebui.com/), where you can discover, download, and explore customized Modelfiles. Open WebUI Community offers a wide range of exciting possibilities for enhancing your chat interactions with Open WebUI! 🚀
#### Emerald
<table>
<tr>
<td>
<a href="https://n8n.io/" target="_blank">
<img src="https://docs.openwebui.com/sponsors/logos/n8n.png" alt="n8n" style="width: 8rem; height: 8rem; border-radius: .75rem;" />
</a>
</td>
<td>
<a href="https://n8n.io/">n8n</a> • Does your interface have a backend yet?<br>Try <a href="https://n8n.io/">n8n</a>
</td>
</tr>
<tr>
<td>
<a href="https://tailscale.com/blog/self-host-a-local-ai-stack/?utm_source=OpenWebUI&utm_medium=paid-ad-placement&utm_campaign=OpenWebUI-Docs" target="_blank">
<img src="https://docs.openwebui.com/sponsors/logos/tailscale.png" alt="Tailscale" style="width: 8rem; height: 8rem; border-radius: .75rem;" />
</a>
</td>
<td>
<a href="https://tailscale.com/blog/self-host-a-local-ai-stack/?utm_source=OpenWebUI&utm_medium=paid-ad-placement&utm_campaign=OpenWebUI-Docs">Tailscale</a> • Connect self-hosted AI to any device with Tailscale
</td>
</tr>
</table>
---
We are incredibly grateful for the generous support of our sponsors. Their contributions help us to maintain and improve our project, ensuring we can continue to deliver quality work to our community. Thank you!
## How to Install 🚀
@@ -150,6 +185,8 @@ After installation, you can access Open WebUI at [http://localhost:3000](http://
We offer various installation alternatives, including non-Docker native installation methods, Docker Compose, Kustomize, and Helm. Visit our [Open WebUI Documentation](https://docs.openwebui.com/getting-started/) or join our [Discord community](https://discord.gg/5rJgQTnV4s) for comprehensive guidance.
Look at the [Local Development Guide](https://docs.openwebui.com/getting-started/advanced-topics/development) for instructions on setting up a local development environment.
### Troubleshooting
Encountering connection issues? Our [Open WebUI Documentation](https://docs.openwebui.com/troubleshooting/) has got you covered. For further assistance and to join our vibrant community, visit the [Open WebUI Discord](https://discord.gg/5rJgQTnV4s).
@@ -174,7 +211,7 @@ docker run --rm --volume /var/run/docker.sock:/var/run/docker.sock containrrr/wa
In the last part of the command, replace `open-webui` with your container name if it is different.
Check our Migration Guide available in our [Open WebUI Documentation](https://docs.openwebui.com/tutorials/migration/).
Check our Updating Guide available in our [Open WebUI Documentation](https://docs.openwebui.com/getting-started/updating).
### Using the Dev Branch 🌙
@@ -201,7 +238,7 @@ Discover upcoming features on our roadmap in the [Open WebUI Documentation](http
## License 📜
This project is licensed under the [BSD-3-Clause License](LICENSE) - see the [LICENSE](LICENSE) file for details. 📄
This project is licensed under the [Open WebUI License](LICENSE), a revised BSD-3-Clause license. You receive all the same rights as the classic BSD-3 license: you can use, modify, and distribute the software, including in proprietary and commercial products, with minimal restrictions. The only additional requirement is to preserve the "Open WebUI" branding, as detailed in the LICENSE file. For full terms, see the [LICENSE](LICENSE) document. 📄
## Support 💬
+2 -1
View File
@@ -1,2 +1,3 @@
export CORS_ALLOW_ORIGIN="http://localhost:5173"
PORT="${PORT:-8080}"
uvicorn open_webui.main:app --port $PORT --host 0.0.0.0 --forwarded-allow-ips '*' --reload
uvicorn open_webui.main:app --port $PORT --host 0.0.0.0 --forwarded-allow-ips '*' --reload
+8 -1
View File
@@ -73,8 +73,15 @@ def serve(
os.environ["LD_LIBRARY_PATH"] = ":".join(LD_LIBRARY_PATH)
import open_webui.main # we need set environment variables before importing main
from open_webui.env import UVICORN_WORKERS # Import the workers setting
uvicorn.run(open_webui.main.app, host=host, port=port, forwarded_allow_ips="*")
uvicorn.run(
"open_webui.main:app",
host=host,
port=port,
forwarded_allow_ips="*",
workers=UVICORN_WORKERS,
)
@app.command()
+1395 -161
View File
File diff suppressed because it is too large Load Diff
+3 -1
View File
@@ -31,6 +31,7 @@ class ERROR_MESSAGES(str, Enum):
USERNAME_TAKEN = (
"Uh-oh! This username is already registered. Please choose another username."
)
PASSWORD_TOO_LONG = "Uh-oh! The password you entered is too long. Please make sure your password is less than 72 bytes long."
COMMAND_TAKEN = "Uh-oh! This command is already registered. Please choose another command string."
FILE_EXISTS = "Uh-oh! This file is already registered. Please choose another file."
@@ -57,7 +58,7 @@ class ERROR_MESSAGES(str, Enum):
)
FILE_NOT_SENT = "FILE_NOT_SENT"
FILE_NOT_SUPPORTED = "Oops! It seems like the file format you're trying to upload is not supported. Please upload a file with a supported format (e.g., JPG, PNG, PDF, TXT) and try again."
FILE_NOT_SUPPORTED = "Oops! It seems like the file format you're trying to upload is not supported. Please upload a file with a supported format and try again."
NOT_FOUND = "We could not find what you're looking for :/"
USER_NOT_FOUND = "We could not find what you're looking for :/"
@@ -110,6 +111,7 @@ class TASKS(str, Enum):
DEFAULT = lambda task="": f"{task if task else 'generation'}"
TITLE_GENERATION = "title_generation"
FOLLOW_UP_GENERATION = "follow_up_generation"
TAGS_GENERATION = "tags_generation"
EMOJI_GENERATION = "emoji_generation"
QUERY_GENERATION = "query_generation"
+368 -31
View File
@@ -5,7 +5,9 @@ import os
import pkgutil
import sys
import shutil
from uuid import uuid4
from pathlib import Path
from cryptography.hazmat.primitives import serialization
import markdown
from bs4 import BeautifulSoup
@@ -65,10 +67,8 @@ except Exception:
# LOGGING
####################################
log_levels = ["CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG"]
GLOBAL_LOG_LEVEL = os.environ.get("GLOBAL_LOG_LEVEL", "").upper()
if GLOBAL_LOG_LEVEL in log_levels:
if GLOBAL_LOG_LEVEL in logging.getLevelNamesMapping():
logging.basicConfig(stream=sys.stdout, level=GLOBAL_LOG_LEVEL, force=True)
else:
GLOBAL_LOG_LEVEL = "INFO"
@@ -78,6 +78,7 @@ log.info(f"GLOBAL_LOG_LEVEL: {GLOBAL_LOG_LEVEL}")
if "cuda_error" in locals():
log.exception(cuda_error)
del cuda_error
log_sources = [
"AUDIO",
@@ -92,6 +93,7 @@ log_sources = [
"RAG",
"WEBHOOK",
"SOCKET",
"OAUTH",
]
SRC_LOG_LEVELS = {}
@@ -99,19 +101,19 @@ SRC_LOG_LEVELS = {}
for source in log_sources:
log_env_var = source + "_LOG_LEVEL"
SRC_LOG_LEVELS[source] = os.environ.get(log_env_var, "").upper()
if SRC_LOG_LEVELS[source] not in log_levels:
if SRC_LOG_LEVELS[source] not in logging.getLevelNamesMapping():
SRC_LOG_LEVELS[source] = GLOBAL_LOG_LEVEL
log.info(f"{log_env_var}: {SRC_LOG_LEVELS[source]}")
log.setLevel(SRC_LOG_LEVELS["CONFIG"])
WEBUI_NAME = os.environ.get("WEBUI_NAME", "Open WebUI")
if WEBUI_NAME != "Open WebUI":
WEBUI_NAME += " (Open WebUI)"
WEBUI_FAVICON_URL = "https://openwebui.com/favicon.png"
TRUSTED_SIGNATURE_KEY = os.environ.get("TRUSTED_SIGNATURE_KEY", "")
####################################
# ENV (dev,test,prod)
@@ -129,8 +131,8 @@ else:
except Exception:
PACKAGE_DATA = {"version": "0.0.0"}
VERSION = PACKAGE_DATA["version"]
INSTANCE_ID = os.environ.get("INSTANCE_ID", str(uuid4()))
# Function to parse each section
@@ -160,7 +162,6 @@ try:
except Exception:
changelog_content = (pkgutil.get_data("open_webui", "CHANGELOG.md") or b"").decode()
# Convert markdown content to HTML
html_content = markdown.markdown(changelog_content)
@@ -191,7 +192,6 @@ for version in soup.find_all("h2"):
changelog_json[version_number] = version_data
CHANGELOG = changelog_json
####################################
@@ -200,6 +200,7 @@ CHANGELOG = changelog_json
SAFE_MODE = os.environ.get("SAFE_MODE", "false").lower() == "true"
####################################
# ENABLE_FORWARD_USER_INFO_HEADERS
####################################
@@ -208,7 +209,6 @@ ENABLE_FORWARD_USER_INFO_HEADERS = (
os.environ.get("ENABLE_FORWARD_USER_INFO_HEADERS", "False").lower() == "true"
)
####################################
# WEBUI_BUILD_HASH
####################################
@@ -243,7 +243,6 @@ if FROM_INIT_PY:
DATA_DIR = Path(os.getenv("DATA_DIR", OPEN_WEBUI_DIR / "data"))
STATIC_DIR = Path(os.getenv("STATIC_DIR", OPEN_WEBUI_DIR / "static"))
FONTS_DIR = Path(os.getenv("FONTS_DIR", OPEN_WEBUI_DIR / "static" / "fonts"))
@@ -255,7 +254,6 @@ if FROM_INIT_PY:
os.getenv("FRONTEND_BUILD_DIR", OPEN_WEBUI_DIR / "frontend")
).resolve()
####################################
# Database
####################################
@@ -270,21 +268,43 @@ else:
DATABASE_URL = os.environ.get("DATABASE_URL", f"sqlite:///{DATA_DIR}/webui.db")
DATABASE_TYPE = os.environ.get("DATABASE_TYPE")
DATABASE_USER = os.environ.get("DATABASE_USER")
DATABASE_PASSWORD = os.environ.get("DATABASE_PASSWORD")
DATABASE_CRED = ""
if DATABASE_USER:
DATABASE_CRED += f"{DATABASE_USER}"
if DATABASE_PASSWORD:
DATABASE_CRED += f":{DATABASE_PASSWORD}"
DB_VARS = {
"db_type": DATABASE_TYPE,
"db_cred": DATABASE_CRED,
"db_host": os.environ.get("DATABASE_HOST"),
"db_port": os.environ.get("DATABASE_PORT"),
"db_name": os.environ.get("DATABASE_NAME"),
}
if all(DB_VARS.values()):
DATABASE_URL = f"{DB_VARS['db_type']}://{DB_VARS['db_cred']}@{DB_VARS['db_host']}:{DB_VARS['db_port']}/{DB_VARS['db_name']}"
elif DATABASE_TYPE == "sqlite+sqlcipher" and not os.environ.get("DATABASE_URL"):
# Handle SQLCipher with local file when DATABASE_URL wasn't explicitly set
DATABASE_URL = f"sqlite+sqlcipher:///{DATA_DIR}/webui.db"
# Replace the postgres:// with postgresql://
if "postgres://" in DATABASE_URL:
DATABASE_URL = DATABASE_URL.replace("postgres://", "postgresql://")
DATABASE_SCHEMA = os.environ.get("DATABASE_SCHEMA", None)
DATABASE_POOL_SIZE = os.environ.get("DATABASE_POOL_SIZE", 0)
DATABASE_POOL_SIZE = os.environ.get("DATABASE_POOL_SIZE", None)
if DATABASE_POOL_SIZE == "":
DATABASE_POOL_SIZE = 0
else:
if DATABASE_POOL_SIZE != None:
try:
DATABASE_POOL_SIZE = int(DATABASE_POOL_SIZE)
except Exception:
DATABASE_POOL_SIZE = 0
DATABASE_POOL_SIZE = None
DATABASE_POOL_MAX_OVERFLOW = os.environ.get("DATABASE_POOL_MAX_OVERFLOW", 0)
@@ -320,7 +340,6 @@ 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"
)
@@ -329,22 +348,63 @@ ENABLE_REALTIME_CHAT_SAVE = (
# REDIS
####################################
REDIS_URL = os.environ.get("REDIS_URL", "redis://localhost:6379/0")
REDIS_URL = os.environ.get("REDIS_URL", "")
REDIS_CLUSTER = os.environ.get("REDIS_CLUSTER", "False").lower() == "true"
REDIS_KEY_PREFIX = os.environ.get("REDIS_KEY_PREFIX", "open-webui")
REDIS_SENTINEL_HOSTS = os.environ.get("REDIS_SENTINEL_HOSTS", "")
REDIS_SENTINEL_PORT = os.environ.get("REDIS_SENTINEL_PORT", "26379")
# Maximum number of retries for Redis operations when using Sentinel fail-over
REDIS_SENTINEL_MAX_RETRY_COUNT = os.environ.get("REDIS_SENTINEL_MAX_RETRY_COUNT", "2")
try:
REDIS_SENTINEL_MAX_RETRY_COUNT = int(REDIS_SENTINEL_MAX_RETRY_COUNT)
if REDIS_SENTINEL_MAX_RETRY_COUNT < 1:
REDIS_SENTINEL_MAX_RETRY_COUNT = 2
except ValueError:
REDIS_SENTINEL_MAX_RETRY_COUNT = 2
####################################
# UVICORN WORKERS
####################################
# Number of uvicorn worker processes for handling requests
UVICORN_WORKERS = os.environ.get("UVICORN_WORKERS", "1")
try:
UVICORN_WORKERS = int(UVICORN_WORKERS)
if UVICORN_WORKERS < 1:
UVICORN_WORKERS = 1
except ValueError:
UVICORN_WORKERS = 1
log.info(f"Invalid UVICORN_WORKERS value, defaulting to {UVICORN_WORKERS}")
####################################
# WEBUI_AUTH (Required for security)
####################################
WEBUI_AUTH = os.environ.get("WEBUI_AUTH", "True").lower() == "true"
ENABLE_SIGNUP_PASSWORD_CONFIRMATION = (
os.environ.get("ENABLE_SIGNUP_PASSWORD_CONFIRMATION", "False").lower() == "true"
)
WEBUI_AUTH_TRUSTED_EMAIL_HEADER = os.environ.get(
"WEBUI_AUTH_TRUSTED_EMAIL_HEADER", None
)
WEBUI_AUTH_TRUSTED_NAME_HEADER = os.environ.get("WEBUI_AUTH_TRUSTED_NAME_HEADER", None)
WEBUI_AUTH_TRUSTED_GROUPS_HEADER = os.environ.get(
"WEBUI_AUTH_TRUSTED_GROUPS_HEADER", None
)
BYPASS_MODEL_ACCESS_CONTROL = (
os.environ.get("BYPASS_MODEL_ACCESS_CONTROL", "False").lower() == "true"
)
WEBUI_AUTH_SIGNOUT_REDIRECT_URL = os.environ.get(
"WEBUI_AUTH_SIGNOUT_REDIRECT_URL", None
)
####################################
# WEBUI_SECRET_KEY
####################################
@@ -356,26 +416,125 @@ WEBUI_SECRET_KEY = os.environ.get(
), # DEPRECATED: remove at next major version
)
WEBUI_SESSION_COOKIE_SAME_SITE = os.environ.get(
"WEBUI_SESSION_COOKIE_SAME_SITE",
os.environ.get("WEBUI_SESSION_COOKIE_SAME_SITE", "lax"),
WEBUI_SESSION_COOKIE_SAME_SITE = os.environ.get("WEBUI_SESSION_COOKIE_SAME_SITE", "lax")
WEBUI_SESSION_COOKIE_SECURE = (
os.environ.get("WEBUI_SESSION_COOKIE_SECURE", "false").lower() == "true"
)
WEBUI_SESSION_COOKIE_SECURE = os.environ.get(
"WEBUI_SESSION_COOKIE_SECURE",
os.environ.get("WEBUI_SESSION_COOKIE_SECURE", "false").lower() == "true",
WEBUI_AUTH_COOKIE_SAME_SITE = os.environ.get(
"WEBUI_AUTH_COOKIE_SAME_SITE", WEBUI_SESSION_COOKIE_SAME_SITE
)
WEBUI_AUTH_COOKIE_SECURE = (
os.environ.get(
"WEBUI_AUTH_COOKIE_SECURE",
os.environ.get("WEBUI_SESSION_COOKIE_SECURE", "false"),
).lower()
== "true"
)
if WEBUI_AUTH and WEBUI_SECRET_KEY == "":
raise ValueError(ERROR_MESSAGES.ENV_VAR_NOT_FOUND)
ENABLE_COMPRESSION_MIDDLEWARE = (
os.environ.get("ENABLE_COMPRESSION_MIDDLEWARE", "True").lower() == "true"
)
####################################
# SCIM Configuration
####################################
SCIM_ENABLED = os.environ.get("SCIM_ENABLED", "False").lower() == "true"
SCIM_TOKEN = os.environ.get("SCIM_TOKEN", "")
####################################
# LICENSE_KEY
####################################
LICENSE_KEY = os.environ.get("LICENSE_KEY", "")
LICENSE_BLOB = None
LICENSE_BLOB_PATH = os.environ.get("LICENSE_BLOB_PATH", DATA_DIR / "l.data")
if LICENSE_BLOB_PATH and os.path.exists(LICENSE_BLOB_PATH):
with open(LICENSE_BLOB_PATH, "rb") as f:
LICENSE_BLOB = f.read()
LICENSE_PUBLIC_KEY = os.environ.get("LICENSE_PUBLIC_KEY", "")
pk = None
if LICENSE_PUBLIC_KEY:
pk = serialization.load_pem_public_key(
f"""
-----BEGIN PUBLIC KEY-----
{LICENSE_PUBLIC_KEY}
-----END PUBLIC KEY-----
""".encode(
"utf-8"
)
)
####################################
# MODELS
####################################
MODELS_CACHE_TTL = os.environ.get("MODELS_CACHE_TTL", "1")
if MODELS_CACHE_TTL == "":
MODELS_CACHE_TTL = None
else:
try:
MODELS_CACHE_TTL = int(MODELS_CACHE_TTL)
except Exception:
MODELS_CACHE_TTL = 1
####################################
# CHAT
####################################
CHAT_RESPONSE_STREAM_DELTA_CHUNK_SIZE = os.environ.get(
"CHAT_RESPONSE_STREAM_DELTA_CHUNK_SIZE", "1"
)
if CHAT_RESPONSE_STREAM_DELTA_CHUNK_SIZE == "":
CHAT_RESPONSE_STREAM_DELTA_CHUNK_SIZE = 1
else:
try:
CHAT_RESPONSE_STREAM_DELTA_CHUNK_SIZE = int(
CHAT_RESPONSE_STREAM_DELTA_CHUNK_SIZE
)
except Exception:
CHAT_RESPONSE_STREAM_DELTA_CHUNK_SIZE = 1
####################################
# WEBSOCKET SUPPORT
####################################
ENABLE_WEBSOCKET_SUPPORT = (
os.environ.get("ENABLE_WEBSOCKET_SUPPORT", "True").lower() == "true"
)
WEBSOCKET_MANAGER = os.environ.get("WEBSOCKET_MANAGER", "")
WEBSOCKET_REDIS_URL = os.environ.get("WEBSOCKET_REDIS_URL", REDIS_URL)
WEBSOCKET_REDIS_CLUSTER = (
os.environ.get("WEBSOCKET_REDIS_CLUSTER", str(REDIS_CLUSTER)).lower() == "true"
)
websocket_redis_lock_timeout = os.environ.get("WEBSOCKET_REDIS_LOCK_TIMEOUT", "60")
try:
WEBSOCKET_REDIS_LOCK_TIMEOUT = int(websocket_redis_lock_timeout)
except ValueError:
WEBSOCKET_REDIS_LOCK_TIMEOUT = 60
WEBSOCKET_SENTINEL_HOSTS = os.environ.get("WEBSOCKET_SENTINEL_HOSTS", "")
WEBSOCKET_SENTINEL_PORT = os.environ.get("WEBSOCKET_SENTINEL_PORT", "26379")
AIOHTTP_CLIENT_TIMEOUT = os.environ.get("AIOHTTP_CLIENT_TIMEOUT", "")
@@ -387,25 +546,203 @@ else:
except Exception:
AIOHTTP_CLIENT_TIMEOUT = 300
AIOHTTP_CLIENT_TIMEOUT_OPENAI_MODEL_LIST = os.environ.get(
"AIOHTTP_CLIENT_TIMEOUT_OPENAI_MODEL_LIST", ""
AIOHTTP_CLIENT_SESSION_SSL = (
os.environ.get("AIOHTTP_CLIENT_SESSION_SSL", "True").lower() == "true"
)
if AIOHTTP_CLIENT_TIMEOUT_OPENAI_MODEL_LIST == "":
AIOHTTP_CLIENT_TIMEOUT_OPENAI_MODEL_LIST = None
AIOHTTP_CLIENT_TIMEOUT_MODEL_LIST = os.environ.get(
"AIOHTTP_CLIENT_TIMEOUT_MODEL_LIST",
os.environ.get("AIOHTTP_CLIENT_TIMEOUT_OPENAI_MODEL_LIST", "10"),
)
if AIOHTTP_CLIENT_TIMEOUT_MODEL_LIST == "":
AIOHTTP_CLIENT_TIMEOUT_MODEL_LIST = None
else:
try:
AIOHTTP_CLIENT_TIMEOUT_OPENAI_MODEL_LIST = int(
AIOHTTP_CLIENT_TIMEOUT_OPENAI_MODEL_LIST
AIOHTTP_CLIENT_TIMEOUT_MODEL_LIST = int(AIOHTTP_CLIENT_TIMEOUT_MODEL_LIST)
except Exception:
AIOHTTP_CLIENT_TIMEOUT_MODEL_LIST = 10
AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER_DATA = os.environ.get(
"AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER_DATA", "10"
)
if AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER_DATA == "":
AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER_DATA = None
else:
try:
AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER_DATA = int(
AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER_DATA
)
except Exception:
AIOHTTP_CLIENT_TIMEOUT_OPENAI_MODEL_LIST = 5
AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER_DATA = 10
AIOHTTP_CLIENT_SESSION_TOOL_SERVER_SSL = (
os.environ.get("AIOHTTP_CLIENT_SESSION_TOOL_SERVER_SSL", "True").lower() == "true"
)
####################################
# SENTENCE TRANSFORMERS
####################################
SENTENCE_TRANSFORMERS_BACKEND = os.environ.get("SENTENCE_TRANSFORMERS_BACKEND", "")
if SENTENCE_TRANSFORMERS_BACKEND == "":
SENTENCE_TRANSFORMERS_BACKEND = "torch"
SENTENCE_TRANSFORMERS_MODEL_KWARGS = os.environ.get(
"SENTENCE_TRANSFORMERS_MODEL_KWARGS", ""
)
if SENTENCE_TRANSFORMERS_MODEL_KWARGS == "":
SENTENCE_TRANSFORMERS_MODEL_KWARGS = None
else:
try:
SENTENCE_TRANSFORMERS_MODEL_KWARGS = json.loads(
SENTENCE_TRANSFORMERS_MODEL_KWARGS
)
except Exception:
SENTENCE_TRANSFORMERS_MODEL_KWARGS = None
SENTENCE_TRANSFORMERS_CROSS_ENCODER_BACKEND = os.environ.get(
"SENTENCE_TRANSFORMERS_CROSS_ENCODER_BACKEND", ""
)
if SENTENCE_TRANSFORMERS_CROSS_ENCODER_BACKEND == "":
SENTENCE_TRANSFORMERS_CROSS_ENCODER_BACKEND = "torch"
SENTENCE_TRANSFORMERS_CROSS_ENCODER_MODEL_KWARGS = os.environ.get(
"SENTENCE_TRANSFORMERS_CROSS_ENCODER_MODEL_KWARGS", ""
)
if SENTENCE_TRANSFORMERS_CROSS_ENCODER_MODEL_KWARGS == "":
SENTENCE_TRANSFORMERS_CROSS_ENCODER_MODEL_KWARGS = None
else:
try:
SENTENCE_TRANSFORMERS_CROSS_ENCODER_MODEL_KWARGS = json.loads(
SENTENCE_TRANSFORMERS_CROSS_ENCODER_MODEL_KWARGS
)
except Exception:
SENTENCE_TRANSFORMERS_CROSS_ENCODER_MODEL_KWARGS = None
####################################
# OFFLINE_MODE
####################################
ENABLE_VERSION_UPDATE_CHECK = (
os.environ.get("ENABLE_VERSION_UPDATE_CHECK", "true").lower() == "true"
)
OFFLINE_MODE = os.environ.get("OFFLINE_MODE", "false").lower() == "true"
if OFFLINE_MODE:
os.environ["HF_HUB_OFFLINE"] = "1"
ENABLE_VERSION_UPDATE_CHECK = False
####################################
# AUDIT LOGGING
####################################
# Where to store log file
AUDIT_LOGS_FILE_PATH = f"{DATA_DIR}/audit.log"
# Maximum size of a file before rotating into a new log file
AUDIT_LOG_FILE_ROTATION_SIZE = os.getenv("AUDIT_LOG_FILE_ROTATION_SIZE", "10MB")
# Comma separated list of logger names to use for audit logging
# Default is "uvicorn.access" which is the access log for Uvicorn
# You can add more logger names to this list if you want to capture more logs
AUDIT_UVICORN_LOGGER_NAMES = os.getenv(
"AUDIT_UVICORN_LOGGER_NAMES", "uvicorn.access"
).split(",")
# METADATA | REQUEST | REQUEST_RESPONSE
AUDIT_LOG_LEVEL = os.getenv("AUDIT_LOG_LEVEL", "NONE").upper()
try:
MAX_BODY_LOG_SIZE = int(os.environ.get("MAX_BODY_LOG_SIZE") or 2048)
except ValueError:
MAX_BODY_LOG_SIZE = 2048
# Comma separated list for urls to exclude from audit
AUDIT_EXCLUDED_PATHS = os.getenv("AUDIT_EXCLUDED_PATHS", "/chats,/chat,/folders").split(
","
)
AUDIT_EXCLUDED_PATHS = [path.strip() for path in AUDIT_EXCLUDED_PATHS]
AUDIT_EXCLUDED_PATHS = [path.lstrip("/") for path in AUDIT_EXCLUDED_PATHS]
####################################
# OPENTELEMETRY
####################################
ENABLE_OTEL = os.environ.get("ENABLE_OTEL", "False").lower() == "true"
ENABLE_OTEL_METRICS = os.environ.get("ENABLE_OTEL_METRICS", "False").lower() == "true"
ENABLE_OTEL_LOGS = os.environ.get("ENABLE_OTEL_LOGS", "False").lower() == "true"
OTEL_EXPORTER_OTLP_ENDPOINT = os.environ.get(
"OTEL_EXPORTER_OTLP_ENDPOINT", "http://localhost:4317"
)
OTEL_METRICS_EXPORTER_OTLP_ENDPOINT = os.environ.get(
"OTEL_METRICS_EXPORTER_OTLP_ENDPOINT", OTEL_EXPORTER_OTLP_ENDPOINT
)
OTEL_LOGS_EXPORTER_OTLP_ENDPOINT = os.environ.get(
"OTEL_LOGS_EXPORTER_OTLP_ENDPOINT", OTEL_EXPORTER_OTLP_ENDPOINT
)
OTEL_EXPORTER_OTLP_INSECURE = (
os.environ.get("OTEL_EXPORTER_OTLP_INSECURE", "False").lower() == "true"
)
OTEL_METRICS_EXPORTER_OTLP_INSECURE = (
os.environ.get("OTEL_METRICS_EXPORTER_OTLP_INSECURE", "False").lower() == "true"
)
OTEL_LOGS_EXPORTER_OTLP_INSECURE = (
os.environ.get("OTEL_LOGS_EXPORTER_OTLP_INSECURE", "False").lower() == "true"
)
OTEL_SERVICE_NAME = os.environ.get("OTEL_SERVICE_NAME", "open-webui")
OTEL_RESOURCE_ATTRIBUTES = os.environ.get(
"OTEL_RESOURCE_ATTRIBUTES", ""
) # e.g. key1=val1,key2=val2
OTEL_TRACES_SAMPLER = os.environ.get(
"OTEL_TRACES_SAMPLER", "parentbased_always_on"
).lower()
OTEL_BASIC_AUTH_USERNAME = os.environ.get("OTEL_BASIC_AUTH_USERNAME", "")
OTEL_BASIC_AUTH_PASSWORD = os.environ.get("OTEL_BASIC_AUTH_PASSWORD", "")
OTEL_METRICS_BASIC_AUTH_USERNAME = os.environ.get(
"OTEL_METRICS_BASIC_AUTH_USERNAME", OTEL_BASIC_AUTH_USERNAME
)
OTEL_METRICS_BASIC_AUTH_PASSWORD = os.environ.get(
"OTEL_METRICS_BASIC_AUTH_PASSWORD", OTEL_BASIC_AUTH_PASSWORD
)
OTEL_LOGS_BASIC_AUTH_USERNAME = os.environ.get(
"OTEL_LOGS_BASIC_AUTH_USERNAME", OTEL_BASIC_AUTH_USERNAME
)
OTEL_LOGS_BASIC_AUTH_PASSWORD = os.environ.get(
"OTEL_LOGS_BASIC_AUTH_PASSWORD", OTEL_BASIC_AUTH_PASSWORD
)
OTEL_OTLP_SPAN_EXPORTER = os.environ.get(
"OTEL_OTLP_SPAN_EXPORTER", "grpc"
).lower() # grpc or http
OTEL_METRICS_OTLP_SPAN_EXPORTER = os.environ.get(
"OTEL_METRICS_OTLP_SPAN_EXPORTER", OTEL_OTLP_SPAN_EXPORTER
).lower() # grpc or http
OTEL_LOGS_OTLP_SPAN_EXPORTER = os.environ.get(
"OTEL_LOGS_OTLP_SPAN_EXPORTER", OTEL_OTLP_SPAN_EXPORTER
).lower() # grpc or http
####################################
# TOOLS/FUNCTIONS PIP OPTIONS
####################################
PIP_OPTIONS = os.getenv("PIP_OPTIONS", "").split()
PIP_PACKAGE_INDEX_OPTIONS = os.getenv("PIP_PACKAGE_INDEX_OPTIONS", "").split()
####################################
# PROGRESSIVE WEB APP OPTIONS
####################################
EXTERNAL_PWA_MANIFEST_URL = os.environ.get("EXTERNAL_PWA_MANIFEST_URL")
+23 -18
View File
@@ -2,6 +2,7 @@ import logging
import sys
import inspect
import json
import asyncio
from pydantic import BaseModel
from typing import AsyncGenerator, Generator, Iterator
@@ -24,10 +25,14 @@ from open_webui.socket.main import (
)
from open_webui.models.users import UserModel
from open_webui.models.functions import Functions
from open_webui.models.models import Models
from open_webui.utils.plugin import load_function_module_by_id
from open_webui.utils.plugin import (
load_function_module_by_id,
get_function_module_from_cache,
)
from open_webui.utils.tools import get_tools
from open_webui.utils.access_control import has_access
@@ -52,12 +57,7 @@ log.setLevel(SRC_LOG_LEVELS["MAIN"])
def get_function_module_by_id(request: Request, pipe_id: str):
# Check if function is already loaded
if pipe_id not in request.app.state.FUNCTIONS:
function_module, _, _ = load_function_module_by_id(pipe_id)
request.app.state.FUNCTIONS[pipe_id] = function_module
else:
function_module = request.app.state.FUNCTIONS[pipe_id]
function_module, _, _ = get_function_module_from_cache(request, pipe_id)
if hasattr(function_module, "valves") and hasattr(function_module, "Valves"):
valves = Functions.get_function_valves_by_id(pipe_id)
@@ -76,11 +76,13 @@ async def get_function_models(request):
if hasattr(function_module, "pipes"):
sub_pipes = []
# Check if pipes is a function or a list
# Handle pipes being a list, sync function, or async function
try:
if callable(function_module.pipes):
sub_pipes = function_module.pipes()
if asyncio.iscoroutinefunction(function_module.pipes):
sub_pipes = await function_module.pipes()
else:
sub_pipes = function_module.pipes()
else:
sub_pipes = function_module.pipes
except Exception as e:
@@ -220,15 +222,13 @@ async def generate_function_chat_completion(
extra_params = {
"__event_emitter__": __event_emitter__,
"__event_call__": __event_call__,
"__chat_id__": metadata.get("chat_id", None),
"__session_id__": metadata.get("session_id", None),
"__message_id__": metadata.get("message_id", None),
"__task__": __task__,
"__task_body__": __task_body__,
"__files__": files,
"__user__": {
"id": user.id,
"email": user.email,
"name": user.name,
"role": user.role,
},
"__user__": user.model_dump() if isinstance(user, UserModel) else {},
"__metadata__": metadata,
"__request__": request,
}
@@ -249,8 +249,13 @@ async def generate_function_chat_completion(
form_data["model"] = model_info.base_model_id
params = model_info.params.model_dump()
form_data = apply_model_params_to_body_openai(params, form_data)
form_data = apply_model_system_prompt_to_body(params, form_data, user)
if params:
system = params.pop("system", None)
form_data = apply_model_params_to_body_openai(params, form_data)
form_data = apply_model_system_prompt_to_body(
system, form_data, metadata, user
)
pipe_id = get_pipe_id(form_data)
function_module = get_function_module_by_id(request, pipe_id)
+51 -14
View File
@@ -1,3 +1,4 @@
import os
import json
import logging
from contextlib import contextmanager
@@ -62,6 +63,9 @@ def handle_peewee_migration(DATABASE_URL):
except Exception as e:
log.error(f"Failed to initialize the database connection: {e}")
log.warning(
"Hint: If your database password contains special characters, you may need to URL-encode it."
)
raise
finally:
# Properly closing the database connection
@@ -76,25 +80,58 @@ handle_peewee_migration(DATABASE_URL)
SQLALCHEMY_DATABASE_URL = DATABASE_URL
if "sqlite" in SQLALCHEMY_DATABASE_URL:
# Handle SQLCipher URLs
if SQLALCHEMY_DATABASE_URL.startswith("sqlite+sqlcipher://"):
database_password = os.environ.get("DATABASE_PASSWORD")
if not database_password or database_password.strip() == "":
raise ValueError(
"DATABASE_PASSWORD is required when using sqlite+sqlcipher:// URLs"
)
# Extract database path from SQLCipher URL
db_path = SQLALCHEMY_DATABASE_URL.replace("sqlite+sqlcipher://", "")
if db_path.startswith("/"):
db_path = db_path[1:] # Remove leading slash for relative paths
# Create a custom creator function that uses sqlcipher3
def create_sqlcipher_connection():
import sqlcipher3
conn = sqlcipher3.connect(db_path, check_same_thread=False)
conn.execute(f"PRAGMA key = '{database_password}'")
return conn
engine = create_engine(
"sqlite://", # Dummy URL since we're using creator
creator=create_sqlcipher_connection,
echo=False,
)
log.info("Connected to encrypted SQLite database using SQLCipher")
elif "sqlite" in SQLALCHEMY_DATABASE_URL:
engine = create_engine(
SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False}
)
else:
if DATABASE_POOL_SIZE > 0:
engine = create_engine(
SQLALCHEMY_DATABASE_URL,
pool_size=DATABASE_POOL_SIZE,
max_overflow=DATABASE_POOL_MAX_OVERFLOW,
pool_timeout=DATABASE_POOL_TIMEOUT,
pool_recycle=DATABASE_POOL_RECYCLE,
pool_pre_ping=True,
poolclass=QueuePool,
)
if isinstance(DATABASE_POOL_SIZE, int):
if DATABASE_POOL_SIZE > 0:
engine = create_engine(
SQLALCHEMY_DATABASE_URL,
pool_size=DATABASE_POOL_SIZE,
max_overflow=DATABASE_POOL_MAX_OVERFLOW,
pool_timeout=DATABASE_POOL_TIMEOUT,
pool_recycle=DATABASE_POOL_RECYCLE,
pool_pre_ping=True,
poolclass=QueuePool,
)
else:
engine = create_engine(
SQLALCHEMY_DATABASE_URL, pool_pre_ping=True, poolclass=NullPool
)
else:
engine = create_engine(
SQLALCHEMY_DATABASE_URL, pool_pre_ping=True, poolclass=NullPool
)
engine = create_engine(SQLALCHEMY_DATABASE_URL, pool_pre_ping=True)
SessionLocal = sessionmaker(
+40 -16
View File
@@ -1,4 +1,5 @@
import logging
import os
from contextvars import ContextVar
from open_webui.env import SRC_LOG_LEVELS
@@ -43,24 +44,47 @@ class ReconnectingPostgresqlDatabase(CustomReconnectMixin, PostgresqlDatabase):
def register_connection(db_url):
db = connect(db_url, unquote_password=True)
if isinstance(db, PostgresqlDatabase):
# Enable autoconnect for SQLite databases, managed by Peewee
# Check if using SQLCipher protocol
if db_url.startswith("sqlite+sqlcipher://"):
database_password = os.environ.get("DATABASE_PASSWORD")
if not database_password or database_password.strip() == "":
raise ValueError(
"DATABASE_PASSWORD is required when using sqlite+sqlcipher:// URLs"
)
from playhouse.sqlcipher_ext import SqlCipherDatabase
# Parse the database path from SQLCipher URL
# Convert sqlite+sqlcipher:///path/to/db.sqlite to /path/to/db.sqlite
db_path = db_url.replace("sqlite+sqlcipher://", "")
if db_path.startswith("/"):
db_path = db_path[1:] # Remove leading slash for relative paths
# Use Peewee's native SqlCipherDatabase with encryption
db = SqlCipherDatabase(db_path, passphrase=database_password)
db.autoconnect = True
db.reuse_if_open = True
log.info("Connected to PostgreSQL database")
log.info("Connected to encrypted SQLite database using SQLCipher")
# Get the connection details
connection = parse(db_url, unquote_password=True)
# Use our custom database class that supports reconnection
db = ReconnectingPostgresqlDatabase(**connection)
db.connect(reuse_if_open=True)
elif isinstance(db, SqliteDatabase):
# Enable autoconnect for SQLite databases, managed by Peewee
db.autoconnect = True
db.reuse_if_open = True
log.info("Connected to SQLite database")
else:
raise ValueError("Unsupported database connection")
# Standard database connection (existing logic)
db = connect(db_url, unquote_user=True, unquote_password=True)
if isinstance(db, PostgresqlDatabase):
# Enable autoconnect for SQLite databases, managed by Peewee
db.autoconnect = True
db.reuse_if_open = True
log.info("Connected to PostgreSQL database")
# Get the connection details
connection = parse(db_url, unquote_user=True, unquote_password=True)
# Use our custom database class that supports reconnection
db = ReconnectingPostgresqlDatabase(**connection)
db.connect(reuse_if_open=True)
elif isinstance(db, SqliteDatabase):
# Enable autoconnect for SQLite databases, managed by Peewee
db.autoconnect = True
db.reuse_if_open = True
log.info("Connected to SQLite database")
else:
raise ValueError("Unsupported database connection")
return db
+824 -112
View File
File diff suppressed because it is too large Load Diff
+34 -7
View File
@@ -2,8 +2,8 @@ from logging.config import fileConfig
from alembic import context
from open_webui.models.auths import Auth
from open_webui.env import DATABASE_URL
from sqlalchemy import engine_from_config, pool
from open_webui.env import DATABASE_URL, DATABASE_PASSWORD
from sqlalchemy import engine_from_config, pool, create_engine
# this is the Alembic Config object, which provides
# access to the values within the .ini file in use.
@@ -62,11 +62,38 @@ def run_migrations_online() -> None:
and associate a connection with the context.
"""
connectable = engine_from_config(
config.get_section(config.config_ini_section, {}),
prefix="sqlalchemy.",
poolclass=pool.NullPool,
)
# Handle SQLCipher URLs
if DB_URL and DB_URL.startswith("sqlite+sqlcipher://"):
if not DATABASE_PASSWORD or DATABASE_PASSWORD.strip() == "":
raise ValueError(
"DATABASE_PASSWORD is required when using sqlite+sqlcipher:// URLs"
)
# Extract database path from SQLCipher URL
db_path = DB_URL.replace("sqlite+sqlcipher://", "")
if db_path.startswith("/"):
db_path = db_path[1:] # Remove leading slash for relative paths
# Create a custom creator function that uses sqlcipher3
def create_sqlcipher_connection():
import sqlcipher3
conn = sqlcipher3.connect(db_path, check_same_thread=False)
conn.execute(f"PRAGMA key = '{DATABASE_PASSWORD}'")
return conn
connectable = create_engine(
"sqlite://", # Dummy URL since we're using creator
creator=create_sqlcipher_connection,
echo=False,
)
else:
# Standard database connection (existing logic)
connectable = engine_from_config(
config.get_section(config.config_ini_section, {}),
prefix="sqlalchemy.",
poolclass=pool.NullPool,
)
with connectable.connect() as connection:
context.configure(connection=connection, target_metadata=target_metadata)
@@ -0,0 +1,33 @@
"""Add note table
Revision ID: 9f0c9cd09105
Revises: 3781e22d8b01
Create Date: 2025-05-03 03:00:00.000000
"""
from alembic import op
import sqlalchemy as sa
revision = "9f0c9cd09105"
down_revision = "3781e22d8b01"
branch_labels = None
depends_on = None
def upgrade():
op.create_table(
"note",
sa.Column("id", sa.Text(), nullable=False, primary_key=True, unique=True),
sa.Column("user_id", sa.Text(), nullable=True),
sa.Column("title", sa.Text(), nullable=True),
sa.Column("data", sa.JSON(), nullable=True),
sa.Column("meta", sa.JSON(), nullable=True),
sa.Column("access_control", sa.JSON(), nullable=True),
sa.Column("created_at", sa.BigInteger(), nullable=True),
sa.Column("updated_at", sa.BigInteger(), nullable=True),
)
def downgrade():
op.drop_table("note")
@@ -0,0 +1,23 @@
"""Update folder table data
Revision ID: d31026856c01
Revises: 9f0c9cd09105
Create Date: 2025-07-13 03:00:00.000000
"""
from alembic import op
import sqlalchemy as sa
revision = "d31026856c01"
down_revision = "9f0c9cd09105"
branch_labels = None
depends_on = None
def upgrade():
op.add_column("folder", sa.Column("data", sa.JSON(), nullable=True))
def downgrade():
op.drop_column("folder", "data")
+8 -4
View File
@@ -129,12 +129,16 @@ class AuthsTable:
def authenticate_user(self, email: str, password: str) -> Optional[UserModel]:
log.info(f"authenticate_user: {email}")
user = Users.get_user_by_email(email)
if not user:
return None
try:
with get_db() as db:
auth = db.query(Auth).filter_by(email=email, active=True).first()
auth = db.query(Auth).filter_by(id=user.id, active=True).first()
if auth:
if verify_password(password, auth.password):
user = Users.get_user_by_id(auth.id)
return user
else:
return None
@@ -155,8 +159,8 @@ class AuthsTable:
except Exception:
return False
def authenticate_user_by_trusted_header(self, email: str) -> Optional[UserModel]:
log.info(f"authenticate_user_by_trusted_header: {email}")
def authenticate_user_by_email(self, email: str) -> Optional[UserModel]:
log.info(f"authenticate_user_by_email: {email}")
try:
with get_db() as db:
auth = db.query(Auth).filter_by(email=email, active=True).first()
+167 -52
View File
@@ -1,3 +1,4 @@
import logging
import json
import time
import uuid
@@ -5,17 +6,22 @@ from typing import Optional
from open_webui.internal.db import Base, get_db
from open_webui.models.tags import TagModel, Tag, Tags
from open_webui.models.folders import Folders
from open_webui.env import SRC_LOG_LEVELS
from pydantic import BaseModel, ConfigDict
from sqlalchemy import BigInteger, Boolean, Column, String, Text, JSON
from sqlalchemy import or_, func, select, and_, text
from sqlalchemy.sql import exists
from sqlalchemy.sql.expression import bindparam
####################
# Chat DB Schema
####################
log = logging.getLogger(__name__)
log.setLevel(SRC_LOG_LEVELS["MODELS"])
class Chat(Base):
__tablename__ = "chat"
@@ -62,12 +68,14 @@ class ChatModel(BaseModel):
class ChatForm(BaseModel):
chat: dict
folder_id: Optional[str] = None
class ChatImportForm(ChatForm):
meta: Optional[dict] = {}
pinned: Optional[bool] = False
folder_id: Optional[str] = None
created_at: Optional[int] = None
updated_at: Optional[int] = None
class ChatTitleMessagesForm(BaseModel):
@@ -114,6 +122,7 @@ class ChatTable:
else "New Chat"
),
"chat": form_data.chat,
"folder_id": form_data.folder_id,
"created_at": int(time.time()),
"updated_at": int(time.time()),
}
@@ -143,8 +152,16 @@ class ChatTable:
"meta": form_data.meta,
"pinned": form_data.pinned,
"folder_id": form_data.folder_id,
"created_at": int(time.time()),
"updated_at": int(time.time()),
"created_at": (
form_data.created_at
if form_data.created_at
else int(time.time())
),
"updated_at": (
form_data.updated_at
if form_data.updated_at
else int(time.time())
),
}
)
@@ -228,6 +245,10 @@ class ChatTable:
if chat is None:
return None
# Sanitize message content for null characters before upserting
if isinstance(message.get("content"), str):
message["content"] = message["content"].replace("\x00", "")
chat = chat.chat
history = chat.get("history", {})
@@ -276,6 +297,9 @@ class ChatTable:
"user_id": f"shared-{chat_id}",
"title": chat.title,
"chat": chat.chat,
"meta": chat.meta,
"pinned": chat.pinned,
"folder_id": chat.folder_id,
"created_at": chat.created_at,
"updated_at": int(time.time()),
}
@@ -307,7 +331,9 @@ class ChatTable:
shared_chat.title = chat.title
shared_chat.chat = chat.chat
shared_chat.meta = chat.meta
shared_chat.pinned = chat.pinned
shared_chat.folder_id = chat.folder_id
shared_chat.updated_at = int(time.time())
db.commit()
db.refresh(shared_chat)
@@ -373,22 +399,47 @@ class ChatTable:
return False
def get_archived_chat_list_by_user_id(
self, user_id: str, skip: int = 0, limit: int = 50
self,
user_id: str,
filter: Optional[dict] = None,
skip: int = 0,
limit: int = 50,
) -> list[ChatModel]:
with get_db() as db:
all_chats = (
db.query(Chat)
.filter_by(user_id=user_id, archived=True)
.order_by(Chat.updated_at.desc())
# .limit(limit).offset(skip)
.all()
)
query = db.query(Chat).filter_by(user_id=user_id, archived=True)
if filter:
query_key = filter.get("query")
if query_key:
query = query.filter(Chat.title.ilike(f"%{query_key}%"))
order_by = filter.get("order_by")
direction = filter.get("direction")
if order_by and direction and getattr(Chat, order_by):
if direction.lower() == "asc":
query = query.order_by(getattr(Chat, order_by).asc())
elif direction.lower() == "desc":
query = query.order_by(getattr(Chat, order_by).desc())
else:
raise ValueError("Invalid direction for ordering")
else:
query = query.order_by(Chat.updated_at.desc())
if skip:
query = query.offset(skip)
if limit:
query = query.limit(limit)
all_chats = query.all()
return [ChatModel.model_validate(chat) for chat in all_chats]
def get_chat_list_by_user_id(
self,
user_id: str,
include_archived: bool = False,
filter: Optional[dict] = None,
skip: int = 0,
limit: int = 50,
) -> list[ChatModel]:
@@ -397,7 +448,23 @@ class ChatTable:
if not include_archived:
query = query.filter_by(archived=False)
query = query.order_by(Chat.updated_at.desc())
if filter:
query_key = filter.get("query")
if query_key:
query = query.filter(Chat.title.ilike(f"%{query_key}%"))
order_by = filter.get("order_by")
direction = filter.get("direction")
if order_by and direction and getattr(Chat, order_by):
if direction.lower() == "asc":
query = query.order_by(getattr(Chat, order_by).asc())
elif direction.lower() == "desc":
query = query.order_by(getattr(Chat, order_by).desc())
else:
raise ValueError("Invalid direction for ordering")
else:
query = query.order_by(Chat.updated_at.desc())
if skip:
query = query.offset(skip)
@@ -432,7 +499,7 @@ class ChatTable:
all_chats = query.all()
# result has to be destrctured from sqlalchemy `row` and mapped to a dict since the `ChatModel`is not the returned dataclass.
# result has to be destructured from sqlalchemy `row` and mapped to a dict since the `ChatModel`is not the returned dataclass.
return [
ChatTitleIdResponse.model_validate(
{
@@ -470,7 +537,7 @@ class ChatTable:
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
# we check if the chat is still shared by checking if a chat with the share_id exists
chat = db.query(Chat).filter_by(share_id=id).first()
if chat:
@@ -535,10 +602,12 @@ class ChatTable:
"""
Filters chats based on a search query using Python, allowing pagination using skip and limit.
"""
search_text = search_text.lower().strip()
search_text = search_text.replace("\u0000", "").lower().strip()
if not search_text:
return self.get_chat_list_by_user_id(user_id, include_archived, skip, limit)
return self.get_chat_list_by_user_id(
user_id, include_archived, filter={}, skip=skip, limit=limit
)
search_text_words = search_text.split(" ")
@@ -549,8 +618,45 @@ class ChatTable:
if word.startswith("tag:")
]
# Extract folder names - handle spaces and case insensitivity
folders = Folders.search_folders_by_names(
user_id,
[
word.replace("folder:", "")
for word in search_text_words
if word.startswith("folder:")
],
)
folder_ids = [folder.id for folder in folders]
is_pinned = None
if "pinned:true" in search_text_words:
is_pinned = True
elif "pinned:false" in search_text_words:
is_pinned = False
is_archived = None
if "archived:true" in search_text_words:
is_archived = True
elif "archived:false" in search_text_words:
is_archived = False
is_shared = None
if "shared:true" in search_text_words:
is_shared = True
elif "shared:false" in search_text_words:
is_shared = False
search_text_words = [
word for word in search_text_words if not word.startswith("tag:")
word
for word in search_text_words
if (
not word.startswith("tag:")
and not word.startswith("folder:")
and not word.startswith("pinned:")
and not word.startswith("archived:")
and not word.startswith("shared:")
)
]
search_text = " ".join(search_text_words)
@@ -558,30 +664,41 @@ class ChatTable:
with get_db() as db:
query = db.query(Chat).filter(Chat.user_id == user_id)
if not include_archived:
if is_archived is not None:
query = query.filter(Chat.archived == is_archived)
elif not include_archived:
query = query.filter(Chat.archived == False)
if is_pinned is not None:
query = query.filter(Chat.pinned == is_pinned)
if is_shared is not None:
if is_shared:
query = query.filter(Chat.share_id.isnot(None))
else:
query = query.filter(Chat.share_id.is_(None))
if folder_ids:
query = query.filter(Chat.folder_id.in_(folder_ids))
query = query.order_by(Chat.updated_at.desc())
# Check if the database dialect is either 'sqlite' or 'postgresql'
dialect_name = db.bind.dialect.name
if dialect_name == "sqlite":
# SQLite case: using JSON1 extension for JSON searching
sqlite_content_sql = (
"EXISTS ("
" SELECT 1 "
" FROM json_each(Chat.chat, '$.messages') AS message "
" WHERE LOWER(message.value->>'content') LIKE '%' || :content_key || '%'"
")"
)
sqlite_content_clause = text(sqlite_content_sql)
query = query.filter(
(
Chat.title.ilike(
f"%{search_text}%"
) # Case-insensitive search in title
| text(
"""
EXISTS (
SELECT 1
FROM json_each(Chat.chat, '$.messages') AS message
WHERE LOWER(message.value->>'content') LIKE '%' || :search_text || '%'
)
"""
)
).params(search_text=search_text)
or_(
Chat.title.ilike(bindparam("title_key")), sqlite_content_clause
).params(title_key=f"%{search_text}%", content_key=search_text)
)
# Check if there are any tags to filter, it should have all the tags
@@ -616,21 +733,19 @@ class ChatTable:
elif dialect_name == "postgresql":
# PostgreSQL relies on proper JSON query for search
postgres_content_sql = (
"EXISTS ("
" SELECT 1 "
" FROM json_array_elements(Chat.chat->'messages') AS message "
" WHERE LOWER(message->>'content') LIKE '%' || :content_key || '%'"
")"
)
postgres_content_clause = text(postgres_content_sql)
query = query.filter(
(
Chat.title.ilike(
f"%{search_text}%"
) # Case-insensitive search in title
| text(
"""
EXISTS (
SELECT 1
FROM json_array_elements(Chat.chat->'messages') AS message
WHERE LOWER(message->>'content') LIKE '%' || :search_text || '%'
)
"""
)
).params(search_text=search_text)
or_(
Chat.title.ilike(bindparam("title_key")),
postgres_content_clause,
).params(title_key=f"%{search_text}%", content_key=search_text)
)
# Check if there are any tags to filter, it should have all the tags
@@ -670,7 +785,7 @@ class ChatTable:
# Perform pagination at the SQL level
all_chats = query.offset(skip).limit(limit).all()
print(len(all_chats))
log.info(f"The number of chats: {len(all_chats)}")
# Validate and return chats
return [ChatModel.model_validate(chat) for chat in all_chats]
@@ -731,7 +846,7 @@ class ChatTable:
query = db.query(Chat).filter_by(user_id=user_id)
tag_id = tag_name.replace(" ", "_").lower()
print(db.bind.dialect.name)
log.info(f"DB dialect name: {db.bind.dialect.name}")
if db.bind.dialect.name == "sqlite":
# SQLite JSON1 querying for tags within the meta JSON field
query = query.filter(
@@ -752,7 +867,7 @@ class ChatTable:
)
all_chats = query.all()
print("all_chats", all_chats)
log.debug(f"all_chats: {all_chats}")
return [ChatModel.model_validate(chat) for chat in all_chats]
def add_chat_tag_by_id_and_user_id_and_tag_name(
@@ -810,7 +925,7 @@ class ChatTable:
count = query.count()
# Debugging output for inspection
print(f"Count of chats for tag '{tag_name}':", count)
log.info(f"Count of chats for tag '{tag_name}': {count}")
return count
+1 -1
View File
@@ -118,7 +118,7 @@ class FeedbackTable:
else:
return None
except Exception as e:
print(e)
log.exception(f"Error creating a new feedback: {e}")
return None
def get_feedback_by_id(self, id: str) -> Optional[FeedbackModel]:
+1 -1
View File
@@ -119,7 +119,7 @@ class FilesTable:
else:
return None
except Exception as e:
print(f"Error creating tool: {e}")
log.exception(f"Error inserting a new file: {e}")
return None
def get_file_by_id(self, id: str) -> Optional[FileModel]:
+90 -22
View File
@@ -2,13 +2,15 @@ import logging
import time
import uuid
from typing import Optional
import re
from pydantic import BaseModel, ConfigDict
from sqlalchemy import BigInteger, Column, Text, JSON, Boolean, func
from open_webui.internal.db import Base, get_db
from open_webui.models.chats import Chats
from open_webui.env import SRC_LOG_LEVELS
from pydantic import BaseModel, ConfigDict
from sqlalchemy import BigInteger, Column, Text, JSON, Boolean
log = logging.getLogger(__name__)
log.setLevel(SRC_LOG_LEVELS["MODELS"])
@@ -27,6 +29,7 @@ class Folder(Base):
name = Column(Text)
items = Column(JSON, nullable=True)
meta = Column(JSON, nullable=True)
data = Column(JSON, nullable=True)
is_expanded = Column(Boolean, default=False)
created_at = Column(BigInteger)
updated_at = Column(BigInteger)
@@ -39,6 +42,7 @@ class FolderModel(BaseModel):
name: str
items: Optional[dict] = None
meta: Optional[dict] = None
data: Optional[dict] = None
is_expanded: bool = False
created_at: int
updated_at: int
@@ -53,12 +57,13 @@ class FolderModel(BaseModel):
class FolderForm(BaseModel):
name: str
data: Optional[dict] = None
model_config = ConfigDict(extra="allow")
class FolderTable:
def insert_new_folder(
self, user_id: str, name: str, parent_id: Optional[str] = None
self, user_id: str, form_data: FolderForm, parent_id: Optional[str] = None
) -> Optional[FolderModel]:
with get_db() as db:
id = str(uuid.uuid4())
@@ -66,7 +71,7 @@ class FolderTable:
**{
"id": id,
"user_id": user_id,
"name": name,
**(form_data.model_dump(exclude_unset=True) or {}),
"parent_id": parent_id,
"created_at": int(time.time()),
"updated_at": int(time.time()),
@@ -82,7 +87,7 @@ class FolderTable:
else:
return None
except Exception as e:
print(e)
log.exception(f"Error inserting a new folder: {e}")
return None
def get_folder_by_id_and_user_id(
@@ -101,7 +106,7 @@ class FolderTable:
def get_children_folders_by_id_and_user_id(
self, id: str, user_id: str
) -> Optional[FolderModel]:
) -> Optional[list[FolderModel]]:
try:
with get_db() as db:
folders = []
@@ -185,8 +190,8 @@ class FolderTable:
log.error(f"update_folder: {e}")
return
def update_folder_name_by_id_and_user_id(
self, id: str, user_id: str, name: str
def update_folder_by_id_and_user_id(
self, id: str, user_id: str, form_data: FolderForm
) -> Optional[FolderModel]:
try:
with get_db() as db:
@@ -195,16 +200,28 @@ class FolderTable:
if not folder:
return None
form_data = form_data.model_dump(exclude_unset=True)
existing_folder = (
db.query(Folder)
.filter_by(name=name, parent_id=folder.parent_id, user_id=user_id)
.filter_by(
name=form_data.get("name"),
parent_id=folder.parent_id,
user_id=user_id,
)
.first()
)
if existing_folder:
if existing_folder and existing_folder.id != id:
return None
folder.name = name
folder.name = form_data.get("name", folder.name)
if "data" in form_data:
folder.data = {
**(folder.data or {}),
**form_data["data"],
}
folder.updated_at = int(time.time())
db.commit()
@@ -234,15 +251,15 @@ class FolderTable:
log.error(f"update_folder: {e}")
return
def delete_folder_by_id_and_user_id(self, id: str, user_id: str) -> bool:
def delete_folder_by_id_and_user_id(self, id: str, user_id: str) -> list[str]:
try:
folder_ids = []
with get_db() as db:
folder = db.query(Folder).filter_by(id=id, user_id=user_id).first()
if not folder:
return False
return folder_ids
# Delete all chats in the folder
Chats.delete_chats_by_user_id_and_folder_id(user_id, folder.id)
folder_ids.append(folder.id)
# Delete all children folders
def delete_children(folder):
@@ -250,10 +267,9 @@ class FolderTable:
folder.id, user_id
)
for folder_child in folder_children:
Chats.delete_chats_by_user_id_and_folder_id(
user_id, folder_child.id
)
delete_children(folder_child)
folder_ids.append(folder_child.id)
folder = db.query(Folder).filter_by(id=folder_child.id).first()
db.delete(folder)
@@ -262,10 +278,62 @@ class FolderTable:
delete_children(folder)
db.delete(folder)
db.commit()
return True
return folder_ids
except Exception as e:
log.error(f"delete_folder: {e}")
return False
return []
def normalize_folder_name(self, name: str) -> str:
# Replace _ and space with a single space, lower case, collapse multiple spaces
name = re.sub(r"[\s_]+", " ", name)
return name.strip().lower()
def search_folders_by_names(
self, user_id: str, queries: list[str]
) -> list[FolderModel]:
"""
Search for folders for a user where the name matches any of the queries, treating _ and space as equivalent, case-insensitive.
"""
normalized_queries = [self.normalize_folder_name(q) for q in queries]
if not normalized_queries:
return []
results = {}
with get_db() as db:
folders = db.query(Folder).filter_by(user_id=user_id).all()
for folder in folders:
if self.normalize_folder_name(folder.name) in normalized_queries:
results[folder.id] = FolderModel.model_validate(folder)
# get children folders
children = self.get_children_folders_by_id_and_user_id(
folder.id, user_id
)
for child in children:
results[child.id] = child
# Return the results as a list
if not results:
return []
else:
results = list(results.values())
return results
def search_folders_by_name_contains(
self, user_id: str, query: str
) -> list[FolderModel]:
"""
Partial match: normalized name contains (as substring) the normalized query.
"""
normalized_query = self.normalize_folder_name(query)
results = []
with get_db() as db:
folders = db.query(Folder).filter_by(user_id=user_id).all()
for folder in folders:
norm_name = self.normalize_folder_name(folder.name)
if normalized_query in norm_name:
results.append(FolderModel.model_validate(folder))
return results
Folders = FolderTable()
+56 -4
View File
@@ -105,9 +105,57 @@ class FunctionsTable:
else:
return None
except Exception as e:
print(f"Error creating tool: {e}")
log.exception(f"Error creating a new function: {e}")
return None
def sync_functions(
self, user_id: str, functions: list[FunctionModel]
) -> list[FunctionModel]:
# Synchronize functions for a user by updating existing ones, inserting new ones, and removing those that are no longer present.
try:
with get_db() as db:
# Get existing functions
existing_functions = db.query(Function).all()
existing_ids = {func.id for func in existing_functions}
# Prepare a set of new function IDs
new_function_ids = {func.id for func in functions}
# Update or insert functions
for func in functions:
if func.id in existing_ids:
db.query(Function).filter_by(id=func.id).update(
{
**func.model_dump(),
"user_id": user_id,
"updated_at": int(time.time()),
}
)
else:
new_func = Function(
**{
**func.model_dump(),
"user_id": user_id,
"updated_at": int(time.time()),
}
)
db.add(new_func)
# Remove functions that are no longer present
for func in existing_functions:
if func.id not in new_function_ids:
db.delete(func)
db.commit()
return [
FunctionModel.model_validate(func)
for func in db.query(Function).all()
]
except Exception as e:
log.exception(f"Error syncing functions for user {user_id}: {e}")
return []
def get_function_by_id(self, id: str) -> Optional[FunctionModel]:
try:
with get_db() as db:
@@ -170,7 +218,7 @@ class FunctionsTable:
function = db.get(Function, id)
return function.valves if function.valves else {}
except Exception as e:
print(f"An error occurred: {e}")
log.exception(f"Error getting function valves by id {id}: {e}")
return None
def update_function_valves_by_id(
@@ -202,7 +250,9 @@ class FunctionsTable:
return user_settings["functions"]["valves"].get(id, {})
except Exception as e:
print(f"An error occurred: {e}")
log.exception(
f"Error getting user values by id {id} and user id {user_id}: {e}"
)
return None
def update_user_valves_by_id_and_user_id(
@@ -225,7 +275,9 @@ class FunctionsTable:
return user_settings["functions"]["valves"][id]
except Exception as e:
print(f"An error occurred: {e}")
log.exception(
f"Error updating user valves by id {id} and user_id {user_id}: {e}"
)
return None
def update_function_by_id(self, id: str, updated: dict) -> Optional[FunctionModel]:
+121 -1
View File
@@ -83,10 +83,14 @@ class GroupForm(BaseModel):
permissions: Optional[dict] = None
class GroupUpdateForm(GroupForm):
class UserIdsForm(BaseModel):
user_ids: Optional[list[str]] = None
class GroupUpdateForm(GroupForm, UserIdsForm):
pass
class GroupTable:
def insert_new_group(
self, user_id: str, form_data: GroupForm
@@ -207,5 +211,121 @@ class GroupTable:
except Exception:
return False
def create_groups_by_group_names(
self, user_id: str, group_names: list[str]
) -> list[GroupModel]:
# check for existing groups
existing_groups = self.get_groups()
existing_group_names = {group.name for group in existing_groups}
new_groups = []
with get_db() as db:
for group_name in group_names:
if group_name not in existing_group_names:
new_group = GroupModel(
id=str(uuid.uuid4()),
user_id=user_id,
name=group_name,
description="",
created_at=int(time.time()),
updated_at=int(time.time()),
)
try:
result = Group(**new_group.model_dump())
db.add(result)
db.commit()
db.refresh(result)
new_groups.append(GroupModel.model_validate(result))
except Exception as e:
log.exception(e)
continue
return new_groups
def sync_groups_by_group_names(self, user_id: str, group_names: list[str]) -> bool:
with get_db() as db:
try:
groups = db.query(Group).filter(Group.name.in_(group_names)).all()
group_ids = [group.id for group in groups]
# Remove user from groups not in the new list
existing_groups = self.get_groups_by_member_id(user_id)
for group in existing_groups:
if group.id not in group_ids:
group.user_ids.remove(user_id)
db.query(Group).filter_by(id=group.id).update(
{
"user_ids": group.user_ids,
"updated_at": int(time.time()),
}
)
# Add user to new groups
for group in groups:
if user_id not in group.user_ids:
group.user_ids.append(user_id)
db.query(Group).filter_by(id=group.id).update(
{
"user_ids": group.user_ids,
"updated_at": int(time.time()),
}
)
db.commit()
return True
except Exception as e:
log.exception(e)
return False
def add_users_to_group(
self, id: str, user_ids: Optional[list[str]] = None
) -> Optional[GroupModel]:
try:
with get_db() as db:
group = db.query(Group).filter_by(id=id).first()
if not group:
return None
if not group.user_ids:
group.user_ids = []
for user_id in user_ids:
if user_id not in group.user_ids:
group.user_ids.append(user_id)
group.updated_at = int(time.time())
db.commit()
db.refresh(group)
return GroupModel.model_validate(group)
except Exception as e:
log.exception(e)
return None
def remove_users_from_group(
self, id: str, user_ids: Optional[list[str]] = None
) -> Optional[GroupModel]:
try:
with get_db() as db:
group = db.query(Group).filter_by(id=id).first()
if not group:
return None
if not group.user_ids:
return GroupModel.model_validate(group)
for user_id in user_ids:
if user_id in group.user_ids:
group.user_ids.remove(user_id)
group.updated_at = int(time.time())
db.commit()
db.refresh(group)
return GroupModel.model_validate(group)
except Exception as e:
log.exception(e)
return None
Groups = GroupTable()
+15 -5
View File
@@ -63,16 +63,21 @@ class MemoriesTable:
else:
return None
def update_memory_by_id(
def update_memory_by_id_and_user_id(
self,
id: str,
user_id: str,
content: str,
) -> Optional[MemoryModel]:
with get_db() as db:
try:
db.query(Memory).filter_by(id=id).update(
{"content": content, "updated_at": int(time.time())}
)
memory = db.get(Memory, id)
if not memory or memory.user_id != user_id:
return None
memory.content = content
memory.updated_at = int(time.time())
db.commit()
return self.get_memory_by_id(id)
except Exception:
@@ -126,7 +131,12 @@ class MemoriesTable:
def delete_memory_by_id_and_user_id(self, id: str, user_id: str) -> bool:
with get_db() as db:
try:
db.query(Memory).filter_by(id=id, user_id=user_id).delete()
memory = db.get(Memory, id)
if not memory or memory.user_id != user_id:
return None
# Delete the memory
db.delete(memory)
db.commit()
return True
+46 -3
View File
@@ -166,7 +166,7 @@ class ModelsTable:
else:
return None
except Exception as e:
print(e)
log.exception(f"Failed to insert a new model: {e}")
return None
def get_all_models(self) -> list[ModelModel]:
@@ -246,8 +246,7 @@ class ModelsTable:
db.refresh(model)
return ModelModel.model_validate(model)
except Exception as e:
print(e)
log.exception(f"Failed to update the model by id {id}: {e}")
return None
def delete_model_by_id(self, id: str) -> bool:
@@ -270,5 +269,49 @@ class ModelsTable:
except Exception:
return False
def sync_models(self, user_id: str, models: list[ModelModel]) -> list[ModelModel]:
try:
with get_db() as db:
# Get existing models
existing_models = db.query(Model).all()
existing_ids = {model.id for model in existing_models}
# Prepare a set of new model IDs
new_model_ids = {model.id for model in models}
# Update or insert models
for model in models:
if model.id in existing_ids:
db.query(Model).filter_by(id=model.id).update(
{
**model.model_dump(),
"user_id": user_id,
"updated_at": int(time.time()),
}
)
else:
new_model = Model(
**{
**model.model_dump(),
"user_id": user_id,
"updated_at": int(time.time()),
}
)
db.add(new_model)
# Remove models that are no longer present
for model in existing_models:
if model.id not in new_model_ids:
db.delete(model)
db.commit()
return [
ModelModel.model_validate(model) for model in db.query(Model).all()
]
except Exception as e:
log.exception(f"Error syncing models for user {user_id}: {e}")
return []
Models = ModelsTable()
+152
View File
@@ -0,0 +1,152 @@
import json
import time
import uuid
from typing import Optional
from open_webui.internal.db import Base, get_db
from open_webui.utils.access_control import has_access
from open_webui.models.users import Users, UserResponse
from pydantic import BaseModel, ConfigDict
from sqlalchemy import BigInteger, Boolean, Column, String, Text, JSON
from sqlalchemy import or_, func, select, and_, text
from sqlalchemy.sql import exists
####################
# Note DB Schema
####################
class Note(Base):
__tablename__ = "note"
id = Column(Text, primary_key=True)
user_id = Column(Text)
title = Column(Text)
data = Column(JSON, nullable=True)
meta = Column(JSON, nullable=True)
access_control = Column(JSON, nullable=True)
created_at = Column(BigInteger)
updated_at = Column(BigInteger)
class NoteModel(BaseModel):
model_config = ConfigDict(from_attributes=True)
id: str
user_id: str
title: str
data: Optional[dict] = None
meta: Optional[dict] = None
access_control: Optional[dict] = None
created_at: int # timestamp in epoch
updated_at: int # timestamp in epoch
####################
# Forms
####################
class NoteForm(BaseModel):
title: str
data: Optional[dict] = None
meta: Optional[dict] = None
access_control: Optional[dict] = None
class NoteUpdateForm(BaseModel):
title: Optional[str] = None
data: Optional[dict] = None
meta: Optional[dict] = None
access_control: Optional[dict] = None
class NoteUserResponse(NoteModel):
user: Optional[UserResponse] = None
class NoteTable:
def insert_new_note(
self,
form_data: NoteForm,
user_id: str,
) -> Optional[NoteModel]:
with get_db() as db:
note = NoteModel(
**{
"id": str(uuid.uuid4()),
"user_id": user_id,
**form_data.model_dump(),
"created_at": int(time.time_ns()),
"updated_at": int(time.time_ns()),
}
)
new_note = Note(**note.model_dump())
db.add(new_note)
db.commit()
return note
def get_notes(self) -> list[NoteModel]:
with get_db() as db:
notes = db.query(Note).order_by(Note.updated_at.desc()).all()
return [NoteModel.model_validate(note) for note in notes]
def get_notes_by_user_id(
self, user_id: str, permission: str = "write"
) -> list[NoteModel]:
notes = self.get_notes()
return [
note
for note in notes
if note.user_id == user_id
or has_access(user_id, permission, note.access_control)
]
def get_note_by_id(self, id: str) -> Optional[NoteModel]:
with get_db() as db:
note = db.query(Note).filter(Note.id == id).first()
return NoteModel.model_validate(note) if note else None
def update_note_by_id(
self, id: str, form_data: NoteUpdateForm
) -> Optional[NoteModel]:
with get_db() as db:
note = db.query(Note).filter(Note.id == id).first()
if not note:
return None
form_data = form_data.model_dump(exclude_unset=True)
if "title" in form_data:
note.title = form_data["title"]
if "data" in form_data:
note.data = {**note.data, **form_data["data"]}
if "meta" in form_data:
note.meta = {**note.meta, **form_data["meta"]}
if "access_control" in form_data:
note.access_control = form_data["access_control"]
note.updated_at = int(time.time_ns())
db.commit()
return NoteModel.model_validate(note) if note else None
def delete_note_by_id(self, id: str):
with get_db() as db:
db.query(Note).filter(Note.id == id).delete()
db.commit()
return True
Notes = NoteTable()
+1 -1
View File
@@ -61,7 +61,7 @@ class TagTable:
else:
return None
except Exception as e:
print(e)
log.exception(f"Error inserting a new tag: {e}")
return None
def get_tag_by_name_and_user_id(
+8 -4
View File
@@ -131,7 +131,7 @@ class ToolsTable:
else:
return None
except Exception as e:
print(f"Error creating tool: {e}")
log.exception(f"Error creating a new tool: {e}")
return None
def get_tool_by_id(self, id: str) -> Optional[ToolModel]:
@@ -175,7 +175,7 @@ class ToolsTable:
tool = db.get(Tool, id)
return tool.valves if tool.valves else {}
except Exception as e:
print(f"An error occurred: {e}")
log.exception(f"Error getting tool valves by id {id}: {e}")
return None
def update_tool_valves_by_id(self, id: str, valves: dict) -> Optional[ToolValves]:
@@ -204,7 +204,9 @@ class ToolsTable:
return user_settings["tools"]["valves"].get(id, {})
except Exception as e:
print(f"An error occurred: {e}")
log.exception(
f"Error getting user values by id {id} and user_id {user_id}: {e}"
)
return None
def update_user_valves_by_id_and_user_id(
@@ -227,7 +229,9 @@ class ToolsTable:
return user_settings["tools"]["valves"][id]
except Exception as e:
print(f"An error occurred: {e}")
log.exception(
f"Error updating user valves by id {id} and user_id {user_id}: {e}"
)
return None
def update_tool_by_id(self, id: str, updated: dict) -> Optional[ToolModel]:
+110 -6
View File
@@ -10,6 +10,8 @@ from open_webui.models.groups import Groups
from pydantic import BaseModel, ConfigDict
from sqlalchemy import BigInteger, Column, String, Text
from sqlalchemy import or_
####################
# User DB Schema
@@ -67,6 +69,23 @@ class UserModel(BaseModel):
####################
class UserListResponse(BaseModel):
users: list[UserModel]
total: int
class UserInfoResponse(BaseModel):
id: str
name: str
email: str
role: str
class UserInfoListResponse(BaseModel):
users: list[UserInfoResponse]
total: int
class UserResponse(BaseModel):
id: str
name: str
@@ -88,6 +107,7 @@ class UserRoleUpdateForm(BaseModel):
class UserUpdateForm(BaseModel):
role: str
name: str
email: str
profile_image_url: str
@@ -160,11 +180,63 @@ class UsersTable:
return None
def get_users(
self, skip: Optional[int] = None, limit: Optional[int] = None
) -> list[UserModel]:
self,
filter: Optional[dict] = None,
skip: Optional[int] = None,
limit: Optional[int] = None,
) -> UserListResponse:
with get_db() as db:
query = db.query(User)
query = db.query(User).order_by(User.created_at.desc())
if filter:
query_key = filter.get("query")
if query_key:
query = query.filter(
or_(
User.name.ilike(f"%{query_key}%"),
User.email.ilike(f"%{query_key}%"),
)
)
order_by = filter.get("order_by")
direction = filter.get("direction")
if order_by == "name":
if direction == "asc":
query = query.order_by(User.name.asc())
else:
query = query.order_by(User.name.desc())
elif order_by == "email":
if direction == "asc":
query = query.order_by(User.email.asc())
else:
query = query.order_by(User.email.desc())
elif order_by == "created_at":
if direction == "asc":
query = query.order_by(User.created_at.asc())
else:
query = query.order_by(User.created_at.desc())
elif order_by == "last_active_at":
if direction == "asc":
query = query.order_by(User.last_active_at.asc())
else:
query = query.order_by(User.last_active_at.desc())
elif order_by == "updated_at":
if direction == "asc":
query = query.order_by(User.updated_at.asc())
else:
query = query.order_by(User.updated_at.desc())
elif order_by == "role":
if direction == "asc":
query = query.order_by(User.role.asc())
else:
query = query.order_by(User.role.desc())
else:
query = query.order_by(User.created_at.desc())
if skip:
query = query.offset(skip)
@@ -172,8 +244,10 @@ class UsersTable:
query = query.limit(limit)
users = query.all()
return [UserModel.model_validate(user) for user in users]
return {
"users": [UserModel.model_validate(user) for user in users],
"total": db.query(User).count(),
}
def get_users_by_user_ids(self, user_ids: list[str]) -> list[UserModel]:
with get_db() as db:
@@ -184,6 +258,10 @@ class UsersTable:
with get_db() as db:
return db.query(User).count()
def has_users(self) -> bool:
with get_db() as db:
return db.query(db.query(User).exists()).scalar()
def get_first_user(self) -> UserModel:
try:
with get_db() as db:
@@ -271,6 +349,24 @@ class UsersTable:
except Exception:
return None
def update_user_settings_by_id(self, id: str, updated: dict) -> Optional[UserModel]:
try:
with get_db() as db:
user_settings = db.query(User).filter_by(id=id).first().settings
if user_settings is None:
user_settings = {}
user_settings.update(updated)
db.query(User).filter_by(id=id).update({"settings": user_settings})
db.commit()
user = db.query(User).filter_by(id=id).first()
return UserModel.model_validate(user)
except Exception:
return None
def delete_user_by_id(self, id: str) -> bool:
try:
# Remove User from Groups
@@ -290,7 +386,7 @@ class UsersTable:
except Exception:
return False
def update_user_api_key_by_id(self, id: str, api_key: str) -> str:
def update_user_api_key_by_id(self, id: str, api_key: str) -> bool:
try:
with get_db() as db:
result = db.query(User).filter_by(id=id).update({"api_key": api_key})
@@ -312,5 +408,13 @@ class UsersTable:
users = db.query(User).filter(User.id.in_(user_ids)).all()
return [user.id for user in users]
def get_super_admin_user(self) -> Optional[UserModel]:
with get_db() as db:
user = db.query(User).filter_by(role="admin").first()
if user:
return UserModel.model_validate(user)
else:
return None
Users = UsersTable()
@@ -0,0 +1,278 @@
import os
import time
import requests
import logging
import json
from typing import List, Optional
from langchain_core.documents import Document
from fastapi import HTTPException, status
log = logging.getLogger(__name__)
class DatalabMarkerLoader:
def __init__(
self,
file_path: str,
api_key: str,
api_base_url: str,
additional_config: Optional[str] = None,
use_llm: bool = False,
skip_cache: bool = False,
force_ocr: bool = False,
paginate: bool = False,
strip_existing_ocr: bool = False,
disable_image_extraction: bool = False,
format_lines: bool = False,
output_format: str = None,
):
self.file_path = file_path
self.api_key = api_key
self.api_base_url = api_base_url
self.additional_config = additional_config
self.use_llm = use_llm
self.skip_cache = skip_cache
self.force_ocr = force_ocr
self.paginate = paginate
self.strip_existing_ocr = strip_existing_ocr
self.disable_image_extraction = disable_image_extraction
self.format_lines = format_lines
self.output_format = output_format
def _get_mime_type(self, filename: str) -> str:
ext = filename.rsplit(".", 1)[-1].lower()
mime_map = {
"pdf": "application/pdf",
"xls": "application/vnd.ms-excel",
"xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"ods": "application/vnd.oasis.opendocument.spreadsheet",
"doc": "application/msword",
"docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"odt": "application/vnd.oasis.opendocument.text",
"ppt": "application/vnd.ms-powerpoint",
"pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
"odp": "application/vnd.oasis.opendocument.presentation",
"html": "text/html",
"epub": "application/epub+zip",
"png": "image/png",
"jpeg": "image/jpeg",
"jpg": "image/jpeg",
"webp": "image/webp",
"gif": "image/gif",
"tiff": "image/tiff",
}
return mime_map.get(ext, "application/octet-stream")
def check_marker_request_status(self, request_id: str) -> dict:
url = f"{self.api_base_url}/marker/{request_id}"
headers = {"X-Api-Key": self.api_key}
try:
response = requests.get(url, headers=headers)
response.raise_for_status()
result = response.json()
log.info(f"Marker API status check for request {request_id}: {result}")
return result
except requests.HTTPError as e:
log.error(f"Error checking Marker request status: {e}")
raise HTTPException(
status.HTTP_502_BAD_GATEWAY,
detail=f"Failed to check Marker request: {e}",
)
except ValueError as e:
log.error(f"Invalid JSON checking Marker request: {e}")
raise HTTPException(
status.HTTP_502_BAD_GATEWAY, detail=f"Invalid JSON: {e}"
)
def load(self) -> List[Document]:
filename = os.path.basename(self.file_path)
mime_type = self._get_mime_type(filename)
headers = {"X-Api-Key": self.api_key}
form_data = {
"use_llm": str(self.use_llm).lower(),
"skip_cache": str(self.skip_cache).lower(),
"force_ocr": str(self.force_ocr).lower(),
"paginate": str(self.paginate).lower(),
"strip_existing_ocr": str(self.strip_existing_ocr).lower(),
"disable_image_extraction": str(self.disable_image_extraction).lower(),
"format_lines": str(self.format_lines).lower(),
"output_format": self.output_format,
}
if self.additional_config and self.additional_config.strip():
form_data["additional_config"] = self.additional_config
log.info(
f"Datalab Marker POST request parameters: {{'filename': '{filename}', 'mime_type': '{mime_type}', **{form_data}}}"
)
try:
with open(self.file_path, "rb") as f:
files = {"file": (filename, f, mime_type)}
response = requests.post(
f"{self.api_base_url}/marker",
data=form_data,
files=files,
headers=headers,
)
response.raise_for_status()
result = response.json()
except FileNotFoundError:
raise HTTPException(
status.HTTP_404_NOT_FOUND, detail=f"File not found: {self.file_path}"
)
except requests.HTTPError as e:
raise HTTPException(
status.HTTP_400_BAD_REQUEST,
detail=f"Datalab Marker request failed: {e}",
)
except ValueError as e:
raise HTTPException(
status.HTTP_502_BAD_GATEWAY, detail=f"Invalid JSON response: {e}"
)
except Exception as e:
raise HTTPException(status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e))
if not result.get("success"):
raise HTTPException(
status.HTTP_400_BAD_REQUEST,
detail=f"Datalab Marker request failed: {result.get('error', 'Unknown error')}",
)
check_url = result.get("request_check_url")
request_id = result.get("request_id")
# Check if this is a direct response (self-hosted) or polling response (DataLab)
if check_url:
# DataLab polling pattern
for _ in range(300): # Up to 10 minutes
time.sleep(2)
try:
poll_response = requests.get(check_url, headers=headers)
poll_response.raise_for_status()
poll_result = poll_response.json()
except (requests.HTTPError, ValueError) as e:
raw_body = poll_response.text
log.error(f"Polling error: {e}, response body: {raw_body}")
raise HTTPException(
status.HTTP_502_BAD_GATEWAY, detail=f"Polling failed: {e}"
)
status_val = poll_result.get("status")
success_val = poll_result.get("success")
if status_val == "complete":
summary = {
k: poll_result.get(k)
for k in (
"status",
"output_format",
"success",
"error",
"page_count",
"total_cost",
)
}
log.info(
f"Marker processing completed successfully: {json.dumps(summary, indent=2)}"
)
break
if status_val == "failed" or success_val is False:
log.error(
f"Marker poll failed full response: {json.dumps(poll_result, indent=2)}"
)
error_msg = (
poll_result.get("error")
or "Marker returned failure without error message"
)
raise HTTPException(
status.HTTP_400_BAD_REQUEST,
detail=f"Marker processing failed: {error_msg}",
)
else:
raise HTTPException(
status.HTTP_504_GATEWAY_TIMEOUT,
detail="Marker processing timed out",
)
if not poll_result.get("success", False):
error_msg = poll_result.get("error") or "Unknown processing error"
raise HTTPException(
status.HTTP_400_BAD_REQUEST,
detail=f"Final processing failed: {error_msg}",
)
# DataLab format - content in format-specific fields
content_key = self.output_format.lower()
raw_content = poll_result.get(content_key)
final_result = poll_result
else:
# Self-hosted direct response - content in "output" field
if "output" in result:
log.info("Self-hosted Marker returned direct response without polling")
raw_content = result.get("output")
final_result = result
else:
available_fields = (
list(result.keys())
if isinstance(result, dict)
else "non-dict response"
)
raise HTTPException(
status.HTTP_502_BAD_GATEWAY,
detail=f"Custom Marker endpoint returned success but no 'output' field found. Available fields: {available_fields}. Expected either 'request_check_url' for polling or 'output' field for direct response.",
)
if self.output_format.lower() == "json":
full_text = json.dumps(raw_content, indent=2)
elif self.output_format.lower() in {"markdown", "html"}:
full_text = str(raw_content).strip()
else:
raise HTTPException(
status.HTTP_400_BAD_REQUEST,
detail=f"Unsupported output format: {self.output_format}",
)
if not full_text:
raise HTTPException(
status.HTTP_400_BAD_REQUEST,
detail="Marker returned empty content",
)
marker_output_dir = os.path.join("/app/backend/data/uploads", "marker_output")
os.makedirs(marker_output_dir, exist_ok=True)
file_ext_map = {"markdown": "md", "json": "json", "html": "html"}
file_ext = file_ext_map.get(self.output_format.lower(), "txt")
output_filename = f"{os.path.splitext(filename)[0]}.{file_ext}"
output_path = os.path.join(marker_output_dir, output_filename)
try:
with open(output_path, "w", encoding="utf-8") as f:
f.write(full_text)
log.info(f"Saved Marker output to: {output_path}")
except Exception as e:
log.warning(f"Failed to write marker output to disk: {e}")
metadata = {
"source": filename,
"output_format": final_result.get("output_format", self.output_format),
"page_count": final_result.get("page_count", 0),
"processed_with_llm": self.use_llm,
"request_id": request_id or "",
}
images = final_result.get("images", {})
if images:
metadata["image_count"] = len(images)
metadata["images"] = json.dumps(list(images.keys()))
for k, v in metadata.items():
if isinstance(v, (dict, list)):
metadata[k] = json.dumps(v)
elif v is None:
metadata[k] = ""
return [Document(page_content=full_text, metadata=metadata)]
@@ -0,0 +1,83 @@
import requests
import logging, os
from typing import Iterator, List, Union
from langchain_core.document_loaders import BaseLoader
from langchain_core.documents import Document
from open_webui.env import SRC_LOG_LEVELS
log = logging.getLogger(__name__)
log.setLevel(SRC_LOG_LEVELS["RAG"])
class ExternalDocumentLoader(BaseLoader):
def __init__(
self,
file_path,
url: str,
api_key: str,
mime_type=None,
**kwargs,
) -> None:
self.url = url
self.api_key = api_key
self.file_path = file_path
self.mime_type = mime_type
def load(self) -> List[Document]:
with open(self.file_path, "rb") as f:
data = f.read()
headers = {}
if self.mime_type is not None:
headers["Content-Type"] = self.mime_type
if self.api_key is not None:
headers["Authorization"] = f"Bearer {self.api_key}"
try:
headers["X-Filename"] = os.path.basename(self.file_path)
except:
pass
url = self.url
if url.endswith("/"):
url = url[:-1]
try:
response = requests.put(f"{url}/process", data=data, headers=headers)
except Exception as e:
log.error(f"Error connecting to endpoint: {e}")
raise Exception(f"Error connecting to endpoint: {e}")
if response.ok:
response_data = response.json()
if response_data:
if isinstance(response_data, dict):
return [
Document(
page_content=response_data.get("page_content"),
metadata=response_data.get("metadata"),
)
]
elif isinstance(response_data, list):
documents = []
for document in response_data:
documents.append(
Document(
page_content=document.get("page_content"),
metadata=document.get("metadata"),
)
)
return documents
else:
raise Exception("Error loading document: Unable to parse content")
else:
raise Exception("Error loading document: No content returned")
else:
raise Exception(
f"Error loading document: {response.status_code} {response.text}"
)
@@ -0,0 +1,53 @@
import requests
import logging
from typing import Iterator, List, Union
from langchain_core.document_loaders import BaseLoader
from langchain_core.documents import Document
from open_webui.env import SRC_LOG_LEVELS
log = logging.getLogger(__name__)
log.setLevel(SRC_LOG_LEVELS["RAG"])
class ExternalWebLoader(BaseLoader):
def __init__(
self,
web_paths: Union[str, List[str]],
external_url: str,
external_api_key: str,
continue_on_failure: bool = True,
**kwargs,
) -> None:
self.external_url = external_url
self.external_api_key = external_api_key
self.urls = web_paths if isinstance(web_paths, list) else [web_paths]
self.continue_on_failure = continue_on_failure
def lazy_load(self) -> Iterator[Document]:
batch_size = 20
for i in range(0, len(self.urls), batch_size):
urls = self.urls[i : i + batch_size]
try:
response = requests.post(
self.external_url,
headers={
"User-Agent": "Open WebUI (https://github.com/open-webui/open-webui) External Web Loader",
"Authorization": f"Bearer {self.external_api_key}",
},
json={
"urls": urls,
},
)
response.raise_for_status()
results = response.json()
for result in results:
yield Document(
page_content=result.get("page_content", ""),
metadata=result.get("metadata", {}),
)
except Exception as e:
if self.continue_on_failure:
log.error(f"Error extracting content from batch {urls}: {e}")
else:
raise e
+228 -12
View File
@@ -2,8 +2,10 @@ import requests
import logging
import ftfy
import sys
import json
from langchain_community.document_loaders import (
AzureAIDocumentIntelligenceLoader,
BSHTMLLoader,
CSVLoader,
Docx2txtLoader,
@@ -12,13 +14,20 @@ from langchain_community.document_loaders import (
TextLoader,
UnstructuredEPubLoader,
UnstructuredExcelLoader,
UnstructuredMarkdownLoader,
UnstructuredODTLoader,
UnstructuredPowerPointLoader,
UnstructuredRSTLoader,
UnstructuredXMLLoader,
YoutubeLoader,
)
from langchain_core.documents import Document
from open_webui.retrieval.loaders.external_document import ExternalDocumentLoader
from open_webui.retrieval.loaders.mistral import MistralLoader
from open_webui.retrieval.loaders.datalab_marker import DatalabMarkerLoader
from open_webui.env import SRC_LOG_LEVELS, GLOBAL_LOG_LEVEL
logging.basicConfig(stream=sys.stdout, level=GLOBAL_LOG_LEVEL)
@@ -68,7 +77,6 @@ known_source_ext = [
"swift",
"vue",
"svelte",
"msg",
"ex",
"exs",
"erl",
@@ -76,15 +84,18 @@ known_source_ext = [
"jsx",
"hs",
"lhs",
"json",
]
class TikaLoader:
def __init__(self, url, file_path, mime_type=None):
def __init__(self, url, file_path, mime_type=None, extract_images=None):
self.url = url
self.file_path = file_path
self.mime_type = mime_type
self.extract_images = extract_images
def load(self) -> list[Document]:
with open(self.file_path, "rb") as f:
data = f.read()
@@ -94,6 +105,9 @@ class TikaLoader:
else:
headers = {}
if self.extract_images == True:
headers["X-Tika-PDFextractInlineImages"] = "true"
endpoint = self.url
if not endpoint.endswith("/"):
endpoint += "/"
@@ -103,7 +117,7 @@ class TikaLoader:
if r.ok:
raw_metadata = r.json()
text = raw_metadata.get("X-TIKA:content", "<No text content found>")
text = raw_metadata.get("X-TIKA:content", "<No text content found>").strip()
if "Content-Type" in raw_metadata:
headers["Content-Type"] = raw_metadata["Content-Type"]
@@ -115,6 +129,83 @@ class TikaLoader:
raise Exception(f"Error calling Tika: {r.reason}")
class DoclingLoader:
def __init__(self, url, file_path=None, mime_type=None, params=None):
self.url = url.rstrip("/")
self.file_path = file_path
self.mime_type = mime_type
self.params = params or {}
def load(self) -> list[Document]:
with open(self.file_path, "rb") as f:
files = {
"files": (
self.file_path,
f,
self.mime_type or "application/octet-stream",
)
}
params = {"image_export_mode": "placeholder", "table_mode": "accurate"}
if self.params:
if self.params.get("do_picture_description"):
params["do_picture_description"] = self.params.get(
"do_picture_description"
)
picture_description_mode = self.params.get(
"picture_description_mode", ""
).lower()
if picture_description_mode == "local" and self.params.get(
"picture_description_local", {}
):
params["picture_description_local"] = json.dumps(
self.params.get("picture_description_local", {})
)
elif picture_description_mode == "api" and self.params.get(
"picture_description_api", {}
):
params["picture_description_api"] = json.dumps(
self.params.get("picture_description_api", {})
)
if self.params.get("ocr_engine") and self.params.get("ocr_lang"):
params["ocr_engine"] = self.params.get("ocr_engine")
params["ocr_lang"] = [
lang.strip()
for lang in self.params.get("ocr_lang").split(",")
if lang.strip()
]
endpoint = f"{self.url}/v1/convert/file"
r = requests.post(endpoint, files=files, data=params)
if r.ok:
result = r.json()
document_data = result.get("document", {})
text = document_data.get("md_content", "<No text content found>")
metadata = {"Content-Type": self.mime_type} if self.mime_type else {}
log.debug("Docling extracted text: %s", text)
return [Document(page_content=text, metadata=metadata)]
else:
error_msg = f"Error calling Docling API: {r.reason}"
if r.text:
try:
error_data = r.json()
if "detail" in error_data:
error_msg += f" - {error_data['detail']}"
except Exception:
error_msg += f" - {r.text}"
raise Exception(f"Error calling Docling: {error_msg}")
class Loader:
def __init__(self, engine: str = "", **kwargs):
self.engine = engine
@@ -133,27 +224,152 @@ class Loader:
for doc in docs
]
def _is_text_file(self, file_ext: str, file_content_type: str) -> bool:
return file_ext in known_source_ext or (
file_content_type
and file_content_type.find("text/") >= 0
# Avoid text/html files being detected as text
and not file_content_type.find("html") >= 0
)
def _get_loader(self, filename: str, file_content_type: str, file_path: str):
file_ext = filename.split(".")[-1].lower()
if self.engine == "tika" and self.kwargs.get("TIKA_SERVER_URL"):
if file_ext in known_source_ext or (
file_content_type and file_content_type.find("text/") >= 0
):
if (
self.engine == "external"
and self.kwargs.get("EXTERNAL_DOCUMENT_LOADER_URL")
and self.kwargs.get("EXTERNAL_DOCUMENT_LOADER_API_KEY")
):
loader = ExternalDocumentLoader(
file_path=file_path,
url=self.kwargs.get("EXTERNAL_DOCUMENT_LOADER_URL"),
api_key=self.kwargs.get("EXTERNAL_DOCUMENT_LOADER_API_KEY"),
mime_type=file_content_type,
)
elif self.engine == "tika" and self.kwargs.get("TIKA_SERVER_URL"):
if self._is_text_file(file_ext, file_content_type):
loader = TextLoader(file_path, autodetect_encoding=True)
else:
loader = TikaLoader(
url=self.kwargs.get("TIKA_SERVER_URL"),
file_path=file_path,
mime_type=file_content_type,
extract_images=self.kwargs.get("PDF_EXTRACT_IMAGES"),
)
elif (
self.engine == "datalab_marker"
and self.kwargs.get("DATALAB_MARKER_API_KEY")
and file_ext
in [
"pdf",
"xls",
"xlsx",
"ods",
"doc",
"docx",
"odt",
"ppt",
"pptx",
"odp",
"html",
"epub",
"png",
"jpeg",
"jpg",
"webp",
"gif",
"tiff",
]
):
api_base_url = self.kwargs.get("DATALAB_MARKER_API_BASE_URL", "")
if not api_base_url or api_base_url.strip() == "":
api_base_url = "https://www.datalab.to/api/v1"
loader = DatalabMarkerLoader(
file_path=file_path,
api_key=self.kwargs["DATALAB_MARKER_API_KEY"],
api_base_url=api_base_url,
additional_config=self.kwargs.get("DATALAB_MARKER_ADDITIONAL_CONFIG"),
use_llm=self.kwargs.get("DATALAB_MARKER_USE_LLM", False),
skip_cache=self.kwargs.get("DATALAB_MARKER_SKIP_CACHE", False),
force_ocr=self.kwargs.get("DATALAB_MARKER_FORCE_OCR", False),
paginate=self.kwargs.get("DATALAB_MARKER_PAGINATE", False),
strip_existing_ocr=self.kwargs.get(
"DATALAB_MARKER_STRIP_EXISTING_OCR", False
),
disable_image_extraction=self.kwargs.get(
"DATALAB_MARKER_DISABLE_IMAGE_EXTRACTION", False
),
format_lines=self.kwargs.get("DATALAB_MARKER_FORMAT_LINES", False),
output_format=self.kwargs.get(
"DATALAB_MARKER_OUTPUT_FORMAT", "markdown"
),
)
elif self.engine == "docling" and self.kwargs.get("DOCLING_SERVER_URL"):
if self._is_text_file(file_ext, file_content_type):
loader = TextLoader(file_path, autodetect_encoding=True)
else:
# Build params for DoclingLoader
params = self.kwargs.get("DOCLING_PARAMS", {})
if not isinstance(params, dict):
try:
params = json.loads(params)
except json.JSONDecodeError:
log.error("Invalid DOCLING_PARAMS format, expected JSON object")
params = {}
loader = DoclingLoader(
url=self.kwargs.get("DOCLING_SERVER_URL"),
file_path=file_path,
mime_type=file_content_type,
params=params,
)
elif (
self.engine == "document_intelligence"
and self.kwargs.get("DOCUMENT_INTELLIGENCE_ENDPOINT") != ""
and self.kwargs.get("DOCUMENT_INTELLIGENCE_KEY") != ""
and (
file_ext in ["pdf", "xls", "xlsx", "docx", "ppt", "pptx"]
or file_content_type
in [
"application/vnd.ms-excel",
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"application/vnd.ms-powerpoint",
"application/vnd.openxmlformats-officedocument.presentationml.presentation",
]
)
):
loader = AzureAIDocumentIntelligenceLoader(
file_path=file_path,
api_endpoint=self.kwargs.get("DOCUMENT_INTELLIGENCE_ENDPOINT"),
api_key=self.kwargs.get("DOCUMENT_INTELLIGENCE_KEY"),
)
elif (
self.engine == "mistral_ocr"
and self.kwargs.get("MISTRAL_OCR_API_KEY") != ""
and file_ext
in ["pdf"] # Mistral OCR currently only supports PDF and images
):
loader = MistralLoader(
api_key=self.kwargs.get("MISTRAL_OCR_API_KEY"), file_path=file_path
)
elif (
self.engine == "external"
and self.kwargs.get("MISTRAL_OCR_API_KEY") != ""
and file_ext
in ["pdf"] # Mistral OCR currently only supports PDF and images
):
loader = MistralLoader(
api_key=self.kwargs.get("MISTRAL_OCR_API_KEY"), file_path=file_path
)
else:
if file_ext == "pdf":
loader = PyPDFLoader(
file_path, extract_images=self.kwargs.get("PDF_EXTRACT_IMAGES")
)
elif file_ext == "csv":
loader = CSVLoader(file_path)
loader = CSVLoader(file_path, autodetect_encoding=True)
elif file_ext == "rst":
loader = UnstructuredRSTLoader(file_path, mode="elements")
elif file_ext == "xml":
@@ -182,9 +398,9 @@ class Loader:
loader = UnstructuredPowerPointLoader(file_path)
elif file_ext == "msg":
loader = OutlookMessageLoader(file_path)
elif file_ext in known_source_ext or (
file_content_type and file_content_type.find("text/") >= 0
):
elif file_ext == "odt":
loader = UnstructuredODTLoader(file_path)
elif self._is_text_file(file_ext, file_content_type):
loader = TextLoader(file_path, autodetect_encoding=True)
else:
loader = TextLoader(file_path, autodetect_encoding=True)
@@ -0,0 +1,768 @@
import requests
import aiohttp
import asyncio
import logging
import os
import sys
import time
from typing import List, Dict, Any
from contextlib import asynccontextmanager
from langchain_core.documents import Document
from open_webui.env import SRC_LOG_LEVELS, GLOBAL_LOG_LEVEL
logging.basicConfig(stream=sys.stdout, level=GLOBAL_LOG_LEVEL)
log = logging.getLogger(__name__)
log.setLevel(SRC_LOG_LEVELS["RAG"])
class MistralLoader:
"""
Enhanced Mistral OCR loader with both sync and async support.
Loads documents by processing them through the Mistral OCR API.
Performance Optimizations:
- Differentiated timeouts for different operations
- Intelligent retry logic with exponential backoff
- Memory-efficient file streaming for large files
- Connection pooling and keepalive optimization
- Semaphore-based concurrency control for batch processing
- Enhanced error handling with retryable error classification
"""
BASE_API_URL = "https://api.mistral.ai/v1"
def __init__(
self,
api_key: str,
file_path: str,
timeout: int = 300, # 5 minutes default
max_retries: int = 3,
enable_debug_logging: bool = False,
):
"""
Initializes the loader with enhanced features.
Args:
api_key: Your Mistral API key.
file_path: The local path to the PDF file to process.
timeout: Request timeout in seconds.
max_retries: Maximum number of retry attempts.
enable_debug_logging: Enable detailed debug logs.
"""
if not api_key:
raise ValueError("API key cannot be empty.")
if not os.path.exists(file_path):
raise FileNotFoundError(f"File not found at {file_path}")
self.api_key = api_key
self.file_path = file_path
self.timeout = timeout
self.max_retries = max_retries
self.debug = enable_debug_logging
# PERFORMANCE OPTIMIZATION: Differentiated timeouts for different operations
# This prevents long-running OCR operations from affecting quick operations
# and improves user experience by failing fast on operations that should be quick
self.upload_timeout = min(
timeout, 120
) # Cap upload at 2 minutes - prevents hanging on large files
self.url_timeout = (
30 # URL requests should be fast - fail quickly if API is slow
)
self.ocr_timeout = (
timeout # OCR can take the full timeout - this is the heavy operation
)
self.cleanup_timeout = (
30 # Cleanup should be quick - don't hang on file deletion
)
# PERFORMANCE OPTIMIZATION: Pre-compute file info to avoid repeated filesystem calls
# This avoids multiple os.path.basename() and os.path.getsize() calls during processing
self.file_name = os.path.basename(file_path)
self.file_size = os.path.getsize(file_path)
# ENHANCEMENT: Added User-Agent for better API tracking and debugging
self.headers = {
"Authorization": f"Bearer {self.api_key}",
"User-Agent": "OpenWebUI-MistralLoader/2.0", # Helps API provider track usage
}
def _debug_log(self, message: str, *args) -> None:
"""
PERFORMANCE OPTIMIZATION: Conditional debug logging for performance.
Only processes debug messages when debug mode is enabled, avoiding
string formatting overhead in production environments.
"""
if self.debug:
log.debug(message, *args)
def _handle_response(self, response: requests.Response) -> Dict[str, Any]:
"""Checks response status and returns JSON content."""
try:
response.raise_for_status() # Raises HTTPError for bad responses (4xx or 5xx)
# Handle potential empty responses for certain successful requests (e.g., DELETE)
if response.status_code == 204 or not response.content:
return {} # Return empty dict if no content
return response.json()
except requests.exceptions.HTTPError as http_err:
log.error(f"HTTP error occurred: {http_err} - Response: {response.text}")
raise
except requests.exceptions.RequestException as req_err:
log.error(f"Request exception occurred: {req_err}")
raise
except ValueError as json_err: # Includes JSONDecodeError
log.error(f"JSON decode error: {json_err} - Response: {response.text}")
raise # Re-raise after logging
async def _handle_response_async(
self, response: aiohttp.ClientResponse
) -> Dict[str, Any]:
"""Async version of response handling with better error info."""
try:
response.raise_for_status()
# Check content type
content_type = response.headers.get("content-type", "")
if "application/json" not in content_type:
if response.status == 204:
return {}
text = await response.text()
raise ValueError(
f"Unexpected content type: {content_type}, body: {text[:200]}..."
)
return await response.json()
except aiohttp.ClientResponseError as e:
error_text = await response.text() if response else "No response"
log.error(f"HTTP {e.status}: {e.message} - Response: {error_text[:500]}")
raise
except aiohttp.ClientError as e:
log.error(f"Client error: {e}")
raise
except Exception as e:
log.error(f"Unexpected error processing response: {e}")
raise
def _is_retryable_error(self, error: Exception) -> bool:
"""
ENHANCEMENT: Intelligent error classification for retry logic.
Determines if an error is retryable based on its type and status code.
This prevents wasting time retrying errors that will never succeed
(like authentication errors) while ensuring transient errors are retried.
Retryable errors:
- Network connection errors (temporary network issues)
- Timeouts (server might be temporarily overloaded)
- Server errors (5xx status codes - server-side issues)
- Rate limiting (429 status - temporary throttling)
Non-retryable errors:
- Authentication errors (401, 403 - won't fix with retry)
- Bad request errors (400 - malformed request)
- Not found errors (404 - resource doesn't exist)
"""
if isinstance(error, requests.exceptions.ConnectionError):
return True # Network issues are usually temporary
if isinstance(error, requests.exceptions.Timeout):
return True # Timeouts might resolve on retry
if isinstance(error, requests.exceptions.HTTPError):
# Only retry on server errors (5xx) or rate limits (429)
if hasattr(error, "response") and error.response is not None:
status_code = error.response.status_code
return status_code >= 500 or status_code == 429
return False
if isinstance(
error, (aiohttp.ClientConnectionError, aiohttp.ServerTimeoutError)
):
return True # Async network/timeout errors are retryable
if isinstance(error, aiohttp.ClientResponseError):
return error.status >= 500 or error.status == 429
return False # All other errors are non-retryable
def _retry_request_sync(self, request_func, *args, **kwargs):
"""
ENHANCEMENT: Synchronous retry logic with intelligent error classification.
Uses exponential backoff with jitter to avoid thundering herd problems.
The wait time increases exponentially but is capped at 30 seconds to
prevent excessive delays. Only retries errors that are likely to succeed
on subsequent attempts.
"""
for attempt in range(self.max_retries):
try:
return request_func(*args, **kwargs)
except Exception as e:
if attempt == self.max_retries - 1 or not self._is_retryable_error(e):
raise
# PERFORMANCE OPTIMIZATION: Exponential backoff with cap
# Prevents overwhelming the server while ensuring reasonable retry delays
wait_time = min((2**attempt) + 0.5, 30) # Cap at 30 seconds
log.warning(
f"Retryable error (attempt {attempt + 1}/{self.max_retries}): {e}. "
f"Retrying in {wait_time}s..."
)
time.sleep(wait_time)
async def _retry_request_async(self, request_func, *args, **kwargs):
"""
ENHANCEMENT: Async retry logic with intelligent error classification.
Async version of retry logic that doesn't block the event loop during
wait periods. Uses the same exponential backoff strategy as sync version.
"""
for attempt in range(self.max_retries):
try:
return await request_func(*args, **kwargs)
except Exception as e:
if attempt == self.max_retries - 1 or not self._is_retryable_error(e):
raise
# PERFORMANCE OPTIMIZATION: Non-blocking exponential backoff
wait_time = min((2**attempt) + 0.5, 30) # Cap at 30 seconds
log.warning(
f"Retryable error (attempt {attempt + 1}/{self.max_retries}): {e}. "
f"Retrying in {wait_time}s..."
)
await asyncio.sleep(wait_time) # Non-blocking wait
def _upload_file(self) -> str:
"""
PERFORMANCE OPTIMIZATION: Enhanced file upload with streaming consideration.
Uploads the file to Mistral for OCR processing (sync version).
Uses context manager for file handling to ensure proper resource cleanup.
Although streaming is not enabled for this endpoint, the file is opened
in a context manager to minimize memory usage duration.
"""
log.info("Uploading file to Mistral API")
url = f"{self.BASE_API_URL}/files"
def upload_request():
# MEMORY OPTIMIZATION: Use context manager to minimize file handle lifetime
# This ensures the file is closed immediately after reading, reducing memory usage
with open(self.file_path, "rb") as f:
files = {"file": (self.file_name, f, "application/pdf")}
data = {"purpose": "ocr"}
# NOTE: stream=False is required for this endpoint
# The Mistral API doesn't support chunked uploads for this endpoint
response = requests.post(
url,
headers=self.headers,
files=files,
data=data,
timeout=self.upload_timeout, # Use specialized upload timeout
stream=False, # Keep as False for this endpoint
)
return self._handle_response(response)
try:
response_data = self._retry_request_sync(upload_request)
file_id = response_data.get("id")
if not file_id:
raise ValueError("File ID not found in upload response.")
log.info(f"File uploaded successfully. File ID: {file_id}")
return file_id
except Exception as e:
log.error(f"Failed to upload file: {e}")
raise
async def _upload_file_async(self, session: aiohttp.ClientSession) -> str:
"""Async file upload with streaming for better memory efficiency."""
url = f"{self.BASE_API_URL}/files"
async def upload_request():
# Create multipart writer for streaming upload
writer = aiohttp.MultipartWriter("form-data")
# Add purpose field
purpose_part = writer.append("ocr")
purpose_part.set_content_disposition("form-data", name="purpose")
# Add file part with streaming
file_part = writer.append_payload(
aiohttp.streams.FilePayload(
self.file_path,
filename=self.file_name,
content_type="application/pdf",
)
)
file_part.set_content_disposition(
"form-data", name="file", filename=self.file_name
)
self._debug_log(
f"Uploading file: {self.file_name} ({self.file_size:,} bytes)"
)
async with session.post(
url,
data=writer,
headers=self.headers,
timeout=aiohttp.ClientTimeout(total=self.upload_timeout),
) as response:
return await self._handle_response_async(response)
response_data = await self._retry_request_async(upload_request)
file_id = response_data.get("id")
if not file_id:
raise ValueError("File ID not found in upload response.")
log.info(f"File uploaded successfully. File ID: {file_id}")
return file_id
def _get_signed_url(self, file_id: str) -> str:
"""Retrieves a temporary signed URL for the uploaded file (sync version)."""
log.info(f"Getting signed URL for file ID: {file_id}")
url = f"{self.BASE_API_URL}/files/{file_id}/url"
params = {"expiry": 1}
signed_url_headers = {**self.headers, "Accept": "application/json"}
def url_request():
response = requests.get(
url, headers=signed_url_headers, params=params, timeout=self.url_timeout
)
return self._handle_response(response)
try:
response_data = self._retry_request_sync(url_request)
signed_url = response_data.get("url")
if not signed_url:
raise ValueError("Signed URL not found in response.")
log.info("Signed URL received.")
return signed_url
except Exception as e:
log.error(f"Failed to get signed URL: {e}")
raise
async def _get_signed_url_async(
self, session: aiohttp.ClientSession, file_id: str
) -> str:
"""Async signed URL retrieval."""
url = f"{self.BASE_API_URL}/files/{file_id}/url"
params = {"expiry": 1}
headers = {**self.headers, "Accept": "application/json"}
async def url_request():
self._debug_log(f"Getting signed URL for file ID: {file_id}")
async with session.get(
url,
headers=headers,
params=params,
timeout=aiohttp.ClientTimeout(total=self.url_timeout),
) as response:
return await self._handle_response_async(response)
response_data = await self._retry_request_async(url_request)
signed_url = response_data.get("url")
if not signed_url:
raise ValueError("Signed URL not found in response.")
self._debug_log("Signed URL received successfully")
return signed_url
def _process_ocr(self, signed_url: str) -> Dict[str, Any]:
"""Sends the signed URL to the OCR endpoint for processing (sync version)."""
log.info("Processing OCR via Mistral API")
url = f"{self.BASE_API_URL}/ocr"
ocr_headers = {
**self.headers,
"Content-Type": "application/json",
"Accept": "application/json",
}
payload = {
"model": "mistral-ocr-latest",
"document": {
"type": "document_url",
"document_url": signed_url,
},
"include_image_base64": False,
}
def ocr_request():
response = requests.post(
url, headers=ocr_headers, json=payload, timeout=self.ocr_timeout
)
return self._handle_response(response)
try:
ocr_response = self._retry_request_sync(ocr_request)
log.info("OCR processing done.")
self._debug_log("OCR response: %s", ocr_response)
return ocr_response
except Exception as e:
log.error(f"Failed during OCR processing: {e}")
raise
async def _process_ocr_async(
self, session: aiohttp.ClientSession, signed_url: str
) -> Dict[str, Any]:
"""Async OCR processing with timing metrics."""
url = f"{self.BASE_API_URL}/ocr"
headers = {
**self.headers,
"Content-Type": "application/json",
"Accept": "application/json",
}
payload = {
"model": "mistral-ocr-latest",
"document": {
"type": "document_url",
"document_url": signed_url,
},
"include_image_base64": False,
}
async def ocr_request():
log.info("Starting OCR processing via Mistral API")
start_time = time.time()
async with session.post(
url,
json=payload,
headers=headers,
timeout=aiohttp.ClientTimeout(total=self.ocr_timeout),
) as response:
ocr_response = await self._handle_response_async(response)
processing_time = time.time() - start_time
log.info(f"OCR processing completed in {processing_time:.2f}s")
return ocr_response
return await self._retry_request_async(ocr_request)
def _delete_file(self, file_id: str) -> None:
"""Deletes the file from Mistral storage (sync version)."""
log.info(f"Deleting uploaded file ID: {file_id}")
url = f"{self.BASE_API_URL}/files/{file_id}"
try:
response = requests.delete(
url, headers=self.headers, timeout=self.cleanup_timeout
)
delete_response = self._handle_response(response)
log.info(f"File deleted successfully: {delete_response}")
except Exception as e:
# Log error but don't necessarily halt execution if deletion fails
log.error(f"Failed to delete file ID {file_id}: {e}")
async def _delete_file_async(
self, session: aiohttp.ClientSession, file_id: str
) -> None:
"""Async file deletion with error tolerance."""
try:
async def delete_request():
self._debug_log(f"Deleting file ID: {file_id}")
async with session.delete(
url=f"{self.BASE_API_URL}/files/{file_id}",
headers=self.headers,
timeout=aiohttp.ClientTimeout(
total=self.cleanup_timeout
), # Shorter timeout for cleanup
) as response:
return await self._handle_response_async(response)
await self._retry_request_async(delete_request)
self._debug_log(f"File {file_id} deleted successfully")
except Exception as e:
# Don't fail the entire process if cleanup fails
log.warning(f"Failed to delete file ID {file_id}: {e}")
@asynccontextmanager
async def _get_session(self):
"""Context manager for HTTP session with optimized settings."""
connector = aiohttp.TCPConnector(
limit=20, # Increased total connection limit for better throughput
limit_per_host=10, # Increased per-host limit for API endpoints
ttl_dns_cache=600, # Longer DNS cache TTL (10 minutes)
use_dns_cache=True,
keepalive_timeout=60, # Increased keepalive for connection reuse
enable_cleanup_closed=True,
force_close=False, # Allow connection reuse
resolver=aiohttp.AsyncResolver(), # Use async DNS resolver
)
timeout = aiohttp.ClientTimeout(
total=self.timeout,
connect=30, # Connection timeout
sock_read=60, # Socket read timeout
)
async with aiohttp.ClientSession(
connector=connector,
timeout=timeout,
headers={"User-Agent": "OpenWebUI-MistralLoader/2.0"},
raise_for_status=False, # We handle status codes manually
trust_env=True,
) as session:
yield session
def _process_results(self, ocr_response: Dict[str, Any]) -> List[Document]:
"""Process OCR results into Document objects with enhanced metadata and memory efficiency."""
pages_data = ocr_response.get("pages")
if not pages_data:
log.warning("No pages found in OCR response.")
return [
Document(
page_content="No text content found",
metadata={"error": "no_pages", "file_name": self.file_name},
)
]
documents = []
total_pages = len(pages_data)
skipped_pages = 0
# Process pages in a memory-efficient way
for page_data in pages_data:
page_content = page_data.get("markdown")
page_index = page_data.get("index") # API uses 0-based index
if page_content is None or page_index is None:
skipped_pages += 1
self._debug_log(
f"Skipping page due to missing 'markdown' or 'index'. Data keys: {list(page_data.keys())}"
)
continue
# Clean up content efficiently with early exit for empty content
if isinstance(page_content, str):
cleaned_content = page_content.strip()
else:
cleaned_content = str(page_content).strip()
if not cleaned_content:
skipped_pages += 1
self._debug_log(f"Skipping empty page {page_index}")
continue
# Create document with optimized metadata
documents.append(
Document(
page_content=cleaned_content,
metadata={
"page": page_index, # 0-based index from API
"page_label": page_index + 1, # 1-based label for convenience
"total_pages": total_pages,
"file_name": self.file_name,
"file_size": self.file_size,
"processing_engine": "mistral-ocr",
"content_length": len(cleaned_content),
},
)
)
if skipped_pages > 0:
log.info(
f"Processed {len(documents)} pages, skipped {skipped_pages} empty/invalid pages"
)
if not documents:
# Case where pages existed but none had valid markdown/index
log.warning(
"OCR response contained pages, but none had valid content/index."
)
return [
Document(
page_content="No valid text content found in document",
metadata={
"error": "no_valid_pages",
"total_pages": total_pages,
"file_name": self.file_name,
},
)
]
return documents
def load(self) -> List[Document]:
"""
Executes the full OCR workflow: upload, get URL, process OCR, delete file.
Synchronous version for backward compatibility.
Returns:
A list of Document objects, one for each page processed.
"""
file_id = None
start_time = time.time()
try:
# 1. Upload file
file_id = self._upload_file()
# 2. Get Signed URL
signed_url = self._get_signed_url(file_id)
# 3. Process OCR
ocr_response = self._process_ocr(signed_url)
# 4. Process results
documents = self._process_results(ocr_response)
total_time = time.time() - start_time
log.info(
f"Sync OCR workflow completed in {total_time:.2f}s, produced {len(documents)} documents"
)
return documents
except Exception as e:
total_time = time.time() - start_time
log.error(
f"An error occurred during the loading process after {total_time:.2f}s: {e}"
)
# Return an error document on failure
return [
Document(
page_content=f"Error during processing: {e}",
metadata={
"error": "processing_failed",
"file_name": self.file_name,
},
)
]
finally:
# 5. Delete file (attempt even if prior steps failed after upload)
if file_id:
try:
self._delete_file(file_id)
except Exception as del_e:
# Log deletion error, but don't overwrite original error if one occurred
log.error(
f"Cleanup error: Could not delete file ID {file_id}. Reason: {del_e}"
)
async def load_async(self) -> List[Document]:
"""
Asynchronous OCR workflow execution with optimized performance.
Returns:
A list of Document objects, one for each page processed.
"""
file_id = None
start_time = time.time()
try:
async with self._get_session() as session:
# 1. Upload file with streaming
file_id = await self._upload_file_async(session)
# 2. Get signed URL
signed_url = await self._get_signed_url_async(session, file_id)
# 3. Process OCR
ocr_response = await self._process_ocr_async(session, signed_url)
# 4. Process results
documents = self._process_results(ocr_response)
total_time = time.time() - start_time
log.info(
f"Async OCR workflow completed in {total_time:.2f}s, produced {len(documents)} documents"
)
return documents
except Exception as e:
total_time = time.time() - start_time
log.error(f"Async OCR workflow failed after {total_time:.2f}s: {e}")
return [
Document(
page_content=f"Error during OCR processing: {e}",
metadata={
"error": "processing_failed",
"file_name": self.file_name,
},
)
]
finally:
# 5. Cleanup - always attempt file deletion
if file_id:
try:
async with self._get_session() as session:
await self._delete_file_async(session, file_id)
except Exception as cleanup_error:
log.error(f"Cleanup failed for file ID {file_id}: {cleanup_error}")
@staticmethod
async def load_multiple_async(
loaders: List["MistralLoader"],
max_concurrent: int = 5, # Limit concurrent requests
) -> List[List[Document]]:
"""
Process multiple files concurrently with controlled concurrency.
Args:
loaders: List of MistralLoader instances
max_concurrent: Maximum number of concurrent requests
Returns:
List of document lists, one for each loader
"""
if not loaders:
return []
log.info(
f"Starting concurrent processing of {len(loaders)} files with max {max_concurrent} concurrent"
)
start_time = time.time()
# Use semaphore to control concurrency
semaphore = asyncio.Semaphore(max_concurrent)
async def process_with_semaphore(loader: "MistralLoader") -> List[Document]:
async with semaphore:
return await loader.load_async()
# Process all files with controlled concurrency
tasks = [process_with_semaphore(loader) for loader in loaders]
results = await asyncio.gather(*tasks, return_exceptions=True)
# Handle any exceptions in results
processed_results = []
for i, result in enumerate(results):
if isinstance(result, Exception):
log.error(f"File {i} failed: {result}")
processed_results.append(
[
Document(
page_content=f"Error processing file: {result}",
metadata={
"error": "batch_processing_failed",
"file_index": i,
},
)
]
)
else:
processed_results.append(result)
# MONITORING: Log comprehensive batch processing statistics
total_time = time.time() - start_time
total_docs = sum(len(docs) for docs in processed_results)
success_count = sum(
1 for result in results if not isinstance(result, Exception)
)
failure_count = len(results) - success_count
log.info(
f"Batch processing completed in {total_time:.2f}s: "
f"{success_count} files succeeded, {failure_count} files failed, "
f"produced {total_docs} total documents"
)
return processed_results
@@ -0,0 +1,93 @@
import requests
import logging
from typing import Iterator, List, Literal, Union
from langchain_core.document_loaders import BaseLoader
from langchain_core.documents import Document
from open_webui.env import SRC_LOG_LEVELS
log = logging.getLogger(__name__)
log.setLevel(SRC_LOG_LEVELS["RAG"])
class TavilyLoader(BaseLoader):
"""Extract web page content from URLs using Tavily Extract API.
This is a LangChain document loader that uses Tavily's Extract API to
retrieve content from web pages and return it as Document objects.
Args:
urls: URL or list of URLs to extract content from.
api_key: The Tavily API key.
extract_depth: Depth of extraction, either "basic" or "advanced".
continue_on_failure: Whether to continue if extraction of a URL fails.
"""
def __init__(
self,
urls: Union[str, List[str]],
api_key: str,
extract_depth: Literal["basic", "advanced"] = "basic",
continue_on_failure: bool = True,
) -> None:
"""Initialize Tavily Extract client.
Args:
urls: URL or list of URLs to extract content from.
api_key: The Tavily API key.
include_images: Whether to include images in the extraction.
extract_depth: Depth of extraction, either "basic" or "advanced".
advanced extraction retrieves more data, including tables and
embedded content, with higher success but may increase latency.
basic costs 1 credit per 5 successful URL extractions,
advanced costs 2 credits per 5 successful URL extractions.
continue_on_failure: Whether to continue if extraction of a URL fails.
"""
if not urls:
raise ValueError("At least one URL must be provided.")
self.api_key = api_key
self.urls = urls if isinstance(urls, list) else [urls]
self.extract_depth = extract_depth
self.continue_on_failure = continue_on_failure
self.api_url = "https://api.tavily.com/extract"
def lazy_load(self) -> Iterator[Document]:
"""Extract and yield documents from the URLs using Tavily Extract API."""
batch_size = 20
for i in range(0, len(self.urls), batch_size):
batch_urls = self.urls[i : i + batch_size]
try:
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {self.api_key}",
}
# Use string for single URL, array for multiple URLs
urls_param = batch_urls[0] if len(batch_urls) == 1 else batch_urls
payload = {"urls": urls_param, "extract_depth": self.extract_depth}
# Make the API call
response = requests.post(self.api_url, headers=headers, json=payload)
response.raise_for_status()
response_data = response.json()
# Process successful results
for result in response_data.get("results", []):
url = result.get("url", "")
content = result.get("raw_content", "")
if not content:
log.warning(f"No content extracted from {url}")
continue
# Add URLs as metadata
metadata = {"source": url}
yield Document(
page_content=content,
metadata=metadata,
)
for failed in response_data.get("failed_results", []):
url = failed.get("url", "")
error = failed.get("error", "Unknown error")
log.error(f"Failed to extract content from {url}: {error}")
except Exception as e:
if self.continue_on_failure:
log.error(f"Error extracting content from batch {batch_urls}: {e}")
else:
raise e
+57 -14
View File
@@ -1,4 +1,5 @@
import logging
from xml.etree.ElementTree import ParseError
from typing import Any, Dict, Generator, List, Optional, Sequence, Union
from urllib.parse import parse_qs, urlparse
@@ -62,12 +63,17 @@ class YoutubeLoader:
_video_id = _parse_video_id(video_id)
self.video_id = _video_id if _video_id is not None else video_id
self._metadata = {"source": video_id}
self.language = language
self.proxy_url = proxy_url
# Ensure language is a list
if isinstance(language, str):
self.language = [language]
else:
self.language = language
self.language = list(language)
# Add English as fallback if not already in the list
if "en" not in self.language:
self.language.append("en")
def load(self) -> List[Document]:
"""Load YouTube transcripts into `Document` objects."""
@@ -88,7 +94,6 @@ class YoutubeLoader:
"http": self.proxy_url,
"https": self.proxy_url,
}
# Don't log complete URL because it might contain secrets
log.debug(f"Using proxy URL: {self.proxy_url[:14]}...")
else:
youtube_proxies = None
@@ -101,17 +106,55 @@ class YoutubeLoader:
log.exception("Loading YouTube transcript failed")
return []
try:
transcript = transcript_list.find_transcript(self.language)
except NoTranscriptFound:
transcript = transcript_list.find_transcript(["en"])
# Try each language in order of priority
for lang in self.language:
try:
transcript = transcript_list.find_transcript([lang])
if transcript.is_generated:
log.debug(f"Found generated transcript for language '{lang}'")
try:
transcript = transcript_list.find_manually_created_transcript(
[lang]
)
log.debug(f"Found manual transcript for language '{lang}'")
except NoTranscriptFound:
log.debug(
f"No manual transcript found for language '{lang}', using generated"
)
pass
transcript_pieces: List[Dict[str, Any]] = transcript.fetch()
log.debug(f"Found transcript for language '{lang}'")
try:
transcript_pieces: List[Dict[str, Any]] = transcript.fetch()
except ParseError:
log.debug(f"Empty or invalid transcript for language '{lang}'")
continue
transcript = " ".join(
map(
lambda transcript_piece: transcript_piece["text"].strip(" "),
transcript_pieces,
)
if not transcript_pieces:
log.debug(f"Empty transcript for language '{lang}'")
continue
transcript_text = " ".join(
map(
lambda transcript_piece: (
transcript_piece.text.strip(" ")
if hasattr(transcript_piece, "text")
else ""
),
transcript_pieces,
)
)
return [Document(page_content=transcript_text, metadata=self._metadata)]
except NoTranscriptFound:
log.debug(f"No transcript found for language '{lang}'")
continue
except Exception as e:
log.info(f"Error finding transcript for language '{lang}'")
raise e
# If we get here, all languages failed
languages_tried = ", ".join(self.language)
log.warning(
f"No transcript found for any of the specified languages: {languages_tried}. Verify if the video has transcripts, add more languages if needed."
)
return [Document(page_content=transcript, metadata=self._metadata)]
raise NoTranscriptFound(self.video_id, self.language, list(transcript_list))
@@ -0,0 +1,8 @@
from abc import ABC, abstractmethod
from typing import Optional, List, Tuple
class BaseReranker(ABC):
@abstractmethod
def predict(self, sentences: List[Tuple[str, str]]) -> Optional[List[float]]:
pass
+10 -2
View File
@@ -1,13 +1,21 @@
import os
import logging
import torch
import numpy as np
from colbert.infra import ColBERTConfig
from colbert.modeling.checkpoint import Checkpoint
from open_webui.env import SRC_LOG_LEVELS
class ColBERT:
from open_webui.retrieval.models.base_reranker import BaseReranker
log = logging.getLogger(__name__)
log.setLevel(SRC_LOG_LEVELS["RAG"])
class ColBERT(BaseReranker):
def __init__(self, name, **kwargs) -> None:
print("ColBERT: Loading model", name)
log.info("ColBERT: Loading model", name)
self.device = "cuda" if torch.cuda.is_available() else "cpu"
DOCKER = kwargs.get("env") == "docker"
@@ -0,0 +1,74 @@
import logging
import requests
from typing import Optional, List, Tuple
from urllib.parse import quote
from open_webui.env import ENABLE_FORWARD_USER_INFO_HEADERS, SRC_LOG_LEVELS
from open_webui.retrieval.models.base_reranker import BaseReranker
log = logging.getLogger(__name__)
log.setLevel(SRC_LOG_LEVELS["RAG"])
class ExternalReranker(BaseReranker):
def __init__(
self,
api_key: str,
url: str = "http://localhost:8080/v1/rerank",
model: str = "reranker",
):
self.api_key = api_key
self.url = url
self.model = model
def predict(
self, sentences: List[Tuple[str, str]], user=None
) -> Optional[List[float]]:
query = sentences[0][0]
docs = [i[1] for i in sentences]
payload = {
"model": self.model,
"query": query,
"documents": docs,
"top_n": len(docs),
}
try:
log.info(f"ExternalReranker:predict:model {self.model}")
log.info(f"ExternalReranker:predict:query {query}")
r = requests.post(
f"{self.url}",
headers={
"Content-Type": "application/json",
"Authorization": f"Bearer {self.api_key}",
**(
{
"X-OpenWebUI-User-Name": quote(user.name, safe=" "),
"X-OpenWebUI-User-Id": user.id,
"X-OpenWebUI-User-Email": user.email,
"X-OpenWebUI-User-Role": user.role,
}
if ENABLE_FORWARD_USER_INFO_HEADERS and user
else {}
),
},
json=payload,
)
r.raise_for_status()
data = r.json()
if "results" in data:
sorted_results = sorted(data["results"], key=lambda x: x["index"])
return [result["relevance_score"] for result in sorted_results]
else:
log.error("No results found in external reranking response")
return None
except Exception as e:
log.exception(f"Error in external reranking: {e}")
return None
File diff suppressed because it is too large Load Diff
@@ -1,22 +0,0 @@
from open_webui.config import VECTOR_DB
if VECTOR_DB == "milvus":
from open_webui.retrieval.vector.dbs.milvus import MilvusClient
VECTOR_DB_CLIENT = MilvusClient()
elif VECTOR_DB == "qdrant":
from open_webui.retrieval.vector.dbs.qdrant import QdrantClient
VECTOR_DB_CLIENT = QdrantClient()
elif VECTOR_DB == "opensearch":
from open_webui.retrieval.vector.dbs.opensearch import OpenSearchClient
VECTOR_DB_CLIENT = OpenSearchClient()
elif VECTOR_DB == "pgvector":
from open_webui.retrieval.vector.dbs.pgvector import PgvectorClient
VECTOR_DB_CLIENT = PgvectorClient()
else:
from open_webui.retrieval.vector.dbs.chroma import ChromaClient
VECTOR_DB_CLIENT = ChromaClient()
+37 -13
View File
@@ -1,10 +1,18 @@
import chromadb
import logging
from chromadb import Settings
from chromadb.utils.batch_utils import create_batches
from typing import Optional
from open_webui.retrieval.vector.main import VectorItem, SearchResult, GetResult
from open_webui.retrieval.vector.main import (
VectorDBBase,
VectorItem,
SearchResult,
GetResult,
)
from open_webui.retrieval.vector.utils import stringify_metadata
from open_webui.config import (
CHROMA_DATA_PATH,
CHROMA_HTTP_HOST,
@@ -16,9 +24,13 @@ from open_webui.config import (
CHROMA_CLIENT_AUTH_PROVIDER,
CHROMA_CLIENT_AUTH_CREDENTIALS,
)
from open_webui.env import SRC_LOG_LEVELS
log = logging.getLogger(__name__)
log.setLevel(SRC_LOG_LEVELS["RAG"])
class ChromaClient:
class ChromaClient(VectorDBBase):
def __init__(self):
settings_dict = {
"allow_reset": True,
@@ -70,10 +82,16 @@ class ChromaClient:
n_results=limit,
)
# chromadb has cosine distance, 2 (worst) -> 0 (best). Re-odering to 0 -> 1
# https://docs.trychroma.com/docs/collections/configure cosine equation
distances: list = result["distances"][0]
distances = [2 - dist for dist in distances]
distances = [[dist / 2 for dist in distances]]
return SearchResult(
**{
"ids": result["ids"],
"distances": result["distances"],
"distances": distances,
"documents": result["documents"],
"metadatas": result["metadatas"],
}
@@ -102,8 +120,7 @@ class ChromaClient:
}
)
return None
except Exception as e:
print(e)
except:
return None
def get(self, collection_name: str) -> Optional[GetResult]:
@@ -129,7 +146,7 @@ class ChromaClient:
ids = [item["id"] for item in items]
documents = [item["text"] for item in items]
embeddings = [item["vector"] for item in items]
metadatas = [item["metadata"] for item in items]
metadatas = [stringify_metadata(item["metadata"]) for item in items]
for batch in create_batches(
api=self.client,
@@ -149,7 +166,7 @@ class ChromaClient:
ids = [item["id"] for item in items]
documents = [item["text"] for item in items]
embeddings = [item["vector"] for item in items]
metadatas = [item["metadata"] for item in items]
metadatas = [stringify_metadata(item["metadata"]) for item in items]
collection.upsert(
ids=ids, documents=documents, embeddings=embeddings, metadatas=metadatas
@@ -162,12 +179,19 @@ class ChromaClient:
filter: Optional[dict] = None,
):
# Delete the items from the collection based on the ids.
collection = self.client.get_collection(name=collection_name)
if collection:
if ids:
collection.delete(ids=ids)
elif filter:
collection.delete(where=filter)
try:
collection = self.client.get_collection(name=collection_name)
if collection:
if ids:
collection.delete(ids=ids)
elif filter:
collection.delete(where=filter)
except Exception as e:
# If collection doesn't exist, that's fine - nothing to delete
log.debug(
f"Attempted to delete from non-existent collection {collection_name}. Ignoring."
)
pass
def reset(self):
# Resets the database. This will delete all collections and item entries.
@@ -0,0 +1,302 @@
from elasticsearch import Elasticsearch, BadRequestError
from typing import Optional
import ssl
from elasticsearch.helpers import bulk, scan
from open_webui.retrieval.vector.utils import stringify_metadata
from open_webui.retrieval.vector.main import (
VectorDBBase,
VectorItem,
SearchResult,
GetResult,
)
from open_webui.config import (
ELASTICSEARCH_URL,
ELASTICSEARCH_CA_CERTS,
ELASTICSEARCH_API_KEY,
ELASTICSEARCH_USERNAME,
ELASTICSEARCH_PASSWORD,
ELASTICSEARCH_CLOUD_ID,
ELASTICSEARCH_INDEX_PREFIX,
SSL_ASSERT_FINGERPRINT,
)
class ElasticsearchClient(VectorDBBase):
"""
Important:
in order to reduce the number of indexes and since the embedding vector length is fixed, we avoid creating
an index for each file but store it as a text field, while seperating to different index
baesd on the embedding length.
"""
def __init__(self):
self.index_prefix = ELASTICSEARCH_INDEX_PREFIX
self.client = Elasticsearch(
hosts=[ELASTICSEARCH_URL],
ca_certs=ELASTICSEARCH_CA_CERTS,
api_key=ELASTICSEARCH_API_KEY,
cloud_id=ELASTICSEARCH_CLOUD_ID,
basic_auth=(
(ELASTICSEARCH_USERNAME, ELASTICSEARCH_PASSWORD)
if ELASTICSEARCH_USERNAME and ELASTICSEARCH_PASSWORD
else None
),
ssl_assert_fingerprint=SSL_ASSERT_FINGERPRINT,
)
# Status: works
def _get_index_name(self, dimension: int) -> str:
return f"{self.index_prefix}_d{str(dimension)}"
# Status: works
def _scan_result_to_get_result(self, result) -> GetResult:
if not result:
return None
ids = []
documents = []
metadatas = []
for hit in result:
ids.append(hit["_id"])
documents.append(hit["_source"].get("text"))
metadatas.append(hit["_source"].get("metadata"))
return GetResult(ids=[ids], documents=[documents], metadatas=[metadatas])
# Status: works
def _result_to_get_result(self, result) -> GetResult:
if not result["hits"]["hits"]:
return None
ids = []
documents = []
metadatas = []
for hit in result["hits"]["hits"]:
ids.append(hit["_id"])
documents.append(hit["_source"].get("text"))
metadatas.append(hit["_source"].get("metadata"))
return GetResult(ids=[ids], documents=[documents], metadatas=[metadatas])
# Status: works
def _result_to_search_result(self, result) -> SearchResult:
ids = []
distances = []
documents = []
metadatas = []
for hit in result["hits"]["hits"]:
ids.append(hit["_id"])
distances.append(hit["_score"])
documents.append(hit["_source"].get("text"))
metadatas.append(hit["_source"].get("metadata"))
return SearchResult(
ids=[ids],
distances=[distances],
documents=[documents],
metadatas=[metadatas],
)
# Status: works
def _create_index(self, dimension: int):
body = {
"mappings": {
"dynamic_templates": [
{
"strings": {
"match_mapping_type": "string",
"mapping": {"type": "keyword"},
}
}
],
"properties": {
"collection": {"type": "keyword"},
"id": {"type": "keyword"},
"vector": {
"type": "dense_vector",
"dims": dimension, # Adjust based on your vector dimensions
"index": True,
"similarity": "cosine",
},
"text": {"type": "text"},
"metadata": {"type": "object"},
},
}
}
self.client.indices.create(index=self._get_index_name(dimension), body=body)
# Status: works
def _create_batches(self, items: list[VectorItem], batch_size=100):
for i in range(0, len(items), batch_size):
yield items[i : min(i + batch_size, len(items))]
# Status: works
def has_collection(self, collection_name) -> bool:
query_body = {"query": {"bool": {"filter": []}}}
query_body["query"]["bool"]["filter"].append(
{"term": {"collection": collection_name}}
)
try:
result = self.client.count(index=f"{self.index_prefix}*", body=query_body)
return result.body["count"] > 0
except Exception as e:
return None
def delete_collection(self, collection_name: str):
query = {"query": {"term": {"collection": collection_name}}}
self.client.delete_by_query(index=f"{self.index_prefix}*", body=query)
# Status: works
def search(
self, collection_name: str, vectors: list[list[float]], limit: int
) -> Optional[SearchResult]:
query = {
"size": limit,
"_source": ["text", "metadata"],
"query": {
"script_score": {
"query": {
"bool": {"filter": [{"term": {"collection": collection_name}}]}
},
"script": {
"source": "cosineSimilarity(params.vector, 'vector') + 1.0",
"params": {
"vector": vectors[0]
}, # Assuming single query vector
},
}
},
}
result = self.client.search(
index=self._get_index_name(len(vectors[0])), body=query
)
return self._result_to_search_result(result)
# Status: only tested halfwat
def query(
self, collection_name: str, filter: dict, limit: Optional[int] = None
) -> Optional[GetResult]:
if not self.has_collection(collection_name):
return None
query_body = {
"query": {"bool": {"filter": []}},
"_source": ["text", "metadata"],
}
for field, value in filter.items():
query_body["query"]["bool"]["filter"].append({"term": {field: value}})
query_body["query"]["bool"]["filter"].append(
{"term": {"collection": collection_name}}
)
size = limit if limit else 10
try:
result = self.client.search(
index=f"{self.index_prefix}*",
body=query_body,
size=size,
)
return self._result_to_get_result(result)
except Exception as e:
return None
# Status: works
def _has_index(self, dimension: int):
return self.client.indices.exists(
index=self._get_index_name(dimension=dimension)
)
def get_or_create_index(self, dimension: int):
if not self._has_index(dimension=dimension):
self._create_index(dimension=dimension)
# Status: works
def get(self, collection_name: str) -> Optional[GetResult]:
# Get all the items in the collection.
query = {
"query": {"bool": {"filter": [{"term": {"collection": collection_name}}]}},
"_source": ["text", "metadata"],
}
results = list(scan(self.client, index=f"{self.index_prefix}*", query=query))
return self._scan_result_to_get_result(results)
# Status: works
def insert(self, collection_name: str, items: list[VectorItem]):
if not self._has_index(dimension=len(items[0]["vector"])):
self._create_index(dimension=len(items[0]["vector"]))
for batch in self._create_batches(items):
actions = [
{
"_index": self._get_index_name(dimension=len(items[0]["vector"])),
"_id": item["id"],
"_source": {
"collection": collection_name,
"vector": item["vector"],
"text": item["text"],
"metadata": stringify_metadata(item["metadata"]),
},
}
for item in batch
]
bulk(self.client, actions)
# Upsert documents using the update API with doc_as_upsert=True.
def upsert(self, collection_name: str, items: list[VectorItem]):
if not self._has_index(dimension=len(items[0]["vector"])):
self._create_index(dimension=len(items[0]["vector"]))
for batch in self._create_batches(items):
actions = [
{
"_op_type": "update",
"_index": self._get_index_name(dimension=len(item["vector"])),
"_id": item["id"],
"doc": {
"collection": collection_name,
"vector": item["vector"],
"text": item["text"],
"metadata": stringify_metadata(item["metadata"]),
},
"doc_as_upsert": True,
}
for item in batch
]
bulk(self.client, actions)
# Delete specific documents from a collection by filtering on both collection and document IDs.
def delete(
self,
collection_name: str,
ids: Optional[list[str]] = None,
filter: Optional[dict] = None,
):
query = {
"query": {"bool": {"filter": [{"term": {"collection": collection_name}}]}}
}
# logic based on chromaDB
if ids:
query["query"]["bool"]["filter"].append({"terms": {"_id": ids}})
elif filter:
for field, value in filter.items():
query["query"]["bool"]["filter"].append(
{"term": {f"metadata.{field}": value}}
)
self.client.delete_by_query(index=f"{self.index_prefix}*", body=query)
def reset(self):
indices = self.client.indices.get(index=f"{self.index_prefix}*")
for index in indices:
self.client.indices.delete(index=index)
+172 -44
View File
@@ -1,26 +1,44 @@
from pymilvus import MilvusClient as Client
from pymilvus import FieldSchema, DataType
import json
import logging
from typing import Optional
from open_webui.retrieval.vector.main import VectorItem, SearchResult, GetResult
from open_webui.retrieval.vector.utils import stringify_metadata
from open_webui.retrieval.vector.main import (
VectorDBBase,
VectorItem,
SearchResult,
GetResult,
)
from open_webui.config import (
MILVUS_URI,
MILVUS_DB,
MILVUS_TOKEN,
MILVUS_INDEX_TYPE,
MILVUS_METRIC_TYPE,
MILVUS_HNSW_M,
MILVUS_HNSW_EFCONSTRUCTION,
MILVUS_IVF_FLAT_NLIST,
)
from open_webui.env import SRC_LOG_LEVELS
log = logging.getLogger(__name__)
log.setLevel(SRC_LOG_LEVELS["RAG"])
class MilvusClient:
class MilvusClient(VectorDBBase):
def __init__(self):
self.collection_prefix = "open_webui"
self.client = Client(uri=MILVUS_URI, database=MILVUS_DB)
if MILVUS_TOKEN is None:
self.client = Client(uri=MILVUS_URI, db_name=MILVUS_DB)
else:
self.client = Client(uri=MILVUS_URI, db_name=MILVUS_DB, token=MILVUS_TOKEN)
def _result_to_get_result(self, result) -> GetResult:
ids = []
documents = []
metadatas = []
for match in result:
_ids = []
_documents = []
@@ -29,11 +47,9 @@ class MilvusClient:
_ids.append(item.get("id"))
_documents.append(item.get("data", {}).get("text"))
_metadatas.append(item.get("metadata"))
ids.append(_ids)
documents.append(_documents)
metadatas.append(_metadatas)
return GetResult(
**{
"ids": ids,
@@ -47,24 +63,23 @@ class MilvusClient:
distances = []
documents = []
metadatas = []
for match in result:
_ids = []
_distances = []
_documents = []
_metadatas = []
for item in match:
_ids.append(item.get("id"))
_distances.append(item.get("distance"))
# normalize milvus score from [-1, 1] to [0, 1] range
# https://milvus.io/docs/de/metric.md
_dist = (item.get("distance") + 1.0) / 2.0
_distances.append(_dist)
_documents.append(item.get("entity", {}).get("data", {}).get("text"))
_metadatas.append(item.get("entity", {}).get("metadata"))
ids.append(_ids)
distances.append(_distances)
documents.append(_documents)
metadatas.append(_metadatas)
return SearchResult(
**{
"ids": ids,
@@ -97,11 +112,39 @@ class MilvusClient:
)
index_params = self.client.prepare_index_params()
# Use configurations from config.py
index_type = MILVUS_INDEX_TYPE.upper()
metric_type = MILVUS_METRIC_TYPE.upper()
log.info(f"Using Milvus index type: {index_type}, metric type: {metric_type}")
index_creation_params = {}
if index_type == "HNSW":
index_creation_params = {
"M": MILVUS_HNSW_M,
"efConstruction": MILVUS_HNSW_EFCONSTRUCTION,
}
log.info(f"HNSW params: {index_creation_params}")
elif index_type == "IVF_FLAT":
index_creation_params = {"nlist": MILVUS_IVF_FLAT_NLIST}
log.info(f"IVF_FLAT params: {index_creation_params}")
elif index_type in ["FLAT", "AUTOINDEX"]:
log.info(f"Using {index_type} index with no specific build-time params.")
else:
log.warning(
f"Unsupported MILVUS_INDEX_TYPE: '{index_type}'. "
f"Supported types: HNSW, IVF_FLAT, FLAT, AUTOINDEX. "
f"Milvus will use its default for the collection if this type is not directly supported for index creation."
)
# For unsupported types, pass the type directly to Milvus; it might handle it or use a default.
# If Milvus errors out, the user needs to correct the MILVUS_INDEX_TYPE env var.
index_params.add_index(
field_name="vector",
index_type="HNSW",
metric_type="COSINE",
params={"M": 16, "efConstruction": 100},
index_type=index_type,
metric_type=metric_type,
params=index_creation_params,
)
self.client.create_collection(
@@ -109,6 +152,9 @@ class MilvusClient:
schema=schema,
index_params=index_params,
)
log.info(
f"Successfully created collection '{self.collection_prefix}_{collection_name}' with index type '{index_type}' and metric '{metric_type}'."
)
def has_collection(self, collection_name: str) -> bool:
# Check if the collection exists based on the collection name.
@@ -129,82 +175,113 @@ class MilvusClient:
) -> Optional[SearchResult]:
# Search for the nearest neighbor items based on the vectors and return 'limit' number of results.
collection_name = collection_name.replace("-", "_")
# For some index types like IVF_FLAT, search params like nprobe can be set.
# Example: search_params = {"nprobe": 10} if using IVF_FLAT
# For simplicity, not adding configurable search_params here, but could be extended.
result = self.client.search(
collection_name=f"{self.collection_prefix}_{collection_name}",
data=vectors,
limit=limit,
output_fields=["data", "metadata"],
# search_params=search_params # Potentially add later if needed
)
return self._result_to_search_result(result)
def query(self, collection_name: str, filter: dict, limit: Optional[int] = None):
# Construct the filter string for querying
collection_name = collection_name.replace("-", "_")
if not self.has_collection(collection_name):
log.warning(
f"Query attempted on non-existent collection: {self.collection_prefix}_{collection_name}"
)
return None
filter_string = " && ".join(
[
f'metadata["{key}"] == {json.dumps(value)}'
for key, value in filter.items()
]
)
max_limit = 16383 # The maximum number of records per request
all_results = []
if limit is None:
limit = float("inf") # Use infinity as a placeholder for no limit
# Milvus default limit for query if not specified is 16384, but docs mention iteration.
# Let's set a practical high number if "all" is intended, or handle true pagination.
# For now, if limit is None, we'll fetch in batches up to a very large number.
# This part could be refined based on expected use cases for "get all".
# For this function signature, None implies "as many as possible" up to Milvus limits.
limit = (
16384 * 10
) # A large number to signify fetching many, will be capped by actual data or max_limit per call.
log.info(
f"Limit not specified for query, fetching up to {limit} results in batches."
)
# Initialize offset and remaining to handle pagination
offset = 0
remaining = limit
try:
log.info(
f"Querying collection {self.collection_prefix}_{collection_name} with filter: '{filter_string}', limit: {limit}"
)
# Loop until there are no more items to fetch or the desired limit is reached
while remaining > 0:
print("remaining", remaining)
current_fetch = min(
max_limit, remaining
) # Determine how many items to fetch in this iteration
max_limit, remaining if isinstance(remaining, int) else max_limit
)
log.debug(
f"Querying with offset: {offset}, current_fetch: {current_fetch}"
)
results = self.client.query(
collection_name=f"{self.collection_prefix}_{collection_name}",
filter=filter_string,
output_fields=["*"],
output_fields=[
"id",
"data",
"metadata",
], # Explicitly list needed fields. Vector not usually needed in query.
limit=current_fetch,
offset=offset,
)
if not results:
log.debug("No more results from query.")
break
all_results.extend(results)
results_count = len(results)
remaining -= (
results_count # Decrease remaining by the number of items fetched
)
log.debug(f"Fetched {results_count} results in this batch.")
if isinstance(remaining, int):
remaining -= results_count
offset += results_count
# Break the loop if the results returned are less than the requested fetch count
# Break the loop if the results returned are less than the requested fetch count (means end of data)
if results_count < current_fetch:
log.debug(
"Fetched less than requested, assuming end of results for this query."
)
break
print(all_results)
log.info(f"Total results from query: {len(all_results)}")
return self._result_to_get_result([all_results])
except Exception as e:
print(e)
log.exception(
f"Error querying collection {self.collection_prefix}_{collection_name} with filter '{filter_string}' and limit {limit}: {e}"
)
return None
def get(self, collection_name: str) -> Optional[GetResult]:
# Get all the items in the collection.
# Get all the items in the collection. This can be very resource-intensive for large collections.
collection_name = collection_name.replace("-", "_")
result = self.client.query(
collection_name=f"{self.collection_prefix}_{collection_name}",
filter='id != ""',
log.warning(
f"Fetching ALL items from collection '{self.collection_prefix}_{collection_name}'. This might be slow for large collections."
)
return self._result_to_get_result([result])
# Using query with a trivial filter to get all items.
# This will use the paginated query logic.
return self.query(collection_name=collection_name, filter={}, limit=None)
def insert(self, collection_name: str, items: list[VectorItem]):
# Insert the items into the collection, if the collection does not exist, it will be created.
@@ -212,10 +289,23 @@ class MilvusClient:
if not self.client.has_collection(
collection_name=f"{self.collection_prefix}_{collection_name}"
):
log.info(
f"Collection {self.collection_prefix}_{collection_name} does not exist. Creating now."
)
if not items:
log.error(
f"Cannot create collection {self.collection_prefix}_{collection_name} without items to determine dimension."
)
raise ValueError(
"Cannot create Milvus collection without items to determine vector dimension."
)
self._create_collection(
collection_name=collection_name, dimension=len(items[0]["vector"])
)
log.info(
f"Inserting {len(items)} items into collection {self.collection_prefix}_{collection_name}."
)
return self.client.insert(
collection_name=f"{self.collection_prefix}_{collection_name}",
data=[
@@ -223,7 +313,7 @@ class MilvusClient:
"id": item["id"],
"vector": item["vector"],
"data": {"text": item["text"]},
"metadata": item["metadata"],
"metadata": stringify_metadata(item["metadata"]),
}
for item in items
],
@@ -235,10 +325,23 @@ class MilvusClient:
if not self.client.has_collection(
collection_name=f"{self.collection_prefix}_{collection_name}"
):
log.info(
f"Collection {self.collection_prefix}_{collection_name} does not exist for upsert. Creating now."
)
if not items:
log.error(
f"Cannot create collection {self.collection_prefix}_{collection_name} for upsert without items to determine dimension."
)
raise ValueError(
"Cannot create Milvus collection for upsert without items to determine vector dimension."
)
self._create_collection(
collection_name=collection_name, dimension=len(items[0]["vector"])
)
log.info(
f"Upserting {len(items)} items into collection {self.collection_prefix}_{collection_name}."
)
return self.client.upsert(
collection_name=f"{self.collection_prefix}_{collection_name}",
data=[
@@ -246,7 +349,7 @@ class MilvusClient:
"id": item["id"],
"vector": item["vector"],
"data": {"text": item["text"]},
"metadata": item["metadata"],
"metadata": stringify_metadata(item["metadata"]),
}
for item in items
],
@@ -258,30 +361,55 @@ class MilvusClient:
ids: Optional[list[str]] = None,
filter: Optional[dict] = None,
):
# Delete the items from the collection based on the ids.
# Delete the items from the collection based on the ids or filter.
collection_name = collection_name.replace("-", "_")
if not self.has_collection(collection_name):
log.warning(
f"Delete attempted on non-existent collection: {self.collection_prefix}_{collection_name}"
)
return None
if ids:
log.info(
f"Deleting items by IDs from {self.collection_prefix}_{collection_name}. IDs: {ids}"
)
return self.client.delete(
collection_name=f"{self.collection_prefix}_{collection_name}",
ids=ids,
)
elif filter:
# Convert the filter dictionary to a string using JSON_CONTAINS.
filter_string = " && ".join(
[
f'metadata["{key}"] == {json.dumps(value)}'
for key, value in filter.items()
]
)
log.info(
f"Deleting items by filter from {self.collection_prefix}_{collection_name}. Filter: {filter_string}"
)
return self.client.delete(
collection_name=f"{self.collection_prefix}_{collection_name}",
filter=filter_string,
)
else:
log.warning(
f"Delete operation on {self.collection_prefix}_{collection_name} called without IDs or filter. No action taken."
)
return None
def reset(self):
# Resets the database. This will delete all collections and item entries.
# Resets the database. This will delete all collections and item entries that match the prefix.
log.warning(
f"Resetting Milvus: Deleting all collections with prefix '{self.collection_prefix}'."
)
collection_names = self.client.list_collections()
for collection_name in collection_names:
if collection_name.startswith(self.collection_prefix):
self.client.drop_collection(collection_name=collection_name)
deleted_collections = []
for collection_name_full in collection_names:
if collection_name_full.startswith(self.collection_prefix):
try:
self.client.drop_collection(collection_name=collection_name_full)
deleted_collections.append(collection_name_full)
log.info(f"Deleted collection: {collection_name_full}")
except Exception as e:
log.error(f"Error deleting collection {collection_name_full}: {e}")
log.info(f"Milvus reset complete. Deleted collections: {deleted_collections}")
@@ -1,7 +1,14 @@
from opensearchpy import OpenSearch
from opensearchpy.helpers import bulk
from typing import Optional
from open_webui.retrieval.vector.main import VectorItem, SearchResult, GetResult
from open_webui.retrieval.vector.utils import stringify_metadata
from open_webui.retrieval.vector.main import (
VectorDBBase,
VectorItem,
SearchResult,
GetResult,
)
from open_webui.config import (
OPENSEARCH_URI,
OPENSEARCH_SSL,
@@ -11,7 +18,7 @@ from open_webui.config import (
)
class OpenSearchClient:
class OpenSearchClient(VectorDBBase):
def __init__(self):
self.index_prefix = "open_webui"
self.client = OpenSearch(
@@ -21,7 +28,13 @@ class OpenSearchClient:
http_auth=(OPENSEARCH_USERNAME, OPENSEARCH_PASSWORD),
)
def _get_index_name(self, collection_name: str) -> str:
return f"{self.index_prefix}_{collection_name}"
def _result_to_get_result(self, result) -> GetResult:
if not result["hits"]["hits"]:
return None
ids = []
documents = []
metadatas = []
@@ -31,9 +44,12 @@ class OpenSearchClient:
documents.append(hit["_source"].get("text"))
metadatas.append(hit["_source"].get("metadata"))
return GetResult(ids=ids, documents=documents, metadatas=metadatas)
return GetResult(ids=[ids], documents=[documents], metadatas=[metadatas])
def _result_to_search_result(self, result) -> SearchResult:
if not result["hits"]["hits"]:
return None
ids = []
distances = []
documents = []
@@ -46,131 +62,204 @@ class OpenSearchClient:
metadatas.append(hit["_source"].get("metadata"))
return SearchResult(
ids=ids, distances=distances, documents=documents, metadatas=metadatas
ids=[ids],
distances=[distances],
documents=[documents],
metadatas=[metadatas],
)
def _create_index(self, index_name: str, dimension: int):
def _create_index(self, collection_name: str, dimension: int):
body = {
"settings": {"index": {"knn": True}},
"mappings": {
"properties": {
"id": {"type": "keyword"},
"vector": {
"type": "dense_vector",
"dims": dimension, # Adjust based on your vector dimensions
"index": true,
"type": "knn_vector",
"dimension": dimension, # Adjust based on your vector dimensions
"index": True,
"similarity": "faiss",
"method": {
"name": "hnsw",
"space_type": "ip", # Use inner product to approximate cosine similarity
"space_type": "innerproduct", # Use inner product to approximate cosine similarity
"engine": "faiss",
"ef_construction": 128,
"m": 16,
"parameters": {
"ef_construction": 128,
"m": 16,
},
},
},
"text": {"type": "text"},
"metadata": {"type": "object"},
}
}
},
}
self.client.indices.create(index=f"{self.index_prefix}_{index_name}", body=body)
self.client.indices.create(
index=self._get_index_name(collection_name), body=body
)
def _create_batches(self, items: list[VectorItem], batch_size=100):
for i in range(0, len(items), batch_size):
yield items[i : i + batch_size]
def has_collection(self, index_name: str) -> bool:
def has_collection(self, collection_name: str) -> bool:
# has_collection here means has index.
# We are simply adapting to the norms of the other DBs.
return self.client.indices.exists(index=f"{self.index_prefix}_{index_name}")
return self.client.indices.exists(index=self._get_index_name(collection_name))
def delete_colleciton(self, index_name: str):
def delete_collection(self, collection_name: str):
# delete_collection here means delete index.
# We are simply adapting to the norms of the other DBs.
self.client.indices.delete(index=f"{self.index_prefix}_{index_name}")
self.client.indices.delete(index=self._get_index_name(collection_name))
def search(
self, index_name: str, vectors: list[list[float]], limit: int
self, collection_name: str, vectors: list[list[float | int]], limit: int
) -> Optional[SearchResult]:
query = {
"size": limit,
try:
if not self.has_collection(collection_name):
return None
query = {
"size": limit,
"_source": ["text", "metadata"],
"query": {
"script_score": {
"query": {"match_all": {}},
"script": {
"source": "(cosineSimilarity(params.query_value, doc[params.field]) + 1.0) / 2.0",
"params": {
"field": "vector",
"query_value": vectors[0],
}, # Assuming single query vector
},
}
},
}
result = self.client.search(
index=self._get_index_name(collection_name), body=query
)
return self._result_to_search_result(result)
except Exception as e:
return None
def query(
self, collection_name: str, filter: dict, limit: Optional[int] = None
) -> Optional[GetResult]:
if not self.has_collection(collection_name):
return None
query_body = {
"query": {"bool": {"filter": []}},
"_source": ["text", "metadata"],
"query": {
"script_score": {
"query": {"match_all": {}},
"script": {
"source": "cosineSimilarity(params.vector, 'vector') + 1.0",
"params": {
"vector": vectors[0]
}, # Assuming single query vector
},
}
},
}
result = self.client.search(
index=f"{self.index_prefix}_{index_name}", body=query
)
for field, value in filter.items():
query_body["query"]["bool"]["filter"].append(
{"term": {"metadata." + str(field) + ".keyword": value}}
)
return self._result_to_search_result(result)
size = limit if limit else 10000
def get_or_create_index(self, index_name: str, dimension: int):
if not self.has_index(index_name):
self._create_index(index_name, dimension)
try:
result = self.client.search(
index=self._get_index_name(collection_name),
body=query_body,
size=size,
)
def get(self, index_name: str) -> Optional[GetResult]:
return self._result_to_get_result(result)
except Exception as e:
return None
def _create_index_if_not_exists(self, collection_name: str, dimension: int):
if not self.has_collection(collection_name):
self._create_index(collection_name, dimension)
def get(self, collection_name: str) -> Optional[GetResult]:
query = {"query": {"match_all": {}}, "_source": ["text", "metadata"]}
result = self.client.search(
index=f"{self.index_prefix}_{index_name}", body=query
index=self._get_index_name(collection_name), body=query
)
return self._result_to_get_result(result)
def insert(self, index_name: str, items: list[VectorItem]):
if not self.has_index(index_name):
self._create_index(index_name, dimension=len(items[0]["vector"]))
def insert(self, collection_name: str, items: list[VectorItem]):
self._create_index_if_not_exists(
collection_name=collection_name, dimension=len(items[0]["vector"])
)
for batch in self._create_batches(items):
actions = [
{
"index": {
"_id": item["id"],
"_source": {
"vector": item["vector"],
"text": item["text"],
"metadata": item["metadata"],
},
}
"_op_type": "index",
"_index": self._get_index_name(collection_name),
"_id": item["id"],
"_source": {
"vector": item["vector"],
"text": item["text"],
"metadata": stringify_metadata(item["metadata"]),
},
}
for item in batch
]
self.client.bulk(actions)
bulk(self.client, actions)
self.client.indices.refresh(self._get_index_name(collection_name))
def upsert(self, index_name: str, items: list[VectorItem]):
if not self.has_index(index_name):
self._create_index(index_name, dimension=len(items[0]["vector"]))
def upsert(self, collection_name: str, items: list[VectorItem]):
self._create_index_if_not_exists(
collection_name=collection_name, dimension=len(items[0]["vector"])
)
for batch in self._create_batches(items):
actions = [
{
"index": {
"_id": item["id"],
"_source": {
"vector": item["vector"],
"text": item["text"],
"metadata": item["metadata"],
},
}
"_op_type": "update",
"_index": self._get_index_name(collection_name),
"_id": item["id"],
"doc": {
"vector": item["vector"],
"text": item["text"],
"metadata": stringify_metadata(item["metadata"]),
},
"doc_as_upsert": True,
}
for item in batch
]
self.client.bulk(actions)
bulk(self.client, actions)
self.client.indices.refresh(self._get_index_name(collection_name))
def delete(self, index_name: str, ids: list[str]):
actions = [
{"delete": {"_index": f"{self.index_prefix}_{index_name}", "_id": id}}
for id in ids
]
self.client.bulk(body=actions)
def delete(
self,
collection_name: str,
ids: Optional[list[str]] = None,
filter: Optional[dict] = None,
):
if ids:
actions = [
{
"_op_type": "delete",
"_index": self._get_index_name(collection_name),
"_id": id,
}
for id in ids
]
bulk(self.client, actions)
elif filter:
query_body = {
"query": {"bool": {"filter": []}},
}
for field, value in filter.items():
query_body["query"]["bool"]["filter"].append(
{"term": {"metadata." + str(field) + ".keyword": value}}
)
self.client.delete_by_query(
index=self._get_index_name(collection_name), body=query_body
)
self.client.indices.refresh(self._get_index_name(collection_name))
def reset(self):
indices = self.client.indices.get(index=f"{self.index_prefix}_*")
@@ -0,0 +1,943 @@
"""
Oracle 23ai Vector Database Client - Fixed Version
# .env
VECTOR_DB = "oracle23ai"
## DBCS or oracle 23ai free
ORACLE_DB_USE_WALLET = false
ORACLE_DB_USER = "DEMOUSER"
ORACLE_DB_PASSWORD = "Welcome123456"
ORACLE_DB_DSN = "localhost:1521/FREEPDB1"
## ADW or ATP
# ORACLE_DB_USE_WALLET = true
# ORACLE_DB_USER = "DEMOUSER"
# ORACLE_DB_PASSWORD = "Welcome123456"
# ORACLE_DB_DSN = "medium"
# ORACLE_DB_DSN = "(description= (retry_count=3)(retry_delay=3)(address=(protocol=tcps)(port=1522)(host=xx.oraclecloud.com))(connect_data=(service_name=yy.adb.oraclecloud.com))(security=(ssl_server_dn_match=no)))"
# ORACLE_WALLET_DIR = "/home/opc/adb_wallet"
# ORACLE_WALLET_PASSWORD = "Welcome1"
ORACLE_VECTOR_LENGTH = 768
ORACLE_DB_POOL_MIN = 2
ORACLE_DB_POOL_MAX = 10
ORACLE_DB_POOL_INCREMENT = 1
"""
from typing import Optional, List, Dict, Any, Union
from decimal import Decimal
import logging
import os
import threading
import time
import json
import array
import oracledb
from open_webui.retrieval.vector.main import (
VectorDBBase,
VectorItem,
SearchResult,
GetResult,
)
from open_webui.config import (
ORACLE_DB_USE_WALLET,
ORACLE_DB_USER,
ORACLE_DB_PASSWORD,
ORACLE_DB_DSN,
ORACLE_WALLET_DIR,
ORACLE_WALLET_PASSWORD,
ORACLE_VECTOR_LENGTH,
ORACLE_DB_POOL_MIN,
ORACLE_DB_POOL_MAX,
ORACLE_DB_POOL_INCREMENT,
)
from open_webui.env import SRC_LOG_LEVELS
log = logging.getLogger(__name__)
log.setLevel(SRC_LOG_LEVELS["RAG"])
class Oracle23aiClient(VectorDBBase):
"""
Oracle Vector Database Client for vector similarity search using Oracle Database 23ai.
This client provides an interface to store, retrieve, and search vector embeddings
in an Oracle database. It uses connection pooling for efficient database access
and supports vector similarity search operations.
Attributes:
pool: Connection pool for Oracle database connections
"""
def __init__(self) -> None:
"""
Initialize the Oracle23aiClient with a connection pool.
Creates a connection pool with configurable min/max connections, initializes
the database schema if needed, and sets up necessary tables and indexes.
Raises:
ValueError: If required configuration parameters are missing
Exception: If database initialization fails
"""
self.pool = None
try:
# Create the appropriate connection pool based on DB type
if ORACLE_DB_USE_WALLET:
self._create_adb_pool()
else: # DBCS
self._create_dbcs_pool()
dsn = ORACLE_DB_DSN
log.info(f"Creating Connection Pool [{ORACLE_DB_USER}:**@{dsn}]")
with self.get_connection() as connection:
log.info(f"Connection version: {connection.version}")
self._initialize_database(connection)
log.info("Oracle Vector Search initialization complete.")
except Exception as e:
log.exception(f"Error during Oracle Vector Search initialization: {e}")
raise
def _create_adb_pool(self) -> None:
"""
Create connection pool for Oracle Autonomous Database.
Uses wallet-based authentication.
"""
self.pool = oracledb.create_pool(
user=ORACLE_DB_USER,
password=ORACLE_DB_PASSWORD,
dsn=ORACLE_DB_DSN,
min=ORACLE_DB_POOL_MIN,
max=ORACLE_DB_POOL_MAX,
increment=ORACLE_DB_POOL_INCREMENT,
config_dir=ORACLE_WALLET_DIR,
wallet_location=ORACLE_WALLET_DIR,
wallet_password=ORACLE_WALLET_PASSWORD,
)
log.info("Created ADB connection pool with wallet authentication.")
def _create_dbcs_pool(self) -> None:
"""
Create connection pool for Oracle Database Cloud Service.
Uses basic authentication without wallet.
"""
self.pool = oracledb.create_pool(
user=ORACLE_DB_USER,
password=ORACLE_DB_PASSWORD,
dsn=ORACLE_DB_DSN,
min=ORACLE_DB_POOL_MIN,
max=ORACLE_DB_POOL_MAX,
increment=ORACLE_DB_POOL_INCREMENT,
)
log.info("Created DB connection pool with basic authentication.")
def get_connection(self):
"""
Acquire a connection from the connection pool with retry logic.
Returns:
connection: A database connection with output type handler configured
"""
max_retries = 3
for attempt in range(max_retries):
try:
connection = self.pool.acquire()
connection.outputtypehandler = self._output_type_handler
return connection
except oracledb.DatabaseError as e:
(error_obj,) = e.args
log.exception(
f"Connection attempt {attempt + 1} failed: {error_obj.message}"
)
if attempt < max_retries - 1:
wait_time = 2**attempt
log.info(f"Retrying in {wait_time} seconds...")
time.sleep(wait_time)
else:
raise
def start_health_monitor(self, interval_seconds: int = 60):
"""
Start a background thread to periodically check the health of the connection pool.
Args:
interval_seconds (int): Number of seconds between health checks
"""
def _monitor():
while True:
try:
log.info("[HealthCheck] Running periodic DB health check...")
self.ensure_connection()
log.info("[HealthCheck] Connection is healthy.")
except Exception as e:
log.exception(f"[HealthCheck] Connection health check failed: {e}")
time.sleep(interval_seconds)
thread = threading.Thread(target=_monitor, daemon=True)
thread.start()
log.info(f"Started DB health monitor every {interval_seconds} seconds.")
def _reconnect_pool(self):
"""
Attempt to reinitialize the connection pool if it's been closed or broken.
"""
try:
log.info("Attempting to reinitialize the Oracle connection pool...")
# Close existing pool if it exists
if self.pool:
try:
self.pool.close()
except Exception as close_error:
log.warning(f"Error closing existing pool: {close_error}")
# Re-create the appropriate connection pool based on DB type
if ORACLE_DB_USE_WALLET:
self._create_adb_pool()
else: # DBCS
self._create_dbcs_pool()
log.info("Connection pool reinitialized.")
except Exception as e:
log.exception(f"Failed to reinitialize the connection pool: {e}")
raise
def ensure_connection(self):
"""
Ensure the database connection is alive, reconnecting pool if needed.
"""
try:
with self.get_connection() as connection:
with connection.cursor() as cursor:
cursor.execute("SELECT 1 FROM dual")
except Exception as e:
log.exception(
f"Connection check failed: {e}, attempting to reconnect pool..."
)
self._reconnect_pool()
def _output_type_handler(self, cursor, metadata):
"""
Handle Oracle vector type conversion.
Args:
cursor: Oracle database cursor
metadata: Metadata for the column
Returns:
A variable with appropriate conversion for vector types
"""
if metadata.type_code is oracledb.DB_TYPE_VECTOR:
return cursor.var(
metadata.type_code, arraysize=cursor.arraysize, outconverter=list
)
def _initialize_database(self, connection) -> None:
"""
Initialize database schema, tables and indexes.
Creates the document_chunk table and necessary indexes if they don't exist.
Args:
connection: Oracle database connection
Raises:
Exception: If schema initialization fails
"""
with connection.cursor() as cursor:
try:
log.info("Creating Table document_chunk")
cursor.execute(
"""
BEGIN
EXECUTE IMMEDIATE '
CREATE TABLE IF NOT EXISTS document_chunk (
id VARCHAR2(255) PRIMARY KEY,
collection_name VARCHAR2(255) NOT NULL,
text CLOB,
vmetadata JSON,
vector vector(*, float32)
)
';
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE != -955 THEN
RAISE;
END IF;
END;
"""
)
log.info("Creating Index document_chunk_collection_name_idx")
cursor.execute(
"""
BEGIN
EXECUTE IMMEDIATE '
CREATE INDEX IF NOT EXISTS document_chunk_collection_name_idx
ON document_chunk (collection_name)
';
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE != -955 THEN
RAISE;
END IF;
END;
"""
)
log.info("Creating VECTOR INDEX document_chunk_vector_ivf_idx")
cursor.execute(
"""
BEGIN
EXECUTE IMMEDIATE '
CREATE VECTOR INDEX IF NOT EXISTS document_chunk_vector_ivf_idx
ON document_chunk(vector)
ORGANIZATION NEIGHBOR PARTITIONS
DISTANCE COSINE
WITH TARGET ACCURACY 95
PARAMETERS (TYPE IVF, NEIGHBOR PARTITIONS 100)
';
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE != -955 THEN
RAISE;
END IF;
END;
"""
)
connection.commit()
log.info("Database initialization completed successfully.")
except Exception as e:
connection.rollback()
log.exception(f"Error during database initialization: {e}")
raise
def check_vector_length(self) -> None:
"""
Check vector length compatibility (placeholder).
This method would check if the configured vector length matches the database schema.
Currently implemented as a placeholder.
"""
pass
def _vector_to_blob(self, vector: List[float]) -> bytes:
"""
Convert a vector to Oracle BLOB format.
Args:
vector (List[float]): The vector to convert
Returns:
bytes: The vector in Oracle BLOB format
"""
return array.array("f", vector)
def adjust_vector_length(self, vector: List[float]) -> List[float]:
"""
Adjust vector to the expected length if needed.
Args:
vector (List[float]): The vector to adjust
Returns:
List[float]: The adjusted vector
"""
return vector
def _decimal_handler(self, obj):
"""
Handle Decimal objects for JSON serialization.
Args:
obj: Object to serialize
Returns:
float: Converted decimal value
Raises:
TypeError: If object is not JSON serializable
"""
if isinstance(obj, Decimal):
return float(obj)
raise TypeError(f"{obj} is not JSON serializable")
def _metadata_to_json(self, metadata: Dict) -> str:
"""
Convert metadata dictionary to JSON string.
Args:
metadata (Dict): Metadata dictionary
Returns:
str: JSON representation of metadata
"""
return json.dumps(metadata, default=self._decimal_handler) if metadata else "{}"
def _json_to_metadata(self, json_str: str) -> Dict:
"""
Convert JSON string to metadata dictionary.
Args:
json_str (str): JSON string
Returns:
Dict: Metadata dictionary
"""
return json.loads(json_str) if json_str else {}
def insert(self, collection_name: str, items: List[VectorItem]) -> None:
"""
Insert vector items into the database.
Args:
collection_name (str): Name of the collection
items (List[VectorItem]): List of vector items to insert
Raises:
Exception: If insertion fails
Example:
>>> client = Oracle23aiClient()
>>> items = [
... {"id": "1", "text": "Sample text", "vector": [0.1, 0.2, ...], "metadata": {"source": "doc1"}},
... {"id": "2", "text": "Another text", "vector": [0.3, 0.4, ...], "metadata": {"source": "doc2"}}
... ]
>>> client.insert("my_collection", items)
"""
log.info(f"Inserting {len(items)} items into collection '{collection_name}'.")
with self.get_connection() as connection:
try:
with connection.cursor() as cursor:
for item in items:
vector_blob = self._vector_to_blob(item["vector"])
metadata_json = self._metadata_to_json(item["metadata"])
cursor.execute(
"""
INSERT INTO document_chunk
(id, collection_name, text, vmetadata, vector)
VALUES (:id, :collection_name, :text, :metadata, :vector)
""",
{
"id": item["id"],
"collection_name": collection_name,
"text": item["text"],
"metadata": metadata_json,
"vector": vector_blob,
},
)
connection.commit()
log.info(
f"Successfully inserted {len(items)} items into collection '{collection_name}'."
)
except Exception as e:
connection.rollback()
log.exception(f"Error during insert: {e}")
raise
def upsert(self, collection_name: str, items: List[VectorItem]) -> None:
"""
Update or insert vector items into the database.
If an item with the same ID exists, it will be updated;
otherwise, it will be inserted.
Args:
collection_name (str): Name of the collection
items (List[VectorItem]): List of vector items to upsert
Raises:
Exception: If upsert operation fails
Example:
>>> client = Oracle23aiClient()
>>> items = [
... {"id": "1", "text": "Updated text", "vector": [0.1, 0.2, ...], "metadata": {"source": "doc1"}},
... {"id": "3", "text": "New item", "vector": [0.5, 0.6, ...], "metadata": {"source": "doc3"}}
... ]
>>> client.upsert("my_collection", items)
"""
log.info(f"Upserting {len(items)} items into collection '{collection_name}'.")
with self.get_connection() as connection:
try:
with connection.cursor() as cursor:
for item in items:
vector_blob = self._vector_to_blob(item["vector"])
metadata_json = self._metadata_to_json(item["metadata"])
cursor.execute(
"""
MERGE INTO document_chunk d
USING (SELECT :merge_id as id FROM dual) s
ON (d.id = s.id)
WHEN MATCHED THEN
UPDATE SET
collection_name = :upd_collection_name,
text = :upd_text,
vmetadata = :upd_metadata,
vector = :upd_vector
WHEN NOT MATCHED THEN
INSERT (id, collection_name, text, vmetadata, vector)
VALUES (:ins_id, :ins_collection_name, :ins_text, :ins_metadata, :ins_vector)
""",
{
"merge_id": item["id"],
"upd_collection_name": collection_name,
"upd_text": item["text"],
"upd_metadata": metadata_json,
"upd_vector": vector_blob,
"ins_id": item["id"],
"ins_collection_name": collection_name,
"ins_text": item["text"],
"ins_metadata": metadata_json,
"ins_vector": vector_blob,
},
)
connection.commit()
log.info(
f"Successfully upserted {len(items)} items into collection '{collection_name}'."
)
except Exception as e:
connection.rollback()
log.exception(f"Error during upsert: {e}")
raise
def search(
self, collection_name: str, vectors: List[List[Union[float, int]]], limit: int
) -> Optional[SearchResult]:
"""
Search for similar vectors in the database.
Performs vector similarity search using cosine distance.
Args:
collection_name (str): Name of the collection to search
vectors (List[List[Union[float, int]]]): Query vectors to find similar items for
limit (int): Maximum number of results to return per query
Returns:
Optional[SearchResult]: Search results containing ids, distances, documents, and metadata
Example:
>>> client = Oracle23aiClient()
>>> query_vector = [0.1, 0.2, 0.3, ...] # Must match VECTOR_LENGTH
>>> results = client.search("my_collection", [query_vector], limit=5)
>>> if results:
... log.info(f"Found {len(results.ids[0])} matches")
... for i, (id, dist) in enumerate(zip(results.ids[0], results.distances[0])):
... log.info(f"Match {i+1}: id={id}, distance={dist}")
"""
log.info(
f"Searching items from collection '{collection_name}' with limit {limit}."
)
try:
if not vectors:
log.warning("No vectors provided for search.")
return None
num_queries = len(vectors)
ids = [[] for _ in range(num_queries)]
distances = [[] for _ in range(num_queries)]
documents = [[] for _ in range(num_queries)]
metadatas = [[] for _ in range(num_queries)]
with self.get_connection() as connection:
with connection.cursor() as cursor:
for qid, vector in enumerate(vectors):
vector_blob = self._vector_to_blob(vector)
cursor.execute(
"""
SELECT dc.id, dc.text,
JSON_SERIALIZE(dc.vmetadata RETURNING VARCHAR2(4096)) as vmetadata,
VECTOR_DISTANCE(dc.vector, :query_vector, COSINE) as distance
FROM document_chunk dc
WHERE dc.collection_name = :collection_name
ORDER BY VECTOR_DISTANCE(dc.vector, :query_vector, COSINE)
FETCH APPROX FIRST :limit ROWS ONLY
""",
{
"query_vector": vector_blob,
"collection_name": collection_name,
"limit": limit,
},
)
results = cursor.fetchall()
for row in results:
ids[qid].append(row[0])
documents[qid].append(
row[1].read()
if isinstance(row[1], oracledb.LOB)
else str(row[1])
)
# 🔧 FIXED: Parse JSON metadata properly
metadata_str = (
row[2].read()
if isinstance(row[2], oracledb.LOB)
else row[2]
)
metadatas[qid].append(self._json_to_metadata(metadata_str))
distances[qid].append(float(row[3]))
log.info(
f"Search completed. Found {sum(len(ids[i]) for i in range(num_queries))} total results."
)
return SearchResult(
ids=ids, distances=distances, documents=documents, metadatas=metadatas
)
except Exception as e:
log.exception(f"Error during search: {e}")
return None
def query(
self, collection_name: str, filter: Dict, limit: Optional[int] = None
) -> Optional[GetResult]:
"""
Query items based on metadata filters.
Retrieves items that match specified metadata criteria.
Args:
collection_name (str): Name of the collection to query
filter (Dict[str, Any]): Metadata filters to apply
limit (Optional[int]): Maximum number of results to return
Returns:
Optional[GetResult]: Query results containing ids, documents, and metadata
Example:
>>> client = Oracle23aiClient()
>>> filter = {"source": "doc1", "category": "finance"}
>>> results = client.query("my_collection", filter, limit=20)
>>> if results:
... print(f"Found {len(results.ids[0])} matching documents")
"""
log.info(f"Querying items from collection '{collection_name}' with filters.")
try:
limit = limit or 100
query = """
SELECT id, text, JSON_SERIALIZE(vmetadata RETURNING VARCHAR2(4096)) as vmetadata
FROM document_chunk
WHERE collection_name = :collection_name
"""
params = {"collection_name": collection_name}
for i, (key, value) in enumerate(filter.items()):
param_name = f"value_{i}"
query += f" AND JSON_VALUE(vmetadata, '$.{key}' RETURNING VARCHAR2(4096)) = :{param_name}"
params[param_name] = str(value)
query += " FETCH FIRST :limit ROWS ONLY"
params["limit"] = limit
with self.get_connection() as connection:
with connection.cursor() as cursor:
cursor.execute(query, params)
results = cursor.fetchall()
if not results:
log.info("No results found for query.")
return None
ids = [[row[0] for row in results]]
documents = [
[
row[1].read() if isinstance(row[1], oracledb.LOB) else str(row[1])
for row in results
]
]
# 🔧 FIXED: Parse JSON metadata properly
metadatas = [
[
self._json_to_metadata(
row[2].read() if isinstance(row[2], oracledb.LOB) else row[2]
)
for row in results
]
]
log.info(f"Query completed. Found {len(results)} results.")
return GetResult(ids=ids, documents=documents, metadatas=metadatas)
except Exception as e:
log.exception(f"Error during query: {e}")
return None
def get(self, collection_name: str) -> Optional[GetResult]:
"""
Get all items in a collection.
Retrieves items from a specified collection up to the limit.
Args:
collection_name (str): Name of the collection to retrieve
limit (Optional[int]): Maximum number of items to retrieve
Returns:
Optional[GetResult]: Result containing ids, documents, and metadata
Example:
>>> client = Oracle23aiClient()
>>> results = client.get("my_collection", limit=50)
>>> if results:
... print(f"Retrieved {len(results.ids[0])} documents from collection")
"""
log.info(
f"Getting items from collection '{collection_name}' with limit {limit}."
)
try:
limit = limit or 1000
with self.get_connection() as connection:
with connection.cursor() as cursor:
cursor.execute(
"""
SELECT /*+ MONITOR */ id, text, JSON_SERIALIZE(vmetadata RETURNING VARCHAR2(4096)) as vmetadata
FROM document_chunk
WHERE collection_name = :collection_name
FETCH FIRST :limit ROWS ONLY
""",
{"collection_name": collection_name, "limit": limit},
)
results = cursor.fetchall()
if not results:
log.info("No results found.")
return None
ids = [[row[0] for row in results]]
documents = [
[
row[1].read() if isinstance(row[1], oracledb.LOB) else str(row[1])
for row in results
]
]
# 🔧 FIXED: Parse JSON metadata properly
metadatas = [
[
self._json_to_metadata(
row[2].read() if isinstance(row[2], oracledb.LOB) else row[2]
)
for row in results
]
]
return GetResult(ids=ids, documents=documents, metadatas=metadatas)
except Exception as e:
log.exception(f"Error during get: {e}")
return None
def delete(
self,
collection_name: str,
ids: Optional[List[str]] = None,
filter: Optional[Dict[str, Any]] = None,
) -> None:
"""
Delete items from the database.
Deletes items from a collection based on IDs or metadata filters.
Args:
collection_name (str): Name of the collection to delete from
ids (Optional[List[str]]): Specific item IDs to delete
filter (Optional[Dict[str, Any]]): Metadata filters for deletion
Raises:
Exception: If deletion fails
Example:
>>> client = Oracle23aiClient()
>>> # Delete specific items by ID
>>> client.delete("my_collection", ids=["1", "3", "5"])
>>> # Or delete by metadata filter
>>> client.delete("my_collection", filter={"source": "deprecated_source"})
"""
log.info(f"Deleting items from collection '{collection_name}'.")
try:
query = (
"DELETE FROM document_chunk WHERE collection_name = :collection_name"
)
params = {"collection_name": collection_name}
if ids:
# 🔧 FIXED: Use proper parameterized query to prevent SQL injection
placeholders = ",".join([f":id_{i}" for i in range(len(ids))])
query += f" AND id IN ({placeholders})"
for i, id_val in enumerate(ids):
params[f"id_{i}"] = id_val
if filter:
for i, (key, value) in enumerate(filter.items()):
param_name = f"value_{i}"
query += f" AND JSON_VALUE(vmetadata, '$.{key}' RETURNING VARCHAR2(4096)) = :{param_name}"
params[param_name] = str(value)
with self.get_connection() as connection:
with connection.cursor() as cursor:
cursor.execute(query, params)
deleted = cursor.rowcount
connection.commit()
log.info(f"Deleted {deleted} items from collection '{collection_name}'.")
except Exception as e:
log.exception(f"Error during delete: {e}")
raise
def reset(self) -> None:
"""
Reset the database by deleting all items.
Deletes all items from the document_chunk table.
Raises:
Exception: If reset fails
Example:
>>> client = Oracle23aiClient()
>>> client.reset() # Warning: Removes all data!
"""
log.info("Resetting database - deleting all items.")
try:
with self.get_connection() as connection:
with connection.cursor() as cursor:
cursor.execute("DELETE FROM document_chunk")
deleted = cursor.rowcount
connection.commit()
log.info(
f"Reset complete. Deleted {deleted} items from 'document_chunk' table."
)
except Exception as e:
log.exception(f"Error during reset: {e}")
raise
def close(self) -> None:
"""
Close the database connection pool.
Properly closes the connection pool and releases all resources.
Example:
>>> client = Oracle23aiClient()
>>> # After finishing all operations
>>> client.close()
"""
try:
if hasattr(self, "pool") and self.pool:
self.pool.close()
log.info("Oracle Vector Search connection pool closed.")
except Exception as e:
log.exception(f"Error closing connection pool: {e}")
def has_collection(self, collection_name: str) -> bool:
"""
Check if a collection exists.
Args:
collection_name (str): Name of the collection to check
Returns:
bool: True if the collection exists, False otherwise
Example:
>>> client = Oracle23aiClient()
>>> if client.has_collection("my_collection"):
... print("Collection exists!")
... else:
... print("Collection does not exist.")
"""
try:
with self.get_connection() as connection:
with connection.cursor() as cursor:
cursor.execute(
"""
SELECT COUNT(*)
FROM document_chunk
WHERE collection_name = :collection_name
FETCH FIRST 1 ROWS ONLY
""",
{"collection_name": collection_name},
)
count = cursor.fetchone()[0]
return count > 0
except Exception as e:
log.exception(f"Error checking collection existence: {e}")
return False
def delete_collection(self, collection_name: str) -> None:
"""
Delete an entire collection.
Removes all items belonging to the specified collection.
Args:
collection_name (str): Name of the collection to delete
Example:
>>> client = Oracle23aiClient()
>>> client.delete_collection("obsolete_collection")
"""
log.info(f"Deleting collection '{collection_name}'.")
try:
with self.get_connection() as connection:
with connection.cursor() as cursor:
cursor.execute(
"""
DELETE FROM document_chunk
WHERE collection_name = :collection_name
""",
{"collection_name": collection_name},
)
deleted = cursor.rowcount
connection.commit()
log.info(
f"Collection '{collection_name}' deleted. Removed {deleted} items."
)
except Exception as e:
log.exception(f"Error deleting collection '{collection_name}': {e}")
raise
@@ -1,11 +1,16 @@
from typing import Optional, List, Dict, Any
import logging
import json
from sqlalchemy import (
func,
literal,
cast,
column,
create_engine,
Column,
Integer,
MetaData,
LargeBinary,
select,
text,
Text,
@@ -13,7 +18,7 @@ from sqlalchemy import (
values,
)
from sqlalchemy.sql import true
from sqlalchemy.pool import NullPool
from sqlalchemy.pool import NullPool, QueuePool
from sqlalchemy.orm import declarative_base, scoped_session, sessionmaker
from sqlalchemy.dialects.postgresql import JSONB, array
@@ -21,12 +26,41 @@ from pgvector.sqlalchemy import Vector
from sqlalchemy.ext.mutable import MutableDict
from sqlalchemy.exc import NoSuchTableError
from open_webui.retrieval.vector.main import VectorItem, SearchResult, GetResult
from open_webui.config import PGVECTOR_DB_URL, PGVECTOR_INITIALIZE_MAX_VECTOR_LENGTH
from open_webui.retrieval.vector.utils import stringify_metadata
from open_webui.retrieval.vector.main import (
VectorDBBase,
VectorItem,
SearchResult,
GetResult,
)
from open_webui.config import (
PGVECTOR_DB_URL,
PGVECTOR_INITIALIZE_MAX_VECTOR_LENGTH,
PGVECTOR_PGCRYPTO,
PGVECTOR_PGCRYPTO_KEY,
PGVECTOR_POOL_SIZE,
PGVECTOR_POOL_MAX_OVERFLOW,
PGVECTOR_POOL_TIMEOUT,
PGVECTOR_POOL_RECYCLE,
)
from open_webui.env import SRC_LOG_LEVELS
VECTOR_LENGTH = PGVECTOR_INITIALIZE_MAX_VECTOR_LENGTH
Base = declarative_base()
log = logging.getLogger(__name__)
log.setLevel(SRC_LOG_LEVELS["RAG"])
def pgcrypto_encrypt(val, key):
return func.pgp_sym_encrypt(val, literal(key))
def pgcrypto_decrypt(col, key, outtype="text"):
return func.cast(func.pgp_sym_decrypt(col, literal(key)), outtype)
class DocumentChunk(Base):
__tablename__ = "document_chunk"
@@ -34,11 +68,16 @@ class DocumentChunk(Base):
id = Column(Text, primary_key=True)
vector = Column(Vector(dim=VECTOR_LENGTH), nullable=True)
collection_name = Column(Text, nullable=False)
text = Column(Text, nullable=True)
vmetadata = Column(MutableDict.as_mutable(JSONB), nullable=True)
if PGVECTOR_PGCRYPTO:
text = Column(LargeBinary, nullable=True)
vmetadata = Column(LargeBinary, nullable=True)
else:
text = Column(Text, nullable=True)
vmetadata = Column(MutableDict.as_mutable(JSONB), nullable=True)
class PgvectorClient:
class PgvectorClient(VectorDBBase):
def __init__(self) -> None:
# if no pgvector uri, use the existing database connection
@@ -47,9 +86,24 @@ class PgvectorClient:
self.session = Session
else:
engine = create_engine(
PGVECTOR_DB_URL, pool_pre_ping=True, poolclass=NullPool
)
if isinstance(PGVECTOR_POOL_SIZE, int):
if PGVECTOR_POOL_SIZE > 0:
engine = create_engine(
PGVECTOR_DB_URL,
pool_size=PGVECTOR_POOL_SIZE,
max_overflow=PGVECTOR_POOL_MAX_OVERFLOW,
pool_timeout=PGVECTOR_POOL_TIMEOUT,
pool_recycle=PGVECTOR_POOL_RECYCLE,
pool_pre_ping=True,
poolclass=QueuePool,
)
else:
engine = create_engine(
PGVECTOR_DB_URL, pool_pre_ping=True, poolclass=NullPool
)
else:
engine = create_engine(PGVECTOR_DB_URL, pool_pre_ping=True)
SessionLocal = sessionmaker(
autocommit=False, autoflush=False, bind=engine, expire_on_commit=False
)
@@ -59,6 +113,15 @@ class PgvectorClient:
# Ensure the pgvector extension is available
self.session.execute(text("CREATE EXTENSION IF NOT EXISTS vector;"))
if PGVECTOR_PGCRYPTO:
# Ensure the pgcrypto extension is available for encryption
self.session.execute(text("CREATE EXTENSION IF NOT EXISTS pgcrypto;"))
if not PGVECTOR_PGCRYPTO_KEY:
raise ValueError(
"PGVECTOR_PGCRYPTO_KEY must be set when PGVECTOR_PGCRYPTO is enabled."
)
# Check vector length consistency
self.check_vector_length()
@@ -82,10 +145,10 @@ class PgvectorClient:
)
)
self.session.commit()
print("Initialization complete.")
log.info("Initialization complete.")
except Exception as e:
self.session.rollback()
print(f"Error during initialization: {e}")
log.exception(f"Error during initialization: {e}")
raise
def check_vector_length(self) -> None:
@@ -130,64 +193,130 @@ class PgvectorClient:
# Pad the vector with zeros
vector += [0.0] * (VECTOR_LENGTH - current_length)
elif current_length > VECTOR_LENGTH:
raise Exception(
f"Vector length {current_length} not supported. Max length must be <= {VECTOR_LENGTH}"
)
# Truncate the vector to VECTOR_LENGTH
vector = vector[:VECTOR_LENGTH]
return vector
def insert(self, collection_name: str, items: List[VectorItem]) -> None:
try:
new_items = []
for item in items:
vector = self.adjust_vector_length(item["vector"])
new_chunk = DocumentChunk(
id=item["id"],
vector=vector,
collection_name=collection_name,
text=item["text"],
vmetadata=item["metadata"],
)
new_items.append(new_chunk)
self.session.bulk_save_objects(new_items)
self.session.commit()
print(
f"Inserted {len(new_items)} items into collection '{collection_name}'."
)
except Exception as e:
self.session.rollback()
print(f"Error during insert: {e}")
raise
def upsert(self, collection_name: str, items: List[VectorItem]) -> None:
try:
for item in items:
vector = self.adjust_vector_length(item["vector"])
existing = (
self.session.query(DocumentChunk)
.filter(DocumentChunk.id == item["id"])
.first()
)
if existing:
existing.vector = vector
existing.text = item["text"]
existing.vmetadata = item["metadata"]
existing.collection_name = (
collection_name # Update collection_name if necessary
if PGVECTOR_PGCRYPTO:
for item in items:
vector = self.adjust_vector_length(item["vector"])
# Use raw SQL for BYTEA/pgcrypto
# Ensure metadata is converted to its JSON text representation
json_metadata = json.dumps(item["metadata"])
self.session.execute(
text(
"""
INSERT INTO document_chunk
(id, vector, collection_name, text, vmetadata)
VALUES (
:id, :vector, :collection_name,
pgp_sym_encrypt(:text, :key),
pgp_sym_encrypt(:metadata_text, :key)
)
ON CONFLICT (id) DO NOTHING
"""
),
{
"id": item["id"],
"vector": vector,
"collection_name": collection_name,
"text": item["text"],
"metadata_text": json_metadata,
"key": PGVECTOR_PGCRYPTO_KEY,
},
)
else:
self.session.commit()
log.info(f"Encrypted & inserted {len(items)} into '{collection_name}'")
else:
new_items = []
for item in items:
vector = self.adjust_vector_length(item["vector"])
new_chunk = DocumentChunk(
id=item["id"],
vector=vector,
collection_name=collection_name,
text=item["text"],
vmetadata=item["metadata"],
vmetadata=stringify_metadata(item["metadata"]),
)
self.session.add(new_chunk)
self.session.commit()
print(f"Upserted {len(items)} items into collection '{collection_name}'.")
new_items.append(new_chunk)
self.session.bulk_save_objects(new_items)
self.session.commit()
log.info(
f"Inserted {len(new_items)} items into collection '{collection_name}'."
)
except Exception as e:
self.session.rollback()
print(f"Error during upsert: {e}")
log.exception(f"Error during insert: {e}")
raise
def upsert(self, collection_name: str, items: List[VectorItem]) -> None:
try:
if PGVECTOR_PGCRYPTO:
for item in items:
vector = self.adjust_vector_length(item["vector"])
json_metadata = json.dumps(item["metadata"])
self.session.execute(
text(
"""
INSERT INTO document_chunk
(id, vector, collection_name, text, vmetadata)
VALUES (
:id, :vector, :collection_name,
pgp_sym_encrypt(:text, :key),
pgp_sym_encrypt(:metadata_text, :key)
)
ON CONFLICT (id) DO UPDATE SET
vector = EXCLUDED.vector,
collection_name = EXCLUDED.collection_name,
text = EXCLUDED.text,
vmetadata = EXCLUDED.vmetadata
"""
),
{
"id": item["id"],
"vector": vector,
"collection_name": collection_name,
"text": item["text"],
"metadata_text": json_metadata,
"key": PGVECTOR_PGCRYPTO_KEY,
},
)
self.session.commit()
log.info(f"Encrypted & upserted {len(items)} into '{collection_name}'")
else:
for item in items:
vector = self.adjust_vector_length(item["vector"])
existing = (
self.session.query(DocumentChunk)
.filter(DocumentChunk.id == item["id"])
.first()
)
if existing:
existing.vector = vector
existing.text = item["text"]
existing.vmetadata = stringify_metadata(item["metadata"])
existing.collection_name = (
collection_name # Update collection_name if necessary
)
else:
new_chunk = DocumentChunk(
id=item["id"],
vector=vector,
collection_name=collection_name,
text=item["text"],
vmetadata=stringify_metadata(item["metadata"]),
)
self.session.add(new_chunk)
self.session.commit()
log.info(
f"Upserted {len(items)} items into collection '{collection_name}'."
)
except Exception as e:
self.session.rollback()
log.exception(f"Error during upsert: {e}")
raise
def search(
@@ -218,16 +347,32 @@ class PgvectorClient:
.alias("query_vectors")
)
result_fields = [
DocumentChunk.id,
]
if PGVECTOR_PGCRYPTO:
result_fields.append(
pgcrypto_decrypt(
DocumentChunk.text, PGVECTOR_PGCRYPTO_KEY, Text
).label("text")
)
result_fields.append(
pgcrypto_decrypt(
DocumentChunk.vmetadata, PGVECTOR_PGCRYPTO_KEY, JSONB
).label("vmetadata")
)
else:
result_fields.append(DocumentChunk.text)
result_fields.append(DocumentChunk.vmetadata)
result_fields.append(
(DocumentChunk.vector.cosine_distance(query_vectors.c.q_vector)).label(
"distance"
)
)
# Build the lateral subquery for each query vector
subq = (
select(
DocumentChunk.id,
DocumentChunk.text,
DocumentChunk.vmetadata,
(
DocumentChunk.vector.cosine_distance(query_vectors.c.q_vector)
).label("distance"),
)
select(*result_fields)
.where(DocumentChunk.collection_name == collection_name)
.order_by(
(DocumentChunk.vector.cosine_distance(query_vectors.c.q_vector))
@@ -270,32 +415,62 @@ class PgvectorClient:
for row in results:
qid = int(row.qid)
ids[qid].append(row.id)
distances[qid].append(row.distance)
# normalize and re-orders pgvec distance from [2, 0] to [0, 1] score range
# https://github.com/pgvector/pgvector?tab=readme-ov-file#querying
distances[qid].append((2.0 - row.distance) / 2.0)
documents[qid].append(row.text)
metadatas[qid].append(row.vmetadata)
self.session.rollback() # read-only transaction
return SearchResult(
ids=ids, distances=distances, documents=documents, metadatas=metadatas
)
except Exception as e:
print(f"Error during search: {e}")
self.session.rollback()
log.exception(f"Error during search: {e}")
return None
def query(
self, collection_name: str, filter: Dict[str, Any], limit: Optional[int] = None
) -> Optional[GetResult]:
try:
query = self.session.query(DocumentChunk).filter(
DocumentChunk.collection_name == collection_name
)
if PGVECTOR_PGCRYPTO:
# Build where clause for vmetadata filter
where_clauses = [DocumentChunk.collection_name == collection_name]
for key, value in filter.items():
# decrypt then check key: JSON filter after decryption
where_clauses.append(
pgcrypto_decrypt(
DocumentChunk.vmetadata, PGVECTOR_PGCRYPTO_KEY, JSONB
)[key].astext
== str(value)
)
stmt = select(
DocumentChunk.id,
pgcrypto_decrypt(
DocumentChunk.text, PGVECTOR_PGCRYPTO_KEY, Text
).label("text"),
pgcrypto_decrypt(
DocumentChunk.vmetadata, PGVECTOR_PGCRYPTO_KEY, JSONB
).label("vmetadata"),
).where(*where_clauses)
if limit is not None:
stmt = stmt.limit(limit)
results = self.session.execute(stmt).all()
else:
query = self.session.query(DocumentChunk).filter(
DocumentChunk.collection_name == collection_name
)
for key, value in filter.items():
query = query.filter(DocumentChunk.vmetadata[key].astext == str(value))
for key, value in filter.items():
query = query.filter(
DocumentChunk.vmetadata[key].astext == str(value)
)
if limit is not None:
query = query.limit(limit)
if limit is not None:
query = query.limit(limit)
results = query.all()
results = query.all()
if not results:
return None
@@ -304,37 +479,59 @@ class PgvectorClient:
documents = [[result.text for result in results]]
metadatas = [[result.vmetadata for result in results]]
self.session.rollback() # read-only transaction
return GetResult(
ids=ids,
documents=documents,
metadatas=metadatas,
)
except Exception as e:
print(f"Error during query: {e}")
self.session.rollback()
log.exception(f"Error during query: {e}")
return None
def get(
self, collection_name: str, limit: Optional[int] = None
) -> Optional[GetResult]:
try:
query = self.session.query(DocumentChunk).filter(
DocumentChunk.collection_name == collection_name
)
if limit is not None:
query = query.limit(limit)
if PGVECTOR_PGCRYPTO:
stmt = select(
DocumentChunk.id,
pgcrypto_decrypt(
DocumentChunk.text, PGVECTOR_PGCRYPTO_KEY, Text
).label("text"),
pgcrypto_decrypt(
DocumentChunk.vmetadata, PGVECTOR_PGCRYPTO_KEY, JSONB
).label("vmetadata"),
).where(DocumentChunk.collection_name == collection_name)
if limit is not None:
stmt = stmt.limit(limit)
results = self.session.execute(stmt).all()
ids = [[row.id for row in results]]
documents = [[row.text for row in results]]
metadatas = [[row.vmetadata for row in results]]
else:
results = query.all()
query = self.session.query(DocumentChunk).filter(
DocumentChunk.collection_name == collection_name
)
if limit is not None:
query = query.limit(limit)
if not results:
return None
results = query.all()
ids = [[result.id for result in results]]
documents = [[result.text for result in results]]
metadatas = [[result.vmetadata for result in results]]
if not results:
return None
ids = [[result.id for result in results]]
documents = [[result.text for result in results]]
metadatas = [[result.vmetadata for result in results]]
self.session.rollback() # read-only transaction
return GetResult(ids=ids, documents=documents, metadatas=metadatas)
except Exception as e:
print(f"Error during get: {e}")
self.session.rollback()
log.exception(f"Error during get: {e}")
return None
def delete(
@@ -344,34 +541,50 @@ class PgvectorClient:
filter: Optional[Dict[str, Any]] = None,
) -> None:
try:
query = self.session.query(DocumentChunk).filter(
DocumentChunk.collection_name == collection_name
)
if ids:
query = query.filter(DocumentChunk.id.in_(ids))
if filter:
for key, value in filter.items():
query = query.filter(
DocumentChunk.vmetadata[key].astext == str(value)
)
deleted = query.delete(synchronize_session=False)
if PGVECTOR_PGCRYPTO:
wheres = [DocumentChunk.collection_name == collection_name]
if ids:
wheres.append(DocumentChunk.id.in_(ids))
if filter:
for key, value in filter.items():
wheres.append(
pgcrypto_decrypt(
DocumentChunk.vmetadata, PGVECTOR_PGCRYPTO_KEY, JSONB
)[key].astext
== str(value)
)
stmt = DocumentChunk.__table__.delete().where(*wheres)
result = self.session.execute(stmt)
deleted = result.rowcount
else:
query = self.session.query(DocumentChunk).filter(
DocumentChunk.collection_name == collection_name
)
if ids:
query = query.filter(DocumentChunk.id.in_(ids))
if filter:
for key, value in filter.items():
query = query.filter(
DocumentChunk.vmetadata[key].astext == str(value)
)
deleted = query.delete(synchronize_session=False)
self.session.commit()
print(f"Deleted {deleted} items from collection '{collection_name}'.")
log.info(f"Deleted {deleted} items from collection '{collection_name}'.")
except Exception as e:
self.session.rollback()
print(f"Error during delete: {e}")
log.exception(f"Error during delete: {e}")
raise
def reset(self) -> None:
try:
deleted = self.session.query(DocumentChunk).delete()
self.session.commit()
print(
log.info(
f"Reset complete. Deleted {deleted} items from 'document_chunk' table."
)
except Exception as e:
self.session.rollback()
print(f"Error during reset: {e}")
log.exception(f"Error during reset: {e}")
raise
def close(self) -> None:
@@ -385,11 +598,13 @@ class PgvectorClient:
.first()
is not None
)
self.session.rollback() # read-only transaction
return exists
except Exception as e:
print(f"Error checking collection existence: {e}")
self.session.rollback()
log.exception(f"Error checking collection existence: {e}")
return False
def delete_collection(self, collection_name: str) -> None:
self.delete(collection_name)
print(f"Collection '{collection_name}' deleted.")
log.info(f"Collection '{collection_name}' deleted.")
@@ -0,0 +1,581 @@
from typing import Optional, List, Dict, Any, Union
import logging
import time # for measuring elapsed time
from pinecone import Pinecone, ServerlessSpec
# Add gRPC support for better performance (Pinecone best practice)
try:
from pinecone.grpc import PineconeGRPC
GRPC_AVAILABLE = True
except ImportError:
GRPC_AVAILABLE = False
import asyncio # for async upserts
import functools # for partial binding in async tasks
import concurrent.futures # for parallel batch upserts
import random # for jitter in retry backoff
from open_webui.retrieval.vector.main import (
VectorDBBase,
VectorItem,
SearchResult,
GetResult,
)
from open_webui.config import (
PINECONE_API_KEY,
PINECONE_ENVIRONMENT,
PINECONE_INDEX_NAME,
PINECONE_DIMENSION,
PINECONE_METRIC,
PINECONE_CLOUD,
)
from open_webui.env import SRC_LOG_LEVELS
NO_LIMIT = 10000 # Reasonable limit to avoid overwhelming the system
BATCH_SIZE = 100 # Recommended batch size for Pinecone operations
log = logging.getLogger(__name__)
log.setLevel(SRC_LOG_LEVELS["RAG"])
class PineconeClient(VectorDBBase):
def __init__(self):
self.collection_prefix = "open-webui"
# Validate required configuration
self._validate_config()
# Store configuration values
self.api_key = PINECONE_API_KEY
self.environment = PINECONE_ENVIRONMENT
self.index_name = PINECONE_INDEX_NAME
self.dimension = PINECONE_DIMENSION
self.metric = PINECONE_METRIC
self.cloud = PINECONE_CLOUD
# Initialize Pinecone client for improved performance
if GRPC_AVAILABLE:
# Use gRPC client for better performance (Pinecone recommendation)
self.client = PineconeGRPC(
api_key=self.api_key,
pool_threads=20, # Improved connection pool size
timeout=30, # Reasonable timeout for operations
)
self.using_grpc = True
log.info("Using Pinecone gRPC client for optimal performance")
else:
# Fallback to HTTP client with enhanced connection pooling
self.client = Pinecone(
api_key=self.api_key,
pool_threads=20, # Improved connection pool size
timeout=30, # Reasonable timeout for operations
)
self.using_grpc = False
log.info("Using Pinecone HTTP client (gRPC not available)")
# Persistent executor for batch operations
self._executor = concurrent.futures.ThreadPoolExecutor(max_workers=5)
# Create index if it doesn't exist
self._initialize_index()
def _validate_config(self) -> None:
"""Validate that all required configuration variables are set."""
missing_vars = []
if not PINECONE_API_KEY:
missing_vars.append("PINECONE_API_KEY")
if not PINECONE_ENVIRONMENT:
missing_vars.append("PINECONE_ENVIRONMENT")
if not PINECONE_INDEX_NAME:
missing_vars.append("PINECONE_INDEX_NAME")
if not PINECONE_DIMENSION:
missing_vars.append("PINECONE_DIMENSION")
if not PINECONE_CLOUD:
missing_vars.append("PINECONE_CLOUD")
if missing_vars:
raise ValueError(
f"Required configuration missing: {', '.join(missing_vars)}"
)
def _initialize_index(self) -> None:
"""Initialize the Pinecone index."""
try:
# Check if index exists
if self.index_name not in self.client.list_indexes().names():
log.info(f"Creating Pinecone index '{self.index_name}'...")
self.client.create_index(
name=self.index_name,
dimension=self.dimension,
metric=self.metric,
spec=ServerlessSpec(cloud=self.cloud, region=self.environment),
)
log.info(f"Successfully created Pinecone index '{self.index_name}'")
else:
log.info(f"Using existing Pinecone index '{self.index_name}'")
# Connect to the index
self.index = self.client.Index(
self.index_name,
pool_threads=20, # Enhanced connection pool for index operations
)
except Exception as e:
log.error(f"Failed to initialize Pinecone index: {e}")
raise RuntimeError(f"Failed to initialize Pinecone index: {e}")
def _retry_pinecone_operation(self, operation_func, max_retries=3):
"""Retry Pinecone operations with exponential backoff for rate limits and network issues."""
for attempt in range(max_retries):
try:
return operation_func()
except Exception as e:
error_str = str(e).lower()
# Check if it's a retryable error (rate limits, network issues, timeouts)
is_retryable = any(
keyword in error_str
for keyword in [
"rate limit",
"quota",
"timeout",
"network",
"connection",
"unavailable",
"internal error",
"429",
"500",
"502",
"503",
"504",
]
)
if not is_retryable or attempt == max_retries - 1:
# Don't retry for non-retryable errors or on final attempt
raise
# Exponential backoff with jitter
delay = (2**attempt) + random.uniform(0, 1)
log.warning(
f"Pinecone operation failed (attempt {attempt + 1}/{max_retries}), "
f"retrying in {delay:.2f}s: {e}"
)
time.sleep(delay)
def _create_points(
self, items: List[VectorItem], collection_name_with_prefix: str
) -> List[Dict[str, Any]]:
"""Convert VectorItem objects to Pinecone point format."""
points = []
for item in items:
# Start with any existing metadata or an empty dict
metadata = item.get("metadata", {}).copy() if item.get("metadata") else {}
# Add text to metadata if available
if "text" in item:
metadata["text"] = item["text"]
# Always add collection_name to metadata for filtering
metadata["collection_name"] = collection_name_with_prefix
point = {
"id": item["id"],
"values": item["vector"],
"metadata": metadata,
}
points.append(point)
return points
def _get_collection_name_with_prefix(self, collection_name: str) -> str:
"""Get the collection name with prefix."""
return f"{self.collection_prefix}_{collection_name}"
def _normalize_distance(self, score: float) -> float:
"""Normalize distance score based on the metric used."""
if self.metric.lower() == "cosine":
# Cosine similarity ranges from -1 to 1, normalize to 0 to 1
return (score + 1.0) / 2.0
elif self.metric.lower() in ["euclidean", "dotproduct"]:
# These are already suitable for ranking (smaller is better for Euclidean)
return score
else:
# For other metrics, use as is
return score
def _result_to_get_result(self, matches: list) -> GetResult:
"""Convert Pinecone matches to GetResult format."""
ids = []
documents = []
metadatas = []
for match in matches:
metadata = getattr(match, "metadata", {}) or {}
ids.append(match.id if hasattr(match, "id") else match["id"])
documents.append(metadata.get("text", ""))
metadatas.append(metadata)
return GetResult(
**{
"ids": [ids],
"documents": [documents],
"metadatas": [metadatas],
}
)
def has_collection(self, collection_name: str) -> bool:
"""Check if a collection exists by searching for at least one item."""
collection_name_with_prefix = self._get_collection_name_with_prefix(
collection_name
)
try:
# Search for at least 1 item with this collection name in metadata
response = self.index.query(
vector=[0.0] * self.dimension, # dummy vector
top_k=1,
filter={"collection_name": collection_name_with_prefix},
include_metadata=False,
)
matches = getattr(response, "matches", []) or []
return len(matches) > 0
except Exception as e:
log.exception(
f"Error checking collection '{collection_name_with_prefix}': {e}"
)
return False
def delete_collection(self, collection_name: str) -> None:
"""Delete a collection by removing all vectors with the collection name in metadata."""
collection_name_with_prefix = self._get_collection_name_with_prefix(
collection_name
)
try:
self.index.delete(filter={"collection_name": collection_name_with_prefix})
log.info(
f"Collection '{collection_name_with_prefix}' deleted (all vectors removed)."
)
except Exception as e:
log.warning(
f"Failed to delete collection '{collection_name_with_prefix}': {e}"
)
raise
def insert(self, collection_name: str, items: List[VectorItem]) -> None:
"""Insert vectors into a collection."""
if not items:
log.warning("No items to insert")
return
start_time = time.time()
collection_name_with_prefix = self._get_collection_name_with_prefix(
collection_name
)
points = self._create_points(items, collection_name_with_prefix)
# Parallelize batch inserts for performance
executor = self._executor
futures = []
for i in range(0, len(points), BATCH_SIZE):
batch = points[i : i + BATCH_SIZE]
futures.append(executor.submit(self.index.upsert, vectors=batch))
for future in concurrent.futures.as_completed(futures):
try:
future.result()
except Exception as e:
log.error(f"Error inserting batch: {e}")
raise
elapsed = time.time() - start_time
log.debug(f"Insert of {len(points)} vectors took {elapsed:.2f} seconds")
log.info(
f"Successfully inserted {len(points)} vectors in parallel batches "
f"into '{collection_name_with_prefix}'"
)
def upsert(self, collection_name: str, items: List[VectorItem]) -> None:
"""Upsert (insert or update) vectors into a collection."""
if not items:
log.warning("No items to upsert")
return
start_time = time.time()
collection_name_with_prefix = self._get_collection_name_with_prefix(
collection_name
)
points = self._create_points(items, collection_name_with_prefix)
# Parallelize batch upserts for performance
executor = self._executor
futures = []
for i in range(0, len(points), BATCH_SIZE):
batch = points[i : i + BATCH_SIZE]
futures.append(executor.submit(self.index.upsert, vectors=batch))
for future in concurrent.futures.as_completed(futures):
try:
future.result()
except Exception as e:
log.error(f"Error upserting batch: {e}")
raise
elapsed = time.time() - start_time
log.debug(f"Upsert of {len(points)} vectors took {elapsed:.2f} seconds")
log.info(
f"Successfully upserted {len(points)} vectors in parallel batches "
f"into '{collection_name_with_prefix}'"
)
async def insert_async(self, collection_name: str, items: List[VectorItem]) -> None:
"""Async version of insert using asyncio and run_in_executor for improved performance."""
if not items:
log.warning("No items to insert")
return
collection_name_with_prefix = self._get_collection_name_with_prefix(
collection_name
)
points = self._create_points(items, collection_name_with_prefix)
# Create batches
batches = [
points[i : i + BATCH_SIZE] for i in range(0, len(points), BATCH_SIZE)
]
loop = asyncio.get_event_loop()
tasks = [
loop.run_in_executor(
None, functools.partial(self.index.upsert, vectors=batch)
)
for batch in batches
]
results = await asyncio.gather(*tasks, return_exceptions=True)
for result in results:
if isinstance(result, Exception):
log.error(f"Error in async insert batch: {result}")
raise result
log.info(
f"Successfully async inserted {len(points)} vectors in batches "
f"into '{collection_name_with_prefix}'"
)
async def upsert_async(self, collection_name: str, items: List[VectorItem]) -> None:
"""Async version of upsert using asyncio and run_in_executor for improved performance."""
if not items:
log.warning("No items to upsert")
return
collection_name_with_prefix = self._get_collection_name_with_prefix(
collection_name
)
points = self._create_points(items, collection_name_with_prefix)
# Create batches
batches = [
points[i : i + BATCH_SIZE] for i in range(0, len(points), BATCH_SIZE)
]
loop = asyncio.get_event_loop()
tasks = [
loop.run_in_executor(
None, functools.partial(self.index.upsert, vectors=batch)
)
for batch in batches
]
results = await asyncio.gather(*tasks, return_exceptions=True)
for result in results:
if isinstance(result, Exception):
log.error(f"Error in async upsert batch: {result}")
raise result
log.info(
f"Successfully async upserted {len(points)} vectors in batches "
f"into '{collection_name_with_prefix}'"
)
def search(
self, collection_name: str, vectors: List[List[Union[float, int]]], limit: int
) -> Optional[SearchResult]:
"""Search for similar vectors in a collection."""
if not vectors or not vectors[0]:
log.warning("No vectors provided for search")
return None
collection_name_with_prefix = self._get_collection_name_with_prefix(
collection_name
)
if limit is None or limit <= 0:
limit = NO_LIMIT
try:
# Search using the first vector (assuming this is the intended behavior)
query_vector = vectors[0]
# Perform the search
query_response = self.index.query(
vector=query_vector,
top_k=limit,
include_metadata=True,
filter={"collection_name": collection_name_with_prefix},
)
matches = getattr(query_response, "matches", []) or []
if not matches:
# Return empty result if no matches
return SearchResult(
ids=[[]],
documents=[[]],
metadatas=[[]],
distances=[[]],
)
# Convert to GetResult format
get_result = self._result_to_get_result(matches)
# Calculate normalized distances based on metric
distances = [
[
self._normalize_distance(getattr(match, "score", 0.0))
for match in matches
]
]
return SearchResult(
ids=get_result.ids,
documents=get_result.documents,
metadatas=get_result.metadatas,
distances=distances,
)
except Exception as e:
log.error(f"Error searching in '{collection_name_with_prefix}': {e}")
return None
def query(
self, collection_name: str, filter: Dict, limit: Optional[int] = None
) -> Optional[GetResult]:
"""Query vectors by metadata filter."""
collection_name_with_prefix = self._get_collection_name_with_prefix(
collection_name
)
if limit is None or limit <= 0:
limit = NO_LIMIT
try:
# Create a zero vector for the dimension as Pinecone requires a vector
zero_vector = [0.0] * self.dimension
# Combine user filter with collection_name
pinecone_filter = {"collection_name": collection_name_with_prefix}
if filter:
pinecone_filter.update(filter)
# Perform metadata-only query
query_response = self.index.query(
vector=zero_vector,
filter=pinecone_filter,
top_k=limit,
include_metadata=True,
)
matches = getattr(query_response, "matches", []) or []
return self._result_to_get_result(matches)
except Exception as e:
log.error(f"Error querying collection '{collection_name}': {e}")
return None
def get(self, collection_name: str) -> Optional[GetResult]:
"""Get all vectors in a collection."""
collection_name_with_prefix = self._get_collection_name_with_prefix(
collection_name
)
try:
# Use a zero vector for fetching all entries
zero_vector = [0.0] * self.dimension
# Add filter to only get vectors for this collection
query_response = self.index.query(
vector=zero_vector,
top_k=NO_LIMIT,
include_metadata=True,
filter={"collection_name": collection_name_with_prefix},
)
matches = getattr(query_response, "matches", []) or []
return self._result_to_get_result(matches)
except Exception as e:
log.error(f"Error getting collection '{collection_name}': {e}")
return None
def delete(
self,
collection_name: str,
ids: Optional[List[str]] = None,
filter: Optional[Dict] = None,
) -> None:
"""Delete vectors by IDs or filter."""
collection_name_with_prefix = self._get_collection_name_with_prefix(
collection_name
)
try:
if ids:
# Delete by IDs (in batches for large deletions)
for i in range(0, len(ids), BATCH_SIZE):
batch_ids = ids[i : i + BATCH_SIZE]
# Note: When deleting by ID, we can't filter by collection_name
# This is a limitation of Pinecone - be careful with ID uniqueness
self.index.delete(ids=batch_ids)
log.debug(
f"Deleted batch of {len(batch_ids)} vectors by ID "
f"from '{collection_name_with_prefix}'"
)
log.info(
f"Successfully deleted {len(ids)} vectors by ID "
f"from '{collection_name_with_prefix}'"
)
elif filter:
# Combine user filter with collection_name
pinecone_filter = {"collection_name": collection_name_with_prefix}
if filter:
pinecone_filter.update(filter)
# Delete by metadata filter
self.index.delete(filter=pinecone_filter)
log.info(
f"Successfully deleted vectors by filter from '{collection_name_with_prefix}'"
)
else:
log.warning("No ids or filter provided for delete operation")
except Exception as e:
log.error(f"Error deleting from collection '{collection_name}': {e}")
raise
def reset(self) -> None:
"""Reset the database by deleting all collections."""
try:
self.index.delete(delete_all=True)
log.info("All vectors successfully deleted from the index.")
except Exception as e:
log.error(f"Failed to reset Pinecone index: {e}")
raise
def close(self):
"""Shut down resources."""
try:
# The new Pinecone client doesn't need explicit closing
pass
except Exception as e:
log.warning(f"Failed to clean up Pinecone resources: {e}")
self._executor.shutdown(wait=True)
def __enter__(self):
"""Enter context manager."""
return self
def __exit__(self, exc_type, exc_val, exc_tb):
"""Exit context manager, ensuring resources are cleaned up."""
self.close()
@@ -1,25 +1,70 @@
from typing import Optional
import logging
from urllib.parse import urlparse
from qdrant_client import QdrantClient as Qclient
from qdrant_client.http.models import PointStruct
from qdrant_client.models import models
from open_webui.retrieval.vector.main import VectorItem, SearchResult, GetResult
from open_webui.config import QDRANT_URI, QDRANT_API_KEY
from open_webui.retrieval.vector.main import (
VectorDBBase,
VectorItem,
SearchResult,
GetResult,
)
from open_webui.config import (
QDRANT_URI,
QDRANT_API_KEY,
QDRANT_ON_DISK,
QDRANT_GRPC_PORT,
QDRANT_PREFER_GRPC,
QDRANT_COLLECTION_PREFIX,
QDRANT_TIMEOUT,
QDRANT_HNSW_M,
)
from open_webui.env import SRC_LOG_LEVELS
NO_LIMIT = 999999999
log = logging.getLogger(__name__)
log.setLevel(SRC_LOG_LEVELS["RAG"])
class QdrantClient:
class QdrantClient(VectorDBBase):
def __init__(self):
self.collection_prefix = "open-webui"
self.collection_prefix = QDRANT_COLLECTION_PREFIX
self.QDRANT_URI = QDRANT_URI
self.QDRANT_API_KEY = QDRANT_API_KEY
self.client = (
Qclient(url=self.QDRANT_URI, api_key=self.QDRANT_API_KEY)
if self.QDRANT_URI
else None
)
self.QDRANT_ON_DISK = QDRANT_ON_DISK
self.PREFER_GRPC = QDRANT_PREFER_GRPC
self.GRPC_PORT = QDRANT_GRPC_PORT
self.QDRANT_TIMEOUT = QDRANT_TIMEOUT
self.QDRANT_HNSW_M = QDRANT_HNSW_M
if not self.QDRANT_URI:
self.client = None
return
# Unified handling for either scheme
parsed = urlparse(self.QDRANT_URI)
host = parsed.hostname or self.QDRANT_URI
http_port = parsed.port or 6333 # default REST port
if self.PREFER_GRPC:
self.client = Qclient(
host=host,
port=http_port,
grpc_port=self.GRPC_PORT,
prefer_grpc=self.PREFER_GRPC,
api_key=self.QDRANT_API_KEY,
timeout=self.QDRANT_TIMEOUT,
)
else:
self.client = Qclient(
url=self.QDRANT_URI,
api_key=self.QDRANT_API_KEY,
timeout=QDRANT_TIMEOUT,
)
def _result_to_get_result(self, points) -> GetResult:
ids = []
@@ -45,11 +90,35 @@ class QdrantClient:
self.client.create_collection(
collection_name=collection_name_with_prefix,
vectors_config=models.VectorParams(
size=dimension, distance=models.Distance.COSINE
size=dimension,
distance=models.Distance.COSINE,
on_disk=self.QDRANT_ON_DISK,
),
hnsw_config=models.HnswConfigDiff(
m=self.QDRANT_HNSW_M,
),
)
print(f"collection {collection_name_with_prefix} successfully created!")
# Create payload indexes for efficient filtering
self.client.create_payload_index(
collection_name=collection_name_with_prefix,
field_name="metadata.hash",
field_schema=models.KeywordIndexParams(
type=models.KeywordIndexType.KEYWORD,
is_tenant=False,
on_disk=self.QDRANT_ON_DISK,
),
)
self.client.create_payload_index(
collection_name=collection_name_with_prefix,
field_name="metadata.file_id",
field_schema=models.KeywordIndexParams(
type=models.KeywordIndexType.KEYWORD,
is_tenant=False,
on_disk=self.QDRANT_ON_DISK,
),
)
log.info(f"collection {collection_name_with_prefix} successfully created!")
def _create_collection_if_not_exists(self, collection_name, dimension):
if not self.has_collection(collection_name=collection_name):
@@ -94,7 +163,8 @@ class QdrantClient:
ids=get_result.ids,
documents=get_result.documents,
metadatas=get_result.metadatas,
distances=[[point.score for point in query_response.points]],
# qdrant distance is [-1, 1], normalize to [0, 1]
distances=[[(point.score + 1.0) / 2.0 for point in query_response.points]],
)
def query(self, collection_name: str, filter: dict, limit: Optional[int] = None):
@@ -113,23 +183,23 @@ class QdrantClient:
)
)
points = self.client.query_points(
points = self.client.scroll(
collection_name=f"{self.collection_prefix}_{collection_name}",
query_filter=models.Filter(should=field_conditions),
scroll_filter=models.Filter(should=field_conditions),
limit=limit,
)
return self._result_to_get_result(points.points)
return self._result_to_get_result(points[0])
except Exception as e:
print(e)
log.exception(f"Error querying a collection '{collection_name}': {e}")
return None
def get(self, collection_name: str) -> Optional[GetResult]:
# Get all the items in the collection.
points = self.client.query_points(
points = self.client.scroll(
collection_name=f"{self.collection_prefix}_{collection_name}",
limit=NO_LIMIT, # otherwise qdrant would set limit to 10!
)
return self._result_to_get_result(points.points)
return self._result_to_get_result(points[0])
def insert(self, collection_name: str, items: list[VectorItem]):
# Insert the items into the collection, if the collection does not exist, it will be created.
@@ -0,0 +1,365 @@
import logging
from typing import Optional, Tuple, List, Dict, Any
from urllib.parse import urlparse
import grpc
from open_webui.config import (
QDRANT_API_KEY,
QDRANT_GRPC_PORT,
QDRANT_ON_DISK,
QDRANT_PREFER_GRPC,
QDRANT_URI,
QDRANT_COLLECTION_PREFIX,
QDRANT_TIMEOUT,
QDRANT_HNSW_M,
)
from open_webui.env import SRC_LOG_LEVELS
from open_webui.retrieval.vector.main import (
GetResult,
SearchResult,
VectorDBBase,
VectorItem,
)
from qdrant_client import QdrantClient as Qclient
from qdrant_client.http.exceptions import UnexpectedResponse
from qdrant_client.http.models import PointStruct
from qdrant_client.models import models
NO_LIMIT = 999999999
TENANT_ID_FIELD = "tenant_id"
DEFAULT_DIMENSION = 384
log = logging.getLogger(__name__)
log.setLevel(SRC_LOG_LEVELS["RAG"])
def _tenant_filter(tenant_id: str) -> models.FieldCondition:
return models.FieldCondition(
key=TENANT_ID_FIELD, match=models.MatchValue(value=tenant_id)
)
def _metadata_filter(key: str, value: Any) -> models.FieldCondition:
return models.FieldCondition(
key=f"metadata.{key}", match=models.MatchValue(value=value)
)
class QdrantClient(VectorDBBase):
def __init__(self):
self.collection_prefix = QDRANT_COLLECTION_PREFIX
self.QDRANT_URI = QDRANT_URI
self.QDRANT_API_KEY = QDRANT_API_KEY
self.QDRANT_ON_DISK = QDRANT_ON_DISK
self.PREFER_GRPC = QDRANT_PREFER_GRPC
self.GRPC_PORT = QDRANT_GRPC_PORT
self.QDRANT_TIMEOUT = QDRANT_TIMEOUT
self.QDRANT_HNSW_M = QDRANT_HNSW_M
if not self.QDRANT_URI:
raise ValueError(
"QDRANT_URI is not set. Please configure it in the environment variables."
)
# Unified handling for either scheme
parsed = urlparse(self.QDRANT_URI)
host = parsed.hostname or self.QDRANT_URI
http_port = parsed.port or 6333 # default REST port
self.client = (
Qclient(
host=host,
port=http_port,
grpc_port=self.GRPC_PORT,
prefer_grpc=self.PREFER_GRPC,
api_key=self.QDRANT_API_KEY,
timeout=self.QDRANT_TIMEOUT,
)
if self.PREFER_GRPC
else Qclient(
url=self.QDRANT_URI,
api_key=self.QDRANT_API_KEY,
timeout=self.QDRANT_TIMEOUT,
)
)
# Main collection types for multi-tenancy
self.MEMORY_COLLECTION = f"{self.collection_prefix}_memories"
self.KNOWLEDGE_COLLECTION = f"{self.collection_prefix}_knowledge"
self.FILE_COLLECTION = f"{self.collection_prefix}_files"
self.WEB_SEARCH_COLLECTION = f"{self.collection_prefix}_web-search"
self.HASH_BASED_COLLECTION = f"{self.collection_prefix}_hash-based"
def _result_to_get_result(self, points) -> GetResult:
ids, documents, metadatas = [], [], []
for point in points:
payload = point.payload
ids.append(point.id)
documents.append(payload["text"])
metadatas.append(payload["metadata"])
return GetResult(ids=[ids], documents=[documents], metadatas=[metadatas])
def _get_collection_and_tenant_id(self, collection_name: str) -> Tuple[str, str]:
"""
Maps the traditional collection name to multi-tenant collection and tenant ID.
Returns:
tuple: (collection_name, tenant_id)
"""
# Check for user memory collections
tenant_id = collection_name
if collection_name.startswith("user-memory-"):
return self.MEMORY_COLLECTION, tenant_id
# Check for file collections
elif collection_name.startswith("file-"):
return self.FILE_COLLECTION, tenant_id
# Check for web search collections
elif collection_name.startswith("web-search-"):
return self.WEB_SEARCH_COLLECTION, tenant_id
# Handle hash-based collections (YouTube and web URLs)
elif len(collection_name) == 63 and all(
c in "0123456789abcdef" for c in collection_name
):
return self.HASH_BASED_COLLECTION, tenant_id
else:
return self.KNOWLEDGE_COLLECTION, tenant_id
def _create_multi_tenant_collection(
self, mt_collection_name: str, dimension: int = DEFAULT_DIMENSION
):
"""
Creates a collection with multi-tenancy configuration and payload indexes for tenant_id and metadata fields.
"""
self.client.create_collection(
collection_name=mt_collection_name,
vectors_config=models.VectorParams(
size=dimension,
distance=models.Distance.COSINE,
on_disk=self.QDRANT_ON_DISK,
),
# Disable global index building due to multitenancy
# For more details https://qdrant.tech/documentation/guides/multiple-partitions/#calibrate-performance
hnsw_config=models.HnswConfigDiff(
payload_m=self.QDRANT_HNSW_M,
m=0,
),
)
log.info(
f"Multi-tenant collection {mt_collection_name} created with dimension {dimension}!"
)
self.client.create_payload_index(
collection_name=mt_collection_name,
field_name=TENANT_ID_FIELD,
field_schema=models.KeywordIndexParams(
type=models.KeywordIndexType.KEYWORD,
is_tenant=True,
on_disk=self.QDRANT_ON_DISK,
),
)
for field in ("metadata.hash", "metadata.file_id"):
self.client.create_payload_index(
collection_name=mt_collection_name,
field_name=field,
field_schema=models.KeywordIndexParams(
type=models.KeywordIndexType.KEYWORD,
on_disk=self.QDRANT_ON_DISK,
),
)
def _create_points(
self, items: List[VectorItem], tenant_id: str
) -> List[PointStruct]:
"""
Create point structs from vector items with tenant ID.
"""
return [
PointStruct(
id=item["id"],
vector=item["vector"],
payload={
"text": item["text"],
"metadata": item["metadata"],
TENANT_ID_FIELD: tenant_id,
},
)
for item in items
]
def _ensure_collection(
self, mt_collection_name: str, dimension: int = DEFAULT_DIMENSION
):
"""
Ensure the collection exists and payload indexes are created for tenant_id and metadata fields.
"""
if not self.client.collection_exists(collection_name=mt_collection_name):
self._create_multi_tenant_collection(mt_collection_name, dimension)
def has_collection(self, collection_name: str) -> bool:
"""
Check if a logical collection exists by checking for any points with the tenant ID.
"""
if not self.client:
return False
mt_collection, tenant_id = self._get_collection_and_tenant_id(collection_name)
if not self.client.collection_exists(collection_name=mt_collection):
return False
tenant_filter = _tenant_filter(tenant_id)
count_result = self.client.count(
collection_name=mt_collection,
count_filter=models.Filter(must=[tenant_filter]),
)
return count_result.count > 0
def delete(
self,
collection_name: str,
ids: Optional[List[str]] = None,
filter: Optional[Dict[str, Any]] = None,
):
"""
Delete vectors by ID or filter from a collection with tenant isolation.
"""
if not self.client:
return None
mt_collection, tenant_id = self._get_collection_and_tenant_id(collection_name)
if not self.client.collection_exists(collection_name=mt_collection):
log.debug(f"Collection {mt_collection} doesn't exist, nothing to delete")
return None
must_conditions = [_tenant_filter(tenant_id)]
should_conditions = []
if ids:
should_conditions = [_metadata_filter("id", id_value) for id_value in ids]
elif filter:
must_conditions += [_metadata_filter(k, v) for k, v in filter.items()]
return self.client.delete(
collection_name=mt_collection,
points_selector=models.FilterSelector(
filter=models.Filter(must=must_conditions, should=should_conditions)
),
)
def search(
self, collection_name: str, vectors: List[List[float | int]], limit: int
) -> Optional[SearchResult]:
"""
Search for the nearest neighbor items based on the vectors with tenant isolation.
"""
if not self.client or not vectors:
return None
mt_collection, tenant_id = self._get_collection_and_tenant_id(collection_name)
if not self.client.collection_exists(collection_name=mt_collection):
log.debug(f"Collection {mt_collection} doesn't exist, search returns None")
return None
tenant_filter = _tenant_filter(tenant_id)
query_response = self.client.query_points(
collection_name=mt_collection,
query=vectors[0],
limit=limit,
query_filter=models.Filter(must=[tenant_filter]),
)
get_result = self._result_to_get_result(query_response.points)
return SearchResult(
ids=get_result.ids,
documents=get_result.documents,
metadatas=get_result.metadatas,
distances=[[(point.score + 1.0) / 2.0 for point in query_response.points]],
)
def query(
self, collection_name: str, filter: Dict[str, Any], limit: Optional[int] = None
):
"""
Query points with filters and tenant isolation.
"""
if not self.client:
return None
mt_collection, tenant_id = self._get_collection_and_tenant_id(collection_name)
if not self.client.collection_exists(collection_name=mt_collection):
log.debug(f"Collection {mt_collection} doesn't exist, query returns None")
return None
if limit is None:
limit = NO_LIMIT
tenant_filter = _tenant_filter(tenant_id)
field_conditions = [_metadata_filter(k, v) for k, v in filter.items()]
combined_filter = models.Filter(must=[tenant_filter, *field_conditions])
points = self.client.scroll(
collection_name=mt_collection,
scroll_filter=combined_filter,
limit=limit,
)
return self._result_to_get_result(points[0])
def get(self, collection_name: str) -> Optional[GetResult]:
"""
Get all items in a collection with tenant isolation.
"""
if not self.client:
return None
mt_collection, tenant_id = self._get_collection_and_tenant_id(collection_name)
if not self.client.collection_exists(collection_name=mt_collection):
log.debug(f"Collection {mt_collection} doesn't exist, get returns None")
return None
tenant_filter = _tenant_filter(tenant_id)
points = self.client.scroll(
collection_name=mt_collection,
scroll_filter=models.Filter(must=[tenant_filter]),
limit=NO_LIMIT,
)
return self._result_to_get_result(points[0])
def upsert(self, collection_name: str, items: List[VectorItem]):
"""
Upsert items with tenant ID.
"""
if not self.client or not items:
return None
mt_collection, tenant_id = self._get_collection_and_tenant_id(collection_name)
dimension = len(items[0]["vector"])
self._ensure_collection(mt_collection, dimension)
points = self._create_points(items, tenant_id)
self.client.upload_points(mt_collection, points)
return None
def insert(self, collection_name: str, items: List[VectorItem]):
"""
Insert items with tenant ID.
"""
return self.upsert(collection_name, items)
def reset(self):
"""
Reset the database by deleting all collections.
"""
if not self.client:
return None
for collection in self.client.get_collections().collections:
if collection.name.startswith(self.collection_prefix):
self.client.delete_collection(collection_name=collection.name)
def delete_collection(self, collection_name: str):
"""
Delete a collection.
"""
if not self.client:
return None
mt_collection, tenant_id = self._get_collection_and_tenant_id(collection_name)
if not self.client.collection_exists(collection_name=mt_collection):
log.debug(f"Collection {mt_collection} doesn't exist, nothing to delete")
return None
self.client.delete(
collection_name=mt_collection,
points_selector=models.FilterSelector(
filter=models.Filter(must=[_tenant_filter(tenant_id)])
),
)
@@ -0,0 +1,752 @@
from backend.open_webui.retrieval.vector.utils import stringify_metadata
from open_webui.retrieval.vector.main import (
VectorDBBase,
VectorItem,
GetResult,
SearchResult,
)
from open_webui.config import S3_VECTOR_BUCKET_NAME, S3_VECTOR_REGION
from open_webui.env import SRC_LOG_LEVELS
from typing import List, Optional, Dict, Any, Union
import logging
import boto3
log = logging.getLogger(__name__)
log.setLevel(SRC_LOG_LEVELS["RAG"])
class S3VectorClient(VectorDBBase):
"""
AWS S3 Vector integration for Open WebUI Knowledge.
"""
def __init__(self):
self.bucket_name = S3_VECTOR_BUCKET_NAME
self.region = S3_VECTOR_REGION
# Simple validation - log warnings instead of raising exceptions
if not self.bucket_name:
log.warning("S3_VECTOR_BUCKET_NAME not set - S3Vector will not work")
if not self.region:
log.warning("S3_VECTOR_REGION not set - S3Vector will not work")
if self.bucket_name and self.region:
try:
self.client = boto3.client("s3vectors", region_name=self.region)
log.info(
f"S3Vector client initialized for bucket '{self.bucket_name}' in region '{self.region}'"
)
except Exception as e:
log.error(f"Failed to initialize S3Vector client: {e}")
self.client = None
else:
self.client = None
def _create_index(
self,
index_name: str,
dimension: int,
data_type: str = "float32",
distance_metric: str = "cosine",
) -> None:
"""
Create a new index in the S3 vector bucket for the given collection if it does not exist.
"""
if self.has_collection(index_name):
log.debug(f"Index '{index_name}' already exists, skipping creation")
return
try:
self.client.create_index(
vectorBucketName=self.bucket_name,
indexName=index_name,
dataType=data_type,
dimension=dimension,
distanceMetric=distance_metric,
)
log.info(
f"Created S3 index: {index_name} (dim={dimension}, type={data_type}, metric={distance_metric})"
)
except Exception as e:
log.error(f"Error creating S3 index '{index_name}': {e}")
raise
def _filter_metadata(
self, metadata: Dict[str, Any], item_id: str
) -> Dict[str, Any]:
"""
Filter vector metadata keys to comply with S3 Vector API limit of 10 keys maximum.
"""
if not isinstance(metadata, dict) or len(metadata) <= 10:
return metadata
# Keep only the first 10 keys, prioritizing important ones based on actual Open WebUI metadata
important_keys = [
"text", # The actual document content
"file_id", # File ID
"source", # Document source file
"title", # Document title
"page", # Page number
"total_pages", # Total pages in document
"embedding_config", # Embedding configuration
"created_by", # User who created it
"name", # Document name
"hash", # Content hash
]
filtered_metadata = {}
# First, add important keys if they exist
for key in important_keys:
if key in metadata:
filtered_metadata[key] = metadata[key]
if len(filtered_metadata) >= 10:
break
# If we still have room, add other keys
if len(filtered_metadata) < 10:
for key, value in metadata.items():
if key not in filtered_metadata:
filtered_metadata[key] = value
if len(filtered_metadata) >= 10:
break
log.warning(
f"Metadata for key '{item_id}' had {len(metadata)} keys, limited to 10 keys"
)
return filtered_metadata
def has_collection(self, collection_name: str) -> bool:
"""
Check if a vector index (collection) exists in the S3 vector bucket.
"""
try:
response = self.client.list_indexes(vectorBucketName=self.bucket_name)
indexes = response.get("indexes", [])
return any(idx.get("indexName") == collection_name for idx in indexes)
except Exception as e:
log.error(f"Error listing indexes: {e}")
return False
def delete_collection(self, collection_name: str) -> None:
"""
Delete an entire S3 Vector index/collection.
"""
if not self.has_collection(collection_name):
log.warning(
f"Collection '{collection_name}' does not exist, nothing to delete"
)
return
try:
log.info(f"Deleting collection '{collection_name}'")
self.client.delete_index(
vectorBucketName=self.bucket_name, indexName=collection_name
)
log.info(f"Successfully deleted collection '{collection_name}'")
except Exception as e:
log.error(f"Error deleting collection '{collection_name}': {e}")
raise
def insert(self, collection_name: str, items: List[VectorItem]) -> None:
"""
Insert vector items into the S3 Vector index. Create index if it does not exist.
"""
if not items:
log.warning("No items to insert")
return
dimension = len(items[0]["vector"])
try:
if not self.has_collection(collection_name):
log.info(f"Index '{collection_name}' does not exist. Creating index.")
self._create_index(
index_name=collection_name,
dimension=dimension,
data_type="float32",
distance_metric="cosine",
)
# Prepare vectors for insertion
vectors = []
for item in items:
# Ensure vector data is in the correct format for S3 Vector API
vector_data = item["vector"]
if isinstance(vector_data, list):
# Convert list to float32 values as required by S3 Vector API
vector_data = [float(x) for x in vector_data]
# Prepare metadata, ensuring the text field is preserved
metadata = item.get("metadata", {}).copy()
# Add the text field to metadata so it's available for retrieval
metadata["text"] = item["text"]
# Convert metadata to string format for consistency
metadata = stringify_metadata(metadata)
# Filter metadata to comply with S3 Vector API limit of 10 keys
metadata = self._filter_metadata(metadata, item["id"])
vectors.append(
{
"key": item["id"],
"data": {"float32": vector_data},
"metadata": metadata,
}
)
# Insert vectors
self.client.put_vectors(
vectorBucketName=self.bucket_name,
indexName=collection_name,
vectors=vectors,
)
log.info(f"Inserted {len(vectors)} vectors into index '{collection_name}'.")
except Exception as e:
log.error(f"Error inserting vectors: {e}")
raise
def upsert(self, collection_name: str, items: List[VectorItem]) -> None:
"""
Insert or update vector items in the S3 Vector index. Create index if it does not exist.
"""
if not items:
log.warning("No items to upsert")
return
dimension = len(items[0]["vector"])
log.info(f"Upsert dimension: {dimension}")
try:
if not self.has_collection(collection_name):
log.info(
f"Index '{collection_name}' does not exist. Creating index for upsert."
)
self._create_index(
index_name=collection_name,
dimension=dimension,
data_type="float32",
distance_metric="cosine",
)
# Prepare vectors for upsert
vectors = []
for item in items:
# Ensure vector data is in the correct format for S3 Vector API
vector_data = item["vector"]
if isinstance(vector_data, list):
# Convert list to float32 values as required by S3 Vector API
vector_data = [float(x) for x in vector_data]
# Prepare metadata, ensuring the text field is preserved
metadata = item.get("metadata", {}).copy()
# Add the text field to metadata so it's available for retrieval
metadata["text"] = item["text"]
# Convert metadata to string format for consistency
metadata = stringify_metadata(metadata)
# Filter metadata to comply with S3 Vector API limit of 10 keys
metadata = self._filter_metadata(metadata, item["id"])
vectors.append(
{
"key": item["id"],
"data": {"float32": vector_data},
"metadata": metadata,
}
)
# Upsert vectors (using put_vectors for upsert semantics)
log.info(
f"Upserting {len(vectors)} vectors. First vector sample: key={vectors[0]['key']}, data_type={type(vectors[0]['data']['float32'])}, data_len={len(vectors[0]['data']['float32'])}"
)
self.client.put_vectors(
vectorBucketName=self.bucket_name,
indexName=collection_name,
vectors=vectors,
)
log.info(f"Upserted {len(vectors)} vectors into index '{collection_name}'.")
except Exception as e:
log.error(f"Error upserting vectors: {e}")
raise
def search(
self, collection_name: str, vectors: List[List[Union[float, int]]], limit: int
) -> Optional[SearchResult]:
"""
Search for similar vectors in a collection using multiple query vectors.
"""
if not self.has_collection(collection_name):
log.warning(f"Collection '{collection_name}' does not exist")
return None
if not vectors:
log.warning("No query vectors provided")
return None
try:
log.info(
f"Searching collection '{collection_name}' with {len(vectors)} query vectors, limit={limit}"
)
# Initialize result lists
all_ids = []
all_documents = []
all_metadatas = []
all_distances = []
# Process each query vector
for i, query_vector in enumerate(vectors):
log.debug(f"Processing query vector {i+1}/{len(vectors)}")
# Prepare the query vector in S3 Vector format
query_vector_dict = {"float32": [float(x) for x in query_vector]}
# Call S3 Vector query API
response = self.client.query_vectors(
vectorBucketName=self.bucket_name,
indexName=collection_name,
topK=limit,
queryVector=query_vector_dict,
returnMetadata=True,
returnDistance=True,
)
# Process results for this query
query_ids = []
query_documents = []
query_metadatas = []
query_distances = []
result_vectors = response.get("vectors", [])
for vector in result_vectors:
vector_id = vector.get("key")
vector_metadata = vector.get("metadata", {})
vector_distance = vector.get("distance", 0.0)
# Extract document text from metadata
document_text = ""
if isinstance(vector_metadata, dict):
# Get the text field first (highest priority)
document_text = vector_metadata.get("text")
if not document_text:
# Fallback to other possible text fields
document_text = (
vector_metadata.get("content")
or vector_metadata.get("document")
or vector_id
)
else:
document_text = vector_id
query_ids.append(vector_id)
query_documents.append(document_text)
query_metadatas.append(vector_metadata)
query_distances.append(vector_distance)
# Add this query's results to the overall results
all_ids.append(query_ids)
all_documents.append(query_documents)
all_metadatas.append(query_metadatas)
all_distances.append(query_distances)
log.info(f"Search completed. Found results for {len(all_ids)} queries")
# Return SearchResult format
return SearchResult(
ids=all_ids if all_ids else None,
documents=all_documents if all_documents else None,
metadatas=all_metadatas if all_metadatas else None,
distances=all_distances if all_distances else None,
)
except Exception as e:
log.error(f"Error searching collection '{collection_name}': {str(e)}")
# Handle specific AWS exceptions
if hasattr(e, "response") and "Error" in e.response:
error_code = e.response["Error"]["Code"]
if error_code == "NotFoundException":
log.warning(f"Collection '{collection_name}' not found")
return None
elif error_code == "ValidationException":
log.error(f"Invalid query vector dimensions or parameters")
return None
elif error_code == "AccessDeniedException":
log.error(
f"Access denied for collection '{collection_name}'. Check permissions."
)
return None
raise
def query(
self, collection_name: str, filter: Dict, limit: Optional[int] = None
) -> Optional[GetResult]:
"""
Query vectors from a collection using metadata filter.
"""
if not self.has_collection(collection_name):
log.warning(f"Collection '{collection_name}' does not exist")
return GetResult(ids=[[]], documents=[[]], metadatas=[[]])
if not filter:
log.warning("No filter provided, returning all vectors")
return self.get(collection_name)
try:
log.info(f"Querying collection '{collection_name}' with filter: {filter}")
# For S3 Vector, we need to use list_vectors and then filter results
# Since S3 Vector may not support complex server-side filtering,
# we'll retrieve all vectors and filter client-side
# Get all vectors first
all_vectors_result = self.get(collection_name)
if not all_vectors_result or not all_vectors_result.ids:
log.warning("No vectors found in collection")
return GetResult(ids=[[]], documents=[[]], metadatas=[[]])
# Extract the lists from the result
all_ids = all_vectors_result.ids[0] if all_vectors_result.ids else []
all_documents = (
all_vectors_result.documents[0] if all_vectors_result.documents else []
)
all_metadatas = (
all_vectors_result.metadatas[0] if all_vectors_result.metadatas else []
)
# Apply client-side filtering
filtered_ids = []
filtered_documents = []
filtered_metadatas = []
for i, metadata in enumerate(all_metadatas):
if self._matches_filter(metadata, filter):
if i < len(all_ids):
filtered_ids.append(all_ids[i])
if i < len(all_documents):
filtered_documents.append(all_documents[i])
filtered_metadatas.append(metadata)
# Apply limit if specified
if limit and len(filtered_ids) >= limit:
break
log.info(
f"Filter applied: {len(filtered_ids)} vectors match out of {len(all_ids)} total"
)
# Return GetResult format
if filtered_ids:
return GetResult(
ids=[filtered_ids],
documents=[filtered_documents],
metadatas=[filtered_metadatas],
)
else:
return GetResult(ids=[[]], documents=[[]], metadatas=[[]])
except Exception as e:
log.error(f"Error querying collection '{collection_name}': {str(e)}")
# Handle specific AWS exceptions
if hasattr(e, "response") and "Error" in e.response:
error_code = e.response["Error"]["Code"]
if error_code == "NotFoundException":
log.warning(f"Collection '{collection_name}' not found")
return GetResult(ids=[[]], documents=[[]], metadatas=[[]])
elif error_code == "AccessDeniedException":
log.error(
f"Access denied for collection '{collection_name}'. Check permissions."
)
return GetResult(ids=[[]], documents=[[]], metadatas=[[]])
raise
def get(self, collection_name: str) -> Optional[GetResult]:
"""
Retrieve all vectors from a collection.
"""
if not self.has_collection(collection_name):
log.warning(f"Collection '{collection_name}' does not exist")
return GetResult(ids=[[]], documents=[[]], metadatas=[[]])
try:
log.info(f"Retrieving all vectors from collection '{collection_name}'")
# Initialize result lists
all_ids = []
all_documents = []
all_metadatas = []
# Handle pagination
next_token = None
while True:
# Prepare request parameters
request_params = {
"vectorBucketName": self.bucket_name,
"indexName": collection_name,
"returnData": False, # Don't include vector data (not needed for get)
"returnMetadata": True, # Include metadata
"maxResults": 500, # Use reasonable page size
}
if next_token:
request_params["nextToken"] = next_token
# Call S3 Vector API
response = self.client.list_vectors(**request_params)
# Process vectors in this page
vectors = response.get("vectors", [])
for vector in vectors:
vector_id = vector.get("key")
vector_data = vector.get("data", {})
vector_metadata = vector.get("metadata", {})
# Extract the actual vector array
vector_array = vector_data.get("float32", [])
# For documents, we try to extract text from metadata or use the vector ID
document_text = ""
if isinstance(vector_metadata, dict):
# Get the text field first (highest priority)
document_text = vector_metadata.get("text")
if not document_text:
# Fallback to other possible text fields
document_text = (
vector_metadata.get("content")
or vector_metadata.get("document")
or vector_id
)
# Log the actual content for debugging
log.debug(
f"Document text preview (first 200 chars): {str(document_text)[:200]}"
)
else:
document_text = vector_id
all_ids.append(vector_id)
all_documents.append(document_text)
all_metadatas.append(vector_metadata)
# Check if there are more pages
next_token = response.get("nextToken")
if not next_token:
break
log.info(
f"Retrieved {len(all_ids)} vectors from collection '{collection_name}'"
)
# Return in GetResult format
# The Open WebUI GetResult expects lists of lists, so we wrap each list
if all_ids:
return GetResult(
ids=[all_ids], documents=[all_documents], metadatas=[all_metadatas]
)
else:
return GetResult(ids=[[]], documents=[[]], metadatas=[[]])
except Exception as e:
log.error(
f"Error retrieving vectors from collection '{collection_name}': {str(e)}"
)
# Handle specific AWS exceptions
if hasattr(e, "response") and "Error" in e.response:
error_code = e.response["Error"]["Code"]
if error_code == "NotFoundException":
log.warning(f"Collection '{collection_name}' not found")
return GetResult(ids=[[]], documents=[[]], metadatas=[[]])
elif error_code == "AccessDeniedException":
log.error(
f"Access denied for collection '{collection_name}'. Check permissions."
)
return GetResult(ids=[[]], documents=[[]], metadatas=[[]])
raise
def delete(
self,
collection_name: str,
ids: Optional[List[str]] = None,
filter: Optional[Dict] = None,
) -> None:
"""
Delete vectors by ID or filter from a collection.
"""
if not self.has_collection(collection_name):
log.warning(
f"Collection '{collection_name}' does not exist, nothing to delete"
)
return
# Check if this is a knowledge collection (not file-specific)
is_knowledge_collection = not collection_name.startswith("file-")
try:
if ids:
# Delete by specific vector IDs/keys
log.info(
f"Deleting {len(ids)} vectors by IDs from collection '{collection_name}'"
)
self.client.delete_vectors(
vectorBucketName=self.bucket_name,
indexName=collection_name,
keys=ids,
)
log.info(f"Deleted {len(ids)} vectors from index '{collection_name}'")
elif filter:
# Handle filter-based deletion
log.info(
f"Deleting vectors by filter from collection '{collection_name}': {filter}"
)
# If this is a knowledge collection and we have a file_id filter,
# also clean up the corresponding file-specific collection
if is_knowledge_collection and "file_id" in filter:
file_id = filter["file_id"]
file_collection_name = f"file-{file_id}"
if self.has_collection(file_collection_name):
log.info(
f"Found related file-specific collection '{file_collection_name}', deleting it to prevent duplicates"
)
self.delete_collection(file_collection_name)
# For the main collection, implement query-then-delete
# First, query to get IDs matching the filter
query_result = self.query(collection_name, filter)
if query_result and query_result.ids and query_result.ids[0]:
matching_ids = query_result.ids[0]
log.info(
f"Found {len(matching_ids)} vectors matching filter, deleting them"
)
# Delete the matching vectors by ID
self.client.delete_vectors(
vectorBucketName=self.bucket_name,
indexName=collection_name,
keys=matching_ids,
)
log.info(
f"Deleted {len(matching_ids)} vectors from index '{collection_name}' using filter"
)
else:
log.warning("No vectors found matching the filter criteria")
else:
log.warning("No IDs or filter provided for deletion")
except Exception as e:
log.error(
f"Error deleting vectors from collection '{collection_name}': {e}"
)
raise
def reset(self) -> None:
"""
Reset/clear all vector data. For S3 Vector, this deletes all indexes.
"""
try:
log.warning(
"Reset called - this will delete all vector indexes in the S3 bucket"
)
# List all indexes
response = self.client.list_indexes(vectorBucketName=self.bucket_name)
indexes = response.get("indexes", [])
if not indexes:
log.warning("No indexes found to delete")
return
# Delete all indexes
deleted_count = 0
for index in indexes:
index_name = index.get("indexName")
if index_name:
try:
self.client.delete_index(
vectorBucketName=self.bucket_name, indexName=index_name
)
deleted_count += 1
log.info(f"Deleted index: {index_name}")
except Exception as e:
log.error(f"Error deleting index '{index_name}': {e}")
log.info(f"Reset completed: deleted {deleted_count} indexes")
except Exception as e:
log.error(f"Error during reset: {e}")
raise
def _matches_filter(self, metadata: Dict[str, Any], filter: Dict[str, Any]) -> bool:
"""
Check if metadata matches the given filter conditions.
"""
if not isinstance(metadata, dict) or not isinstance(filter, dict):
return False
# Check each filter condition
for key, expected_value in filter.items():
# Handle special operators
if key.startswith("$"):
if key == "$and":
# All conditions must match
if not isinstance(expected_value, list):
continue
for condition in expected_value:
if not self._matches_filter(metadata, condition):
return False
elif key == "$or":
# At least one condition must match
if not isinstance(expected_value, list):
continue
any_match = False
for condition in expected_value:
if self._matches_filter(metadata, condition):
any_match = True
break
if not any_match:
return False
continue
# Get the actual value from metadata
actual_value = metadata.get(key)
# Handle different types of expected values
if isinstance(expected_value, dict):
# Handle comparison operators
for op, op_value in expected_value.items():
if op == "$eq":
if actual_value != op_value:
return False
elif op == "$ne":
if actual_value == op_value:
return False
elif op == "$in":
if (
not isinstance(op_value, list)
or actual_value not in op_value
):
return False
elif op == "$nin":
if isinstance(op_value, list) and actual_value in op_value:
return False
elif op == "$exists":
if bool(op_value) != (key in metadata):
return False
# Add more operators as needed
else:
# Simple equality check
if actual_value != expected_value:
return False
return True
@@ -0,0 +1,63 @@
from open_webui.retrieval.vector.main import VectorDBBase
from open_webui.retrieval.vector.type import VectorType
from open_webui.config import VECTOR_DB, ENABLE_QDRANT_MULTITENANCY_MODE
class Vector:
@staticmethod
def get_vector(vector_type: str) -> VectorDBBase:
"""
get vector db instance by vector type
"""
match vector_type:
case VectorType.MILVUS:
from open_webui.retrieval.vector.dbs.milvus import MilvusClient
return MilvusClient()
case VectorType.QDRANT:
if ENABLE_QDRANT_MULTITENANCY_MODE:
from open_webui.retrieval.vector.dbs.qdrant_multitenancy import (
QdrantClient,
)
return QdrantClient()
else:
from open_webui.retrieval.vector.dbs.qdrant import QdrantClient
return QdrantClient()
case VectorType.PINECONE:
from open_webui.retrieval.vector.dbs.pinecone import PineconeClient
return PineconeClient()
case VectorType.S3VECTOR:
from open_webui.retrieval.vector.dbs.s3vector import S3VectorClient
return S3VectorClient()
case VectorType.OPENSEARCH:
from open_webui.retrieval.vector.dbs.opensearch import OpenSearchClient
return OpenSearchClient()
case VectorType.PGVECTOR:
from open_webui.retrieval.vector.dbs.pgvector import PgvectorClient
return PgvectorClient()
case VectorType.ELASTICSEARCH:
from open_webui.retrieval.vector.dbs.elasticsearch import (
ElasticsearchClient,
)
return ElasticsearchClient()
case VectorType.CHROMA:
from open_webui.retrieval.vector.dbs.chroma import ChromaClient
return ChromaClient()
case VectorType.ORACLE23AI:
from open_webui.retrieval.vector.dbs.oracle23ai import Oracle23aiClient
return Oracle23aiClient()
case _:
raise ValueError(f"Unsupported vector type: {vector_type}")
VECTOR_DB_CLIENT = Vector.get_vector(VECTOR_DB)
+68 -1
View File
@@ -1,5 +1,6 @@
from pydantic import BaseModel
from typing import Optional, List, Any
from abc import ABC, abstractmethod
from typing import Any, Dict, List, Optional, Union
class VectorItem(BaseModel):
@@ -17,3 +18,69 @@ class GetResult(BaseModel):
class SearchResult(GetResult):
distances: Optional[List[List[float | int]]]
class VectorDBBase(ABC):
"""
Abstract base class for all vector database backends.
Implementations of this class provide methods for collection management,
vector insertion, deletion, similarity search, and metadata filtering.
Any custom vector database integration must inherit from this class and
implement all abstract methods.
"""
@abstractmethod
def has_collection(self, collection_name: str) -> bool:
"""Check if the collection exists in the vector DB."""
pass
@abstractmethod
def delete_collection(self, collection_name: str) -> None:
"""Delete a collection from the vector DB."""
pass
@abstractmethod
def insert(self, collection_name: str, items: List[VectorItem]) -> None:
"""Insert a list of vector items into a collection."""
pass
@abstractmethod
def upsert(self, collection_name: str, items: List[VectorItem]) -> None:
"""Insert or update vector items in a collection."""
pass
@abstractmethod
def search(
self, collection_name: str, vectors: List[List[Union[float, int]]], limit: int
) -> Optional[SearchResult]:
"""Search for similar vectors in a collection."""
pass
@abstractmethod
def query(
self, collection_name: str, filter: Dict, limit: Optional[int] = None
) -> Optional[GetResult]:
"""Query vectors from a collection using metadata filter."""
pass
@abstractmethod
def get(self, collection_name: str) -> Optional[GetResult]:
"""Retrieve all vectors from a collection."""
pass
@abstractmethod
def delete(
self,
collection_name: str,
ids: Optional[List[str]] = None,
filter: Optional[Dict] = None,
) -> None:
"""Delete vectors by ID or filter from a collection."""
pass
@abstractmethod
def reset(self) -> None:
"""Reset the vector database by removing all collections or those matching a condition."""
pass
@@ -0,0 +1,13 @@
from enum import StrEnum
class VectorType(StrEnum):
MILVUS = "milvus"
QDRANT = "qdrant"
CHROMA = "chroma"
PINECONE = "pinecone"
ELASTICSEARCH = "elasticsearch"
OPENSEARCH = "opensearch"
PGVECTOR = "pgvector"
ORACLE23AI = "oracle23ai"
S3VECTOR = "s3vector"
@@ -0,0 +1,14 @@
from datetime import datetime
def stringify_metadata(
metadata: dict[str, any],
) -> dict[str, any]:
for key, value in metadata.items():
if (
isinstance(value, datetime)
or isinstance(value, list)
or isinstance(value, dict)
):
metadata[key] = str(value)
return metadata
+65
View File
@@ -0,0 +1,65 @@
import logging
from typing import Optional
import requests
import json
from open_webui.retrieval.web.main import SearchResult, get_filtered_results
from open_webui.env import SRC_LOG_LEVELS
log = logging.getLogger(__name__)
log.setLevel(SRC_LOG_LEVELS["RAG"])
def _parse_response(response):
result = {}
if "data" in response:
data = response["data"]
if "webPages" in data:
webPages = data["webPages"]
if "value" in webPages:
result["webpage"] = [
{
"id": item.get("id", ""),
"name": item.get("name", ""),
"url": item.get("url", ""),
"snippet": item.get("snippet", ""),
"summary": item.get("summary", ""),
"siteName": item.get("siteName", ""),
"siteIcon": item.get("siteIcon", ""),
"datePublished": item.get("datePublished", "")
or item.get("dateLastCrawled", ""),
}
for item in webPages["value"]
]
return result
def search_bocha(
api_key: str, query: str, count: int, filter_list: Optional[list[str]] = None
) -> list[SearchResult]:
"""Search using Bocha's Search API and return the results as a list of SearchResult objects.
Args:
api_key (str): A Bocha Search API key
query (str): The query to search for
"""
url = "https://api.bochaai.com/v1/web-search?utm_source=ollama"
headers = {"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"}
payload = json.dumps(
{"query": query, "summary": True, "freshness": "noLimit", "count": count}
)
response = requests.post(url, headers=headers, data=payload, timeout=5)
response.raise_for_status()
results = _parse_response(response.json())
print(results)
if filter_list:
results = get_filtered_results(results, filter_list)
return [
SearchResult(
link=result["url"], title=result.get("name"), snippet=result.get("summary")
)
for result in results.get("webpage", [])[:count]
]
+3 -1
View File
@@ -36,7 +36,9 @@ def search_brave(
return [
SearchResult(
link=result["url"], title=result.get("title"), snippet=result.get("snippet")
link=result["url"],
title=result.get("title"),
snippet=result.get("description"),
)
for result in results[:count]
]
+18 -22
View File
@@ -2,7 +2,8 @@ import logging
from typing import Optional
from open_webui.retrieval.web.main import SearchResult, get_filtered_results
from duckduckgo_search import DDGS
from ddgs import DDGS
from ddgs.exceptions import RatelimitException
from open_webui.env import SRC_LOG_LEVELS
log = logging.getLogger(__name__)
@@ -22,29 +23,24 @@ def search_duckduckgo(
list[SearchResult]: A list of search results
"""
# Use the DDGS context manager to create a DDGS object
search_results = []
with DDGS() as ddgs:
# Use the ddgs.text() method to perform the search
ddgs_gen = ddgs.text(
query, safesearch="moderate", max_results=count, backend="api"
)
# Check if there are search results
if ddgs_gen:
# Convert the search results into a list
search_results = [r for r in ddgs_gen]
# Create an empty list to store the SearchResult objects
results = []
# Iterate over each search result
for result in search_results:
# Create a SearchResult object and append it to the results list
results.append(
SearchResult(
link=result["href"],
title=result.get("title"),
snippet=result.get("body"),
try:
search_results = ddgs.text(
query, safesearch="moderate", max_results=count, backend="lite"
)
)
except RatelimitException as e:
log.error(f"RatelimitException: {e}")
if filter_list:
results = get_filtered_results(results, filter_list)
search_results = get_filtered_results(search_results, filter_list)
# Return the list of search results
return results
return [
SearchResult(
link=result["href"],
title=result.get("title"),
snippet=result.get("body"),
)
for result in search_results
]
+76
View File
@@ -0,0 +1,76 @@
import logging
from dataclasses import dataclass
from typing import Optional
import requests
from open_webui.env import SRC_LOG_LEVELS
from open_webui.retrieval.web.main import SearchResult
log = logging.getLogger(__name__)
log.setLevel(SRC_LOG_LEVELS["RAG"])
EXA_API_BASE = "https://api.exa.ai"
@dataclass
class ExaResult:
url: str
title: str
text: str
def search_exa(
api_key: str,
query: str,
count: int,
filter_list: Optional[list[str]] = None,
) -> list[SearchResult]:
"""Search using Exa Search API and return the results as a list of SearchResult objects.
Args:
api_key (str): A Exa Search API key
query (str): The query to search for
count (int): Number of results to return
filter_list (Optional[list[str]]): List of domains to filter results by
"""
log.info(f"Searching with Exa for query: {query}")
headers = {"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"}
payload = {
"query": query,
"numResults": count or 5,
"includeDomains": filter_list,
"contents": {"text": True, "highlights": True},
"type": "auto", # Use the auto search type (keyword or neural)
}
try:
response = requests.post(
f"{EXA_API_BASE}/search", headers=headers, json=payload
)
response.raise_for_status()
data = response.json()
results = []
for result in data["results"]:
results.append(
ExaResult(
url=result["url"],
title=result["title"],
text=result["text"],
)
)
log.info(f"Found {len(results)} results")
return [
SearchResult(
link=result.url,
title=result.title,
snippet=result.text,
)
for result in results
]
except Exception as e:
log.error(f"Error searching Exa: {e}")
return []
@@ -0,0 +1,47 @@
import logging
from typing import Optional, List
import requests
from open_webui.retrieval.web.main import SearchResult, get_filtered_results
from open_webui.env import SRC_LOG_LEVELS
log = logging.getLogger(__name__)
log.setLevel(SRC_LOG_LEVELS["RAG"])
def search_external(
external_url: str,
external_api_key: str,
query: str,
count: int,
filter_list: Optional[List[str]] = None,
) -> List[SearchResult]:
try:
response = requests.post(
external_url,
headers={
"User-Agent": "Open WebUI (https://github.com/open-webui/open-webui) RAG Bot",
"Authorization": f"Bearer {external_api_key}",
},
json={
"query": query,
"count": count,
},
)
response.raise_for_status()
results = response.json()
if filter_list:
results = get_filtered_results(results, filter_list)
results = [
SearchResult(
link=result.get("link"),
title=result.get("title"),
snippet=result.get("snippet"),
)
for result in results[:count]
]
log.info(f"External search results: {results}")
return results
except Exception as e:
log.error(f"Error in External search: {e}")
return []
@@ -0,0 +1,49 @@
import logging
from typing import Optional, List
from urllib.parse import urljoin
import requests
from open_webui.retrieval.web.main import SearchResult, get_filtered_results
from open_webui.env import SRC_LOG_LEVELS
log = logging.getLogger(__name__)
log.setLevel(SRC_LOG_LEVELS["RAG"])
def search_firecrawl(
firecrawl_url: str,
firecrawl_api_key: str,
query: str,
count: int,
filter_list: Optional[List[str]] = None,
) -> List[SearchResult]:
try:
firecrawl_search_url = urljoin(firecrawl_url, "/v1/search")
response = requests.post(
firecrawl_search_url,
headers={
"User-Agent": "Open WebUI (https://github.com/open-webui/open-webui) RAG Bot",
"Authorization": f"Bearer {firecrawl_api_key}",
},
json={
"query": query,
"limit": count,
},
)
response.raise_for_status()
results = response.json().get("data", [])
if filter_list:
results = get_filtered_results(results, filter_list)
results = [
SearchResult(
link=result.get("url"),
title=result.get("title"),
snippet=result.get("description"),
)
for result in results[:count]
]
log.info(f"External search results: {results}")
return results
except Exception as e:
log.error(f"Error in External search: {e}")
return []
+32 -13
View File
@@ -17,34 +17,53 @@ def search_google_pse(
filter_list: Optional[list[str]] = None,
) -> list[SearchResult]:
"""Search using Google's Programmable Search Engine API and return the results as a list of SearchResult objects.
Handles pagination for counts greater than 10.
Args:
api_key (str): A Programmable Search Engine API key
search_engine_id (str): A Programmable Search Engine ID
query (str): The query to search for
count (int): The number of results to return (max 100, as PSE max results per query is 10 and max page is 10)
filter_list (Optional[list[str]], optional): A list of keywords to filter out from results. Defaults to None.
Returns:
list[SearchResult]: A list of SearchResult objects.
"""
url = "https://www.googleapis.com/customsearch/v1"
headers = {"Content-Type": "application/json"}
params = {
"cx": search_engine_id,
"q": query,
"key": api_key,
"num": count,
}
all_results = []
start_index = 1 # Google PSE start parameter is 1-based
response = requests.request("GET", url, headers=headers, params=params)
response.raise_for_status()
while count > 0:
num_results_this_page = min(count, 10) # Google PSE max results per page is 10
params = {
"cx": search_engine_id,
"q": query,
"key": api_key,
"num": num_results_this_page,
"start": start_index,
}
response = requests.request("GET", url, headers=headers, params=params)
response.raise_for_status()
json_response = response.json()
results = json_response.get("items", [])
if results: # check if results are returned. If not, no more pages to fetch.
all_results.extend(results)
count -= len(
results
) # Decrement count by the number of results fetched in this page.
start_index += 10 # Increment start index for the next page
else:
break # No more results from Google PSE, break the loop
json_response = response.json()
results = json_response.get("items", [])
if filter_list:
results = get_filtered_results(results, filter_list)
all_results = get_filtered_results(all_results, filter_list)
return [
SearchResult(
link=result["link"],
title=result.get("title"),
snippet=result.get("snippet"),
)
for result in results
for result in all_results
]
@@ -20,14 +20,23 @@ def search_jina(api_key: str, query: str, count: int) -> list[SearchResult]:
list[SearchResult]: A list of search results
"""
jina_search_endpoint = "https://s.jina.ai/"
headers = {"Accept": "application/json", "Authorization": f"Bearer {api_key}"}
url = str(URL(jina_search_endpoint + query))
response = requests.get(url, headers=headers)
headers = {
"Accept": "application/json",
"Content-Type": "application/json",
"Authorization": api_key,
"X-Retain-Images": "none",
}
payload = {"q": query, "count": count if count <= 10 else 10}
url = str(URL(jina_search_endpoint))
response = requests.post(url, headers=headers, json=payload)
response.raise_for_status()
data = response.json()
results = []
for result in data["data"][:count]:
for result in data["data"]:
results.append(
SearchResult(
link=result["url"],
+4
View File
@@ -1,3 +1,5 @@
import validators
from typing import Optional
from urllib.parse import urlparse
@@ -10,6 +12,8 @@ def get_filtered_results(results, filter_list):
filtered_results = []
for result in results:
url = result.get("url") or result.get("link", "")
if not validators.url(url):
continue
domain = urlparse(url).netloc
if any(domain.endswith(filtered_domain) for filtered_domain in filter_list):
filtered_results.append(result)
@@ -0,0 +1,105 @@
import logging
from typing import Optional, Literal
import requests
from open_webui.retrieval.web.main import SearchResult, get_filtered_results
from open_webui.env import SRC_LOG_LEVELS
MODELS = Literal[
"sonar",
"sonar-pro",
"sonar-reasoning",
"sonar-reasoning-pro",
"sonar-deep-research",
]
SEARCH_CONTEXT_USAGE_LEVELS = Literal["low", "medium", "high"]
log = logging.getLogger(__name__)
log.setLevel(SRC_LOG_LEVELS["RAG"])
def search_perplexity(
api_key: str,
query: str,
count: int,
filter_list: Optional[list[str]] = None,
model: MODELS = "sonar",
search_context_usage: SEARCH_CONTEXT_USAGE_LEVELS = "medium",
) -> list[SearchResult]:
"""Search using Perplexity API and return the results as a list of SearchResult objects.
Args:
api_key (str): A Perplexity API key
query (str): The query to search for
count (int): Maximum number of results to return
filter_list (Optional[list[str]]): List of domains to filter results
model (str): The Perplexity model to use (sonar, sonar-pro)
search_context_usage (str): Search context usage level (low, medium, high)
"""
# Handle PersistentConfig object
if hasattr(api_key, "__str__"):
api_key = str(api_key)
try:
url = "https://api.perplexity.ai/chat/completions"
# Create payload for the API call
payload = {
"model": model,
"messages": [
{
"role": "system",
"content": "You are a search assistant. Provide factual information with citations.",
},
{"role": "user", "content": query},
],
"temperature": 0.2, # Lower temperature for more factual responses
"stream": False,
"web_search_options": {
"search_context_usage": search_context_usage,
},
}
headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json",
}
# Make the API request
response = requests.request("POST", url, json=payload, headers=headers)
# Parse the JSON response
json_response = response.json()
# Extract citations from the response
citations = json_response.get("citations", [])
# Create search results from citations
results = []
for i, citation in enumerate(citations[:count]):
# Extract content from the response to use as snippet
content = ""
if "choices" in json_response and json_response["choices"]:
if i == 0:
content = json_response["choices"][0]["message"]["content"]
result = {"link": citation, "title": f"Source {i+1}", "snippet": content}
results.append(result)
if filter_list:
results = get_filtered_results(results, filter_list)
return [
SearchResult(
link=result["link"], title=result["title"], snippet=result["snippet"]
)
for result in results[:count]
]
except Exception as e:
log.error(f"Error searching with Perplexity API: {e}")
return []
@@ -42,7 +42,9 @@ def search_searchapi(
results = get_filtered_results(results, filter_list)
return [
SearchResult(
link=result["link"], title=result["title"], snippet=result["snippet"]
link=result["link"],
title=result.get("title"),
snippet=result.get("snippet"),
)
for result in results[:count]
]
@@ -0,0 +1,50 @@
import logging
from typing import Optional
from urllib.parse import urlencode
import requests
from open_webui.retrieval.web.main import SearchResult, get_filtered_results
from open_webui.env import SRC_LOG_LEVELS
log = logging.getLogger(__name__)
log.setLevel(SRC_LOG_LEVELS["RAG"])
def search_serpapi(
api_key: str,
engine: str,
query: str,
count: int,
filter_list: Optional[list[str]] = None,
) -> list[SearchResult]:
"""Search using serpapi.com's API and return the results as a list of SearchResult objects.
Args:
api_key (str): A serpapi.com API key
query (str): The query to search for
"""
url = "https://serpapi.com/search"
engine = engine or "google"
payload = {"engine": engine, "q": query, "api_key": api_key}
url = f"{url}?{urlencode(payload)}"
response = requests.request("GET", url)
json_response = response.json()
log.info(f"results from serpapi search: {json_response}")
results = sorted(
json_response.get("organic_results", []), key=lambda x: x.get("position", 0)
)
if filter_list:
results = get_filtered_results(results, filter_list)
return [
SearchResult(
link=result["link"],
title=result.get("title"),
snippet=result.get("snippet"),
)
for result in results[:count]
]
@@ -0,0 +1,60 @@
import logging
import json
from typing import Optional, List
from open_webui.retrieval.web.main import SearchResult, get_filtered_results
from open_webui.env import SRC_LOG_LEVELS
log = logging.getLogger(__name__)
log.setLevel(SRC_LOG_LEVELS["RAG"])
def search_sougou(
sougou_api_sid: str,
sougou_api_sk: str,
query: str,
count: int,
filter_list: Optional[List[str]] = None,
) -> List[SearchResult]:
from tencentcloud.common.common_client import CommonClient
from tencentcloud.common import credential
from tencentcloud.common.exception.tencent_cloud_sdk_exception import (
TencentCloudSDKException,
)
from tencentcloud.common.profile.client_profile import ClientProfile
from tencentcloud.common.profile.http_profile import HttpProfile
try:
cred = credential.Credential(sougou_api_sid, sougou_api_sk)
http_profile = HttpProfile()
http_profile.endpoint = "tms.tencentcloudapi.com"
client_profile = ClientProfile()
client_profile.http_profile = http_profile
params = json.dumps({"Query": query, "Cnt": 20})
common_client = CommonClient(
"tms", "2020-12-29", cred, "", profile=client_profile
)
results = [
json.loads(page)
for page in common_client.call_json("SearchPro", json.loads(params))[
"Response"
]["Pages"]
]
sorted_results = sorted(
results, key=lambda x: x.get("scour", 0.0), reverse=True
)
if filter_list:
sorted_results = get_filtered_results(sorted_results, filter_list)
return [
SearchResult(
link=result.get("url"),
title=result.get("title"),
snippet=result.get("passage"),
)
for result in sorted_results[:count]
]
except TencentCloudSDKException as err:
log.error(f"Error in Sougou search: {err}")
return []
+20 -7
View File
@@ -1,32 +1,45 @@
import logging
from typing import Optional
import requests
from open_webui.retrieval.web.main import SearchResult
from open_webui.retrieval.web.main import SearchResult, get_filtered_results
from open_webui.env import SRC_LOG_LEVELS
log = logging.getLogger(__name__)
log.setLevel(SRC_LOG_LEVELS["RAG"])
def search_tavily(api_key: str, query: str, count: int) -> list[SearchResult]:
def search_tavily(
api_key: str,
query: str,
count: int,
filter_list: Optional[list[str]] = None,
# **kwargs,
) -> list[SearchResult]:
"""Search using Tavily's Search API and return the results as a list of SearchResult objects.
Args:
api_key (str): A Tavily Search API key
query (str): The query to search for
count (int): The maximum number of results to return
Returns:
list[SearchResult]: A list of search results
"""
url = "https://api.tavily.com/search"
data = {"query": query, "api_key": api_key}
response = requests.post(url, json=data)
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {api_key}",
}
data = {"query": query, "max_results": count}
response = requests.post(url, headers=headers, json=data)
response.raise_for_status()
json_response = response.json()
raw_search_results = json_response.get("results", [])
results = json_response.get("results", [])
if filter_list:
results = get_filtered_results(results, filter_list)
return [
SearchResult(
@@ -34,5 +47,5 @@ def search_tavily(api_key: str, query: str, count: int) -> list[SearchResult]:
title=result.get("title", ""),
snippet=result.get("content"),
)
for result in raw_search_results[:count]
for result in results
]
+587 -34
View File
@@ -1,19 +1,45 @@
import socket
import urllib.parse
import validators
from typing import Union, Sequence, Iterator
from langchain_community.document_loaders import (
WebBaseLoader,
)
from langchain_core.documents import Document
from open_webui.constants import ERROR_MESSAGES
from open_webui.config import ENABLE_RAG_LOCAL_WEB_FETCH
from open_webui.env import SRC_LOG_LEVELS
import asyncio
import logging
import socket
import ssl
import urllib.parse
import urllib.request
from collections import defaultdict
from datetime import datetime, time, timedelta
from typing import (
Any,
AsyncIterator,
Dict,
Iterator,
List,
Optional,
Sequence,
Union,
Literal,
)
import aiohttp
import certifi
import validators
from langchain_community.document_loaders import PlaywrightURLLoader, WebBaseLoader
from langchain_community.document_loaders.firecrawl import FireCrawlLoader
from langchain_community.document_loaders.base import BaseLoader
from langchain_core.documents import Document
from open_webui.retrieval.loaders.tavily import TavilyLoader
from open_webui.retrieval.loaders.external_web import ExternalWebLoader
from open_webui.constants import ERROR_MESSAGES
from open_webui.config import (
ENABLE_RAG_LOCAL_WEB_FETCH,
PLAYWRIGHT_WS_URL,
PLAYWRIGHT_TIMEOUT,
WEB_LOADER_ENGINE,
FIRECRAWL_API_BASE_URL,
FIRECRAWL_API_KEY,
TAVILY_API_KEY,
TAVILY_EXTRACT_DEPTH,
EXTERNAL_WEB_LOADER_URL,
EXTERNAL_WEB_LOADER_API_KEY,
)
from open_webui.env import SRC_LOG_LEVELS, AIOHTTP_CLIENT_SESSION_SSL
log = logging.getLogger(__name__)
log.setLevel(SRC_LOG_LEVELS["RAG"])
@@ -43,6 +69,17 @@ def validate_url(url: Union[str, Sequence[str]]):
return False
def safe_validate_urls(url: Sequence[str]) -> Sequence[str]:
valid_urls = []
for u in url:
try:
if validate_url(u):
valid_urls.append(u)
except ValueError:
continue
return valid_urls
def resolve_hostname(hostname):
# Get address information
addr_info = socket.getaddrinfo(hostname, None)
@@ -54,9 +91,472 @@ def resolve_hostname(hostname):
return ipv4_addresses, ipv6_addresses
def extract_metadata(soup, url):
metadata = {"source": url}
if title := soup.find("title"):
metadata["title"] = title.get_text()
if description := soup.find("meta", attrs={"name": "description"}):
metadata["description"] = description.get("content", "No description found.")
if html := soup.find("html"):
metadata["language"] = html.get("lang", "No language found.")
return metadata
def verify_ssl_cert(url: str) -> bool:
"""Verify SSL certificate for the given URL."""
if not url.startswith("https://"):
return True
try:
hostname = url.split("://")[-1].split("/")[0]
context = ssl.create_default_context(cafile=certifi.where())
with context.wrap_socket(ssl.socket(), server_hostname=hostname) as s:
s.connect((hostname, 443))
return True
except ssl.SSLError:
return False
except Exception as e:
log.warning(f"SSL verification failed for {url}: {str(e)}")
return False
class RateLimitMixin:
async def _wait_for_rate_limit(self):
"""Wait to respect the rate limit if specified."""
if self.requests_per_second and self.last_request_time:
min_interval = timedelta(seconds=1.0 / self.requests_per_second)
time_since_last = datetime.now() - self.last_request_time
if time_since_last < min_interval:
await asyncio.sleep((min_interval - time_since_last).total_seconds())
self.last_request_time = datetime.now()
def _sync_wait_for_rate_limit(self):
"""Synchronous version of rate limit wait."""
if self.requests_per_second and self.last_request_time:
min_interval = timedelta(seconds=1.0 / self.requests_per_second)
time_since_last = datetime.now() - self.last_request_time
if time_since_last < min_interval:
time.sleep((min_interval - time_since_last).total_seconds())
self.last_request_time = datetime.now()
class URLProcessingMixin:
def _verify_ssl_cert(self, url: str) -> bool:
"""Verify SSL certificate for a URL."""
return verify_ssl_cert(url)
async def _safe_process_url(self, url: str) -> bool:
"""Perform safety checks before processing a URL."""
if self.verify_ssl and not self._verify_ssl_cert(url):
raise ValueError(f"SSL certificate verification failed for {url}")
await self._wait_for_rate_limit()
return True
def _safe_process_url_sync(self, url: str) -> bool:
"""Synchronous version of safety checks."""
if self.verify_ssl and not self._verify_ssl_cert(url):
raise ValueError(f"SSL certificate verification failed for {url}")
self._sync_wait_for_rate_limit()
return True
class SafeFireCrawlLoader(BaseLoader, RateLimitMixin, URLProcessingMixin):
def __init__(
self,
web_paths,
verify_ssl: bool = True,
trust_env: bool = False,
requests_per_second: Optional[float] = None,
continue_on_failure: bool = True,
api_key: Optional[str] = None,
api_url: Optional[str] = None,
mode: Literal["crawl", "scrape", "map"] = "scrape",
proxy: Optional[Dict[str, str]] = None,
params: Optional[Dict] = None,
):
"""Concurrent document loader for FireCrawl operations.
Executes multiple FireCrawlLoader instances concurrently using thread pooling
to improve bulk processing efficiency.
Args:
web_paths: List of URLs/paths to process.
verify_ssl: If True, verify SSL certificates.
trust_env: If True, use proxy settings from environment variables.
requests_per_second: Number of requests per second to limit to.
continue_on_failure (bool): If True, continue loading other URLs on failure.
api_key: API key for FireCrawl service. Defaults to None
(uses FIRE_CRAWL_API_KEY environment variable if not provided).
api_url: Base URL for FireCrawl API. Defaults to official API endpoint.
mode: Operation mode selection:
- 'crawl': Website crawling mode (default)
- 'scrape': Direct page scraping
- 'map': Site map generation
proxy: Proxy override settings for the FireCrawl API.
params: The parameters to pass to the Firecrawl API.
Examples include crawlerOptions.
For more details, visit: https://github.com/mendableai/firecrawl-py
"""
proxy_server = proxy.get("server") if proxy else None
if trust_env and not proxy_server:
env_proxies = urllib.request.getproxies()
env_proxy_server = env_proxies.get("https") or env_proxies.get("http")
if env_proxy_server:
if proxy:
proxy["server"] = env_proxy_server
else:
proxy = {"server": env_proxy_server}
self.web_paths = web_paths
self.verify_ssl = verify_ssl
self.requests_per_second = requests_per_second
self.last_request_time = None
self.trust_env = trust_env
self.continue_on_failure = continue_on_failure
self.api_key = api_key
self.api_url = api_url
self.mode = mode
self.params = params
def lazy_load(self) -> Iterator[Document]:
"""Load documents concurrently using FireCrawl."""
for url in self.web_paths:
try:
self._safe_process_url_sync(url)
loader = FireCrawlLoader(
url=url,
api_key=self.api_key,
api_url=self.api_url,
mode=self.mode,
params=self.params,
)
for document in loader.lazy_load():
if not document.metadata.get("source"):
document.metadata["source"] = document.metadata.get("sourceURL")
yield document
except Exception as e:
if self.continue_on_failure:
log.exception(f"Error loading {url}: {e}")
continue
raise e
async def alazy_load(self):
"""Async version of lazy_load."""
for url in self.web_paths:
try:
await self._safe_process_url(url)
loader = FireCrawlLoader(
url=url,
api_key=self.api_key,
api_url=self.api_url,
mode=self.mode,
params=self.params,
)
async for document in loader.alazy_load():
if not document.metadata.get("source"):
document.metadata["source"] = document.metadata.get("sourceURL")
yield document
except Exception as e:
if self.continue_on_failure:
log.exception(f"Error loading {url}: {e}")
continue
raise e
class SafeTavilyLoader(BaseLoader, RateLimitMixin, URLProcessingMixin):
def __init__(
self,
web_paths: Union[str, List[str]],
api_key: str,
extract_depth: Literal["basic", "advanced"] = "basic",
continue_on_failure: bool = True,
requests_per_second: Optional[float] = None,
verify_ssl: bool = True,
trust_env: bool = False,
proxy: Optional[Dict[str, str]] = None,
):
"""Initialize SafeTavilyLoader with rate limiting and SSL verification support.
Args:
web_paths: List of URLs/paths to process.
api_key: The Tavily API key.
extract_depth: Depth of extraction ("basic" or "advanced").
continue_on_failure: Whether to continue if extraction of a URL fails.
requests_per_second: Number of requests per second to limit to.
verify_ssl: If True, verify SSL certificates.
trust_env: If True, use proxy settings from environment variables.
proxy: Optional proxy configuration.
"""
# Initialize proxy configuration if using environment variables
proxy_server = proxy.get("server") if proxy else None
if trust_env and not proxy_server:
env_proxies = urllib.request.getproxies()
env_proxy_server = env_proxies.get("https") or env_proxies.get("http")
if env_proxy_server:
if proxy:
proxy["server"] = env_proxy_server
else:
proxy = {"server": env_proxy_server}
# Store parameters for creating TavilyLoader instances
self.web_paths = web_paths if isinstance(web_paths, list) else [web_paths]
self.api_key = api_key
self.extract_depth = extract_depth
self.continue_on_failure = continue_on_failure
self.verify_ssl = verify_ssl
self.trust_env = trust_env
self.proxy = proxy
# Add rate limiting
self.requests_per_second = requests_per_second
self.last_request_time = None
def lazy_load(self) -> Iterator[Document]:
"""Load documents with rate limiting support, delegating to TavilyLoader."""
valid_urls = []
for url in self.web_paths:
try:
self._safe_process_url_sync(url)
valid_urls.append(url)
except Exception as e:
log.warning(f"SSL verification failed for {url}: {str(e)}")
if not self.continue_on_failure:
raise e
if not valid_urls:
if self.continue_on_failure:
log.warning("No valid URLs to process after SSL verification")
return
raise ValueError("No valid URLs to process after SSL verification")
try:
loader = TavilyLoader(
urls=valid_urls,
api_key=self.api_key,
extract_depth=self.extract_depth,
continue_on_failure=self.continue_on_failure,
)
yield from loader.lazy_load()
except Exception as e:
if self.continue_on_failure:
log.exception(f"Error extracting content from URLs: {e}")
else:
raise e
async def alazy_load(self) -> AsyncIterator[Document]:
"""Async version with rate limiting and SSL verification."""
valid_urls = []
for url in self.web_paths:
try:
await self._safe_process_url(url)
valid_urls.append(url)
except Exception as e:
log.warning(f"SSL verification failed for {url}: {str(e)}")
if not self.continue_on_failure:
raise e
if not valid_urls:
if self.continue_on_failure:
log.warning("No valid URLs to process after SSL verification")
return
raise ValueError("No valid URLs to process after SSL verification")
try:
loader = TavilyLoader(
urls=valid_urls,
api_key=self.api_key,
extract_depth=self.extract_depth,
continue_on_failure=self.continue_on_failure,
)
async for document in loader.alazy_load():
yield document
except Exception as e:
if self.continue_on_failure:
log.exception(f"Error loading URLs: {e}")
else:
raise e
class SafePlaywrightURLLoader(PlaywrightURLLoader, RateLimitMixin, URLProcessingMixin):
"""Load HTML pages safely with Playwright, supporting SSL verification, rate limiting, and remote browser connection.
Attributes:
web_paths (List[str]): List of URLs to load.
verify_ssl (bool): If True, verify SSL certificates.
trust_env (bool): If True, use proxy settings from environment variables.
requests_per_second (Optional[float]): Number of requests per second to limit to.
continue_on_failure (bool): If True, continue loading other URLs on failure.
headless (bool): If True, the browser will run in headless mode.
proxy (dict): Proxy override settings for the Playwright session.
playwright_ws_url (Optional[str]): WebSocket endpoint URI for remote browser connection.
playwright_timeout (Optional[int]): Maximum operation time in milliseconds.
"""
def __init__(
self,
web_paths: List[str],
verify_ssl: bool = True,
trust_env: bool = False,
requests_per_second: Optional[float] = None,
continue_on_failure: bool = True,
headless: bool = True,
remove_selectors: Optional[List[str]] = None,
proxy: Optional[Dict[str, str]] = None,
playwright_ws_url: Optional[str] = None,
playwright_timeout: Optional[int] = 10000,
):
"""Initialize with additional safety parameters and remote browser support."""
proxy_server = proxy.get("server") if proxy else None
if trust_env and not proxy_server:
env_proxies = urllib.request.getproxies()
env_proxy_server = env_proxies.get("https") or env_proxies.get("http")
if env_proxy_server:
if proxy:
proxy["server"] = env_proxy_server
else:
proxy = {"server": env_proxy_server}
# We'll set headless to False if using playwright_ws_url since it's handled by the remote browser
super().__init__(
urls=web_paths,
continue_on_failure=continue_on_failure,
headless=headless if playwright_ws_url is None else False,
remove_selectors=remove_selectors,
proxy=proxy,
)
self.verify_ssl = verify_ssl
self.requests_per_second = requests_per_second
self.last_request_time = None
self.playwright_ws_url = playwright_ws_url
self.trust_env = trust_env
self.playwright_timeout = playwright_timeout
def lazy_load(self) -> Iterator[Document]:
"""Safely load URLs synchronously with support for remote browser."""
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
# Use remote browser if ws_endpoint is provided, otherwise use local browser
if self.playwright_ws_url:
browser = p.chromium.connect(self.playwright_ws_url)
else:
browser = p.chromium.launch(headless=self.headless, proxy=self.proxy)
for url in self.urls:
try:
self._safe_process_url_sync(url)
page = browser.new_page()
response = page.goto(url, timeout=self.playwright_timeout)
if response is None:
raise ValueError(f"page.goto() returned None for url {url}")
text = self.evaluator.evaluate(page, browser, response)
metadata = {"source": url}
yield Document(page_content=text, metadata=metadata)
except Exception as e:
if self.continue_on_failure:
log.exception(f"Error loading {url}: {e}")
continue
raise e
browser.close()
async def alazy_load(self) -> AsyncIterator[Document]:
"""Safely load URLs asynchronously with support for remote browser."""
from playwright.async_api import async_playwright
async with async_playwright() as p:
# Use remote browser if ws_endpoint is provided, otherwise use local browser
if self.playwright_ws_url:
browser = await p.chromium.connect(self.playwright_ws_url)
else:
browser = await p.chromium.launch(
headless=self.headless, proxy=self.proxy
)
for url in self.urls:
try:
await self._safe_process_url(url)
page = await browser.new_page()
response = await page.goto(url, timeout=self.playwright_timeout)
if response is None:
raise ValueError(f"page.goto() returned None for url {url}")
text = await self.evaluator.evaluate_async(page, browser, response)
metadata = {"source": url}
yield Document(page_content=text, metadata=metadata)
except Exception as e:
if self.continue_on_failure:
log.exception(f"Error loading {url}: {e}")
continue
raise e
await browser.close()
class SafeWebBaseLoader(WebBaseLoader):
"""WebBaseLoader with enhanced error handling for URLs."""
def __init__(self, trust_env: bool = False, *args, **kwargs):
"""Initialize SafeWebBaseLoader
Args:
trust_env (bool, optional): set to True if using proxy to make web requests, for example
using http(s)_proxy environment variables. Defaults to False.
"""
super().__init__(*args, **kwargs)
self.trust_env = trust_env
async def _fetch(
self, url: str, retries: int = 3, cooldown: int = 2, backoff: float = 1.5
) -> str:
async with aiohttp.ClientSession(trust_env=self.trust_env) as session:
for i in range(retries):
try:
kwargs: Dict = dict(
headers=self.session.headers,
cookies=self.session.cookies.get_dict(),
)
if not self.session.verify:
kwargs["ssl"] = False
async with session.get(
url,
**(self.requests_kwargs | kwargs),
) as response:
if self.raise_for_status:
response.raise_for_status()
return await response.text()
except aiohttp.ClientConnectionError as e:
if i == retries - 1:
raise
else:
log.warning(
f"Error fetching {url} with attempt "
f"{i + 1}/{retries}: {e}. Retrying..."
)
await asyncio.sleep(cooldown * backoff**i)
raise ValueError("retry count exceeded")
def _unpack_fetch_results(
self, results: Any, urls: List[str], parser: Union[str, None] = None
) -> List[Any]:
"""Unpack fetch results into BeautifulSoup objects."""
from bs4 import BeautifulSoup
final_results = []
for i, result in enumerate(results):
url = urls[i]
if parser is None:
if url.endswith(".xml"):
parser = "xml"
else:
parser = self.default_parser
self._check_parser(parser)
final_results.append(BeautifulSoup(result, parser, **self.bs_kwargs))
return final_results
async def ascrape_all(
self, urls: List[str], parser: Union[str, None] = None
) -> List[Any]:
"""Async fetch all urls, then return soups for all results."""
results = await self.fetch_all(urls)
return self._unpack_fetch_results(results, urls, parser=parser)
def lazy_load(self) -> Iterator[Document]:
"""Lazy load text from the url(s) in web_path with error handling."""
for path in self.web_paths:
@@ -65,33 +565,86 @@ class SafeWebBaseLoader(WebBaseLoader):
text = soup.get_text(**self.bs_get_text_kwargs)
# Build metadata
metadata = {"source": path}
if title := soup.find("title"):
metadata["title"] = title.get_text()
if description := soup.find("meta", attrs={"name": "description"}):
metadata["description"] = description.get(
"content", "No description found."
)
if html := soup.find("html"):
metadata["language"] = html.get("lang", "No language found.")
metadata = extract_metadata(soup, path)
yield Document(page_content=text, metadata=metadata)
except Exception as e:
# Log the error and continue with the next URL
log.error(f"Error loading {path}: {e}")
log.exception(f"Error loading {path}: {e}")
async def alazy_load(self) -> AsyncIterator[Document]:
"""Async lazy load text from the url(s) in web_path."""
results = await self.ascrape_all(self.web_paths)
for path, soup in zip(self.web_paths, results):
text = soup.get_text(**self.bs_get_text_kwargs)
metadata = {"source": path}
if title := soup.find("title"):
metadata["title"] = title.get_text()
if description := soup.find("meta", attrs={"name": "description"}):
metadata["description"] = description.get(
"content", "No description found."
)
if html := soup.find("html"):
metadata["language"] = html.get("lang", "No language found.")
yield Document(page_content=text, metadata=metadata)
async def aload(self) -> list[Document]:
"""Load data into Document objects."""
return [document async for document in self.alazy_load()]
def get_web_loader(
urls: Union[str, Sequence[str]],
verify_ssl: bool = True,
requests_per_second: int = 2,
trust_env: bool = False,
):
# Check if the URL is valid
if not validate_url(urls):
raise ValueError(ERROR_MESSAGES.INVALID_URL)
return SafeWebBaseLoader(
urls,
verify_ssl=verify_ssl,
requests_per_second=requests_per_second,
continue_on_failure=True,
)
# Check if the URLs are valid
safe_urls = safe_validate_urls([urls] if isinstance(urls, str) else urls)
web_loader_args = {
"web_paths": safe_urls,
"verify_ssl": verify_ssl,
"requests_per_second": requests_per_second,
"continue_on_failure": True,
"trust_env": trust_env,
}
if WEB_LOADER_ENGINE.value == "" or WEB_LOADER_ENGINE.value == "safe_web":
WebLoaderClass = SafeWebBaseLoader
if WEB_LOADER_ENGINE.value == "playwright":
WebLoaderClass = SafePlaywrightURLLoader
web_loader_args["playwright_timeout"] = PLAYWRIGHT_TIMEOUT.value * 1000
if PLAYWRIGHT_WS_URL.value:
web_loader_args["playwright_ws_url"] = PLAYWRIGHT_WS_URL.value
if WEB_LOADER_ENGINE.value == "firecrawl":
WebLoaderClass = SafeFireCrawlLoader
web_loader_args["api_key"] = FIRECRAWL_API_KEY.value
web_loader_args["api_url"] = FIRECRAWL_API_BASE_URL.value
if WEB_LOADER_ENGINE.value == "tavily":
WebLoaderClass = SafeTavilyLoader
web_loader_args["api_key"] = TAVILY_API_KEY.value
web_loader_args["extract_depth"] = TAVILY_EXTRACT_DEPTH.value
if WEB_LOADER_ENGINE.value == "external":
WebLoaderClass = ExternalWebLoader
web_loader_args["external_url"] = EXTERNAL_WEB_LOADER_URL.value
web_loader_args["external_api_key"] = EXTERNAL_WEB_LOADER_API_KEY.value
if WebLoaderClass:
web_loader = WebLoaderClass(**web_loader_args)
log.debug(
"Using WEB_LOADER_ENGINE %s for %s URLs",
web_loader.__class__.__name__,
len(safe_urls),
)
return web_loader
else:
raise ValueError(
f"Invalid WEB_LOADER_ENGINE: {WEB_LOADER_ENGINE.value}. "
"Please set it to 'safe_web', 'playwright', 'firecrawl', or 'tavily'."
)
+87
View File
@@ -0,0 +1,87 @@
import logging
from typing import Optional
import requests
from requests.auth import HTTPDigestAuth
from open_webui.retrieval.web.main import SearchResult, get_filtered_results
from open_webui.env import SRC_LOG_LEVELS
log = logging.getLogger(__name__)
log.setLevel(SRC_LOG_LEVELS["RAG"])
def search_yacy(
query_url: str,
username: Optional[str],
password: Optional[str],
query: str,
count: int,
filter_list: Optional[list[str]] = None,
) -> list[SearchResult]:
"""
Search a Yacy instance for a given query and return the results as a list of SearchResult objects.
The function accepts username and password for authenticating to Yacy.
Args:
query_url (str): The base URL of the Yacy server.
username (str): Optional YaCy username.
password (str): Optional YaCy password.
query (str): The search term or question to find in the Yacy database.
count (int): The maximum number of results to retrieve from the search.
Returns:
list[SearchResult]: A list of SearchResults sorted by relevance score in descending order.
Raise:
requests.exceptions.RequestException: If a request error occurs during the search process.
"""
# Use authentication if either username or password is set
yacy_auth = None
if username or password:
yacy_auth = HTTPDigestAuth(username, password)
params = {
"query": query,
"contentdom": "text",
"resource": "global",
"maximumRecords": count,
"nav": "none",
}
# Check if provided a json API URL
if not query_url.endswith("yacysearch.json"):
# Strip all query parameters from the URL
query_url = query_url.rstrip("/") + "/yacysearch.json"
log.debug(f"searching {query_url}")
response = requests.get(
query_url,
auth=yacy_auth,
headers={
"User-Agent": "Open WebUI (https://github.com/open-webui/open-webui) RAG Bot",
"Accept": "text/html",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "en-US,en;q=0.5",
"Connection": "keep-alive",
},
params=params,
)
response.raise_for_status() # Raise an exception for HTTP errors.
json_response = response.json()
results = json_response.get("channels", [{}])[0].get("items", [])
sorted_results = sorted(results, key=lambda x: x.get("ranking", 0), reverse=True)
if filter_list:
sorted_results = get_filtered_results(sorted_results, filter_list)
return [
SearchResult(
link=result["link"],
title=result.get("title"),
snippet=result.get("description"),
)
for result in sorted_results[:count]
]
+513 -79
View File
@@ -7,15 +7,21 @@ from functools import lru_cache
from pathlib import Path
from pydub import AudioSegment
from pydub.silence import split_on_silence
from concurrent.futures import ThreadPoolExecutor
from typing import Optional
from fnmatch import fnmatch
import aiohttp
import aiofiles
import requests
import mimetypes
from urllib.parse import quote
from fastapi import (
Depends,
FastAPI,
File,
Form,
HTTPException,
Request,
UploadFile,
@@ -32,10 +38,13 @@ from open_webui.config import (
WHISPER_MODEL_AUTO_UPDATE,
WHISPER_MODEL_DIR,
CACHE_DIR,
WHISPER_LANGUAGE,
)
from open_webui.constants import ERROR_MESSAGES
from open_webui.env import (
AIOHTTP_CLIENT_SESSION_SSL,
AIOHTTP_CLIENT_TIMEOUT,
ENV,
SRC_LOG_LEVELS,
DEVICE_TYPE,
@@ -46,13 +55,15 @@ from open_webui.env import (
router = APIRouter()
# Constants
MAX_FILE_SIZE_MB = 25
MAX_FILE_SIZE_MB = 20
MAX_FILE_SIZE = MAX_FILE_SIZE_MB * 1024 * 1024 # Convert MB to bytes
AZURE_MAX_FILE_SIZE_MB = 200
AZURE_MAX_FILE_SIZE = AZURE_MAX_FILE_SIZE_MB * 1024 * 1024 # Convert MB to bytes
log = logging.getLogger(__name__)
log.setLevel(SRC_LOG_LEVELS["AUDIO"])
SPEECH_CACHE_DIR = Path(CACHE_DIR).joinpath("./audio/speech/")
SPEECH_CACHE_DIR = CACHE_DIR / "audio" / "speech"
SPEECH_CACHE_DIR.mkdir(parents=True, exist_ok=True)
@@ -66,27 +77,47 @@ from pydub import AudioSegment
from pydub.utils import mediainfo
def is_mp4_audio(file_path):
"""Check if the given file is an MP4 audio file."""
def is_audio_conversion_required(file_path):
"""
Check if the given audio file needs conversion to mp3.
"""
SUPPORTED_FORMATS = {"flac", "m4a", "mp3", "mp4", "mpeg", "wav", "webm"}
if not os.path.isfile(file_path):
print(f"File not found: {file_path}")
log.error(f"File not found: {file_path}")
return False
info = mediainfo(file_path)
if (
info.get("codec_name") == "aac"
and info.get("codec_type") == "audio"
and info.get("codec_tag_string") == "mp4a"
):
try:
info = mediainfo(file_path)
codec_name = info.get("codec_name", "").lower()
codec_type = info.get("codec_type", "").lower()
codec_tag_string = info.get("codec_tag_string", "").lower()
if codec_name == "aac" and codec_type == "audio" and codec_tag_string == "mp4a":
# File is AAC/mp4a audio, recommend mp3 conversion
return True
# If the codec name is in the supported formats
if codec_name in SUPPORTED_FORMATS:
return False
return True
return False
except Exception as e:
log.error(f"Error getting audio format: {e}")
return False
def convert_mp4_to_wav(file_path, output_path):
"""Convert MP4 audio file to WAV format."""
audio = AudioSegment.from_file(file_path, format="mp4")
audio.export(output_path, format="wav")
print(f"Converted {file_path} to {output_path}")
def convert_audio_to_mp3(file_path):
"""Convert audio file to mp3 format."""
try:
output_path = os.path.splitext(file_path)[0] + ".mp3"
audio = AudioSegment.from_file(file_path)
audio.export(output_path, format="mp3")
log.info(f"Converted {file_path} to {output_path}")
return output_path
except Exception as e:
log.error(f"Error converting audio file: {e}")
return None
def set_faster_whisper_model(model: str, auto_update: bool = False):
@@ -129,6 +160,7 @@ class TTSConfigForm(BaseModel):
VOICE: str
SPLIT_ON: str
AZURE_SPEECH_REGION: str
AZURE_SPEECH_BASE_URL: str
AZURE_SPEECH_OUTPUT_FORMAT: str
@@ -137,7 +169,14 @@ class STTConfigForm(BaseModel):
OPENAI_API_KEY: str
ENGINE: str
MODEL: str
SUPPORTED_CONTENT_TYPES: list[str] = []
WHISPER_MODEL: str
DEEPGRAM_API_KEY: str
AZURE_API_KEY: str
AZURE_REGION: str
AZURE_LOCALES: str
AZURE_BASE_URL: str
AZURE_MAX_SPEAKERS: str
class AudioConfigUpdateForm(BaseModel):
@@ -157,6 +196,7 @@ async def get_audio_config(request: Request, user=Depends(get_admin_user)):
"VOICE": request.app.state.config.TTS_VOICE,
"SPLIT_ON": request.app.state.config.TTS_SPLIT_ON,
"AZURE_SPEECH_REGION": request.app.state.config.TTS_AZURE_SPEECH_REGION,
"AZURE_SPEECH_BASE_URL": request.app.state.config.TTS_AZURE_SPEECH_BASE_URL,
"AZURE_SPEECH_OUTPUT_FORMAT": request.app.state.config.TTS_AZURE_SPEECH_OUTPUT_FORMAT,
},
"stt": {
@@ -164,7 +204,14 @@ async def get_audio_config(request: Request, user=Depends(get_admin_user)):
"OPENAI_API_KEY": request.app.state.config.STT_OPENAI_API_KEY,
"ENGINE": request.app.state.config.STT_ENGINE,
"MODEL": request.app.state.config.STT_MODEL,
"SUPPORTED_CONTENT_TYPES": request.app.state.config.STT_SUPPORTED_CONTENT_TYPES,
"WHISPER_MODEL": request.app.state.config.WHISPER_MODEL,
"DEEPGRAM_API_KEY": request.app.state.config.DEEPGRAM_API_KEY,
"AZURE_API_KEY": request.app.state.config.AUDIO_STT_AZURE_API_KEY,
"AZURE_REGION": request.app.state.config.AUDIO_STT_AZURE_REGION,
"AZURE_LOCALES": request.app.state.config.AUDIO_STT_AZURE_LOCALES,
"AZURE_BASE_URL": request.app.state.config.AUDIO_STT_AZURE_BASE_URL,
"AZURE_MAX_SPEAKERS": request.app.state.config.AUDIO_STT_AZURE_MAX_SPEAKERS,
},
}
@@ -181,6 +228,9 @@ async def update_audio_config(
request.app.state.config.TTS_VOICE = form_data.tts.VOICE
request.app.state.config.TTS_SPLIT_ON = form_data.tts.SPLIT_ON
request.app.state.config.TTS_AZURE_SPEECH_REGION = form_data.tts.AZURE_SPEECH_REGION
request.app.state.config.TTS_AZURE_SPEECH_BASE_URL = (
form_data.tts.AZURE_SPEECH_BASE_URL
)
request.app.state.config.TTS_AZURE_SPEECH_OUTPUT_FORMAT = (
form_data.tts.AZURE_SPEECH_OUTPUT_FORMAT
)
@@ -189,12 +239,26 @@ async def update_audio_config(
request.app.state.config.STT_OPENAI_API_KEY = form_data.stt.OPENAI_API_KEY
request.app.state.config.STT_ENGINE = form_data.stt.ENGINE
request.app.state.config.STT_MODEL = form_data.stt.MODEL
request.app.state.config.STT_SUPPORTED_CONTENT_TYPES = (
form_data.stt.SUPPORTED_CONTENT_TYPES
)
request.app.state.config.WHISPER_MODEL = form_data.stt.WHISPER_MODEL
request.app.state.config.DEEPGRAM_API_KEY = form_data.stt.DEEPGRAM_API_KEY
request.app.state.config.AUDIO_STT_AZURE_API_KEY = form_data.stt.AZURE_API_KEY
request.app.state.config.AUDIO_STT_AZURE_REGION = form_data.stt.AZURE_REGION
request.app.state.config.AUDIO_STT_AZURE_LOCALES = form_data.stt.AZURE_LOCALES
request.app.state.config.AUDIO_STT_AZURE_BASE_URL = form_data.stt.AZURE_BASE_URL
request.app.state.config.AUDIO_STT_AZURE_MAX_SPEAKERS = (
form_data.stt.AZURE_MAX_SPEAKERS
)
if request.app.state.config.STT_ENGINE == "":
request.app.state.faster_whisper_model = set_faster_whisper_model(
form_data.stt.WHISPER_MODEL, WHISPER_MODEL_AUTO_UPDATE
)
else:
request.app.state.faster_whisper_model = None
return {
"tts": {
@@ -206,6 +270,7 @@ async def update_audio_config(
"VOICE": request.app.state.config.TTS_VOICE,
"SPLIT_ON": request.app.state.config.TTS_SPLIT_ON,
"AZURE_SPEECH_REGION": request.app.state.config.TTS_AZURE_SPEECH_REGION,
"AZURE_SPEECH_BASE_URL": request.app.state.config.TTS_AZURE_SPEECH_BASE_URL,
"AZURE_SPEECH_OUTPUT_FORMAT": request.app.state.config.TTS_AZURE_SPEECH_OUTPUT_FORMAT,
},
"stt": {
@@ -213,7 +278,14 @@ async def update_audio_config(
"OPENAI_API_KEY": request.app.state.config.STT_OPENAI_API_KEY,
"ENGINE": request.app.state.config.STT_ENGINE,
"MODEL": request.app.state.config.STT_MODEL,
"SUPPORTED_CONTENT_TYPES": request.app.state.config.STT_SUPPORTED_CONTENT_TYPES,
"WHISPER_MODEL": request.app.state.config.WHISPER_MODEL,
"DEEPGRAM_API_KEY": request.app.state.config.DEEPGRAM_API_KEY,
"AZURE_API_KEY": request.app.state.config.AUDIO_STT_AZURE_API_KEY,
"AZURE_REGION": request.app.state.config.AUDIO_STT_AZURE_REGION,
"AZURE_LOCALES": request.app.state.config.AUDIO_STT_AZURE_LOCALES,
"AZURE_BASE_URL": request.app.state.config.AUDIO_STT_AZURE_BASE_URL,
"AZURE_MAX_SPEAKERS": request.app.state.config.AUDIO_STT_AZURE_MAX_SPEAKERS,
},
}
@@ -256,13 +328,16 @@ async def speech(request: Request, user=Depends(get_verified_user)):
log.exception(e)
raise HTTPException(status_code=400, detail="Invalid JSON payload")
r = None
if request.app.state.config.TTS_ENGINE == "openai":
payload["model"] = request.app.state.config.TTS_MODEL
try:
# print(payload)
async with aiohttp.ClientSession() as session:
async with session.post(
timeout = aiohttp.ClientTimeout(total=AIOHTTP_CLIENT_TIMEOUT)
async with aiohttp.ClientSession(
timeout=timeout, trust_env=True
) as session:
r = await session.post(
url=f"{request.app.state.config.TTS_OPENAI_API_BASE_URL}/audio/speech",
json=payload,
headers={
@@ -270,7 +345,7 @@ async def speech(request: Request, user=Depends(get_verified_user)):
"Authorization": f"Bearer {request.app.state.config.TTS_OPENAI_API_KEY}",
**(
{
"X-OpenWebUI-User-Name": user.name,
"X-OpenWebUI-User-Name": quote(user.name, safe=" "),
"X-OpenWebUI-User-Id": user.id,
"X-OpenWebUI-User-Email": user.email,
"X-OpenWebUI-User-Role": user.role,
@@ -279,14 +354,16 @@ async def speech(request: Request, user=Depends(get_verified_user)):
else {}
),
},
) as r:
r.raise_for_status()
ssl=AIOHTTP_CLIENT_SESSION_SSL,
)
async with aiofiles.open(file_path, "wb") as f:
await f.write(await r.read())
r.raise_for_status()
async with aiofiles.open(file_body_path, "w") as f:
await f.write(json.dumps(payload))
async with aiofiles.open(file_path, "wb") as f:
await f.write(await r.read())
async with aiofiles.open(file_body_path, "w") as f:
await f.write(json.dumps(payload))
return FileResponse(file_path)
@@ -294,18 +371,22 @@ async def speech(request: Request, user=Depends(get_verified_user)):
log.exception(e)
detail = None
try:
if r.status != 200:
res = await r.json()
status_code = 500
detail = f"Open WebUI: Server Connection Error"
if r is not None:
status_code = r.status
try:
res = await r.json()
if "error" in res:
detail = f"External: {res['error'].get('message', '')}"
except Exception:
detail = f"External: {e}"
detail = f"External: {res['error']}"
except Exception:
detail = f"External: {e}"
raise HTTPException(
status_code=getattr(r, "status", 500),
detail=detail if detail else "Open WebUI: Server Connection Error",
status_code=status_code,
detail=detail,
)
elif request.app.state.config.TTS_ENGINE == "elevenlabs":
@@ -318,7 +399,10 @@ async def speech(request: Request, user=Depends(get_verified_user)):
)
try:
async with aiohttp.ClientSession() as session:
timeout = aiohttp.ClientTimeout(total=AIOHTTP_CLIENT_TIMEOUT)
async with aiohttp.ClientSession(
timeout=timeout, trust_env=True
) as session:
async with session.post(
f"https://api.elevenlabs.io/v1/text-to-speech/{voice_id}",
json={
@@ -331,6 +415,7 @@ async def speech(request: Request, user=Depends(get_verified_user)):
"Content-Type": "application/json",
"xi-api-key": request.app.state.config.TTS_API_KEY,
},
ssl=AIOHTTP_CLIENT_SESSION_SSL,
) as r:
r.raise_for_status()
@@ -355,7 +440,7 @@ async def speech(request: Request, user=Depends(get_verified_user)):
detail = f"External: {e}"
raise HTTPException(
status_code=getattr(r, "status", 500),
status_code=getattr(r, "status", 500) if r else 500,
detail=detail if detail else "Open WebUI: Server Connection Error",
)
@@ -366,7 +451,8 @@ async def speech(request: Request, user=Depends(get_verified_user)):
log.exception(e)
raise HTTPException(status_code=400, detail="Invalid JSON payload")
region = request.app.state.config.TTS_AZURE_SPEECH_REGION
region = request.app.state.config.TTS_AZURE_SPEECH_REGION or "eastus"
base_url = request.app.state.config.TTS_AZURE_SPEECH_BASE_URL
language = request.app.state.config.TTS_VOICE
locale = "-".join(request.app.state.config.TTS_VOICE.split("-")[:1])
output_format = request.app.state.config.TTS_AZURE_SPEECH_OUTPUT_FORMAT
@@ -375,15 +461,20 @@ async def speech(request: Request, user=Depends(get_verified_user)):
data = f"""<speak version="1.0" xmlns="http://www.w3.org/2001/10/synthesis" xml:lang="{locale}">
<voice name="{language}">{payload["input"]}</voice>
</speak>"""
async with aiohttp.ClientSession() as session:
timeout = aiohttp.ClientTimeout(total=AIOHTTP_CLIENT_TIMEOUT)
async with aiohttp.ClientSession(
timeout=timeout, trust_env=True
) as session:
async with session.post(
f"https://{region}.tts.speech.microsoft.com/cognitiveservices/v1",
(base_url or f"https://{region}.tts.speech.microsoft.com")
+ "/cognitiveservices/v1",
headers={
"Ocp-Apim-Subscription-Key": request.app.state.config.TTS_API_KEY,
"Content-Type": "application/ssml+xml",
"X-Microsoft-OutputFormat": output_format,
},
data=data,
ssl=AIOHTTP_CLIENT_SESSION_SSL,
) as r:
r.raise_for_status()
@@ -408,7 +499,7 @@ async def speech(request: Request, user=Depends(get_verified_user)):
detail = f"External: {e}"
raise HTTPException(
status_code=getattr(r, "status", 500),
status_code=getattr(r, "status", 500) if r else 500,
detail=detail if detail else "Open WebUI: Server Connection Error",
)
@@ -452,12 +543,13 @@ async def speech(request: Request, user=Depends(get_verified_user)):
return FileResponse(file_path)
def transcribe(request: Request, file_path):
print("transcribe", file_path)
def transcription_handler(request, file_path, metadata):
filename = os.path.basename(file_path)
file_dir = os.path.dirname(file_path)
id = filename.split(".")[0]
metadata = metadata or {}
if request.app.state.config.STT_ENGINE == "":
if request.app.state.faster_whisper_model is None:
request.app.state.faster_whisper_model = set_faster_whisper_model(
@@ -465,7 +557,16 @@ def transcribe(request: Request, file_path):
)
model = request.app.state.faster_whisper_model
segments, info = model.transcribe(file_path, beam_size=5)
segments, info = model.transcribe(
file_path,
beam_size=5,
vad_filter=request.app.state.config.WHISPER_VAD_FILTER,
language=(
metadata.get("language", None)
if WHISPER_LANGUAGE == ""
else WHISPER_LANGUAGE
),
)
log.info(
"Detected language '%s' with probability %f"
% (info.language, info.language_probability)
@@ -482,11 +583,6 @@ def transcribe(request: Request, file_path):
log.debug(data)
return data
elif request.app.state.config.STT_ENGINE == "openai":
if is_mp4_audio(file_path):
os.rename(file_path, file_path.replace(".wav", ".mp4"))
# Convert MP4 audio file to WAV format
convert_mp4_to_wav(file_path.replace(".wav", ".mp4"), file_path)
r = None
try:
r = requests.post(
@@ -495,7 +591,14 @@ def transcribe(request: Request, file_path):
"Authorization": f"Bearer {request.app.state.config.STT_OPENAI_API_KEY}"
},
files={"file": (filename, open(file_path, "rb"))},
data={"model": request.app.state.config.STT_MODEL},
data={
"model": request.app.state.config.STT_MODEL,
**(
{"language": metadata.get("language")}
if metadata.get("language")
else {}
),
},
)
r.raise_for_status()
@@ -521,34 +624,325 @@ def transcribe(request: Request, file_path):
raise Exception(detail if detail else "Open WebUI: Server Connection Error")
elif request.app.state.config.STT_ENGINE == "deepgram":
try:
# Determine the MIME type of the file
mime, _ = mimetypes.guess_type(file_path)
if not mime:
mime = "audio/wav" # fallback to wav if undetectable
# Read the audio file
with open(file_path, "rb") as f:
file_data = f.read()
# Build headers and parameters
headers = {
"Authorization": f"Token {request.app.state.config.DEEPGRAM_API_KEY}",
"Content-Type": mime,
}
# Add model if specified
params = {}
if request.app.state.config.STT_MODEL:
params["model"] = request.app.state.config.STT_MODEL
# Make request to Deepgram API
r = requests.post(
"https://api.deepgram.com/v1/listen?smart_format=true",
headers=headers,
params=params,
data=file_data,
)
r.raise_for_status()
response_data = r.json()
# Extract transcript from Deepgram response
try:
transcript = response_data["results"]["channels"][0]["alternatives"][
0
].get("transcript", "")
except (KeyError, IndexError) as e:
log.error(f"Malformed response from Deepgram: {str(e)}")
raise Exception(
"Failed to parse Deepgram response - unexpected response format"
)
data = {"text": transcript.strip()}
# Save transcript
transcript_file = f"{file_dir}/{id}.json"
with open(transcript_file, "w") as f:
json.dump(data, f)
return data
except Exception as e:
log.exception(e)
detail = None
if r is not None:
try:
res = r.json()
if "error" in res:
detail = f"External: {res['error'].get('message', '')}"
except Exception:
detail = f"External: {e}"
raise Exception(detail if detail else "Open WebUI: Server Connection Error")
elif request.app.state.config.STT_ENGINE == "azure":
# Check file exists and size
if not os.path.exists(file_path):
raise HTTPException(status_code=400, detail="Audio file not found")
# Check file size (Azure has a larger limit of 200MB)
file_size = os.path.getsize(file_path)
if file_size > AZURE_MAX_FILE_SIZE:
raise HTTPException(
status_code=400,
detail=f"File size exceeds Azure's limit of {AZURE_MAX_FILE_SIZE_MB}MB",
)
api_key = request.app.state.config.AUDIO_STT_AZURE_API_KEY
region = request.app.state.config.AUDIO_STT_AZURE_REGION or "eastus"
locales = request.app.state.config.AUDIO_STT_AZURE_LOCALES
base_url = request.app.state.config.AUDIO_STT_AZURE_BASE_URL
max_speakers = request.app.state.config.AUDIO_STT_AZURE_MAX_SPEAKERS or 3
# IF NO LOCALES, USE DEFAULTS
if len(locales) < 2:
locales = [
"en-US",
"es-ES",
"es-MX",
"fr-FR",
"hi-IN",
"it-IT",
"de-DE",
"en-GB",
"en-IN",
"ja-JP",
"ko-KR",
"pt-BR",
"zh-CN",
]
locales = ",".join(locales)
if not api_key or not region:
raise HTTPException(
status_code=400,
detail="Azure API key is required for Azure STT",
)
r = None
try:
# Prepare the request
data = {
"definition": json.dumps(
{
"locales": locales.split(","),
"diarization": {"maxSpeakers": max_speakers, "enabled": True},
}
if locales
else {}
)
}
url = (
base_url or f"https://{region}.api.cognitive.microsoft.com"
) + "/speechtotext/transcriptions:transcribe?api-version=2024-11-15"
# Use context manager to ensure file is properly closed
with open(file_path, "rb") as audio_file:
r = requests.post(
url=url,
files={"audio": audio_file},
data=data,
headers={
"Ocp-Apim-Subscription-Key": api_key,
},
)
r.raise_for_status()
response = r.json()
# Extract transcript from response
if not response.get("combinedPhrases"):
raise ValueError("No transcription found in response")
# Get the full transcript from combinedPhrases
transcript = response["combinedPhrases"][0].get("text", "").strip()
if not transcript:
raise ValueError("Empty transcript in response")
data = {"text": transcript}
# Save transcript to json file (consistent with other providers)
transcript_file = f"{file_dir}/{id}.json"
with open(transcript_file, "w") as f:
json.dump(data, f)
log.debug(data)
return data
except (KeyError, IndexError, ValueError) as e:
log.exception("Error parsing Azure response")
raise HTTPException(
status_code=500,
detail=f"Failed to parse Azure response: {str(e)}",
)
except requests.exceptions.RequestException as e:
log.exception(e)
detail = None
try:
if r is not None and r.status_code != 200:
res = r.json()
if "error" in res:
detail = f"External: {res['error'].get('message', '')}"
except Exception:
detail = f"External: {e}"
raise HTTPException(
status_code=getattr(r, "status_code", 500) if r else 500,
detail=detail if detail else "Open WebUI: Server Connection Error",
)
def transcribe(request: Request, file_path: str, metadata: Optional[dict] = None):
log.info(f"transcribe: {file_path} {metadata}")
if is_audio_conversion_required(file_path):
file_path = convert_audio_to_mp3(file_path)
try:
file_path = compress_audio(file_path)
except Exception as e:
log.exception(e)
# Always produce a list of chunk paths (could be one entry if small)
try:
chunk_paths = split_audio(file_path, MAX_FILE_SIZE)
print(f"Chunk paths: {chunk_paths}")
except Exception as e:
log.exception(e)
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=ERROR_MESSAGES.DEFAULT(e),
)
results = []
try:
with ThreadPoolExecutor() as executor:
# Submit tasks for each chunk_path
futures = [
executor.submit(transcription_handler, request, chunk_path, metadata)
for chunk_path in chunk_paths
]
# Gather results as they complete
for future in futures:
try:
results.append(future.result())
except Exception as transcribe_exc:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"Error transcribing chunk: {transcribe_exc}",
)
finally:
# Clean up only the temporary chunks, never the original file
for chunk_path in chunk_paths:
if chunk_path != file_path and os.path.isfile(chunk_path):
try:
os.remove(chunk_path)
except Exception:
pass
return {
"text": " ".join([result["text"] for result in results]),
}
def compress_audio(file_path):
if os.path.getsize(file_path) > MAX_FILE_SIZE:
id = os.path.splitext(os.path.basename(file_path))[
0
] # Handles names with multiple dots
file_dir = os.path.dirname(file_path)
audio = AudioSegment.from_file(file_path)
audio = audio.set_frame_rate(16000).set_channels(1) # Compress audio
compressed_path = f"{file_dir}/{id}_compressed.opus"
audio.export(compressed_path, format="opus", bitrate="32k")
log.debug(f"Compressed audio to {compressed_path}")
if (
os.path.getsize(compressed_path) > MAX_FILE_SIZE
): # Still larger than MAX_FILE_SIZE after compression
raise Exception(ERROR_MESSAGES.FILE_TOO_LARGE(size=f"{MAX_FILE_SIZE_MB}MB"))
compressed_path = os.path.join(file_dir, f"{id}_compressed.mp3")
audio.export(compressed_path, format="mp3", bitrate="32k")
# log.debug(f"Compressed audio to {compressed_path}") # Uncomment if log is defined
return compressed_path
else:
return file_path
def split_audio(file_path, max_bytes, format="mp3", bitrate="32k"):
"""
Splits audio into chunks not exceeding max_bytes.
Returns a list of chunk file paths. If audio fits, returns list with original path.
"""
file_size = os.path.getsize(file_path)
if file_size <= max_bytes:
return [file_path] # Nothing to split
audio = AudioSegment.from_file(file_path)
duration_ms = len(audio)
orig_size = file_size
approx_chunk_ms = max(int(duration_ms * (max_bytes / orig_size)) - 1000, 1000)
chunks = []
start = 0
i = 0
base, _ = os.path.splitext(file_path)
while start < duration_ms:
end = min(start + approx_chunk_ms, duration_ms)
chunk = audio[start:end]
chunk_path = f"{base}_chunk_{i}.{format}"
chunk.export(chunk_path, format=format, bitrate=bitrate)
# Reduce chunk duration if still too large
while os.path.getsize(chunk_path) > max_bytes and (end - start) > 5000:
end = start + ((end - start) // 2)
chunk = audio[start:end]
chunk.export(chunk_path, format=format, bitrate=bitrate)
if os.path.getsize(chunk_path) > max_bytes:
os.remove(chunk_path)
raise Exception("Audio chunk cannot be reduced below max file size.")
chunks.append(chunk_path)
start = end
i += 1
return chunks
@router.post("/transcriptions")
def transcription(
request: Request,
file: UploadFile = File(...),
language: Optional[str] = Form(None),
user=Depends(get_verified_user),
):
log.info(f"file.content_type: {file.content_type}")
if file.content_type not in ["audio/mpeg", "audio/wav", "audio/ogg", "audio/x-m4a"]:
stt_supported_content_types = getattr(
request.app.state.config, "STT_SUPPORTED_CONTENT_TYPES", []
)
if not any(
fnmatch(file.content_type, content_type)
for content_type in (
stt_supported_content_types
if stt_supported_content_types
and any(t.strip() for t in stt_supported_content_types)
else ["audio/*", "video/webm"]
)
):
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=ERROR_MESSAGES.FILE_NOT_SUPPORTED,
@@ -569,19 +963,18 @@ def transcription(
f.write(contents)
try:
try:
file_path = compress_audio(file_path)
except Exception as e:
log.exception(e)
metadata = None
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=ERROR_MESSAGES.DEFAULT(e),
)
if language:
metadata = {"language": language}
result = transcribe(request, file_path, metadata)
return {
**result,
"filename": os.path.basename(file_path),
}
data = transcribe(request, file_path)
file_path = file_path.split("/")[-1]
return {**data, "filename": file_path}
except Exception as e:
log.exception(e)
@@ -602,7 +995,22 @@ def transcription(
def get_available_models(request: Request) -> list[dict]:
available_models = []
if request.app.state.config.TTS_ENGINE == "openai":
available_models = [{"id": "tts-1"}, {"id": "tts-1-hd"}]
# Use custom endpoint if not using the official OpenAI API URL
if not request.app.state.config.TTS_OPENAI_API_BASE_URL.startswith(
"https://api.openai.com"
):
try:
response = requests.get(
f"{request.app.state.config.TTS_OPENAI_API_BASE_URL}/audio/models"
)
response.raise_for_status()
data = response.json()
available_models = data.get("models", [])
except Exception as e:
log.error(f"Error fetching models from custom endpoint: {str(e)}")
available_models = [{"id": "tts-1"}, {"id": "tts-1-hd"}]
else:
available_models = [{"id": "tts-1"}, {"id": "tts-1-hd"}]
elif request.app.state.config.TTS_ENGINE == "elevenlabs":
try:
response = requests.get(
@@ -633,14 +1041,37 @@ def get_available_voices(request) -> dict:
"""Returns {voice_id: voice_name} dict"""
available_voices = {}
if request.app.state.config.TTS_ENGINE == "openai":
available_voices = {
"alloy": "alloy",
"echo": "echo",
"fable": "fable",
"onyx": "onyx",
"nova": "nova",
"shimmer": "shimmer",
}
# Use custom endpoint if not using the official OpenAI API URL
if not request.app.state.config.TTS_OPENAI_API_BASE_URL.startswith(
"https://api.openai.com"
):
try:
response = requests.get(
f"{request.app.state.config.TTS_OPENAI_API_BASE_URL}/audio/voices"
)
response.raise_for_status()
data = response.json()
voices_list = data.get("voices", [])
available_voices = {voice["id"]: voice["name"] for voice in voices_list}
except Exception as e:
log.error(f"Error fetching voices from custom endpoint: {str(e)}")
available_voices = {
"alloy": "alloy",
"echo": "echo",
"fable": "fable",
"onyx": "onyx",
"nova": "nova",
"shimmer": "shimmer",
}
else:
available_voices = {
"alloy": "alloy",
"echo": "echo",
"fable": "fable",
"onyx": "onyx",
"nova": "nova",
"shimmer": "shimmer",
}
elif request.app.state.config.TTS_ENGINE == "elevenlabs":
try:
available_voices = get_elevenlabs_voices(
@@ -652,7 +1083,10 @@ def get_available_voices(request) -> dict:
elif request.app.state.config.TTS_ENGINE == "azure":
try:
region = request.app.state.config.TTS_AZURE_SPEECH_REGION
url = f"https://{region}.tts.speech.microsoft.com/cognitiveservices/voices/list"
base_url = request.app.state.config.TTS_AZURE_SPEECH_BASE_URL
url = (
base_url or f"https://{region}.tts.speech.microsoft.com"
) + "/cognitiveservices/voices/list"
headers = {
"Ocp-Apim-Subscription-Key": request.app.state.config.TTS_API_KEY
}
+308 -98
View File
@@ -19,38 +19,42 @@ from open_webui.models.auths import (
UserResponse,
)
from open_webui.models.users import Users
from open_webui.models.groups import Groups
from open_webui.constants import ERROR_MESSAGES, WEBHOOK_MESSAGES
from open_webui.env import (
WEBUI_AUTH,
WEBUI_AUTH_TRUSTED_EMAIL_HEADER,
WEBUI_AUTH_TRUSTED_NAME_HEADER,
WEBUI_SESSION_COOKIE_SAME_SITE,
WEBUI_SESSION_COOKIE_SECURE,
WEBUI_AUTH_TRUSTED_GROUPS_HEADER,
WEBUI_AUTH_COOKIE_SAME_SITE,
WEBUI_AUTH_COOKIE_SECURE,
WEBUI_AUTH_SIGNOUT_REDIRECT_URL,
SRC_LOG_LEVELS,
)
from fastapi import APIRouter, Depends, HTTPException, Request, status
from fastapi.responses import RedirectResponse, Response
from open_webui.config import (
OPENID_PROVIDER_URL,
ENABLE_OAUTH_SIGNUP,
)
from fastapi.responses import RedirectResponse, Response, JSONResponse
from open_webui.config import OPENID_PROVIDER_URL, ENABLE_OAUTH_SIGNUP, ENABLE_LDAP
from pydantic import BaseModel
from open_webui.utils.misc import parse_duration, validate_email_format
from open_webui.utils.auth import (
decode_token,
create_api_key,
create_token,
get_admin_user,
get_verified_user,
get_current_user,
get_password_hash,
get_http_authorization_cred,
)
from open_webui.utils.webhook import post_webhook
from open_webui.utils.access_control import get_permissions
from typing import Optional, List
from ssl import CERT_REQUIRED, PROTOCOL_TLS
from ssl import CERT_NONE, CERT_REQUIRED, PROTOCOL_TLS
from ldap3 import Server, Connection, NONE, Tls
from ldap3.utils.conv import escape_filter_chars
@@ -73,31 +77,36 @@ class SessionUserResponse(Token, UserResponse):
async def get_session_user(
request: Request, response: Response, user=Depends(get_current_user)
):
expires_delta = parse_duration(request.app.state.config.JWT_EXPIRES_IN)
auth_header = request.headers.get("Authorization")
auth_token = get_http_authorization_cred(auth_header)
token = auth_token.credentials
data = decode_token(token)
expires_at = None
if expires_delta:
expires_at = int(time.time()) + int(expires_delta.total_seconds())
token = create_token(
data={"id": user.id},
expires_delta=expires_delta,
)
if data:
expires_at = data.get("exp")
datetime_expires_at = (
datetime.datetime.fromtimestamp(expires_at, datetime.timezone.utc)
if expires_at
else None
)
if (expires_at is not None) and int(time.time()) > expires_at:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail=ERROR_MESSAGES.INVALID_TOKEN,
)
# Set the cookie token
response.set_cookie(
key="token",
value=token,
expires=datetime_expires_at,
httponly=True, # Ensures the cookie is not accessible via JavaScript
samesite=WEBUI_SESSION_COOKIE_SAME_SITE,
secure=WEBUI_SESSION_COOKIE_SECURE,
)
# Set the cookie token
response.set_cookie(
key="token",
value=token,
expires=(
datetime.datetime.fromtimestamp(expires_at, datetime.timezone.utc)
if expires_at
else None
),
httponly=True, # Ensures the cookie is not accessible via JavaScript
samesite=WEBUI_AUTH_COOKIE_SAME_SITE,
secure=WEBUI_AUTH_COOKIE_SECURE,
)
user_permissions = get_permissions(
user.id, request.app.state.config.USER_PERMISSIONS
@@ -164,7 +173,7 @@ async def update_password(
############################
# LDAP Authentication
############################
@router.post("/ldap", response_model=SigninResponse)
@router.post("/ldap", response_model=SessionUserResponse)
async def ldap_auth(request: Request, response: Response, form_data: LdapForm):
ENABLE_LDAP = request.app.state.config.ENABLE_LDAP
LDAP_SERVER_LABEL = request.app.state.config.LDAP_SERVER_LABEL
@@ -178,6 +187,9 @@ async def ldap_auth(request: Request, response: Response, form_data: LdapForm):
LDAP_APP_PASSWORD = request.app.state.config.LDAP_APP_PASSWORD
LDAP_USE_TLS = request.app.state.config.LDAP_USE_TLS
LDAP_CA_CERT_FILE = request.app.state.config.LDAP_CA_CERT_FILE
LDAP_VALIDATE_CERT = (
CERT_REQUIRED if request.app.state.config.LDAP_VALIDATE_CERT else CERT_NONE
)
LDAP_CIPHERS = (
request.app.state.config.LDAP_CIPHERS
if request.app.state.config.LDAP_CIPHERS
@@ -189,14 +201,14 @@ async def ldap_auth(request: Request, response: Response, form_data: LdapForm):
try:
tls = Tls(
validate=CERT_REQUIRED,
validate=LDAP_VALIDATE_CERT,
version=PROTOCOL_TLS,
ca_certs_file=LDAP_CA_CERT_FILE,
ciphers=LDAP_CIPHERS,
)
except Exception as e:
log.error(f"An error occurred on TLS: {str(e)}")
raise HTTPException(400, detail=str(e))
log.error(f"TLS configuration error: {str(e)}")
raise HTTPException(400, detail="Failed to configure TLS for LDAP connection.")
try:
server = Server(
@@ -211,32 +223,120 @@ async def ldap_auth(request: Request, response: Response, form_data: LdapForm):
LDAP_APP_DN,
LDAP_APP_PASSWORD,
auto_bind="NONE",
authentication="SIMPLE",
authentication="SIMPLE" if LDAP_APP_DN else "ANONYMOUS",
)
if not connection_app.bind():
raise HTTPException(400, detail="Application account bind failed")
ENABLE_LDAP_GROUP_MANAGEMENT = (
request.app.state.config.ENABLE_LDAP_GROUP_MANAGEMENT
)
ENABLE_LDAP_GROUP_CREATION = request.app.state.config.ENABLE_LDAP_GROUP_CREATION
LDAP_ATTRIBUTE_FOR_GROUPS = request.app.state.config.LDAP_ATTRIBUTE_FOR_GROUPS
search_attributes = [
f"{LDAP_ATTRIBUTE_FOR_USERNAME}",
f"{LDAP_ATTRIBUTE_FOR_MAIL}",
"cn",
]
if ENABLE_LDAP_GROUP_MANAGEMENT:
search_attributes.append(f"{LDAP_ATTRIBUTE_FOR_GROUPS}")
log.info(
f"LDAP Group Management enabled. Adding {LDAP_ATTRIBUTE_FOR_GROUPS} to search attributes"
)
log.info(f"LDAP search attributes: {search_attributes}")
search_success = connection_app.search(
search_base=LDAP_SEARCH_BASE,
search_filter=f"(&({LDAP_ATTRIBUTE_FOR_USERNAME}={escape_filter_chars(form_data.user.lower())}){LDAP_SEARCH_FILTERS})",
attributes=[
f"{LDAP_ATTRIBUTE_FOR_USERNAME}",
f"{LDAP_ATTRIBUTE_FOR_MAIL}",
"cn",
],
attributes=search_attributes,
)
if not search_success:
if not search_success or not connection_app.entries:
raise HTTPException(400, detail="User not found in the LDAP server")
entry = connection_app.entries[0]
username = str(entry[f"{LDAP_ATTRIBUTE_FOR_USERNAME}"]).lower()
mail = str(entry[f"{LDAP_ATTRIBUTE_FOR_MAIL}"])
if not mail or mail == "" or mail == "[]":
raise HTTPException(400, f"User {form_data.user} does not have mail.")
email = entry[
f"{LDAP_ATTRIBUTE_FOR_MAIL}"
].value # retrieve the Attribute value
if not email:
raise HTTPException(400, "User does not have a valid email address.")
elif isinstance(email, str):
email = email.lower()
elif isinstance(email, list):
email = email[0].lower()
else:
email = str(email).lower()
cn = str(entry["cn"])
user_dn = entry.entry_dn
user_groups = []
if ENABLE_LDAP_GROUP_MANAGEMENT and LDAP_ATTRIBUTE_FOR_GROUPS in entry:
group_dns = entry[LDAP_ATTRIBUTE_FOR_GROUPS]
log.info(f"LDAP raw group DNs for user {username}: {group_dns}")
if group_dns:
log.info(f"LDAP group_dns original: {group_dns}")
log.info(f"LDAP group_dns type: {type(group_dns)}")
log.info(f"LDAP group_dns length: {len(group_dns)}")
if hasattr(group_dns, "value"):
group_dns = group_dns.value
log.info(f"Extracted .value property: {group_dns}")
elif hasattr(group_dns, "__iter__") and not isinstance(
group_dns, (str, bytes)
):
group_dns = list(group_dns)
log.info(f"Converted to list: {group_dns}")
if isinstance(group_dns, list):
group_dns = [str(item) for item in group_dns]
else:
group_dns = [str(group_dns)]
log.info(
f"LDAP group_dns after processing - type: {type(group_dns)}, length: {len(group_dns)}"
)
for group_idx, group_dn in enumerate(group_dns):
group_dn = str(group_dn)
log.info(f"Processing group DN #{group_idx + 1}: {group_dn}")
try:
group_cn = None
for item in group_dn.split(","):
item = item.strip()
if item.upper().startswith("CN="):
group_cn = item[3:]
break
if group_cn:
user_groups.append(group_cn)
else:
log.warning(
f"Could not extract CN from group DN: {group_dn}"
)
except Exception as e:
log.warning(
f"Failed to extract group name from DN {group_dn}: {e}"
)
log.info(
f"LDAP groups for user {username}: {user_groups} (total: {len(user_groups)})"
)
else:
log.info(f"No groups found for user {username}")
elif ENABLE_LDAP_GROUP_MANAGEMENT:
log.warning(
f"LDAP Group Management enabled but {LDAP_ATTRIBUTE_FOR_GROUPS} attribute not found in user entry"
)
if username == form_data.user.lower():
connection_user = Connection(
server,
@@ -246,19 +346,22 @@ async def ldap_auth(request: Request, response: Response, form_data: LdapForm):
authentication="SIMPLE",
)
if not connection_user.bind():
raise HTTPException(400, f"Authentication failed for {form_data.user}")
raise HTTPException(400, "Authentication failed.")
user = Users.get_user_by_email(mail)
user = Users.get_user_by_email(email)
if not user:
try:
role = (
"admin"
if Users.get_num_users() == 0
if not Users.has_users()
else request.app.state.config.DEFAULT_USER_ROLE
)
user = Auths.insert_new_auth(
email=mail, password=str(uuid.uuid4()), name=cn, role=role
email=email,
password=str(uuid.uuid4()),
name=cn,
role=role,
)
if not user:
@@ -269,43 +372,78 @@ async def ldap_auth(request: Request, response: Response, form_data: LdapForm):
except HTTPException:
raise
except Exception as err:
raise HTTPException(500, detail=ERROR_MESSAGES.DEFAULT(err))
log.error(f"LDAP user creation error: {str(err)}")
raise HTTPException(
500, detail="Internal error occurred during LDAP user creation."
)
user = Auths.authenticate_user_by_trusted_header(mail)
user = Auths.authenticate_user_by_email(email)
if user:
expires_delta = parse_duration(request.app.state.config.JWT_EXPIRES_IN)
expires_at = None
if expires_delta:
expires_at = int(time.time()) + int(expires_delta.total_seconds())
token = create_token(
data={"id": user.id},
expires_delta=parse_duration(
request.app.state.config.JWT_EXPIRES_IN
),
expires_delta=expires_delta,
)
# Set the cookie token
response.set_cookie(
key="token",
value=token,
expires=(
datetime.datetime.fromtimestamp(
expires_at, datetime.timezone.utc
)
if expires_at
else None
),
httponly=True, # Ensures the cookie is not accessible via JavaScript
samesite=WEBUI_AUTH_COOKIE_SAME_SITE,
secure=WEBUI_AUTH_COOKIE_SECURE,
)
user_permissions = get_permissions(
user.id, request.app.state.config.USER_PERMISSIONS
)
if (
user.role != "admin"
and ENABLE_LDAP_GROUP_MANAGEMENT
and user_groups
):
if ENABLE_LDAP_GROUP_CREATION:
Groups.create_groups_by_group_names(user.id, user_groups)
try:
Groups.sync_groups_by_group_names(user.id, user_groups)
log.info(
f"Successfully synced groups for user {user.id}: {user_groups}"
)
except Exception as e:
log.error(f"Failed to sync groups for user {user.id}: {e}")
return {
"token": token,
"token_type": "Bearer",
"expires_at": expires_at,
"id": user.id,
"email": user.email,
"name": user.name,
"role": user.role,
"profile_image_url": user.profile_image_url,
"permissions": user_permissions,
}
else:
raise HTTPException(400, detail=ERROR_MESSAGES.INVALID_CRED)
else:
raise HTTPException(
400,
f"User {form_data.user} does not match the record. Search result: {str(entry[f'{LDAP_ATTRIBUTE_FOR_USERNAME}'])}",
)
raise HTTPException(400, "User record mismatch.")
except Exception as e:
raise HTTPException(400, detail=str(e))
log.error(f"LDAP authentication error: {str(e)}")
raise HTTPException(400, detail="LDAP authentication failed.")
############################
@@ -319,21 +457,29 @@ async def signin(request: Request, response: Response, form_data: SigninForm):
if WEBUI_AUTH_TRUSTED_EMAIL_HEADER not in request.headers:
raise HTTPException(400, detail=ERROR_MESSAGES.INVALID_TRUSTED_HEADER)
trusted_email = request.headers[WEBUI_AUTH_TRUSTED_EMAIL_HEADER].lower()
trusted_name = trusted_email
email = request.headers[WEBUI_AUTH_TRUSTED_EMAIL_HEADER].lower()
name = email
if WEBUI_AUTH_TRUSTED_NAME_HEADER:
trusted_name = request.headers.get(
WEBUI_AUTH_TRUSTED_NAME_HEADER, trusted_email
)
if not Users.get_user_by_email(trusted_email.lower()):
name = request.headers.get(WEBUI_AUTH_TRUSTED_NAME_HEADER, email)
if not Users.get_user_by_email(email.lower()):
await signup(
request,
response,
SignupForm(
email=trusted_email, password=str(uuid.uuid4()), name=trusted_name
),
SignupForm(email=email, password=str(uuid.uuid4()), name=name),
)
user = Auths.authenticate_user_by_trusted_header(trusted_email)
user = Auths.authenticate_user_by_email(email)
if WEBUI_AUTH_TRUSTED_GROUPS_HEADER and user and user.role != "admin":
group_names = request.headers.get(
WEBUI_AUTH_TRUSTED_GROUPS_HEADER, ""
).split(",")
group_names = [name.strip() for name in group_names if name.strip()]
if group_names:
Groups.sync_groups_by_group_names(user.id, group_names)
elif WEBUI_AUTH == False:
admin_email = "admin@localhost"
admin_password = "admin"
@@ -341,7 +487,7 @@ async def signin(request: Request, response: Response, form_data: SigninForm):
if Users.get_user_by_email(admin_email.lower()):
user = Auths.authenticate_user(admin_email.lower(), admin_password)
else:
if Users.get_num_users() != 0:
if Users.has_users():
raise HTTPException(400, detail=ERROR_MESSAGES.EXISTING_USERS)
await signup(
@@ -378,8 +524,8 @@ async def signin(request: Request, response: Response, form_data: SigninForm):
value=token,
expires=datetime_expires_at,
httponly=True, # Ensures the cookie is not accessible via JavaScript
samesite=WEBUI_SESSION_COOKIE_SAME_SITE,
secure=WEBUI_SESSION_COOKIE_SECURE,
samesite=WEBUI_AUTH_COOKIE_SAME_SITE,
secure=WEBUI_AUTH_COOKIE_SECURE,
)
user_permissions = get_permissions(
@@ -408,6 +554,8 @@ async def signin(request: Request, response: Response, form_data: SigninForm):
@router.post("/signup", response_model=SessionUserResponse)
async def signup(request: Request, response: Response, form_data: SignupForm):
has_users = Users.has_users()
if WEBUI_AUTH:
if (
not request.app.state.config.ENABLE_SIGNUP
@@ -417,7 +565,7 @@ async def signup(request: Request, response: Response, form_data: SignupForm):
status.HTTP_403_FORBIDDEN, detail=ERROR_MESSAGES.ACCESS_PROHIBITED
)
else:
if Users.get_num_users() != 0:
if has_users:
raise HTTPException(
status.HTTP_403_FORBIDDEN, detail=ERROR_MESSAGES.ACCESS_PROHIBITED
)
@@ -431,15 +579,14 @@ async def signup(request: Request, response: Response, form_data: SignupForm):
raise HTTPException(400, detail=ERROR_MESSAGES.EMAIL_TAKEN)
try:
role = (
"admin"
if Users.get_num_users() == 0
else request.app.state.config.DEFAULT_USER_ROLE
)
role = "admin" if not has_users else request.app.state.config.DEFAULT_USER_ROLE
if Users.get_num_users() == 0:
# Disable signup after the first user is created
request.app.state.config.ENABLE_SIGNUP = False
# The password passed to bcrypt must be 72 bytes or fewer. If it is longer, it will be truncated before hashing.
if len(form_data.password.encode("utf-8")) > 72:
raise HTTPException(
status.HTTP_400_BAD_REQUEST,
detail=ERROR_MESSAGES.PASSWORD_TOO_LONG,
)
hashed = get_password_hash(form_data.password)
user = Auths.insert_new_auth(
@@ -473,12 +620,13 @@ async def signup(request: Request, response: Response, form_data: SignupForm):
value=token,
expires=datetime_expires_at,
httponly=True, # Ensures the cookie is not accessible via JavaScript
samesite=WEBUI_SESSION_COOKIE_SAME_SITE,
secure=WEBUI_SESSION_COOKIE_SECURE,
samesite=WEBUI_AUTH_COOKIE_SAME_SITE,
secure=WEBUI_AUTH_COOKIE_SECURE,
)
if request.app.state.config.WEBHOOK_URL:
post_webhook(
request.app.state.WEBUI_NAME,
request.app.state.config.WEBHOOK_URL,
WEBHOOK_MESSAGES.USER_SIGNUP(user.name),
{
@@ -492,6 +640,10 @@ async def signup(request: Request, response: Response, form_data: SignupForm):
user.id, request.app.state.config.USER_PERMISSIONS
)
if not has_users:
# Disable signup after the first user is created
request.app.state.config.ENABLE_SIGNUP = False
return {
"token": token,
"token_type": "Bearer",
@@ -506,26 +658,39 @@ async def signup(request: Request, response: Response, form_data: SignupForm):
else:
raise HTTPException(500, detail=ERROR_MESSAGES.CREATE_USER_ERROR)
except Exception as err:
raise HTTPException(500, detail=ERROR_MESSAGES.DEFAULT(err))
log.error(f"Signup error: {str(err)}")
raise HTTPException(500, detail="An internal error occurred during signup.")
@router.get("/signout")
async def signout(request: Request, response: Response):
response.delete_cookie("token")
response.delete_cookie("oui-session")
if ENABLE_OAUTH_SIGNUP.value:
oauth_id_token = request.cookies.get("oauth_id_token")
if oauth_id_token:
if oauth_id_token and OPENID_PROVIDER_URL.value:
try:
async with ClientSession() as session:
async with ClientSession(trust_env=True) as session:
async with session.get(OPENID_PROVIDER_URL.value) as resp:
if resp.status == 200:
openid_data = await resp.json()
logout_url = openid_data.get("end_session_endpoint")
if logout_url:
response.delete_cookie("oauth_id_token")
return RedirectResponse(
url=f"{logout_url}?id_token_hint={oauth_id_token}"
return JSONResponse(
status_code=200,
content={
"status": True,
"redirect_url": f"{logout_url}?id_token_hint={oauth_id_token}"
+ (
f"&post_logout_redirect_uri={WEBUI_AUTH_SIGNOUT_REDIRECT_URL}"
if WEBUI_AUTH_SIGNOUT_REDIRECT_URL
else ""
),
},
headers=response.headers,
)
else:
raise HTTPException(
@@ -533,9 +698,25 @@ async def signout(request: Request, response: Response):
detail="Failed to fetch OpenID configuration",
)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
log.error(f"OpenID signout error: {str(e)}")
raise HTTPException(
status_code=500,
detail="Failed to sign out from the OpenID provider.",
)
return {"status": True}
if WEBUI_AUTH_SIGNOUT_REDIRECT_URL:
return JSONResponse(
status_code=200,
content={
"status": True,
"redirect_url": WEBUI_AUTH_SIGNOUT_REDIRECT_URL,
},
headers=response.headers,
)
return JSONResponse(
status_code=200, content={"status": True}, headers=response.headers
)
############################
@@ -577,7 +758,10 @@ async def add_user(form_data: AddUserForm, user=Depends(get_admin_user)):
else:
raise HTTPException(500, detail=ERROR_MESSAGES.CREATE_USER_ERROR)
except Exception as err:
raise HTTPException(500, detail=ERROR_MESSAGES.DEFAULT(err))
log.error(f"Add user error: {str(err)}")
raise HTTPException(
500, detail="An internal error occurred while adding the user."
)
############################
@@ -591,7 +775,7 @@ async def get_admin_details(request: Request, user=Depends(get_current_user)):
admin_email = request.app.state.config.ADMIN_EMAIL
admin_name = None
print(admin_email, admin_name)
log.info(f"Admin details - Email: {admin_email}, Name: {admin_name}")
if admin_email:
admin = Users.get_user_by_email(admin_email)
@@ -625,11 +809,16 @@ async def get_admin_config(request: Request, user=Depends(get_admin_user)):
"ENABLE_API_KEY": request.app.state.config.ENABLE_API_KEY,
"ENABLE_API_KEY_ENDPOINT_RESTRICTIONS": request.app.state.config.ENABLE_API_KEY_ENDPOINT_RESTRICTIONS,
"API_KEY_ALLOWED_ENDPOINTS": request.app.state.config.API_KEY_ALLOWED_ENDPOINTS,
"ENABLE_CHANNELS": request.app.state.config.ENABLE_CHANNELS,
"DEFAULT_USER_ROLE": request.app.state.config.DEFAULT_USER_ROLE,
"JWT_EXPIRES_IN": request.app.state.config.JWT_EXPIRES_IN,
"ENABLE_COMMUNITY_SHARING": request.app.state.config.ENABLE_COMMUNITY_SHARING,
"ENABLE_MESSAGE_RATING": request.app.state.config.ENABLE_MESSAGE_RATING,
"ENABLE_CHANNELS": request.app.state.config.ENABLE_CHANNELS,
"ENABLE_NOTES": request.app.state.config.ENABLE_NOTES,
"ENABLE_USER_WEBHOOKS": request.app.state.config.ENABLE_USER_WEBHOOKS,
"PENDING_USER_OVERLAY_TITLE": request.app.state.config.PENDING_USER_OVERLAY_TITLE,
"PENDING_USER_OVERLAY_CONTENT": request.app.state.config.PENDING_USER_OVERLAY_CONTENT,
"RESPONSE_WATERMARK": request.app.state.config.RESPONSE_WATERMARK,
}
@@ -640,11 +829,16 @@ class AdminConfig(BaseModel):
ENABLE_API_KEY: bool
ENABLE_API_KEY_ENDPOINT_RESTRICTIONS: bool
API_KEY_ALLOWED_ENDPOINTS: str
ENABLE_CHANNELS: bool
DEFAULT_USER_ROLE: str
JWT_EXPIRES_IN: str
ENABLE_COMMUNITY_SHARING: bool
ENABLE_MESSAGE_RATING: bool
ENABLE_CHANNELS: bool
ENABLE_NOTES: bool
ENABLE_USER_WEBHOOKS: bool
PENDING_USER_OVERLAY_TITLE: Optional[str] = None
PENDING_USER_OVERLAY_CONTENT: Optional[str] = None
RESPONSE_WATERMARK: Optional[str] = None
@router.post("/admin/config")
@@ -664,6 +858,7 @@ async def update_admin_config(
)
request.app.state.config.ENABLE_CHANNELS = form_data.ENABLE_CHANNELS
request.app.state.config.ENABLE_NOTES = form_data.ENABLE_NOTES
if form_data.DEFAULT_USER_ROLE in ["pending", "user", "admin"]:
request.app.state.config.DEFAULT_USER_ROLE = form_data.DEFAULT_USER_ROLE
@@ -679,6 +874,17 @@ async def update_admin_config(
)
request.app.state.config.ENABLE_MESSAGE_RATING = form_data.ENABLE_MESSAGE_RATING
request.app.state.config.ENABLE_USER_WEBHOOKS = form_data.ENABLE_USER_WEBHOOKS
request.app.state.config.PENDING_USER_OVERLAY_TITLE = (
form_data.PENDING_USER_OVERLAY_TITLE
)
request.app.state.config.PENDING_USER_OVERLAY_CONTENT = (
form_data.PENDING_USER_OVERLAY_CONTENT
)
request.app.state.config.RESPONSE_WATERMARK = form_data.RESPONSE_WATERMARK
return {
"SHOW_ADMIN_DETAILS": request.app.state.config.SHOW_ADMIN_DETAILS,
"WEBUI_URL": request.app.state.config.WEBUI_URL,
@@ -686,11 +892,16 @@ async def update_admin_config(
"ENABLE_API_KEY": request.app.state.config.ENABLE_API_KEY,
"ENABLE_API_KEY_ENDPOINT_RESTRICTIONS": request.app.state.config.ENABLE_API_KEY_ENDPOINT_RESTRICTIONS,
"API_KEY_ALLOWED_ENDPOINTS": request.app.state.config.API_KEY_ALLOWED_ENDPOINTS,
"ENABLE_CHANNELS": request.app.state.config.ENABLE_CHANNELS,
"DEFAULT_USER_ROLE": request.app.state.config.DEFAULT_USER_ROLE,
"JWT_EXPIRES_IN": request.app.state.config.JWT_EXPIRES_IN,
"ENABLE_COMMUNITY_SHARING": request.app.state.config.ENABLE_COMMUNITY_SHARING,
"ENABLE_MESSAGE_RATING": request.app.state.config.ENABLE_MESSAGE_RATING,
"ENABLE_CHANNELS": request.app.state.config.ENABLE_CHANNELS,
"ENABLE_NOTES": request.app.state.config.ENABLE_NOTES,
"ENABLE_USER_WEBHOOKS": request.app.state.config.ENABLE_USER_WEBHOOKS,
"PENDING_USER_OVERLAY_TITLE": request.app.state.config.PENDING_USER_OVERLAY_TITLE,
"PENDING_USER_OVERLAY_CONTENT": request.app.state.config.PENDING_USER_OVERLAY_CONTENT,
"RESPONSE_WATERMARK": request.app.state.config.RESPONSE_WATERMARK,
}
@@ -706,6 +917,7 @@ class LdapServerConfig(BaseModel):
search_filters: str = ""
use_tls: bool = True
certificate_path: Optional[str] = None
validate_cert: bool = True
ciphers: Optional[str] = "ALL"
@@ -723,6 +935,7 @@ async def get_ldap_server(request: Request, user=Depends(get_admin_user)):
"search_filters": request.app.state.config.LDAP_SEARCH_FILTERS,
"use_tls": request.app.state.config.LDAP_USE_TLS,
"certificate_path": request.app.state.config.LDAP_CA_CERT_FILE,
"validate_cert": request.app.state.config.LDAP_VALIDATE_CERT,
"ciphers": request.app.state.config.LDAP_CIPHERS,
}
@@ -745,11 +958,6 @@ async def update_ldap_server(
if not value:
raise HTTPException(400, detail=f"Required field {key} is empty")
if form_data.use_tls and not form_data.certificate_path:
raise HTTPException(
400, detail="TLS is enabled but certificate file path is missing"
)
request.app.state.config.LDAP_SERVER_LABEL = form_data.label
request.app.state.config.LDAP_SERVER_HOST = form_data.host
request.app.state.config.LDAP_SERVER_PORT = form_data.port
@@ -763,6 +971,7 @@ async def update_ldap_server(
request.app.state.config.LDAP_SEARCH_FILTERS = form_data.search_filters
request.app.state.config.LDAP_USE_TLS = form_data.use_tls
request.app.state.config.LDAP_CA_CERT_FILE = form_data.certificate_path
request.app.state.config.LDAP_VALIDATE_CERT = form_data.validate_cert
request.app.state.config.LDAP_CIPHERS = form_data.ciphers
return {
@@ -777,6 +986,7 @@ async def update_ldap_server(
"search_filters": request.app.state.config.LDAP_SEARCH_FILTERS,
"use_tls": request.app.state.config.LDAP_USE_TLS,
"certificate_path": request.app.state.config.LDAP_CA_CERT_FILE,
"validate_cert": request.app.state.config.LDAP_VALIDATE_CERT,
"ciphers": request.app.state.config.LDAP_CIPHERS,
}
+27 -17
View File
@@ -40,10 +40,14 @@ router = APIRouter()
@router.get("/", response_model=list[ChannelModel])
async def get_channels(user=Depends(get_verified_user)):
return Channels.get_channels_by_user_id(user.id)
@router.get("/list", response_model=list[ChannelModel])
async def get_all_channels(user=Depends(get_verified_user)):
if user.role == "admin":
return Channels.get_channels()
else:
return Channels.get_channels_by_user_id(user.id)
return Channels.get_channels_by_user_id(user.id)
############################
@@ -192,7 +196,7 @@ async def get_channel_messages(
############################
async def send_notification(webui_url, channel, message, active_user_ids):
async def send_notification(name, webui_url, channel, message, active_user_ids):
users = get_users_with_access("read", channel.access_control)
for user in users:
@@ -206,6 +210,7 @@ async def send_notification(webui_url, channel, message, active_user_ids):
if webhook_url:
post_webhook(
name,
webhook_url,
f"#{channel.name} - {webui_url}/channels/{channel.id}\n\n{message.content}",
{
@@ -302,6 +307,7 @@ async def post_new_message(
background_tasks.add_task(
send_notification,
request.app.state.WEBUI_NAME,
request.app.state.config.WEBUI_URL,
channel,
message,
@@ -428,13 +434,6 @@ async def update_message_by_id(
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(
@@ -446,6 +445,15 @@ async def update_message_by_id(
status_code=status.HTTP_400_BAD_REQUEST, detail=ERROR_MESSAGES.DEFAULT()
)
if (
user.role != "admin"
and message.user_id != user.id
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()
)
try:
message = Messages.update_message_by_id(message_id, form_data)
message = Messages.get_message_by_id(message_id)
@@ -635,13 +643,6 @@ async def delete_message_by_id(
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(
@@ -653,6 +654,15 @@ async def delete_message_by_id(
status_code=status.HTTP_400_BAD_REQUEST, detail=ERROR_MESSAGES.DEFAULT()
)
if (
user.role != "admin"
and message.user_id != user.id
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()
)
try:
Messages.delete_message_by_id(message_id)
await sio.emit(
+218 -19
View File
@@ -2,6 +2,8 @@ import json
import logging
from typing import Optional
from open_webui.socket.main import get_event_emitter
from open_webui.models.chats import (
ChatForm,
ChatImportForm,
@@ -37,13 +39,21 @@ router = APIRouter()
async def get_session_user_chat_list(
user=Depends(get_verified_user), page: Optional[int] = None
):
if page is not None:
limit = 60
skip = (page - 1) * limit
try:
if page is not None:
limit = 60
skip = (page - 1) * limit
return Chats.get_chat_title_id_list_by_user_id(user.id, skip=skip, limit=limit)
else:
return Chats.get_chat_title_id_list_by_user_id(user.id)
return Chats.get_chat_title_id_list_by_user_id(
user.id, skip=skip, limit=limit
)
else:
return Chats.get_chat_title_id_list_by_user_id(user.id)
except Exception as e:
log.exception(e)
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST, detail=ERROR_MESSAGES.DEFAULT()
)
############################
@@ -74,17 +84,34 @@ async def delete_all_user_chats(request: Request, user=Depends(get_verified_user
@router.get("/list/user/{user_id}", response_model=list[ChatTitleIdResponse])
async def get_user_chat_list_by_user_id(
user_id: str,
page: Optional[int] = None,
query: Optional[str] = None,
order_by: Optional[str] = None,
direction: Optional[str] = None,
user=Depends(get_admin_user),
skip: int = 0,
limit: int = 50,
):
if not ENABLE_ADMIN_CHAT_ACCESS:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail=ERROR_MESSAGES.ACCESS_PROHIBITED,
)
if page is None:
page = 1
limit = 60
skip = (page - 1) * limit
filter = {}
if query:
filter["query"] = query
if order_by:
filter["order_by"] = order_by
if direction:
filter["direction"] = direction
return Chats.get_chat_list_by_user_id(
user_id, include_archived=True, skip=skip, limit=limit
user_id, include_archived=True, filter=filter, skip=skip, limit=limit
)
@@ -192,10 +219,10 @@ async def get_chats_by_folder_id(folder_id: str, user=Depends(get_verified_user)
############################
@router.get("/pinned", response_model=list[ChatResponse])
@router.get("/pinned", response_model=list[ChatTitleIdResponse])
async def get_user_pinned_chats(user=Depends(get_verified_user)):
return [
ChatResponse(**chat.model_dump())
ChatTitleIdResponse(**chat.model_dump())
for chat in Chats.get_pinned_chats_by_user_id(user.id)
]
@@ -265,9 +292,37 @@ async def get_all_user_chats_in_db(user=Depends(get_admin_user)):
@router.get("/archived", response_model=list[ChatTitleIdResponse])
async def get_archived_session_user_chat_list(
user=Depends(get_verified_user), skip: int = 0, limit: int = 50
page: Optional[int] = None,
query: Optional[str] = None,
order_by: Optional[str] = None,
direction: Optional[str] = None,
user=Depends(get_verified_user),
):
return Chats.get_archived_chat_list_by_user_id(user.id, skip, limit)
if page is None:
page = 1
limit = 60
skip = (page - 1) * limit
filter = {}
if query:
filter["query"] = query
if order_by:
filter["order_by"] = order_by
if direction:
filter["direction"] = direction
chat_list = [
ChatTitleIdResponse(**chat.model_dump())
for chat in Chats.get_archived_chat_list_by_user_id(
user.id,
filter=filter,
skip=skip,
limit=limit,
)
]
return chat_list
############################
@@ -372,6 +427,107 @@ async def update_chat_by_id(
)
############################
# UpdateChatMessageById
############################
class MessageForm(BaseModel):
content: str
@router.post("/{id}/messages/{message_id}", response_model=Optional[ChatResponse])
async def update_chat_message_by_id(
id: str, message_id: str, form_data: MessageForm, user=Depends(get_verified_user)
):
chat = Chats.get_chat_by_id(id)
if not chat:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail=ERROR_MESSAGES.ACCESS_PROHIBITED,
)
if chat.user_id != user.id and user.role != "admin":
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail=ERROR_MESSAGES.ACCESS_PROHIBITED,
)
chat = Chats.upsert_message_to_chat_by_id_and_message_id(
id,
message_id,
{
"content": form_data.content,
},
)
event_emitter = get_event_emitter(
{
"user_id": user.id,
"chat_id": id,
"message_id": message_id,
},
False,
)
if event_emitter:
await event_emitter(
{
"type": "chat:message",
"data": {
"chat_id": id,
"message_id": message_id,
"content": form_data.content,
},
}
)
return ChatResponse(**chat.model_dump())
############################
# SendChatMessageEventById
############################
class EventForm(BaseModel):
type: str
data: dict
@router.post("/{id}/messages/{message_id}/event", response_model=Optional[bool])
async def send_chat_message_event_by_id(
id: str, message_id: str, form_data: EventForm, user=Depends(get_verified_user)
):
chat = Chats.get_chat_by_id(id)
if not chat:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail=ERROR_MESSAGES.ACCESS_PROHIBITED,
)
if chat.user_id != user.id and user.role != "admin":
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail=ERROR_MESSAGES.ACCESS_PROHIBITED,
)
event_emitter = get_event_emitter(
{
"user_id": user.id,
"chat_id": id,
"message_id": message_id,
}
)
try:
if event_emitter:
await event_emitter(form_data.model_dump())
else:
return False
return True
except:
return False
############################
# DeleteChatById
############################
@@ -444,18 +600,35 @@ async def pin_chat_by_id(id: str, user=Depends(get_verified_user)):
############################
class CloneForm(BaseModel):
title: Optional[str] = None
@router.post("/{id}/clone", response_model=Optional[ChatResponse])
async def clone_chat_by_id(id: str, user=Depends(get_verified_user)):
async def clone_chat_by_id(
form_data: CloneForm, id: str, user=Depends(get_verified_user)
):
chat = Chats.get_chat_by_id_and_user_id(id, user.id)
if chat:
updated_chat = {
**chat.chat,
"originalChatId": chat.id,
"branchPointMessageId": chat.chat["history"]["currentId"],
"title": f"Clone of {chat.title}",
"title": form_data.title if form_data.title else f"Clone of {chat.title}",
}
chat = Chats.insert_new_chat(user.id, ChatForm(**{"chat": updated_chat}))
chat = Chats.import_chat(
user.id,
ChatImportForm(
**{
"chat": updated_chat,
"meta": chat.meta,
"pinned": chat.pinned,
"folder_id": chat.folder_id,
}
),
)
return ChatResponse(**chat.model_dump())
else:
raise HTTPException(
@@ -470,7 +643,12 @@ async def clone_chat_by_id(id: str, user=Depends(get_verified_user)):
@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 user.role == "admin":
chat = Chats.get_chat_by_id(id)
else:
chat = Chats.get_chat_by_share_id(id)
if chat:
updated_chat = {
**chat.chat,
@@ -479,7 +657,17 @@ async def clone_shared_chat_by_id(id: str, user=Depends(get_verified_user)):
"title": f"Clone of {chat.title}",
}
chat = Chats.insert_new_chat(user.id, ChatForm(**{"chat": updated_chat}))
chat = Chats.import_chat(
user.id,
ChatImportForm(
**{
"chat": updated_chat,
"meta": chat.meta,
"pinned": chat.pinned,
"folder_id": chat.folder_id,
}
),
)
return ChatResponse(**chat.model_dump())
else:
raise HTTPException(
@@ -524,8 +712,19 @@ async def archive_chat_by_id(id: str, user=Depends(get_verified_user)):
@router.post("/{id}/share", response_model=Optional[ChatResponse])
async def share_chat_by_id(id: str, user=Depends(get_verified_user)):
async def share_chat_by_id(request: Request, id: str, user=Depends(get_verified_user)):
if (user.role != "admin") and (
not has_permission(
user.id, "chat.share", request.app.state.config.USER_PERMISSIONS
)
):
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail=ERROR_MESSAGES.ACCESS_PROHIBITED,
)
chat = Chats.get_chat_by_id_and_user_id(id, user.id)
if chat:
if chat.share_id:
shared_chat = Chats.update_shared_chat_by_chat_id(chat.id)
+223 -2
View File
@@ -1,5 +1,5 @@
from fastapi import APIRouter, Depends, Request
from pydantic import BaseModel
from fastapi import APIRouter, Depends, Request, HTTPException
from pydantic import BaseModel, ConfigDict
from typing import Optional
@@ -7,6 +7,12 @@ from open_webui.utils.auth import get_admin_user, get_verified_user
from open_webui.config import get_config, save_config
from open_webui.config import BannerModel
from open_webui.utils.tools import (
get_tool_server_data,
get_tool_servers_data,
get_tool_server_url,
)
router = APIRouter()
@@ -36,6 +42,221 @@ async def export_config(user=Depends(get_admin_user)):
return get_config()
############################
# Connections Config
############################
class ConnectionsConfigForm(BaseModel):
ENABLE_DIRECT_CONNECTIONS: bool
ENABLE_BASE_MODELS_CACHE: bool
@router.get("/connections", response_model=ConnectionsConfigForm)
async def get_connections_config(request: Request, user=Depends(get_admin_user)):
return {
"ENABLE_DIRECT_CONNECTIONS": request.app.state.config.ENABLE_DIRECT_CONNECTIONS,
"ENABLE_BASE_MODELS_CACHE": request.app.state.config.ENABLE_BASE_MODELS_CACHE,
}
@router.post("/connections", response_model=ConnectionsConfigForm)
async def set_connections_config(
request: Request,
form_data: ConnectionsConfigForm,
user=Depends(get_admin_user),
):
request.app.state.config.ENABLE_DIRECT_CONNECTIONS = (
form_data.ENABLE_DIRECT_CONNECTIONS
)
request.app.state.config.ENABLE_BASE_MODELS_CACHE = (
form_data.ENABLE_BASE_MODELS_CACHE
)
return {
"ENABLE_DIRECT_CONNECTIONS": request.app.state.config.ENABLE_DIRECT_CONNECTIONS,
"ENABLE_BASE_MODELS_CACHE": request.app.state.config.ENABLE_BASE_MODELS_CACHE,
}
############################
# ToolServers Config
############################
class ToolServerConnection(BaseModel):
url: str
path: str
auth_type: Optional[str]
key: Optional[str]
config: Optional[dict]
model_config = ConfigDict(extra="allow")
class ToolServersConfigForm(BaseModel):
TOOL_SERVER_CONNECTIONS: list[ToolServerConnection]
@router.get("/tool_servers", response_model=ToolServersConfigForm)
async def get_tool_servers_config(request: Request, user=Depends(get_admin_user)):
return {
"TOOL_SERVER_CONNECTIONS": request.app.state.config.TOOL_SERVER_CONNECTIONS,
}
@router.post("/tool_servers", response_model=ToolServersConfigForm)
async def set_tool_servers_config(
request: Request,
form_data: ToolServersConfigForm,
user=Depends(get_admin_user),
):
request.app.state.config.TOOL_SERVER_CONNECTIONS = [
connection.model_dump() for connection in form_data.TOOL_SERVER_CONNECTIONS
]
request.app.state.TOOL_SERVERS = await get_tool_servers_data(
request.app.state.config.TOOL_SERVER_CONNECTIONS
)
return {
"TOOL_SERVER_CONNECTIONS": request.app.state.config.TOOL_SERVER_CONNECTIONS,
}
@router.post("/tool_servers/verify")
async def verify_tool_servers_config(
request: Request, form_data: ToolServerConnection, user=Depends(get_admin_user)
):
"""
Verify the connection to the tool server.
"""
try:
token = None
if form_data.auth_type == "bearer":
token = form_data.key
elif form_data.auth_type == "session":
token = request.state.token.credentials
url = get_tool_server_url(form_data.url, form_data.path)
return await get_tool_server_data(token, url)
except Exception as e:
raise HTTPException(
status_code=400,
detail=f"Failed to connect to the tool server: {str(e)}",
)
############################
# CodeInterpreterConfig
############################
class CodeInterpreterConfigForm(BaseModel):
ENABLE_CODE_EXECUTION: bool
CODE_EXECUTION_ENGINE: str
CODE_EXECUTION_JUPYTER_URL: Optional[str]
CODE_EXECUTION_JUPYTER_AUTH: Optional[str]
CODE_EXECUTION_JUPYTER_AUTH_TOKEN: Optional[str]
CODE_EXECUTION_JUPYTER_AUTH_PASSWORD: Optional[str]
CODE_EXECUTION_JUPYTER_TIMEOUT: Optional[int]
ENABLE_CODE_INTERPRETER: bool
CODE_INTERPRETER_ENGINE: str
CODE_INTERPRETER_PROMPT_TEMPLATE: Optional[str]
CODE_INTERPRETER_JUPYTER_URL: Optional[str]
CODE_INTERPRETER_JUPYTER_AUTH: Optional[str]
CODE_INTERPRETER_JUPYTER_AUTH_TOKEN: Optional[str]
CODE_INTERPRETER_JUPYTER_AUTH_PASSWORD: Optional[str]
CODE_INTERPRETER_JUPYTER_TIMEOUT: Optional[int]
@router.get("/code_execution", response_model=CodeInterpreterConfigForm)
async def get_code_execution_config(request: Request, user=Depends(get_admin_user)):
return {
"ENABLE_CODE_EXECUTION": request.app.state.config.ENABLE_CODE_EXECUTION,
"CODE_EXECUTION_ENGINE": request.app.state.config.CODE_EXECUTION_ENGINE,
"CODE_EXECUTION_JUPYTER_URL": request.app.state.config.CODE_EXECUTION_JUPYTER_URL,
"CODE_EXECUTION_JUPYTER_AUTH": request.app.state.config.CODE_EXECUTION_JUPYTER_AUTH,
"CODE_EXECUTION_JUPYTER_AUTH_TOKEN": request.app.state.config.CODE_EXECUTION_JUPYTER_AUTH_TOKEN,
"CODE_EXECUTION_JUPYTER_AUTH_PASSWORD": request.app.state.config.CODE_EXECUTION_JUPYTER_AUTH_PASSWORD,
"CODE_EXECUTION_JUPYTER_TIMEOUT": request.app.state.config.CODE_EXECUTION_JUPYTER_TIMEOUT,
"ENABLE_CODE_INTERPRETER": request.app.state.config.ENABLE_CODE_INTERPRETER,
"CODE_INTERPRETER_ENGINE": request.app.state.config.CODE_INTERPRETER_ENGINE,
"CODE_INTERPRETER_PROMPT_TEMPLATE": request.app.state.config.CODE_INTERPRETER_PROMPT_TEMPLATE,
"CODE_INTERPRETER_JUPYTER_URL": request.app.state.config.CODE_INTERPRETER_JUPYTER_URL,
"CODE_INTERPRETER_JUPYTER_AUTH": request.app.state.config.CODE_INTERPRETER_JUPYTER_AUTH,
"CODE_INTERPRETER_JUPYTER_AUTH_TOKEN": request.app.state.config.CODE_INTERPRETER_JUPYTER_AUTH_TOKEN,
"CODE_INTERPRETER_JUPYTER_AUTH_PASSWORD": request.app.state.config.CODE_INTERPRETER_JUPYTER_AUTH_PASSWORD,
"CODE_INTERPRETER_JUPYTER_TIMEOUT": request.app.state.config.CODE_INTERPRETER_JUPYTER_TIMEOUT,
}
@router.post("/code_execution", response_model=CodeInterpreterConfigForm)
async def set_code_execution_config(
request: Request, form_data: CodeInterpreterConfigForm, user=Depends(get_admin_user)
):
request.app.state.config.ENABLE_CODE_EXECUTION = form_data.ENABLE_CODE_EXECUTION
request.app.state.config.CODE_EXECUTION_ENGINE = form_data.CODE_EXECUTION_ENGINE
request.app.state.config.CODE_EXECUTION_JUPYTER_URL = (
form_data.CODE_EXECUTION_JUPYTER_URL
)
request.app.state.config.CODE_EXECUTION_JUPYTER_AUTH = (
form_data.CODE_EXECUTION_JUPYTER_AUTH
)
request.app.state.config.CODE_EXECUTION_JUPYTER_AUTH_TOKEN = (
form_data.CODE_EXECUTION_JUPYTER_AUTH_TOKEN
)
request.app.state.config.CODE_EXECUTION_JUPYTER_AUTH_PASSWORD = (
form_data.CODE_EXECUTION_JUPYTER_AUTH_PASSWORD
)
request.app.state.config.CODE_EXECUTION_JUPYTER_TIMEOUT = (
form_data.CODE_EXECUTION_JUPYTER_TIMEOUT
)
request.app.state.config.ENABLE_CODE_INTERPRETER = form_data.ENABLE_CODE_INTERPRETER
request.app.state.config.CODE_INTERPRETER_ENGINE = form_data.CODE_INTERPRETER_ENGINE
request.app.state.config.CODE_INTERPRETER_PROMPT_TEMPLATE = (
form_data.CODE_INTERPRETER_PROMPT_TEMPLATE
)
request.app.state.config.CODE_INTERPRETER_JUPYTER_URL = (
form_data.CODE_INTERPRETER_JUPYTER_URL
)
request.app.state.config.CODE_INTERPRETER_JUPYTER_AUTH = (
form_data.CODE_INTERPRETER_JUPYTER_AUTH
)
request.app.state.config.CODE_INTERPRETER_JUPYTER_AUTH_TOKEN = (
form_data.CODE_INTERPRETER_JUPYTER_AUTH_TOKEN
)
request.app.state.config.CODE_INTERPRETER_JUPYTER_AUTH_PASSWORD = (
form_data.CODE_INTERPRETER_JUPYTER_AUTH_PASSWORD
)
request.app.state.config.CODE_INTERPRETER_JUPYTER_TIMEOUT = (
form_data.CODE_INTERPRETER_JUPYTER_TIMEOUT
)
return {
"ENABLE_CODE_EXECUTION": request.app.state.config.ENABLE_CODE_EXECUTION,
"CODE_EXECUTION_ENGINE": request.app.state.config.CODE_EXECUTION_ENGINE,
"CODE_EXECUTION_JUPYTER_URL": request.app.state.config.CODE_EXECUTION_JUPYTER_URL,
"CODE_EXECUTION_JUPYTER_AUTH": request.app.state.config.CODE_EXECUTION_JUPYTER_AUTH,
"CODE_EXECUTION_JUPYTER_AUTH_TOKEN": request.app.state.config.CODE_EXECUTION_JUPYTER_AUTH_TOKEN,
"CODE_EXECUTION_JUPYTER_AUTH_PASSWORD": request.app.state.config.CODE_EXECUTION_JUPYTER_AUTH_PASSWORD,
"CODE_EXECUTION_JUPYTER_TIMEOUT": request.app.state.config.CODE_EXECUTION_JUPYTER_TIMEOUT,
"ENABLE_CODE_INTERPRETER": request.app.state.config.ENABLE_CODE_INTERPRETER,
"CODE_INTERPRETER_ENGINE": request.app.state.config.CODE_INTERPRETER_ENGINE,
"CODE_INTERPRETER_PROMPT_TEMPLATE": request.app.state.config.CODE_INTERPRETER_PROMPT_TEMPLATE,
"CODE_INTERPRETER_JUPYTER_URL": request.app.state.config.CODE_INTERPRETER_JUPYTER_URL,
"CODE_INTERPRETER_JUPYTER_AUTH": request.app.state.config.CODE_INTERPRETER_JUPYTER_AUTH,
"CODE_INTERPRETER_JUPYTER_AUTH_TOKEN": request.app.state.config.CODE_INTERPRETER_JUPYTER_AUTH_TOKEN,
"CODE_INTERPRETER_JUPYTER_AUTH_PASSWORD": request.app.state.config.CODE_INTERPRETER_JUPYTER_AUTH_PASSWORD,
"CODE_INTERPRETER_JUPYTER_TIMEOUT": request.app.state.config.CODE_INTERPRETER_JUPYTER_TIMEOUT,
}
############################
# SetDefaultModels
############################
+33 -16
View File
@@ -56,19 +56,35 @@ async def update_config(
}
class UserResponse(BaseModel):
id: str
name: str
email: str
role: str = "pending"
last_active_at: int # timestamp in epoch
updated_at: int # timestamp in epoch
created_at: int # timestamp in epoch
class FeedbackUserResponse(FeedbackResponse):
user: Optional[UserModel] = None
user: Optional[UserResponse] = None
@router.get("/feedbacks/all", response_model=list[FeedbackUserResponse])
async def get_all_feedbacks(user=Depends(get_admin_user)):
feedbacks = Feedbacks.get_all_feedbacks()
return [
FeedbackUserResponse(
**feedback.model_dump(), user=Users.get_user_by_id(feedback.user_id)
feedback_list = []
for feedback in feedbacks:
user = Users.get_user_by_id(feedback.user_id)
feedback_list.append(
FeedbackUserResponse(
**feedback.model_dump(),
user=UserResponse(**user.model_dump()) if user else None,
)
)
for feedback in feedbacks
]
return feedback_list
@router.delete("/feedbacks/all")
@@ -80,12 +96,7 @@ async def delete_all_feedbacks(user=Depends(get_admin_user)):
@router.get("/feedbacks/all/export", response_model=list[FeedbackModel])
async def get_all_feedbacks(user=Depends(get_admin_user)):
feedbacks = Feedbacks.get_all_feedbacks()
return [
FeedbackModel(
**feedback.model_dump(), user=Users.get_user_by_id(feedback.user_id)
)
for feedback in feedbacks
]
return feedbacks
@router.get("/feedbacks/user", response_model=list[FeedbackUserResponse])
@@ -118,7 +129,10 @@ async def create_feedback(
@router.get("/feedback/{id}", response_model=FeedbackModel)
async def get_feedback_by_id(id: str, user=Depends(get_verified_user)):
feedback = Feedbacks.get_feedback_by_id_and_user_id(id=id, user_id=user.id)
if user.role == "admin":
feedback = Feedbacks.get_feedback_by_id(id=id)
else:
feedback = Feedbacks.get_feedback_by_id_and_user_id(id=id, user_id=user.id)
if not feedback:
raise HTTPException(
@@ -132,9 +146,12 @@ async def get_feedback_by_id(id: str, user=Depends(get_verified_user)):
async def update_feedback_by_id(
id: str, form_data: FeedbackForm, user=Depends(get_verified_user)
):
feedback = Feedbacks.update_feedback_by_id_and_user_id(
id=id, user_id=user.id, form_data=form_data
)
if user.role == "admin":
feedback = Feedbacks.update_feedback_by_id(id=id, form_data=form_data)
else:
feedback = Feedbacks.update_feedback_by_id_and_user_id(
id=id, user_id=user.id, form_data=form_data
)
if not feedback:
raise HTTPException(
+313 -53
View File
@@ -1,32 +1,43 @@
import logging
import os
import uuid
import json
from fnmatch import fnmatch
from pathlib import Path
from typing import Optional
from pydantic import BaseModel
import mimetypes
from urllib.parse import quote
from open_webui.storage.provider import Storage
from fastapi import (
APIRouter,
Depends,
File,
Form,
HTTPException,
Request,
UploadFile,
status,
Query,
)
from fastapi.responses import FileResponse, StreamingResponse
from open_webui.constants import ERROR_MESSAGES
from open_webui.env import SRC_LOG_LEVELS
from open_webui.retrieval.vector.factory import VECTOR_DB_CLIENT
from open_webui.models.users import Users
from open_webui.models.files import (
FileForm,
FileModel,
FileModelResponse,
Files,
)
from open_webui.routers.retrieval import process_file, ProcessFileForm
from open_webui.config import UPLOAD_DIR
from open_webui.env import SRC_LOG_LEVELS
from open_webui.constants import ERROR_MESSAGES
from fastapi import APIRouter, Depends, File, HTTPException, UploadFile, status, Request
from fastapi.responses import FileResponse, StreamingResponse
from open_webui.models.knowledge import Knowledges
from open_webui.routers.knowledge import get_knowledge, get_knowledge_list
from open_webui.routers.retrieval import ProcessFileForm, process_file
from open_webui.routers.audio import transcribe
from open_webui.storage.provider import Storage
from open_webui.utils.auth import get_admin_user, get_verified_user
from pydantic import BaseModel
log = logging.getLogger(__name__)
log.setLevel(SRC_LOG_LEVELS["MODELS"])
@@ -34,6 +45,39 @@ log.setLevel(SRC_LOG_LEVELS["MODELS"])
router = APIRouter()
############################
# Check if the current user has access to a file through any knowledge bases the user may be in.
############################
def has_access_to_file(
file_id: Optional[str], access_type: str, user=Depends(get_verified_user)
) -> bool:
file = Files.get_file_by_id(file_id)
log.debug(f"Checking if user has {access_type} access to file")
if not file:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=ERROR_MESSAGES.NOT_FOUND,
)
has_access = False
knowledge_base_id = file.meta.get("collection_name") if file.meta else None
if knowledge_base_id:
knowledge_bases = Knowledges.get_knowledge_bases_by_user_id(
user.id, access_type
)
for knowledge_base in knowledge_bases:
if knowledge_base.id == knowledge_base_id:
has_access = True
break
return has_access
############################
# Upload File
############################
@@ -41,18 +85,57 @@ router = APIRouter()
@router.post("/", response_model=FileModelResponse)
def upload_file(
request: Request, file: UploadFile = File(...), user=Depends(get_verified_user)
request: Request,
file: UploadFile = File(...),
metadata: Optional[dict | str] = Form(None),
process: bool = Query(True),
internal: bool = False,
user=Depends(get_verified_user),
):
log.info(f"file.content_type: {file.content_type}")
if isinstance(metadata, str):
try:
metadata = json.loads(metadata)
except json.JSONDecodeError:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=ERROR_MESSAGES.DEFAULT("Invalid metadata format"),
)
file_metadata = metadata if metadata else {}
try:
unsanitized_filename = file.filename
filename = os.path.basename(unsanitized_filename)
file_extension = os.path.splitext(filename)[1]
# Remove the leading dot from the file extension
file_extension = file_extension[1:] if file_extension else ""
if (not internal) and request.app.state.config.ALLOWED_FILE_EXTENSIONS:
request.app.state.config.ALLOWED_FILE_EXTENSIONS = [
ext for ext in request.app.state.config.ALLOWED_FILE_EXTENSIONS if ext
]
if file_extension not in request.app.state.config.ALLOWED_FILE_EXTENSIONS:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=ERROR_MESSAGES.DEFAULT(
f"File type {file_extension} is not allowed"
),
)
# replace filename with uuid
id = str(uuid.uuid4())
name = filename
filename = f"{id}_{filename}"
contents, file_path = Storage.upload_file(file.file, filename)
tags = {
"OpenWebUI-User-Email": user.email,
"OpenWebUI-User-Id": user.id,
"OpenWebUI-User-Name": user.name,
"OpenWebUI-File-Id": id,
}
contents, file_path = Storage.upload_file(file.file, filename, tags)
file_item = Files.insert_new_file(
user.id,
@@ -65,23 +148,55 @@ def upload_file(
"name": name,
"content_type": file.content_type,
"size": len(contents),
"data": file_metadata,
},
}
),
)
if process:
try:
if file.content_type:
stt_supported_content_types = getattr(
request.app.state.config, "STT_SUPPORTED_CONTENT_TYPES", []
)
try:
process_file(request, ProcessFileForm(file_id=id))
file_item = Files.get_file_by_id(id=id)
except Exception as e:
log.exception(e)
log.error(f"Error processing file: {file_item.id}")
file_item = FileModelResponse(
**{
**file_item.model_dump(),
"error": str(e.detail) if hasattr(e, "detail") else str(e),
}
)
if any(
fnmatch(file.content_type, content_type)
for content_type in (
stt_supported_content_types
if stt_supported_content_types
and any(t.strip() for t in stt_supported_content_types)
else ["audio/*", "video/webm"]
)
):
file_path = Storage.get_file(file_path)
result = transcribe(request, file_path, file_metadata)
process_file(
request,
ProcessFileForm(file_id=id, content=result.get("text", "")),
user=user,
)
elif (not file.content_type.startswith(("image/", "video/"))) or (
request.app.state.config.CONTENT_EXTRACTION_ENGINE == "external"
):
process_file(request, ProcessFileForm(file_id=id), user=user)
else:
log.info(
f"File type {file.content_type} is not provided, but trying to process anyway"
)
process_file(request, ProcessFileForm(file_id=id), user=user)
file_item = Files.get_file_by_id(id=id)
except Exception as e:
log.exception(e)
log.error(f"Error processing file: {file_item.id}")
file_item = FileModelResponse(
**{
**file_item.model_dump(),
"error": str(e.detail) if hasattr(e, "detail") else str(e),
}
)
if file_item:
return file_item
@@ -95,7 +210,7 @@ def upload_file(
log.exception(e)
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=ERROR_MESSAGES.DEFAULT(e),
detail=ERROR_MESSAGES.DEFAULT("Error uploading file"),
)
@@ -105,14 +220,62 @@ def upload_file(
@router.get("/", response_model=list[FileModelResponse])
async def list_files(user=Depends(get_verified_user)):
async def list_files(user=Depends(get_verified_user), content: bool = Query(True)):
if user.role == "admin":
files = Files.get_files()
else:
files = Files.get_files_by_user_id(user.id)
if not content:
for file in files:
if "content" in file.data:
del file.data["content"]
return files
############################
# Search Files
############################
@router.get("/search", response_model=list[FileModelResponse])
async def search_files(
filename: str = Query(
...,
description="Filename pattern to search for. Supports wildcards such as '*.txt'",
),
content: bool = Query(True),
user=Depends(get_verified_user),
):
"""
Search for files by filename with support for wildcard patterns.
"""
# Get files according to user role
if user.role == "admin":
files = Files.get_files()
else:
files = Files.get_files_by_user_id(user.id)
# Get matching files
matching_files = [
file for file in files if fnmatch(file.filename.lower(), filename.lower())
]
if not matching_files:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="No files found matching the pattern.",
)
if not content:
for file in matching_files:
if "content" in file.data:
del file.data["content"]
return matching_files
############################
# Delete All Files
############################
@@ -124,9 +287,10 @@ async def delete_all_files(user=Depends(get_admin_user)):
if result:
try:
Storage.delete_all_files()
VECTOR_DB_CLIENT.reset()
except Exception as e:
log.exception(e)
log.error(f"Error deleting files")
log.error("Error deleting files")
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=ERROR_MESSAGES.DEFAULT("Error deleting files"),
@@ -148,7 +312,17 @@ async def delete_all_files(user=Depends(get_admin_user)):
async def get_file_by_id(id: str, user=Depends(get_verified_user)):
file = Files.get_file_by_id(id)
if file and (file.user_id == user.id or user.role == "admin"):
if not file:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=ERROR_MESSAGES.NOT_FOUND,
)
if (
file.user_id == user.id
or user.role == "admin"
or has_access_to_file(id, "read", user)
):
return file
else:
raise HTTPException(
@@ -166,7 +340,17 @@ async def get_file_by_id(id: str, user=Depends(get_verified_user)):
async def get_file_data_content_by_id(id: str, user=Depends(get_verified_user)):
file = Files.get_file_by_id(id)
if file and (file.user_id == user.id or user.role == "admin"):
if not file:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=ERROR_MESSAGES.NOT_FOUND,
)
if (
file.user_id == user.id
or user.role == "admin"
or has_access_to_file(id, "read", user)
):
return {"content": file.data.get("content", "")}
else:
raise HTTPException(
@@ -190,10 +374,22 @@ async def update_file_data_content_by_id(
):
file = Files.get_file_by_id(id)
if file and (file.user_id == user.id or user.role == "admin"):
if not file:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=ERROR_MESSAGES.NOT_FOUND,
)
if (
file.user_id == user.id
or user.role == "admin"
or has_access_to_file(id, "write", user)
):
try:
process_file(
request, ProcessFileForm(file_id=id, content=form_data.content)
request,
ProcessFileForm(file_id=id, content=form_data.content),
user=user,
)
file = Files.get_file_by_id(id=id)
except Exception as e:
@@ -214,9 +410,22 @@ async def update_file_data_content_by_id(
@router.get("/{id}/content")
async def get_file_content_by_id(id: str, user=Depends(get_verified_user)):
async def get_file_content_by_id(
id: str, user=Depends(get_verified_user), attachment: bool = Query(False)
):
file = Files.get_file_by_id(id)
if file and (file.user_id == user.id or user.role == "admin"):
if not file:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=ERROR_MESSAGES.NOT_FOUND,
)
if (
file.user_id == user.id
or user.role == "admin"
or has_access_to_file(id, "read", user)
):
try:
file_path = Storage.get_file(file.path)
file_path = Path(file_path)
@@ -227,17 +436,29 @@ async def get_file_content_by_id(id: str, user=Depends(get_verified_user)):
filename = file.meta.get("name", file.filename)
encoded_filename = quote(filename) # RFC5987 encoding
content_type = file.meta.get("content_type")
filename = file.meta.get("name", file.filename)
encoded_filename = quote(filename)
headers = {}
if file.meta.get("content_type") not in [
"application/pdf",
"text/plain",
]:
headers = {
**headers,
"Content-Disposition": f"attachment; filename*=UTF-8''{encoded_filename}",
}
return FileResponse(file_path, headers=headers)
if attachment:
headers["Content-Disposition"] = (
f"attachment; filename*=UTF-8''{encoded_filename}"
)
else:
if content_type == "application/pdf" or filename.lower().endswith(
".pdf"
):
headers["Content-Disposition"] = (
f"inline; filename*=UTF-8''{encoded_filename}"
)
content_type = "application/pdf"
elif content_type != "text/plain":
headers["Content-Disposition"] = (
f"attachment; filename*=UTF-8''{encoded_filename}"
)
return FileResponse(file_path, headers=headers, media_type=content_type)
else:
raise HTTPException(
@@ -246,7 +467,7 @@ async def get_file_content_by_id(id: str, user=Depends(get_verified_user)):
)
except Exception as e:
log.exception(e)
log.error(f"Error getting file content")
log.error("Error getting file content")
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=ERROR_MESSAGES.DEFAULT("Error getting file content"),
@@ -261,14 +482,32 @@ async def get_file_content_by_id(id: str, user=Depends(get_verified_user)):
@router.get("/{id}/content/html")
async def get_html_file_content_by_id(id: str, user=Depends(get_verified_user)):
file = Files.get_file_by_id(id)
if file and (file.user_id == user.id or user.role == "admin"):
if not file:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=ERROR_MESSAGES.NOT_FOUND,
)
file_user = Users.get_user_by_id(file.user_id)
if not file_user.role == "admin":
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=ERROR_MESSAGES.NOT_FOUND,
)
if (
file.user_id == user.id
or user.role == "admin"
or has_access_to_file(id, "read", user)
):
try:
file_path = Storage.get_file(file.path)
file_path = Path(file_path)
# Check if the file already exists in the cache
if file_path.is_file():
print(f"file_path: {file_path}")
log.info(f"file_path: {file_path}")
return FileResponse(file_path)
else:
raise HTTPException(
@@ -277,7 +516,7 @@ async def get_html_file_content_by_id(id: str, user=Depends(get_verified_user)):
)
except Exception as e:
log.exception(e)
log.error(f"Error getting file content")
log.error("Error getting file content")
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=ERROR_MESSAGES.DEFAULT("Error getting file content"),
@@ -293,7 +532,17 @@ async def get_html_file_content_by_id(id: str, user=Depends(get_verified_user)):
async def get_file_content_by_id(id: str, user=Depends(get_verified_user)):
file = Files.get_file_by_id(id)
if file and (file.user_id == user.id or user.role == "admin"):
if not file:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=ERROR_MESSAGES.NOT_FOUND,
)
if (
file.user_id == user.id
or user.role == "admin"
or has_access_to_file(id, "read", user)
):
file_path = file.path
# Handle Unicode filenames
@@ -344,16 +593,27 @@ async def get_file_content_by_id(id: str, user=Depends(get_verified_user)):
@router.delete("/{id}")
async def delete_file_by_id(id: str, user=Depends(get_verified_user)):
file = Files.get_file_by_id(id)
if file and (file.user_id == user.id or user.role == "admin"):
# We should add Chroma cleanup here
if not file:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=ERROR_MESSAGES.NOT_FOUND,
)
if (
file.user_id == user.id
or user.role == "admin"
or has_access_to_file(id, "write", user)
):
result = Files.delete_file_by_id(id)
if result:
try:
Storage.delete_file(file.path)
VECTOR_DB_CLIENT.delete(collection_name=f"file-{id}")
except Exception as e:
log.exception(e)
log.error(f"Error deleting files")
log.error("Error deleting files")
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=ERROR_MESSAGES.DEFAULT("Error deleting files"),
+25 -13
View File
@@ -20,11 +20,13 @@ from open_webui.env import SRC_LOG_LEVELS
from open_webui.constants import ERROR_MESSAGES
from fastapi import APIRouter, Depends, File, HTTPException, UploadFile, status
from fastapi import APIRouter, Depends, File, HTTPException, UploadFile, status, Request
from fastapi.responses import FileResponse, StreamingResponse
from open_webui.utils.auth import get_admin_user, get_verified_user
from open_webui.utils.access_control import has_permission
log = logging.getLogger(__name__)
log.setLevel(SRC_LOG_LEVELS["MODELS"])
@@ -47,7 +49,7 @@ async def get_folders(user=Depends(get_verified_user)):
**folder.model_dump(),
"items": {
"chats": [
{"title": chat.title, "id": chat.id}
{"title": chat.title, "id": chat.id, "updated_at": chat.updated_at}
for chat in Chats.get_chats_by_folder_id_and_user_id(
folder.id, user.id
)
@@ -76,7 +78,7 @@ def create_folder(form_data: FolderForm, user=Depends(get_verified_user)):
)
try:
folder = Folders.insert_new_folder(user.id, form_data.name)
folder = Folders.insert_new_folder(user.id, form_data)
return folder
except Exception as e:
log.exception(e)
@@ -118,16 +120,14 @@ async def update_folder_name_by_id(
existing_folder = Folders.get_folder_by_parent_id_and_user_id_and_name(
folder.parent_id, user.id, form_data.name
)
if existing_folder:
if existing_folder and existing_folder.id != id:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=ERROR_MESSAGES.DEFAULT("Folder already exists"),
)
try:
folder = Folders.update_folder_name_by_id_and_user_id(
id, user.id, form_data.name
)
folder = Folders.update_folder_by_id_and_user_id(id, user.id, form_data)
return folder
except Exception as e:
@@ -228,15 +228,27 @@ async def update_folder_is_expanded_by_id(
@router.delete("/{id}")
async def delete_folder_by_id(id: str, user=Depends(get_verified_user)):
async def delete_folder_by_id(
request: Request, id: str, user=Depends(get_verified_user)
):
chat_delete_permission = has_permission(
user.id, "chat.delete", request.app.state.config.USER_PERMISSIONS
)
if user.role != "admin" and not chat_delete_permission:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail=ERROR_MESSAGES.ACCESS_PROHIBITED,
)
folder = Folders.get_folder_by_id_and_user_id(id, user.id)
if folder:
try:
result = Folders.delete_folder_by_id_and_user_id(id, user.id)
if result:
return result
else:
raise Exception("Error deleting folder")
folder_ids = Folders.delete_folder_by_id_and_user_id(id, user.id)
for folder_id in folder_ids:
Chats.delete_chats_by_user_id_and_folder_id(user.id, folder_id)
return True
except Exception as e:
log.exception(e)
log.error(f"Error deleting folder: {id}")
+138 -26
View File
@@ -1,4 +1,8 @@
import os
import re
import logging
import aiohttp
from pathlib import Path
from typing import Optional
@@ -8,11 +12,22 @@ from open_webui.models.functions import (
FunctionResponse,
Functions,
)
from open_webui.utils.plugin import load_function_module_by_id, replace_imports
from open_webui.utils.plugin import (
load_function_module_by_id,
replace_imports,
get_function_module_from_cache,
)
from open_webui.config import CACHE_DIR
from open_webui.constants import ERROR_MESSAGES
from fastapi import APIRouter, Depends, HTTPException, Request, status
from open_webui.utils.auth import get_admin_user, get_verified_user
from open_webui.env import SRC_LOG_LEVELS
from pydantic import BaseModel, HttpUrl
log = logging.getLogger(__name__)
log.setLevel(SRC_LOG_LEVELS["MAIN"])
router = APIRouter()
@@ -36,6 +51,111 @@ async def get_functions(user=Depends(get_admin_user)):
return Functions.get_functions()
############################
# LoadFunctionFromLink
############################
class LoadUrlForm(BaseModel):
url: HttpUrl
def github_url_to_raw_url(url: str) -> str:
# Handle 'tree' (folder) URLs (add main.py at the end)
m1 = re.match(r"https://github\.com/([^/]+)/([^/]+)/tree/([^/]+)/(.*)", url)
if m1:
org, repo, branch, path = m1.groups()
return f"https://raw.githubusercontent.com/{org}/{repo}/refs/heads/{branch}/{path.rstrip('/')}/main.py"
# Handle 'blob' (file) URLs
m2 = re.match(r"https://github\.com/([^/]+)/([^/]+)/blob/([^/]+)/(.*)", url)
if m2:
org, repo, branch, path = m2.groups()
return (
f"https://raw.githubusercontent.com/{org}/{repo}/refs/heads/{branch}/{path}"
)
# No match; return as-is
return url
@router.post("/load/url", response_model=Optional[dict])
async def load_function_from_url(
request: Request, form_data: LoadUrlForm, user=Depends(get_admin_user)
):
# NOTE: This is NOT a SSRF vulnerability:
# This endpoint is admin-only (see get_admin_user), meant for *trusted* internal use,
# and does NOT accept untrusted user input. Access is enforced by authentication.
url = str(form_data.url)
if not url:
raise HTTPException(status_code=400, detail="Please enter a valid URL")
url = github_url_to_raw_url(url)
url_parts = url.rstrip("/").split("/")
file_name = url_parts[-1]
function_name = (
file_name[:-3]
if (
file_name.endswith(".py")
and (not file_name.startswith(("main.py", "index.py", "__init__.py")))
)
else url_parts[-2] if len(url_parts) > 1 else "function"
)
try:
async with aiohttp.ClientSession(trust_env=True) as session:
async with session.get(
url, headers={"Content-Type": "application/json"}
) as resp:
if resp.status != 200:
raise HTTPException(
status_code=resp.status, detail="Failed to fetch the function"
)
data = await resp.text()
if not data:
raise HTTPException(
status_code=400, detail="No data received from the URL"
)
return {
"name": function_name,
"content": data,
}
except Exception as e:
raise HTTPException(status_code=500, detail=f"Error importing function: {e}")
############################
# SyncFunctions
############################
class SyncFunctionsForm(BaseModel):
functions: list[FunctionModel] = []
@router.post("/sync", response_model=list[FunctionModel])
async def sync_functions(
request: Request, form_data: SyncFunctionsForm, user=Depends(get_admin_user)
):
try:
for function in form_data.functions:
function.content = replace_imports(function.content)
function_module, function_type, frontmatter = load_function_module_by_id(
function.id,
content=function.content,
)
return Functions.sync_functions(user.id, form_data.functions)
except Exception as e:
log.exception(f"Failed to load a function: {e}")
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=ERROR_MESSAGES.DEFAULT(e),
)
############################
# CreateNewFunction
############################
@@ -68,7 +188,7 @@ async def create_new_function(
function = Functions.insert_new_function(user.id, function_type, form_data)
function_cache_dir = Path(CACHE_DIR) / "functions" / form_data.id
function_cache_dir = CACHE_DIR / "functions" / form_data.id
function_cache_dir.mkdir(parents=True, exist_ok=True)
if function:
@@ -79,7 +199,7 @@ async def create_new_function(
detail=ERROR_MESSAGES.DEFAULT("Error creating function"),
)
except Exception as e:
print(e)
log.exception(f"Failed to create a new function: {e}")
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=ERROR_MESSAGES.DEFAULT(e),
@@ -183,7 +303,7 @@ async def update_function_by_id(
FUNCTIONS[id] = function_module
updated = {**form_data.model_dump(exclude={"id"}), "type": function_type}
print(updated)
log.debug(updated)
function = Functions.update_function_by_id(id, updated)
@@ -256,11 +376,9 @@ async def get_function_valves_spec_by_id(
):
function = Functions.get_function_by_id(id)
if function:
if id in request.app.state.FUNCTIONS:
function_module = request.app.state.FUNCTIONS[id]
else:
function_module, function_type, frontmatter = load_function_module_by_id(id)
request.app.state.FUNCTIONS[id] = function_module
function_module, function_type, frontmatter = get_function_module_from_cache(
request, id
)
if hasattr(function_module, "Valves"):
Valves = function_module.Valves
@@ -284,11 +402,9 @@ async def update_function_valves_by_id(
):
function = Functions.get_function_by_id(id)
if function:
if id in request.app.state.FUNCTIONS:
function_module = request.app.state.FUNCTIONS[id]
else:
function_module, function_type, frontmatter = load_function_module_by_id(id)
request.app.state.FUNCTIONS[id] = function_module
function_module, function_type, frontmatter = get_function_module_from_cache(
request, id
)
if hasattr(function_module, "Valves"):
Valves = function_module.Valves
@@ -299,7 +415,7 @@ async def update_function_valves_by_id(
Functions.update_function_valves_by_id(id, valves.model_dump())
return valves.model_dump()
except Exception as e:
print(e)
log.exception(f"Error updating function values by id {id}: {e}")
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=ERROR_MESSAGES.DEFAULT(e),
@@ -347,11 +463,9 @@ async def get_function_user_valves_spec_by_id(
):
function = Functions.get_function_by_id(id)
if function:
if id in request.app.state.FUNCTIONS:
function_module = request.app.state.FUNCTIONS[id]
else:
function_module, function_type, frontmatter = load_function_module_by_id(id)
request.app.state.FUNCTIONS[id] = function_module
function_module, function_type, frontmatter = get_function_module_from_cache(
request, id
)
if hasattr(function_module, "UserValves"):
UserValves = function_module.UserValves
@@ -371,11 +485,9 @@ async def update_function_user_valves_by_id(
function = Functions.get_function_by_id(id)
if function:
if id in request.app.state.FUNCTIONS:
function_module = request.app.state.FUNCTIONS[id]
else:
function_module, function_type, frontmatter = load_function_module_by_id(id)
request.app.state.FUNCTIONS[id] = function_module
function_module, function_type, frontmatter = get_function_module_from_cache(
request, id
)
if hasattr(function_module, "UserValves"):
UserValves = function_module.UserValves
@@ -388,7 +500,7 @@ async def update_function_user_valves_by_id(
)
return user_valves.model_dump()
except Exception as e:
print(e)
log.exception(f"Error updating function user valves by id {id}: {e}")
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=ERROR_MESSAGES.DEFAULT(e),
+62 -5
View File
@@ -1,7 +1,7 @@
import os
from pathlib import Path
from typing import Optional
import logging
from open_webui.models.users import Users
from open_webui.models.groups import (
@@ -9,12 +9,19 @@ from open_webui.models.groups import (
GroupForm,
GroupUpdateForm,
GroupResponse,
UserIdsForm,
)
from open_webui.config import CACHE_DIR
from open_webui.constants import ERROR_MESSAGES
from fastapi import APIRouter, Depends, HTTPException, Request, status
from open_webui.utils.auth import get_admin_user, get_verified_user
from open_webui.env import SRC_LOG_LEVELS
log = logging.getLogger(__name__)
log.setLevel(SRC_LOG_LEVELS["MAIN"])
router = APIRouter()
@@ -37,7 +44,7 @@ async def get_groups(user=Depends(get_verified_user)):
@router.post("/create", response_model=Optional[GroupResponse])
async def create_new_function(form_data: GroupForm, user=Depends(get_admin_user)):
async def create_new_group(form_data: GroupForm, user=Depends(get_admin_user)):
try:
group = Groups.insert_new_group(user.id, form_data)
if group:
@@ -48,7 +55,7 @@ async def create_new_function(form_data: GroupForm, user=Depends(get_admin_user)
detail=ERROR_MESSAGES.DEFAULT("Error creating group"),
)
except Exception as e:
print(e)
log.exception(f"Error creating a new group: {e}")
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=ERROR_MESSAGES.DEFAULT(e),
@@ -94,7 +101,57 @@ async def update_group_by_id(
detail=ERROR_MESSAGES.DEFAULT("Error updating group"),
)
except Exception as e:
print(e)
log.exception(f"Error updating group {id}: {e}")
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=ERROR_MESSAGES.DEFAULT(e),
)
############################
# AddUserToGroupByUserIdAndGroupId
############################
@router.post("/id/{id}/users/add", response_model=Optional[GroupResponse])
async def add_user_to_group(
id: str, form_data: UserIdsForm, user=Depends(get_admin_user)
):
try:
if form_data.user_ids:
form_data.user_ids = Users.get_valid_user_ids(form_data.user_ids)
group = Groups.add_users_to_group(id, form_data.user_ids)
if group:
return group
else:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=ERROR_MESSAGES.DEFAULT("Error adding users to group"),
)
except Exception as e:
log.exception(f"Error adding users to group {id}: {e}")
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=ERROR_MESSAGES.DEFAULT(e),
)
@router.post("/id/{id}/users/remove", response_model=Optional[GroupResponse])
async def remove_users_from_group(
id: str, form_data: UserIdsForm, user=Depends(get_admin_user)
):
try:
group = Groups.remove_users_from_group(id, form_data.user_ids)
if group:
return group
else:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=ERROR_MESSAGES.DEFAULT("Error removing users from group"),
)
except Exception as e:
log.exception(f"Error removing users from group {id}: {e}")
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=ERROR_MESSAGES.DEFAULT(e),
@@ -118,7 +175,7 @@ async def delete_group_by_id(id: str, user=Depends(get_admin_user)):
detail=ERROR_MESSAGES.DEFAULT("Error deleting group"),
)
except Exception as e:
print(e)
log.exception(f"Error deleting group {id}: {e}")
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=ERROR_MESSAGES.DEFAULT(e),

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