Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
63 changes: 12 additions & 51 deletions langfuse/openai.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,24 +80,6 @@ class OpenAiDefinition:
max_version: Optional[str] = None


OPENAI_METHODS_V0 = [
OpenAiDefinition(
module="openai",
object="ChatCompletion",
method="create",
type="chat",
sync=True,
),
OpenAiDefinition(
module="openai",
object="Completion",
method="create",
type="completion",
sync=True,
),
]


OPENAI_METHODS_V1 = [
OpenAiDefinition(
module="openai.resources.chat.completions",
Expand Down Expand Up @@ -798,8 +780,7 @@ def _extract_streamed_openai_response(resource: Any, chunks: Any) -> Any:
model, usage, finish_reason, service_tier = None, None, None, None

for chunk in chunks:
if _is_openai_v1():
chunk = chunk.__dict__
chunk = chunk.__dict__

model = model or chunk.get("model", None) or None
service_tier = service_tier or chunk.get("service_tier", None) or None
Expand All @@ -810,15 +791,14 @@ def _extract_streamed_openai_response(resource: Any, chunks: Any) -> Any:
choices = chunk.get("choices") or []

for choice in choices:
if _is_openai_v1():
choice = choice.__dict__
choice = choice.__dict__
if resource.type == "chat":
delta = choice.get("delta", None)
choice_finish_reason = choice.get("finish_reason", None)
if choice_finish_reason is not None:
finish_reason = choice_finish_reason

if _is_openai_v1() and delta is not None:
if delta is not None:
delta = delta.__dict__

if delta is None:
Expand Down Expand Up @@ -956,7 +936,7 @@ def _get_langfuse_data_from_default_response(
if len(choices) > 0:
choice = choices[-1]

completion = choice.text if _is_openai_v1() else choice.get("text", None)
completion = choice.text

elif resource.object == "Responses" or resource.object == "AsyncResponses":
completion = _extract_response_api_completion(response.get("output", {}))
Expand All @@ -968,17 +948,11 @@ def _get_langfuse_data_from_default_response(
if len(choices) > 1:
completion = [
_extract_chat_response(choice.message.__dict__)
if _is_openai_v1()
else choice.get("message", None)
for choice in choices
]
else:
choice = choices[0]
completion = (
_extract_chat_response(choice.message.__dict__)
if _is_openai_v1()
else choice.get("message", None)
)
completion = _extract_chat_response(choice.message.__dict__)

elif resource.type == "embedding":
data = response.get("data") or []
Expand Down Expand Up @@ -1015,16 +989,12 @@ def _merge_service_tier_into_model_parameters(
return {**(model_parameters or {}), "service_tier": service_tier}


def _is_openai_v1() -> bool:
return Version(openai.__version__) >= Version("1.0.0")


def _is_streaming_response(response: Any) -> bool:
return (
isinstance(response, types.GeneratorType)
or isinstance(response, types.AsyncGeneratorType)
or (_is_openai_v1() and isinstance(response, openai.Stream))
or (_is_openai_v1() and isinstance(response, openai.AsyncStream))
or isinstance(response, openai.Stream)
or isinstance(response, openai.AsyncStream)
)


Expand All @@ -1034,9 +1004,6 @@ def _is_streaming_response(response: Any) -> bool:
def _install_openai_stream_iteration_hooks() -> None:
global _openai_stream_iter_hook_installed

if not _is_openai_v1():
return

if not _openai_stream_iter_hook_installed:
original_iter = openai.Stream.__iter__
original_aiter = openai.AsyncStream.__aiter__
Expand Down Expand Up @@ -1318,7 +1285,7 @@ def _wrap(
try:
openai_response = wrapped(**arg_extractor.get_openai_args())

if _is_openai_v1() and isinstance(openai_response, openai.Stream):
if isinstance(openai_response, openai.Stream):
return _instrument_openai_stream(
resource=open_ai_resource,
response=openai_response,
Expand All @@ -1338,9 +1305,7 @@ def _wrap(
model, completion, usage, service_tier = (
_get_langfuse_data_from_default_response(
open_ai_resource,
(parsed_response and parsed_response.__dict__)
if _is_openai_v1()
else parsed_response,
parsed_response and parsed_response.__dict__,
)
)

Expand Down Expand Up @@ -1407,7 +1372,7 @@ async def _wrap_async(
try:
openai_response = await wrapped(**arg_extractor.get_openai_args())

if _is_openai_v1() and isinstance(openai_response, openai.AsyncStream):
if isinstance(openai_response, openai.AsyncStream):
return _instrument_openai_async_stream(
resource=open_ai_resource,
response=openai_response,
Expand All @@ -1427,9 +1392,7 @@ async def _wrap_async(
model, completion, usage, service_tier = (
_get_langfuse_data_from_default_response(
open_ai_resource,
(parsed_response and parsed_response.__dict__)
if _is_openai_v1()
else parsed_response,
parsed_response and parsed_response.__dict__,
)
)
generation.update(
Expand Down Expand Up @@ -1460,9 +1423,7 @@ async def _wrap_async(


def register_tracing() -> None:
resources = OPENAI_METHODS_V1 if _is_openai_v1() else OPENAI_METHODS_V0

for resource in resources:
for resource in OPENAI_METHODS_V1:
if resource.min_version is not None and Version(openai.__version__) < Version(
resource.min_version
):
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ dev = [
"pytest-httpserver>=1.0.8,<2",
"ruff>=0.15.2,<0.16",
"mypy>=1.0.0,<2",
"openai>=0.27.8",
"openai>=1.0.0",
"langchain-openai>=0.0.5,<0.4",
"langchain>=1,<2",
"langgraph>=1,<2",
Expand Down
2 changes: 1 addition & 1 deletion uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading