Merge branch 'dev' of https://github.com/open-webui/open-webui into tools-refac-2.1

This commit is contained in:
Michael Poluektov
2024-08-20 14:56:47 +01:00
73 changed files with 755 additions and 354 deletions

View File

@@ -38,6 +38,7 @@ from config import (
AUDIO_TTS_MODEL,
AUDIO_TTS_VOICE,
AppConfig,
CORS_ALLOW_ORIGIN,
)
from constants import ERROR_MESSAGES
from utils.utils import (
@@ -52,7 +53,7 @@ log.setLevel(SRC_LOG_LEVELS["AUDIO"])
app = FastAPI()
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_origins=CORS_ALLOW_ORIGIN,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],

View File

@@ -1,15 +1,10 @@
import re
import requests
import base64
from fastapi import (
FastAPI,
Request,
Depends,
HTTPException,
status,
UploadFile,
File,
Form,
)
from fastapi.middleware.cors import CORSMiddleware
@@ -20,7 +15,6 @@ from utils.utils import (
)
from apps.images.utils.comfyui import ImageGenerationPayload, comfyui_generate_image
from utils.misc import calculate_sha256
from typing import Optional
from pydantic import BaseModel
from pathlib import Path
@@ -51,6 +45,7 @@ from config import (
IMAGE_SIZE,
IMAGE_STEPS,
AppConfig,
CORS_ALLOW_ORIGIN,
)
log = logging.getLogger(__name__)
@@ -62,7 +57,7 @@ IMAGE_CACHE_DIR.mkdir(parents=True, exist_ok=True)
app = FastAPI()
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_origins=CORS_ALLOW_ORIGIN,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],

View File

@@ -41,6 +41,7 @@ from config import (
MODEL_FILTER_LIST,
UPLOAD_DIR,
AppConfig,
CORS_ALLOW_ORIGIN,
)
from utils.misc import (
calculate_sha256,
@@ -55,7 +56,7 @@ log.setLevel(SRC_LOG_LEVELS["OLLAMA"])
app = FastAPI()
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_origins=CORS_ALLOW_ORIGIN,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],

View File

@@ -32,6 +32,7 @@ from config import (
ENABLE_MODEL_FILTER,
MODEL_FILTER_LIST,
AppConfig,
CORS_ALLOW_ORIGIN,
)
from typing import Optional, Literal, overload
@@ -45,7 +46,7 @@ log.setLevel(SRC_LOG_LEVELS["OPENAI"])
app = FastAPI()
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_origins=CORS_ALLOW_ORIGIN,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],

View File

@@ -129,6 +129,7 @@ from config import (
RAG_WEB_SEARCH_RESULT_COUNT,
RAG_WEB_SEARCH_CONCURRENT_REQUESTS,
RAG_EMBEDDING_OPENAI_BATCH_SIZE,
CORS_ALLOW_ORIGIN,
)
from constants import ERROR_MESSAGES
@@ -240,12 +241,9 @@ app.state.EMBEDDING_FUNCTION = get_embedding_function(
app.state.config.RAG_EMBEDDING_OPENAI_BATCH_SIZE,
)
origins = ["*"]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_origins=CORS_ALLOW_ORIGIN,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],

View File

@@ -44,10 +44,12 @@ from config import (
JWT_EXPIRES_IN,
WEBUI_BANNERS,
ENABLE_COMMUNITY_SHARING,
ENABLE_MESSAGE_RATING,
AppConfig,
OAUTH_USERNAME_CLAIM,
OAUTH_PICTURE_CLAIM,
OAUTH_EMAIL_CLAIM,
CORS_ALLOW_ORIGIN,
)
from apps.socket.main import get_event_call, get_event_emitter
@@ -60,8 +62,6 @@ from pydantic import BaseModel
app = FastAPI()
origins = ["*"]
app.state.config = AppConfig()
app.state.config.ENABLE_SIGNUP = ENABLE_SIGNUP
@@ -83,6 +83,7 @@ app.state.config.WEBHOOK_URL = WEBHOOK_URL
app.state.config.BANNERS = WEBUI_BANNERS
app.state.config.ENABLE_COMMUNITY_SHARING = ENABLE_COMMUNITY_SHARING
app.state.config.ENABLE_MESSAGE_RATING = ENABLE_MESSAGE_RATING
app.state.config.OAUTH_USERNAME_CLAIM = OAUTH_USERNAME_CLAIM
app.state.config.OAUTH_PICTURE_CLAIM = OAUTH_PICTURE_CLAIM
@@ -94,7 +95,7 @@ app.state.FUNCTIONS = {}
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_origins=CORS_ALLOW_ORIGIN,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],

View File

@@ -352,6 +352,7 @@ async def get_admin_config(request: Request, user=Depends(get_admin_user)):
"DEFAULT_USER_ROLE": request.app.state.config.DEFAULT_USER_ROLE,
"JWT_EXPIRES_IN": request.app.state.config.JWT_EXPIRES_IN,
"ENABLE_COMMUNITY_SHARING": request.app.state.config.ENABLE_COMMUNITY_SHARING,
"ENABLE_MESSAGE_RATING": request.app.state.config.ENABLE_MESSAGE_RATING,
}
@@ -361,6 +362,7 @@ class AdminConfig(BaseModel):
DEFAULT_USER_ROLE: str
JWT_EXPIRES_IN: str
ENABLE_COMMUNITY_SHARING: bool
ENABLE_MESSAGE_RATING: bool
@router.post("/admin/config")
@@ -382,6 +384,7 @@ async def update_admin_config(
request.app.state.config.ENABLE_COMMUNITY_SHARING = (
form_data.ENABLE_COMMUNITY_SHARING
)
request.app.state.config.ENABLE_MESSAGE_RATING = form_data.ENABLE_MESSAGE_RATING
return {
"SHOW_ADMIN_DETAILS": request.app.state.config.SHOW_ADMIN_DETAILS,
@@ -389,6 +392,7 @@ async def update_admin_config(
"DEFAULT_USER_ROLE": request.app.state.config.DEFAULT_USER_ROLE,
"JWT_EXPIRES_IN": request.app.state.config.JWT_EXPIRES_IN,
"ENABLE_COMMUNITY_SHARING": request.app.state.config.ENABLE_COMMUNITY_SHARING,
"ENABLE_MESSAGE_RATING": request.app.state.config.ENABLE_MESSAGE_RATING,
}

View File

@@ -85,9 +85,10 @@ async def download_chat_as_pdf(
pdf.add_font("NotoSans", "i", f"{FONTS_DIR}/NotoSans-Italic.ttf")
pdf.add_font("NotoSansKR", "", f"{FONTS_DIR}/NotoSansKR-Regular.ttf")
pdf.add_font("NotoSansJP", "", f"{FONTS_DIR}/NotoSansJP-Regular.ttf")
pdf.add_font("NotoSansSC", "", f"{FONTS_DIR}/NotoSansSC-Regular.ttf")
pdf.set_font("NotoSans", size=12)
pdf.set_fallback_fonts(["NotoSansKR", "NotoSansJP"])
pdf.set_fallback_fonts(["NotoSansKR", "NotoSansJP", "NotoSansSC"])
pdf.set_auto_page_break(auto=True, margin=15)

View File

@@ -3,6 +3,8 @@ import sys
import logging
import importlib.metadata
import pkgutil
from urllib.parse import urlparse
import chromadb
from chromadb import Settings
from bs4 import BeautifulSoup
@@ -805,10 +807,24 @@ USER_PERMISSIONS_CHAT_DELETION = (
os.environ.get("USER_PERMISSIONS_CHAT_DELETION", "True").lower() == "true"
)
USER_PERMISSIONS_CHAT_EDITING = (
os.environ.get("USER_PERMISSIONS_CHAT_EDITING", "True").lower() == "true"
)
USER_PERMISSIONS_CHAT_TEMPORARY = (
os.environ.get("USER_PERMISSIONS_CHAT_TEMPORARY", "True").lower() == "true"
)
USER_PERMISSIONS = PersistentConfig(
"USER_PERMISSIONS",
"ui.user_permissions",
{"chat": {"deletion": USER_PERMISSIONS_CHAT_DELETION}},
{
"chat": {
"deletion": USER_PERMISSIONS_CHAT_DELETION,
"editing": USER_PERMISSIONS_CHAT_EDITING,
"temporary": USER_PERMISSIONS_CHAT_TEMPORARY,
}
},
)
ENABLE_MODEL_FILTER = PersistentConfig(
@@ -839,6 +855,47 @@ ENABLE_COMMUNITY_SHARING = PersistentConfig(
os.environ.get("ENABLE_COMMUNITY_SHARING", "True").lower() == "true",
)
ENABLE_MESSAGE_RATING = PersistentConfig(
"ENABLE_MESSAGE_RATING",
"ui.enable_message_rating",
os.environ.get("ENABLE_MESSAGE_RATING", "True").lower() == "true",
)
def validate_cors_origins(origins):
for origin in origins:
if origin != "*":
validate_cors_origin(origin)
def validate_cors_origin(origin):
parsed_url = urlparse(origin)
# Check if the scheme is either http or https
if parsed_url.scheme not in ["http", "https"]:
raise ValueError(
f"Invalid scheme in CORS_ALLOW_ORIGIN: '{origin}'. Only 'http' and 'https' are allowed."
)
# Ensure that the netloc (domain + port) is present, indicating it's a valid URL
if not parsed_url.netloc:
raise ValueError(f"Invalid URL structure in CORS_ALLOW_ORIGIN: '{origin}'.")
# For production, you should only need one host as
# fastapi serves the svelte-kit built frontend and backend from the same host and port.
# To test CORS_ALLOW_ORIGIN locally, you can set something like
# CORS_ALLOW_ORIGIN=http://localhost:5173;http://localhost:8080
# in your .env file depending on your frontend port, 5173 in this case.
CORS_ALLOW_ORIGIN = os.environ.get("CORS_ALLOW_ORIGIN", "*").split(";")
if "*" in CORS_ALLOW_ORIGIN:
log.warning(
"\n\nWARNING: CORS_ALLOW_ORIGIN IS SET TO '*' - NOT RECOMMENDED FOR PRODUCTION DEPLOYMENTS.\n"
)
validate_cors_origins(CORS_ALLOW_ORIGIN)
class BannerModel(BaseModel):
id: str
@@ -894,10 +951,7 @@ TITLE_GENERATION_PROMPT_TEMPLATE = PersistentConfig(
"task.title.prompt_template",
os.environ.get(
"TITLE_GENERATION_PROMPT_TEMPLATE",
"""Here is the query:
{{prompt:middletruncate:8000}}
Create a concise, 3-5 word phrase with an emoji as a title for the previous query. Suitable Emojis for the summary can be used to enhance understanding but avoid quotation marks or special formatting. RESPOND ONLY WITH THE TITLE TEXT.
"""Create a concise, 3-5 word title with an emoji as a title for the prompt in the given language. Suitable Emojis for the summary can be used to enhance understanding but avoid quotation marks or special formatting. RESPOND ONLY WITH THE TITLE TEXT.
Examples of titles:
📉 Stock Market Trends
@@ -905,7 +959,9 @@ Examples of titles:
Evolution of Music Streaming
Remote Work Productivity Tips
Artificial Intelligence in Healthcare
🎮 Video Game Development Insights""",
🎮 Video Game Development Insights
Prompt: {{prompt:middletruncate:8000}}""",
),
)

View File

@@ -67,6 +67,7 @@ from utils.utils import (
get_http_authorization_cred,
get_password_hash,
create_token,
decode_token,
)
from utils.task import (
title_generation_template,
@@ -120,6 +121,7 @@ from config import (
WEBUI_SESSION_COOKIE_SECURE,
ENABLE_ADMIN_CHAT_ACCESS,
AppConfig,
CORS_ALLOW_ORIGIN,
)
from constants import ERROR_MESSAGES, WEBHOOK_MESSAGES, TASKS
@@ -210,8 +212,6 @@ app.state.config.TOOLS_FUNCTION_CALLING_PROMPT_TEMPLATE = (
app.state.MODELS = {}
origins = ["*"]
##################################
#
@@ -754,7 +754,7 @@ app.add_middleware(PipelineMiddleware)
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_origins=CORS_ALLOW_ORIGIN,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
@@ -1881,40 +1881,61 @@ async def update_pipeline_valves(
@app.get("/api/config")
async def get_app_config():
async def get_app_config(request: Request):
user = None
if "token" in request.cookies:
token = request.cookies.get("token")
data = decode_token(token)
if data is not None and "id" in data:
user = Users.get_user_by_id(data["id"])
return {
"status": True,
"name": WEBUI_NAME,
"version": VERSION,
"default_locale": str(DEFAULT_LOCALE),
"default_models": webui_app.state.config.DEFAULT_MODELS,
"default_prompt_suggestions": webui_app.state.config.DEFAULT_PROMPT_SUGGESTIONS,
"features": {
"auth": WEBUI_AUTH,
"auth_trusted_header": bool(webui_app.state.AUTH_TRUSTED_EMAIL_HEADER),
"enable_signup": webui_app.state.config.ENABLE_SIGNUP,
"enable_login_form": webui_app.state.config.ENABLE_LOGIN_FORM,
"enable_web_search": rag_app.state.config.ENABLE_RAG_WEB_SEARCH,
"enable_image_generation": images_app.state.config.ENABLED,
"enable_community_sharing": webui_app.state.config.ENABLE_COMMUNITY_SHARING,
"enable_admin_export": ENABLE_ADMIN_EXPORT,
"enable_admin_chat_access": ENABLE_ADMIN_CHAT_ACCESS,
},
"audio": {
"tts": {
"engine": audio_app.state.config.TTS_ENGINE,
"voice": audio_app.state.config.TTS_VOICE,
},
"stt": {
"engine": audio_app.state.config.STT_ENGINE,
},
},
"oauth": {
"providers": {
name: config.get("name", name)
for name, config in OAUTH_PROVIDERS.items()
}
},
"features": {
"auth": WEBUI_AUTH,
"auth_trusted_header": bool(webui_app.state.AUTH_TRUSTED_EMAIL_HEADER),
"enable_signup": webui_app.state.config.ENABLE_SIGNUP,
"enable_login_form": webui_app.state.config.ENABLE_LOGIN_FORM,
**(
{
"enable_web_search": rag_app.state.config.ENABLE_RAG_WEB_SEARCH,
"enable_image_generation": images_app.state.config.ENABLED,
"enable_community_sharing": webui_app.state.config.ENABLE_COMMUNITY_SHARING,
"enable_message_rating": webui_app.state.config.ENABLE_MESSAGE_RATING,
"enable_admin_export": ENABLE_ADMIN_EXPORT,
"enable_admin_chat_access": ENABLE_ADMIN_CHAT_ACCESS,
}
if user is not None
else {}
),
},
**(
{
"default_models": webui_app.state.config.DEFAULT_MODELS,
"default_prompt_suggestions": webui_app.state.config.DEFAULT_PROMPT_SUGGESTIONS,
"audio": {
"tts": {
"engine": audio_app.state.config.TTS_ENGINE,
"voice": audio_app.state.config.TTS_VOICE,
},
"stt": {
"engine": audio_app.state.config.STT_ENGINE,
},
},
"permissions": {**webui_app.state.config.USER_PERMISSIONS},
}
if user is not None
else {}
),
}

View File

@@ -1,5 +1,5 @@
fastapi==0.111.0
uvicorn[standard]==0.22.0
uvicorn[standard]==0.30.6
pydantic==2.8.2
python-multipart==0.0.9
@@ -13,17 +13,17 @@ passlib[bcrypt]==1.7.4
requests==2.32.3
aiohttp==3.10.2
sqlalchemy==2.0.31
sqlalchemy==2.0.32
alembic==1.13.2
peewee==3.17.6
peewee-migrate==1.12.2
psycopg2-binary==2.9.9
PyMySQL==1.1.1
bcrypt==4.1.3
bcrypt==4.2.0
pymongo
redis
boto3==1.34.153
boto3==1.35.0
argon2-cffi==23.1.0
APScheduler==3.10.4
@@ -60,7 +60,7 @@ rapidocr-onnxruntime==1.3.24
fpdf2==2.7.9
rank-bm25==0.2.2
faster-whisper==1.0.2
faster-whisper==1.0.3
PyJWT[crypto]==2.9.0
authlib==1.3.1

Binary file not shown.