|
| 1 | +import json |
| 2 | +from datetime import datetime |
| 3 | +from typing import Any, Dict, List, Optional |
| 4 | + |
| 5 | +from langfuse.model import PromptClient |
| 6 | + |
| 7 | +from ..serializer import EventSerializer |
| 8 | +from ..types import MapValue, SpanLevel |
| 9 | + |
| 10 | + |
| 11 | +class LangfuseSpanAttributes: |
| 12 | + # Langfuse-Trace attributes |
| 13 | + TRACE_NAME = "langfuse.trace.name" |
| 14 | + TRACE_ID = "langfuse.trace.id" |
| 15 | + TRACE_USER_ID = "user.id" |
| 16 | + TRACE_SESSION_ID = "session.id" |
| 17 | + TRACE_TAGS = "langfuse.trace.tags" |
| 18 | + TRACE_PUBLIC = "langfuse.trace.public" |
| 19 | + TRACE_METADATA = "langfuse.trace.metadata" |
| 20 | + TRACE_INPUT = "langfuse.trace.input" |
| 21 | + TRACE_OUTPUT = "langfuse.trace.output" |
| 22 | + |
| 23 | + # Langfuse-observation attributes |
| 24 | + OBSERVATION_NAME = "langfuse.observation.name" |
| 25 | + OBSERVATION_TYPE = "langfuse.observation.type" |
| 26 | + OBSERVATION_METADATA = "langfuse.observation.metadata" |
| 27 | + OBSERVATION_LEVEL = "langfuse.observation.level" |
| 28 | + OBSERVATION_STATUS_MESSAGE = "langfuse.observation.status_message" |
| 29 | + OBSERVATION_INPUT = "langfuse.observation.input" |
| 30 | + OBSERVATION_OUTPUT = "langfuse.observation.output" |
| 31 | + |
| 32 | + # Langfuse-observation of type Generation attributes |
| 33 | + OBSERVATION_COMPLETION_START_TIME = "langfuse.observation.completion_start_time" |
| 34 | + OBSERVATION_MODEL = "gen_ai.response.model" |
| 35 | + OBSERVATION_MODEL_PARAMETERS = "langfuse.observation.model_parameters" |
| 36 | + OBSERVATION_USAGE_DETAILS = "gen_ai.usage" |
| 37 | + OBSERVATION_COST_DETAILS = "langfuse.observation.cost_details" |
| 38 | + OBSERVATION_PROMPT_NAME = "langfuse.observation.prompt.name" |
| 39 | + OBSERVATION_PROMPT_VERSION = "langfuse.observation.prompt.version" |
| 40 | + |
| 41 | + # General |
| 42 | + ENVIRONMENT = "langfuse.environment" |
| 43 | + RELEASE = "langfuse.release" |
| 44 | + VERSION = "langfuse.version" |
| 45 | + |
| 46 | + |
| 47 | +def create_trace_attributes( |
| 48 | + *, |
| 49 | + name: Optional[str] = None, |
| 50 | + user_id: Optional[str] = None, |
| 51 | + session_id: Optional[str] = None, |
| 52 | + version: Optional[str] = None, |
| 53 | + release: Optional[str] = None, |
| 54 | + input: Optional[Any] = None, |
| 55 | + output: Optional[Any] = None, |
| 56 | + metadata: Optional[Any] = None, |
| 57 | + tags: Optional[List[str]] = None, |
| 58 | + public: Optional[bool] = None, |
| 59 | +): |
| 60 | + attributes = { |
| 61 | + LangfuseSpanAttributes.TRACE_NAME: name, |
| 62 | + LangfuseSpanAttributes.TRACE_USER_ID: user_id, |
| 63 | + LangfuseSpanAttributes.TRACE_SESSION_ID: session_id, |
| 64 | + LangfuseSpanAttributes.VERSION: version, |
| 65 | + LangfuseSpanAttributes.RELEASE: release, |
| 66 | + LangfuseSpanAttributes.TRACE_INPUT: _serialize(input), |
| 67 | + LangfuseSpanAttributes.TRACE_OUTPUT: _serialize(output), |
| 68 | + LangfuseSpanAttributes.TRACE_METADATA: _serialize(metadata), |
| 69 | + LangfuseSpanAttributes.TRACE_TAGS: tags, |
| 70 | + LangfuseSpanAttributes.TRACE_PUBLIC: public, |
| 71 | + } |
| 72 | + |
| 73 | + return {k: v for k, v in attributes.items() if v is not None} |
| 74 | + |
| 75 | + |
| 76 | +def create_span_attributes( |
| 77 | + *, |
| 78 | + metadata: Optional[Any] = None, |
| 79 | + input: Optional[Any] = None, |
| 80 | + output: Optional[Any] = None, |
| 81 | + level: Optional[SpanLevel] = None, |
| 82 | + status_message: Optional[str] = None, |
| 83 | + version: Optional[str] = None, |
| 84 | +): |
| 85 | + attributes = { |
| 86 | + LangfuseSpanAttributes.OBSERVATION_TYPE: "span", |
| 87 | + LangfuseSpanAttributes.OBSERVATION_LEVEL: level, |
| 88 | + LangfuseSpanAttributes.OBSERVATION_STATUS_MESSAGE: status_message, |
| 89 | + LangfuseSpanAttributes.VERSION: version, |
| 90 | + LangfuseSpanAttributes.OBSERVATION_INPUT: _serialize(input), |
| 91 | + LangfuseSpanAttributes.OBSERVATION_OUTPUT: _serialize(output), |
| 92 | + LangfuseSpanAttributes.OBSERVATION_METADATA: _serialize(metadata), |
| 93 | + } |
| 94 | + |
| 95 | + return {k: v for k, v in attributes.items() if v is not None} |
| 96 | + |
| 97 | + |
| 98 | +def create_generation_attributes( |
| 99 | + *, |
| 100 | + name: Optional[str] = None, |
| 101 | + completion_start_time: Optional[datetime] = None, |
| 102 | + metadata: Optional[Any] = None, |
| 103 | + level: Optional[SpanLevel] = None, |
| 104 | + status_message: Optional[str] = None, |
| 105 | + version: Optional[str] = None, |
| 106 | + model: Optional[str] = None, |
| 107 | + model_parameters: Optional[Dict[str, MapValue]] = None, |
| 108 | + input: Optional[Any] = None, |
| 109 | + output: Optional[Any] = None, |
| 110 | + usage_details: Optional[Dict[str, int]] = None, |
| 111 | + cost_details: Optional[Dict[str, float]] = None, |
| 112 | + prompt: Optional[PromptClient] = None, |
| 113 | +): |
| 114 | + attributes = { |
| 115 | + LangfuseSpanAttributes.OBSERVATION_TYPE: "generation", |
| 116 | + LangfuseSpanAttributes.OBSERVATION_NAME: name, |
| 117 | + LangfuseSpanAttributes.OBSERVATION_LEVEL: level, |
| 118 | + LangfuseSpanAttributes.OBSERVATION_STATUS_MESSAGE: status_message, |
| 119 | + LangfuseSpanAttributes.VERSION: version, |
| 120 | + LangfuseSpanAttributes.OBSERVATION_INPUT: _serialize(input), |
| 121 | + LangfuseSpanAttributes.OBSERVATION_OUTPUT: _serialize(output), |
| 122 | + LangfuseSpanAttributes.OBSERVATION_METADATA: _serialize(metadata), |
| 123 | + LangfuseSpanAttributes.OBSERVATION_MODEL: model, |
| 124 | + LangfuseSpanAttributes.OBSERVATION_PROMPT_NAME: prompt and prompt.name, |
| 125 | + LangfuseSpanAttributes.OBSERVATION_PROMPT_VERSION: prompt and prompt.version, |
| 126 | + LangfuseSpanAttributes.OBSERVATION_USAGE_DETAILS: _serialize(usage_details), |
| 127 | + LangfuseSpanAttributes.OBSERVATION_COST_DETAILS: _serialize(cost_details), |
| 128 | + LangfuseSpanAttributes.OBSERVATION_COMPLETION_START_TIME: _serialize( |
| 129 | + completion_start_time |
| 130 | + ), |
| 131 | + LangfuseSpanAttributes.OBSERVATION_MODEL_PARAMETERS: _serialize( |
| 132 | + model_parameters |
| 133 | + ), |
| 134 | + } |
| 135 | + |
| 136 | + return {k: v for k, v in attributes.items() if v is not None} |
| 137 | + |
| 138 | + |
| 139 | +def _serialize(obj): |
| 140 | + return json.dumps(obj, cls=EventSerializer) if obj is not None else None |
0 commit comments