arize-phoenix 4.12.0__py3-none-any.whl → 4.12.1rc1__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.

Files changed (39) hide show
  1. {arize_phoenix-4.12.0.dist-info → arize_phoenix-4.12.1rc1.dist-info}/METADATA +4 -3
  2. {arize_phoenix-4.12.0.dist-info → arize_phoenix-4.12.1rc1.dist-info}/RECORD +36 -27
  3. phoenix/server/api/context.py +3 -7
  4. phoenix/server/api/openapi/main.py +18 -2
  5. phoenix/server/api/openapi/schema.py +12 -12
  6. phoenix/server/api/routers/v1/__init__.py +36 -83
  7. phoenix/server/api/routers/v1/dataset_examples.py +102 -123
  8. phoenix/server/api/routers/v1/datasets.py +390 -506
  9. phoenix/server/api/routers/v1/evaluations.py +73 -66
  10. phoenix/server/api/routers/v1/experiment_evaluations.py +68 -91
  11. phoenix/server/api/routers/v1/experiment_runs.py +98 -155
  12. phoenix/server/api/routers/v1/experiments.py +132 -181
  13. phoenix/server/api/routers/v1/pydantic_compat.py +78 -0
  14. phoenix/server/api/routers/v1/spans.py +144 -173
  15. phoenix/server/api/routers/v1/traces.py +115 -128
  16. phoenix/server/api/routers/v1/utils.py +95 -0
  17. phoenix/server/api/types/Project.py +33 -0
  18. phoenix/server/app.py +172 -176
  19. phoenix/server/main.py +3 -0
  20. phoenix/server/static/.vite/manifest.json +78 -0
  21. phoenix/server/static/assets/components-C8sm_r1F.js +1142 -0
  22. phoenix/server/static/assets/index-BEKPzgQs.js +100 -0
  23. phoenix/server/static/assets/pages-bN7juCjh.js +2885 -0
  24. phoenix/server/static/assets/vendor-CUDAPm8e.js +641 -0
  25. phoenix/server/static/assets/vendor-DxkFTwjz.css +1 -0
  26. phoenix/server/static/assets/vendor-arizeai-Do2HOmcL.js +662 -0
  27. phoenix/server/static/assets/vendor-codemirror-CrdxOlMs.js +12 -0
  28. phoenix/server/static/assets/vendor-recharts-PKRvByVe.js +59 -0
  29. phoenix/server/static/assets/vendor-three-DwGkEfCM.js +2998 -0
  30. phoenix/server/templates/index.html +83 -24
  31. phoenix/server/thread_server.py +2 -2
  32. phoenix/session/client.py +3 -2
  33. phoenix/version.py +1 -1
  34. phoenix/server/openapi/docs.py +0 -221
  35. phoenix/server/static/index.css +0 -6
  36. phoenix/server/static/index.js +0 -8548
  37. {arize_phoenix-4.12.0.dist-info → arize_phoenix-4.12.1rc1.dist-info}/WHEEL +0 -0
  38. {arize_phoenix-4.12.0.dist-info → arize_phoenix-4.12.1rc1.dist-info}/licenses/IP_NOTICE +0 -0
  39. {arize_phoenix-4.12.0.dist-info → arize_phoenix-4.12.1rc1.dist-info}/licenses/LICENSE +0 -0
@@ -1,178 +1,157 @@
1
+ from datetime import datetime
2
+ from typing import Any, Dict, List, Optional
3
+
4
+ from fastapi import APIRouter, HTTPException, Path, Query
1
5
  from sqlalchemy import and_, func, select
2
6
  from starlette.requests import Request
3
- from starlette.responses import JSONResponse, Response
4
7
  from starlette.status import HTTP_404_NOT_FOUND
5
8
  from strawberry.relay import GlobalID
6
9
 
7
- from phoenix.db.models import Dataset, DatasetExample, DatasetExampleRevision, DatasetVersion
8
-
9
-
10
- async def list_dataset_examples(request: Request) -> Response:
11
- """
12
- summary: Get dataset examples by dataset ID
13
- operationId: getDatasetExamples
14
- tags:
15
- - datasets
16
- parameters:
17
- - in: path
18
- name: id
19
- required: true
20
- schema:
21
- type: string
22
- description: Dataset ID
23
- - in: query
24
- name: version_id
25
- schema:
26
- type: string
27
- description: Dataset version ID. If omitted, returns the latest version.
28
- responses:
29
- 200:
30
- description: Success
31
- content:
32
- application/json:
33
- schema:
34
- type: object
35
- properties:
36
- data:
37
- type: object
38
- properties:
39
- dataset_id:
40
- type: string
41
- description: ID of the dataset
42
- version_id:
43
- type: string
44
- description: ID of the version
45
- examples:
46
- type: array
47
- items:
48
- type: object
49
- properties:
50
- id:
51
- type: string
52
- description: ID of the dataset example
53
- input:
54
- type: object
55
- description: Input data of the example
56
- output:
57
- type: object
58
- description: Output data of the example
59
- metadata:
60
- type: object
61
- description: Metadata of the example
62
- updated_at:
63
- type: string
64
- format: date-time
65
- description: ISO formatted timestamp of when the example was updated
66
- required:
67
- - id
68
- - input
69
- - output
70
- - metadata
71
- - updated_at
72
- required:
73
- - dataset_id
74
- - version_id
75
- - examples
76
- 403:
77
- description: Forbidden
78
- 404:
79
- description: Dataset does not exist.
80
- """
81
- dataset_id = GlobalID.from_id(request.path_params["id"])
82
- raw_version_id = request.query_params.get("version_id")
83
- version_id = GlobalID.from_id(raw_version_id) if raw_version_id else None
84
-
85
- if (dataset_type := dataset_id.type_name) != "Dataset":
86
- return Response(
87
- content=f"ID {dataset_id} refers to a {dataset_type}", status_code=HTTP_404_NOT_FOUND
10
+ from phoenix.db.models import (
11
+ Dataset as ORMDataset,
12
+ )
13
+ from phoenix.db.models import (
14
+ DatasetExample as ORMDatasetExample,
15
+ )
16
+ from phoenix.db.models import (
17
+ DatasetExampleRevision as ORMDatasetExampleRevision,
18
+ )
19
+ from phoenix.db.models import (
20
+ DatasetVersion as ORMDatasetVersion,
21
+ )
22
+
23
+ from .pydantic_compat import V1RoutesBaseModel
24
+ from .utils import ResponseBody, add_errors_to_responses
25
+
26
+ router = APIRouter(tags=["datasets"])
27
+
28
+
29
+ class DatasetExample(V1RoutesBaseModel):
30
+ id: str
31
+ input: Dict[str, Any]
32
+ output: Dict[str, Any]
33
+ metadata: Dict[str, Any]
34
+ updated_at: datetime
35
+
36
+
37
+ class ListDatasetExamplesData(V1RoutesBaseModel):
38
+ dataset_id: str
39
+ version_id: str
40
+ examples: List[DatasetExample]
41
+
42
+
43
+ class ListDatasetExamplesResponseBody(ResponseBody[ListDatasetExamplesData]):
44
+ pass
45
+
46
+
47
+ @router.get(
48
+ "/datasets/{id}/examples",
49
+ operation_id="getDatasetExamples",
50
+ summary="Get examples from a dataset",
51
+ responses=add_errors_to_responses([HTTP_404_NOT_FOUND]),
52
+ )
53
+ async def get_dataset_examples(
54
+ request: Request,
55
+ id: str = Path(description="The ID of the dataset"),
56
+ version_id: Optional[str] = Query(
57
+ default=None,
58
+ description=(
59
+ "The ID of the dataset version " "(if omitted, returns data from the latest version)"
60
+ ),
61
+ ),
62
+ ) -> ListDatasetExamplesResponseBody:
63
+ dataset_gid = GlobalID.from_id(id)
64
+ version_gid = GlobalID.from_id(version_id) if version_id else None
65
+
66
+ if (dataset_type := dataset_gid.type_name) != "Dataset":
67
+ raise HTTPException(
68
+ detail=f"ID {dataset_gid} refers to a {dataset_type}", status_code=HTTP_404_NOT_FOUND
88
69
  )
89
70
 
90
- if version_id and (version_type := version_id.type_name) != "DatasetVersion":
91
- return Response(
92
- content=f"ID {version_id} refers to a {version_type}", status_code=HTTP_404_NOT_FOUND
71
+ if version_gid and (version_type := version_gid.type_name) != "DatasetVersion":
72
+ raise HTTPException(
73
+ detail=f"ID {version_gid} refers to a {version_type}", status_code=HTTP_404_NOT_FOUND
93
74
  )
94
75
 
95
76
  async with request.app.state.db() as session:
96
77
  if (
97
78
  resolved_dataset_id := await session.scalar(
98
- select(Dataset.id).where(Dataset.id == int(dataset_id.node_id))
79
+ select(ORMDataset.id).where(ORMDataset.id == int(dataset_gid.node_id))
99
80
  )
100
81
  ) is None:
101
- return Response(
102
- content=f"No dataset with id {dataset_id} can be found.",
82
+ raise HTTPException(
83
+ detail=f"No dataset with id {dataset_gid} can be found.",
103
84
  status_code=HTTP_404_NOT_FOUND,
104
85
  )
105
86
 
106
87
  # Subquery to find the maximum created_at for each dataset_example_id
107
88
  # timestamp tiebreaks are resolved by the largest id
108
89
  partial_subquery = select(
109
- func.max(DatasetExampleRevision.id).label("max_id"),
110
- ).group_by(DatasetExampleRevision.dataset_example_id)
90
+ func.max(ORMDatasetExampleRevision.id).label("max_id"),
91
+ ).group_by(ORMDatasetExampleRevision.dataset_example_id)
111
92
 
112
- if version_id:
93
+ if version_gid:
113
94
  if (
114
95
  resolved_version_id := await session.scalar(
115
- select(DatasetVersion.id).where(
96
+ select(ORMDatasetVersion.id).where(
116
97
  and_(
117
- DatasetVersion.dataset_id == resolved_dataset_id,
118
- DatasetVersion.id == int(version_id.node_id),
98
+ ORMDatasetVersion.dataset_id == resolved_dataset_id,
99
+ ORMDatasetVersion.id == int(version_gid.node_id),
119
100
  )
120
101
  )
121
102
  )
122
103
  ) is None:
123
- return Response(
124
- content=f"No dataset version with id {version_id} can be found.",
104
+ raise HTTPException(
105
+ detail=f"No dataset version with id {version_id} can be found.",
125
106
  status_code=HTTP_404_NOT_FOUND,
126
107
  )
127
108
  # if a version_id is provided, filter the subquery to only include revisions from that
128
109
  partial_subquery = partial_subquery.filter(
129
- DatasetExampleRevision.dataset_version_id <= resolved_version_id
110
+ ORMDatasetExampleRevision.dataset_version_id <= resolved_version_id
130
111
  )
131
112
  else:
132
113
  if (
133
114
  resolved_version_id := await session.scalar(
134
- select(func.max(DatasetVersion.id)).where(
135
- DatasetVersion.dataset_id == resolved_dataset_id
115
+ select(func.max(ORMDatasetVersion.id)).where(
116
+ ORMDatasetVersion.dataset_id == resolved_dataset_id
136
117
  )
137
118
  )
138
119
  ) is None:
139
- return Response(
140
- content="Dataset has no versions.",
120
+ raise HTTPException(
121
+ detail="Dataset has no versions.",
141
122
  status_code=HTTP_404_NOT_FOUND,
142
123
  )
143
124
 
144
125
  subquery = partial_subquery.subquery()
145
126
  # Query for the most recent example revisions that are not deleted
146
127
  query = (
147
- select(DatasetExample, DatasetExampleRevision)
128
+ select(ORMDatasetExample, ORMDatasetExampleRevision)
148
129
  .join(
149
- DatasetExampleRevision,
150
- DatasetExample.id == DatasetExampleRevision.dataset_example_id,
130
+ ORMDatasetExampleRevision,
131
+ ORMDatasetExample.id == ORMDatasetExampleRevision.dataset_example_id,
151
132
  )
152
133
  .join(
153
134
  subquery,
154
- (subquery.c.max_id == DatasetExampleRevision.id),
135
+ (subquery.c.max_id == ORMDatasetExampleRevision.id),
155
136
  )
156
- .filter(DatasetExample.dataset_id == resolved_dataset_id)
157
- .filter(DatasetExampleRevision.revision_kind != "DELETE")
158
- .order_by(DatasetExample.id.asc())
137
+ .filter(ORMDatasetExample.dataset_id == resolved_dataset_id)
138
+ .filter(ORMDatasetExampleRevision.revision_kind != "DELETE")
139
+ .order_by(ORMDatasetExample.id.asc())
159
140
  )
160
141
  examples = [
161
- {
162
- "id": str(GlobalID("DatasetExample", str(example.id))),
163
- "input": revision.input,
164
- "output": revision.output,
165
- "metadata": revision.metadata_,
166
- "updated_at": revision.created_at.isoformat(),
167
- }
142
+ DatasetExample(
143
+ id=str(GlobalID("DatasetExample", str(example.id))),
144
+ input=revision.input,
145
+ output=revision.output,
146
+ metadata=revision.metadata_,
147
+ updated_at=revision.created_at,
148
+ )
168
149
  async for example, revision in await session.stream(query)
169
150
  ]
170
- return JSONResponse(
171
- {
172
- "data": {
173
- "dataset_id": str(GlobalID("Dataset", str(resolved_dataset_id))),
174
- "version_id": str(GlobalID("DatasetVersion", str(resolved_version_id))),
175
- "examples": examples,
176
- }
177
- }
151
+ return ListDatasetExamplesResponseBody(
152
+ data=ListDatasetExamplesData(
153
+ dataset_id=str(GlobalID("Dataset", str(resolved_dataset_id))),
154
+ version_id=str(GlobalID("DatasetVersion", str(resolved_version_id))),
155
+ examples=examples,
156
+ )
178
157
  )