arize-phoenix 4.10.2rc2__py3-none-any.whl → 4.12.0__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.10.2rc2.dist-info → arize_phoenix-4.12.0.dist-info}/METADATA +3 -4
- {arize_phoenix-4.10.2rc2.dist-info → arize_phoenix-4.12.0.dist-info}/RECORD +29 -29
- phoenix/server/api/context.py +7 -3
- 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 +507 -389
- phoenix/server/api/routers/v1/evaluations.py +66 -73
- phoenix/server/api/routers/v1/experiment_evaluations.py +91 -67
- phoenix/server/api/routers/v1/experiment_runs.py +155 -97
- phoenix/server/api/routers/v1/experiments.py +181 -131
- phoenix/server/api/routers/v1/spans.py +173 -143
- phoenix/server/api/routers/v1/traces.py +128 -114
- phoenix/server/api/types/Span.py +1 -0
- phoenix/server/app.py +176 -148
- phoenix/server/openapi/docs.py +221 -0
- phoenix/server/static/index.js +574 -573
- phoenix/server/thread_server.py +2 -2
- phoenix/session/client.py +5 -0
- phoenix/session/data_extractor.py +20 -1
- phoenix/session/session.py +4 -0
- phoenix/trace/attributes.py +2 -1
- phoenix/trace/schemas.py +1 -0
- phoenix/trace/span_json_decoder.py +1 -1
- phoenix/version.py +1 -1
- phoenix/server/api/routers/v1/utils.py +0 -94
- {arize_phoenix-4.10.2rc2.dist-info → arize_phoenix-4.12.0.dist-info}/WHEEL +0 -0
- {arize_phoenix-4.10.2rc2.dist-info → arize_phoenix-4.12.0.dist-info}/licenses/IP_NOTICE +0 -0
- {arize_phoenix-4.10.2rc2.dist-info → arize_phoenix-4.12.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
from datetime import datetime
|
|
2
|
-
from typing import Any, List, Optional
|
|
3
2
|
|
|
4
|
-
from fastapi import APIRouter, HTTPException
|
|
5
|
-
from pydantic import BaseModel, Field
|
|
6
3
|
from sqlalchemy import select
|
|
7
4
|
from starlette.requests import Request
|
|
5
|
+
from starlette.responses import JSONResponse, Response
|
|
8
6
|
from starlette.status import HTTP_404_NOT_FOUND
|
|
9
7
|
from strawberry.relay import GlobalID
|
|
10
8
|
|
|
@@ -12,128 +10,188 @@ from phoenix.db import models
|
|
|
12
10
|
from phoenix.db.models import ExperimentRunOutput
|
|
13
11
|
from phoenix.server.api.types.node import from_global_id_with_expected_type
|
|
14
12
|
|
|
15
|
-
from .utils import ResponseBody, add_errors_to_responses
|
|
16
13
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
14
|
+
async def create_experiment_run(request: Request) -> Response:
|
|
15
|
+
"""
|
|
16
|
+
summary: Create a new experiment run for a specific experiment
|
|
17
|
+
operationId: createExperimentRun
|
|
18
|
+
tags:
|
|
19
|
+
- private
|
|
20
|
+
parameters:
|
|
21
|
+
- in: path
|
|
22
|
+
name: experiment_id
|
|
23
|
+
required: true
|
|
24
|
+
description: The ID of the experiment for which the run is being created
|
|
25
|
+
schema:
|
|
26
|
+
type: string
|
|
27
|
+
requestBody:
|
|
28
|
+
description: Details of the experiment run to be created
|
|
29
|
+
required: true
|
|
30
|
+
content:
|
|
31
|
+
application/json:
|
|
32
|
+
schema:
|
|
33
|
+
type: object
|
|
34
|
+
properties:
|
|
35
|
+
dataset_example_id:
|
|
36
|
+
type: string
|
|
37
|
+
description: The ID of the dataset example used in the experiment run
|
|
38
|
+
trace_id:
|
|
39
|
+
type: string
|
|
40
|
+
description: Optional trace ID for tracking
|
|
41
|
+
output:
|
|
42
|
+
description: The output of the experiment task
|
|
43
|
+
repetition_number:
|
|
44
|
+
type: integer
|
|
45
|
+
description: The repetition number of the experiment run
|
|
46
|
+
start_time:
|
|
47
|
+
type: string
|
|
48
|
+
format: date-time
|
|
49
|
+
description: The start time of the experiment run in ISO format
|
|
50
|
+
end_time:
|
|
51
|
+
type: string
|
|
52
|
+
format: date-time
|
|
53
|
+
description: The end time of the experiment run in ISO format
|
|
54
|
+
error:
|
|
55
|
+
type: string
|
|
56
|
+
description: Optional error message if the experiment run encountered an error
|
|
57
|
+
nullable: true
|
|
58
|
+
required:
|
|
59
|
+
- dataset_example_id
|
|
60
|
+
- output
|
|
61
|
+
- repetition_number
|
|
62
|
+
- start_time
|
|
63
|
+
- end_time
|
|
64
|
+
responses:
|
|
65
|
+
200:
|
|
66
|
+
description: Experiment run created successfully
|
|
67
|
+
content:
|
|
68
|
+
application/json:
|
|
69
|
+
schema:
|
|
70
|
+
type: object
|
|
71
|
+
properties:
|
|
72
|
+
data:
|
|
73
|
+
type: object
|
|
74
|
+
properties:
|
|
75
|
+
id:
|
|
76
|
+
type: string
|
|
77
|
+
description: The ID of the created experiment run
|
|
78
|
+
404:
|
|
79
|
+
description: Experiment or DatasetExample not found
|
|
80
|
+
"""
|
|
81
|
+
experiment_gid = GlobalID.from_id(request.path_params["experiment_id"])
|
|
67
82
|
try:
|
|
68
|
-
|
|
83
|
+
experiment_id = from_global_id_with_expected_type(experiment_gid, "Experiment")
|
|
69
84
|
except ValueError:
|
|
70
|
-
|
|
71
|
-
|
|
85
|
+
return Response(
|
|
86
|
+
content=f"Experiment with ID {experiment_gid} does not exist",
|
|
72
87
|
status_code=HTTP_404_NOT_FOUND,
|
|
73
88
|
)
|
|
74
89
|
|
|
75
|
-
|
|
90
|
+
payload = await request.json()
|
|
91
|
+
|
|
92
|
+
example_gid = GlobalID.from_id(payload["dataset_example_id"])
|
|
76
93
|
try:
|
|
77
94
|
dataset_example_id = from_global_id_with_expected_type(example_gid, "DatasetExample")
|
|
78
95
|
except ValueError:
|
|
79
|
-
|
|
80
|
-
|
|
96
|
+
return Response(
|
|
97
|
+
content=f"DatasetExample with ID {example_gid} does not exist",
|
|
81
98
|
status_code=HTTP_404_NOT_FOUND,
|
|
82
99
|
)
|
|
83
100
|
|
|
84
|
-
trace_id =
|
|
85
|
-
task_output =
|
|
86
|
-
repetition_number =
|
|
87
|
-
start_time =
|
|
88
|
-
end_time =
|
|
89
|
-
error =
|
|
101
|
+
trace_id = payload.get("trace_id", None)
|
|
102
|
+
task_output = payload["output"]
|
|
103
|
+
repetition_number = payload["repetition_number"]
|
|
104
|
+
start_time = payload["start_time"]
|
|
105
|
+
end_time = payload["end_time"]
|
|
106
|
+
error = payload.get("error")
|
|
90
107
|
|
|
91
108
|
async with request.app.state.db() as session:
|
|
92
109
|
exp_run = models.ExperimentRun(
|
|
93
|
-
experiment_id=
|
|
110
|
+
experiment_id=experiment_id,
|
|
94
111
|
dataset_example_id=dataset_example_id,
|
|
95
112
|
trace_id=trace_id,
|
|
96
113
|
output=ExperimentRunOutput(task_output=task_output),
|
|
97
114
|
repetition_number=repetition_number,
|
|
98
|
-
start_time=start_time,
|
|
99
|
-
end_time=end_time,
|
|
115
|
+
start_time=datetime.fromisoformat(start_time),
|
|
116
|
+
end_time=datetime.fromisoformat(end_time),
|
|
100
117
|
error=error,
|
|
101
118
|
)
|
|
102
119
|
session.add(exp_run)
|
|
103
120
|
await session.flush()
|
|
104
121
|
run_gid = GlobalID("ExperimentRun", str(exp_run.id))
|
|
105
|
-
return
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
122
|
+
return JSONResponse(content={"data": {"id": str(run_gid)}})
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
async def list_experiment_runs(request: Request) -> Response:
|
|
126
|
+
"""
|
|
127
|
+
summary: List all runs for a specific experiment
|
|
128
|
+
operationId: listExperimentRuns
|
|
129
|
+
tags:
|
|
130
|
+
- private
|
|
131
|
+
parameters:
|
|
132
|
+
- in: path
|
|
133
|
+
name: experiment_id
|
|
134
|
+
required: true
|
|
135
|
+
description: The ID of the experiment to list runs for
|
|
136
|
+
schema:
|
|
137
|
+
type: string
|
|
138
|
+
responses:
|
|
139
|
+
200:
|
|
140
|
+
description: Experiment runs retrieved successfully
|
|
141
|
+
content:
|
|
142
|
+
application/json:
|
|
143
|
+
schema:
|
|
144
|
+
type: object
|
|
145
|
+
properties:
|
|
146
|
+
data:
|
|
147
|
+
type: array
|
|
148
|
+
items:
|
|
149
|
+
type: object
|
|
150
|
+
properties:
|
|
151
|
+
id:
|
|
152
|
+
type: string
|
|
153
|
+
description: The ID of the experiment run
|
|
154
|
+
experiment_id:
|
|
155
|
+
type: string
|
|
156
|
+
description: The ID of the experiment
|
|
157
|
+
dataset_example_id:
|
|
158
|
+
type: string
|
|
159
|
+
description: The ID of the dataset example
|
|
160
|
+
repetition_number:
|
|
161
|
+
type: integer
|
|
162
|
+
description: The repetition number of the experiment run
|
|
163
|
+
start_time:
|
|
164
|
+
type: string
|
|
165
|
+
format: date-time
|
|
166
|
+
description: The start time of the experiment run in ISO format
|
|
167
|
+
end_time:
|
|
168
|
+
type: string
|
|
169
|
+
format: date-time
|
|
170
|
+
description: The end time of the experiment run in ISO format
|
|
171
|
+
output:
|
|
172
|
+
description: The output of the experiment task
|
|
173
|
+
error:
|
|
174
|
+
type: string
|
|
175
|
+
description: Error message if the experiment run encountered an error
|
|
176
|
+
trace_id:
|
|
177
|
+
type: string
|
|
178
|
+
description: Optional trace ID for tracking
|
|
179
|
+
404:
|
|
180
|
+
description: Experiment not found
|
|
181
|
+
"""
|
|
182
|
+
experiment_gid = GlobalID.from_id(request.path_params["experiment_id"])
|
|
125
183
|
try:
|
|
126
|
-
|
|
184
|
+
experiment_id = from_global_id_with_expected_type(experiment_gid, "Experiment")
|
|
127
185
|
except ValueError:
|
|
128
|
-
|
|
129
|
-
|
|
186
|
+
return Response(
|
|
187
|
+
content=f"Experiment with ID {experiment_gid} does not exist",
|
|
130
188
|
status_code=HTTP_404_NOT_FOUND,
|
|
131
189
|
)
|
|
132
190
|
|
|
133
191
|
async with request.app.state.db() as session:
|
|
134
192
|
experiment_runs = await session.execute(
|
|
135
193
|
select(models.ExperimentRun)
|
|
136
|
-
.where(models.ExperimentRun.experiment_id ==
|
|
194
|
+
.where(models.ExperimentRun.experiment_id == experiment_id)
|
|
137
195
|
# order by dataset_example_id to be consistent with `list_dataset_examples`
|
|
138
196
|
.order_by(models.ExperimentRun.dataset_example_id.asc())
|
|
139
197
|
)
|
|
@@ -144,9 +202,9 @@ async def list_experiment_runs(
|
|
|
144
202
|
experiment_gid = GlobalID("Experiment", str(exp_run.experiment_id))
|
|
145
203
|
example_gid = GlobalID("DatasetExample", str(exp_run.dataset_example_id))
|
|
146
204
|
runs.append(
|
|
147
|
-
|
|
148
|
-
start_time=exp_run.start_time,
|
|
149
|
-
end_time=exp_run.end_time,
|
|
205
|
+
dict(
|
|
206
|
+
start_time=exp_run.start_time.isoformat(),
|
|
207
|
+
end_time=exp_run.end_time.isoformat(),
|
|
150
208
|
experiment_id=str(experiment_gid),
|
|
151
209
|
dataset_example_id=str(example_gid),
|
|
152
210
|
repetition_number=exp_run.repetition_number,
|
|
@@ -156,4 +214,4 @@ async def list_experiment_runs(
|
|
|
156
214
|
trace_id=exp_run.trace_id,
|
|
157
215
|
)
|
|
158
216
|
)
|
|
159
|
-
return
|
|
217
|
+
return JSONResponse(content={"data": runs}, status_code=200)
|