From 867c179e2da462300d96500492381299b45ab69e Mon Sep 17 00:00:00 2001 From: Robin Kroonen Date: Wed, 15 May 2024 11:10:00 -0400 Subject: [PATCH 1/5] latest changes with upstream --- docker-compose.yaml | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/docker-compose.yaml b/docker-compose.yaml index 74249febd..042c73c23 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -14,7 +14,7 @@ services: args: OLLAMA_BASE_URL: '/ollama' dockerfile: Dockerfile - image: ghcr.io/open-webui/open-webui:${WEBUI_DOCKER_TAG-main} + image: ghcr.io/open-webui/open-webui:dev container_name: open-webui volumes: - open-webui:/app/backend/data @@ -25,10 +25,23 @@ services: environment: - 'OLLAMA_BASE_URL=http://ollama:11434' - 'WEBUI_SECRET_KEY=' + - 'OPENAI_API_KEY=${OPENAI_API_KEY}' + - 'LANGFUSE_PUBLIC_KEY=${LANGFUSE_PUBLIC_KEY}' + - 'LANGFUSE_SECRET_KEY=${LANGFUSE_SECRET_KEY}' extra_hosts: - host.docker.internal:host-gateway restart: unless-stopped + watchtower: + container_name: watchtower + image: containrrr/watchtower:latest + restart: unless-stopped + volumes: + - /var/run/docker.sock:/var/run/docker.sock + environment: + - WATCHTOWER_CLEANUP=true + - WATCHTOWER_POLL_INTERVAL=1800 + volumes: ollama: {} open-webui: {} From e10d029b0697253b1d15c4b603d0e9b73e452d56 Mon Sep 17 00:00:00 2001 From: Robin Kroonen Date: Sun, 19 May 2024 15:51:41 -0400 Subject: [PATCH 2/5] Merge branch 'dev' of https://github.com/kroonen/open-webui into dev --- Dockerfile | 57 ++--- backend/main.py | 5 + cypress/e2e/chat.cy.ts | 33 +++ cypress/e2e/settings.cy.ts | 8 +- src/app.css | 11 + src/lib/components/admin/AddUserModal.svelte | 7 +- .../components/admin/Settings/General.svelte | 4 +- src/lib/components/chat/MessageInput.svelte | 8 +- .../chat/Messages/ResponseMessage.svelte | 174 +++++++------- .../chat/Messages/UserMessage.svelte | 215 +++++++++++++----- .../components/chat/Settings/Account.svelte | 2 +- .../components/chat/Settings/Advanced.svelte | 2 +- .../Settings/Advanced/AdvancedParams.svelte | 4 +- src/lib/components/chat/Settings/Audio.svelte | 4 +- .../chat/Settings/Connections.svelte | 2 +- .../components/chat/Settings/General.svelte | 4 +- .../components/chat/Settings/Interface.svelte | 31 ++- src/lib/components/chat/SettingsModal.svelte | 28 ++- src/lib/components/chat/ShareChatModal.svelte | 16 +- src/lib/components/common/Modal.svelte | 4 +- src/lib/components/common/Switch.svelte | 22 ++ .../documents/Settings/General.svelte | 4 +- .../documents/Settings/QueryParams.svelte | 2 +- src/lib/components/icons/User.svelte | 11 + src/lib/components/layout/Navbar.svelte | 4 +- src/lib/components/layout/Navbar/Menu.svelte | 34 +-- src/lib/components/layout/Sidebar.svelte | 91 ++++---- .../components/layout/Sidebar/ChatMenu.svelte | 8 +- .../components/layout/Sidebar/UserMenu.svelte | 8 +- src/lib/components/workspace/Documents.svelte | 1 - src/lib/i18n/locales/ar-BH/translation.json | 9 +- src/lib/i18n/locales/bg-BG/translation.json | 9 +- src/lib/i18n/locales/bn-BD/translation.json | 9 +- src/lib/i18n/locales/ca-ES/translation.json | 9 +- src/lib/i18n/locales/de-DE/translation.json | 9 +- src/lib/i18n/locales/dg-DG/translation.json | 9 +- src/lib/i18n/locales/en-GB/translation.json | 9 +- src/lib/i18n/locales/en-US/translation.json | 9 +- src/lib/i18n/locales/es-ES/translation.json | 9 +- src/lib/i18n/locales/fa-IR/translation.json | 9 +- src/lib/i18n/locales/fi-FI/translation.json | 9 +- src/lib/i18n/locales/fr-CA/translation.json | 9 +- src/lib/i18n/locales/fr-FR/translation.json | 9 +- src/lib/i18n/locales/he-IL/translation.json | 9 +- src/lib/i18n/locales/hi-IN/translation.json | 9 +- src/lib/i18n/locales/it-IT/translation.json | 9 +- src/lib/i18n/locales/ja-JP/translation.json | 9 +- src/lib/i18n/locales/ka-GE/translation.json | 9 +- src/lib/i18n/locales/ko-KR/translation.json | 9 +- src/lib/i18n/locales/nl-NL/translation.json | 9 +- src/lib/i18n/locales/pl-PL/translation.json | 9 +- src/lib/i18n/locales/pt-BR/translation.json | 9 +- src/lib/i18n/locales/pt-PT/translation.json | 9 +- src/lib/i18n/locales/ru-RU/translation.json | 9 +- src/lib/i18n/locales/sv-SE/translation.json | 9 +- src/lib/i18n/locales/tr-TR/translation.json | 9 +- src/lib/i18n/locales/uk-UA/translation.json | 9 +- src/lib/i18n/locales/vi-VN/translation.json | 9 +- src/lib/i18n/locales/zh-CN/translation.json | 213 +++++++++-------- src/lib/i18n/locales/zh-TW/translation.json | 9 +- src/routes/(app)/+page.svelte | 2 +- src/routes/(app)/admin/+page.svelte | 2 +- src/routes/(app)/c/[id]/+page.svelte | 2 +- src/routes/modelfiles/create/+page.svelte | 27 +++ src/routes/prompts/create/+page.svelte | 27 +++ 65 files changed, 767 insertions(+), 571 deletions(-) create mode 100644 src/lib/components/common/Switch.svelte create mode 100644 src/lib/components/icons/User.svelte create mode 100644 src/routes/modelfiles/create/+page.svelte create mode 100644 src/routes/prompts/create/+page.svelte diff --git a/Dockerfile b/Dockerfile index e8ac47c8e..a5cc2bb39 100644 --- a/Dockerfile +++ b/Dockerfile @@ -80,25 +80,25 @@ RUN mkdir -p $HOME/.cache/chroma RUN echo -n 00000000-0000-0000-0000-000000000000 > $HOME/.cache/chroma/telemetry_user_id RUN if [ "$USE_OLLAMA" = "true" ]; then \ - apt-get update && \ - # Install pandoc and netcat - apt-get install -y --no-install-recommends pandoc netcat-openbsd curl && \ - # for RAG OCR - apt-get install -y --no-install-recommends ffmpeg libsm6 libxext6 && \ - # install helper tools - apt-get install -y --no-install-recommends curl && \ - # install ollama - curl -fsSL https://ollama.com/install.sh | sh && \ - # cleanup - rm -rf /var/lib/apt/lists/*; \ + apt-get update && \ + # Install pandoc and netcat + apt-get install -y --no-install-recommends pandoc netcat-openbsd curl && \ + # for RAG OCR + apt-get install -y --no-install-recommends ffmpeg libsm6 libxext6 && \ + # install helper tools + apt-get install -y --no-install-recommends curl jq && \ + # install ollama + curl -fsSL https://ollama.com/install.sh | sh && \ + # cleanup + rm -rf /var/lib/apt/lists/*; \ else \ - apt-get update && \ - # Install pandoc and netcat - apt-get install -y --no-install-recommends pandoc netcat-openbsd curl && \ - # for RAG OCR - apt-get install -y --no-install-recommends ffmpeg libsm6 libxext6 && \ - # cleanup - rm -rf /var/lib/apt/lists/*; \ + apt-get update && \ + # Install pandoc and netcat + apt-get install -y --no-install-recommends pandoc netcat-openbsd curl jq && \ + # for RAG OCR + apt-get install -y --no-install-recommends ffmpeg libsm6 libxext6 && \ + # cleanup + rm -rf /var/lib/apt/lists/*; \ fi # install python dependencies @@ -106,16 +106,16 @@ COPY ./backend/requirements.txt ./requirements.txt RUN pip3 install 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 && \ - uv pip install --system -r requirements.txt --no-cache-dir && \ - python -c "import os; from sentence_transformers import SentenceTransformer; SentenceTransformer(os.environ['RAG_EMBEDDING_MODEL'], device='cpu')" && \ - python -c "import os; from faster_whisper import WhisperModel; WhisperModel(os.environ['WHISPER_MODEL'], device='cpu', compute_type='int8', download_root=os.environ['WHISPER_MODEL_DIR'])"; \ + # 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 && \ + uv pip install --system -r requirements.txt --no-cache-dir && \ + python -c "import os; from sentence_transformers import SentenceTransformer; SentenceTransformer(os.environ['RAG_EMBEDDING_MODEL'], device='cpu')" && \ + python -c "import os; from faster_whisper import WhisperModel; WhisperModel(os.environ['WHISPER_MODEL'], device='cpu', compute_type='int8', download_root=os.environ['WHISPER_MODEL_DIR'])"; \ else \ - pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu --no-cache-dir && \ - uv pip install --system -r requirements.txt --no-cache-dir && \ - python -c "import os; from sentence_transformers import SentenceTransformer; SentenceTransformer(os.environ['RAG_EMBEDDING_MODEL'], device='cpu')" && \ - python -c "import os; from faster_whisper import WhisperModel; WhisperModel(os.environ['WHISPER_MODEL'], device='cpu', compute_type='int8', download_root=os.environ['WHISPER_MODEL_DIR'])"; \ + pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu --no-cache-dir && \ + uv pip install --system -r requirements.txt --no-cache-dir && \ + python -c "import os; from sentence_transformers import SentenceTransformer; SentenceTransformer(os.environ['RAG_EMBEDDING_MODEL'], device='cpu')" && \ + python -c "import os; from faster_whisper import WhisperModel; WhisperModel(os.environ['WHISPER_MODEL'], device='cpu', compute_type='int8', download_root=os.environ['WHISPER_MODEL_DIR'])"; \ fi @@ -134,6 +134,7 @@ COPY ./backend . EXPOSE 8080 -HEALTHCHECK CMD curl --fail http://localhost:8080 || exit 1 +HEALTHCHECK CMD curl --silent --fail http://localhost:8080/health | jq -e '.status == true' || exit 1 + CMD [ "bash", "start.sh"] diff --git a/backend/main.py b/backend/main.py index e3031e793..d98a532b7 100644 --- a/backend/main.py +++ b/backend/main.py @@ -377,6 +377,11 @@ async def get_opensearch_xml(): return Response(content=xml_content, media_type="application/xml") +@app.get("/health") +async def healthcheck(): + return {"status": True} + + app.mount("/static", StaticFiles(directory=STATIC_DIR), name="static") app.mount("/cache", StaticFiles(directory=CACHE_DIR), name="cache") diff --git a/cypress/e2e/chat.cy.ts b/cypress/e2e/chat.cy.ts index f46bef57b..6f5fa36c9 100644 --- a/cypress/e2e/chat.cy.ts +++ b/cypress/e2e/chat.cy.ts @@ -42,5 +42,38 @@ describe('Settings', () => { .find('div[aria-label="Generation Info"]', { timeout: 120_000 }) // Generation Info is created after the stop token is received .should('exist'); }); + + it('user can share chat', () => { + // Click on the model selector + cy.get('button[aria-label="Select a model"]').click(); + // Select the first model + cy.get('button[aria-label="model-item"]').first().click(); + // Type a message + cy.get('#chat-textarea').type('Hi, what can you do? A single sentence only please.', { + force: true + }); + // Send the message + cy.get('button[type="submit"]').click(); + // User's message should be visible + cy.get('.chat-user').should('exist'); + // Wait for the response + cy.get('.chat-assistant', { timeout: 120_000 }) // .chat-assistant is created after the first token is received + .find('div[aria-label="Generation Info"]', { timeout: 120_000 }) // Generation Info is created after the stop token is received + .should('exist'); + // spy on requests + const spy = cy.spy(); + cy.intercept("GET", "/api/v1/chats/*", spy); + // Open context menu + cy.get('#chat-context-menu-button').click(); + // Click share button + cy.get('#chat-share-button').click(); + // Check if the share dialog is visible + cy.get('#copy-and-share-chat-button').should('exist'); + cy.wrap({}, { timeout: 5000 }) + .should(() => { + // Check if the request was made twice (once for to replace chat object and once more due to change event) + expect(spy).to.be.callCount(2); + }); + }); }); }); diff --git a/cypress/e2e/settings.cy.ts b/cypress/e2e/settings.cy.ts index 560ce9794..5db232faa 100644 --- a/cypress/e2e/settings.cy.ts +++ b/cypress/e2e/settings.cy.ts @@ -15,12 +15,8 @@ describe('Settings', () => { cy.loginAdmin(); // Visit the home page cy.visit('/'); - // Open the sidebar if it is not already open - cy.get('[aria-label="Open sidebar"]').then(() => { - cy.get('button[id="sidebar-toggle-button"]').click(); - }); - // Click on the profile link - cy.get('button').contains(adminUser.name).click(); + // Click on the user menu + cy.get('button[aria-label="User Menu"]').click(); // Click on the settings link cy.get('button').contains('Settings').click(); }); diff --git a/src/app.css b/src/app.css index 759570c46..f7c14bcbd 100644 --- a/src/app.css +++ b/src/app.css @@ -100,3 +100,14 @@ select { -ms-overflow-style: none; /* IE and Edge */ scrollbar-width: none; /* Firefox */ } + +input::-webkit-outer-spin-button, +input::-webkit-inner-spin-button { + /* display: none; <- Crashes Chrome on hover */ + -webkit-appearance: none; + margin: 0; /* <-- Apparently some margin are still there even though it's hidden */ +} + +input[type='number'] { + -moz-appearance: textfield; /* Firefox */ +} diff --git a/src/lib/components/admin/AddUserModal.svelte b/src/lib/components/admin/AddUserModal.svelte index 57ad9362c..a38177a75 100644 --- a/src/lib/components/admin/AddUserModal.svelte +++ b/src/lib/components/admin/AddUserModal.svelte @@ -73,13 +73,16 @@ console.log(idx, columns); if (idx > 0) { - if (columns.length === 4 && ['admin', 'user', 'pending'].includes(columns[3])) { + if ( + columns.length === 4 && + ['admin', 'user', 'pending'].includes(columns[3].toLowerCase()) + ) { const res = await addUser( localStorage.token, columns[0], columns[1], columns[2], - columns[3] + columns[3].toLowerCase() ).catch((error) => { toast.error(`Row ${idx + 1}: ${error}`); return null; diff --git a/src/lib/components/admin/Settings/General.svelte b/src/lib/components/admin/Settings/General.svelte index f93991f1e..5674916d6 100644 --- a/src/lib/components/admin/Settings/General.svelte +++ b/src/lib/components/admin/Settings/General.svelte @@ -123,7 +123,7 @@
{/if} -
+
-
+
{#if autoScroll === false && messages.length > 0} @@ -535,7 +535,7 @@
-
+
1}
{#if siblings.length > 1}
@@ -553,7 +553,7 @@ - {#if !readOnly} - - - - - - - - {/if} - + + + + + + {/if} + {#if isLastMessage && !readOnly} + +
+ {siblings.indexOf(message.id) + 1}/{siblings.length} +
+ + +
+ {/if} + {/if} {#if !readOnly} {/if} - {#if siblings.length > 1} -
- -
- {siblings.indexOf(message.id) + 1}/{siblings.length} + {#if $settings?.chatBubble ?? true} + {#if siblings.length > 1} +
+ + +
+ {siblings.indexOf(message.id) + 1}/{siblings.length} +
+ +
- - -
+ {/if} {/if}
diff --git a/src/lib/components/chat/Settings/Account.svelte b/src/lib/components/chat/Settings/Account.svelte index d27344bdb..978c1b9b6 100644 --- a/src/lib/components/chat/Settings/Account.svelte +++ b/src/lib/components/chat/Settings/Account.svelte @@ -71,7 +71,7 @@
-
+
{$i18n.t('Seed')}
{$i18n.t('Stop Sequence')}
-
+
{$i18n.t('STT Settings')}
@@ -345,7 +345,7 @@ {/if}
-
+
+
+
+
{$i18n.t('Title Auto-Generation')}
@@ -283,7 +310,7 @@ {#if $user.role === 'admin'}
-
+
{$i18n.t('Default Prompt Suggestions')} diff --git a/src/lib/components/chat/SettingsModal.svelte b/src/lib/components/chat/SettingsModal.svelte index d3403dc87..2673ec0a2 100644 --- a/src/lib/components/chat/SettingsModal.svelte +++ b/src/lib/components/chat/SettingsModal.svelte @@ -165,6 +165,32 @@
{$i18n.t('Interface')}
+ +
-
+
{#if selectedTab === 'general'} { + if (!chat) { + return true; + } + if (!_chat) { + return false; + } + return chat.id !== _chat.id || chat.share_id !== _chat.share_id; + } + $: if (show) { (async () => { if (chatId) { - chat = await getChatById(localStorage.token, chatId); + const _chat = await getChatById(localStorage.token, chatId); + if (isDifferentChat(_chat)) { + chat = _chat; + } } else { chat = null; console.log(chat); @@ -137,6 +150,7 @@ - - {/if} -
+
+ User profile +
+
{$user.name}
+ + + {/if}
- {/if} +
- +
-->