From b61bb779502b654e934e8055d34654f149bfca39 Mon Sep 17 00:00:00 2001 From: "Timothy J. Baek" Date: Thu, 28 Dec 2023 23:02:49 -0800 Subject: [PATCH 01/19] feat: delete user backend support --- backend/apps/web/models/users.py | 16 +++++++++++++++ backend/apps/web/routers/users.py | 33 +++++++++++++++++++++++++++++++ backend/constants.py | 2 ++ 3 files changed, 51 insertions(+) diff --git a/backend/apps/web/models/users.py b/backend/apps/web/models/users.py index 782b7f47..2768f20b 100644 --- a/backend/apps/web/models/users.py +++ b/backend/apps/web/models/users.py @@ -8,6 +8,8 @@ from utils.utils import decode_token from utils.misc import get_gravatar_url from apps.web.internal.db import DB +from apps.web.models.chats import Chat + #################### # User DB Schema @@ -110,5 +112,19 @@ class UsersTable: except: return None + def delete_user_by_id(self, id: str) -> bool: + try: + # Delete User Chats + query = Chat.delete().where(Chat.user_id == id) + query.execute() # Remove the rows, return number of rows removed. + + # Delete User + query = User.delete().where(User.id == id) + query.execute() # Remove the rows, return number of rows removed. + + return True + except: + return False + Users = UsersTable(DB) diff --git a/backend/apps/web/routers/users.py b/backend/apps/web/routers/users.py index 08437bd3..0206b7d7 100644 --- a/backend/apps/web/routers/users.py +++ b/backend/apps/web/routers/users.py @@ -73,3 +73,36 @@ async def update_user_role(form_data: UserRoleUpdateForm, cred=Depends(bearer_sc status_code=status.HTTP_401_UNAUTHORIZED, detail=ERROR_MESSAGES.INVALID_TOKEN, ) + + +############################ +# DeleteUser +############################ + + +@router.delete("/{user_id}", response_model=bool) +async def delete_user_by_id(user_id: str, cred=Depends(bearer_scheme)): + token = cred.credentials + user = Users.get_user_by_token(token) + + if user: + if user.role == "admin": + result = Users.delete_user_by_id(user_id) + + if result: + return True + else: + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail=ERROR_MESSAGES.DELETE_USER_ERROR, + ) + else: + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail=ERROR_MESSAGES.ACCESS_PROHIBITED, + ) + else: + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail=ERROR_MESSAGES.INVALID_TOKEN, + ) diff --git a/backend/constants.py b/backend/constants.py index 06d67eec..a068995d 100644 --- a/backend/constants.py +++ b/backend/constants.py @@ -12,6 +12,7 @@ class ERROR_MESSAGES(str, Enum): DEFAULT = lambda err="": f"Something went wrong :/\n{err if err else ''}" ENV_VAR_NOT_FOUND = "Required environment variable not found. Terminating now." CREATE_USER_ERROR = "Oops! Something went wrong while creating your account. Please try again later. If the issue persists, contact support for assistance." + DELETE_USER_ERROR = "Oops! Something went wrong. We encountered an issue while trying to delete the user. Please give it another shot." EMAIL_TAKEN = "Uh-oh! This email is already registered. Sign in with your existing account or choose another email to start anew." USERNAME_TAKEN = ( "Uh-oh! This username is already registered. Please choose another username." @@ -27,4 +28,5 @@ class ERROR_MESSAGES(str, Enum): ) NOT_FOUND = "We could not find what you're looking for :/" USER_NOT_FOUND = "We could not find what you're looking for :/" + MALICIOUS = "Unusual activities detected, please try again in a few minutes." From ad1cb5fc256b9ff1f3a2f008484a765fd8c139d4 Mon Sep 17 00:00:00 2001 From: "Timothy J. Baek" Date: Thu, 28 Dec 2023 23:07:46 -0800 Subject: [PATCH 02/19] fix: disable admin self user delete --- backend/apps/web/routers/users.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/backend/apps/web/routers/users.py b/backend/apps/web/routers/users.py index 0206b7d7..2b116828 100644 --- a/backend/apps/web/routers/users.py +++ b/backend/apps/web/routers/users.py @@ -87,14 +87,20 @@ async def delete_user_by_id(user_id: str, cred=Depends(bearer_scheme)): if user: if user.role == "admin": - result = Users.delete_user_by_id(user_id) + if user.id != user_id: + result = Users.delete_user_by_id(user_id) - if result: - return True + if result: + return True + else: + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=ERROR_MESSAGES.DELETE_USER_ERROR, + ) else: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, - detail=ERROR_MESSAGES.DELETE_USER_ERROR, + detail=ERROR_MESSAGES.ACTION_PROHIBITED, ) else: raise HTTPException( From 7fade0bb2f308741a5207ba69ba09fc368a48547 Mon Sep 17 00:00:00 2001 From: "Timothy J. Baek" Date: Thu, 28 Dec 2023 23:12:58 -0800 Subject: [PATCH 03/19] feat: delete user button added to admin page --- src/lib/apis/users/index.ts | 32 ++++++++++++++++++-- src/routes/(app)/admin/+page.svelte | 45 ++++++++++++++++++++++++----- 2 files changed, 68 insertions(+), 9 deletions(-) diff --git a/src/lib/apis/users/index.ts b/src/lib/apis/users/index.ts index b1f9e5d9..3fca8b99 100644 --- a/src/lib/apis/users/index.ts +++ b/src/lib/apis/users/index.ts @@ -45,8 +45,9 @@ export const getUsers = async (token: string) => { if (!res.ok) throw await res.json(); return res.json(); }) - .catch((error) => { - console.log(error); + .catch((err) => { + console.log(err); + error = err.detail; return null; }); @@ -56,3 +57,30 @@ export const getUsers = async (token: string) => { return res ? res : []; }; + +export const deleteUserById = async (token: string, userId: string) => { + let error = null; + + const res = await fetch(`${WEBUI_API_BASE_URL}/users/${userId}`, { + method: 'DELETE', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${token}` + } + }) + .then(async (res) => { + if (!res.ok) throw await res.json(); + return res.json(); + }) + .catch((err) => { + console.log(err); + error = err.detail; + return null; + }); + + if (error) { + throw error; + } + + return res; +}; diff --git a/src/routes/(app)/admin/+page.svelte b/src/routes/(app)/admin/+page.svelte index 13078b3c..5f5beeae 100644 --- a/src/routes/(app)/admin/+page.svelte +++ b/src/routes/(app)/admin/+page.svelte @@ -6,7 +6,7 @@ import toast from 'svelte-french-toast'; - import { updateUserRole, getUsers } from '$lib/apis/users'; + import { updateUserRole, getUsers, deleteUserById } from '$lib/apis/users'; let loaded = false; let users = []; @@ -22,6 +22,16 @@ } }; + const deleteUserHandler = async (id) => { + const res = await deleteUserById(localStorage.token, id).catch((error) => { + toast.error(error); + return null; + }); + if (res) { + users = await getUsers(localStorage.token); + } + }; + onMount(async () => { if ($user?.role !== 'admin') { await goto('/'); @@ -55,7 +65,7 @@ Name Email Role - + Action @@ -63,15 +73,16 @@
user -
{user.name}
+
{user.name}
{user.email} @@ -89,9 +100,29 @@ }}>{user.role} - + + + {/each} From 48cc2c5053f4a770a39eaf202aadf9a605696965 Mon Sep 17 00:00:00 2001 From: "Timothy J. Baek" Date: Thu, 28 Dec 2023 23:17:58 -0800 Subject: [PATCH 04/19] chore: delete user backend refac --- backend/apps/web/models/chats.py | 9 +++++++++ backend/apps/web/models/users.py | 14 ++++++++------ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/backend/apps/web/models/chats.py b/backend/apps/web/models/chats.py index 8f075e40..ebc17d9a 100644 --- a/backend/apps/web/models/chats.py +++ b/backend/apps/web/models/chats.py @@ -153,5 +153,14 @@ class ChatTable: except: return False + def delete_chats_by_user_id(self, user_id: str) -> bool: + try: + query = Chat.delete().where(Chat.user_id == user_id) + query.execute() # Remove the rows, return number of rows removed. + + return True + except: + return False + Chats = ChatTable(DB) diff --git a/backend/apps/web/models/users.py b/backend/apps/web/models/users.py index 2768f20b..4b790ab2 100644 --- a/backend/apps/web/models/users.py +++ b/backend/apps/web/models/users.py @@ -115,14 +115,16 @@ class UsersTable: def delete_user_by_id(self, id: str) -> bool: try: # Delete User Chats - query = Chat.delete().where(Chat.user_id == id) - query.execute() # Remove the rows, return number of rows removed. + result = Chat.delete_chats_by_user_id(id) - # Delete User - query = User.delete().where(User.id == id) - query.execute() # Remove the rows, return number of rows removed. + if result: + # Delete User + query = User.delete().where(User.id == id) + query.execute() # Remove the rows, return number of rows removed. - return True + return True + else: + return False except: return False From 5b4bf45ad275faa9003275877e71af0575ee2117 Mon Sep 17 00:00:00 2001 From: "Timothy J. Baek" Date: Thu, 28 Dec 2023 23:24:51 -0800 Subject: [PATCH 05/19] fix: delete auth with user --- backend/apps/web/models/auths.py | 16 ++++++++++++++++ backend/apps/web/models/users.py | 4 ++-- backend/apps/web/routers/users.py | 6 ++++-- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/backend/apps/web/models/auths.py b/backend/apps/web/models/auths.py index c066dbef..1bd4b4cb 100644 --- a/backend/apps/web/models/auths.py +++ b/backend/apps/web/models/auths.py @@ -109,5 +109,21 @@ class AuthsTable: except: return None + def delete_auth_by_id(self, id: str) -> Optional[UserModel]: + try: + # Delete User + result = Users.delete_user_by_id(id) + + if result: + # Delete Auth + query = Auth.delete().where(Auth.id == id) + query.execute() # Remove the rows, return number of rows removed. + + return True + else: + return False + except: + return False + Auths = AuthsTable(DB) diff --git a/backend/apps/web/models/users.py b/backend/apps/web/models/users.py index 4b790ab2..b7df92eb 100644 --- a/backend/apps/web/models/users.py +++ b/backend/apps/web/models/users.py @@ -8,7 +8,7 @@ from utils.utils import decode_token from utils.misc import get_gravatar_url from apps.web.internal.db import DB -from apps.web.models.chats import Chat +from apps.web.models.chats import Chats #################### @@ -115,7 +115,7 @@ class UsersTable: def delete_user_by_id(self, id: str) -> bool: try: # Delete User Chats - result = Chat.delete_chats_by_user_id(id) + result = Chats.delete_chats_by_user_id(id) if result: # Delete User diff --git a/backend/apps/web/routers/users.py b/backend/apps/web/routers/users.py index 2b116828..fd0d2d6f 100644 --- a/backend/apps/web/routers/users.py +++ b/backend/apps/web/routers/users.py @@ -9,6 +9,8 @@ import time import uuid from apps.web.models.users import UserModel, UserRoleUpdateForm, Users +from apps.web.models.auths import Auths + from utils.utils import ( get_password_hash, @@ -76,7 +78,7 @@ async def update_user_role(form_data: UserRoleUpdateForm, cred=Depends(bearer_sc ############################ -# DeleteUser +# DeleteUserById ############################ @@ -88,7 +90,7 @@ async def delete_user_by_id(user_id: str, cred=Depends(bearer_scheme)): if user: if user.role == "admin": if user.id != user_id: - result = Users.delete_user_by_id(user_id) + result = Auths.delete_auth_by_id(user_id) if result: return True From 136eb18fb0be488cf0ffadee4b65ba6bdd73c613 Mon Sep 17 00:00:00 2001 From: "Timothy J. Baek" Date: Thu, 28 Dec 2023 23:32:25 -0800 Subject: [PATCH 06/19] feat: account settings --- src/lib/components/chat/SettingsModal.svelte | 26 ++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/lib/components/chat/SettingsModal.svelte b/src/lib/components/chat/SettingsModal.svelte index 47c57d99..05dcefd1 100644 --- a/src/lib/components/chat/SettingsModal.svelte +++ b/src/lib/components/chat/SettingsModal.svelte @@ -845,6 +845,32 @@ {/if} + + + {:else if selectedTab === 'account'} +
{ + console.log('change save'); + }} + > +
Change Password
+ +
+
+
Current Password
+ +
+ +
+
+ +
+
New Password
+ +
+ +
+
+ +
+
Confirm Password
+ +
+ +
+
+
+ +
+ +
+
{:else if selectedTab === 'about'}
From d8bb19fd8ad962ec290388c6e7116bbfb1745971 Mon Sep 17 00:00:00 2001 From: "Timothy J. Baek" Date: Fri, 29 Dec 2023 00:26:47 -0800 Subject: [PATCH 08/19] feat: change password frontend added --- backend/apps/web/routers/auths.py | 12 +++++--- backend/constants.py | 3 ++ src/lib/apis/auths/index.ts | 31 ++++++++++++++++++++ src/lib/components/chat/SettingsModal.svelte | 28 +++++++++++++++++- 4 files changed, 69 insertions(+), 5 deletions(-) diff --git a/backend/apps/web/routers/auths.py b/backend/apps/web/routers/auths.py index 31b41b6d..bcbe00d5 100644 --- a/backend/apps/web/routers/auths.py +++ b/backend/apps/web/routers/auths.py @@ -62,12 +62,16 @@ async def get_session_user(cred=Depends(bearer_scheme)): @router.post("/update/password", response_model=bool) async def update_password(form_data: UpdatePasswordForm, cred=Depends(bearer_scheme)): token = cred.credentials - user = Users.get_user_by_token(token) + session_user = Users.get_user_by_token(token) - if user: - hashed = get_password_hash(form_data.new_password) - return Auths.update_user_password_by_id(user.id, form_data.password, hashed) + if session_user: + user = Auths.authenticate_user(session_user.email, form_data.password) + if user: + hashed = get_password_hash(form_data.new_password) + return Auths.update_user_password_by_id(user.id, form_data.password, hashed) + else: + raise HTTPException(400, detail=ERROR_MESSAGES.INVALID_PASSWORD) else: raise HTTPException(400, detail=ERROR_MESSAGES.INVALID_CRED) diff --git a/backend/constants.py b/backend/constants.py index a068995d..761507f2 100644 --- a/backend/constants.py +++ b/backend/constants.py @@ -21,6 +21,9 @@ class ERROR_MESSAGES(str, Enum): "Your session has expired or the token is invalid. Please sign in again." ) INVALID_CRED = "The email or password provided is incorrect. Please check for typos and try logging in again." + INVALID_PASSWORD = ( + "The password provided is incorrect. Please check for typos and try again." + ) UNAUTHORIZED = "401 Unauthorized" ACCESS_PROHIBITED = "You do not have permission to access this resource. Please contact your administrator for assistance." ACTION_PROHIBITED = ( diff --git a/src/lib/apis/auths/index.ts b/src/lib/apis/auths/index.ts index 56a4a7a6..73934055 100644 --- a/src/lib/apis/auths/index.ts +++ b/src/lib/apis/auths/index.ts @@ -88,3 +88,34 @@ export const userSignUp = async (name: string, email: string, password: string) return res; }; + +export const updateUserPassword = async (token: string, password: string, newPassword: string) => { + let error = null; + + const res = await fetch(`${WEBUI_API_BASE_URL}/auths/update/password`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + ...(token && { authorization: `Bearer ${token}` }) + }, + body: JSON.stringify({ + password: password, + new_password: newPassword + }) + }) + .then(async (res) => { + if (!res.ok) throw await res.json(); + return res.json(); + }) + .catch((err) => { + console.log(err); + error = err.detail; + return null; + }); + + if (error) { + throw error; + } + + return res; +}; diff --git a/src/lib/components/chat/SettingsModal.svelte b/src/lib/components/chat/SettingsModal.svelte index e5332296..18aa6eca 100644 --- a/src/lib/components/chat/SettingsModal.svelte +++ b/src/lib/components/chat/SettingsModal.svelte @@ -18,6 +18,7 @@ import Advanced from './Settings/Advanced.svelte'; import Modal from '../common/Modal.svelte'; + import { updateUserPassword } from '$lib/apis/auths'; export let show = false; @@ -600,6 +601,31 @@ return models; }; + const updatePasswordHandler = async () => { + if (newPassword === newPasswordConfirm) { + const res = await updateUserPassword(localStorage.token, currentPassword, newPassword).catch( + (error) => { + toast.error(error); + return null; + } + ); + + if (res) { + toast.success('Successfully updated.'); + } + + currentPassword = ''; + newPassword = ''; + newPasswordConfirm = ''; + } else { + toast.error( + `The passwords you entered don't quite match. Please double-check and try again.` + ); + newPassword = ''; + newPasswordConfirm = ''; + } + }; + onMount(async () => { let settings = JSON.parse(localStorage.getItem('settings') ?? '{}'); console.log(settings); @@ -1852,7 +1878,7 @@
{ - console.log('change save'); + updatePasswordHandler(); }} >
Change Password
From 500f61b7ee9abc528be14d91dad959c59b030765 Mon Sep 17 00:00:00 2001 From: "Timothy J. Baek" Date: Fri, 29 Dec 2023 00:29:18 -0800 Subject: [PATCH 09/19] chore: update password refac --- backend/apps/web/models/auths.py | 16 ++++------------ backend/apps/web/routers/auths.py | 2 +- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/backend/apps/web/models/auths.py b/backend/apps/web/models/auths.py index ce087316..0f96f096 100644 --- a/backend/apps/web/models/auths.py +++ b/backend/apps/web/models/auths.py @@ -114,19 +114,11 @@ class AuthsTable: except: return None - def update_user_password_by_id( - self, id: str, password: str, new_password: str - ) -> bool: + def update_user_password_by_id(self, id: str, new_password: str) -> bool: try: - auth = Auth.get(Auth.id == id, Auth.active == True) - if auth: - if verify_password(password, auth.password): - query = Auth.update(password=new_password).where(Auth.id == id) - result = query.execute() - print(result) - return True - else: - return False + query = Auth.update(password=new_password).where(Auth.id == id) + result = query.execute() + print(result) return True except: return False diff --git a/backend/apps/web/routers/auths.py b/backend/apps/web/routers/auths.py index bcbe00d5..9174865a 100644 --- a/backend/apps/web/routers/auths.py +++ b/backend/apps/web/routers/auths.py @@ -69,7 +69,7 @@ async def update_password(form_data: UpdatePasswordForm, cred=Depends(bearer_sch if user: hashed = get_password_hash(form_data.new_password) - return Auths.update_user_password_by_id(user.id, form_data.password, hashed) + return Auths.update_user_password_by_id(user.id, hashed) else: raise HTTPException(400, detail=ERROR_MESSAGES.INVALID_PASSWORD) else: From d5bc54b8f8561cbab40b4e5c759a8a006df669e6 Mon Sep 17 00:00:00 2001 From: "Timothy J. Baek" Date: Fri, 29 Dec 2023 00:31:23 -0800 Subject: [PATCH 10/19] fix: update password --- backend/apps/web/models/auths.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/apps/web/models/auths.py b/backend/apps/web/models/auths.py index 0f96f096..800750c3 100644 --- a/backend/apps/web/models/auths.py +++ b/backend/apps/web/models/auths.py @@ -118,8 +118,8 @@ class AuthsTable: try: query = Auth.update(password=new_password).where(Auth.id == id) result = query.execute() - print(result) - return True + + return True if result == 1 else False except: return False From 36d2a589d21d37092fdf4aa7e70555f51412b4b8 Mon Sep 17 00:00:00 2001 From: "Timothy J. Baek" Date: Fri, 29 Dec 2023 09:05:43 -0800 Subject: [PATCH 11/19] doc: clarity --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bde67525..c40b88f5 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ Also check our sibling project, [OllamaHub](https://ollamahub.com/), where you c - πŸ” **Role-Based Access Control (RBAC)**: Ensure secure access with restricted permissions; only authorized individuals can access your Ollama, and exclusive model creation/pulling rights are reserved for administrators. -- πŸ”’ **Backend Reverse Proxy Support**: Strengthen security by enabling direct communication between Ollama Web UI backend and Ollama, eliminating the need to expose Ollama over LAN. +- πŸ”’ **Backend Reverse Proxy Support**: Bolster security through direct communication between Ollama Web UI backend and Ollama. This key feature eliminates the need to expose Ollama over LAN. Requests made to the '/ollama/api' route from the web UI are seamlessly redirected to Ollama from the backend, enhancing overall system security. - 🌟 **Continuous Updates**: We are committed to improving Ollama Web UI with regular updates and new features. From ec87a5e795e5de6cf63714a8cc62233663293f61 Mon Sep 17 00:00:00 2001 From: "Timothy J. Baek" Date: Fri, 29 Dec 2023 09:29:12 -0800 Subject: [PATCH 12/19] doc: troubleshooting update --- TROUBLESHOOTING.md | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/TROUBLESHOOTING.md b/TROUBLESHOOTING.md index 59f7049b..339c230f 100644 --- a/TROUBLESHOOTING.md +++ b/TROUBLESHOOTING.md @@ -1,30 +1,32 @@ # Ollama Web UI Troubleshooting Guide +## Understanding the Ollama WebUI Architecture + +The Ollama WebUI system is designed to streamline interactions between the client (your browser) and the Ollama API. At the heart of this design is a backend reverse proxy, enhancing security and resolving CORS issues. + +- **How it Works**: When you make a request (like `/ollama/api/tags`) from the Ollama WebUI, it doesn’t go directly to the Ollama API. Instead, it first reaches the Ollama WebUI backend. The backend then forwards this request to the Ollama API via the route you define in the `OLLAMA_API_BASE_URL` environment variable. For instance, a request to `/ollama/api/tags` in the WebUI is equivalent to `OLLAMA_API_BASE_URL/tags` in the backend. + +- **Security Benefits**: This design prevents direct exposure of the Ollama API to the frontend, safeguarding against potential CORS (Cross-Origin Resource Sharing) issues and unauthorized access. Requiring authentication to access the Ollama API further enhances this security layer. + ## Ollama WebUI: Server Connection Error -If you're running ollama-webui and have chosen to install webui and ollama separately, you might encounter connection issues. This is often due to the docker container being unable to reach the Ollama server at 127.0.0.1:11434(host.docker.internal:11434). To resolve this, you can use the `--network=host` flag in the docker command. When done so port would be changed from 3000 to 8080, and the link would be: http://localhost:8080. +If you're experiencing connection issues, it’s often due to the WebUI docker container not being able to reach the Ollama server at 127.0.0.1:11434 (host.docker.internal:11434) inside the container . Use the `--network=host` flag in your docker command to resolve this. Note that the port changes from 3000 to 8080, resulting in the link: `http://localhost:8080`. -Here's an example of the command you should run: +**Example Docker Command**: ```bash docker run -d --network=host -v ollama-webui:/app/backend/data -e OLLAMA_API_BASE_URL=http://127.0.0.1:11434/api --name ollama-webui --restart always ghcr.io/ollama-webui/ollama-webui:main ``` -## Connection Errors +### General Connection Errors -Make sure you have the **latest version of Ollama** installed before proceeding with the installation. You can find the latest version of Ollama at [https://ollama.ai/](https://ollama.ai/). +**Ensure Ollama Version is Up-to-Date**: Always start by checking that you have the latest version of Ollama. Visit [Ollama's official site](https://ollama.ai/) for the latest updates. -If you encounter difficulties connecting to the Ollama server, please follow these steps to diagnose and resolve the issue: +**Troubleshooting Steps**: -**1. Check Ollama URL Format** +1. **Verify Ollama URL Format**: + - When running the Web UI container, ensure the `OLLAMA_API_BASE_URL` is correctly set, including the `/api` suffix. (e.g., `http://192.168.1.1:11434/api` for different host setups). + - In the Ollama WebUI, navigate to "Settings" > "General". + - Confirm that the Ollama Server URL is correctly set to `/ollama/api`, including the `/api` suffix. -Ensure that the Ollama URL is correctly formatted in the application settings. Follow these steps: - -- If your Ollama runs in a different host than Web UI make sure Ollama host address is provided when running Web UI container via `OLLAMA_API_BASE_URL` environment variable. [(e.g. OLLAMA_API_BASE_URL=http://192.168.1.1:11434/api)](https://github.com/ollama-webui/ollama-webui#accessing-external-ollama-on-a-different-server) -- Go to "Settings" within the Ollama WebUI. -- Navigate to the "General" section. -- Verify that the Ollama Server URL is set to: `/ollama/api`. - -It is crucial to include the `/api` at the end of the URL to ensure that the Ollama Web UI can communicate with the server. - -By following these troubleshooting steps, you should be able to identify and resolve connection issues with your Ollama server configuration. If you require further assistance or have additional questions, please don't hesitate to reach out or refer to our documentation for comprehensive guidance. +By following these enhanced troubleshooting steps, connection issues should be effectively resolved. For further assistance or queries, feel free to reach out to us on our community Discord. From 28a3d599553007e42f709b8162e2a3b9f80b284b Mon Sep 17 00:00:00 2001 From: "Timothy J. Baek" Date: Fri, 29 Dec 2023 09:29:54 -0800 Subject: [PATCH 13/19] feat: update troubleshooting messages --- src/lib/components/chat/SettingsModal.svelte | 9 ++++++--- src/routes/(app)/+layout.svelte | 11 +++++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/lib/components/chat/SettingsModal.svelte b/src/lib/components/chat/SettingsModal.svelte index 18aa6eca..5dd57c78 100644 --- a/src/lib/components/chat/SettingsModal.svelte +++ b/src/lib/components/chat/SettingsModal.svelte @@ -997,12 +997,12 @@
-
Ollama Server URL
+
Ollama API URL
@@ -1028,7 +1028,10 @@
From 78d095ad9de68a24ec09d9db9334e422510c3217 Mon Sep 17 00:00:00 2001 From: "Timothy J. Baek" Date: Fri, 29 Dec 2023 09:41:46 -0800 Subject: [PATCH 14/19] doc: important note update --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c40b88f5..e99704ab 100644 --- a/README.md +++ b/README.md @@ -71,11 +71,14 @@ Don't forget to explore our sibling project, [OllamaHub](https://ollamahub.com/) ## How to Install πŸš€ -🌟 **Important Note on User Roles:** +🌟 **Important Note on User Roles and Privacy:** - **Admin Creation:** The very first account to sign up on the Ollama Web UI will be granted **Administrator privileges**. This account will have comprehensive control over the platform, including user management and system settings. + - **User Registrations:** All subsequent users signing up will initially have their accounts set to **Pending** status by default. These accounts will require approval from the Administrator to gain access to the platform functionalities. +- **Privacy and Data Security:** We prioritize your privacy and data security above all. Please be reassured that all data entered into the Ollama Web UI is stored locally on your device. Our system is designed to be privacy-first, ensuring that no external requests are made, and your data does not leave your local environment. We are committed to maintaining the highest standards of data privacy and security, ensuring that your information remains confidential and under your control. + ### Installing Both Ollama and Ollama Web UI Using Docker Compose If you don't have Ollama installed yet, you can use the provided Docker Compose file for a hassle-free installation. Simply run the following command: From f91a6b63d122b78f79faee655214ce2c6f1ce67b Mon Sep 17 00:00:00 2001 From: "Timothy J. Baek" Date: Fri, 29 Dec 2023 23:03:48 -0800 Subject: [PATCH 15/19] feat: message components refac --- src/lib/components/chat/Messages.svelte | 830 +----------------- src/lib/components/chat/Messages/Name.svelte | 3 + .../chat/Messages/Placeholder.svelte | 71 ++ .../chat/Messages/ProfileImage.svelte | 7 + .../chat/Messages/ResponseMessage.svelte | 544 ++++++++++++ .../components/chat/Messages/Skeleton.svelte | 19 + .../chat/Messages/UserMessage.svelte | 195 ++++ src/routes/(app)/+page.svelte | 13 +- static/ollama-dark.png | Bin 0 -> 13509 bytes static/ollama.png | Bin 7487 -> 7788 bytes 10 files changed, 891 insertions(+), 791 deletions(-) create mode 100644 src/lib/components/chat/Messages/Name.svelte create mode 100644 src/lib/components/chat/Messages/Placeholder.svelte create mode 100644 src/lib/components/chat/Messages/ProfileImage.svelte create mode 100644 src/lib/components/chat/Messages/ResponseMessage.svelte create mode 100644 src/lib/components/chat/Messages/Skeleton.svelte create mode 100644 src/lib/components/chat/Messages/UserMessage.svelte create mode 100644 static/ollama-dark.png diff --git a/src/lib/components/chat/Messages.svelte b/src/lib/components/chat/Messages.svelte index df8a72b8..08589420 100644 --- a/src/lib/components/chat/Messages.svelte +++ b/src/lib/components/chat/Messages.svelte @@ -1,12 +1,5 @@ {#if messages.length == 0} -
-
- {#if selectedModelfile && selectedModelfile.imageUrl} - modelfile - {:else} - ollama - {/if} -
-
- {#if selectedModelfile} - - {selectedModelfile.title} - -
- {selectedModelfile.desc} -
- {#if selectedModelfile.user} - - {/if} - {:else} - How can I help you today? - {/if} -
-
+ {:else} {#each messages as message, messageIdx}
-
-
- {#if message.role === 'user'} - {#if $config === null || !($config?.auth ?? true)} - User profile - {:else} - User profile - {/if} - {:else if selectedModelfile} - Ollama profile - {:else} - Ollama profile - {/if} -
- -
-
- {#if message.role === 'user'} - You - {:else if selectedModelfile} - - {selectedModelfile.title} - - {:else} - Ollama {message.model ? ` ${message.model}` : ''} - {/if} -
- - {#if message.role !== 'user' && message.content === ''} -
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
- {:else} -
- {#if message.role == 'user'} - {#if message.files} -
- {#each message.files as file} -
- {#if file.type === 'image'} - input - {/if} -
- {/each} -
- {/if} - - {#if message?.edit === true} -
-