arize-phoenix 5.5.2__py3-none-any.whl → 5.6.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-5.5.2.dist-info → arize_phoenix-5.6.0.dist-info}/METADATA +3 -6
- {arize_phoenix-5.5.2.dist-info → arize_phoenix-5.6.0.dist-info}/RECORD +171 -171
- phoenix/config.py +8 -8
- phoenix/core/model.py +3 -3
- phoenix/core/model_schema.py +41 -50
- phoenix/core/model_schema_adapter.py +17 -16
- phoenix/datetime_utils.py +2 -2
- phoenix/db/bulk_inserter.py +10 -20
- phoenix/db/engines.py +2 -1
- phoenix/db/enums.py +2 -2
- phoenix/db/helpers.py +8 -7
- phoenix/db/insertion/dataset.py +9 -19
- phoenix/db/insertion/document_annotation.py +14 -13
- phoenix/db/insertion/helpers.py +6 -16
- phoenix/db/insertion/span_annotation.py +14 -13
- phoenix/db/insertion/trace_annotation.py +14 -13
- phoenix/db/insertion/types.py +19 -30
- phoenix/db/migrations/versions/3be8647b87d8_add_token_columns_to_spans_table.py +8 -8
- phoenix/db/models.py +28 -28
- phoenix/experiments/evaluators/base.py +2 -1
- phoenix/experiments/evaluators/code_evaluators.py +4 -5
- phoenix/experiments/evaluators/llm_evaluators.py +157 -4
- phoenix/experiments/evaluators/utils.py +3 -2
- phoenix/experiments/functions.py +10 -21
- phoenix/experiments/tracing.py +2 -1
- phoenix/experiments/types.py +20 -29
- phoenix/experiments/utils.py +2 -1
- phoenix/inferences/errors.py +6 -5
- phoenix/inferences/fixtures.py +6 -5
- phoenix/inferences/inferences.py +37 -37
- phoenix/inferences/schema.py +11 -10
- phoenix/inferences/validation.py +13 -14
- phoenix/logging/_formatter.py +3 -3
- phoenix/metrics/__init__.py +5 -4
- phoenix/metrics/binning.py +2 -1
- phoenix/metrics/metrics.py +2 -1
- phoenix/metrics/mixins.py +7 -6
- phoenix/metrics/retrieval_metrics.py +2 -1
- phoenix/metrics/timeseries.py +5 -4
- phoenix/metrics/wrappers.py +2 -2
- phoenix/pointcloud/clustering.py +3 -4
- phoenix/pointcloud/pointcloud.py +7 -5
- phoenix/pointcloud/umap_parameters.py +2 -1
- phoenix/server/api/dataloaders/annotation_summaries.py +12 -19
- phoenix/server/api/dataloaders/average_experiment_run_latency.py +2 -2
- phoenix/server/api/dataloaders/cache/two_tier_cache.py +3 -2
- phoenix/server/api/dataloaders/dataset_example_revisions.py +3 -8
- phoenix/server/api/dataloaders/dataset_example_spans.py +2 -5
- phoenix/server/api/dataloaders/document_evaluation_summaries.py +12 -18
- phoenix/server/api/dataloaders/document_evaluations.py +3 -7
- phoenix/server/api/dataloaders/document_retrieval_metrics.py +6 -13
- phoenix/server/api/dataloaders/experiment_annotation_summaries.py +4 -8
- phoenix/server/api/dataloaders/experiment_error_rates.py +2 -5
- phoenix/server/api/dataloaders/experiment_run_annotations.py +3 -7
- phoenix/server/api/dataloaders/experiment_run_counts.py +1 -5
- phoenix/server/api/dataloaders/experiment_sequence_number.py +2 -5
- phoenix/server/api/dataloaders/latency_ms_quantile.py +21 -30
- phoenix/server/api/dataloaders/min_start_or_max_end_times.py +7 -13
- phoenix/server/api/dataloaders/project_by_name.py +3 -3
- phoenix/server/api/dataloaders/record_counts.py +11 -18
- phoenix/server/api/dataloaders/span_annotations.py +3 -7
- phoenix/server/api/dataloaders/span_dataset_examples.py +3 -8
- phoenix/server/api/dataloaders/span_descendants.py +3 -7
- phoenix/server/api/dataloaders/span_projects.py +2 -2
- phoenix/server/api/dataloaders/token_counts.py +12 -19
- phoenix/server/api/dataloaders/trace_row_ids.py +3 -7
- phoenix/server/api/dataloaders/user_roles.py +3 -3
- phoenix/server/api/dataloaders/users.py +3 -3
- phoenix/server/api/helpers/__init__.py +4 -3
- phoenix/server/api/helpers/dataset_helpers.py +10 -9
- phoenix/server/api/input_types/AddExamplesToDatasetInput.py +2 -2
- phoenix/server/api/input_types/AddSpansToDatasetInput.py +2 -2
- phoenix/server/api/input_types/ChatCompletionMessageInput.py +13 -1
- phoenix/server/api/input_types/ClusterInput.py +2 -2
- phoenix/server/api/input_types/DeleteAnnotationsInput.py +1 -3
- phoenix/server/api/input_types/DeleteDatasetExamplesInput.py +2 -2
- phoenix/server/api/input_types/DeleteExperimentsInput.py +1 -3
- phoenix/server/api/input_types/DimensionFilter.py +4 -4
- phoenix/server/api/input_types/Granularity.py +1 -1
- phoenix/server/api/input_types/InvocationParameters.py +2 -2
- phoenix/server/api/input_types/PatchDatasetExamplesInput.py +2 -2
- phoenix/server/api/mutations/dataset_mutations.py +4 -4
- phoenix/server/api/mutations/experiment_mutations.py +1 -2
- phoenix/server/api/mutations/export_events_mutations.py +7 -7
- phoenix/server/api/mutations/span_annotations_mutations.py +4 -4
- phoenix/server/api/mutations/trace_annotations_mutations.py +4 -4
- phoenix/server/api/mutations/user_mutations.py +4 -4
- phoenix/server/api/openapi/schema.py +2 -2
- phoenix/server/api/queries.py +20 -20
- phoenix/server/api/routers/oauth2.py +4 -4
- phoenix/server/api/routers/v1/datasets.py +22 -36
- phoenix/server/api/routers/v1/evaluations.py +6 -5
- phoenix/server/api/routers/v1/experiment_evaluations.py +2 -2
- phoenix/server/api/routers/v1/experiment_runs.py +2 -2
- phoenix/server/api/routers/v1/experiments.py +4 -4
- phoenix/server/api/routers/v1/spans.py +13 -12
- phoenix/server/api/routers/v1/traces.py +5 -5
- phoenix/server/api/routers/v1/utils.py +5 -5
- phoenix/server/api/subscriptions.py +284 -162
- phoenix/server/api/types/AnnotationSummary.py +3 -3
- phoenix/server/api/types/Cluster.py +8 -7
- phoenix/server/api/types/Dataset.py +5 -4
- phoenix/server/api/types/Dimension.py +3 -3
- phoenix/server/api/types/DocumentEvaluationSummary.py +8 -7
- phoenix/server/api/types/EmbeddingDimension.py +6 -5
- phoenix/server/api/types/EvaluationSummary.py +3 -3
- phoenix/server/api/types/Event.py +7 -7
- phoenix/server/api/types/Experiment.py +3 -3
- phoenix/server/api/types/ExperimentComparison.py +2 -4
- phoenix/server/api/types/Inferences.py +9 -8
- phoenix/server/api/types/InferencesRole.py +2 -2
- phoenix/server/api/types/Model.py +2 -2
- phoenix/server/api/types/Project.py +11 -18
- phoenix/server/api/types/Segments.py +3 -3
- phoenix/server/api/types/Span.py +8 -7
- phoenix/server/api/types/TimeSeries.py +8 -7
- phoenix/server/api/types/Trace.py +2 -2
- phoenix/server/api/types/UMAPPoints.py +6 -6
- phoenix/server/api/types/User.py +3 -3
- phoenix/server/api/types/node.py +1 -3
- phoenix/server/api/types/pagination.py +4 -4
- phoenix/server/api/utils.py +2 -4
- phoenix/server/app.py +16 -25
- phoenix/server/bearer_auth.py +4 -10
- phoenix/server/dml_event.py +3 -3
- phoenix/server/dml_event_handler.py +10 -24
- phoenix/server/grpc_server.py +3 -2
- phoenix/server/jwt_store.py +22 -21
- phoenix/server/main.py +3 -3
- phoenix/server/oauth2.py +3 -2
- phoenix/server/rate_limiters.py +5 -8
- phoenix/server/static/.vite/manifest.json +31 -31
- phoenix/server/static/assets/components-C70HJiXz.js +1612 -0
- phoenix/server/static/assets/{index-DCzakdJq.js → index-DLe1Oo3l.js} +2 -2
- phoenix/server/static/assets/{pages-CAL1FDMt.js → pages-C8-Sl7JI.js} +269 -434
- phoenix/server/static/assets/{vendor-6IcPAw_j.js → vendor-CtqfhlbC.js} +6 -6
- phoenix/server/static/assets/{vendor-arizeai-DRZuoyuF.js → vendor-arizeai-C_3SBz56.js} +2 -2
- phoenix/server/static/assets/{vendor-codemirror-DVE2_WBr.js → vendor-codemirror-wfdk9cjp.js} +1 -1
- phoenix/server/static/assets/{vendor-recharts-DwrexFA4.js → vendor-recharts-BiVnSv90.js} +1 -1
- phoenix/server/thread_server.py +1 -1
- phoenix/server/types.py +17 -29
- phoenix/services.py +4 -3
- phoenix/session/client.py +12 -24
- phoenix/session/data_extractor.py +3 -3
- phoenix/session/evaluation.py +1 -2
- phoenix/session/session.py +11 -20
- phoenix/trace/attributes.py +16 -28
- phoenix/trace/dsl/filter.py +17 -21
- phoenix/trace/dsl/helpers.py +3 -3
- phoenix/trace/dsl/query.py +13 -22
- phoenix/trace/fixtures.py +11 -17
- phoenix/trace/otel.py +5 -15
- phoenix/trace/projects.py +3 -2
- phoenix/trace/schemas.py +2 -2
- phoenix/trace/span_evaluations.py +9 -8
- phoenix/trace/span_json_decoder.py +3 -3
- phoenix/trace/span_json_encoder.py +2 -2
- phoenix/trace/trace_dataset.py +6 -5
- phoenix/trace/utils.py +6 -6
- phoenix/utilities/deprecation.py +3 -2
- phoenix/utilities/error_handling.py +3 -2
- phoenix/utilities/json.py +2 -1
- phoenix/utilities/logging.py +2 -2
- phoenix/utilities/project.py +1 -1
- phoenix/utilities/re.py +3 -4
- phoenix/utilities/template_formatters.py +5 -4
- phoenix/version.py +1 -1
- phoenix/server/static/assets/components-hX0LgYz3.js +0 -1428
- {arize_phoenix-5.5.2.dist-info → arize_phoenix-5.6.0.dist-info}/WHEEL +0 -0
- {arize_phoenix-5.5.2.dist-info → arize_phoenix-5.6.0.dist-info}/entry_points.txt +0 -0
- {arize_phoenix-5.5.2.dist-info → arize_phoenix-5.6.0.dist-info}/licenses/IP_NOTICE +0 -0
- {arize_phoenix-5.5.2.dist-info → arize_phoenix-5.6.0.dist-info}/licenses/LICENSE +0 -0
phoenix/db/insertion/dataset.py
CHANGED
|
@@ -1,20 +1,10 @@
|
|
|
1
1
|
import logging
|
|
2
|
+
from collections.abc import Awaitable, Iterable, Iterator, Mapping
|
|
2
3
|
from dataclasses import dataclass, field
|
|
3
4
|
from datetime import datetime, timezone
|
|
4
5
|
from enum import Enum
|
|
5
6
|
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
|
-
)
|
|
7
|
+
from typing import Any, Optional, Union, cast
|
|
18
8
|
|
|
19
9
|
from sqlalchemy import insert, select
|
|
20
10
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
@@ -34,9 +24,9 @@ SpanRowId: TypeAlias = int
|
|
|
34
24
|
|
|
35
25
|
@dataclass(frozen=True)
|
|
36
26
|
class ExampleContent:
|
|
37
|
-
input:
|
|
38
|
-
output:
|
|
39
|
-
metadata:
|
|
27
|
+
input: dict[str, Any] = field(default_factory=dict)
|
|
28
|
+
output: dict[str, Any] = field(default_factory=dict)
|
|
29
|
+
metadata: dict[str, Any] = field(default_factory=dict)
|
|
40
30
|
|
|
41
31
|
|
|
42
32
|
Examples: TypeAlias = Iterable[ExampleContent]
|
|
@@ -220,14 +210,14 @@ async def add_dataset_examples(
|
|
|
220
210
|
|
|
221
211
|
@dataclass(frozen=True)
|
|
222
212
|
class DatasetKeys:
|
|
223
|
-
input:
|
|
224
|
-
output:
|
|
225
|
-
metadata:
|
|
213
|
+
input: frozenset[str]
|
|
214
|
+
output: frozenset[str]
|
|
215
|
+
metadata: frozenset[str]
|
|
226
216
|
|
|
227
217
|
def __iter__(self) -> Iterator[str]:
|
|
228
218
|
yield from sorted(set(chain(self.input, self.output, self.metadata)))
|
|
229
219
|
|
|
230
|
-
def check_differences(self, column_headers_set:
|
|
220
|
+
def check_differences(self, column_headers_set: frozenset[str]) -> None:
|
|
231
221
|
for category, keys in (
|
|
232
222
|
("input", self.input),
|
|
233
223
|
("output", self.output),
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
from collections.abc import Mapping
|
|
1
2
|
from datetime import datetime
|
|
2
|
-
from typing import Any,
|
|
3
|
+
from typing import Any, NamedTuple, Optional
|
|
3
4
|
|
|
4
5
|
from sqlalchemy import Row, Select, and_, select, tuple_
|
|
5
6
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
@@ -24,9 +25,9 @@ _DocumentPosition: TypeAlias = int
|
|
|
24
25
|
_AnnoRowId: TypeAlias = int
|
|
25
26
|
_NumDocs: TypeAlias = int
|
|
26
27
|
|
|
27
|
-
_Key: TypeAlias =
|
|
28
|
-
_UniqueBy: TypeAlias =
|
|
29
|
-
_Existing: TypeAlias =
|
|
28
|
+
_Key: TypeAlias = tuple[_Name, _SpanId, _DocumentPosition]
|
|
29
|
+
_UniqueBy: TypeAlias = tuple[_Name, _SpanRowId, _DocumentPosition]
|
|
30
|
+
_Existing: TypeAlias = tuple[
|
|
30
31
|
_SpanRowId,
|
|
31
32
|
_SpanId,
|
|
32
33
|
_NumDocs,
|
|
@@ -51,7 +52,7 @@ class DocumentAnnotationQueueInserter(
|
|
|
51
52
|
self,
|
|
52
53
|
session: AsyncSession,
|
|
53
54
|
*insertions: Insertables.DocumentAnnotation,
|
|
54
|
-
) ->
|
|
55
|
+
) -> list[DocumentAnnotationDmlEvent]:
|
|
55
56
|
records = [dict(as_kv(ins.row)) for ins in insertions]
|
|
56
57
|
stmt = self._insert_on_conflict(*records).returning(self.table.id)
|
|
57
58
|
ids = tuple([_ async for _ in await session.stream_scalars(stmt)])
|
|
@@ -61,17 +62,17 @@ class DocumentAnnotationQueueInserter(
|
|
|
61
62
|
self,
|
|
62
63
|
session: AsyncSession,
|
|
63
64
|
*parcels: Received[Precursors.DocumentAnnotation],
|
|
64
|
-
) ->
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
65
|
+
) -> tuple[
|
|
66
|
+
list[Received[Insertables.DocumentAnnotation]],
|
|
67
|
+
list[Postponed[Precursors.DocumentAnnotation]],
|
|
68
|
+
list[Received[Precursors.DocumentAnnotation]],
|
|
68
69
|
]:
|
|
69
|
-
to_insert:
|
|
70
|
-
to_postpone:
|
|
71
|
-
to_discard:
|
|
70
|
+
to_insert: list[Received[Insertables.DocumentAnnotation]] = []
|
|
71
|
+
to_postpone: list[Postponed[Precursors.DocumentAnnotation]] = []
|
|
72
|
+
to_discard: list[Received[Precursors.DocumentAnnotation]] = []
|
|
72
73
|
|
|
73
74
|
stmt = self._select_existing(*map(_key, parcels))
|
|
74
|
-
existing:
|
|
75
|
+
existing: list[Row[_Existing]] = [_ async for _ in await session.stream(stmt)]
|
|
75
76
|
existing_spans: Mapping[str, _SpanAttr] = {
|
|
76
77
|
e.span_id: _SpanAttr(e.span_rowid, e.num_docs) for e in existing
|
|
77
78
|
}
|
phoenix/db/insertion/helpers.py
CHANGED
|
@@ -1,17 +1,7 @@
|
|
|
1
1
|
from abc import ABC
|
|
2
|
+
from collections.abc import Awaitable, Callable, Iterable, Iterator, Mapping, Sequence
|
|
2
3
|
from enum import Enum, auto
|
|
3
|
-
from typing import
|
|
4
|
-
Any,
|
|
5
|
-
Awaitable,
|
|
6
|
-
Callable,
|
|
7
|
-
Iterable,
|
|
8
|
-
Iterator,
|
|
9
|
-
Mapping,
|
|
10
|
-
Optional,
|
|
11
|
-
Sequence,
|
|
12
|
-
Tuple,
|
|
13
|
-
Type,
|
|
14
|
-
)
|
|
4
|
+
from typing import Any, Optional
|
|
15
5
|
|
|
16
6
|
from sqlalchemy import Insert
|
|
17
7
|
from sqlalchemy.dialects.postgresql import insert as insert_postgresql
|
|
@@ -41,7 +31,7 @@ class OnConflict(Enum):
|
|
|
41
31
|
|
|
42
32
|
def insert_on_conflict(
|
|
43
33
|
*records: Mapping[str, Any],
|
|
44
|
-
table:
|
|
34
|
+
table: type[Base],
|
|
45
35
|
dialect: SupportedSQLDialect,
|
|
46
36
|
unique_by: Sequence[str],
|
|
47
37
|
on_conflict: OnConflict = OnConflict.DO_UPDATE,
|
|
@@ -85,8 +75,8 @@ def insert_on_conflict(
|
|
|
85
75
|
|
|
86
76
|
|
|
87
77
|
def _clean(
|
|
88
|
-
kv: Iterable[
|
|
89
|
-
) -> Iterator[
|
|
78
|
+
kv: Iterable[tuple[str, KeyedColumnElement[Any]]],
|
|
79
|
+
) -> Iterator[tuple[str, KeyedColumnElement[Any]]]:
|
|
90
80
|
for k, v in kv:
|
|
91
81
|
if v.primary_key or v.foreign_keys or k == "created_at":
|
|
92
82
|
continue
|
|
@@ -96,7 +86,7 @@ def _clean(
|
|
|
96
86
|
yield k, v
|
|
97
87
|
|
|
98
88
|
|
|
99
|
-
def as_kv(obj: models.Base) -> Iterator[
|
|
89
|
+
def as_kv(obj: models.Base) -> Iterator[tuple[str, Any]]:
|
|
100
90
|
for k, c in obj.__table__.c.items():
|
|
101
91
|
if k in ["created_at", "updated_at"]:
|
|
102
92
|
continue
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
from collections.abc import Mapping
|
|
1
2
|
from datetime import datetime
|
|
2
|
-
from typing import Any,
|
|
3
|
+
from typing import Any, NamedTuple, Optional
|
|
3
4
|
|
|
4
5
|
from sqlalchemy import Row, Select, and_, select, tuple_
|
|
5
6
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
@@ -22,9 +23,9 @@ _SpanId: TypeAlias = str
|
|
|
22
23
|
_SpanRowId: TypeAlias = int
|
|
23
24
|
_AnnoRowId: TypeAlias = int
|
|
24
25
|
|
|
25
|
-
_Key: TypeAlias =
|
|
26
|
-
_UniqueBy: TypeAlias =
|
|
27
|
-
_Existing: TypeAlias =
|
|
26
|
+
_Key: TypeAlias = tuple[_Name, _SpanId]
|
|
27
|
+
_UniqueBy: TypeAlias = tuple[_Name, _SpanRowId]
|
|
28
|
+
_Existing: TypeAlias = tuple[
|
|
28
29
|
_SpanRowId,
|
|
29
30
|
_SpanId,
|
|
30
31
|
Optional[_AnnoRowId],
|
|
@@ -47,7 +48,7 @@ class SpanAnnotationQueueInserter(
|
|
|
47
48
|
self,
|
|
48
49
|
session: AsyncSession,
|
|
49
50
|
*insertions: Insertables.SpanAnnotation,
|
|
50
|
-
) ->
|
|
51
|
+
) -> list[SpanAnnotationDmlEvent]:
|
|
51
52
|
records = [dict(as_kv(ins.row)) for ins in insertions]
|
|
52
53
|
stmt = self._insert_on_conflict(*records).returning(self.table.id)
|
|
53
54
|
ids = tuple([_ async for _ in await session.stream_scalars(stmt)])
|
|
@@ -57,17 +58,17 @@ class SpanAnnotationQueueInserter(
|
|
|
57
58
|
self,
|
|
58
59
|
session: AsyncSession,
|
|
59
60
|
*parcels: Received[Precursors.SpanAnnotation],
|
|
60
|
-
) ->
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
61
|
+
) -> tuple[
|
|
62
|
+
list[Received[Insertables.SpanAnnotation]],
|
|
63
|
+
list[Postponed[Precursors.SpanAnnotation]],
|
|
64
|
+
list[Received[Precursors.SpanAnnotation]],
|
|
64
65
|
]:
|
|
65
|
-
to_insert:
|
|
66
|
-
to_postpone:
|
|
67
|
-
to_discard:
|
|
66
|
+
to_insert: list[Received[Insertables.SpanAnnotation]] = []
|
|
67
|
+
to_postpone: list[Postponed[Precursors.SpanAnnotation]] = []
|
|
68
|
+
to_discard: list[Received[Precursors.SpanAnnotation]] = []
|
|
68
69
|
|
|
69
70
|
stmt = self._select_existing(*map(_key, parcels))
|
|
70
|
-
existing:
|
|
71
|
+
existing: list[Row[_Existing]] = [_ async for _ in await session.stream(stmt)]
|
|
71
72
|
existing_spans: Mapping[str, _SpanAttr] = {
|
|
72
73
|
e.span_id: _SpanAttr(e.span_rowid) for e in existing
|
|
73
74
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
from collections.abc import Mapping
|
|
1
2
|
from datetime import datetime
|
|
2
|
-
from typing import Any,
|
|
3
|
+
from typing import Any, NamedTuple, Optional
|
|
3
4
|
|
|
4
5
|
from sqlalchemy import Row, Select, and_, select, tuple_
|
|
5
6
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
@@ -22,9 +23,9 @@ _TraceId: TypeAlias = str
|
|
|
22
23
|
_TraceRowId: TypeAlias = int
|
|
23
24
|
_AnnoRowId: TypeAlias = int
|
|
24
25
|
|
|
25
|
-
_Key: TypeAlias =
|
|
26
|
-
_UniqueBy: TypeAlias =
|
|
27
|
-
_Existing: TypeAlias =
|
|
26
|
+
_Key: TypeAlias = tuple[_Name, _TraceId]
|
|
27
|
+
_UniqueBy: TypeAlias = tuple[_Name, _TraceRowId]
|
|
28
|
+
_Existing: TypeAlias = tuple[
|
|
28
29
|
_TraceRowId,
|
|
29
30
|
_TraceId,
|
|
30
31
|
Optional[_AnnoRowId],
|
|
@@ -47,7 +48,7 @@ class TraceAnnotationQueueInserter(
|
|
|
47
48
|
self,
|
|
48
49
|
session: AsyncSession,
|
|
49
50
|
*insertions: Insertables.TraceAnnotation,
|
|
50
|
-
) ->
|
|
51
|
+
) -> list[TraceAnnotationDmlEvent]:
|
|
51
52
|
records = [dict(as_kv(ins.row)) for ins in insertions]
|
|
52
53
|
stmt = self._insert_on_conflict(*records).returning(self.table.id)
|
|
53
54
|
ids = tuple([_ async for _ in await session.stream_scalars(stmt)])
|
|
@@ -57,17 +58,17 @@ class TraceAnnotationQueueInserter(
|
|
|
57
58
|
self,
|
|
58
59
|
session: AsyncSession,
|
|
59
60
|
*parcels: Received[Precursors.TraceAnnotation],
|
|
60
|
-
) ->
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
61
|
+
) -> tuple[
|
|
62
|
+
list[Received[Insertables.TraceAnnotation]],
|
|
63
|
+
list[Postponed[Precursors.TraceAnnotation]],
|
|
64
|
+
list[Received[Precursors.TraceAnnotation]],
|
|
64
65
|
]:
|
|
65
|
-
to_insert:
|
|
66
|
-
to_postpone:
|
|
67
|
-
to_discard:
|
|
66
|
+
to_insert: list[Received[Insertables.TraceAnnotation]] = []
|
|
67
|
+
to_postpone: list[Postponed[Precursors.TraceAnnotation]] = []
|
|
68
|
+
to_discard: list[Received[Precursors.TraceAnnotation]] = []
|
|
68
69
|
|
|
69
70
|
stmt = self._select_existing(*map(_key, parcels))
|
|
70
|
-
existing:
|
|
71
|
+
existing: list[Row[_Existing]] = [_ async for _ in await session.stream(stmt)]
|
|
71
72
|
existing_traces: Mapping[str, _TraceAttr] = {
|
|
72
73
|
e.trace_id: _TraceAttr(e.trace_rowid) for e in existing
|
|
73
74
|
}
|
phoenix/db/insertion/types.py
CHANGED
|
@@ -3,22 +3,11 @@ from __future__ import annotations
|
|
|
3
3
|
import asyncio
|
|
4
4
|
import logging
|
|
5
5
|
from abc import ABC, abstractmethod
|
|
6
|
+
from collections.abc import Mapping, Sequence
|
|
6
7
|
from copy import copy
|
|
7
8
|
from dataclasses import dataclass, field
|
|
8
9
|
from datetime import datetime, timezone
|
|
9
|
-
from typing import
|
|
10
|
-
Any,
|
|
11
|
-
Generic,
|
|
12
|
-
List,
|
|
13
|
-
Mapping,
|
|
14
|
-
Optional,
|
|
15
|
-
Protocol,
|
|
16
|
-
Sequence,
|
|
17
|
-
Tuple,
|
|
18
|
-
Type,
|
|
19
|
-
TypeVar,
|
|
20
|
-
cast,
|
|
21
|
-
)
|
|
10
|
+
from typing import Any, Generic, Optional, Protocol, TypeVar, cast
|
|
22
11
|
|
|
23
12
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
24
13
|
from sqlalchemy.sql.dml import Insert
|
|
@@ -59,12 +48,12 @@ class Postponed(Received[_AnyT]):
|
|
|
59
48
|
|
|
60
49
|
|
|
61
50
|
class QueueInserter(ABC, Generic[_PrecursorT, _InsertableT, _RowT, _DmlEventT]):
|
|
62
|
-
table:
|
|
51
|
+
table: type[_RowT]
|
|
63
52
|
unique_by: Sequence[str]
|
|
64
53
|
|
|
65
54
|
def __init_subclass__(
|
|
66
55
|
cls,
|
|
67
|
-
table:
|
|
56
|
+
table: type[_RowT],
|
|
68
57
|
unique_by: Sequence[str],
|
|
69
58
|
) -> None:
|
|
70
59
|
cls.table = table
|
|
@@ -76,7 +65,7 @@ class QueueInserter(ABC, Generic[_PrecursorT, _InsertableT, _RowT, _DmlEventT]):
|
|
|
76
65
|
retry_delay_sec: float = DEFAULT_RETRY_DELAY_SEC,
|
|
77
66
|
retry_allowance: int = DEFAULT_RETRY_ALLOWANCE,
|
|
78
67
|
) -> None:
|
|
79
|
-
self._queue:
|
|
68
|
+
self._queue: list[Received[_PrecursorT]] = []
|
|
80
69
|
self._db = db
|
|
81
70
|
self._retry_delay_sec = retry_delay_sec
|
|
82
71
|
self._retry_allowance = retry_allowance
|
|
@@ -93,17 +82,17 @@ class QueueInserter(ABC, Generic[_PrecursorT, _InsertableT, _RowT, _DmlEventT]):
|
|
|
93
82
|
self,
|
|
94
83
|
session: AsyncSession,
|
|
95
84
|
*parcels: Received[_PrecursorT],
|
|
96
|
-
) ->
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
85
|
+
) -> tuple[
|
|
86
|
+
list[Received[_InsertableT]],
|
|
87
|
+
list[Postponed[_PrecursorT]],
|
|
88
|
+
list[Received[_PrecursorT]],
|
|
100
89
|
]: ...
|
|
101
90
|
|
|
102
|
-
async def insert(self) -> Optional[
|
|
91
|
+
async def insert(self) -> Optional[list[_DmlEventT]]:
|
|
103
92
|
if not self._queue:
|
|
104
93
|
return None
|
|
105
94
|
self._queue, parcels = [], self._queue
|
|
106
|
-
events:
|
|
95
|
+
events: list[_DmlEventT] = []
|
|
107
96
|
async with self._db() as session:
|
|
108
97
|
to_insert, to_postpone, _ = await self._partition(session, *parcels)
|
|
109
98
|
if to_insert:
|
|
@@ -128,20 +117,20 @@ class QueueInserter(ABC, Generic[_PrecursorT, _InsertableT, _RowT, _DmlEventT]):
|
|
|
128
117
|
self,
|
|
129
118
|
session: AsyncSession,
|
|
130
119
|
*insertions: _InsertableT,
|
|
131
|
-
) ->
|
|
120
|
+
) -> list[_DmlEventT]: ...
|
|
132
121
|
|
|
133
122
|
async def _insert(
|
|
134
123
|
self,
|
|
135
124
|
session: AsyncSession,
|
|
136
125
|
*parcels: Received[_InsertableT],
|
|
137
|
-
) ->
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
126
|
+
) -> tuple[
|
|
127
|
+
list[_DmlEventT],
|
|
128
|
+
list[Postponed[_PrecursorT]],
|
|
129
|
+
list[Received[_InsertableT]],
|
|
141
130
|
]:
|
|
142
|
-
to_retry:
|
|
143
|
-
failures:
|
|
144
|
-
events:
|
|
131
|
+
to_retry: list[Postponed[_PrecursorT]] = []
|
|
132
|
+
failures: list[Received[_InsertableT]] = []
|
|
133
|
+
events: list[_DmlEventT] = []
|
|
145
134
|
try:
|
|
146
135
|
async with session.begin_nested():
|
|
147
136
|
events.extend(await self._events(session, *(p.item for p in parcels)))
|
|
@@ -6,7 +6,7 @@ Create Date: 2024-08-03 22:11:28.733133
|
|
|
6
6
|
|
|
7
7
|
"""
|
|
8
8
|
|
|
9
|
-
from typing import Any,
|
|
9
|
+
from typing import Any, Optional, Sequence, TypedDict, Union
|
|
10
10
|
|
|
11
11
|
import sqlalchemy as sa
|
|
12
12
|
from alembic import op
|
|
@@ -51,21 +51,21 @@ JSON_ = (
|
|
|
51
51
|
)
|
|
52
52
|
|
|
53
53
|
|
|
54
|
-
class JsonDict(TypeDecorator[
|
|
54
|
+
class JsonDict(TypeDecorator[dict[str, Any]]):
|
|
55
55
|
# See # See https://docs.sqlalchemy.org/en/20/core/custom_types.html
|
|
56
56
|
cache_ok = True
|
|
57
57
|
impl = JSON_
|
|
58
58
|
|
|
59
|
-
def process_bind_param(self, value: Optional[
|
|
59
|
+
def process_bind_param(self, value: Optional[dict[str, Any]], _: Dialect) -> dict[str, Any]:
|
|
60
60
|
return value if isinstance(value, dict) else {}
|
|
61
61
|
|
|
62
62
|
|
|
63
|
-
class JsonList(TypeDecorator[
|
|
63
|
+
class JsonList(TypeDecorator[list[Any]]):
|
|
64
64
|
# See # See https://docs.sqlalchemy.org/en/20/core/custom_types.html
|
|
65
65
|
cache_ok = True
|
|
66
66
|
impl = JSON_
|
|
67
67
|
|
|
68
|
-
def process_bind_param(self, value: Optional[
|
|
68
|
+
def process_bind_param(self, value: Optional[list[Any]], _: Dialect) -> list[Any]:
|
|
69
69
|
return value if isinstance(value, list) else []
|
|
70
70
|
|
|
71
71
|
|
|
@@ -86,8 +86,8 @@ class Base(DeclarativeBase):
|
|
|
86
86
|
}
|
|
87
87
|
)
|
|
88
88
|
type_annotation_map = {
|
|
89
|
-
|
|
90
|
-
|
|
89
|
+
dict[str, Any]: JsonDict,
|
|
90
|
+
list[dict[str, Any]]: JsonList,
|
|
91
91
|
ExperimentRunOutput: JsonDict,
|
|
92
92
|
}
|
|
93
93
|
|
|
@@ -95,7 +95,7 @@ class Base(DeclarativeBase):
|
|
|
95
95
|
class Span(Base):
|
|
96
96
|
__tablename__ = "spans"
|
|
97
97
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
98
|
-
attributes: Mapped[
|
|
98
|
+
attributes: Mapped[dict[str, Any]]
|
|
99
99
|
llm_token_count_prompt: Mapped[Optional[int]]
|
|
100
100
|
llm_token_count_completion: Mapped[Optional[int]]
|
|
101
101
|
|
phoenix/db/models.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from datetime import datetime, timezone
|
|
2
2
|
from enum import Enum
|
|
3
|
-
from typing import Any,
|
|
3
|
+
from typing import Any, Optional, TypedDict
|
|
4
4
|
|
|
5
5
|
from sqlalchemy import (
|
|
6
6
|
JSON,
|
|
@@ -69,21 +69,21 @@ JSON_ = (
|
|
|
69
69
|
)
|
|
70
70
|
|
|
71
71
|
|
|
72
|
-
class JsonDict(TypeDecorator[
|
|
72
|
+
class JsonDict(TypeDecorator[dict[str, Any]]):
|
|
73
73
|
# See # See https://docs.sqlalchemy.org/en/20/core/custom_types.html
|
|
74
74
|
cache_ok = True
|
|
75
75
|
impl = JSON_
|
|
76
76
|
|
|
77
|
-
def process_bind_param(self, value: Optional[
|
|
77
|
+
def process_bind_param(self, value: Optional[dict[str, Any]], _: Dialect) -> dict[str, Any]:
|
|
78
78
|
return value if isinstance(value, dict) else {}
|
|
79
79
|
|
|
80
80
|
|
|
81
|
-
class JsonList(TypeDecorator[
|
|
81
|
+
class JsonList(TypeDecorator[list[Any]]):
|
|
82
82
|
# See # See https://docs.sqlalchemy.org/en/20/core/custom_types.html
|
|
83
83
|
cache_ok = True
|
|
84
84
|
impl = JSON_
|
|
85
85
|
|
|
86
|
-
def process_bind_param(self, value: Optional[
|
|
86
|
+
def process_bind_param(self, value: Optional[list[Any]], _: Dialect) -> list[Any]:
|
|
87
87
|
return value if isinstance(value, list) else []
|
|
88
88
|
|
|
89
89
|
|
|
@@ -117,8 +117,8 @@ class Base(DeclarativeBase):
|
|
|
117
117
|
},
|
|
118
118
|
)
|
|
119
119
|
type_annotation_map = {
|
|
120
|
-
|
|
121
|
-
|
|
120
|
+
dict[str, Any]: JsonDict,
|
|
121
|
+
list[dict[str, Any]]: JsonList,
|
|
122
122
|
ExperimentRunOutput: JsonDict,
|
|
123
123
|
}
|
|
124
124
|
|
|
@@ -142,7 +142,7 @@ class Project(Base):
|
|
|
142
142
|
UtcTimeStamp, server_default=func.now(), onupdate=func.now()
|
|
143
143
|
)
|
|
144
144
|
|
|
145
|
-
traces: WriteOnlyMapped[
|
|
145
|
+
traces: WriteOnlyMapped[list["Trace"]] = relationship(
|
|
146
146
|
"Trace",
|
|
147
147
|
back_populates="project",
|
|
148
148
|
cascade="all, delete-orphan",
|
|
@@ -182,13 +182,13 @@ class Trace(Base):
|
|
|
182
182
|
"Project",
|
|
183
183
|
back_populates="traces",
|
|
184
184
|
)
|
|
185
|
-
spans: Mapped[
|
|
185
|
+
spans: Mapped[list["Span"]] = relationship(
|
|
186
186
|
"Span",
|
|
187
187
|
back_populates="trace",
|
|
188
188
|
cascade="all, delete-orphan",
|
|
189
189
|
uselist=True,
|
|
190
190
|
)
|
|
191
|
-
experiment_runs: Mapped[
|
|
191
|
+
experiment_runs: Mapped[list["ExperimentRun"]] = relationship(
|
|
192
192
|
primaryjoin="foreign(ExperimentRun.trace_id) == Trace.trace_id",
|
|
193
193
|
back_populates="trace",
|
|
194
194
|
)
|
|
@@ -212,8 +212,8 @@ class Span(Base):
|
|
|
212
212
|
span_kind: Mapped[str]
|
|
213
213
|
start_time: Mapped[datetime] = mapped_column(UtcTimeStamp, index=True)
|
|
214
214
|
end_time: Mapped[datetime] = mapped_column(UtcTimeStamp)
|
|
215
|
-
attributes: Mapped[
|
|
216
|
-
events: Mapped[
|
|
215
|
+
attributes: Mapped[dict[str, Any]]
|
|
216
|
+
events: Mapped[list[dict[str, Any]]]
|
|
217
217
|
status_code: Mapped[str] = mapped_column(
|
|
218
218
|
CheckConstraint("status_code IN ('OK', 'ERROR', 'UNSET')", name="valid_status")
|
|
219
219
|
)
|
|
@@ -248,8 +248,8 @@ class Span(Base):
|
|
|
248
248
|
return (self.llm_token_count_prompt or 0) + (self.llm_token_count_completion or 0)
|
|
249
249
|
|
|
250
250
|
trace: Mapped["Trace"] = relationship("Trace", back_populates="spans")
|
|
251
|
-
document_annotations: Mapped[
|
|
252
|
-
dataset_examples: Mapped[
|
|
251
|
+
document_annotations: Mapped[list["DocumentAnnotation"]] = relationship(back_populates="span")
|
|
252
|
+
dataset_examples: Mapped[list["DatasetExample"]] = relationship(back_populates="span")
|
|
253
253
|
|
|
254
254
|
__table_args__ = (
|
|
255
255
|
UniqueConstraint(
|
|
@@ -351,7 +351,7 @@ class SpanAnnotation(Base):
|
|
|
351
351
|
label: Mapped[Optional[str]] = mapped_column(String, index=True)
|
|
352
352
|
score: Mapped[Optional[float]] = mapped_column(Float, index=True)
|
|
353
353
|
explanation: Mapped[Optional[str]]
|
|
354
|
-
metadata_: Mapped[
|
|
354
|
+
metadata_: Mapped[dict[str, Any]] = mapped_column("metadata")
|
|
355
355
|
annotator_kind: Mapped[str] = mapped_column(
|
|
356
356
|
CheckConstraint("annotator_kind IN ('LLM', 'HUMAN')", name="valid_annotator_kind"),
|
|
357
357
|
)
|
|
@@ -378,7 +378,7 @@ class TraceAnnotation(Base):
|
|
|
378
378
|
label: Mapped[Optional[str]] = mapped_column(String, index=True)
|
|
379
379
|
score: Mapped[Optional[float]] = mapped_column(Float, index=True)
|
|
380
380
|
explanation: Mapped[Optional[str]]
|
|
381
|
-
metadata_: Mapped[
|
|
381
|
+
metadata_: Mapped[dict[str, Any]] = mapped_column("metadata")
|
|
382
382
|
annotator_kind: Mapped[str] = mapped_column(
|
|
383
383
|
CheckConstraint("annotator_kind IN ('LLM', 'HUMAN')", name="valid_annotator_kind"),
|
|
384
384
|
)
|
|
@@ -406,7 +406,7 @@ class DocumentAnnotation(Base):
|
|
|
406
406
|
label: Mapped[Optional[str]] = mapped_column(String, index=True)
|
|
407
407
|
score: Mapped[Optional[float]] = mapped_column(Float, index=True)
|
|
408
408
|
explanation: Mapped[Optional[str]]
|
|
409
|
-
metadata_: Mapped[
|
|
409
|
+
metadata_: Mapped[dict[str, Any]] = mapped_column("metadata")
|
|
410
410
|
annotator_kind: Mapped[str] = mapped_column(
|
|
411
411
|
CheckConstraint("annotator_kind IN ('LLM', 'HUMAN')", name="valid_annotator_kind"),
|
|
412
412
|
)
|
|
@@ -430,7 +430,7 @@ class Dataset(Base):
|
|
|
430
430
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
431
431
|
name: Mapped[str] = mapped_column(unique=True)
|
|
432
432
|
description: Mapped[Optional[str]]
|
|
433
|
-
metadata_: Mapped[
|
|
433
|
+
metadata_: Mapped[dict[str, Any]] = mapped_column("metadata")
|
|
434
434
|
created_at: Mapped[datetime] = mapped_column(UtcTimeStamp, server_default=func.now())
|
|
435
435
|
updated_at: Mapped[datetime] = mapped_column(
|
|
436
436
|
UtcTimeStamp, server_default=func.now(), onupdate=func.now()
|
|
@@ -493,7 +493,7 @@ class DatasetVersion(Base):
|
|
|
493
493
|
index=True,
|
|
494
494
|
)
|
|
495
495
|
description: Mapped[Optional[str]]
|
|
496
|
-
metadata_: Mapped[
|
|
496
|
+
metadata_: Mapped[dict[str, Any]] = mapped_column("metadata")
|
|
497
497
|
created_at: Mapped[datetime] = mapped_column(UtcTimeStamp, server_default=func.now())
|
|
498
498
|
|
|
499
499
|
|
|
@@ -525,9 +525,9 @@ class DatasetExampleRevision(Base):
|
|
|
525
525
|
ForeignKey("dataset_versions.id", ondelete="CASCADE"),
|
|
526
526
|
index=True,
|
|
527
527
|
)
|
|
528
|
-
input: Mapped[
|
|
529
|
-
output: Mapped[
|
|
530
|
-
metadata_: Mapped[
|
|
528
|
+
input: Mapped[dict[str, Any]]
|
|
529
|
+
output: Mapped[dict[str, Any]]
|
|
530
|
+
metadata_: Mapped[dict[str, Any]] = mapped_column("metadata")
|
|
531
531
|
revision_kind: Mapped[str] = mapped_column(
|
|
532
532
|
CheckConstraint(
|
|
533
533
|
"revision_kind IN ('CREATE', 'PATCH', 'DELETE')", name="valid_revision_kind"
|
|
@@ -557,7 +557,7 @@ class Experiment(Base):
|
|
|
557
557
|
name: Mapped[str]
|
|
558
558
|
description: Mapped[Optional[str]]
|
|
559
559
|
repetitions: Mapped[int]
|
|
560
|
-
metadata_: Mapped[
|
|
560
|
+
metadata_: Mapped[dict[str, Any]] = mapped_column("metadata")
|
|
561
561
|
project_name: Mapped[Optional[str]] = mapped_column(index=True)
|
|
562
562
|
created_at: Mapped[datetime] = mapped_column(UtcTimeStamp, server_default=func.now())
|
|
563
563
|
updated_at: Mapped[datetime] = mapped_column(
|
|
@@ -615,7 +615,7 @@ class ExperimentRunAnnotation(Base):
|
|
|
615
615
|
explanation: Mapped[Optional[str]]
|
|
616
616
|
trace_id: Mapped[Optional[str]]
|
|
617
617
|
error: Mapped[Optional[str]]
|
|
618
|
-
metadata_: Mapped[
|
|
618
|
+
metadata_: Mapped[dict[str, Any]] = mapped_column("metadata")
|
|
619
619
|
start_time: Mapped[datetime] = mapped_column(UtcTimeStamp)
|
|
620
620
|
end_time: Mapped[datetime] = mapped_column(UtcTimeStamp)
|
|
621
621
|
|
|
@@ -631,7 +631,7 @@ class UserRole(Base):
|
|
|
631
631
|
__tablename__ = "user_roles"
|
|
632
632
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
633
633
|
name: Mapped[str] = mapped_column(unique=True, index=True)
|
|
634
|
-
users: Mapped[
|
|
634
|
+
users: Mapped[list["User"]] = relationship("User", back_populates="role")
|
|
635
635
|
|
|
636
636
|
|
|
637
637
|
class User(Base):
|
|
@@ -659,11 +659,11 @@ class User(Base):
|
|
|
659
659
|
back_populates="user",
|
|
660
660
|
uselist=False,
|
|
661
661
|
)
|
|
662
|
-
access_tokens: Mapped[
|
|
663
|
-
refresh_tokens: Mapped[
|
|
662
|
+
access_tokens: Mapped[list["AccessToken"]] = relationship("AccessToken", back_populates="user")
|
|
663
|
+
refresh_tokens: Mapped[list["RefreshToken"]] = relationship(
|
|
664
664
|
"RefreshToken", back_populates="user"
|
|
665
665
|
)
|
|
666
|
-
api_keys: Mapped[
|
|
666
|
+
api_keys: Mapped[list["ApiKey"]] = relationship("ApiKey", back_populates="user")
|
|
667
667
|
|
|
668
668
|
@hybrid_property
|
|
669
669
|
def auth_method(self) -> Optional[str]:
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import functools
|
|
2
2
|
import inspect
|
|
3
3
|
from abc import ABC
|
|
4
|
+
from collections.abc import Awaitable, Callable
|
|
4
5
|
from types import MappingProxyType
|
|
5
|
-
from typing import Any,
|
|
6
|
+
from typing import Any, Optional, Union
|
|
6
7
|
|
|
7
8
|
from typing_extensions import TypeAlias
|
|
8
9
|
|
|
@@ -4,7 +4,6 @@ import json
|
|
|
4
4
|
import re
|
|
5
5
|
from typing import (
|
|
6
6
|
Any,
|
|
7
|
-
List,
|
|
8
7
|
Optional,
|
|
9
8
|
Pattern, # import from re module when we drop support for 3.8
|
|
10
9
|
Union,
|
|
@@ -78,7 +77,7 @@ class ContainsAnyKeyword(CodeEvaluator):
|
|
|
78
77
|
An evaluator that checks if any of the keywords are present in the output of an experiment run.
|
|
79
78
|
|
|
80
79
|
Args:
|
|
81
|
-
keywords (
|
|
80
|
+
keywords (list[str]): The keywords to search for in the output.
|
|
82
81
|
name (str, optional): An optional name for the evaluator. Defaults to
|
|
83
82
|
"ContainsAny(<keywords>)".
|
|
84
83
|
|
|
@@ -91,7 +90,7 @@ class ContainsAnyKeyword(CodeEvaluator):
|
|
|
91
90
|
run_experiment(dataset, task, evaluators=[ContainsAnyKeyword(["foo", "bar"])])
|
|
92
91
|
"""
|
|
93
92
|
|
|
94
|
-
def __init__(self, keywords:
|
|
93
|
+
def __init__(self, keywords: list[str], name: Optional[str] = None) -> None:
|
|
95
94
|
self.keywords = keywords
|
|
96
95
|
self._name = name or f"ContainsAny({keywords})"
|
|
97
96
|
|
|
@@ -113,7 +112,7 @@ class ContainsAllKeywords(CodeEvaluator):
|
|
|
113
112
|
An evaluator that checks if all of the keywords are present in the output of an experiment run.
|
|
114
113
|
|
|
115
114
|
Args:
|
|
116
|
-
keywords (
|
|
115
|
+
keywords (list[str]): The keywords to search for in the output.
|
|
117
116
|
name (str, optional): An optional name for the evaluator. Defaults to
|
|
118
117
|
"ContainsAll(<keywords>)".
|
|
119
118
|
|
|
@@ -126,7 +125,7 @@ class ContainsAllKeywords(CodeEvaluator):
|
|
|
126
125
|
run_experiment(dataset, task, evaluators=[ContainsAllKeywords(["foo", "bar"])])
|
|
127
126
|
"""
|
|
128
127
|
|
|
129
|
-
def __init__(self, keywords:
|
|
128
|
+
def __init__(self, keywords: list[str], name: Optional[str] = None) -> None:
|
|
130
129
|
self.keywords = keywords
|
|
131
130
|
self._name = name or f"ContainsAll({keywords})"
|
|
132
131
|
|