Skip to content

Commit

Permalink
Loosen openai version for instrumentation + linting
Browse files Browse the repository at this point in the history
  • Loading branch information
alizenhom committed Aug 12, 2024
1 parent 6383978 commit e1bca1a
Show file tree
Hide file tree
Showing 7 changed files with 116 additions and 71 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@ classifiers = [
]
dependencies = [
"opentelemetry-api ~= 1.12",
"opentelemetry-instrumentation == 0.48b0.dev",
"opentelemetry-instrumentation == 0.47b0",
]

[project.optional-dependencies]
instruments = [
"openai ~= 1.37.1",
"openai >= 0.27.0",
]

[project.entry-points.opentelemetry_instrumentor]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
from opentelemetry.trace import get_tracer
from wrapt import wrap_function_wrapper
from langtrace_python_sdk.instrumentation.openai.patch import (
chat_completions_create
chat_completions_create,
)


Expand All @@ -58,16 +58,16 @@ def instrumentation_dependencies(self) -> Collection[str]:
return _instruments

def _instrument(self, **kwargs):
"""Enable OpenAI instrumentation.
"""
"""Enable OpenAI instrumentation."""
tracer_provider = kwargs.get("tracer_provider")
tracer = get_tracer(__name__, "", tracer_provider)
version = importlib.metadata.version("openai")

wrap_function_wrapper(
"openai.resources.chat.completions",
"Completions.create",
chat_completions_create("openai.chat.completions.create", version, tracer),
chat_completions_create(
"openai.chat.completions.create", version, tracer
),
)

def _uninstrument(self, **kwargs):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@
# limitations under the License.


_instruments = ("openai ~= 1.37.1",)
_instruments = ("openai >= 0.27.0",)
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,12 @@
from opentelemetry.trace.propagation import set_span_in_context
from openai._types import NOT_GIVEN
from span_attributes import SpanAttributes, LLMSpanAttributes, Event
from utils import estimate_tokens, silently_fail, extract_content, calculate_prompt_tokens
from utils import (
estimate_tokens,
silently_fail,
extract_content,
calculate_prompt_tokens,
)


def chat_completions_create(original_method, version, tracer):
Expand All @@ -34,7 +39,11 @@ def traced_method(wrapped, instance, args, kwargs):
for tool_call in tools:
tool_call_dict = {
"id": tool_call.id if hasattr(tool_call, "id") else "",
"type": tool_call.type if hasattr(tool_call, "type") else "",
"type": (
tool_call.type
if hasattr(tool_call, "type")
else ""
),
}
if hasattr(tool_call, "function"):
tool_call_dict["function"] = {
Expand Down Expand Up @@ -125,9 +134,14 @@ def _set_input_attributes(span, kwargs, attributes):
for field, value in attributes.model_dump(by_alias=True).items():
set_span_attribute(span, field, value)

if kwargs.get("functions") is not None and kwargs.get("functions") != NOT_GIVEN:
if (
kwargs.get("functions") is not None
and kwargs.get("functions") != NOT_GIVEN
):
for function in kwargs.get("functions"):
tools.append(json.dumps({"type": "function", "function": function}))
tools.append(
json.dumps({"type": "function", "function": function})
)

if kwargs.get("tools") is not None and kwargs.get("tools") != NOT_GIVEN:
tools.append(json.dumps(kwargs.get("tools")))
Expand All @@ -149,7 +163,11 @@ def _set_response_attributes(span, kwargs, result):
),
"content": extract_content(choice),
**(
{"content_filter_results": choice["content_filter_results"]}
{
"content_filter_results": choice[
"content_filter_results"
]
}
if "content_filter_results" in choice
else {}
),
Expand Down Expand Up @@ -239,7 +257,9 @@ def is_streaming(kwargs):
)


def get_llm_request_attributes(kwargs, prompts=None, model=None, operation_name="chat"):
def get_llm_request_attributes(
kwargs, prompts=None, model=None, operation_name="chat"
):

user = kwargs.get("user", None)
if prompts is None:
Expand Down Expand Up @@ -267,7 +287,9 @@ def get_llm_request_attributes(kwargs, prompts=None, model=None, operation_name=
SpanAttributes.LLM_USER: user,
SpanAttributes.LLM_REQUEST_TOP_P: top_p,
SpanAttributes.LLM_REQUEST_MAX_TOKENS: kwargs.get("max_tokens"),
SpanAttributes.LLM_SYSTEM_FINGERPRINT: kwargs.get("system_fingerprint"),
SpanAttributes.LLM_SYSTEM_FINGERPRINT: kwargs.get(
"system_fingerprint"
),
SpanAttributes.LLM_PRESENCE_PENALTY: kwargs.get("presence_penalty"),
SpanAttributes.LLM_FREQUENCY_PENALTY: kwargs.get("frequency_penalty"),
SpanAttributes.LLM_REQUEST_SEED: kwargs.get("seed"),
Expand All @@ -283,7 +305,12 @@ class StreamWrapper:
span: Span

def __init__(
self, stream, span, prompt_tokens, function_call=False, tool_calls=False
self,
stream,
span,
prompt_tokens,
function_call=False,
tool_calls=False,
):
self.stream = stream
self.span = span
Expand Down Expand Up @@ -416,7 +443,11 @@ def process_chunk(self, chunk):
content.append(tool_call.function.arguments)
set_event_completion_chunk(
self.span,
"".join(content) if len(content) > 0 and content[0] is not None else "",
(
"".join(content)
if len(content) > 0 and content[0] is not None
else ""
),
)
if content:
self.result_content.append(content[0])
Expand All @@ -427,12 +458,18 @@ def process_chunk(self, chunk):
content = [chunk.text]
set_event_completion_chunk(
self.span,
"".join(content) if len(content) > 0 and content[0] is not None else "",
(
"".join(content)
if len(content) > 0 and content[0] is not None
else ""
),
)

if content:
self.result_content.append(content[0])

if hasattr(chunk, "usage_metadata"):
self.completion_tokens = chunk.usage_metadata.candidates_token_count
self.completion_tokens = (
chunk.usage_metadata.candidates_token_count
)
self.prompt_tokens = chunk.usage_metadata.prompt_token_count
Original file line number Diff line number Diff line change
Expand Up @@ -80,133 +80,139 @@ class LLMSpanAttributes(BaseModel):
model_config = ConfigDict(extra="allow")
gen_ai_operation_name: str = Field(
...,
alias='gen_ai.operation.name',
description='The name of the operation being performed.',
alias="gen_ai.operation.name",
description="The name of the operation being performed.",
)
gen_ai_request_model: str = Field(
...,
alias='gen_ai.request.model',
description='Model name from the input request',
alias="gen_ai.request.model",
description="Model name from the input request",
)
gen_ai_response_model: Optional[str] = Field(
None, alias='gen_ai.response.model', description='Model name from the response'
None,
alias="gen_ai.response.model",
description="Model name from the response",
)
gen_ai_request_temperature: Optional[float] = Field(
None,
alias='gen_ai.request.temperature',
description='Temperature value from the input request',
alias="gen_ai.request.temperature",
description="Temperature value from the input request",
)
gen_ai_request_logit_bias: Optional[str] = Field(
None,
alias='gen_ai.request.logit_bias',
description='Likelihood bias of the specified tokens the input request.',
alias="gen_ai.request.logit_bias",
description="Likelihood bias of the specified tokens the input request.",
)
gen_ai_request_logprobs: Optional[bool] = Field(
None,
alias='gen_ai.request.logprobs',
description='Logprobs flag returns log probabilities.',
alias="gen_ai.request.logprobs",
description="Logprobs flag returns log probabilities.",
)
gen_ai_request_top_logprobs: Optional[float] = Field(
None,
alias='gen_ai.request.top_logprobs',
description='Integer between 0 and 5 specifying the number of most likely tokens to return.',
alias="gen_ai.request.top_logprobs",
description="Integer between 0 and 5 specifying the number of most likely tokens to return.",
)
gen_ai_request_top_p: Optional[float] = Field(
None,
alias='gen_ai.request.top_p',
description='Top P value from the input request',
alias="gen_ai.request.top_p",
description="Top P value from the input request",
)
gen_ai_request_top_k: Optional[float] = Field(
None,
alias='gen_ai.request.top_k',
description='Top K results to return from the input request',
alias="gen_ai.request.top_k",
description="Top K results to return from the input request",
)
gen_ai_user: Optional[str] = Field(
None, alias='gen_ai.user', description='User ID from the input request'
None, alias="gen_ai.user", description="User ID from the input request"
)
gen_ai_prompt: Optional[str] = Field(
None, alias='gen_ai.prompt', description='Prompt text from the input request'
None,
alias="gen_ai.prompt",
description="Prompt text from the input request",
)
gen_ai_completion: Optional[str] = Field(
None,
alias='gen_ai.completion',
alias="gen_ai.completion",
description='Completion text from the response. This will be an array of json objects with the following format {"role": "", "content": ""}. Role can be one of the following values: [system, user, assistant, tool]',
)
gen_ai_request_stream: Optional[bool] = Field(
None,
alias='gen_ai.request.stream',
description='Stream flag from the input request',
alias="gen_ai.request.stream",
description="Stream flag from the input request",
)
gen_ai_request_encoding_formats: Optional[List[str]] = Field(
None,
alias='gen_ai.request.encoding_formats',
alias="gen_ai.request.encoding_formats",
description="Encoding formats from the input request. Allowed values: ['float', 'int8','uint8', 'binary', 'ubinary', 'base64']",
)
gen_ai_completion_chunk: Optional[str] = Field(
None,
alias='gen_ai.completion.chunk',
description='Chunk text from the response',
alias="gen_ai.completion.chunk",
description="Chunk text from the response",
)
gen_ai_response_finish_reasons: Optional[List[str]] = Field(
None,
alias='gen_ai.response.finish_reasons',
description='Array of reasons the model stopped generating tokens, corresponding to each generation received',
alias="gen_ai.response.finish_reasons",
description="Array of reasons the model stopped generating tokens, corresponding to each generation received",
)
gen_ai_system_fingerprint: Optional[str] = Field(
None,
alias='gen_ai.system_fingerprint',
description='System fingerprint of the system that generated the response',
alias="gen_ai.system_fingerprint",
description="System fingerprint of the system that generated the response",
)
gen_ai_request_tool_choice: Optional[str] = Field(
None,
alias='gen_ai.request.tool_choice',
description='Tool choice from the input request',
alias="gen_ai.request.tool_choice",
description="Tool choice from the input request",
)
gen_ai_response_tool_calls: Optional[str] = Field(
None,
alias='gen_ai.response.tool_calls',
description='Array of tool calls from the response json stringified',
alias="gen_ai.response.tool_calls",
description="Array of tool calls from the response json stringified",
)
gen_ai_request_max_tokens: Optional[float] = Field(
None,
alias='gen_ai.request.max_tokens',
description='The maximum number of tokens the LLM generates for a request.',
alias="gen_ai.request.max_tokens",
description="The maximum number of tokens the LLM generates for a request.",
)
gen_ai_usage_input_tokens: Optional[float] = Field(
None,
alias='gen_ai.usage.input_tokens',
description='The number of tokens used in the llm prompt.',
alias="gen_ai.usage.input_tokens",
description="The number of tokens used in the llm prompt.",
)
gen_ai_usage_total_tokens: Optional[float] = Field(
None,
alias='gen_ai.usage.total_tokens',
description='The total number of tokens used in the llm request.',
alias="gen_ai.usage.total_tokens",
description="The total number of tokens used in the llm request.",
)
gen_ai_usage_output_tokens: Optional[float] = Field(
None,
alias='gen_ai.usage.output_tokens',
description='The number of tokens in the llm response.',
alias="gen_ai.usage.output_tokens",
description="The number of tokens in the llm response.",
)
gen_ai_request_seed: Optional[str] = Field(
None, alias='gen_ai.request.seed', description='Seed from the input request'
None,
alias="gen_ai.request.seed",
description="Seed from the input request",
)
gen_ai_request_frequency_penalty: Optional[float] = Field(
None,
alias='gen_ai.request.frequency_penalty',
description='Frequency penalty from the input request',
alias="gen_ai.request.frequency_penalty",
description="Frequency penalty from the input request",
)
gen_ai_request_presence_penalty: Optional[float] = Field(
None,
alias='gen_ai.request.presence_penalty',
description='Presence penalty from the input request',
alias="gen_ai.request.presence_penalty",
description="Presence penalty from the input request",
)
gen_ai_request_tools: Optional[str] = Field(
None,
alias='gen_ai.request.tools',
description='An array of tools from the input request json stringified',
alias="gen_ai.request.tools",
description="An array of tools from the input request json stringified",
)
gen_ai_request_tool_results: Optional[str] = Field(
None,
alias='gen_ai.request.tool_results',
description='An array of tool results from the input request json stringified',
alias="gen_ai.request.tool_results",
description="An array of tool results from the input request json stringified",
)
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,9 @@ def wrapper(*args, **kwargs):
return func(*args, **kwargs)
except Exception as exception:
logger.warning(
"Failed to execute %s, error: %s", func.__name__, str(exception)
"Failed to execute %s, error: %s",
func.__name__,
str(exception),
)

return wrapper
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@
# See the License for the specific language governing permissions and
# limitations under the License.

__version__ = "0.0.1dev"
__version__ = "0.47b0"

0 comments on commit e1bca1a

Please sign in to comment.