arize-phoenix 0.0.32rc1__py3-none-any.whl → 0.0.33__py3-none-any.whl
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.
Potentially problematic release.
This version of arize-phoenix might be problematic. Click here for more details.
- {arize_phoenix-0.0.32rc1.dist-info → arize_phoenix-0.0.33.dist-info}/METADATA +11 -5
- {arize_phoenix-0.0.32rc1.dist-info → arize_phoenix-0.0.33.dist-info}/RECORD +69 -40
- phoenix/__init__.py +3 -1
- phoenix/config.py +23 -1
- phoenix/core/model_schema.py +14 -37
- phoenix/core/model_schema_adapter.py +0 -1
- phoenix/core/traces.py +285 -0
- phoenix/datasets/dataset.py +14 -21
- phoenix/datasets/errors.py +4 -1
- phoenix/datasets/schema.py +1 -1
- phoenix/datetime_utils.py +87 -0
- phoenix/experimental/callbacks/__init__.py +0 -0
- phoenix/experimental/callbacks/langchain_tracer.py +228 -0
- phoenix/experimental/callbacks/llama_index_trace_callback_handler.py +364 -0
- phoenix/experimental/evals/__init__.py +33 -0
- phoenix/experimental/evals/functions/__init__.py +4 -0
- phoenix/experimental/evals/functions/binary.py +156 -0
- phoenix/experimental/evals/functions/common.py +31 -0
- phoenix/experimental/evals/functions/generate.py +50 -0
- phoenix/experimental/evals/models/__init__.py +4 -0
- phoenix/experimental/evals/models/base.py +130 -0
- phoenix/experimental/evals/models/openai.py +128 -0
- phoenix/experimental/evals/retrievals.py +2 -2
- phoenix/experimental/evals/templates/__init__.py +24 -0
- phoenix/experimental/evals/templates/default_templates.py +126 -0
- phoenix/experimental/evals/templates/template.py +107 -0
- phoenix/experimental/evals/utils/__init__.py +0 -0
- phoenix/experimental/evals/utils/downloads.py +33 -0
- phoenix/experimental/evals/utils/threads.py +27 -0
- phoenix/experimental/evals/utils/types.py +9 -0
- phoenix/experimental/evals/utils.py +33 -0
- phoenix/metrics/binning.py +0 -1
- phoenix/metrics/timeseries.py +2 -3
- phoenix/server/api/context.py +2 -0
- phoenix/server/api/input_types/SpanSort.py +60 -0
- phoenix/server/api/schema.py +85 -4
- phoenix/server/api/types/DataQualityMetric.py +10 -1
- phoenix/server/api/types/Dataset.py +2 -4
- phoenix/server/api/types/DatasetInfo.py +10 -0
- phoenix/server/api/types/ExportEventsMutation.py +4 -1
- phoenix/server/api/types/Functionality.py +15 -0
- phoenix/server/api/types/MimeType.py +16 -0
- phoenix/server/api/types/Model.py +3 -5
- phoenix/server/api/types/SortDir.py +13 -0
- phoenix/server/api/types/Span.py +229 -0
- phoenix/server/api/types/TimeSeries.py +9 -2
- phoenix/server/api/types/pagination.py +2 -0
- phoenix/server/app.py +24 -4
- phoenix/server/main.py +60 -24
- phoenix/server/span_handler.py +39 -0
- phoenix/server/static/index.js +956 -479
- phoenix/server/thread_server.py +10 -2
- phoenix/services.py +39 -16
- phoenix/session/session.py +99 -27
- phoenix/trace/exporter.py +71 -0
- phoenix/trace/filter.py +181 -0
- phoenix/trace/fixtures.py +23 -8
- phoenix/trace/schemas.py +59 -6
- phoenix/trace/semantic_conventions.py +141 -1
- phoenix/trace/span_json_decoder.py +60 -6
- phoenix/trace/span_json_encoder.py +1 -9
- phoenix/trace/trace_dataset.py +100 -8
- phoenix/trace/tracer.py +26 -3
- phoenix/trace/v1/__init__.py +522 -0
- phoenix/trace/v1/trace_pb2.py +52 -0
- phoenix/trace/v1/trace_pb2.pyi +351 -0
- phoenix/core/dimension_data_type.py +0 -6
- phoenix/core/dimension_type.py +0 -9
- {arize_phoenix-0.0.32rc1.dist-info → arize_phoenix-0.0.33.dist-info}/WHEEL +0 -0
- {arize_phoenix-0.0.32rc1.dist-info → arize_phoenix-0.0.33.dist-info}/licenses/IP_NOTICE +0 -0
- {arize_phoenix-0.0.32rc1.dist-info → arize_phoenix-0.0.33.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,522 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from datetime import datetime, timezone
|
|
3
|
+
from itertools import chain
|
|
4
|
+
from typing import (
|
|
5
|
+
Any,
|
|
6
|
+
Dict,
|
|
7
|
+
Iterable,
|
|
8
|
+
Iterator,
|
|
9
|
+
Mapping,
|
|
10
|
+
Optional,
|
|
11
|
+
SupportsFloat,
|
|
12
|
+
Tuple,
|
|
13
|
+
Union,
|
|
14
|
+
cast,
|
|
15
|
+
)
|
|
16
|
+
from uuid import UUID
|
|
17
|
+
|
|
18
|
+
from google.protobuf.json_format import MessageToDict
|
|
19
|
+
from google.protobuf.struct_pb2 import Struct
|
|
20
|
+
from google.protobuf.timestamp_pb2 import Timestamp
|
|
21
|
+
from google.protobuf.wrappers_pb2 import BoolValue, BytesValue, FloatValue, StringValue
|
|
22
|
+
|
|
23
|
+
import phoenix.trace.v1.trace_pb2 as pb
|
|
24
|
+
from phoenix.trace.schemas import (
|
|
25
|
+
Span,
|
|
26
|
+
SpanContext,
|
|
27
|
+
SpanEvent,
|
|
28
|
+
SpanException,
|
|
29
|
+
SpanKind,
|
|
30
|
+
SpanStatusCode,
|
|
31
|
+
)
|
|
32
|
+
from phoenix.trace.semantic_conventions import (
|
|
33
|
+
DOCUMENT_CONTENT,
|
|
34
|
+
DOCUMENT_ID,
|
|
35
|
+
DOCUMENT_METADATA,
|
|
36
|
+
DOCUMENT_SCORE,
|
|
37
|
+
EMBEDDING_EMBEDDINGS,
|
|
38
|
+
EMBEDDING_MODEL_NAME,
|
|
39
|
+
EMBEDDING_TEXT,
|
|
40
|
+
EMBEDDING_VECTOR,
|
|
41
|
+
EXCEPTION_ESCAPED,
|
|
42
|
+
EXCEPTION_MESSAGE,
|
|
43
|
+
EXCEPTION_STACKTRACE,
|
|
44
|
+
EXCEPTION_TYPE,
|
|
45
|
+
INPUT_MIME_TYPE,
|
|
46
|
+
INPUT_VALUE,
|
|
47
|
+
OUTPUT_MIME_TYPE,
|
|
48
|
+
OUTPUT_VALUE,
|
|
49
|
+
RETRIEVAL_DOCUMENTS,
|
|
50
|
+
MimeType,
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def encode(span: Span) -> pb.Span:
|
|
55
|
+
_attributes: Mapping[str, Any] = dict(span.attributes)
|
|
56
|
+
retrieval, _attributes = _excise_retrieval(_attributes)
|
|
57
|
+
embedding, _attributes = _excise_embedding(_attributes)
|
|
58
|
+
input, _attributes = _excise_input(_attributes)
|
|
59
|
+
output, _attributes = _excise_output(_attributes)
|
|
60
|
+
status = pb.Span.Status(message=_maybe_str(span.status_message))
|
|
61
|
+
if span.status_code is SpanStatusCode.ERROR:
|
|
62
|
+
status.code = pb.Span.Status.Code.ERROR
|
|
63
|
+
elif span.status_code is SpanStatusCode.OK:
|
|
64
|
+
status.code = pb.Span.Status.Code.OK
|
|
65
|
+
parent_span_id = BytesValue(value=span.parent_id.bytes) if span.parent_id else None
|
|
66
|
+
pb_span = pb.Span(
|
|
67
|
+
start_time=_as_timestamp(span.start_time),
|
|
68
|
+
end_time=_maybe_timestamp(span.end_time),
|
|
69
|
+
status=status,
|
|
70
|
+
name=span.name,
|
|
71
|
+
kind=span.span_kind.value,
|
|
72
|
+
context=pb.Span.Context(
|
|
73
|
+
trace_id=span.context.trace_id.bytes,
|
|
74
|
+
span_id=span.context.span_id.bytes,
|
|
75
|
+
),
|
|
76
|
+
parent_span_id=parent_span_id,
|
|
77
|
+
attributes=_maybe_struct(_attributes),
|
|
78
|
+
input=input,
|
|
79
|
+
output=output,
|
|
80
|
+
retrieval=retrieval,
|
|
81
|
+
embedding=embedding,
|
|
82
|
+
)
|
|
83
|
+
for event in span.events:
|
|
84
|
+
if event.name == "exception":
|
|
85
|
+
pb_span.exceptions.append(
|
|
86
|
+
_encode_exception(
|
|
87
|
+
cast(SpanException, event),
|
|
88
|
+
),
|
|
89
|
+
)
|
|
90
|
+
else:
|
|
91
|
+
pb_span.events.append(
|
|
92
|
+
_encode_event(event),
|
|
93
|
+
)
|
|
94
|
+
return pb_span
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def decode(
|
|
98
|
+
pb_span: pb.Span,
|
|
99
|
+
) -> Span:
|
|
100
|
+
trace_id = UUID(bytes=pb_span.context.trace_id)
|
|
101
|
+
span_id = UUID(bytes=pb_span.context.span_id)
|
|
102
|
+
parent_id = (
|
|
103
|
+
UUID(bytes=pb_span.parent_span_id.value) if pb_span.HasField("parent_span_id") else None
|
|
104
|
+
)
|
|
105
|
+
start_time = pb_span.start_time.ToDatetime(timezone.utc)
|
|
106
|
+
end_time = pb_span.end_time.ToDatetime(timezone.utc) if pb_span.HasField("end_time") else None
|
|
107
|
+
attributes = MessageToDict(pb_span.attributes)
|
|
108
|
+
if pb_span.HasField("input"):
|
|
109
|
+
attributes.update(_decode_input(pb_span.input))
|
|
110
|
+
if pb_span.HasField("output"):
|
|
111
|
+
attributes.update(_decode_output(pb_span.output))
|
|
112
|
+
if pb_span.HasField("retrieval"):
|
|
113
|
+
attributes.update(_decode_retrieval(pb_span.retrieval))
|
|
114
|
+
if pb_span.HasField("embedding"):
|
|
115
|
+
attributes.update(_decode_embedding(pb_span.embedding))
|
|
116
|
+
events = sorted(
|
|
117
|
+
chain(
|
|
118
|
+
map(_decode_event, pb_span.events),
|
|
119
|
+
map(_decode_exception, pb_span.exceptions),
|
|
120
|
+
),
|
|
121
|
+
key=lambda event: event.timestamp,
|
|
122
|
+
)
|
|
123
|
+
status_code = SpanStatusCode.UNSET
|
|
124
|
+
if pb_span.status.code == pb.Span.Status.Code.OK:
|
|
125
|
+
status_code = SpanStatusCode.OK
|
|
126
|
+
elif pb_span.status.code == pb.Span.Status.Code.ERROR:
|
|
127
|
+
status_code = SpanStatusCode.ERROR
|
|
128
|
+
return Span(
|
|
129
|
+
name=pb_span.name,
|
|
130
|
+
context=SpanContext(trace_id=trace_id, span_id=span_id),
|
|
131
|
+
parent_id=parent_id,
|
|
132
|
+
span_kind=SpanKind(pb_span.kind.upper()),
|
|
133
|
+
start_time=start_time,
|
|
134
|
+
end_time=end_time,
|
|
135
|
+
attributes=attributes,
|
|
136
|
+
status_code=status_code,
|
|
137
|
+
status_message=pb_span.status.message.value,
|
|
138
|
+
conversation=None,
|
|
139
|
+
events=events,
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def _excise_input(
|
|
144
|
+
attributes: Mapping[str, Any],
|
|
145
|
+
) -> Tuple[Optional[pb.Span.IOValue], Dict[str, Any]]:
|
|
146
|
+
_attributes = dict(attributes)
|
|
147
|
+
if not (
|
|
148
|
+
_attributes.keys()
|
|
149
|
+
& {
|
|
150
|
+
INPUT_VALUE,
|
|
151
|
+
INPUT_MIME_TYPE,
|
|
152
|
+
}
|
|
153
|
+
):
|
|
154
|
+
return None, _attributes
|
|
155
|
+
input_value: Optional[str] = _attributes.pop(INPUT_VALUE, None)
|
|
156
|
+
assert input_value is None or isinstance(
|
|
157
|
+
input_value, str
|
|
158
|
+
), f"{INPUT_VALUE} must be str, found {type(input_value)}"
|
|
159
|
+
input_mime_type: Optional[MimeType] = _attributes.pop(INPUT_MIME_TYPE, None)
|
|
160
|
+
assert input_mime_type is None or isinstance(
|
|
161
|
+
input_mime_type, MimeType
|
|
162
|
+
), f"{INPUT_MIME_TYPE} must be MimeType, found {type(input_mime_type)}"
|
|
163
|
+
return (
|
|
164
|
+
_encode_io_value(
|
|
165
|
+
input_value or "",
|
|
166
|
+
input_mime_type,
|
|
167
|
+
),
|
|
168
|
+
_attributes,
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def _excise_output(
|
|
173
|
+
attributes: Mapping[str, Any],
|
|
174
|
+
) -> Tuple[Optional[pb.Span.IOValue], Dict[str, Any]]:
|
|
175
|
+
_attributes = dict(attributes)
|
|
176
|
+
if not (
|
|
177
|
+
_attributes.keys()
|
|
178
|
+
& {
|
|
179
|
+
OUTPUT_VALUE,
|
|
180
|
+
OUTPUT_MIME_TYPE,
|
|
181
|
+
}
|
|
182
|
+
):
|
|
183
|
+
return None, _attributes
|
|
184
|
+
output_value: Optional[str] = _attributes.pop(OUTPUT_VALUE, None)
|
|
185
|
+
assert output_value is None or isinstance(
|
|
186
|
+
output_value, str
|
|
187
|
+
), f"{OUTPUT_VALUE} must be str, found {type(output_value)}"
|
|
188
|
+
output_mime_type: Optional[MimeType] = _attributes.pop(OUTPUT_MIME_TYPE, None)
|
|
189
|
+
assert output_mime_type is None or isinstance(
|
|
190
|
+
output_mime_type, MimeType
|
|
191
|
+
), f"{OUTPUT_MIME_TYPE} must be MimeType, found {type(output_mime_type)}"
|
|
192
|
+
return (
|
|
193
|
+
_encode_io_value(
|
|
194
|
+
output_value or "",
|
|
195
|
+
output_mime_type,
|
|
196
|
+
),
|
|
197
|
+
_attributes,
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def _excise_retrieval(
|
|
202
|
+
attributes: Mapping[str, Any],
|
|
203
|
+
) -> Tuple[Optional[pb.Retrieval], Dict[str, Any]]:
|
|
204
|
+
_attributes = dict(attributes)
|
|
205
|
+
if not (
|
|
206
|
+
_attributes.keys()
|
|
207
|
+
& {
|
|
208
|
+
RETRIEVAL_DOCUMENTS,
|
|
209
|
+
}
|
|
210
|
+
):
|
|
211
|
+
return None, _attributes
|
|
212
|
+
documents: Optional[Iterable[Mapping[str, Any]]] = _attributes.pop(RETRIEVAL_DOCUMENTS, None)
|
|
213
|
+
assert documents is None or isinstance(
|
|
214
|
+
documents, Iterable
|
|
215
|
+
), f"{RETRIEVAL_DOCUMENTS} must be Iterable, found {type(documents)}"
|
|
216
|
+
return (
|
|
217
|
+
_encode_retrieval(documents=() if documents is None else documents),
|
|
218
|
+
_attributes,
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
def _excise_embedding(
|
|
223
|
+
attributes: Mapping[str, Any],
|
|
224
|
+
) -> Tuple[Optional[pb.Embedding], Dict[str, Any]]:
|
|
225
|
+
_attributes = dict(attributes)
|
|
226
|
+
if not (
|
|
227
|
+
_attributes.keys()
|
|
228
|
+
& {
|
|
229
|
+
EMBEDDING_EMBEDDINGS,
|
|
230
|
+
EMBEDDING_MODEL_NAME,
|
|
231
|
+
}
|
|
232
|
+
):
|
|
233
|
+
return None, _attributes
|
|
234
|
+
embeddings: Optional[Iterable[Mapping[str, Any]]] = _attributes.pop(EMBEDDING_EMBEDDINGS, None)
|
|
235
|
+
assert embeddings is None or isinstance(
|
|
236
|
+
embeddings, Iterable
|
|
237
|
+
), f"{EMBEDDING_EMBEDDINGS} must be Mapping, found {type(embeddings)}"
|
|
238
|
+
model_name: Optional[str] = _attributes.pop(EMBEDDING_MODEL_NAME, None)
|
|
239
|
+
assert model_name is None or isinstance(
|
|
240
|
+
model_name, str
|
|
241
|
+
), f"{EMBEDDING_MODEL_NAME} must be str, found {type(model_name)}"
|
|
242
|
+
return (
|
|
243
|
+
_encode_embedding(
|
|
244
|
+
embeddings=embeddings or (),
|
|
245
|
+
model_name=model_name,
|
|
246
|
+
),
|
|
247
|
+
_attributes,
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
def _encode_event(
|
|
252
|
+
span_event: SpanEvent,
|
|
253
|
+
) -> pb.Span.Event:
|
|
254
|
+
timestamp = Timestamp()
|
|
255
|
+
timestamp.FromDatetime(span_event.timestamp)
|
|
256
|
+
attributes = None
|
|
257
|
+
if span_event.attributes:
|
|
258
|
+
attributes = Struct()
|
|
259
|
+
attributes.update(span_event.attributes)
|
|
260
|
+
pb_span_event = pb.Span.Event(
|
|
261
|
+
name=span_event.name,
|
|
262
|
+
timestamp=timestamp,
|
|
263
|
+
attributes=attributes,
|
|
264
|
+
)
|
|
265
|
+
return pb_span_event
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
def _decode_event(
|
|
269
|
+
pb_span_event: pb.Span.Event,
|
|
270
|
+
) -> SpanEvent:
|
|
271
|
+
return SpanEvent(
|
|
272
|
+
name=pb_span_event.name,
|
|
273
|
+
timestamp=pb_span_event.timestamp.ToDatetime(timezone.utc),
|
|
274
|
+
attributes=MessageToDict(pb_span_event.attributes),
|
|
275
|
+
)
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
def _encode_exception(
|
|
279
|
+
span_exception: SpanException,
|
|
280
|
+
) -> pb.Span.Exception:
|
|
281
|
+
timestamp = Timestamp()
|
|
282
|
+
timestamp.FromDatetime(span_exception.timestamp)
|
|
283
|
+
_attributes: Dict[str, Any] = dict(span_exception.attributes)
|
|
284
|
+
exception_message: Optional[str] = _attributes.pop(EXCEPTION_MESSAGE, None)
|
|
285
|
+
assert exception_message is None or isinstance(
|
|
286
|
+
exception_message, str
|
|
287
|
+
), f"{EXCEPTION_MESSAGE} must be str, found {type(exception_message)}"
|
|
288
|
+
exception_type: Optional[str] = _attributes.pop(EXCEPTION_TYPE, None)
|
|
289
|
+
assert exception_type is None or isinstance(
|
|
290
|
+
exception_type, str
|
|
291
|
+
), f"{EXCEPTION_TYPE} must be str, found {type(exception_type)}"
|
|
292
|
+
exception_escaped: Optional[bool] = _attributes.pop(EXCEPTION_ESCAPED, None)
|
|
293
|
+
assert exception_escaped is None or isinstance(
|
|
294
|
+
exception_escaped, bool
|
|
295
|
+
), f"{EXCEPTION_ESCAPED} must be bool, found {type(exception_escaped)}"
|
|
296
|
+
exception_stacktrace: Optional[str] = _attributes.pop(EXCEPTION_STACKTRACE, None)
|
|
297
|
+
assert exception_stacktrace is None or isinstance(
|
|
298
|
+
exception_stacktrace, str
|
|
299
|
+
), f"{EXCEPTION_STACKTRACE} must be str, found {type(exception_stacktrace)}"
|
|
300
|
+
pb_span_exception = pb.Span.Exception(
|
|
301
|
+
timestamp=timestamp,
|
|
302
|
+
message=_maybe_str(exception_message),
|
|
303
|
+
type=_maybe_str(exception_type),
|
|
304
|
+
escaped=_maybe_bool(exception_escaped),
|
|
305
|
+
stacktrace=_maybe_str(exception_stacktrace),
|
|
306
|
+
attributes=_maybe_struct(_attributes),
|
|
307
|
+
)
|
|
308
|
+
return pb_span_exception
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
def _decode_exception(
|
|
312
|
+
pb_span_exception: pb.Span.Exception,
|
|
313
|
+
) -> SpanException:
|
|
314
|
+
exception_message = (
|
|
315
|
+
pb_span_exception.message.value if pb_span_exception.HasField("message") else None
|
|
316
|
+
)
|
|
317
|
+
exception_type = pb_span_exception.type.value if pb_span_exception.HasField("type") else None
|
|
318
|
+
exception_escaped = (
|
|
319
|
+
pb_span_exception.escaped.value if pb_span_exception.HasField("escaped") else None
|
|
320
|
+
)
|
|
321
|
+
exception_stacktrace = (
|
|
322
|
+
pb_span_exception.stacktrace.value if pb_span_exception.HasField("stacktrace") else None
|
|
323
|
+
)
|
|
324
|
+
span_exception = SpanException(
|
|
325
|
+
timestamp=pb_span_exception.timestamp.ToDatetime(timezone.utc),
|
|
326
|
+
message=exception_message or "",
|
|
327
|
+
exception_type=exception_type,
|
|
328
|
+
exception_escaped=exception_escaped,
|
|
329
|
+
exception_stacktrace=exception_stacktrace,
|
|
330
|
+
)
|
|
331
|
+
span_exception.attributes.update(
|
|
332
|
+
MessageToDict(
|
|
333
|
+
pb_span_exception.attributes,
|
|
334
|
+
),
|
|
335
|
+
)
|
|
336
|
+
return span_exception
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
def _decode_input(
|
|
340
|
+
pb_io_value: pb.Span.IOValue,
|
|
341
|
+
) -> Iterator[Tuple[str, Union[str, MimeType]]]:
|
|
342
|
+
return zip(
|
|
343
|
+
(INPUT_VALUE, INPUT_MIME_TYPE),
|
|
344
|
+
_decode_io_value(pb_io_value),
|
|
345
|
+
)
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
def _decode_output(
|
|
349
|
+
pb_io_value: pb.Span.IOValue,
|
|
350
|
+
) -> Iterator[Tuple[str, Union[str, MimeType]]]:
|
|
351
|
+
return zip(
|
|
352
|
+
(OUTPUT_VALUE, OUTPUT_MIME_TYPE),
|
|
353
|
+
_decode_io_value(pb_io_value),
|
|
354
|
+
)
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
def _encode_io_value(
|
|
358
|
+
io_value: str,
|
|
359
|
+
mime_type: Optional[MimeType],
|
|
360
|
+
) -> pb.Span.IOValue:
|
|
361
|
+
if mime_type is MimeType.JSON:
|
|
362
|
+
struct = Struct()
|
|
363
|
+
if io_value:
|
|
364
|
+
struct.update(json.loads(io_value))
|
|
365
|
+
return pb.Span.IOValue(json_value=struct)
|
|
366
|
+
return pb.Span.IOValue(string_value=io_value)
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
def _decode_io_value(
|
|
370
|
+
pb_io_value: pb.Span.IOValue,
|
|
371
|
+
) -> Iterator[Union[str, MimeType]]:
|
|
372
|
+
if pb_io_value.WhichOneof("kind") == "json_value":
|
|
373
|
+
yield json.dumps(MessageToDict(pb_io_value.json_value))
|
|
374
|
+
yield MimeType.JSON
|
|
375
|
+
else:
|
|
376
|
+
yield pb_io_value.string_value
|
|
377
|
+
|
|
378
|
+
|
|
379
|
+
def _encode_retrieval(
|
|
380
|
+
documents: Iterable[Mapping[str, Any]],
|
|
381
|
+
) -> pb.Retrieval:
|
|
382
|
+
return pb.Retrieval(
|
|
383
|
+
documents=map(
|
|
384
|
+
_encode_retrieval_document,
|
|
385
|
+
documents,
|
|
386
|
+
),
|
|
387
|
+
)
|
|
388
|
+
|
|
389
|
+
|
|
390
|
+
def _decode_retrieval(
|
|
391
|
+
pb_retrieval: pb.Retrieval,
|
|
392
|
+
) -> Iterator[Tuple[str, Any]]:
|
|
393
|
+
yield RETRIEVAL_DOCUMENTS, [
|
|
394
|
+
dict(_decode_retrieval_document(pb_retrieval_document))
|
|
395
|
+
for pb_retrieval_document in pb_retrieval.documents
|
|
396
|
+
]
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
def _encode_retrieval_document(
|
|
400
|
+
document: Mapping[str, Any],
|
|
401
|
+
) -> pb.Retrieval.Document:
|
|
402
|
+
_attributes: Dict[str, Any] = dict(document)
|
|
403
|
+
document_id: Optional[str] = _attributes.pop(DOCUMENT_ID, None)
|
|
404
|
+
assert document_id is None or isinstance(
|
|
405
|
+
document_id, str
|
|
406
|
+
), f"{DOCUMENT_ID} must be str, found {type(document_id)}"
|
|
407
|
+
document_score: Optional[float] = _attributes.pop(DOCUMENT_SCORE, None)
|
|
408
|
+
assert document_score is None or isinstance(
|
|
409
|
+
document_score, SupportsFloat
|
|
410
|
+
), f"{DOCUMENT_SCORE} must be float, found {type(document_score)}"
|
|
411
|
+
document_content: Optional[str] = _attributes.pop(DOCUMENT_CONTENT, None)
|
|
412
|
+
assert document_content is None or isinstance(
|
|
413
|
+
document_content, str
|
|
414
|
+
), f"{DOCUMENT_CONTENT} must be str, found {type(document_content)}"
|
|
415
|
+
document_metadata: Optional[Mapping[str, Any]] = _attributes.pop(DOCUMENT_METADATA, None)
|
|
416
|
+
assert document_metadata is None or isinstance(
|
|
417
|
+
document_metadata, Mapping
|
|
418
|
+
), f"{DOCUMENT_METADATA} must be Mapping, found {type(document_metadata)}"
|
|
419
|
+
return pb.Retrieval.Document(
|
|
420
|
+
id=_maybe_str(document_id),
|
|
421
|
+
score=_maybe_float(document_score),
|
|
422
|
+
content=_maybe_str(document_content),
|
|
423
|
+
metadata=_maybe_struct(document_metadata),
|
|
424
|
+
attributes=_maybe_struct(_attributes),
|
|
425
|
+
)
|
|
426
|
+
|
|
427
|
+
|
|
428
|
+
def _decode_retrieval_document(
|
|
429
|
+
pb_document: pb.Retrieval.Document,
|
|
430
|
+
) -> Iterator[Tuple[str, Any]]:
|
|
431
|
+
if pb_document.HasField("id"):
|
|
432
|
+
yield DOCUMENT_ID, pb_document.id.value
|
|
433
|
+
if pb_document.HasField("score"):
|
|
434
|
+
yield DOCUMENT_SCORE, pb_document.score.value
|
|
435
|
+
if pb_document.HasField("content"):
|
|
436
|
+
yield DOCUMENT_CONTENT, pb_document.content.value
|
|
437
|
+
if pb_document.HasField("metadata"):
|
|
438
|
+
yield DOCUMENT_METADATA, MessageToDict(pb_document.metadata)
|
|
439
|
+
if pb_document.HasField("attributes"):
|
|
440
|
+
yield from MessageToDict(pb_document.attributes).items()
|
|
441
|
+
|
|
442
|
+
|
|
443
|
+
def _encode_embedding(
|
|
444
|
+
embeddings: Iterable[Mapping[str, Any]],
|
|
445
|
+
model_name: Optional[str],
|
|
446
|
+
) -> pb.Embedding:
|
|
447
|
+
return pb.Embedding(
|
|
448
|
+
model_name=_maybe_str(model_name),
|
|
449
|
+
embeddings=map(_encode_embedding_embedding, embeddings),
|
|
450
|
+
)
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
def _decode_embedding(
|
|
454
|
+
pb_embedding: pb.Embedding,
|
|
455
|
+
) -> Iterator[Tuple[str, Any]]:
|
|
456
|
+
if pb_embedding.HasField("model_name"):
|
|
457
|
+
yield EMBEDDING_MODEL_NAME, pb_embedding.model_name.value
|
|
458
|
+
yield EMBEDDING_EMBEDDINGS, [
|
|
459
|
+
dict(_decode_embedding_embedding(pb_embedding_embedding))
|
|
460
|
+
for pb_embedding_embedding in pb_embedding.embeddings
|
|
461
|
+
]
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
def _encode_embedding_embedding(
|
|
465
|
+
embedding: Mapping[str, Any],
|
|
466
|
+
) -> pb.Embedding.Embedding:
|
|
467
|
+
_attributes = dict(embedding)
|
|
468
|
+
vector: Optional[Iterable[float]] = _attributes.pop(EMBEDDING_VECTOR, None)
|
|
469
|
+
assert vector is None or isinstance(
|
|
470
|
+
vector, Iterable
|
|
471
|
+
), f"{EMBEDDING_VECTOR} must be Iterable, found {type(vector)}"
|
|
472
|
+
embedding_text: Optional[str] = _attributes.pop(EMBEDDING_TEXT, None)
|
|
473
|
+
assert embedding_text is None or isinstance(
|
|
474
|
+
embedding_text, str
|
|
475
|
+
), f"{EMBEDDING_TEXT} must be str, found {type(embedding_text)}"
|
|
476
|
+
return pb.Embedding.Embedding(
|
|
477
|
+
vector=() if vector is None else vector,
|
|
478
|
+
text=_maybe_str(embedding_text),
|
|
479
|
+
attributes=_maybe_struct(_attributes),
|
|
480
|
+
)
|
|
481
|
+
|
|
482
|
+
|
|
483
|
+
def _decode_embedding_embedding(
|
|
484
|
+
pb_embedding_embedding: pb.Embedding.Embedding,
|
|
485
|
+
) -> Iterator[Tuple[str, Any]]:
|
|
486
|
+
yield EMBEDDING_VECTOR, list(pb_embedding_embedding.vector)
|
|
487
|
+
if pb_embedding_embedding.HasField("text"):
|
|
488
|
+
yield EMBEDDING_TEXT, pb_embedding_embedding.text.value
|
|
489
|
+
if pb_embedding_embedding.HasField("attributes"):
|
|
490
|
+
yield from MessageToDict(pb_embedding_embedding.attributes).items()
|
|
491
|
+
|
|
492
|
+
|
|
493
|
+
def _maybe_str(obj: Optional[str]) -> Optional[StringValue]:
|
|
494
|
+
return None if not obj else StringValue(value=obj)
|
|
495
|
+
|
|
496
|
+
|
|
497
|
+
def _maybe_float(obj: Optional[float]) -> Optional[FloatValue]:
|
|
498
|
+
return None if obj is None else FloatValue(value=obj)
|
|
499
|
+
|
|
500
|
+
|
|
501
|
+
def _maybe_bool(obj: Optional[bool]) -> Optional[BoolValue]:
|
|
502
|
+
return None if obj is None else BoolValue(value=obj)
|
|
503
|
+
|
|
504
|
+
|
|
505
|
+
def _as_timestamp(obj: datetime) -> Timestamp:
|
|
506
|
+
timestamp = Timestamp()
|
|
507
|
+
timestamp.FromDatetime(obj)
|
|
508
|
+
return timestamp
|
|
509
|
+
|
|
510
|
+
|
|
511
|
+
def _maybe_timestamp(obj: Optional[datetime]) -> Optional[Timestamp]:
|
|
512
|
+
return _as_timestamp(obj) if obj else None
|
|
513
|
+
|
|
514
|
+
|
|
515
|
+
def _as_struct(obj: Mapping[str, Any]) -> Struct:
|
|
516
|
+
struct = Struct()
|
|
517
|
+
struct.update(obj)
|
|
518
|
+
return struct
|
|
519
|
+
|
|
520
|
+
|
|
521
|
+
def _maybe_struct(obj: Optional[Mapping[str, Any]]) -> Optional[Struct]:
|
|
522
|
+
return _as_struct(obj) if obj else None
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
|
3
|
+
# source: trace/v1/trace.proto
|
|
4
|
+
"""Generated protocol buffer code."""
|
|
5
|
+
from google.protobuf.internal import builder as _builder
|
|
6
|
+
from google.protobuf import descriptor as _descriptor
|
|
7
|
+
from google.protobuf import descriptor_pool as _descriptor_pool
|
|
8
|
+
from google.protobuf import symbol_database as _symbol_database
|
|
9
|
+
# @@protoc_insertion_point(imports)
|
|
10
|
+
|
|
11
|
+
_sym_db = _symbol_database.Default()
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2
|
|
15
|
+
from google.protobuf import struct_pb2 as google_dot_protobuf_dot_struct__pb2
|
|
16
|
+
from google.protobuf import wrappers_pb2 as google_dot_protobuf_dot_wrappers__pb2
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x14trace/v1/trace.proto\x12\x16phoenix.proto.trace.v1\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x1cgoogle/protobuf/struct.proto\x1a\x1egoogle/protobuf/wrappers.proto\"\xa2\x0b\n\x04Span\x12+\n\nattributes\x18\x01 \x01(\x0b\x32\x17.google.protobuf.Struct\x12\x35\n\x07\x63ontext\x18\x02 \x01(\x0b\x32$.phoenix.proto.trace.v1.Span.Context\x12\x33\n\x0eparent_span_id\x18\x03 \x01(\x0b\x32\x1b.google.protobuf.BytesValue\x12\x0c\n\x04name\x18\x04 \x01(\t\x12.\n\nstart_time\x18\x05 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12,\n\x08\x65nd_time\x18\x06 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x33\n\x06status\x18\x07 \x01(\x0b\x32#.phoenix.proto.trace.v1.Span.Status\x12\x32\n\x06\x65vents\x18\x08 \x03(\x0b\x32\".phoenix.proto.trace.v1.Span.Event\x12:\n\nexceptions\x18\t \x03(\x0b\x32&.phoenix.proto.trace.v1.Span.Exception\x12\x33\n\x05input\x18\n \x01(\x0b\x32$.phoenix.proto.trace.v1.Span.IOValue\x12\x34\n\x06output\x18\x0b \x01(\x0b\x32$.phoenix.proto.trace.v1.Span.IOValue\x12\x0c\n\x04kind\x18\x0c \x01(\t\x12\x34\n\tretrieval\x18\r \x01(\x0b\x32!.phoenix.proto.trace.v1.Retrieval\x12\x34\n\tembedding\x18\x0e \x01(\x0b\x32!.phoenix.proto.trace.v1.Embedding\x12(\n\x03llm\x18\x0f \x01(\x0b\x32\x1b.phoenix.proto.trace.v1.LLM\x12*\n\x04tool\x18\x10 \x01(\x0b\x32\x1c.phoenix.proto.trace.v1.Tool\x1a,\n\x07\x43ontext\x12\x10\n\x08trace_id\x18\x01 \x01(\x0c\x12\x0f\n\x07span_id\x18\x02 \x01(\x0c\x1a\x95\x01\n\x06Status\x12\x36\n\x04\x63ode\x18\x01 \x01(\x0e\x32(.phoenix.proto.trace.v1.Span.Status.Code\x12-\n\x07message\x18\x02 \x01(\x0b\x32\x1c.google.protobuf.StringValue\"$\n\x04\x43ode\x12\t\n\x05UNSET\x10\x00\x12\x06\n\x02OK\x10\x01\x12\t\n\x05\x45RROR\x10\x02\x1aq\n\x05\x45vent\x12+\n\nattributes\x18\x01 \x01(\x0b\x32\x17.google.protobuf.Struct\x12\x0c\n\x04name\x18\x02 \x01(\t\x12-\n\ttimestamp\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x1a\xa1\x02\n\tException\x12+\n\nattributes\x18\x01 \x01(\x0b\x32\x17.google.protobuf.Struct\x12-\n\x07message\x18\x02 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12*\n\x04type\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12+\n\x07\x65scaped\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.BoolValue\x12\x30\n\nstacktrace\x18\x05 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12-\n\ttimestamp\x18\x06 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x1aX\n\x07IOValue\x12\x16\n\x0cstring_value\x18\x01 \x01(\tH\x00\x12-\n\njson_value\x18\x02 \x01(\x0b\x32\x17.google.protobuf.StructH\x00\x42\x06\n\x04kind\"\xdf\x02\n\tRetrieval\x12=\n\tdocuments\x18\x01 \x03(\x0b\x32*.phoenix.proto.trace.v1.Retrieval.Document\x1a\x92\x02\n\x08\x44ocument\x12+\n\nattributes\x18\x01 \x01(\x0b\x32\x17.google.protobuf.Struct\x12(\n\x02id\x18\x02 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12*\n\x05score\x18\x03 \x01(\x0b\x32\x1b.google.protobuf.FloatValue\x12-\n\x07\x63ontent\x18\x04 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12)\n\x08metadata\x18\x05 \x01(\x0b\x32\x17.google.protobuf.Struct\x12)\n\x04hash\x18\x06 \x01(\x0b\x32\x1b.google.protobuf.BytesValue\"\xf4\x01\n\tEmbedding\x12?\n\nembeddings\x18\x01 \x03(\x0b\x32+.phoenix.proto.trace.v1.Embedding.Embedding\x12\x30\n\nmodel_name\x18\x02 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x1at\n\tEmbedding\x12+\n\nattributes\x18\x01 \x01(\x0b\x32\x17.google.protobuf.Struct\x12\x0e\n\x06vector\x18\x02 \x03(\x02\x12*\n\x04text\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.StringValue\"2\n\x03LLM\x12+\n\nattributes\x18\x01 \x01(\x0b\x32\x17.google.protobuf.Struct\"3\n\x04Tool\x12+\n\nattributes\x18\x01 \x01(\x0b\x32\x17.google.protobuf.Structb\x06proto3')
|
|
20
|
+
|
|
21
|
+
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
|
|
22
|
+
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'trace.v1.trace_pb2', globals())
|
|
23
|
+
if _descriptor._USE_C_DESCRIPTORS == False:
|
|
24
|
+
|
|
25
|
+
DESCRIPTOR._options = None
|
|
26
|
+
_SPAN._serialized_start=144
|
|
27
|
+
_SPAN._serialized_end=1586
|
|
28
|
+
_SPAN_CONTEXT._serialized_start=893
|
|
29
|
+
_SPAN_CONTEXT._serialized_end=937
|
|
30
|
+
_SPAN_STATUS._serialized_start=940
|
|
31
|
+
_SPAN_STATUS._serialized_end=1089
|
|
32
|
+
_SPAN_STATUS_CODE._serialized_start=1053
|
|
33
|
+
_SPAN_STATUS_CODE._serialized_end=1089
|
|
34
|
+
_SPAN_EVENT._serialized_start=1091
|
|
35
|
+
_SPAN_EVENT._serialized_end=1204
|
|
36
|
+
_SPAN_EXCEPTION._serialized_start=1207
|
|
37
|
+
_SPAN_EXCEPTION._serialized_end=1496
|
|
38
|
+
_SPAN_IOVALUE._serialized_start=1498
|
|
39
|
+
_SPAN_IOVALUE._serialized_end=1586
|
|
40
|
+
_RETRIEVAL._serialized_start=1589
|
|
41
|
+
_RETRIEVAL._serialized_end=1940
|
|
42
|
+
_RETRIEVAL_DOCUMENT._serialized_start=1666
|
|
43
|
+
_RETRIEVAL_DOCUMENT._serialized_end=1940
|
|
44
|
+
_EMBEDDING._serialized_start=1943
|
|
45
|
+
_EMBEDDING._serialized_end=2187
|
|
46
|
+
_EMBEDDING_EMBEDDING._serialized_start=2071
|
|
47
|
+
_EMBEDDING_EMBEDDING._serialized_end=2187
|
|
48
|
+
_LLM._serialized_start=2189
|
|
49
|
+
_LLM._serialized_end=2239
|
|
50
|
+
_TOOL._serialized_start=2241
|
|
51
|
+
_TOOL._serialized_end=2292
|
|
52
|
+
# @@protoc_insertion_point(module_scope)
|