From 903226a7bfd83436c48974d921cb5e57d83b139e Mon Sep 17 00:00:00 2001 From: Phil Szalay Date: Thu, 13 Feb 2025 10:29:33 +0100 Subject: [PATCH] Finish customer segregation, docker setup --- backend/beyond_the_loop/dev.sh | 12 ++++++++ backend/beyond_the_loop/models/companies.py | 3 ++ .../routers/auths.py | 26 +++++++++-------- backend/dev.sh | 2 -- backend/open_webui/main.py | 4 +-- backend/open_webui/models/auths.py | 1 - .../test/apps/webui/routers/test_auths.py | 15 +++++----- backend/open_webui/utils/oauth.py | 3 +- docker-compose.yaml | 7 ++++- litellm-config.yaml | 29 +++++++++++++++++++ main.py | 0 11 files changed, 76 insertions(+), 26 deletions(-) create mode 100755 backend/beyond_the_loop/dev.sh rename backend/{open_webui => beyond_the_loop}/routers/auths.py (97%) delete mode 100755 backend/dev.sh create mode 100644 litellm-config.yaml create mode 100644 main.py diff --git a/backend/beyond_the_loop/dev.sh b/backend/beyond_the_loop/dev.sh new file mode 100755 index 000000000..08d15e068 --- /dev/null +++ b/backend/beyond_the_loop/dev.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +# Set the Python path to include the backend directory +export PYTHONPATH="/Users/philszalay/Documents/code/beyond-the-loop/backend:$PYTHONPATH" + +PORT="${PORT:-8080}" + +# Start the LiteLLM container in the background +cd /Users/philszalay/Documents/code/beyond-the-loop && docker-compose up -d litellm + +# Start the uvicorn server +cd /Users/philszalay/Documents/code/beyond-the-loop/backend && uvicorn open_webui.main:app --port $PORT --host 0.0.0.0 --forwarded-allow-ips '*' --reload diff --git a/backend/beyond_the_loop/models/companies.py b/backend/beyond_the_loop/models/companies.py index 9eb6487d4..269b785ee 100644 --- a/backend/beyond_the_loop/models/companies.py +++ b/backend/beyond_the_loop/models/companies.py @@ -7,6 +7,9 @@ from sqlalchemy import String, Column, Text from open_webui.internal.db import get_db, Base +# Constants +NO_COMPANY = "NO_COMPANY" + #################### # Company DB Schema #################### diff --git a/backend/open_webui/routers/auths.py b/backend/beyond_the_loop/routers/auths.py similarity index 97% rename from backend/open_webui/routers/auths.py rename to backend/beyond_the_loop/routers/auths.py index 39c3b8333..03c2e2486 100644 --- a/backend/open_webui/routers/auths.py +++ b/backend/beyond_the_loop/routers/auths.py @@ -19,6 +19,7 @@ from open_webui.models.auths import ( UserResponse, ) from beyond_the_loop.models.users import Users +from beyond_the_loop.models.companies import NO_COMPANY from open_webui.constants import ERROR_MESSAGES, WEBHOOK_MESSAGES from open_webui.env import ( @@ -258,7 +259,7 @@ async def ldap_auth(request: Request, response: Response, form_data: LdapForm): ) user = Auths.insert_new_auth( - email=mail, password=str(uuid.uuid4()), name=cn, company_id="NO_COMPANY", role=role + email=mail, password=str(uuid.uuid4()), name=cn, company_id=NO_COMPANY, role=role ) if not user: @@ -451,7 +452,7 @@ async def signup(request: Request, response: Response, form_data: SignupForm): form_data.email.lower(), hashed, form_data.name, - "NO_COMPANY", + NO_COMPANY, form_data.profile_image_url, role, ) @@ -550,7 +551,7 @@ async def signout(request: Request, response: Response): @router.post("/add", response_model=SigninResponse) -async def add_user(form_data: AddUserForm, user=Depends(get_admin_user)): +async def add_user(form_data: AddUserForm, admin_user: Users = Depends(get_admin_user)): if not validate_email_format(form_data.email.lower()): raise HTTPException( status.HTTP_400_BAD_REQUEST, detail=ERROR_MESSAGES.INVALID_EMAIL_FORMAT @@ -561,25 +562,26 @@ async def add_user(form_data: AddUserForm, user=Depends(get_admin_user)): try: hashed = get_password_hash(form_data.password) - user = Auths.insert_new_auth( + new_user = Auths.insert_new_auth( form_data.email.lower(), hashed, form_data.name, - form_data.company_id, + admin_user.company_id, form_data.profile_image_url, form_data.role, ) - if user: - token = create_token(data={"id": user.id}) + if new_user: + token = create_token(data={"id": new_user.id}) return { "token": token, "token_type": "Bearer", - "id": user.id, - "email": user.email, - "name": user.name, - "role": user.role, - "profile_image_url": user.profile_image_url, + "id": new_user.id, + "email": new_user.email, + "name": new_user.name, + "role": new_user.role, + "company_id": new_user.company_id, + "profile_image_url": new_user.profile_image_url, } else: raise HTTPException(500, detail=ERROR_MESSAGES.CREATE_USER_ERROR) diff --git a/backend/dev.sh b/backend/dev.sh deleted file mode 100755 index 5449ab777..000000000 --- a/backend/dev.sh +++ /dev/null @@ -1,2 +0,0 @@ -PORT="${PORT:-8080}" -uvicorn open_webui.main:app --port $PORT --host 0.0.0.0 --forwarded-allow-ips '*' --reload \ No newline at end of file diff --git a/backend/open_webui/main.py b/backend/open_webui/main.py index d851c243d..07202bc27 100644 --- a/backend/open_webui/main.py +++ b/backend/open_webui/main.py @@ -57,7 +57,6 @@ from open_webui.routers import ( retrieval, pipelines, tasks, - auths, channels, chats, folders, @@ -85,7 +84,8 @@ from open_webui.internal.db import Session from open_webui.models.functions import Functions from beyond_the_loop.models.models import Models -from beyond_the_loop.models.users import UserModel, Users +from beyond_the_loop.models.users import Users +from beyond_the_loop.routers import auths from open_webui.config import ( # Ollama diff --git a/backend/open_webui/models/auths.py b/backend/open_webui/models/auths.py index 95d7242db..41afcbf35 100644 --- a/backend/open_webui/models/auths.py +++ b/backend/open_webui/models/auths.py @@ -92,7 +92,6 @@ class SignupForm(BaseModel): class AddUserForm(SignupForm): role: Optional[str] = "pending", - company_id: str class AuthsTable: diff --git a/backend/open_webui/test/apps/webui/routers/test_auths.py b/backend/open_webui/test/apps/webui/routers/test_auths.py index ef4b6468d..81d692f22 100644 --- a/backend/open_webui/test/apps/webui/routers/test_auths.py +++ b/backend/open_webui/test/apps/webui/routers/test_auths.py @@ -1,5 +1,6 @@ from test.util.abstract_integration_test import AbstractPostgresTest from test.util.mock_user import mock_webui_user +from beyond_the_loop.models.companies import NO_COMPANY class TestAuths(AbstractPostgresTest): @@ -32,7 +33,7 @@ class TestAuths(AbstractPostgresTest): email="john.doe@openwebui.com", password=get_password_hash("old_password"), name="John Doe", - company_id="1", + company_id=NO_COMPANY, profile_image_url="/user.png", role="user", ) @@ -54,7 +55,7 @@ class TestAuths(AbstractPostgresTest): email="john.doe@openwebui.com", password=get_password_hash("old_password"), name="John Doe", - company_id="1", + company_id=NO_COMPANY, profile_image_url="/user.png", role="user", ) @@ -82,7 +83,7 @@ class TestAuths(AbstractPostgresTest): email="john.doe@openwebui.com", password=get_password_hash("password"), name="John Doe", - company_id="1", + company_id=NO_COMPANY, profile_image_url="/user.png", role="user", ) @@ -145,7 +146,7 @@ class TestAuths(AbstractPostgresTest): email="john.doe@openwebui.com", password="password", name="John Doe", - company_id="1", + company_id=NO_COMPANY, profile_image_url="/user.png", role="admin", ) @@ -163,7 +164,7 @@ class TestAuths(AbstractPostgresTest): email="john.doe@openwebui.com", password="password", name="John Doe", - company_id="1", + company_id=NO_COMPANY, profile_image_url="/user.png", role="admin", ) @@ -179,7 +180,7 @@ class TestAuths(AbstractPostgresTest): email="john.doe@openwebui.com", password="password", name="John Doe", - company_id="1", + company_id=NO_COMPANY, profile_image_url="/user.png", role="admin", ) @@ -196,7 +197,7 @@ class TestAuths(AbstractPostgresTest): email="john.doe@openwebui.com", password="password", name="John Doe", - company_id="1", + company_id=NO_COMPANY, profile_image_url="/user.png", role="admin", ) diff --git a/backend/open_webui/utils/oauth.py b/backend/open_webui/utils/oauth.py index e5182f650..0dc3478f0 100644 --- a/backend/open_webui/utils/oauth.py +++ b/backend/open_webui/utils/oauth.py @@ -14,6 +14,7 @@ from starlette.responses import RedirectResponse from open_webui.models.auths import Auths from beyond_the_loop.models.users import Users +from beyond_the_loop.models.companies import NO_COMPANY from open_webui.models.groups import Groups, GroupModel, GroupUpdateForm from open_webui.config import ( DEFAULT_USER_ROLE, @@ -292,7 +293,7 @@ class OAuthManager: str(uuid.uuid4()) ), # Random password, not used name=name, - company_id="NO_COMPANY", + company_id=NO_COMPANY, profile_image_url=picture_url, role=role, oauth_sub=provider_sub, diff --git a/docker-compose.yaml b/docker-compose.yaml index f23b4387b..0d784eb30 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -4,6 +4,9 @@ services: litellm: container_name: litellm image: ghcr.io/berriai/litellm:main-stable + environment: + - "AZURE_OPENAI_API_BASE_URL=${AZURE_OPENAI_API_BASE_URL}" + - "AZURE_OPENAI_API_KEY=${AZURE_OPENAI_API_KEY}" restart: unless-stopped ports: - "4000:4000" @@ -22,16 +25,18 @@ services: image: ghcr.io/open-webui/open-webui:${WEBUI_DOCKER_TAG-main} container_name: open-webui volumes: - - open-webui:/app/backend/data + - ./backend/data:/app/backend/data depends_on: - litellm ports: - "8080:8080" # Open Web UI port environment: - "OPENAI_API_BASE_URL=http://litellm:4000/v1" # Point Open Web UI to LiteLLM + - "DATABASE_URL=sqlite:////app/backend/data/database.sqlite" extra_hosts: - host.docker.internal:host-gateway restart: unless-stopped volumes: open-webui: {} + litellm: {} diff --git a/litellm-config.yaml b/litellm-config.yaml new file mode 100644 index 000000000..c46ba4789 --- /dev/null +++ b/litellm-config.yaml @@ -0,0 +1,29 @@ +litellm_settings: + debug: true + verbose: true + load_env_variables: true + +model_list: + - model_name: "GPT 4o" + litellm_params: + model: "azure/gpt-4o" + api_base: os.environ/AZURE_OPENAI_API_BASE_URL + api_key: os.environ/AZURE_OPENAI_API_KEY + model_info: + description: "OpenAI's most advanced model, ideal for complex tasks." + arena_elo: 1287 + knowledge_cutoff: "October 2023" + context_window: 128000 + + - model_name: "GPT 3.5 Turbo" + litellm_params: + model: "azure/gpt-35-turbo" + api_base: os.environ/AZURE_OPENAI_API_BASE_URL + api_key: os.environ/AZURE_OPENAI_API_KEY + model_info: + description: "OpenAI's cheaper model for less complex tasks." + arena_elo: 1116 + knowledge_cutoff: "September 2021" + context_window: 16000 + +general_settings: {} diff --git a/main.py b/main.py new file mode 100644 index 000000000..e69de29bb