Przeglądaj źródła

Merge branch 'dev' of github.com:taylorwilsdon/open-webui into dev

Taylor Wilsdon 4 miesięcy temu
rodzic
commit
708fcdc6b7

+ 8 - 1
backend/open_webui/__init__.py

@@ -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()

+ 1 - 0
backend/open_webui/constants.py

@@ -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."
 

+ 14 - 0
backend/open_webui/env.py

@@ -326,6 +326,20 @@ REDIS_URL = os.environ.get("REDIS_URL", "")
 REDIS_SENTINEL_HOSTS = os.environ.get("REDIS_SENTINEL_HOSTS", "")
 REDIS_SENTINEL_PORT = os.environ.get("REDIS_SENTINEL_PORT", "26379")
 
+####################################
+# 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)
 ####################################

+ 8 - 0
backend/open_webui/retrieval/utils.py

@@ -77,6 +77,7 @@ def query_doc(
     collection_name: str, query_embedding: list[float], k: int, user: UserModel = None
 ):
     try:
+        log.debug(f"query_doc:doc {collection_name}")
         result = VECTOR_DB_CLIENT.search(
             collection_name=collection_name,
             vectors=[query_embedding],
@@ -94,6 +95,7 @@ def query_doc(
 
 def get_doc(collection_name: str, user: UserModel = None):
     try:
+        log.debug(f"get_doc:doc {collection_name}")
         result = VECTOR_DB_CLIENT.get(collection_name=collection_name)
 
         if result:
@@ -116,6 +118,7 @@ def query_doc_with_hybrid_search(
     r: float,
 ) -> dict:
     try:
+        log.debug(f"query_doc_with_hybrid_search:doc {collection_name}")
         bm25_retriever = BM25Retriever.from_texts(
             texts=collection_result.documents[0],
             metadatas=collection_result.metadatas[0],
@@ -168,6 +171,7 @@ def query_doc_with_hybrid_search(
         )
         return result
     except Exception as e:
+        log.exception(f"Error querying doc {collection_name} with hybrid search: {e}")
         raise e
 
 
@@ -257,6 +261,7 @@ def query_collection(
 ) -> dict:
     results = []
     for query in queries:
+        log.debug(f"query_collection:query {query}")
         query_embedding = embedding_function(query, prefix=RAG_EMBEDDING_QUERY_PREFIX)
         for collection_name in collection_names:
             if collection_name:
@@ -292,6 +297,7 @@ def query_collection_with_hybrid_search(
     collection_results = {}
     for collection_name in collection_names:
         try:
+            log.debug(f"query_collection_with_hybrid_search:VECTOR_DB_CLIENT.get:collection {collection_name}")
             collection_results[collection_name] = VECTOR_DB_CLIENT.get(
                 collection_name=collection_name
             )
@@ -613,6 +619,7 @@ def generate_openai_batch_embeddings(
     user: UserModel = None,
 ) -> Optional[list[list[float]]]:
     try:
+        log.debug(f"generate_openai_batch_embeddings:model {model} batch size: {len(texts)}")
         json_data = {"input": texts, "model": model}
         if isinstance(RAG_EMBEDDING_PREFIX_FIELD_NAME, str) and isinstance(prefix, str):
             json_data[RAG_EMBEDDING_PREFIX_FIELD_NAME] = prefix
@@ -655,6 +662,7 @@ def generate_ollama_batch_embeddings(
     user: UserModel = None,
 ) -> Optional[list[list[float]]]:
     try:
+        log.debug(f"generate_ollama_batch_embeddings:model {model} batch size: {len(texts)}")
         json_data = {"input": texts, "model": model}
         if isinstance(RAG_EMBEDDING_PREFIX_FIELD_NAME, str) and isinstance(prefix, str):
             json_data[RAG_EMBEDDING_PREFIX_FIELD_NAME] = prefix

+ 8 - 8
backend/open_webui/retrieval/web/duckduckgo.py

@@ -3,6 +3,7 @@ from typing import Optional
 
 from open_webui.retrieval.web.main import SearchResult, get_filtered_results
 from duckduckgo_search import DDGS
+from duckduckgo_search.exceptions import RatelimitException
 from open_webui.env import SRC_LOG_LEVELS
 
 log = logging.getLogger(__name__)
@@ -22,16 +23,15 @@ 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]
-
+        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:
         search_results = get_filtered_results(search_results, filter_list)
 

+ 7 - 0
backend/open_webui/routers/auths.py

@@ -454,6 +454,13 @@ async def signup(request: Request, response: Response, form_data: SignupForm):
             # 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(
             form_data.email.lower(),

+ 9 - 9
backend/requirements.txt

@@ -98,7 +98,7 @@ pytube==15.0.0
 
 extract_msg
 pydub
-duckduckgo-search~=7.3.2
+duckduckgo-search~=7.5.5
 
 ## Google Drive
 google-api-python-client
@@ -127,11 +127,11 @@ firecrawl-py==1.12.0
 opentelemetry-api==1.31.1
 opentelemetry-sdk==1.31.1
 opentelemetry-exporter-otlp==1.31.1
-opentelemetry-instrumentation==0.52b0
-opentelemetry-instrumentation-fastapi==0.52b0
-opentelemetry-instrumentation-sqlalchemy==0.52b0
-opentelemetry-instrumentation-redis==0.52b0
-opentelemetry-instrumentation-requests==0.52b0
-opentelemetry-instrumentation-logging==0.52b0
-opentelemetry-instrumentation-httpx==0.52b0
-opentelemetry-instrumentation-aiohttp-client==0.52b0
+opentelemetry-instrumentation==0.52b1
+opentelemetry-instrumentation-fastapi==0.52b1
+opentelemetry-instrumentation-sqlalchemy==0.52b1
+opentelemetry-instrumentation-redis==0.52b1
+opentelemetry-instrumentation-requests==0.52b1
+opentelemetry-instrumentation-logging==0.52b1
+opentelemetry-instrumentation-httpx==0.52b1
+opentelemetry-instrumentation-aiohttp-client==0.52b1

+ 1 - 1
backend/start.sh

@@ -65,4 +65,4 @@ if [ -n "$SPACE_ID" ]; then
   export WEBUI_URL=${SPACE_HOST}
 fi
 
-WEBUI_SECRET_KEY="$WEBUI_SECRET_KEY" exec uvicorn open_webui.main:app --host "$HOST" --port "$PORT" --forwarded-allow-ips '*'
+WEBUI_SECRET_KEY="$WEBUI_SECRET_KEY" exec uvicorn open_webui.main:app --host "$HOST" --port "$PORT" --forwarded-allow-ips '*' --workers "${UVICORN_WORKERS:-1}"

+ 2 - 1
backend/start_windows.bat

@@ -41,5 +41,6 @@ IF "%WEBUI_SECRET_KEY%%WEBUI_JWT_SECRET_KEY%" == " " (
 
 :: Execute uvicorn
 SET "WEBUI_SECRET_KEY=%WEBUI_SECRET_KEY%"
-uvicorn open_webui.main:app --host "%HOST%" --port "%PORT%" --forwarded-allow-ips '*' --ws auto
+IF "%UVICORN_WORKERS%"=="" SET UVICORN_WORKERS=1
+uvicorn open_webui.main:app --host "%HOST%" --port "%PORT%" --forwarded-allow-ips '*' --workers %UVICORN_WORKERS% --ws auto
 :: For ssl user uvicorn open_webui.main:app --host "%HOST%" --port "%PORT%" --forwarded-allow-ips '*' --ssl-keyfile "key.pem" --ssl-certfile "cert.pem" --ws auto

+ 1 - 1
pyproject.toml

@@ -104,7 +104,7 @@ dependencies = [
 
     "extract_msg",
     "pydub",
-    "duckduckgo-search~=7.3.2",
+    "duckduckgo-search~=7.5.5",
 
     "google-api-python-client",
     "google-auth-httplib2",

+ 1 - 1
src/lib/components/chat/ToolServersModal.svelte

@@ -15,7 +15,7 @@
 
 	let selectedTools = [];
 
-	$: selectedTools = $tools.filter((tool) => selectedToolIds.includes(tool.id));
+	$: selectedTools = ($tools ?? []).filter((tool) => selectedToolIds.includes(tool.id));
 
 	const i18n = getContext('i18n');
 </script>