arize-phoenix 4.12.1rc1__py3-none-any.whl → 4.14.1__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-4.12.1rc1.dist-info → arize_phoenix-4.14.1.dist-info}/METADATA +12 -9
- {arize_phoenix-4.12.1rc1.dist-info → arize_phoenix-4.14.1.dist-info}/RECORD +48 -49
- phoenix/db/bulk_inserter.py +3 -1
- phoenix/experiments/evaluators/base.py +4 -0
- phoenix/experiments/evaluators/code_evaluators.py +80 -0
- phoenix/experiments/evaluators/llm_evaluators.py +77 -1
- phoenix/experiments/evaluators/utils.py +70 -21
- phoenix/experiments/functions.py +14 -14
- phoenix/server/api/context.py +7 -3
- phoenix/server/api/dataloaders/average_experiment_run_latency.py +23 -23
- phoenix/server/api/dataloaders/experiment_error_rates.py +30 -10
- phoenix/server/api/dataloaders/experiment_run_counts.py +18 -5
- phoenix/server/api/input_types/{CreateSpanAnnotationsInput.py → CreateSpanAnnotationInput.py} +4 -2
- phoenix/server/api/input_types/{CreateTraceAnnotationsInput.py → CreateTraceAnnotationInput.py} +4 -2
- phoenix/server/api/input_types/{PatchAnnotationsInput.py → PatchAnnotationInput.py} +4 -2
- phoenix/server/api/mutations/span_annotations_mutations.py +12 -6
- phoenix/server/api/mutations/trace_annotations_mutations.py +12 -6
- phoenix/server/api/openapi/main.py +2 -18
- phoenix/server/api/openapi/schema.py +12 -12
- phoenix/server/api/routers/v1/__init__.py +83 -36
- phoenix/server/api/routers/v1/dataset_examples.py +123 -102
- phoenix/server/api/routers/v1/datasets.py +506 -390
- phoenix/server/api/routers/v1/evaluations.py +66 -73
- phoenix/server/api/routers/v1/experiment_evaluations.py +91 -68
- phoenix/server/api/routers/v1/experiment_runs.py +155 -98
- phoenix/server/api/routers/v1/experiments.py +181 -132
- phoenix/server/api/routers/v1/spans.py +173 -144
- phoenix/server/api/routers/v1/traces.py +128 -115
- phoenix/server/api/types/Experiment.py +2 -2
- phoenix/server/api/types/Inferences.py +1 -2
- phoenix/server/api/types/Model.py +1 -2
- phoenix/server/app.py +177 -152
- phoenix/server/openapi/docs.py +221 -0
- phoenix/server/static/.vite/manifest.json +31 -31
- phoenix/server/static/assets/{components-C8sm_r1F.js → components-DeS0YEmv.js} +2 -2
- phoenix/server/static/assets/index-CQgXRwU0.js +100 -0
- phoenix/server/static/assets/{pages-bN7juCjh.js → pages-hdjlFZhO.js} +275 -198
- phoenix/server/static/assets/{vendor-CUDAPm8e.js → vendor-DPvSDRn3.js} +1 -1
- phoenix/server/static/assets/{vendor-arizeai-Do2HOmcL.js → vendor-arizeai-CkvPT67c.js} +2 -2
- phoenix/server/static/assets/{vendor-codemirror-CrdxOlMs.js → vendor-codemirror-Cqwpwlua.js} +1 -1
- phoenix/server/static/assets/{vendor-recharts-PKRvByVe.js → vendor-recharts-5jlNaZuF.js} +1 -1
- phoenix/server/thread_server.py +2 -2
- phoenix/session/client.py +9 -8
- phoenix/trace/dsl/filter.py +40 -25
- phoenix/version.py +1 -1
- phoenix/server/api/routers/v1/pydantic_compat.py +0 -78
- phoenix/server/api/routers/v1/utils.py +0 -95
- phoenix/server/static/assets/index-BEKPzgQs.js +0 -100
- {arize_phoenix-4.12.1rc1.dist-info → arize_phoenix-4.14.1.dist-info}/WHEEL +0 -0
- {arize_phoenix-4.12.1rc1.dist-info → arize_phoenix-4.14.1.dist-info}/licenses/IP_NOTICE +0 -0
- {arize_phoenix-4.12.1rc1.dist-info → arize_phoenix-4.14.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
import gzip
|
|
2
2
|
import zlib
|
|
3
|
-
from typing import Any, Dict, List
|
|
3
|
+
from typing import Any, Dict, List
|
|
4
4
|
|
|
5
|
-
from fastapi import APIRouter, BackgroundTasks, Header, HTTPException
|
|
6
5
|
from google.protobuf.message import DecodeError
|
|
7
6
|
from opentelemetry.proto.collector.trace.v1.trace_service_pb2 import (
|
|
8
7
|
ExportTraceServiceRequest,
|
|
9
8
|
)
|
|
10
|
-
from pydantic import Field
|
|
11
9
|
from sqlalchemy import select
|
|
10
|
+
from starlette.background import BackgroundTask
|
|
12
11
|
from starlette.concurrency import run_in_threadpool
|
|
13
12
|
from starlette.datastructures import State
|
|
14
13
|
from starlette.requests import Request
|
|
14
|
+
from starlette.responses import JSONResponse, Response
|
|
15
15
|
from starlette.status import (
|
|
16
|
-
HTTP_204_NO_CONTENT,
|
|
17
16
|
HTTP_404_NOT_FOUND,
|
|
18
17
|
HTTP_415_UNSUPPORTED_MEDIA_TYPE,
|
|
19
18
|
HTTP_422_UNPROCESSABLE_ENTITY,
|
|
@@ -27,51 +26,40 @@ from phoenix.server.api.types.node import from_global_id_with_expected_type
|
|
|
27
26
|
from phoenix.trace.otel import decode_otlp_span
|
|
28
27
|
from phoenix.utilities.project import get_project_name
|
|
29
28
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
"content": {
|
|
56
|
-
"application/x-protobuf": {"schema": {"type": "string", "format": "binary"}}
|
|
57
|
-
},
|
|
58
|
-
}
|
|
59
|
-
},
|
|
60
|
-
)
|
|
61
|
-
async def post_traces(
|
|
62
|
-
request: Request,
|
|
63
|
-
background_tasks: BackgroundTasks,
|
|
64
|
-
content_type: Optional[str] = Header(default=None),
|
|
65
|
-
content_encoding: Optional[str] = Header(default=None),
|
|
66
|
-
) -> None:
|
|
29
|
+
|
|
30
|
+
async def post_traces(request: Request) -> Response:
|
|
31
|
+
"""
|
|
32
|
+
summary: Send traces to Phoenix
|
|
33
|
+
operationId: addTraces
|
|
34
|
+
tags:
|
|
35
|
+
- private
|
|
36
|
+
requestBody:
|
|
37
|
+
required: true
|
|
38
|
+
content:
|
|
39
|
+
application/x-protobuf:
|
|
40
|
+
schema:
|
|
41
|
+
type: string
|
|
42
|
+
format: binary
|
|
43
|
+
responses:
|
|
44
|
+
200:
|
|
45
|
+
description: Success
|
|
46
|
+
403:
|
|
47
|
+
description: Forbidden
|
|
48
|
+
415:
|
|
49
|
+
description: Unsupported content type, only gzipped protobuf
|
|
50
|
+
422:
|
|
51
|
+
description: Request body is invalid
|
|
52
|
+
"""
|
|
53
|
+
content_type = request.headers.get("content-type")
|
|
67
54
|
if content_type != "application/x-protobuf":
|
|
68
|
-
|
|
69
|
-
|
|
55
|
+
return Response(
|
|
56
|
+
content=f"Unsupported content type: {content_type}",
|
|
70
57
|
status_code=HTTP_415_UNSUPPORTED_MEDIA_TYPE,
|
|
71
58
|
)
|
|
59
|
+
content_encoding = request.headers.get("content-encoding")
|
|
72
60
|
if content_encoding and content_encoding not in ("gzip", "deflate"):
|
|
73
|
-
|
|
74
|
-
|
|
61
|
+
return Response(
|
|
62
|
+
content=f"Unsupported content encoding: {content_encoding}",
|
|
75
63
|
status_code=HTTP_415_UNSUPPORTED_MEDIA_TYPE,
|
|
76
64
|
)
|
|
77
65
|
body = await request.body()
|
|
@@ -83,69 +71,96 @@ async def post_traces(
|
|
|
83
71
|
try:
|
|
84
72
|
await run_in_threadpool(req.ParseFromString, body)
|
|
85
73
|
except DecodeError:
|
|
86
|
-
|
|
87
|
-
|
|
74
|
+
return Response(
|
|
75
|
+
content="Request body is invalid ExportTraceServiceRequest",
|
|
88
76
|
status_code=HTTP_422_UNPROCESSABLE_ENTITY,
|
|
89
77
|
)
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
78
|
+
return Response(background=BackgroundTask(_add_spans, req, request.state))
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
async def annotate_traces(request: Request) -> Response:
|
|
82
|
+
"""
|
|
83
|
+
summary: Upsert annotations for traces
|
|
84
|
+
operationId: annotateTraces
|
|
85
|
+
tags:
|
|
86
|
+
- private
|
|
87
|
+
requestBody:
|
|
88
|
+
description: List of trace annotations to be inserted
|
|
89
|
+
required: true
|
|
90
|
+
content:
|
|
91
|
+
application/json:
|
|
92
|
+
schema:
|
|
93
|
+
type: object
|
|
94
|
+
properties:
|
|
95
|
+
data:
|
|
96
|
+
type: array
|
|
97
|
+
items:
|
|
98
|
+
type: object
|
|
99
|
+
properties:
|
|
100
|
+
trace_id:
|
|
101
|
+
type: string
|
|
102
|
+
description: The ID of the trace being annotated
|
|
103
|
+
name:
|
|
104
|
+
type: string
|
|
105
|
+
description: The name of the annotation
|
|
106
|
+
annotator_kind:
|
|
107
|
+
type: string
|
|
108
|
+
description: The kind of annotator used for the annotation ("LLM" or "HUMAN")
|
|
109
|
+
result:
|
|
110
|
+
type: object
|
|
111
|
+
description: The result of the annotation
|
|
112
|
+
properties:
|
|
113
|
+
label:
|
|
114
|
+
type: string
|
|
115
|
+
description: The label assigned by the annotation
|
|
116
|
+
score:
|
|
117
|
+
type: number
|
|
118
|
+
format: float
|
|
119
|
+
description: The score assigned by the annotation
|
|
120
|
+
explanation:
|
|
121
|
+
type: string
|
|
122
|
+
description: Explanation of the annotation result
|
|
123
|
+
error:
|
|
124
|
+
type: string
|
|
125
|
+
description: Optional error message if the annotation encountered an error
|
|
126
|
+
metadata:
|
|
127
|
+
type: object
|
|
128
|
+
description: Metadata for the annotation
|
|
129
|
+
additionalProperties:
|
|
130
|
+
type: string
|
|
131
|
+
required:
|
|
132
|
+
- trace_id
|
|
133
|
+
- name
|
|
134
|
+
- annotator_kind
|
|
135
|
+
responses:
|
|
136
|
+
200:
|
|
137
|
+
description: Trace annotations inserted successfully
|
|
138
|
+
content:
|
|
139
|
+
application/json:
|
|
140
|
+
schema:
|
|
141
|
+
type: object
|
|
142
|
+
properties:
|
|
143
|
+
data:
|
|
144
|
+
type: array
|
|
145
|
+
items:
|
|
146
|
+
type: object
|
|
147
|
+
properties:
|
|
148
|
+
id:
|
|
149
|
+
type: string
|
|
150
|
+
description: The ID of the inserted trace annotation
|
|
151
|
+
404:
|
|
152
|
+
description: Trace not found
|
|
153
|
+
"""
|
|
154
|
+
payload: List[Dict[str, Any]] = (await request.json()).get("data", [])
|
|
155
|
+
trace_gids = [GlobalID.from_id(annotation["trace_id"]) for annotation in payload]
|
|
141
156
|
|
|
142
157
|
resolved_trace_ids = []
|
|
143
158
|
for trace_gid in trace_gids:
|
|
144
159
|
try:
|
|
145
160
|
resolved_trace_ids.append(from_global_id_with_expected_type(trace_gid, "Trace"))
|
|
146
161
|
except ValueError:
|
|
147
|
-
|
|
148
|
-
|
|
162
|
+
return Response(
|
|
163
|
+
content="Trace with ID {trace_gid} does not exist",
|
|
149
164
|
status_code=HTTP_404_NOT_FOUND,
|
|
150
165
|
)
|
|
151
166
|
|
|
@@ -160,24 +175,24 @@ async def annotate_traces(
|
|
|
160
175
|
missing_trace_gids = [
|
|
161
176
|
str(GlobalID("Trace", str(trace_gid))) for trace_gid in missing_trace_ids
|
|
162
177
|
]
|
|
163
|
-
|
|
164
|
-
|
|
178
|
+
return Response(
|
|
179
|
+
content=f"Traces with IDs {', '.join(missing_trace_gids)} do not exist.",
|
|
165
180
|
status_code=HTTP_404_NOT_FOUND,
|
|
166
181
|
)
|
|
167
182
|
|
|
168
183
|
inserted_annotations = []
|
|
169
184
|
|
|
170
|
-
for annotation in
|
|
171
|
-
trace_gid = GlobalID.from_id(annotation
|
|
185
|
+
for annotation in payload:
|
|
186
|
+
trace_gid = GlobalID.from_id(annotation["trace_id"])
|
|
172
187
|
trace_id = from_global_id_with_expected_type(trace_gid, "Trace")
|
|
173
188
|
|
|
174
|
-
name = annotation
|
|
175
|
-
annotator_kind = annotation
|
|
176
|
-
result = annotation.result
|
|
177
|
-
label = result.label if result else None
|
|
178
|
-
score = result.score if result else None
|
|
179
|
-
explanation = result.explanation if result else None
|
|
180
|
-
metadata = annotation.metadata or {}
|
|
189
|
+
name = annotation["name"]
|
|
190
|
+
annotator_kind = annotation["annotator_kind"]
|
|
191
|
+
result = annotation.get("result")
|
|
192
|
+
label = result.get("label") if result else None
|
|
193
|
+
score = result.get("score") if result else None
|
|
194
|
+
explanation = result.get("explanation") if result else None
|
|
195
|
+
metadata = annotation.get("metadata") or {}
|
|
181
196
|
|
|
182
197
|
values = dict(
|
|
183
198
|
trace_rowid=trace_id,
|
|
@@ -198,12 +213,10 @@ async def annotate_traces(
|
|
|
198
213
|
).returning(models.TraceAnnotation.id)
|
|
199
214
|
)
|
|
200
215
|
inserted_annotations.append(
|
|
201
|
-
|
|
202
|
-
id=str(GlobalID("TraceAnnotation", str(trace_annotation_id)))
|
|
203
|
-
)
|
|
216
|
+
{"id": str(GlobalID("TraceAnnotation", str(trace_annotation_id)))}
|
|
204
217
|
)
|
|
205
218
|
|
|
206
|
-
return
|
|
219
|
+
return JSONResponse(content={"data": inserted_annotations})
|
|
207
220
|
|
|
208
221
|
|
|
209
222
|
async def _add_spans(req: ExportTraceServiceRequest, state: State) -> None:
|
|
@@ -104,11 +104,11 @@ class Experiment(Node):
|
|
|
104
104
|
return await info.context.data_loaders.experiment_error_rates.load(self.id_attr)
|
|
105
105
|
|
|
106
106
|
@strawberry.field
|
|
107
|
-
async def average_run_latency_ms(self, info: Info[Context, None]) -> float:
|
|
107
|
+
async def average_run_latency_ms(self, info: Info[Context, None]) -> Optional[float]:
|
|
108
108
|
latency_seconds = await info.context.data_loaders.average_experiment_run_latency.load(
|
|
109
109
|
self.id_attr
|
|
110
110
|
)
|
|
111
|
-
return latency_seconds * 1000
|
|
111
|
+
return latency_seconds * 1000 if latency_seconds is not None else None
|
|
112
112
|
|
|
113
113
|
@strawberry.field
|
|
114
114
|
async def project(self, info: Info[Context, None]) -> Optional[Project]:
|
|
@@ -2,8 +2,7 @@ from datetime import datetime
|
|
|
2
2
|
from typing import Iterable, List, Optional, Set, Union
|
|
3
3
|
|
|
4
4
|
import strawberry
|
|
5
|
-
from strawberry
|
|
6
|
-
from strawberry.unset import UNSET
|
|
5
|
+
from strawberry import ID, UNSET
|
|
7
6
|
|
|
8
7
|
import phoenix.core.model_schema as ms
|
|
9
8
|
from phoenix.core.model_schema import FEATURE, TAG, ScalarDimension
|
|
@@ -2,9 +2,8 @@ import asyncio
|
|
|
2
2
|
from typing import List, Optional
|
|
3
3
|
|
|
4
4
|
import strawberry
|
|
5
|
+
from strawberry import UNSET, Info
|
|
5
6
|
from strawberry.relay import Connection
|
|
6
|
-
from strawberry.types import Info
|
|
7
|
-
from strawberry.unset import UNSET
|
|
8
7
|
from typing_extensions import Annotated
|
|
9
8
|
|
|
10
9
|
from phoenix.config import get_exported_files
|