wip
This commit is contained in:
@@ -941,7 +941,7 @@ async def get_ollama_url(request: Request, model: str, url_idx: Optional[int] =
|
||||
@router.post("/api/chat/{url_idx}")
|
||||
async def generate_chat_completion(
|
||||
request: Request,
|
||||
form_data: GenerateChatCompletionForm,
|
||||
form_data: dict,
|
||||
url_idx: Optional[int] = None,
|
||||
user=Depends(get_verified_user),
|
||||
bypass_filter: Optional[bool] = False,
|
||||
@@ -949,6 +949,15 @@ async def generate_chat_completion(
|
||||
if BYPASS_MODEL_ACCESS_CONTROL:
|
||||
bypass_filter = True
|
||||
|
||||
try:
|
||||
form_data = GenerateChatCompletionForm(**form_data)
|
||||
except Exception as e:
|
||||
log.exception(e)
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail=str(e),
|
||||
)
|
||||
|
||||
payload = {**form_data.model_dump(exclude_none=True)}
|
||||
if "metadata" in payload:
|
||||
del payload["metadata"]
|
||||
|
||||
@@ -30,6 +30,130 @@ log = logging.getLogger(__name__)
|
||||
log.setLevel(SRC_LOG_LEVELS["MAIN"])
|
||||
|
||||
|
||||
##################################
|
||||
#
|
||||
# Pipeline Middleware
|
||||
#
|
||||
##################################
|
||||
|
||||
|
||||
def get_sorted_filters(model_id, models):
|
||||
filters = [
|
||||
model
|
||||
for model in models.values()
|
||||
if "pipeline" in model
|
||||
and "type" in model["pipeline"]
|
||||
and model["pipeline"]["type"] == "filter"
|
||||
and (
|
||||
model["pipeline"]["pipelines"] == ["*"]
|
||||
or any(
|
||||
model_id == target_model_id
|
||||
for target_model_id in model["pipeline"]["pipelines"]
|
||||
)
|
||||
)
|
||||
]
|
||||
sorted_filters = sorted(filters, key=lambda x: x["pipeline"]["priority"])
|
||||
return sorted_filters
|
||||
|
||||
|
||||
def process_pipeline_inlet_filter(request, payload, user, models):
|
||||
user = {"id": user.id, "email": user.email, "name": user.name, "role": user.role}
|
||||
model_id = payload["model"]
|
||||
|
||||
sorted_filters = get_sorted_filters(model_id, models)
|
||||
model = models[model_id]
|
||||
|
||||
if "pipeline" in model:
|
||||
sorted_filters.append(model)
|
||||
|
||||
for filter in sorted_filters:
|
||||
r = None
|
||||
try:
|
||||
urlIdx = filter["urlIdx"]
|
||||
|
||||
url = request.app.state.config.OPENAI_API_BASE_URLS[urlIdx]
|
||||
key = request.app.state.config.OPENAI_API_KEYS[urlIdx]
|
||||
|
||||
if key == "":
|
||||
continue
|
||||
|
||||
headers = {"Authorization": f"Bearer {key}"}
|
||||
r = requests.post(
|
||||
f"{url}/{filter['id']}/filter/inlet",
|
||||
headers=headers,
|
||||
json={
|
||||
"user": user,
|
||||
"body": payload,
|
||||
},
|
||||
)
|
||||
|
||||
r.raise_for_status()
|
||||
payload = r.json()
|
||||
except Exception as e:
|
||||
# Handle connection error here
|
||||
print(f"Connection error: {e}")
|
||||
|
||||
if r is not None:
|
||||
res = r.json()
|
||||
if "detail" in res:
|
||||
raise Exception(r.status_code, res["detail"])
|
||||
|
||||
return payload
|
||||
|
||||
|
||||
def process_pipeline_outlet_filter(request, payload, user, models):
|
||||
user = {"id": user.id, "email": user.email, "name": user.name, "role": user.role}
|
||||
model_id = payload["model"]
|
||||
|
||||
sorted_filters = get_sorted_filters(model_id, models)
|
||||
model = models[model_id]
|
||||
|
||||
if "pipeline" in model:
|
||||
sorted_filters = [model] + sorted_filters
|
||||
|
||||
for filter in sorted_filters:
|
||||
r = None
|
||||
try:
|
||||
urlIdx = filter["urlIdx"]
|
||||
|
||||
url = request.app.state.config.OPENAI_API_BASE_URLS[urlIdx]
|
||||
key = request.app.state.config.OPENAI_API_KEYS[urlIdx]
|
||||
|
||||
if key != "":
|
||||
r = requests.post(
|
||||
f"{url}/{filter['id']}/filter/outlet",
|
||||
headers={"Authorization": f"Bearer {key}"},
|
||||
json={
|
||||
"user": {
|
||||
"id": user.id,
|
||||
"name": user.name,
|
||||
"email": user.email,
|
||||
"role": user.role,
|
||||
},
|
||||
"body": data,
|
||||
},
|
||||
)
|
||||
|
||||
r.raise_for_status()
|
||||
data = r.json()
|
||||
except Exception as e:
|
||||
# Handle connection error here
|
||||
print(f"Connection error: {e}")
|
||||
|
||||
if r is not None:
|
||||
try:
|
||||
res = r.json()
|
||||
if "detail" in res:
|
||||
return Exception(r.status_code, res)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
else:
|
||||
pass
|
||||
|
||||
return payload
|
||||
|
||||
|
||||
##################################
|
||||
#
|
||||
# Pipelines Endpoints
|
||||
@@ -39,7 +163,7 @@ log.setLevel(SRC_LOG_LEVELS["MAIN"])
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get("/api/pipelines/list")
|
||||
@router.get("/list")
|
||||
async def get_pipelines_list(request: Request, user=Depends(get_admin_user)):
|
||||
responses = await get_all_models_responses(request)
|
||||
log.debug(f"get_pipelines_list: get_openai_models_responses returned {responses}")
|
||||
@@ -61,7 +185,7 @@ async def get_pipelines_list(request: Request, user=Depends(get_admin_user)):
|
||||
}
|
||||
|
||||
|
||||
@router.post("/api/pipelines/upload")
|
||||
@router.post("/upload")
|
||||
async def upload_pipeline(
|
||||
request: Request,
|
||||
urlIdx: int = Form(...),
|
||||
@@ -131,7 +255,7 @@ class AddPipelineForm(BaseModel):
|
||||
urlIdx: int
|
||||
|
||||
|
||||
@router.post("/api/pipelines/add")
|
||||
@router.post("/add")
|
||||
async def add_pipeline(
|
||||
request: Request, form_data: AddPipelineForm, user=Depends(get_admin_user)
|
||||
):
|
||||
@@ -176,7 +300,7 @@ class DeletePipelineForm(BaseModel):
|
||||
urlIdx: int
|
||||
|
||||
|
||||
@router.delete("/api/pipelines/delete")
|
||||
@router.delete("/delete")
|
||||
async def delete_pipeline(
|
||||
request: Request, form_data: DeletePipelineForm, user=Depends(get_admin_user)
|
||||
):
|
||||
@@ -216,7 +340,7 @@ async def delete_pipeline(
|
||||
)
|
||||
|
||||
|
||||
@router.get("/api/pipelines")
|
||||
@router.get("/")
|
||||
async def get_pipelines(
|
||||
request: Request, urlIdx: Optional[int] = None, user=Depends(get_admin_user)
|
||||
):
|
||||
@@ -250,7 +374,7 @@ async def get_pipelines(
|
||||
)
|
||||
|
||||
|
||||
@router.get("/api/pipelines/{pipeline_id}/valves")
|
||||
@router.get("/{pipeline_id}/valves")
|
||||
async def get_pipeline_valves(
|
||||
request: Request,
|
||||
urlIdx: Optional[int],
|
||||
@@ -289,7 +413,7 @@ async def get_pipeline_valves(
|
||||
)
|
||||
|
||||
|
||||
@router.get("/api/pipelines/{pipeline_id}/valves/spec")
|
||||
@router.get("/{pipeline_id}/valves/spec")
|
||||
async def get_pipeline_valves_spec(
|
||||
request: Request,
|
||||
urlIdx: Optional[int],
|
||||
@@ -329,7 +453,7 @@ async def get_pipeline_valves_spec(
|
||||
)
|
||||
|
||||
|
||||
@router.post("/api/pipelines/{pipeline_id}/valves/update")
|
||||
@router.post("/{pipeline_id}/valves/update")
|
||||
async def update_pipeline_valves(
|
||||
request: Request,
|
||||
urlIdx: Optional[int],
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from fastapi import APIRouter, Depends, HTTPException, Response, status, Request
|
||||
from fastapi.responses import JSONResponse, RedirectResponse
|
||||
|
||||
from pydantic import BaseModel
|
||||
from starlette.responses import FileResponse
|
||||
from typing import Optional
|
||||
import logging
|
||||
|
||||
@@ -16,6 +17,9 @@ from open_webui.utils.task import (
|
||||
from open_webui.utils.auth import get_admin_user, get_verified_user
|
||||
from open_webui.constants import TASKS
|
||||
|
||||
from open_webui.routers.pipelines import process_pipeline_inlet_filter
|
||||
from open_webui.utils.task import get_task_model_id
|
||||
|
||||
from open_webui.config import (
|
||||
DEFAULT_QUERY_GENERATION_PROMPT_TEMPLATE,
|
||||
DEFAULT_AUTOCOMPLETE_GENERATION_PROMPT_TEMPLATE,
|
||||
@@ -121,9 +125,7 @@ async def update_task_config(
|
||||
async def generate_title(
|
||||
request: Request, form_data: dict, user=Depends(get_verified_user)
|
||||
):
|
||||
|
||||
model_list = await get_all_models()
|
||||
models = {model["id"]: model for model in model_list}
|
||||
models = request.app.state.MODELS
|
||||
|
||||
model_id = form_data["model"]
|
||||
if model_id not in models:
|
||||
@@ -191,7 +193,7 @@ Artificial Intelligence in Healthcare
|
||||
|
||||
# Handle pipeline filters
|
||||
try:
|
||||
payload = filter_pipeline(payload, user, models)
|
||||
payload = process_pipeline_inlet_filter(payload, user, models)
|
||||
except Exception as e:
|
||||
if len(e.args) > 1:
|
||||
return JSONResponse(
|
||||
@@ -220,8 +222,7 @@ async def generate_chat_tags(
|
||||
content={"detail": "Tags generation is disabled"},
|
||||
)
|
||||
|
||||
model_list = await get_all_models()
|
||||
models = {model["id"]: model for model in model_list}
|
||||
models = request.app.state.MODELS
|
||||
|
||||
model_id = form_data["model"]
|
||||
if model_id not in models:
|
||||
@@ -281,7 +282,7 @@ JSON format: { "tags": ["tag1", "tag2", "tag3"] }
|
||||
|
||||
# Handle pipeline filters
|
||||
try:
|
||||
payload = filter_pipeline(payload, user, models)
|
||||
payload = process_pipeline_inlet_filter(payload, user, models)
|
||||
except Exception as e:
|
||||
if len(e.args) > 1:
|
||||
return JSONResponse(
|
||||
@@ -318,8 +319,7 @@ async def generate_queries(
|
||||
detail=f"Query generation is disabled",
|
||||
)
|
||||
|
||||
model_list = await get_all_models()
|
||||
models = {model["id"]: model for model in model_list}
|
||||
models = request.app.state.MODELS
|
||||
|
||||
model_id = form_data["model"]
|
||||
if model_id not in models:
|
||||
@@ -363,7 +363,7 @@ async def generate_queries(
|
||||
|
||||
# Handle pipeline filters
|
||||
try:
|
||||
payload = filter_pipeline(payload, user, models)
|
||||
payload = process_pipeline_inlet_filter(payload, user, models)
|
||||
except Exception as e:
|
||||
if len(e.args) > 1:
|
||||
return JSONResponse(
|
||||
@@ -405,8 +405,7 @@ async def generate_autocompletion(
|
||||
detail=f"Input prompt exceeds maximum length of {request.app.state.config.AUTOCOMPLETE_GENERATION_INPUT_MAX_LENGTH}",
|
||||
)
|
||||
|
||||
model_list = await get_all_models()
|
||||
models = {model["id"]: model for model in model_list}
|
||||
models = request.app.state.MODELS
|
||||
|
||||
model_id = form_data["model"]
|
||||
if model_id not in models:
|
||||
@@ -450,7 +449,7 @@ async def generate_autocompletion(
|
||||
|
||||
# Handle pipeline filters
|
||||
try:
|
||||
payload = filter_pipeline(payload, user, models)
|
||||
payload = process_pipeline_inlet_filter(payload, user, models)
|
||||
except Exception as e:
|
||||
if len(e.args) > 1:
|
||||
return JSONResponse(
|
||||
@@ -473,8 +472,7 @@ async def generate_emoji(
|
||||
request: Request, form_data: dict, user=Depends(get_verified_user)
|
||||
):
|
||||
|
||||
model_list = await get_all_models()
|
||||
models = {model["id"]: model for model in model_list}
|
||||
models = request.app.state.MODELS
|
||||
|
||||
model_id = form_data["model"]
|
||||
if model_id not in models:
|
||||
@@ -525,7 +523,7 @@ Message: """{{prompt}}"""
|
||||
|
||||
# Handle pipeline filters
|
||||
try:
|
||||
payload = filter_pipeline(payload, user, models)
|
||||
payload = process_pipeline_inlet_filter(payload, user, models)
|
||||
except Exception as e:
|
||||
if len(e.args) > 1:
|
||||
return JSONResponse(
|
||||
@@ -548,10 +546,9 @@ async def generate_moa_response(
|
||||
request: Request, form_data: dict, user=Depends(get_verified_user)
|
||||
):
|
||||
|
||||
model_list = await get_all_models()
|
||||
models = {model["id"]: model for model in model_list}
|
||||
|
||||
models = request.app.state.MODELS
|
||||
model_id = form_data["model"]
|
||||
|
||||
if model_id not in models:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
@@ -593,7 +590,7 @@ Responses from models: {{responses}}"""
|
||||
}
|
||||
|
||||
try:
|
||||
payload = filter_pipeline(payload, user, models)
|
||||
payload = process_pipeline_inlet_filter(payload, user, models)
|
||||
except Exception as e:
|
||||
if len(e.args) > 1:
|
||||
return JSONResponse(
|
||||
|
||||
Reference in New Issue
Block a user