Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
ReinderVosDeWael committed Nov 1, 2024
0 parents commit e75131a
Show file tree
Hide file tree
Showing 7 changed files with 4,864 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.venv
.pytst_cache
.github
local
1 change: 1 addition & 0 deletions .python-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.12
5 changes: 5 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
FROM ghcr.io/open-webui/open-webui

RUN pip install anthropic

CMD [ "bash", "start.sh"]
Empty file added README.md
Empty file.
118 changes: 118 additions & 0 deletions functions/pipe_anthropic_bedrock.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
"""Pipeline for Bedrock Anthropic.""" # noqa: INP001

import os
from collections.abc import Generator
from typing import Any

import anthropic
import pydantic
from open_webui.utils import misc as open_webui_misc


class Pipe:
"""Anthropic Bedrock Connector."""

class Valves(pydantic.BaseModel):
"""Variables exposed via the admin UI."""

AWS_ACCESS_KEY: str = os.getenv("AWS_ACCESS_KEY")
AWS_SECRET_ACCESS_KEY: str = os.getenv("AWS_SECRET_KEY")
AWS_REGION: str = os.getenv("AWS_REGION")

def __init__(self) -> None:
"""Initialize the pipe."""
self.type = "manifold"
self.name = "Anthropic - "
self.valves = self.Valves()

def pipes(self) -> list[dict[str, str]]:
"""List of models to include."""
return [
{
"id": "anthropic.claude-3-5-sonnet-20241022-v2:0",
"name": "Claude 3.5 Sonnet V2",
},
]

def process_image(self, image_data: dict[str, Any]) -> dict[str, Any]:
"""Converts images into a format accepted by Claude."""
if image_data["image_url"]["url"].startswith("data:image"):
mime_type, base64_data = image_data["image_url"]["url"].split(",", 1)
media_type = mime_type.split(":")[1].split(";")[0]
return {
"type": "image",
"source": {
"type": "base64",
"media_type": media_type,
"data": base64_data,
},
}
return {
"type": "image",
"source": {"type": "url", "url": image_data["image_url"]["url"]},
}

def pipe(self, body: dict) -> Generator[str, None, None]:
"""Main runner of the pipe.
Args:
body: The request as provided by Open WebUI.
Returns:
A string or iterable string.
"""
system_message, messages = open_webui_misc.pop_system_message(body["messages"])
if system_message is None:
system_message = {"content": ""}

processed_messages = []
image_count = 0
total_image_size = 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({"type": "text", "text": item["text"]})
elif item["type"] == "image_url":
if image_count >= 5: # noqa: PLR2004
msg = "Maximum of 5 images per API call exceeded"
raise ValueError(msg)

processed_image = self.process_image(item)
processed_content.append(processed_image)

if processed_image["source"]["type"] == "base64":
image_size = len(processed_image["source"]["data"]) * 3 / 4
else:
image_size = 0

total_image_size += image_size
if total_image_size > 100 * 1024 * 1024:
msg = "Total size of images exceeds 100 MB limit"
raise ValueError(msg)
image_count += 1
else:
processed_content = [
{"type": "text", "text": message.get("content", "")},
]

processed_messages.append(
{"role": message["role"], "content": processed_content},
)

client = anthropic.AnthropicBedrock(
aws_access_key=self.valves.AWS_ACCESS_KEY,
aws_secret_key=self.valves.AWS_SECRET_ACCESS_KEY,
aws_region=self.valves.AWS_REGION,
)

model = body["model"][body["model"].find(".") + 1 :]
with client.messages.stream(
system=system_message["content"],
model=model,
messages=processed_messages,
max_tokens=8192,
) as stream:
yield from stream.text_stream
66 changes: 66 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
[project]
name = "jade"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.12"
dependencies = [
"anthropic>=0.37.1",
"open-webui>=0.3.35",
]

[tool.ruff]
exclude = [
".bzr",
".direnv",
".eggs",
".git",
".git-rewrite",
".hg",
".mypy_cache",
".nox",
".pants.d",
".pytype",
".ruff_cache",
".svn",
".tox",
".venv",
"__pypackages__",
"_build",
"buck-out",
"build",
"dist",
"node_modules",
"venv"
]
line-length = 88
indent-width = 4
src = ["src"]
target-version = "py311"

[tool.ruff.lint]
select = ["ALL"]
ignore = [
"ANN101", # self should not be annotated.
"ANN102" # cls should not be annotated.
]
fixable = ["ALL"]
unfixable = []
dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"

[tool.ruff.lint.pydocstyle]
convention = "google"

[tool.ruff.lint.per-file-ignores]
"tests/**/*.py" = [
"S101", # asserts should be used in pytest
"SLF001", # accessing private members in tests is fine
"INP001" # tests should not be a module
]
"local/**/*" = ["ALL"]

[tool.ruff.format]
quote-style = "double"
indent-style = "space"
skip-magic-trailing-comma = false
line-ending = "auto"
Loading

0 comments on commit e75131a

Please sign in to comment.