arize-phoenix 5.5.2__py3-none-any.whl → 5.7.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.7.0.dist-info}/METADATA +4 -7
- arize_phoenix-5.7.0.dist-info/RECORD +330 -0
- phoenix/config.py +50 -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/helpers/playground_clients.py +671 -0
- phoenix/server/api/helpers/playground_registry.py +70 -0
- phoenix/server/api/helpers/playground_spans.py +325 -0
- phoenix/server/api/input_types/AddExamplesToDatasetInput.py +2 -2
- phoenix/server/api/input_types/AddSpansToDatasetInput.py +2 -2
- phoenix/server/api/input_types/ChatCompletionInput.py +38 -0
- 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/GenerativeModelInput.py +17 -0
- phoenix/server/api/input_types/Granularity.py +1 -1
- phoenix/server/api/input_types/InvocationParameters.py +156 -13
- phoenix/server/api/input_types/PatchDatasetExamplesInput.py +2 -2
- phoenix/server/api/input_types/TemplateOptions.py +10 -0
- phoenix/server/api/mutations/__init__.py +4 -0
- phoenix/server/api/mutations/chat_mutations.py +374 -0
- 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 +61 -72
- 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/schema.py +42 -10
- phoenix/server/api/subscriptions.py +347 -494
- phoenix/server/api/types/AnnotationSummary.py +3 -3
- phoenix/server/api/types/ChatCompletionSubscriptionPayload.py +44 -0
- 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/GenerativeProvider.py +27 -3
- 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 +45 -7
- phoenix/server/api/types/TemplateLanguage.py +9 -0
- 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 +76 -37
- 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 +17 -4
- 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-Csu8UKOs.js +1612 -0
- phoenix/server/static/assets/{index-DCzakdJq.js → index-Bk5C9EA7.js} +2 -2
- phoenix/server/static/assets/{pages-CAL1FDMt.js → pages-UeWaKXNs.js} +337 -442
- 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/templates/index.html +1 -0
- phoenix/server/thread_server.py +1 -1
- phoenix/server/types.py +17 -29
- phoenix/services.py +8 -3
- phoenix/session/client.py +12 -24
- phoenix/session/data_extractor.py +3 -3
- phoenix/session/evaluation.py +1 -2
- phoenix/session/session.py +26 -21
- 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 +16 -5
- phoenix/version.py +1 -1
- arize_phoenix-5.5.2.dist-info/RECORD +0 -321
- phoenix/server/static/assets/components-hX0LgYz3.js +0 -1428
- {arize_phoenix-5.5.2.dist-info → arize_phoenix-5.7.0.dist-info}/WHEEL +0 -0
- {arize_phoenix-5.5.2.dist-info → arize_phoenix-5.7.0.dist-info}/entry_points.txt +0 -0
- {arize_phoenix-5.5.2.dist-info → arize_phoenix-5.7.0.dist-info}/licenses/IP_NOTICE +0 -0
- {arize_phoenix-5.5.2.dist-info → arize_phoenix-5.7.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,13 +1,6 @@
|
|
|
1
1
|
from collections import defaultdict
|
|
2
2
|
from datetime import datetime
|
|
3
|
-
from typing import
|
|
4
|
-
Any,
|
|
5
|
-
DefaultDict,
|
|
6
|
-
List,
|
|
7
|
-
Literal,
|
|
8
|
-
Optional,
|
|
9
|
-
Tuple,
|
|
10
|
-
)
|
|
3
|
+
from typing import Any, Literal, Optional
|
|
11
4
|
|
|
12
5
|
from cachetools import LFUCache, TTLCache
|
|
13
6
|
from sqlalchemy import Select, func, select
|
|
@@ -22,20 +15,20 @@ from phoenix.trace.dsl import SpanFilter
|
|
|
22
15
|
|
|
23
16
|
Kind: TypeAlias = Literal["span", "trace"]
|
|
24
17
|
ProjectRowId: TypeAlias = int
|
|
25
|
-
TimeInterval: TypeAlias =
|
|
18
|
+
TimeInterval: TypeAlias = tuple[Optional[datetime], Optional[datetime]]
|
|
26
19
|
FilterCondition: TypeAlias = Optional[str]
|
|
27
20
|
SpanCount: TypeAlias = int
|
|
28
21
|
|
|
29
|
-
Segment: TypeAlias =
|
|
22
|
+
Segment: TypeAlias = tuple[Kind, TimeInterval, FilterCondition]
|
|
30
23
|
Param: TypeAlias = ProjectRowId
|
|
31
24
|
|
|
32
|
-
Key: TypeAlias =
|
|
25
|
+
Key: TypeAlias = tuple[Kind, ProjectRowId, Optional[TimeRange], FilterCondition]
|
|
33
26
|
Result: TypeAlias = SpanCount
|
|
34
27
|
ResultPosition: TypeAlias = int
|
|
35
28
|
DEFAULT_VALUE: Result = 0
|
|
36
29
|
|
|
37
30
|
|
|
38
|
-
def _cache_key_fn(key: Key) ->
|
|
31
|
+
def _cache_key_fn(key: Key) -> tuple[Segment, Param]:
|
|
39
32
|
kind, project_rowid, time_range, filter_condition = key
|
|
40
33
|
interval = (
|
|
41
34
|
(time_range.start, time_range.end) if isinstance(time_range, TimeRange) else (None, None)
|
|
@@ -44,7 +37,7 @@ def _cache_key_fn(key: Key) -> Tuple[Segment, Param]:
|
|
|
44
37
|
|
|
45
38
|
|
|
46
39
|
_Section: TypeAlias = ProjectRowId
|
|
47
|
-
_SubKey: TypeAlias =
|
|
40
|
+
_SubKey: TypeAlias = tuple[TimeInterval, FilterCondition, Kind]
|
|
48
41
|
|
|
49
42
|
|
|
50
43
|
class RecordCountCache(
|
|
@@ -59,7 +52,7 @@ class RecordCountCache(
|
|
|
59
52
|
sub_cache_factory=lambda: LFUCache(maxsize=2 * 2 * 2),
|
|
60
53
|
)
|
|
61
54
|
|
|
62
|
-
def _cache_key(self, key: Key) ->
|
|
55
|
+
def _cache_key(self, key: Key) -> tuple[_Section, _SubKey]:
|
|
63
56
|
(kind, interval, filter_condition), project_rowid = _cache_key_fn(key)
|
|
64
57
|
return project_rowid, (interval, filter_condition, kind)
|
|
65
58
|
|
|
@@ -77,11 +70,11 @@ class RecordCountDataLoader(DataLoader[Key, Result]):
|
|
|
77
70
|
)
|
|
78
71
|
self._db = db
|
|
79
72
|
|
|
80
|
-
async def _load_fn(self, keys:
|
|
81
|
-
results:
|
|
82
|
-
arguments:
|
|
73
|
+
async def _load_fn(self, keys: list[Key]) -> list[Result]:
|
|
74
|
+
results: list[Result] = [DEFAULT_VALUE] * len(keys)
|
|
75
|
+
arguments: defaultdict[
|
|
83
76
|
Segment,
|
|
84
|
-
|
|
77
|
+
defaultdict[Param, list[ResultPosition]],
|
|
85
78
|
] = defaultdict(lambda: defaultdict(list))
|
|
86
79
|
for position, key in enumerate(keys):
|
|
87
80
|
segment, param = _cache_key_fn(key)
|
|
@@ -1,8 +1,4 @@
|
|
|
1
1
|
from collections import defaultdict
|
|
2
|
-
from typing import (
|
|
3
|
-
DefaultDict,
|
|
4
|
-
List,
|
|
5
|
-
)
|
|
6
2
|
|
|
7
3
|
from sqlalchemy import select
|
|
8
4
|
from strawberry.dataloader import DataLoader
|
|
@@ -12,7 +8,7 @@ from phoenix.db.models import SpanAnnotation as ORMSpanAnnotation
|
|
|
12
8
|
from phoenix.server.types import DbSessionFactory
|
|
13
9
|
|
|
14
10
|
Key: TypeAlias = int
|
|
15
|
-
Result: TypeAlias =
|
|
11
|
+
Result: TypeAlias = list[ORMSpanAnnotation]
|
|
16
12
|
|
|
17
13
|
|
|
18
14
|
class SpanAnnotationsDataLoader(DataLoader[Key, Result]):
|
|
@@ -20,8 +16,8 @@ class SpanAnnotationsDataLoader(DataLoader[Key, Result]):
|
|
|
20
16
|
super().__init__(load_fn=self._load_fn)
|
|
21
17
|
self._db = db
|
|
22
18
|
|
|
23
|
-
async def _load_fn(self, keys:
|
|
24
|
-
span_annotations_by_id:
|
|
19
|
+
async def _load_fn(self, keys: list[Key]) -> list[Result]:
|
|
20
|
+
span_annotations_by_id: defaultdict[Key, Result] = defaultdict(list)
|
|
25
21
|
async with self._db() as session:
|
|
26
22
|
async for span_annotation in await session.stream_scalars(
|
|
27
23
|
select(ORMSpanAnnotation).where(ORMSpanAnnotation.span_rowid.in_(keys))
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
from typing import (
|
|
2
|
-
Dict,
|
|
3
|
-
List,
|
|
4
|
-
)
|
|
5
|
-
|
|
6
1
|
from sqlalchemy import select
|
|
7
2
|
from strawberry.dataloader import DataLoader
|
|
8
3
|
from typing_extensions import TypeAlias
|
|
@@ -12,7 +7,7 @@ from phoenix.server.types import DbSessionFactory
|
|
|
12
7
|
|
|
13
8
|
SpanID: TypeAlias = int
|
|
14
9
|
Key: TypeAlias = SpanID
|
|
15
|
-
Result: TypeAlias =
|
|
10
|
+
Result: TypeAlias = list[models.DatasetExample]
|
|
16
11
|
|
|
17
12
|
|
|
18
13
|
class SpanDatasetExamplesDataLoader(DataLoader[Key, Result]):
|
|
@@ -20,10 +15,10 @@ class SpanDatasetExamplesDataLoader(DataLoader[Key, Result]):
|
|
|
20
15
|
super().__init__(load_fn=self._load_fn)
|
|
21
16
|
self._db = db
|
|
22
17
|
|
|
23
|
-
async def _load_fn(self, keys:
|
|
18
|
+
async def _load_fn(self, keys: list[Key]) -> list[Result]:
|
|
24
19
|
span_rowids = keys
|
|
25
20
|
async with self._db() as session:
|
|
26
|
-
dataset_examples:
|
|
21
|
+
dataset_examples: dict[Key, list[models.DatasetExample]] = {
|
|
27
22
|
span_rowid: [] for span_rowid in span_rowids
|
|
28
23
|
}
|
|
29
24
|
async for span_rowid, dataset_example in await session.stream(
|
|
@@ -1,8 +1,4 @@
|
|
|
1
1
|
from random import randint
|
|
2
|
-
from typing import (
|
|
3
|
-
Dict,
|
|
4
|
-
List,
|
|
5
|
-
)
|
|
6
2
|
|
|
7
3
|
from aioitertools.itertools import groupby
|
|
8
4
|
from sqlalchemy import select
|
|
@@ -16,7 +12,7 @@ from phoenix.server.types import DbSessionFactory
|
|
|
16
12
|
SpanId: TypeAlias = str
|
|
17
13
|
|
|
18
14
|
Key: TypeAlias = SpanId
|
|
19
|
-
Result: TypeAlias =
|
|
15
|
+
Result: TypeAlias = list[models.Span]
|
|
20
16
|
|
|
21
17
|
|
|
22
18
|
class SpanDescendantsDataLoader(DataLoader[Key, Result]):
|
|
@@ -24,7 +20,7 @@ class SpanDescendantsDataLoader(DataLoader[Key, Result]):
|
|
|
24
20
|
super().__init__(load_fn=self._load_fn)
|
|
25
21
|
self._db = db
|
|
26
22
|
|
|
27
|
-
async def _load_fn(self, keys:
|
|
23
|
+
async def _load_fn(self, keys: list[Key]) -> list[Result]:
|
|
28
24
|
root_ids = set(keys)
|
|
29
25
|
root_id_label = f"root_id_{randint(0, 10**6):06}"
|
|
30
26
|
descendant_ids = (
|
|
@@ -53,7 +49,7 @@ class SpanDescendantsDataLoader(DataLoader[Key, Result]):
|
|
|
53
49
|
.options(joinedload(models.Span.trace, innerjoin=True).load_only(models.Trace.trace_id))
|
|
54
50
|
.order_by(descendant_ids.c[root_id_label])
|
|
55
51
|
)
|
|
56
|
-
results:
|
|
52
|
+
results: dict[SpanId, Result] = {key: [] for key in keys}
|
|
57
53
|
async with self._db() as session:
|
|
58
54
|
data = await session.stream(stmt)
|
|
59
55
|
async for root_id, group in groupby(data, key=lambda d: d[0]):
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import
|
|
1
|
+
from typing import Union
|
|
2
2
|
|
|
3
3
|
from sqlalchemy import select
|
|
4
4
|
from strawberry.dataloader import DataLoader
|
|
@@ -17,7 +17,7 @@ class SpanProjectsDataLoader(DataLoader[Key, Result]):
|
|
|
17
17
|
super().__init__(load_fn=self._load_fn)
|
|
18
18
|
self._db = db
|
|
19
19
|
|
|
20
|
-
async def _load_fn(self, keys:
|
|
20
|
+
async def _load_fn(self, keys: list[Key]) -> list[Union[Result, ValueError]]:
|
|
21
21
|
span_ids = list(set(keys))
|
|
22
22
|
async with self._db() as session:
|
|
23
23
|
projects = {
|
|
@@ -1,13 +1,6 @@
|
|
|
1
1
|
from collections import defaultdict
|
|
2
2
|
from datetime import datetime
|
|
3
|
-
from typing import
|
|
4
|
-
Any,
|
|
5
|
-
DefaultDict,
|
|
6
|
-
List,
|
|
7
|
-
Literal,
|
|
8
|
-
Optional,
|
|
9
|
-
Tuple,
|
|
10
|
-
)
|
|
3
|
+
from typing import Any, Literal, Optional
|
|
11
4
|
|
|
12
5
|
from cachetools import LFUCache, TTLCache
|
|
13
6
|
from sqlalchemy import Select, func, select
|
|
@@ -23,20 +16,20 @@ from phoenix.trace.dsl import SpanFilter
|
|
|
23
16
|
|
|
24
17
|
Kind: TypeAlias = Literal["prompt", "completion", "total"]
|
|
25
18
|
ProjectRowId: TypeAlias = int
|
|
26
|
-
TimeInterval: TypeAlias =
|
|
19
|
+
TimeInterval: TypeAlias = tuple[Optional[datetime], Optional[datetime]]
|
|
27
20
|
FilterCondition: TypeAlias = Optional[str]
|
|
28
21
|
TokenCount: TypeAlias = int
|
|
29
22
|
|
|
30
|
-
Segment: TypeAlias =
|
|
31
|
-
Param: TypeAlias =
|
|
23
|
+
Segment: TypeAlias = tuple[TimeInterval, FilterCondition]
|
|
24
|
+
Param: TypeAlias = tuple[ProjectRowId, Kind]
|
|
32
25
|
|
|
33
|
-
Key: TypeAlias =
|
|
26
|
+
Key: TypeAlias = tuple[Kind, ProjectRowId, Optional[TimeRange], FilterCondition]
|
|
34
27
|
Result: TypeAlias = TokenCount
|
|
35
28
|
ResultPosition: TypeAlias = int
|
|
36
29
|
DEFAULT_VALUE: Result = 0
|
|
37
30
|
|
|
38
31
|
|
|
39
|
-
def _cache_key_fn(key: Key) ->
|
|
32
|
+
def _cache_key_fn(key: Key) -> tuple[Segment, Param]:
|
|
40
33
|
kind, project_rowid, time_range, filter_condition = key
|
|
41
34
|
interval = (
|
|
42
35
|
(time_range.start, time_range.end) if isinstance(time_range, TimeRange) else (None, None)
|
|
@@ -45,7 +38,7 @@ def _cache_key_fn(key: Key) -> Tuple[Segment, Param]:
|
|
|
45
38
|
|
|
46
39
|
|
|
47
40
|
_Section: TypeAlias = ProjectRowId
|
|
48
|
-
_SubKey: TypeAlias =
|
|
41
|
+
_SubKey: TypeAlias = tuple[TimeInterval, FilterCondition, Kind]
|
|
49
42
|
|
|
50
43
|
|
|
51
44
|
class TokenCountCache(
|
|
@@ -60,7 +53,7 @@ class TokenCountCache(
|
|
|
60
53
|
sub_cache_factory=lambda: LFUCache(maxsize=2 * 2 * 3),
|
|
61
54
|
)
|
|
62
55
|
|
|
63
|
-
def _cache_key(self, key: Key) ->
|
|
56
|
+
def _cache_key(self, key: Key) -> tuple[_Section, _SubKey]:
|
|
64
57
|
(interval, filter_condition), (project_rowid, kind) = _cache_key_fn(key)
|
|
65
58
|
return project_rowid, (interval, filter_condition, kind)
|
|
66
59
|
|
|
@@ -78,11 +71,11 @@ class TokenCountDataLoader(DataLoader[Key, Result]):
|
|
|
78
71
|
)
|
|
79
72
|
self._db = db
|
|
80
73
|
|
|
81
|
-
async def _load_fn(self, keys:
|
|
82
|
-
results:
|
|
83
|
-
arguments:
|
|
74
|
+
async def _load_fn(self, keys: list[Key]) -> list[Result]:
|
|
75
|
+
results: list[Result] = [DEFAULT_VALUE] * len(keys)
|
|
76
|
+
arguments: defaultdict[
|
|
84
77
|
Segment,
|
|
85
|
-
|
|
78
|
+
defaultdict[Param, list[ResultPosition]],
|
|
86
79
|
] = defaultdict(lambda: defaultdict(list))
|
|
87
80
|
for position, key in enumerate(keys):
|
|
88
81
|
segment, param = _cache_key_fn(key)
|
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
from typing import
|
|
2
|
-
List,
|
|
3
|
-
Optional,
|
|
4
|
-
Tuple,
|
|
5
|
-
)
|
|
1
|
+
from typing import Optional
|
|
6
2
|
|
|
7
3
|
from sqlalchemy import select
|
|
8
4
|
from strawberry.dataloader import DataLoader
|
|
@@ -15,7 +11,7 @@ TraceId: TypeAlias = str
|
|
|
15
11
|
Key: TypeAlias = TraceId
|
|
16
12
|
TraceRowId: TypeAlias = int
|
|
17
13
|
ProjectRowId: TypeAlias = int
|
|
18
|
-
Result: TypeAlias = Optional[
|
|
14
|
+
Result: TypeAlias = Optional[tuple[TraceRowId, ProjectRowId]]
|
|
19
15
|
|
|
20
16
|
|
|
21
17
|
class TraceRowIdsDataLoader(DataLoader[Key, Result]):
|
|
@@ -23,7 +19,7 @@ class TraceRowIdsDataLoader(DataLoader[Key, Result]):
|
|
|
23
19
|
super().__init__(load_fn=self._load_fn)
|
|
24
20
|
self._db = db
|
|
25
21
|
|
|
26
|
-
async def _load_fn(self, keys:
|
|
22
|
+
async def _load_fn(self, keys: list[Key]) -> list[Result]:
|
|
27
23
|
stmt = select(
|
|
28
24
|
models.Trace.trace_id,
|
|
29
25
|
models.Trace.id,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from collections import defaultdict
|
|
2
|
-
from typing import
|
|
2
|
+
from typing import Optional
|
|
3
3
|
|
|
4
4
|
from sqlalchemy import select
|
|
5
5
|
from strawberry.dataloader import DataLoader
|
|
@@ -20,8 +20,8 @@ class UserRolesDataLoader(DataLoader[Key, Result]):
|
|
|
20
20
|
super().__init__(load_fn=self._load_fn)
|
|
21
21
|
self._db = db
|
|
22
22
|
|
|
23
|
-
async def _load_fn(self, keys:
|
|
24
|
-
user_roles_by_id:
|
|
23
|
+
async def _load_fn(self, keys: list[Key]) -> list[Result]:
|
|
24
|
+
user_roles_by_id: defaultdict[Key, Result] = defaultdict(None)
|
|
25
25
|
async with self._db() as session:
|
|
26
26
|
data = await session.stream_scalars(select(models.UserRole))
|
|
27
27
|
async for user_role in data:
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from collections import defaultdict
|
|
2
|
-
from typing import
|
|
2
|
+
from typing import Optional
|
|
3
3
|
|
|
4
4
|
from sqlalchemy import select
|
|
5
5
|
from strawberry.dataloader import DataLoader
|
|
@@ -20,9 +20,9 @@ class UsersDataLoader(DataLoader[Key, Result]):
|
|
|
20
20
|
super().__init__(load_fn=self._load_fn)
|
|
21
21
|
self._db = db
|
|
22
22
|
|
|
23
|
-
async def _load_fn(self, keys:
|
|
23
|
+
async def _load_fn(self, keys: list[Key]) -> list[Result]:
|
|
24
24
|
user_ids = list(set(keys))
|
|
25
|
-
users_by_id:
|
|
25
|
+
users_by_id: defaultdict[Key, Result] = defaultdict(None)
|
|
26
26
|
async with self._db() as session:
|
|
27
27
|
data = await session.stream_scalars(
|
|
28
28
|
select(models.User).where(models.User.id.in_(user_ids))
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
from
|
|
1
|
+
from collections.abc import Iterable
|
|
2
|
+
from typing import Optional, TypeVar
|
|
2
3
|
|
|
3
4
|
T = TypeVar("T")
|
|
4
5
|
|
|
5
6
|
|
|
6
|
-
def ensure_list(obj: Optional[Iterable[T]]) ->
|
|
7
|
-
if isinstance(obj,
|
|
7
|
+
def ensure_list(obj: Optional[Iterable[T]]) -> list[T]:
|
|
8
|
+
if isinstance(obj, list):
|
|
8
9
|
return obj
|
|
9
10
|
if isinstance(obj, Iterable):
|
|
10
11
|
return list(obj)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import json
|
|
2
|
-
from
|
|
2
|
+
from collections.abc import Mapping
|
|
3
|
+
from typing import Any, Literal, Optional, Protocol
|
|
3
4
|
|
|
4
5
|
from openinference.semconv.trace import (
|
|
5
6
|
MessageAttributes,
|
|
@@ -28,7 +29,7 @@ class HasSpanIO(Protocol):
|
|
|
28
29
|
retrieval_documents: Any
|
|
29
30
|
|
|
30
31
|
|
|
31
|
-
def get_dataset_example_input(span: HasSpanIO) ->
|
|
32
|
+
def get_dataset_example_input(span: HasSpanIO) -> dict[str, Any]:
|
|
32
33
|
"""
|
|
33
34
|
Extracts the input value from a span and returns it as a dictionary. Input
|
|
34
35
|
values from LLM spans are extracted from the input messages and prompt
|
|
@@ -47,7 +48,7 @@ def get_dataset_example_input(span: HasSpanIO) -> Dict[str, Any]:
|
|
|
47
48
|
return _get_generic_io_value(io_value=input_value, mime_type=input_mime_type, kind="input")
|
|
48
49
|
|
|
49
50
|
|
|
50
|
-
def get_dataset_example_output(span: HasSpanIO) ->
|
|
51
|
+
def get_dataset_example_output(span: HasSpanIO) -> dict[str, Any]:
|
|
51
52
|
"""
|
|
52
53
|
Extracts the output value from a span and returns it as a dictionary. Output
|
|
53
54
|
values from LLM spans are extracted from the output messages (if present).
|
|
@@ -78,13 +79,13 @@ def _get_llm_span_input(
|
|
|
78
79
|
input_value: Any,
|
|
79
80
|
input_mime_type: Optional[str],
|
|
80
81
|
prompt_template_variables: Any,
|
|
81
|
-
) ->
|
|
82
|
+
) -> dict[str, Any]:
|
|
82
83
|
"""
|
|
83
84
|
Extracts the input value from an LLM span and returns it as a dictionary.
|
|
84
85
|
The input is extracted from the input messages (if present) and prompt
|
|
85
86
|
template variables (if present).
|
|
86
87
|
"""
|
|
87
|
-
input:
|
|
88
|
+
input: dict[str, Any] = {}
|
|
88
89
|
if messages := [_get_message(m) for m in input_messages or ()]:
|
|
89
90
|
input["messages"] = messages
|
|
90
91
|
if not input:
|
|
@@ -98,7 +99,7 @@ def _get_llm_span_output(
|
|
|
98
99
|
output_messages: Any,
|
|
99
100
|
output_value: Any,
|
|
100
101
|
output_mime_type: Optional[str],
|
|
101
|
-
) ->
|
|
102
|
+
) -> dict[str, Any]:
|
|
102
103
|
"""
|
|
103
104
|
Extracts the output value from an LLM span and returns it as a dictionary.
|
|
104
105
|
The output is extracted from the output messages (if present).
|
|
@@ -112,7 +113,7 @@ def _get_retriever_span_output(
|
|
|
112
113
|
retrieval_documents: Any,
|
|
113
114
|
output_value: Any,
|
|
114
115
|
output_mime_type: Optional[str],
|
|
115
|
-
) ->
|
|
116
|
+
) -> dict[str, Any]:
|
|
116
117
|
"""
|
|
117
118
|
Extracts the output value from a retriever span and returns it as a dictionary.
|
|
118
119
|
The output is extracted from the retrieval documents (if present).
|
|
@@ -124,7 +125,7 @@ def _get_retriever_span_output(
|
|
|
124
125
|
|
|
125
126
|
def _get_generic_io_value(
|
|
126
127
|
io_value: Any, mime_type: Optional[str], kind: Literal["input", "output"]
|
|
127
|
-
) ->
|
|
128
|
+
) -> dict[str, Any]:
|
|
128
129
|
"""
|
|
129
130
|
Makes a best-effort attempt to extract the input or output value from a span
|
|
130
131
|
and returns it as a dictionary.
|
|
@@ -140,7 +141,7 @@ def _get_generic_io_value(
|
|
|
140
141
|
return {}
|
|
141
142
|
|
|
142
143
|
|
|
143
|
-
def _get_message(message: Mapping[str, Any]) ->
|
|
144
|
+
def _get_message(message: Mapping[str, Any]) -> dict[str, Any]:
|
|
144
145
|
content = get_attribute_value(message, MESSAGE_CONTENT)
|
|
145
146
|
name = get_attribute_value(message, MESSAGE_NAME)
|
|
146
147
|
function_call_name = get_attribute_value(message, MESSAGE_FUNCTION_CALL_NAME)
|