openlit 1.30.2__tar.gz → 1.30.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. {openlit-1.30.2 → openlit-1.30.4}/PKG-INFO +3 -2
  2. {openlit-1.30.2 → openlit-1.30.4}/README.md +2 -1
  3. {openlit-1.30.2 → openlit-1.30.4}/pyproject.toml +1 -1
  4. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/langchain/langchain.py +8 -6
  5. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/litellm/__init__.py +16 -2
  6. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/litellm/async_litellm.py +115 -0
  7. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/litellm/litellm.py +115 -0
  8. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/openai/async_openai.py +8 -6
  9. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/openai/openai.py +8 -6
  10. {openlit-1.30.2 → openlit-1.30.4}/LICENSE +0 -0
  11. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/__helpers.py +0 -0
  12. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/__init__.py +0 -0
  13. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/evals/__init__.py +0 -0
  14. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/evals/all.py +0 -0
  15. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/evals/bias_detection.py +0 -0
  16. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/evals/hallucination.py +0 -0
  17. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/evals/toxicity.py +0 -0
  18. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/evals/utils.py +0 -0
  19. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/guard/__init__.py +0 -0
  20. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/guard/all.py +0 -0
  21. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/guard/prompt_injection.py +0 -0
  22. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/guard/restrict_topic.py +0 -0
  23. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/guard/sensitive_topic.py +0 -0
  24. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/guard/utils.py +0 -0
  25. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/anthropic/__init__.py +0 -0
  26. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/anthropic/anthropic.py +0 -0
  27. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/anthropic/async_anthropic.py +0 -0
  28. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/azure_ai_inference/__init__.py +0 -0
  29. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/azure_ai_inference/async_azure_ai_inference.py +0 -0
  30. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/azure_ai_inference/azure_ai_inference.py +0 -0
  31. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/bedrock/__init__.py +0 -0
  32. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/bedrock/bedrock.py +0 -0
  33. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/chroma/__init__.py +0 -0
  34. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/chroma/chroma.py +0 -0
  35. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/cohere/__init__.py +0 -0
  36. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/cohere/cohere.py +0 -0
  37. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/crewai/__init__.py +0 -0
  38. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/crewai/crewai.py +0 -0
  39. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/elevenlabs/__init__.py +0 -0
  40. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/elevenlabs/async_elevenlabs.py +0 -0
  41. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/elevenlabs/elevenlabs.py +0 -0
  42. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/embedchain/__init__.py +0 -0
  43. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/embedchain/embedchain.py +0 -0
  44. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/google_ai_studio/__init__.py +0 -0
  45. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/google_ai_studio/async_google_ai_studio.py +0 -0
  46. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/google_ai_studio/google_ai_studio.py +0 -0
  47. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/gpt4all/__init__.py +0 -0
  48. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/gpt4all/gpt4all.py +0 -0
  49. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/gpu/__init__.py +0 -0
  50. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/groq/__init__.py +0 -0
  51. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/groq/async_groq.py +0 -0
  52. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/groq/groq.py +0 -0
  53. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/haystack/__init__.py +0 -0
  54. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/haystack/haystack.py +0 -0
  55. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/langchain/__init__.py +0 -0
  56. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/llamaindex/__init__.py +0 -0
  57. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/llamaindex/llamaindex.py +0 -0
  58. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/milvus/__init__.py +0 -0
  59. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/milvus/milvus.py +0 -0
  60. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/mistral/__init__.py +0 -0
  61. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/mistral/async_mistral.py +0 -0
  62. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/mistral/mistral.py +0 -0
  63. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/ollama/__init__.py +0 -0
  64. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/ollama/async_ollama.py +0 -0
  65. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/ollama/ollama.py +0 -0
  66. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/openai/__init__.py +0 -0
  67. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/openai/async_azure_openai.py +0 -0
  68. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/openai/azure_openai.py +0 -0
  69. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/pinecone/__init__.py +0 -0
  70. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/pinecone/pinecone.py +0 -0
  71. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/qdrant/__init__.py +0 -0
  72. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/qdrant/async_qdrant.py +0 -0
  73. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/qdrant/qdrant.py +0 -0
  74. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/transformers/__init__.py +0 -0
  75. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/transformers/transformers.py +0 -0
  76. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/vertexai/__init__.py +0 -0
  77. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/vertexai/async_vertexai.py +0 -0
  78. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/vertexai/vertexai.py +0 -0
  79. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/vllm/__init__.py +0 -0
  80. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/instrumentation/vllm/vllm.py +0 -0
  81. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/otel/metrics.py +0 -0
  82. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/otel/tracing.py +0 -0
  83. {openlit-1.30.2 → openlit-1.30.4}/src/openlit/semcov/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: openlit
3
- Version: 1.30.2
3
+ Version: 1.30.4
4
4
  Summary: OpenTelemetry-native Auto instrumentation library for monitoring LLM Applications and GPUs, facilitating the integration of observability into your GenAI-driven projects
5
5
  Home-page: https://github.com/openlit/openlit/tree/main/openlit/python
6
6
  Keywords: OpenTelemetry,otel,otlp,llm,tracing,openai,anthropic,claude,cohere,llm monitoring,observability,monitoring,gpt,Generative AI,chatGPT,gpu
@@ -72,7 +72,7 @@ This project proudly follows and maintains the [Semantic Conventions](https://gi
72
72
  | [✅ Cohere](https://docs.openlit.io/latest/integrations/cohere) | | [✅ EmbedChain](https://docs.openlit.io/latest/integrations/embedchain) | |
73
73
  | [✅ Mistral](https://docs.openlit.io/latest/integrations/mistral) | | [✅ Guardrails](https://docs.openlit.io/latest/integrations/guardrails) | |
74
74
  | [✅ Azure OpenAI](https://docs.openlit.io/latest/integrations/azure-openai) | | [✅ CrewAI](https://docs.openlit.io/latest/integrations/crewai) | |
75
- | [✅ Azure AI Inference](https://docs.openlit.io/latest/integrations/azure-ai-inference) | |
75
+ | [✅ Azure AI Inference](https://docs.openlit.io/latest/integrations/azure-ai-inference) | | [✅ DSPy](https://docs.openlit.io/latest/integrations/dspy) | |
76
76
  | [✅ GitHub AI Models](https://docs.openlit.io/latest/integrations/github-models) | | | |
77
77
  | [✅ HuggingFace Transformers](https://docs.openlit.io/latest/integrations/huggingface) | | | |
78
78
  | [✅ Amazon Bedrock](https://docs.openlit.io/latest/integrations/bedrock) | | | |
@@ -84,6 +84,7 @@ This project proudly follows and maintains the [Semantic Conventions](https://gi
84
84
  | [✅ Google AI Studio](https://docs.openlit.io/latest/integrations/google-ai-studio) | | | |
85
85
  | [✅ NVIDIA NIM](https://docs.openlit.io/latest/integrations/nvidia-nim) | | | |
86
86
 
87
+
87
88
  ## Supported Destinations
88
89
  - [✅ OpenTelemetry Collector](https://docs.openlit.io/latest/connections/otelcol)
89
90
  - [✅ Prometheus + Tempo](https://docs.openlit.io/latest/connections/prometheus-tempo)
@@ -41,7 +41,7 @@ This project proudly follows and maintains the [Semantic Conventions](https://gi
41
41
  | [✅ Cohere](https://docs.openlit.io/latest/integrations/cohere) | | [✅ EmbedChain](https://docs.openlit.io/latest/integrations/embedchain) | |
42
42
  | [✅ Mistral](https://docs.openlit.io/latest/integrations/mistral) | | [✅ Guardrails](https://docs.openlit.io/latest/integrations/guardrails) | |
43
43
  | [✅ Azure OpenAI](https://docs.openlit.io/latest/integrations/azure-openai) | | [✅ CrewAI](https://docs.openlit.io/latest/integrations/crewai) | |
44
- | [✅ Azure AI Inference](https://docs.openlit.io/latest/integrations/azure-ai-inference) | |
44
+ | [✅ Azure AI Inference](https://docs.openlit.io/latest/integrations/azure-ai-inference) | | [✅ DSPy](https://docs.openlit.io/latest/integrations/dspy) | |
45
45
  | [✅ GitHub AI Models](https://docs.openlit.io/latest/integrations/github-models) | | | |
46
46
  | [✅ HuggingFace Transformers](https://docs.openlit.io/latest/integrations/huggingface) | | | |
47
47
  | [✅ Amazon Bedrock](https://docs.openlit.io/latest/integrations/bedrock) | | | |
@@ -53,6 +53,7 @@ This project proudly follows and maintains the [Semantic Conventions](https://gi
53
53
  | [✅ Google AI Studio](https://docs.openlit.io/latest/integrations/google-ai-studio) | | | |
54
54
  | [✅ NVIDIA NIM](https://docs.openlit.io/latest/integrations/nvidia-nim) | | | |
55
55
 
56
+
56
57
  ## Supported Destinations
57
58
  - [✅ OpenTelemetry Collector](https://docs.openlit.io/latest/connections/otelcol)
58
59
  - [✅ Prometheus + Tempo](https://docs.openlit.io/latest/connections/prometheus-tempo)
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "openlit"
3
- version = "1.30.2"
3
+ version = "1.30.4"
4
4
  description = "OpenTelemetry-native Auto instrumentation library for monitoring LLM Applications and GPUs, facilitating the integration of observability into your GenAI-driven projects"
5
5
  authors = ["OpenLIT"]
6
6
  repository = "https://github.com/openlit/openlit/tree/main/openlit/python"
@@ -481,11 +481,12 @@ def chat(gen_ai_endpoint, version, environment, application_name,
481
481
  response = wrapped(*args, **kwargs)
482
482
 
483
483
  try:
484
- input_tokens = response.response_metadata.get("prompt_eval_count", 0)
485
- output_tokens = response.response_metadata.get("eval_count", 0)
484
+ token_usage = response.response_metadata.get("token_usage", {})
485
+ input_tokens = token_usage.get("prompt_tokens", 0)
486
+ output_tokens = token_usage.get("completion_tokens", 0)
487
+ model = response.response_metadata.get("model_name", "gpt-4")
486
488
 
487
489
  prompt = "" if isinstance(args[0], list) else args[0]
488
- model = getattr(instance, 'model_name', getattr(instance, 'model', 'gpt-4'))
489
490
 
490
491
  # Calculate cost of the operation
491
492
  cost = get_chat_model_cost(
@@ -620,11 +621,12 @@ def achat(gen_ai_endpoint, version, environment, application_name,
620
621
  response = await wrapped(*args, **kwargs)
621
622
 
622
623
  try:
623
- input_tokens = response.response_metadata.get("prompt_eval_count", 0)
624
- output_tokens = response.response_metadata.get("eval_count", 0)
624
+ token_usage = response.response_metadata.get("token_usage", {})
625
+ input_tokens = token_usage.get("prompt_tokens", 0)
626
+ output_tokens = token_usage.get("completion_tokens", 0)
627
+ model = response.response_metadata.get("model_name", "gpt-4")
625
628
 
626
629
  prompt = "" if isinstance(args[0], list) else args[0]
627
- model = getattr(instance, 'model_name', getattr(instance, 'model', 'gpt-4'))
628
630
  # Calculate cost of the operation
629
631
  cost = get_chat_model_cost(
630
632
  model,
@@ -7,10 +7,10 @@ from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
7
7
  from wrapt import wrap_function_wrapper
8
8
 
9
9
  from openlit.instrumentation.litellm.litellm import (
10
- completion
10
+ completion, embedding
11
11
  )
12
12
  from openlit.instrumentation.litellm.async_litellm import (
13
- acompletion
13
+ acompletion, aembedding
14
14
  )
15
15
 
16
16
  _instruments = ("litellm >= 1.52.6",)
@@ -48,6 +48,20 @@ class LiteLLMInstrumentor(BaseInstrumentor):
48
48
  tracer, pricing_info, trace_content, metrics, disable_metrics),
49
49
  )
50
50
 
51
+ wrap_function_wrapper(
52
+ "litellm",
53
+ "embedding",
54
+ embedding("litellm.embedding", version, environment, application_name,
55
+ tracer, pricing_info, trace_content, metrics, disable_metrics),
56
+ )
57
+
58
+ wrap_function_wrapper(
59
+ "litellm",
60
+ "aembedding",
61
+ aembedding("litellm.embedding", version, environment, application_name,
62
+ tracer, pricing_info, trace_content, metrics, disable_metrics),
63
+ )
64
+
51
65
 
52
66
  def _uninstrument(self, **kwargs):
53
67
  # Proper uninstrumentation logic to revert patched methods
@@ -8,6 +8,7 @@ from opentelemetry.trace import SpanKind, Status, StatusCode
8
8
  from opentelemetry.sdk.resources import TELEMETRY_SDK_NAME
9
9
  from openlit.__helpers import (
10
10
  get_chat_model_cost,
11
+ get_embed_model_cost,
11
12
  openai_tokens,
12
13
  handle_exception,
13
14
  response_as_dict,
@@ -404,3 +405,117 @@ def acompletion(gen_ai_endpoint, version, environment, application_name,
404
405
  return response
405
406
 
406
407
  return wrapper
408
+
409
+ def aembedding(gen_ai_endpoint, version, environment, application_name,
410
+ tracer, pricing_info, trace_content, metrics, disable_metrics):
411
+ """
412
+ Generates a telemetry wrapper for embeddings to collect metrics.
413
+
414
+ Args:
415
+ gen_ai_endpoint: Endpoint identifier for logging and tracing.
416
+ version: Version of the monitoring package.
417
+ environment: Deployment environment (e.g., production, staging).
418
+ application_name: Name of the application using the OpenAI API.
419
+ tracer: OpenTelemetry tracer for creating spans.
420
+ pricing_info: Information used for calculating the cost of OpenAI usage.
421
+ trace_content: Flag indicating whether to trace the actual content.
422
+
423
+ Returns:
424
+ A function that wraps the embeddings method to add telemetry.
425
+ """
426
+
427
+ async def wrapper(wrapped, instance, args, kwargs):
428
+ """
429
+ Wraps the 'embeddings' API call to add telemetry.
430
+
431
+ This collects metrics such as execution time, cost, and token usage, and handles errors
432
+ gracefully, adding details to the trace for observability.
433
+
434
+ Args:
435
+ wrapped: The original 'embeddings' method to be wrapped.
436
+ instance: The instance of the class where the original method is defined.
437
+ args: Positional arguments for the 'embeddings' method.
438
+ kwargs: Keyword arguments for the 'embeddings' method.
439
+
440
+ Returns:
441
+ The response from the original 'embeddings' method.
442
+ """
443
+
444
+ with tracer.start_as_current_span(gen_ai_endpoint, kind= SpanKind.CLIENT) as span:
445
+ response = await wrapped(*args, **kwargs)
446
+ response_dict = response_as_dict(response)
447
+ try:
448
+ # Calculate cost of the operation
449
+ cost = get_embed_model_cost(kwargs.get("model", "text-embedding-ada-002"),
450
+ pricing_info, response_dict.get('usage').get('prompt_tokens'))
451
+
452
+ # Set Span attributes
453
+ span.set_attribute(TELEMETRY_SDK_NAME, "openlit")
454
+ span.set_attribute(SemanticConvetion.GEN_AI_SYSTEM,
455
+ SemanticConvetion.GEN_AI_SYSTEM_OPENAI)
456
+ span.set_attribute(SemanticConvetion.GEN_AI_TYPE,
457
+ SemanticConvetion.GEN_AI_TYPE_EMBEDDING)
458
+ span.set_attribute(SemanticConvetion.GEN_AI_ENDPOINT,
459
+ gen_ai_endpoint)
460
+ span.set_attribute(SemanticConvetion.GEN_AI_ENVIRONMENT,
461
+ environment)
462
+ span.set_attribute(SemanticConvetion.GEN_AI_APPLICATION_NAME,
463
+ application_name)
464
+ span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_MODEL,
465
+ kwargs.get("model", "text-embedding-ada-002"))
466
+ span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_EMBEDDING_FORMAT,
467
+ kwargs.get("encoding_format", "float"))
468
+ # span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_EMBEDDING_DIMENSION,
469
+ # kwargs.get("dimensions", "null"))
470
+ span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_USER,
471
+ kwargs.get("user", ""))
472
+ span.set_attribute(SemanticConvetion.GEN_AI_USAGE_PROMPT_TOKENS,
473
+ response_dict.get('usage').get('prompt_tokens'))
474
+ span.set_attribute(SemanticConvetion.GEN_AI_USAGE_TOTAL_TOKENS,
475
+ response_dict.get('usage').get('total_tokens'))
476
+ span.set_attribute(SemanticConvetion.GEN_AI_USAGE_COST,
477
+ cost)
478
+ if trace_content:
479
+ span.add_event(
480
+ name=SemanticConvetion.GEN_AI_CONTENT_PROMPT_EVENT,
481
+ attributes={
482
+ SemanticConvetion.GEN_AI_CONTENT_PROMPT: kwargs.get("input", ""),
483
+ },
484
+ )
485
+
486
+ span.set_status(Status(StatusCode.OK))
487
+
488
+ if disable_metrics is False:
489
+ attributes = {
490
+ TELEMETRY_SDK_NAME:
491
+ "openlit",
492
+ SemanticConvetion.GEN_AI_APPLICATION_NAME:
493
+ application_name,
494
+ SemanticConvetion.GEN_AI_SYSTEM:
495
+ SemanticConvetion.GEN_AI_SYSTEM_OPENAI,
496
+ SemanticConvetion.GEN_AI_ENVIRONMENT:
497
+ environment,
498
+ SemanticConvetion.GEN_AI_TYPE:
499
+ SemanticConvetion.GEN_AI_TYPE_EMBEDDING,
500
+ SemanticConvetion.GEN_AI_REQUEST_MODEL:
501
+ kwargs.get("model", "text-embedding-ada-002")
502
+ }
503
+
504
+ metrics["genai_requests"].add(1, attributes)
505
+ metrics["genai_total_tokens"].add(
506
+ response_dict.get('usage').get('total_tokens'), attributes)
507
+ metrics["genai_prompt_tokens"].add(
508
+ response_dict.get('usage').get('prompt_tokens'), attributes)
509
+ metrics["genai_cost"].record(cost, attributes)
510
+
511
+ # Return original response
512
+ return response
513
+
514
+ except Exception as e:
515
+ handle_exception(span, e)
516
+ logger.error("Error in trace creation: %s", e)
517
+
518
+ # Return original response
519
+ return response
520
+
521
+ return wrapper
@@ -8,6 +8,7 @@ from opentelemetry.trace import SpanKind, Status, StatusCode
8
8
  from opentelemetry.sdk.resources import TELEMETRY_SDK_NAME
9
9
  from openlit.__helpers import (
10
10
  get_chat_model_cost,
11
+ get_embed_model_cost,
11
12
  openai_tokens,
12
13
  handle_exception,
13
14
  response_as_dict,
@@ -404,3 +405,117 @@ def completion(gen_ai_endpoint, version, environment, application_name,
404
405
  return response
405
406
 
406
407
  return wrapper
408
+
409
+ def embedding(gen_ai_endpoint, version, environment, application_name,
410
+ tracer, pricing_info, trace_content, metrics, disable_metrics):
411
+ """
412
+ Generates a telemetry wrapper for embeddings to collect metrics.
413
+
414
+ Args:
415
+ gen_ai_endpoint: Endpoint identifier for logging and tracing.
416
+ version: Version of the monitoring package.
417
+ environment: Deployment environment (e.g., production, staging).
418
+ application_name: Name of the application using the OpenAI API.
419
+ tracer: OpenTelemetry tracer for creating spans.
420
+ pricing_info: Information used for calculating the cost of OpenAI usage.
421
+ trace_content: Flag indicating whether to trace the actual content.
422
+
423
+ Returns:
424
+ A function that wraps the embeddings method to add telemetry.
425
+ """
426
+
427
+ def wrapper(wrapped, instance, args, kwargs):
428
+ """
429
+ Wraps the 'embeddings' API call to add telemetry.
430
+
431
+ This collects metrics such as execution time, cost, and token usage, and handles errors
432
+ gracefully, adding details to the trace for observability.
433
+
434
+ Args:
435
+ wrapped: The original 'embeddings' method to be wrapped.
436
+ instance: The instance of the class where the original method is defined.
437
+ args: Positional arguments for the 'embeddings' method.
438
+ kwargs: Keyword arguments for the 'embeddings' method.
439
+
440
+ Returns:
441
+ The response from the original 'embeddings' method.
442
+ """
443
+
444
+ with tracer.start_as_current_span(gen_ai_endpoint, kind= SpanKind.CLIENT) as span:
445
+ response = wrapped(*args, **kwargs)
446
+ response_dict = response_as_dict(response)
447
+ try:
448
+ # Calculate cost of the operation
449
+ cost = get_embed_model_cost(kwargs.get("model", "text-embedding-ada-002"),
450
+ pricing_info, response_dict.get('usage').get('prompt_tokens'))
451
+
452
+ # Set Span attributes
453
+ span.set_attribute(TELEMETRY_SDK_NAME, "openlit")
454
+ span.set_attribute(SemanticConvetion.GEN_AI_SYSTEM,
455
+ SemanticConvetion.GEN_AI_SYSTEM_OPENAI)
456
+ span.set_attribute(SemanticConvetion.GEN_AI_TYPE,
457
+ SemanticConvetion.GEN_AI_TYPE_EMBEDDING)
458
+ span.set_attribute(SemanticConvetion.GEN_AI_ENDPOINT,
459
+ gen_ai_endpoint)
460
+ span.set_attribute(SemanticConvetion.GEN_AI_ENVIRONMENT,
461
+ environment)
462
+ span.set_attribute(SemanticConvetion.GEN_AI_APPLICATION_NAME,
463
+ application_name)
464
+ span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_MODEL,
465
+ kwargs.get("model", "text-embedding-ada-002"))
466
+ span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_EMBEDDING_FORMAT,
467
+ kwargs.get("encoding_format", "float"))
468
+ # span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_EMBEDDING_DIMENSION,
469
+ # kwargs.get("dimensions", "null"))
470
+ span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_USER,
471
+ kwargs.get("user", ""))
472
+ span.set_attribute(SemanticConvetion.GEN_AI_USAGE_PROMPT_TOKENS,
473
+ response_dict.get('usage').get('prompt_tokens'))
474
+ span.set_attribute(SemanticConvetion.GEN_AI_USAGE_TOTAL_TOKENS,
475
+ response_dict.get('usage').get('total_tokens'))
476
+ span.set_attribute(SemanticConvetion.GEN_AI_USAGE_COST,
477
+ cost)
478
+ if trace_content:
479
+ span.add_event(
480
+ name=SemanticConvetion.GEN_AI_CONTENT_PROMPT_EVENT,
481
+ attributes={
482
+ SemanticConvetion.GEN_AI_CONTENT_PROMPT: kwargs.get("input", ""),
483
+ },
484
+ )
485
+
486
+ span.set_status(Status(StatusCode.OK))
487
+
488
+ if disable_metrics is False:
489
+ attributes = {
490
+ TELEMETRY_SDK_NAME:
491
+ "openlit",
492
+ SemanticConvetion.GEN_AI_APPLICATION_NAME:
493
+ application_name,
494
+ SemanticConvetion.GEN_AI_SYSTEM:
495
+ SemanticConvetion.GEN_AI_SYSTEM_OPENAI,
496
+ SemanticConvetion.GEN_AI_ENVIRONMENT:
497
+ environment,
498
+ SemanticConvetion.GEN_AI_TYPE:
499
+ SemanticConvetion.GEN_AI_TYPE_EMBEDDING,
500
+ SemanticConvetion.GEN_AI_REQUEST_MODEL:
501
+ kwargs.get("model", "text-embedding-ada-002")
502
+ }
503
+
504
+ metrics["genai_requests"].add(1, attributes)
505
+ metrics["genai_total_tokens"].add(
506
+ response_dict.get('usage').get('total_tokens'), attributes)
507
+ metrics["genai_prompt_tokens"].add(
508
+ response_dict.get('usage').get('prompt_tokens'), attributes)
509
+ metrics["genai_cost"].record(cost, attributes)
510
+
511
+ # Return original response
512
+ return response
513
+
514
+ except Exception as e:
515
+ handle_exception(span, e)
516
+ logger.error("Error in trace creation: %s", e)
517
+
518
+ # Return original response
519
+ return response
520
+
521
+ return wrapper
@@ -446,11 +446,11 @@ def async_embedding(gen_ai_endpoint, version, environment, application_name,
446
446
 
447
447
  with tracer.start_as_current_span(gen_ai_endpoint, kind= SpanKind.CLIENT) as span:
448
448
  response = await wrapped(*args, **kwargs)
449
-
449
+ response_dict = response_as_dict(response)
450
450
  try:
451
451
  # Calculate cost of the operation
452
452
  cost = get_embed_model_cost(kwargs.get("model", "text-embedding-ada-002"),
453
- pricing_info, response.usage.prompt_tokens)
453
+ pricing_info, response_dict.get('usage').get('prompt_tokens'))
454
454
 
455
455
  # Set Span attributes
456
456
  span.set_attribute(TELEMETRY_SDK_NAME, "openlit")
@@ -473,9 +473,9 @@ def async_embedding(gen_ai_endpoint, version, environment, application_name,
473
473
  span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_USER,
474
474
  kwargs.get("user", ""))
475
475
  span.set_attribute(SemanticConvetion.GEN_AI_USAGE_PROMPT_TOKENS,
476
- response.usage.prompt_tokens)
476
+ response_dict.get('usage').get('prompt_tokens'))
477
477
  span.set_attribute(SemanticConvetion.GEN_AI_USAGE_TOTAL_TOKENS,
478
- response.usage.total_tokens)
478
+ response_dict.get('usage').get('total_tokens'))
479
479
  span.set_attribute(SemanticConvetion.GEN_AI_USAGE_COST,
480
480
  cost)
481
481
  if trace_content:
@@ -505,8 +505,10 @@ def async_embedding(gen_ai_endpoint, version, environment, application_name,
505
505
  }
506
506
 
507
507
  metrics["genai_requests"].add(1, attributes)
508
- metrics["genai_total_tokens"].add(response.usage.total_tokens, attributes)
509
- metrics["genai_prompt_tokens"].add(response.usage.prompt_tokens, attributes)
508
+ metrics["genai_total_tokens"].add(
509
+ response_dict.get('usage').get('total_tokens'), attributes)
510
+ metrics["genai_prompt_tokens"].add(
511
+ response_dict.get('usage').get('prompt_tokens'), attributes)
510
512
  metrics["genai_cost"].record(cost, attributes)
511
513
 
512
514
  # Return original response
@@ -446,11 +446,11 @@ def embedding(gen_ai_endpoint, version, environment, application_name,
446
446
 
447
447
  with tracer.start_as_current_span(gen_ai_endpoint, kind= SpanKind.CLIENT) as span:
448
448
  response = wrapped(*args, **kwargs)
449
-
449
+ response_dict = response_as_dict(response)
450
450
  try:
451
451
  # Calculate cost of the operation
452
452
  cost = get_embed_model_cost(kwargs.get("model", "text-embedding-ada-002"),
453
- pricing_info, response.usage.prompt_tokens)
453
+ pricing_info, response_dict.get('usage').get('prompt_tokens'))
454
454
 
455
455
  # Set Span attributes
456
456
  span.set_attribute(TELEMETRY_SDK_NAME, "openlit")
@@ -473,9 +473,9 @@ def embedding(gen_ai_endpoint, version, environment, application_name,
473
473
  span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_USER,
474
474
  kwargs.get("user", ""))
475
475
  span.set_attribute(SemanticConvetion.GEN_AI_USAGE_PROMPT_TOKENS,
476
- response.usage.prompt_tokens)
476
+ response_dict.get('usage').get('prompt_tokens'))
477
477
  span.set_attribute(SemanticConvetion.GEN_AI_USAGE_TOTAL_TOKENS,
478
- response.usage.total_tokens)
478
+ response_dict.get('usage').get('total_tokens'))
479
479
  span.set_attribute(SemanticConvetion.GEN_AI_USAGE_COST,
480
480
  cost)
481
481
  if trace_content:
@@ -505,8 +505,10 @@ def embedding(gen_ai_endpoint, version, environment, application_name,
505
505
  }
506
506
 
507
507
  metrics["genai_requests"].add(1, attributes)
508
- metrics["genai_total_tokens"].add(response.usage.total_tokens, attributes)
509
- metrics["genai_prompt_tokens"].add(response.usage.prompt_tokens, attributes)
508
+ metrics["genai_total_tokens"].add(
509
+ response_dict.get('usage').get('total_tokens'), attributes)
510
+ metrics["genai_prompt_tokens"].add(
511
+ response_dict.get('usage').get('prompt_tokens'), attributes)
510
512
  metrics["genai_cost"].record(cost, attributes)
511
513
 
512
514
  # Return original response
File without changes