This commit is contained in:
Timothy Jaeryang Baek
2026-07-23 12:48:14 -04:00
parent 8ace4f0a8a
commit f9107edeeb
3 changed files with 44 additions and 33 deletions
+18 -8
View File
@@ -7,7 +7,7 @@ import time
# local imports
from open_webui.internal.db import Base, JSONField, get_async_db_context
from open_webui.models.users import UserResponse, Users
from open_webui.models.users import User, UserResponse, Users, UserSettings
from open_webui.utils.valves import decrypt_valves, encrypt_valves
from pydantic import BaseModel, ConfigDict
from sqlalchemy import BigInteger, Boolean, Column, Index, String, Text, delete, select, update
@@ -275,6 +275,12 @@ class FunctionsTable:
result = await db.execute(select(Function).filter_by(type='filter', is_active=True, is_global=True))
return [FunctionModel.model_validate(function) for function in result.scalars().all()]
async def get_active_filter_ids(self, db: AsyncSession | None = None) -> list[tuple[str, bool]]:
"""Return (id, is_global) for active filters without fetching plugin source."""
async with get_async_db_context(db) as db:
result = await db.execute(select(Function.id, Function.is_global).filter_by(type='filter', is_active=True))
return [(id, bool(is_global)) for id, is_global in result.all()]
async def get_global_action_functions(self, db: AsyncSession | None = None) -> list[FunctionModel]:
async with get_async_db_context(db) as db:
result = await db.execute(select(Function).filter_by(type='action', is_active=True, is_global=True))
@@ -283,13 +289,15 @@ class FunctionsTable:
async def get_function_valves_by_id(self, id: str, db: AsyncSession | None = None) -> dict | None:
async with get_async_db_context(db) as db:
try:
function = await db.get(Function, id)
return decrypt_valves(function.valves if function else None)
result = await db.execute(select(Function.valves).filter_by(id=id))
return decrypt_valves(result.scalar_one_or_none())
except Exception as e:
log.exception(f'Error getting function valves by id {id}: {e}')
return None
async def get_function_valves_by_ids(self, ids: list[str], db: AsyncSession | None = None) -> dict[str, dict]:
async def get_function_valves_by_ids(
self, ids: list[str], db: AsyncSession | None = None
) -> dict[str, dict]:
"""
Batch fetch valves for multiple functions in a single query.
Returns a dict mapping function_id -> valves dict.
@@ -300,8 +308,7 @@ class FunctionsTable:
try:
async with get_async_db_context(db) as db:
result = await db.execute(select(Function.id, Function.valves).filter(Function.id.in_(ids)))
functions = result.all()
return {f.id: decrypt_valves(f.valves) for f in functions}
return {id: decrypt_valves(valves) for id, valves in result.all()}
except Exception as e:
log.exception(f'Error batch-fetching function valves: {e}')
return {}
@@ -347,8 +354,11 @@ class FunctionsTable:
self, id: str, user_id: str, db: AsyncSession | None = None
) -> dict | None:
try:
user = await Users.get_user_by_id(user_id, db=db)
user_settings = user.settings.model_dump() if user.settings else {}
async with get_async_db_context(db) as db:
result = await db.execute(select(User.settings).filter_by(id=user_id))
settings = result.scalar_one_or_none()
user_settings = UserSettings(**settings).model_dump() if settings else {}
# Check if user has "functions" and "valves" settings
if 'functions' not in user_settings:
+23 -21
View File
@@ -3,10 +3,7 @@ import logging
from open_webui.env import ENABLE_PLUGINS
from open_webui.models.functions import Functions
from open_webui.utils.plugin import (
get_function_module_from_cache,
load_function_module_by_id,
)
from open_webui.utils.plugin import get_function_module_from_cache
log = logging.getLogger(__name__)
@@ -23,22 +20,12 @@ async def get_sorted_filter_ids(request, model: dict, enabled_filter_ids: list =
if not ENABLE_PLUGINS:
return []
async def get_priority(function_id):
try:
function_module = await get_function_module(request, function_id)
if function_module and hasattr(function_module, 'Valves'):
valves_db = await Functions.get_function_valves_by_id(function_id)
valves = function_module.Valves(**(valves_db if valves_db else {}))
return getattr(valves, 'priority', 0)
except Exception:
pass
return 0
filter_ids = [function.id for function in await Functions.get_global_filter_functions()]
active_filters = await Functions.get_active_filter_ids()
filter_ids = [fid for fid, is_global in active_filters if is_global]
if 'info' in model and 'meta' in model['info']:
filter_ids.extend(model['info']['meta'].get('filterIds', []))
filter_ids = list(set(filter_ids))
active_filter_ids = {function.id for function in await Functions.get_functions_by_type('filter', active_only=True)}
active_filter_ids = {fid for fid, _ in active_filters}
async def get_active_status(filter_id):
function_module = await get_function_module(request, filter_id)
@@ -55,6 +42,18 @@ async def get_sorted_filter_ids(request, model: dict, enabled_filter_ids: list =
active_filter_ids = {fid for fid, is_active in resolved_active.items() if is_active}
filter_ids = [fid for fid in filter_ids if fid in active_filter_ids]
valves_by_id = await Functions.get_function_valves_by_ids(filter_ids)
async def get_priority(function_id):
try:
function_module = await get_function_module(request, function_id)
if function_module and hasattr(function_module, 'Valves'):
valves_db = valves_by_id.get(function_id)
valves = function_module.Valves(**(valves_db if valves_db else {}))
return getattr(valves, 'priority', 0)
except Exception:
pass
return 0
# Pre-compute priorities (async functions can't be used in sort keys)
priorities = {}
@@ -72,12 +71,13 @@ async def process_filter_functions(request, filter_functions, filter_type, form_
return form_data, {}
skip_files = None
valves_by_id = None
filter_ids = [function.id for function in filter_functions if function]
for function in filter_functions:
filter = function
filter_id = function.id
if not filter:
if not function:
continue
filter_id = function.id
function_module = await get_function_module(request, filter_id, load_from_db=(filter_type != 'stream'))
# Prepare handler function
@@ -91,7 +91,9 @@ async def process_filter_functions(request, filter_functions, filter_type, form_
# Apply valves to the function
if hasattr(function_module, 'valves') and hasattr(function_module, 'Valves'):
valves = await Functions.get_function_valves_by_id(filter_id)
if valves_by_id is None:
valves_by_id = await Functions.get_function_valves_by_ids(filter_ids)
valves = valves_by_id.get(filter_id)
function_module.valves = function_module.Valves(**(valves if valves else {}))
try:
+3 -4
View File
@@ -3709,10 +3709,9 @@ async def streaming_chat_response_handler(response, ctx):
}
filter_functions = (
[
await Functions.get_function_by_id(filter_id)
for filter_id in await get_sorted_filter_ids(request, model, metadata.get('filter_ids', []))
]
await Functions.get_functions_by_ids(
await get_sorted_filter_ids(request, model, metadata.get('filter_ids', []))
)
if ENABLE_PLUGINS
else []
)