Convert an LLMEvent to a Span with GenAI semantic conventions
(
self,
trace_id: Optional[str] = None,
parent_span_id: Optional[str] = None,
project_id: Optional[str] = None,
)
| 381 | end_timestamp: Optional[datetime] = None |
| 382 | |
| 383 | async def to_span( |
| 384 | self, |
| 385 | trace_id: Optional[str] = None, |
| 386 | parent_span_id: Optional[str] = None, |
| 387 | project_id: Optional[str] = None, |
| 388 | ) -> Span: |
| 389 | """Convert an LLMEvent to a Span with GenAI semantic conventions""" |
| 390 | |
| 391 | # Use GenAI semantic conventions for span attributes |
| 392 | # See: https://github.com/open-telemetry/semantic-conventions/blob/main/docs/gen-ai/gen-ai.md |
| 393 | |
| 394 | # { |
| 395 | # "gen_ai.completion.0.content": "Why couldn't the bicycle stand up by itself? It was two tired.", |
| 396 | # "gen_ai.completion.0.finish_reason": "stop", |
| 397 | # "gen_ai.completion.0.role": "assistant", |
| 398 | # "gen_ai.openai.api_base": "https://api.openai.com/v1/", |
| 399 | # "gen_ai.prompt.0.content": "Write a one-line joke", |
| 400 | # "gen_ai.prompt.0.role": "user", |
| 401 | # "gen_ai.request.model": "gpt-3.5-turbo", |
| 402 | # "gen_ai.response.id": "chatcmpl-B9ekm6iX1GDInqhtj5XlmIqFHamFf", |
| 403 | # "gen_ai.response.model": "gpt-3.5-turbo-0125", |
| 404 | # "gen_ai.system": "OpenAI", |
| 405 | # "gen_ai.usage.completion_tokens": "16", |
| 406 | # "gen_ai.usage.prompt_tokens": "12", |
| 407 | # "llm.headers": "None", |
| 408 | # "llm.is_streaming": "false", |
| 409 | # "llm.request.type": "chat", |
| 410 | # "llm.usage.total_tokens": "28" |
| 411 | # } |
| 412 | |
| 413 | span_attributes = { |
| 414 | "llm.id": str(self.id), |
| 415 | "llm.model": self.model if self.model else "", |
| 416 | "llm.prompt_tokens": str(self.prompt_tokens), |
| 417 | "llm.completion_tokens": str(self.completion_tokens), |
| 418 | "llm.total_tokens": str(self.prompt_tokens + self.completion_tokens), |
| 419 | "llm.cost": str(self.cost) if self.cost is not None else "0.0", |
| 420 | "session.id": str(self.session_id), |
| 421 | "agent.id": str(self.agent_id), |
| 422 | "thread.id": str(self.thread_id) if self.thread_id else "", |
| 423 | "llm.is_streaming": "false", |
| 424 | "llm.request.type": "chat", |
| 425 | "gen_ai.openai.api_base": "https://api.openai.com/v1/", |
| 426 | "gen_ai.usage.prompt_tokens": str(self.prompt_tokens), |
| 427 | "gen_ai.usage.completion_tokens": str(self.completion_tokens), |
| 428 | } |
| 429 | |
| 430 | try: |
| 431 | prompts = self.prompt.get('messages', self.prompt) |
| 432 | if not isinstance(prompts, list): |
| 433 | prompts = [prompts] |
| 434 | for i, prompt in enumerate(prompts): |
| 435 | if not isinstance(prompt, dict): |
| 436 | continue |
| 437 | if 'content' in prompt: |
| 438 | content = prompt['content'] |
| 439 | elif 'string' in prompt: |
| 440 | content = prompt['string'] |
no test coverage detected