diff --git a/.github/workflows/deploy-to-hf-spaces.yml b/.github/workflows/deploy-to-hf-spaces.yml index aa8bbcfce..7fc66acf5 100644 --- a/.github/workflows/deploy-to-hf-spaces.yml +++ b/.github/workflows/deploy-to-hf-spaces.yml @@ -28,6 +28,8 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v4 + with: + lfs: true - name: Remove git history run: rm -rf .git @@ -52,7 +54,9 @@ jobs: - name: Set up Git and push to Space run: | git init --initial-branch=main + git lfs install git lfs track "*.ttf" + git lfs track "*.jpg" rm demo.gif git add . git commit -m "GitHub deploy: ${{ github.sha }}" diff --git a/CHANGELOG.md b/CHANGELOG.md index 765ca6fc8..2be2e872f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,19 @@ 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.4.1] - 2024-11-19 + +### Added + +- **📊 Enhanced Feedback System**: Introduced a detailed 1-10 rating scale for feedback alongside thumbs up/down, preparing for more precise model fine-tuning and improving feedback quality. +- **ℹ️ Tool Descriptions on Hover**: Easily access tool descriptions by hovering over the message input, providing a smoother workflow with more context when utilizing tools. + +### Fixed + +- **🗑️ Graceful Handling of Deleted Users**: Resolved an issue where deleted users caused workspace items (models, knowledge, prompts, tools) to fail, ensuring reliable workspace loading. +- **🔑 API Key Creation**: Fixed an issue preventing users from creating new API keys, restoring secure and seamless API management. +- **🔗 HTTPS Proxy Fix**: Corrected HTTPS proxy issues affecting the '/api/v1/models/' endpoint, ensuring smoother, uninterrupted model management. + ## [0.4.0] - 2024-11-19 ### Added diff --git a/backend/open_webui/apps/webui/routers/auths.py b/backend/open_webui/apps/webui/routers/auths.py index 630a8bcbf..63ee5e3b0 100644 --- a/backend/open_webui/apps/webui/routers/auths.py +++ b/backend/open_webui/apps/webui/routers/auths.py @@ -738,8 +738,8 @@ async def update_ldap_config( # create api key @router.post("/api_key", response_model=ApiKey) -async def create_api_key(request: Request, user=Depends(get_current_user)): - if not request.app.config.state.ENABLE_API_KEY: +async def generate_api_key(request: Request, user=Depends(get_current_user)): + if not request.app.state.config.ENABLE_API_KEY: raise HTTPException( status.HTTP_403_FORBIDDEN, detail=ERROR_MESSAGES.API_KEY_CREATION_NOT_ALLOWED, diff --git a/backend/open_webui/apps/webui/routers/models.py b/backend/open_webui/apps/webui/routers/models.py index 576df8d94..6a8085385 100644 --- a/backend/open_webui/apps/webui/routers/models.py +++ b/backend/open_webui/apps/webui/routers/models.py @@ -83,7 +83,8 @@ async def create_new_model( ########################### -@router.get("/id/{id}", response_model=Optional[ModelResponse]) +# Note: We're not using the typical url path param here, but instead using a query parameter to allow '/' in the id +@router.get("/model", response_model=Optional[ModelResponse]) async def get_model_by_id(id: str, user=Depends(get_verified_user)): model = Models.get_model_by_id(id) if model: @@ -105,7 +106,7 @@ async def get_model_by_id(id: str, user=Depends(get_verified_user)): ############################ -@router.post("/id/{id}/toggle", response_model=Optional[ModelResponse]) +@router.post("/model/toggle", response_model=Optional[ModelResponse]) async def toggle_model_by_id(id: str, user=Depends(get_verified_user)): model = Models.get_model_by_id(id) if model: @@ -140,7 +141,7 @@ async def toggle_model_by_id(id: str, user=Depends(get_verified_user)): ############################ -@router.post("/id/{id}/update", response_model=Optional[ModelModel]) +@router.post("/model/update", response_model=Optional[ModelModel]) async def update_model_by_id( id: str, form_data: ModelForm, @@ -163,7 +164,7 @@ async def update_model_by_id( ############################ -@router.delete("/id/{id}/delete", response_model=bool) +@router.delete("/model/delete", response_model=bool) async def delete_model_by_id(id: str, user=Depends(get_verified_user)): model = Models.get_model_by_id(id) if not model: diff --git a/package-lock.json b/package-lock.json index 66eb9c019..d2114a6ac 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "open-webui", - "version": "0.4.0", + "version": "0.4.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "open-webui", - "version": "0.4.0", + "version": "0.4.1", "dependencies": { "@codemirror/lang-javascript": "^6.2.2", "@codemirror/lang-python": "^6.1.6", diff --git a/package.json b/package.json index fbb732549..47e232773 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "open-webui", - "version": "0.4.0", + "version": "0.4.1", "private": true, "scripts": { "dev": "npm run pyodide:fetch && vite dev --host", diff --git a/src/lib/apis/models/index.ts b/src/lib/apis/models/index.ts index fdce03f84..5880874bb 100644 --- a/src/lib/apis/models/index.ts +++ b/src/lib/apis/models/index.ts @@ -3,7 +3,7 @@ import { WEBUI_API_BASE_URL } from '$lib/constants'; export const getModels = async (token: string = '') => { let error = null; - const res = await fetch(`${WEBUI_API_BASE_URL}/models`, { + const res = await fetch(`${WEBUI_API_BASE_URL}/models/`, { method: 'GET', headers: { Accept: 'application/json', @@ -97,7 +97,7 @@ export const getModelById = async (token: string, id: string) => { const searchParams = new URLSearchParams(); searchParams.append('id', id); - const res = await fetch(`${WEBUI_API_BASE_URL}/models/id/${id}`, { + const res = await fetch(`${WEBUI_API_BASE_URL}/models/model?${searchParams.toString()}`, { method: 'GET', headers: { Accept: 'application/json', @@ -132,7 +132,7 @@ export const toggleModelById = async (token: string, id: string) => { const searchParams = new URLSearchParams(); searchParams.append('id', id); - const res = await fetch(`${WEBUI_API_BASE_URL}/models/id/${id}/toggle`, { + const res = await fetch(`${WEBUI_API_BASE_URL}/models/model/toggle?${searchParams.toString()}`, { method: 'POST', headers: { Accept: 'application/json', @@ -167,7 +167,7 @@ export const updateModelById = async (token: string, id: string, model: object) const searchParams = new URLSearchParams(); searchParams.append('id', id); - const res = await fetch(`${WEBUI_API_BASE_URL}/models/id/${id}/update`, { + const res = await fetch(`${WEBUI_API_BASE_URL}/models/model/update?${searchParams.toString()}`, { method: 'POST', headers: { Accept: 'application/json', @@ -203,7 +203,7 @@ export const deleteModelById = async (token: string, id: string) => { const searchParams = new URLSearchParams(); searchParams.append('id', id); - const res = await fetch(`${WEBUI_API_BASE_URL}/models/id/${id}/delete`, { + const res = await fetch(`${WEBUI_API_BASE_URL}/models/model/delete?${searchParams.toString()}`, { method: 'DELETE', headers: { Accept: 'application/json', diff --git a/src/lib/components/chat/Chat.svelte b/src/lib/components/chat/Chat.svelte index bfc9800fe..8a1ef2d91 100644 --- a/src/lib/components/chat/Chat.svelte +++ b/src/lib/components/chat/Chat.svelte @@ -663,7 +663,8 @@ role: m.role, content: m.content, info: m.info ? m.info : undefined, - timestamp: m.timestamp + timestamp: m.timestamp, + ...(m.citations ? { citations: m.citations } : {}) })), chat_id: chatId, session_id: $socket?.id, @@ -716,7 +717,8 @@ role: m.role, content: m.content, info: m.info ? m.info : undefined, - timestamp: m.timestamp + timestamp: m.timestamp, + ...(m.citations ? { citations: m.citations } : {}) })), ...(event ? { event: event } : {}), chat_id: chatId, diff --git a/src/lib/components/chat/MessageInput.svelte b/src/lib/components/chat/MessageInput.svelte index a7ff37354..a869a1d99 100644 --- a/src/lib/components/chat/MessageInput.svelte +++ b/src/lib/components/chat/MessageInput.svelte @@ -321,12 +321,22 @@ -
- {selectedToolIds - .map((id) => { - return $tools ? $tools.find((tool) => tool.id === id)?.name : id; - }) - .join(', ')} +
+ {#each selectedToolIds.map((id) => { + return $tools ? $tools.find((t) => t.id === id) : { id: id, name: id }; + }) as tool, toolIdx (toolIdx)} + + {tool.name} + + + {#if toolIdx !== selectedToolIds.length - 1} + , + {/if} + {/each}
diff --git a/src/lib/components/chat/Messages/RateComment.svelte b/src/lib/components/chat/Messages/RateComment.svelte index 2cccf20d8..39ae17318 100644 --- a/src/lib/components/chat/Messages/RateComment.svelte +++ b/src/lib/components/chat/Messages/RateComment.svelte @@ -38,6 +38,7 @@ let selectedReason = null; let comment = ''; + let detailedRating = null; let selectedModel = null; $: if (message?.annotation?.rating === 1) { @@ -56,6 +57,7 @@ tags = (message?.annotation?.tags ?? []).map((tag) => ({ name: tag })); + detailedRating = message?.annotation?.details?.rating ?? null; }; onMount(() => { @@ -79,7 +81,10 @@ dispatch('save', { reason: selectedReason, comment: comment, - tags: tags.map((tag) => tag.name) + tags: tags.map((tag) => tag.name), + details: { + rating: detailedRating + } }); toast.success($i18n.t('Thanks for your feedback!')); @@ -100,7 +105,9 @@ id="message-feedback-{message.id}" >
-
{$i18n.t('Tell us more:')}
+
{$i18n.t('How would you rate this response?')}
+ +
- {#if reasons.length > 0} -
- {#each reasons as reason} - - {/each} +
+
+
+ + {#each Array.from({ length: 10 }).map((_, i) => i + 1) as rating} + + {/each} +
+ +
+
+ 1 - {$i18n.t('Awful')} +
+ +
+ 10 - {$i18n.t('Amazing')} +
+
- {/if} +
+ +
+ {#if reasons.length > 0} +
{$i18n.t('Why?')}
+ +
+ {#each reasons as reason} + + {/each} +
+ {/if} +