Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(media): broaden content type support #1011

Merged
merged 17 commits into from
Nov 28, 2024
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,10 @@ jobs:
fail-fast: false
matrix:
python-version:
- "3.8"
- "3.9"
- "3.10"
- "3.11"

hassiebp marked this conversation as resolved.
Show resolved Hide resolved
name: Test on Python version ${{ matrix.python-version }}
steps:
- uses: actions/checkout@v3
Expand Down Expand Up @@ -90,7 +90,7 @@ jobs:
rm -rf .env

echo "::group::Run server"
TELEMETRY_ENABLED=false CLICKHOUSE_CLUSTER_ENABLED=false LANGFUSE_ASYNC_INGESTION_PROCESSING=false LANGFUSE_ASYNC_CLICKHOUSE_INGESTION_PROCESSING=false LANGFUSE_READ_FROM_POSTGRES_ONLY=true LANGFUSE_READ_FROM_CLICKHOUSE_ONLY=false docker compose -f docker-compose.v3preview.yml up -d
TELEMETRY_ENABLED=false CLICKHOUSE_CLUSTER_ENABLED=false LANGFUSE_ASYNC_INGESTION_PROCESSING=false LANGFUSE_ASYNC_CLICKHOUSE_INGESTION_PROCESSING=false LANGFUSE_READ_FROM_POSTGRES_ONLY=true LANGFUSE_RETURN_FROM_CLICKHOUSE_ONLY=false docker compose -f docker-compose.v3preview.yml up -d
echo "::endgroup::"

# Add this step to check the health of the container
Expand Down
46 changes: 46 additions & 0 deletions langfuse/_task_manager/media_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,52 @@ def _process_data_recursively(data: Any, level: int):

return media

# Anthropic
if (
isinstance(data, dict)
and "type" in data
and data["type"] == "base64"
and "media_type" in data
and "data" in data
):
media = LangfuseMedia(
base64_data_uri=f"data:{data['media_type']};base64," + data["data"],
)

self._process_media(
media=media,
trace_id=trace_id,
observation_id=observation_id,
field=field,
)

data["data"] = media

return data

# Vertex
if (
isinstance(data, dict)
and "type" in data
and data["type"] == "media"
and "mime_type" in data
and "data" in data
):
media = LangfuseMedia(
base64_data_uri=f"data:{data['mime_type']};base64," + data["data"],
)

self._process_media(
media=media,
trace_id=trace_id,
observation_id=observation_id,
field=field,
)

data["data"] = media

return data

if isinstance(data, list):
return [_process_data_recursively(item, level + 1) for item in data]

Expand Down
13 changes: 7 additions & 6 deletions langfuse/api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ pip install finto
Instantiate and use the client with the following:

```python
from finto import CreateCommentRequest
from finto.client import FernLangfuse
from langfuse.api import CreateCommentRequest
from langfuse.api.client import FernLangfuse

client = FernLangfuse(
x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
Expand Down Expand Up @@ -45,8 +45,8 @@ The SDK also exports an `async` client so that you can make non-blocking calls t
```python
import asyncio

from finto import CreateCommentRequest
from finto.client import AsyncFernLangfuse
from langfuse.api import CreateCommentRequest
from langfuse.api.client import AsyncFernLangfuse

client = AsyncFernLangfuse(
x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
Expand Down Expand Up @@ -116,7 +116,7 @@ The SDK defaults to a 60 second timeout. You can configure this with a timeout o

```python

from finto.client import FernLangfuse
from langfuse.api.client import FernLangfuse

client = FernLangfuse(..., { timeout=20.0 }, )

Expand All @@ -131,9 +131,10 @@ client.comments.create(...,{

You can override the `httpx` client to customize it for your use-case. Some common use-cases include support for proxies
and transports.

```python
import httpx
from finto.client import FernLangfuse
from langfuse.api.client import FernLangfuse

client = FernLangfuse(
...,
Expand Down
4 changes: 2 additions & 2 deletions langfuse/api/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class FernLangfuse:

Examples
--------
from finto.client import FernLangfuse
from langfuse.api.client import FernLangfuse

client = FernLangfuse(
x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
Expand Down Expand Up @@ -140,7 +140,7 @@ class AsyncFernLangfuse:

Examples
--------
from finto.client import AsyncFernLangfuse
from langfuse.api.client import AsyncFernLangfuse

client = AsyncFernLangfuse(
x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
Expand Down
4 changes: 3 additions & 1 deletion langfuse/api/core/api_error.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ class ApiError(Exception):
status_code: typing.Optional[int]
body: typing.Any

def __init__(self, *, status_code: typing.Optional[int] = None, body: typing.Any = None):
def __init__(
self, *, status_code: typing.Optional[int] = None, body: typing.Any = None
):
self.status_code = status_code
self.body = body

Expand Down
6 changes: 3 additions & 3 deletions langfuse/api/core/client_wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def __init__(
username: typing.Optional[typing.Union[str, typing.Callable[[], str]]] = None,
password: typing.Optional[typing.Union[str, typing.Callable[[], str]]] = None,
base_url: str,
timeout: typing.Optional[float] = None
timeout: typing.Optional[float] = None,
):
self._x_langfuse_sdk_name = x_langfuse_sdk_name
self._x_langfuse_sdk_version = x_langfuse_sdk_version
Expand Down Expand Up @@ -71,7 +71,7 @@ def __init__(
password: typing.Optional[typing.Union[str, typing.Callable[[], str]]] = None,
base_url: str,
timeout: typing.Optional[float] = None,
httpx_client: httpx.Client
httpx_client: httpx.Client,
):
super().__init__(
x_langfuse_sdk_name=x_langfuse_sdk_name,
Expand Down Expand Up @@ -101,7 +101,7 @@ def __init__(
password: typing.Optional[typing.Union[str, typing.Callable[[], str]]] = None,
base_url: str,
timeout: typing.Optional[float] = None,
httpx_client: httpx.AsyncClient
httpx_client: httpx.AsyncClient,
):
super().__init__(
x_langfuse_sdk_name=x_langfuse_sdk_name,
Expand Down
4 changes: 3 additions & 1 deletion langfuse/api/core/datetime_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ def serialize_datetime(v: dt.datetime) -> str:
"""

def _serialize_zoned_datetime(v: dt.datetime) -> str:
if v.tzinfo is not None and v.tzinfo.tzname(None) == dt.timezone.utc.tzname(None):
if v.tzinfo is not None and v.tzinfo.tzname(None) == dt.timezone.utc.tzname(
None
):
# UTC is a special case where we use "Z" at the end instead of "+00:00"
return v.isoformat().replace("+00:00", "Z")
else:
Expand Down
9 changes: 7 additions & 2 deletions langfuse/api/core/file.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,17 @@
# (filename, file (or bytes), content_type)
typing.Tuple[typing.Optional[str], FileContent, typing.Optional[str]],
# (filename, file (or bytes), content_type, headers)
typing.Tuple[typing.Optional[str], FileContent, typing.Optional[str], typing.Mapping[str, str]],
typing.Tuple[
typing.Optional[str],
FileContent,
typing.Optional[str],
typing.Mapping[str, str],
],
]


def convert_file_dict_to_httpx_tuples(
d: typing.Dict[str, typing.Union[File, typing.List[File]]]
d: typing.Dict[str, typing.Union[File, typing.List[File]]],
) -> typing.List[typing.Tuple[str, File]]:
"""
The format we use is a list of tuples, where the first element is the
Expand Down
Loading
Loading