arize-phoenix 4.4.4rc5__py3-none-any.whl → 4.5.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.

Files changed (118) hide show
  1. {arize_phoenix-4.4.4rc5.dist-info → arize_phoenix-4.5.0.dist-info}/METADATA +5 -5
  2. {arize_phoenix-4.4.4rc5.dist-info → arize_phoenix-4.5.0.dist-info}/RECORD +56 -117
  3. {arize_phoenix-4.4.4rc5.dist-info → arize_phoenix-4.5.0.dist-info}/WHEEL +1 -1
  4. phoenix/__init__.py +27 -0
  5. phoenix/config.py +7 -21
  6. phoenix/core/model.py +25 -25
  7. phoenix/core/model_schema.py +62 -64
  8. phoenix/core/model_schema_adapter.py +25 -27
  9. phoenix/db/bulk_inserter.py +14 -54
  10. phoenix/db/insertion/evaluation.py +6 -6
  11. phoenix/db/insertion/helpers.py +2 -13
  12. phoenix/db/migrations/versions/cf03bd6bae1d_init.py +28 -2
  13. phoenix/db/models.py +4 -236
  14. phoenix/inferences/fixtures.py +23 -23
  15. phoenix/inferences/inferences.py +7 -7
  16. phoenix/inferences/validation.py +1 -1
  17. phoenix/server/api/context.py +0 -18
  18. phoenix/server/api/dataloaders/__init__.py +0 -18
  19. phoenix/server/api/dataloaders/span_descendants.py +3 -2
  20. phoenix/server/api/routers/v1/__init__.py +2 -77
  21. phoenix/server/api/routers/v1/evaluations.py +2 -4
  22. phoenix/server/api/routers/v1/spans.py +1 -3
  23. phoenix/server/api/routers/v1/traces.py +4 -1
  24. phoenix/server/api/schema.py +303 -2
  25. phoenix/server/api/types/Cluster.py +19 -19
  26. phoenix/server/api/types/Dataset.py +63 -282
  27. phoenix/server/api/types/DatasetRole.py +23 -0
  28. phoenix/server/api/types/Dimension.py +29 -30
  29. phoenix/server/api/types/EmbeddingDimension.py +34 -40
  30. phoenix/server/api/types/Event.py +16 -16
  31. phoenix/server/api/{mutations/export_events_mutations.py → types/ExportEventsMutation.py} +14 -17
  32. phoenix/server/api/types/Model.py +42 -43
  33. phoenix/server/api/types/Project.py +12 -26
  34. phoenix/server/api/types/Span.py +2 -79
  35. phoenix/server/api/types/TimeSeries.py +6 -6
  36. phoenix/server/api/types/Trace.py +4 -15
  37. phoenix/server/api/types/UMAPPoints.py +1 -1
  38. phoenix/server/api/types/node.py +111 -5
  39. phoenix/server/api/types/pagination.py +52 -10
  40. phoenix/server/app.py +49 -101
  41. phoenix/server/main.py +27 -49
  42. phoenix/server/openapi/docs.py +0 -3
  43. phoenix/server/static/index.js +2595 -3523
  44. phoenix/server/templates/index.html +0 -1
  45. phoenix/services.py +15 -15
  46. phoenix/session/client.py +21 -438
  47. phoenix/session/session.py +37 -47
  48. phoenix/trace/exporter.py +9 -14
  49. phoenix/trace/fixtures.py +7 -133
  50. phoenix/trace/schemas.py +2 -1
  51. phoenix/trace/span_evaluations.py +3 -3
  52. phoenix/trace/trace_dataset.py +6 -6
  53. phoenix/version.py +1 -1
  54. phoenix/datasets/__init__.py +0 -0
  55. phoenix/datasets/evaluators/__init__.py +0 -18
  56. phoenix/datasets/evaluators/code_evaluators.py +0 -99
  57. phoenix/datasets/evaluators/llm_evaluators.py +0 -244
  58. phoenix/datasets/evaluators/utils.py +0 -292
  59. phoenix/datasets/experiments.py +0 -550
  60. phoenix/datasets/tracing.py +0 -85
  61. phoenix/datasets/types.py +0 -178
  62. phoenix/db/insertion/dataset.py +0 -237
  63. phoenix/db/migrations/types.py +0 -29
  64. phoenix/db/migrations/versions/10460e46d750_datasets.py +0 -291
  65. phoenix/server/api/dataloaders/dataset_example_revisions.py +0 -100
  66. phoenix/server/api/dataloaders/dataset_example_spans.py +0 -43
  67. phoenix/server/api/dataloaders/experiment_annotation_summaries.py +0 -85
  68. phoenix/server/api/dataloaders/experiment_error_rates.py +0 -43
  69. phoenix/server/api/dataloaders/experiment_run_counts.py +0 -42
  70. phoenix/server/api/dataloaders/experiment_sequence_number.py +0 -49
  71. phoenix/server/api/dataloaders/project_by_name.py +0 -31
  72. phoenix/server/api/dataloaders/span_projects.py +0 -33
  73. phoenix/server/api/dataloaders/trace_row_ids.py +0 -39
  74. phoenix/server/api/helpers/dataset_helpers.py +0 -179
  75. phoenix/server/api/input_types/AddExamplesToDatasetInput.py +0 -16
  76. phoenix/server/api/input_types/AddSpansToDatasetInput.py +0 -14
  77. phoenix/server/api/input_types/ClearProjectInput.py +0 -15
  78. phoenix/server/api/input_types/CreateDatasetInput.py +0 -12
  79. phoenix/server/api/input_types/DatasetExampleInput.py +0 -14
  80. phoenix/server/api/input_types/DatasetSort.py +0 -17
  81. phoenix/server/api/input_types/DatasetVersionSort.py +0 -16
  82. phoenix/server/api/input_types/DeleteDatasetExamplesInput.py +0 -13
  83. phoenix/server/api/input_types/DeleteDatasetInput.py +0 -7
  84. phoenix/server/api/input_types/DeleteExperimentsInput.py +0 -9
  85. phoenix/server/api/input_types/PatchDatasetExamplesInput.py +0 -35
  86. phoenix/server/api/input_types/PatchDatasetInput.py +0 -14
  87. phoenix/server/api/mutations/__init__.py +0 -13
  88. phoenix/server/api/mutations/auth.py +0 -11
  89. phoenix/server/api/mutations/dataset_mutations.py +0 -520
  90. phoenix/server/api/mutations/experiment_mutations.py +0 -65
  91. phoenix/server/api/mutations/project_mutations.py +0 -47
  92. phoenix/server/api/openapi/__init__.py +0 -0
  93. phoenix/server/api/openapi/main.py +0 -6
  94. phoenix/server/api/openapi/schema.py +0 -16
  95. phoenix/server/api/queries.py +0 -503
  96. phoenix/server/api/routers/v1/dataset_examples.py +0 -178
  97. phoenix/server/api/routers/v1/datasets.py +0 -965
  98. phoenix/server/api/routers/v1/experiment_evaluations.py +0 -66
  99. phoenix/server/api/routers/v1/experiment_runs.py +0 -108
  100. phoenix/server/api/routers/v1/experiments.py +0 -174
  101. phoenix/server/api/types/AnnotatorKind.py +0 -10
  102. phoenix/server/api/types/CreateDatasetPayload.py +0 -8
  103. phoenix/server/api/types/DatasetExample.py +0 -85
  104. phoenix/server/api/types/DatasetExampleRevision.py +0 -34
  105. phoenix/server/api/types/DatasetVersion.py +0 -14
  106. phoenix/server/api/types/ExampleRevisionInterface.py +0 -14
  107. phoenix/server/api/types/Experiment.py +0 -140
  108. phoenix/server/api/types/ExperimentAnnotationSummary.py +0 -13
  109. phoenix/server/api/types/ExperimentComparison.py +0 -19
  110. phoenix/server/api/types/ExperimentRun.py +0 -91
  111. phoenix/server/api/types/ExperimentRunAnnotation.py +0 -57
  112. phoenix/server/api/types/Inferences.py +0 -80
  113. phoenix/server/api/types/InferencesRole.py +0 -23
  114. phoenix/utilities/json.py +0 -61
  115. phoenix/utilities/re.py +0 -50
  116. {arize_phoenix-4.4.4rc5.dist-info → arize_phoenix-4.5.0.dist-info}/licenses/IP_NOTICE +0 -0
  117. {arize_phoenix-4.4.4rc5.dist-info → arize_phoenix-4.5.0.dist-info}/licenses/LICENSE +0 -0
  118. /phoenix/server/api/{helpers/__init__.py → helpers.py} +0 -0
phoenix/datasets/types.py DELETED
@@ -1,178 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from dataclasses import dataclass, field
4
- from datetime import datetime
5
- from enum import Enum
6
- from typing import (
7
- Any,
8
- Awaitable,
9
- Callable,
10
- Dict,
11
- List,
12
- Mapping,
13
- Optional,
14
- Sequence,
15
- Union,
16
- )
17
-
18
- from typing_extensions import TypeAlias
19
-
20
-
21
- class AnnotatorKind(Enum):
22
- CODE = "CODE"
23
- LLM = "LLM"
24
-
25
-
26
- JSONSerializable: TypeAlias = Optional[Union[Dict[str, Any], List[Any], str, int, float, bool]]
27
-
28
- ExperimentId: TypeAlias = str
29
- DatasetId: TypeAlias = str
30
- DatasetVersionId: TypeAlias = str
31
- ExampleId: TypeAlias = str
32
- RepetitionNumber: TypeAlias = int
33
- ExperimentRunId: TypeAlias = str
34
- TraceId: TypeAlias = str
35
-
36
- TaskOutput: TypeAlias = JSONSerializable
37
-
38
-
39
- @dataclass(frozen=True)
40
- class Example:
41
- id: ExampleId
42
- updated_at: datetime
43
- input: Mapping[str, JSONSerializable]
44
- output: Mapping[str, JSONSerializable]
45
- metadata: Mapping[str, JSONSerializable] = field(default_factory=dict)
46
-
47
- @classmethod
48
- def from_dict(cls, obj: Mapping[str, Any]) -> Example:
49
- return cls(
50
- input=obj["input"],
51
- output=obj["output"],
52
- metadata=obj.get("metadata") or {},
53
- id=obj["id"],
54
- updated_at=obj["updated_at"],
55
- )
56
-
57
-
58
- @dataclass(frozen=True)
59
- class Dataset:
60
- id: DatasetId
61
- version_id: DatasetVersionId
62
- examples: Sequence[Example]
63
-
64
-
65
- @dataclass(frozen=True)
66
- class TestCase:
67
- example: Example
68
- repetition_number: RepetitionNumber
69
-
70
-
71
- @dataclass(frozen=True)
72
- class Experiment:
73
- id: ExperimentId
74
- dataset_id: DatasetId
75
- dataset_version_id: DatasetVersionId
76
- project_name: Optional[str] = None
77
-
78
-
79
- @dataclass(frozen=True)
80
- class ExperimentResult:
81
- result: TaskOutput
82
-
83
- @classmethod
84
- def from_dict(cls, obj: Optional[Mapping[str, Any]]) -> Optional[ExperimentResult]:
85
- if not obj:
86
- return None
87
- return cls(result=obj["result"])
88
-
89
-
90
- @dataclass(frozen=True)
91
- class ExperimentRun:
92
- start_time: datetime
93
- end_time: datetime
94
- experiment_id: ExperimentId
95
- dataset_example_id: ExampleId
96
- repetition_number: RepetitionNumber
97
- output: Optional[ExperimentResult] = None
98
- error: Optional[str] = None
99
- id: Optional[ExperimentRunId] = None
100
- trace_id: Optional[TraceId] = None
101
-
102
- @classmethod
103
- def from_dict(cls, obj: Mapping[str, Any]) -> ExperimentRun:
104
- return cls(
105
- start_time=obj["start_time"],
106
- end_time=obj["end_time"],
107
- experiment_id=obj["experiment_id"],
108
- dataset_example_id=obj["dataset_example_id"],
109
- repetition_number=obj.get("repetition_number") or 1,
110
- output=ExperimentResult.from_dict(obj["output"]),
111
- error=obj.get("error"),
112
- id=obj.get("id"),
113
- trace_id=obj.get("trace_id"),
114
- )
115
-
116
- def __post_init__(self) -> None:
117
- if bool(self.output) == bool(self.error):
118
- ValueError("Must specify either result or error")
119
-
120
-
121
- @dataclass(frozen=True)
122
- class EvaluationResult:
123
- score: Optional[float] = None
124
- label: Optional[str] = None
125
- explanation: Optional[str] = None
126
- metadata: Mapping[str, JSONSerializable] = field(default_factory=dict)
127
-
128
- @classmethod
129
- def from_dict(cls, obj: Optional[Mapping[str, Any]]) -> Optional[EvaluationResult]:
130
- if not obj:
131
- return None
132
- return cls(
133
- score=obj.get("score"),
134
- label=obj.get("label"),
135
- explanation=obj.get("explanation"),
136
- metadata=obj.get("metadata") or {},
137
- )
138
-
139
- def __post_init__(self) -> None:
140
- if self.score is None and not self.label and not self.explanation:
141
- ValueError("Must specify one of score, label, or explanation")
142
-
143
-
144
- @dataclass(frozen=True)
145
- class ExperimentEvaluationRun:
146
- experiment_run_id: ExperimentRunId
147
- start_time: datetime
148
- end_time: datetime
149
- name: str
150
- annotator_kind: str
151
- error: Optional[str] = None
152
- result: Optional[EvaluationResult] = None
153
- id: Optional[str] = None
154
- trace_id: Optional[TraceId] = None
155
-
156
- @classmethod
157
- def from_dict(cls, obj: Mapping[str, Any]) -> ExperimentEvaluationRun:
158
- return cls(
159
- experiment_run_id=obj["experiment_run_id"],
160
- start_time=obj["start_time"],
161
- end_time=obj["end_time"],
162
- name=obj["name"],
163
- annotator_kind=obj["annotator_kind"],
164
- error=obj.get("error"),
165
- result=EvaluationResult.from_dict(obj.get("result")),
166
- id=obj.get("id"),
167
- trace_id=obj.get("trace_id"),
168
- )
169
-
170
- def __post_init__(self) -> None:
171
- if bool(self.result) == bool(self.error):
172
- ValueError("Must specify either result or error")
173
-
174
-
175
- ExperimentTask: TypeAlias = Union[
176
- Callable[[Example], TaskOutput],
177
- Callable[[Example], Awaitable[TaskOutput]],
178
- ]
@@ -1,237 +0,0 @@
1
- import logging
2
- from dataclasses import dataclass, field
3
- from datetime import datetime, timezone
4
- from enum import Enum
5
- from itertools import chain
6
- from typing import (
7
- Any,
8
- Awaitable,
9
- Dict,
10
- FrozenSet,
11
- Iterable,
12
- Iterator,
13
- Mapping,
14
- Optional,
15
- Union,
16
- cast,
17
- )
18
-
19
- from sqlalchemy import insert, select
20
- from sqlalchemy.ext.asyncio import AsyncSession
21
- from typing_extensions import TypeAlias
22
-
23
- from phoenix.db import models
24
- from phoenix.db.insertion.helpers import DataManipulationEvent
25
-
26
- logger = logging.getLogger(__name__)
27
-
28
- DatasetId: TypeAlias = int
29
- DatasetVersionId: TypeAlias = int
30
- DatasetExampleId: TypeAlias = int
31
- DatasetExampleRevisionId: TypeAlias = int
32
- SpanRowId: TypeAlias = int
33
-
34
-
35
- @dataclass(frozen=True)
36
- class ExampleContent:
37
- input: Dict[str, Any] = field(default_factory=dict)
38
- output: Dict[str, Any] = field(default_factory=dict)
39
- metadata: Dict[str, Any] = field(default_factory=dict)
40
-
41
-
42
- Examples: TypeAlias = Iterable[ExampleContent]
43
-
44
-
45
- @dataclass(frozen=True)
46
- class DatasetExampleAdditionEvent(DataManipulationEvent):
47
- dataset_id: DatasetId
48
-
49
-
50
- async def insert_dataset(
51
- session: AsyncSession,
52
- name: str,
53
- description: Optional[str] = None,
54
- metadata: Optional[Mapping[str, Any]] = None,
55
- created_at: Optional[datetime] = None,
56
- ) -> DatasetId:
57
- id_ = await session.scalar(
58
- insert(models.Dataset)
59
- .values(
60
- name=name,
61
- description=description,
62
- metadata_=metadata,
63
- created_at=created_at,
64
- )
65
- .returning(models.Dataset.id)
66
- )
67
- return cast(DatasetId, id_)
68
-
69
-
70
- async def insert_dataset_version(
71
- session: AsyncSession,
72
- dataset_id: DatasetId,
73
- description: Optional[str] = None,
74
- metadata: Optional[Mapping[str, Any]] = None,
75
- created_at: Optional[datetime] = None,
76
- ) -> DatasetVersionId:
77
- id_ = await session.scalar(
78
- insert(models.DatasetVersion)
79
- .values(
80
- dataset_id=dataset_id,
81
- description=description,
82
- metadata_=metadata,
83
- created_at=created_at,
84
- )
85
- .returning(models.DatasetVersion.id)
86
- )
87
- return cast(DatasetVersionId, id_)
88
-
89
-
90
- async def insert_dataset_example(
91
- session: AsyncSession,
92
- dataset_id: DatasetId,
93
- span_rowid: Optional[SpanRowId] = None,
94
- created_at: Optional[datetime] = None,
95
- ) -> DatasetExampleId:
96
- id_ = await session.scalar(
97
- insert(models.DatasetExample)
98
- .values(
99
- dataset_id=dataset_id,
100
- span_rowid=span_rowid,
101
- created_at=created_at,
102
- )
103
- .returning(models.DatasetExample.id)
104
- )
105
- return cast(DatasetExampleId, id_)
106
-
107
-
108
- class RevisionKind(Enum):
109
- CREATE = "CREATE"
110
- PATCH = "PATCH"
111
- DELETE = "DELETE"
112
-
113
- @classmethod
114
- def _missing_(cls, v: Any) -> "RevisionKind":
115
- if isinstance(v, str) and v and v.isascii() and not v.isupper():
116
- return cls(v.upper())
117
- raise ValueError(f"Invalid revision kind: {v}")
118
-
119
-
120
- async def insert_dataset_example_revision(
121
- session: AsyncSession,
122
- dataset_version_id: DatasetVersionId,
123
- dataset_example_id: DatasetExampleId,
124
- input: Mapping[str, Any],
125
- output: Mapping[str, Any],
126
- metadata: Optional[Mapping[str, Any]] = None,
127
- revision_kind: RevisionKind = RevisionKind.CREATE,
128
- created_at: Optional[datetime] = None,
129
- ) -> DatasetExampleRevisionId:
130
- id_ = await session.scalar(
131
- insert(models.DatasetExampleRevision)
132
- .values(
133
- dataset_version_id=dataset_version_id,
134
- dataset_example_id=dataset_example_id,
135
- input=input,
136
- output=output,
137
- metadata_=metadata,
138
- revision_kind=revision_kind.value,
139
- created_at=created_at,
140
- )
141
- .returning(models.DatasetExampleRevision.id)
142
- )
143
- return cast(DatasetExampleRevisionId, id_)
144
-
145
-
146
- class DatasetAction(Enum):
147
- CREATE = "create"
148
- APPEND = "append"
149
-
150
- @classmethod
151
- def _missing_(cls, v: Any) -> "DatasetAction":
152
- if isinstance(v, str) and v and v.isascii() and not v.islower():
153
- return cls(v.lower())
154
- raise ValueError(f"Invalid dateset action: {v}")
155
-
156
-
157
- async def add_dataset_examples(
158
- session: AsyncSession,
159
- name: str,
160
- examples: Union[Examples, Awaitable[Examples]],
161
- description: Optional[str] = None,
162
- metadata: Optional[Mapping[str, Any]] = None,
163
- action: DatasetAction = DatasetAction.CREATE,
164
- ) -> Optional[DatasetExampleAdditionEvent]:
165
- created_at = datetime.now(timezone.utc)
166
- dataset_id: Optional[DatasetId] = None
167
- if action is DatasetAction.APPEND and name:
168
- dataset_id = await session.scalar(
169
- select(models.Dataset.id).where(models.Dataset.name == name)
170
- )
171
- if action is DatasetAction.CREATE or dataset_id is None:
172
- try:
173
- dataset_id = await insert_dataset(
174
- session=session,
175
- name=name,
176
- description=description,
177
- metadata=metadata,
178
- created_at=created_at,
179
- )
180
- except Exception:
181
- logger.exception(f"Failed to insert dataset: {name=}")
182
- raise
183
- try:
184
- dataset_version_id = await insert_dataset_version(
185
- session=session,
186
- dataset_id=dataset_id,
187
- created_at=created_at,
188
- )
189
- except Exception:
190
- logger.exception(f"Failed to insert dataset version for {dataset_id=}")
191
- raise
192
- for example in (await examples) if isinstance(examples, Awaitable) else examples:
193
- try:
194
- dataset_example_id = await insert_dataset_example(
195
- session=session,
196
- dataset_id=dataset_id,
197
- created_at=created_at,
198
- )
199
- except Exception:
200
- logger.exception(f"Failed to insert dataset example for {dataset_id=}")
201
- raise
202
- try:
203
- await insert_dataset_example_revision(
204
- session=session,
205
- dataset_version_id=dataset_version_id,
206
- dataset_example_id=dataset_example_id,
207
- input=example.input,
208
- output=example.output,
209
- metadata=example.metadata,
210
- created_at=created_at,
211
- )
212
- except Exception:
213
- logger.exception(
214
- f"Failed to insert dataset example revision for {dataset_version_id=}, "
215
- f"{dataset_example_id=}"
216
- )
217
- raise
218
- return DatasetExampleAdditionEvent(dataset_id=dataset_id)
219
-
220
-
221
- @dataclass(frozen=True)
222
- class DatasetKeys:
223
- input: FrozenSet[str]
224
- output: FrozenSet[str]
225
- metadata: FrozenSet[str]
226
-
227
- def __iter__(self) -> Iterator[str]:
228
- yield from sorted(set(chain(self.input, self.output, self.metadata)))
229
-
230
- def check_differences(self, column_headers_set: FrozenSet[str]) -> None:
231
- for category, keys in (
232
- ("input", self.input),
233
- ("output", self.output),
234
- ("metadata", self.metadata),
235
- ):
236
- if diff := keys.difference(column_headers_set):
237
- raise ValueError(f"{category} keys not found in table column headers: {diff}")
@@ -1,29 +0,0 @@
1
- from typing import Any
2
-
3
- from sqlalchemy import JSON
4
- from sqlalchemy.dialects import postgresql
5
- from sqlalchemy.ext.compiler import compiles
6
-
7
-
8
- class JSONB(JSON):
9
- # See https://docs.sqlalchemy.org/en/20/core/custom_types.html
10
- __visit_name__ = "JSONB"
11
-
12
-
13
- @compiles(JSONB, "sqlite") # type: ignore
14
- def _(*args: Any, **kwargs: Any) -> str:
15
- # See https://docs.sqlalchemy.org/en/20/core/custom_types.html
16
- return "JSONB"
17
-
18
-
19
- JSON_ = (
20
- JSON()
21
- .with_variant(
22
- postgresql.JSONB(), # type: ignore
23
- "postgresql",
24
- )
25
- .with_variant(
26
- JSONB(),
27
- "sqlite",
28
- )
29
- )