mirror of
https://github.com/open-webui/pipelines
synced 2025-05-11 08:01:08 +00:00
Merge branch 'open-webui:main' into routellm-pipeline
This commit is contained in:
commit
1db3cf7245
@ -6,4 +6,4 @@
|
||||
|
||||
# Runs the containers with Ollama image for Open WebUI and the Pipelines endpoint in place
|
||||
docker run -d -p 9099:9099 --add-host=host.docker.internal:host-gateway -v pipelines:/app/pipelines --name pipelines --restart always --env-file .env ghcr.io/open-webui/pipelines:latest
|
||||
docker run -d -p 3000:8080 -v ~/.ollama:/root/.ollama -v open-webui:/app/backend/data --name open-webui --restart always -e OPENAI_API_BASE_URL=http://host.docker.internal:9099 -e OPENAI_API_KEY=0p3n-w3bu! ghcr.io/open-webui/open-webui:ollama
|
||||
docker run -d -p 3000:8080 -p 11434:11434 --add-host=host.docker.internal:host-gateway -v ~/.ollama:/root/.ollama -v open-webui:/app/backend/data --name open-webui --restart always -e OPENAI_API_BASE_URL=http://host.docker.internal:9099 -e OPENAI_API_KEY=0p3n-w3bu! -e OLLAMA_HOST=0.0.0.0 ghcr.io/open-webui/open-webui:ollama
|
@ -5,7 +5,7 @@ date: 2024-06-15
|
||||
version: 1.0
|
||||
license: MIT
|
||||
description: A pipeline for controlling Home Assistant entities based on their easy names. Only supports lights at the moment.
|
||||
requirements: pytz, difflab
|
||||
requirements: pytz, difflib
|
||||
"""
|
||||
import requests
|
||||
from typing import Literal, Dict, Any
|
||||
@ -113,4 +113,4 @@ class Pipeline(FunctionCallingBlueprint):
|
||||
"pipelines": ["*"], # Connect to all pipelines
|
||||
},
|
||||
)
|
||||
self.tools = self.Tools(self)
|
||||
self.tools = self.Tools(self)
|
||||
|
181
examples/pipelines/providers/aws_bedrock_claude_pipeline.py
Normal file
181
examples/pipelines/providers/aws_bedrock_claude_pipeline.py
Normal file
@ -0,0 +1,181 @@
|
||||
"""
|
||||
title: AWS Bedrock Claude Pipeline
|
||||
author: G-mario
|
||||
date: 2024-08-18
|
||||
version: 1.0
|
||||
license: MIT
|
||||
description: A pipeline for generating text and processing images using the AWS Bedrock API(By Anthropic claude).
|
||||
requirements: requests, boto3
|
||||
environment_variables: AWS_ACCESS_KEY, AWS_SECRET_KEY, AWS_REGION_NAME
|
||||
"""
|
||||
import base64
|
||||
import json
|
||||
import logging
|
||||
from io import BytesIO
|
||||
from typing import List, Union, Generator, Iterator
|
||||
|
||||
import boto3
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
import os
|
||||
import requests
|
||||
|
||||
from utils.pipelines.main import pop_system_message
|
||||
|
||||
|
||||
class Pipeline:
|
||||
class Valves(BaseModel):
|
||||
AWS_ACCESS_KEY: str = ""
|
||||
AWS_SECRET_KEY: str = ""
|
||||
AWS_REGION_NAME: str = ""
|
||||
|
||||
def __init__(self):
|
||||
self.type = "manifold"
|
||||
# Optionally, you can set the id and name of the pipeline.
|
||||
# Best practice is to not specify the id so that it can be automatically inferred from the filename, so that users can install multiple versions of the same pipeline.
|
||||
# The identifier must be unique across all pipelines.
|
||||
# The identifier must be an alphanumeric string that can include underscores or hyphens. It cannot contain spaces, special characters, slashes, or backslashes.
|
||||
# self.id = "openai_pipeline"
|
||||
self.name = "Bedrock: "
|
||||
|
||||
self.valves = self.Valves(
|
||||
**{
|
||||
"AWS_ACCESS_KEY": os.getenv("AWS_ACCESS_KEY", "your-aws-access-key-here"),
|
||||
"AWS_SECRET_KEY": os.getenv("AWS_SECRET_KEY", "your-aws-secret-key-here"),
|
||||
"AWS_REGION_NAME": os.getenv("AWS_REGION_NAME", "your-aws-region-name-here"),
|
||||
}
|
||||
)
|
||||
|
||||
self.bedrock = boto3.client(aws_access_key_id=self.valves.AWS_ACCESS_KEY,
|
||||
aws_secret_access_key=self.valves.AWS_SECRET_KEY,
|
||||
service_name="bedrock",
|
||||
region_name=self.valves.AWS_REGION_NAME)
|
||||
self.bedrock_runtime = boto3.client(aws_access_key_id=self.valves.AWS_ACCESS_KEY,
|
||||
aws_secret_access_key=self.valves.AWS_SECRET_KEY,
|
||||
service_name="bedrock-runtime",
|
||||
region_name=self.valves.AWS_REGION_NAME)
|
||||
|
||||
self.pipelines = self.get_models()
|
||||
|
||||
|
||||
async def on_startup(self):
|
||||
# This function is called when the server is started.
|
||||
print(f"on_startup:{__name__}")
|
||||
pass
|
||||
|
||||
async def on_shutdown(self):
|
||||
# This function is called when the server is stopped.
|
||||
print(f"on_shutdown:{__name__}")
|
||||
pass
|
||||
|
||||
async def on_valves_updated(self):
|
||||
# This function is called when the valves are updated.
|
||||
print(f"on_valves_updated:{__name__}")
|
||||
self.bedrock = boto3.client(aws_access_key_id=self.valves.AWS_ACCESS_KEY,
|
||||
aws_secret_access_key=self.valves.AWS_SECRET_KEY,
|
||||
service_name="bedrock",
|
||||
region_name=self.valves.AWS_REGION_NAME)
|
||||
self.bedrock_runtime = boto3.client(aws_access_key_id=self.valves.AWS_ACCESS_KEY,
|
||||
aws_secret_access_key=self.valves.AWS_SECRET_KEY,
|
||||
service_name="bedrock-runtime",
|
||||
region_name=self.valves.AWS_REGION_NAME)
|
||||
self.pipelines = self.get_models()
|
||||
|
||||
def pipelines(self) -> List[dict]:
|
||||
return self.get_models()
|
||||
|
||||
def get_models(self):
|
||||
if self.valves.AWS_ACCESS_KEY and self.valves.AWS_SECRET_KEY:
|
||||
try:
|
||||
response = self.bedrock.list_foundation_models(byProvider='Anthropic', byInferenceType='ON_DEMAND')
|
||||
return [
|
||||
{
|
||||
"id": model["modelId"],
|
||||
"name": model["modelName"],
|
||||
}
|
||||
for model in response["modelSummaries"]
|
||||
]
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
return [
|
||||
{
|
||||
"id": "error",
|
||||
"name": "Could not fetch models from Bedrock, please update the Access/Secret Key in the valves.",
|
||||
},
|
||||
]
|
||||
else:
|
||||
return []
|
||||
|
||||
def pipe(
|
||||
self, user_message: str, model_id: str, messages: List[dict], body: dict
|
||||
) -> Union[str, Generator, Iterator]:
|
||||
# This is where you can add your custom pipelines like RAG.
|
||||
print(f"pipe:{__name__}")
|
||||
|
||||
system_message, messages = pop_system_message(messages)
|
||||
|
||||
logging.info(f"pop_system_message: {json.dumps(messages)}")
|
||||
|
||||
try:
|
||||
processed_messages = []
|
||||
image_count = 0
|
||||
for message in messages:
|
||||
processed_content = []
|
||||
if isinstance(message.get("content"), list):
|
||||
for item in message["content"]:
|
||||
if item["type"] == "text":
|
||||
processed_content.append({"text": item["text"]})
|
||||
elif item["type"] == "image_url":
|
||||
if image_count >= 20:
|
||||
raise ValueError("Maximum of 20 images per API call exceeded")
|
||||
processed_image = self.process_image(item["image_url"])
|
||||
processed_content.append(processed_image)
|
||||
image_count += 1
|
||||
else:
|
||||
processed_content = [{"text": message.get("content", "")}]
|
||||
|
||||
processed_messages.append({"role": message["role"], "content": processed_content})
|
||||
|
||||
payload = {"modelId": model_id,
|
||||
"messages": processed_messages,
|
||||
"system": [{'text': system_message if system_message else 'you are an intelligent ai assistant'}],
|
||||
"inferenceConfig": {"temperature": body.get("temperature", 0.5)},
|
||||
"additionalModelRequestFields": {"top_k": body.get("top_k", 200), "top_p": body.get("top_p", 0.9)}
|
||||
}
|
||||
if body.get("stream", False):
|
||||
return self.stream_response(model_id, payload)
|
||||
else:
|
||||
return self.get_completion(model_id, payload)
|
||||
except Exception as e:
|
||||
return f"Error: {e}"
|
||||
|
||||
def process_image(self, image: str):
|
||||
img_stream = None
|
||||
if image["url"].startswith("data:image"):
|
||||
if ',' in image["url"]:
|
||||
base64_string = image["url"].split(',')[1]
|
||||
image_data = base64.b64decode(base64_string)
|
||||
|
||||
img_stream = BytesIO(image_data)
|
||||
else:
|
||||
img_stream = requests.get(image["url"]).content
|
||||
return {
|
||||
"image": {"format": "png" if image["url"].endswith(".png") else "jpeg",
|
||||
"source": {"bytes": img_stream.read()}}
|
||||
}
|
||||
|
||||
def stream_response(self, model_id: str, payload: dict) -> Generator:
|
||||
if "system" in payload:
|
||||
del payload["system"]
|
||||
if "additionalModelRequestFields" in payload:
|
||||
del payload["additionalModelRequestFields"]
|
||||
streaming_response = self.bedrock_runtime.converse_stream(**payload)
|
||||
for chunk in streaming_response["stream"]:
|
||||
if "contentBlockDelta" in chunk:
|
||||
yield chunk["contentBlockDelta"]["delta"]["text"]
|
||||
|
||||
def get_completion(self, model_id: str, payload: dict) -> str:
|
||||
response = self.bedrock_runtime.converse(**payload)
|
||||
return response['output']['message']['content'][0]['text']
|
||||
|
@ -56,8 +56,8 @@ class Pipeline:
|
||||
url = f"{self.valves.AZURE_OPENAI_ENDPOINT}/openai/deployments/{self.valves.AZURE_OPENAI_DEPLOYMENT_NAME}/chat/completions?api-version={self.valves.AZURE_OPENAI_API_VERSION}"
|
||||
|
||||
allowed_params = {'messages', 'temperature', 'role', 'content', 'contentPart', 'contentPartImage',
|
||||
'enhancements', 'dataSources', 'n', 'stream', 'stop', 'max_tokens', 'presence_penalty',
|
||||
'frequency_penalty', 'logit_bias', 'user', 'function_call', 'funcions', 'tools',
|
||||
'enhancements', 'data_sources', 'n', 'stream', 'stop', 'max_tokens', 'presence_penalty',
|
||||
'frequency_penalty', 'logit_bias', 'user', 'function_call', 'functions', 'tools',
|
||||
'tool_choice', 'top_p', 'log_probs', 'top_logprobs', 'response_format', 'seed'}
|
||||
# remap user field
|
||||
if "user" in body and not isinstance(body["user"], str):
|
||||
@ -67,6 +67,8 @@ class Pipeline:
|
||||
if len(body) != len(filtered_body):
|
||||
print(f"Dropped params: {', '.join(set(body.keys()) - set(filtered_body.keys()))}")
|
||||
|
||||
# Initialize the response variable to None.
|
||||
r = None
|
||||
try:
|
||||
r = requests.post(
|
||||
url=url,
|
||||
|
83
examples/pipelines/providers/cloudflare_ai_pipeline.py
Normal file
83
examples/pipelines/providers/cloudflare_ai_pipeline.py
Normal file
@ -0,0 +1,83 @@
|
||||
from typing import List, Union, Generator, Iterator
|
||||
from schemas import OpenAIChatMessage
|
||||
from pydantic import BaseModel
|
||||
import os
|
||||
import requests
|
||||
|
||||
|
||||
class Pipeline:
|
||||
class Valves(BaseModel):
|
||||
CLOUDFLARE_ACCOUNT_ID: str = ""
|
||||
CLOUDFLARE_API_KEY: str = ""
|
||||
CLOUDFLARE_MODEL: str = ""
|
||||
pass
|
||||
|
||||
def __init__(self):
|
||||
# Optionally, you can set the id and name of the pipeline.
|
||||
# Best practice is to not specify the id so that it can be automatically inferred from the filename, so that users can install multiple versions of the same pipeline.
|
||||
# The identifier must be unique across all pipelines.
|
||||
# The identifier must be an alphanumeric string that can include underscores or hyphens. It cannot contain spaces, special characters, slashes, or backslashes.
|
||||
# self.id = "openai_pipeline"
|
||||
self.name = "Cloudlfare AI"
|
||||
self.valves = self.Valves(
|
||||
**{
|
||||
"CLOUDFLARE_ACCOUNT_ID": os.getenv(
|
||||
"CLOUDFLARE_ACCOUNT_ID",
|
||||
"your-account-id",
|
||||
),
|
||||
"CLOUDFLARE_API_KEY": os.getenv(
|
||||
"CLOUDFLARE_API_KEY", "your-cloudflare-api-key"
|
||||
),
|
||||
"CLOUDFLARE_MODEL": os.getenv(
|
||||
"CLOUDFLARE_MODELS",
|
||||
"@cf/meta/llama-3.1-8b-instruct",
|
||||
),
|
||||
}
|
||||
)
|
||||
pass
|
||||
|
||||
async def on_startup(self):
|
||||
# This function is called when the server is started.
|
||||
print(f"on_startup:{__name__}")
|
||||
pass
|
||||
|
||||
async def on_shutdown(self):
|
||||
# This function is called when the server is stopped.
|
||||
print(f"on_shutdown:{__name__}")
|
||||
pass
|
||||
|
||||
def pipe(
|
||||
self, user_message: str, model_id: str, messages: List[dict], body: dict
|
||||
) -> Union[str, Generator, Iterator]:
|
||||
# This is where you can add your custom pipelines like RAG.
|
||||
print(f"pipe:{__name__}")
|
||||
|
||||
headers = {}
|
||||
headers["Authorization"] = f"Bearer {self.valves.CLOUDFLARE_API_KEY}"
|
||||
headers["Content-Type"] = "application/json"
|
||||
|
||||
payload = {**body, "model": self.valves.CLOUDFLARE_MODEL}
|
||||
|
||||
if "user" in payload:
|
||||
del payload["user"]
|
||||
if "chat_id" in payload:
|
||||
del payload["chat_id"]
|
||||
if "title" in payload:
|
||||
del payload["title"]
|
||||
|
||||
try:
|
||||
r = requests.post(
|
||||
url=f"https://api.cloudflare.com/client/v4/accounts/{self.valves.CLOUDFLARE_ACCOUNT_ID}/ai/v1/chat/completions",
|
||||
json=payload,
|
||||
headers=headers,
|
||||
stream=True,
|
||||
)
|
||||
|
||||
r.raise_for_status()
|
||||
|
||||
if body["stream"]:
|
||||
return r.iter_lines()
|
||||
else:
|
||||
return r.json()
|
||||
except Exception as e:
|
||||
return f"Error: {e}"
|
@ -1,8 +1,8 @@
|
||||
"""
|
||||
title: Llama Index DB Pipeline
|
||||
author: 0xThresh
|
||||
date: 2024-07-01
|
||||
version: 1.0
|
||||
date: 2024-08-11
|
||||
version: 1.1
|
||||
license: MIT
|
||||
description: A pipeline for using text-to-SQL for retrieving relevant information from a database using the Llama Index library.
|
||||
requirements: llama_index, sqlalchemy, psycopg2-binary
|
||||
@ -24,7 +24,7 @@ class Pipeline:
|
||||
DB_USER: str
|
||||
DB_PASSWORD: str
|
||||
DB_DATABASE: str
|
||||
DB_TABLES: list[str]
|
||||
DB_TABLE: str
|
||||
OLLAMA_HOST: str
|
||||
TEXT_TO_SQL_MODEL: str
|
||||
|
||||
@ -39,14 +39,14 @@ class Pipeline:
|
||||
self.valves = self.Valves(
|
||||
**{
|
||||
"pipelines": ["*"], # Connect to all pipelines
|
||||
"DB_HOST": os.getenv("PG_HOST", "http://localhost:5432"), # Database hostname
|
||||
"DB_PORT": os.getenv("PG_PORT", 5432), # Database port
|
||||
"DB_USER": os.getenv("PG_USER", "postgres"), # User to connect to the database with
|
||||
"DB_PASSWORD": os.getenv("PG_PASSWORD", "password"), # Password to connect to the database with
|
||||
"DB_DATABASE": os.getenv("PG_DB", "postgres"), # Database to select on the DB instance
|
||||
"DB_TABLES": ["albums"], # Table(s) to run queries against
|
||||
"DB_HOST": os.getenv("DB_HOST", "http://localhost"), # Database hostname
|
||||
"DB_PORT": os.getenv("DB_PORT", 5432), # Database port
|
||||
"DB_USER": os.getenv("DB_USER", "postgres"), # User to connect to the database with
|
||||
"DB_PASSWORD": os.getenv("DB_PASSWORD", "password"), # Password to connect to the database with
|
||||
"DB_DATABASE": os.getenv("DB_DATABASE", "postgres"), # Database to select on the DB instance
|
||||
"DB_TABLE": os.getenv("DB_TABLE", "table_name"), # Table(s) to run queries against
|
||||
"OLLAMA_HOST": os.getenv("OLLAMA_HOST", "http://host.docker.internal:11434"), # Make sure to update with the URL of your Ollama host, such as http://localhost:11434 or remote server address
|
||||
"TEXT_TO_SQL_MODEL": "phi3:latest" # Model to use for text-to-SQL generation
|
||||
"TEXT_TO_SQL_MODEL": os.getenv("TEXT_TO_SQL_MODEL", "llama3.1:latest") # Model to use for text-to-SQL generation
|
||||
}
|
||||
)
|
||||
|
||||
@ -69,7 +69,7 @@ class Pipeline:
|
||||
# Debug logging is required to see what SQL query is generated by the LlamaIndex library; enable on Pipelines server if needed
|
||||
|
||||
# Create database reader for Postgres
|
||||
sql_database = SQLDatabase(self.engine, include_tables=self.valves.DB_TABLES)
|
||||
sql_database = SQLDatabase(self.engine, include_tables=[self.valves.DB_TABLE])
|
||||
|
||||
# Set up LLM connection; uses phi3 model with 128k context limit since some queries have returned 20k+ tokens
|
||||
llm = Ollama(model=self.valves.TEXT_TO_SQL_MODEL, base_url=self.valves.OLLAMA_HOST, request_timeout=180.0, context_window=30000)
|
||||
@ -99,7 +99,7 @@ class Pipeline:
|
||||
|
||||
query_engine = NLSQLTableQueryEngine(
|
||||
sql_database=sql_database,
|
||||
tables=self.valves.DB_TABLES,
|
||||
tables=[self.valves.DB_TABLE],
|
||||
llm=llm,
|
||||
embed_model="local",
|
||||
text_to_sql_prompt=text_to_sql_template,
|
||||
|
Loading…
Reference in New Issue
Block a user