arize-phoenix 3.16.1__py3-none-any.whl → 7.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-7.7.0.dist-info/METADATA +261 -0
- arize_phoenix-7.7.0.dist-info/RECORD +345 -0
- {arize_phoenix-3.16.1.dist-info → arize_phoenix-7.7.0.dist-info}/WHEEL +1 -1
- arize_phoenix-7.7.0.dist-info/entry_points.txt +3 -0
- phoenix/__init__.py +86 -14
- phoenix/auth.py +309 -0
- phoenix/config.py +675 -45
- phoenix/core/model.py +32 -30
- phoenix/core/model_schema.py +102 -109
- phoenix/core/model_schema_adapter.py +48 -45
- phoenix/datetime_utils.py +24 -3
- phoenix/db/README.md +54 -0
- phoenix/db/__init__.py +4 -0
- phoenix/db/alembic.ini +85 -0
- phoenix/db/bulk_inserter.py +294 -0
- phoenix/db/engines.py +208 -0
- phoenix/db/enums.py +20 -0
- phoenix/db/facilitator.py +113 -0
- phoenix/db/helpers.py +159 -0
- phoenix/db/insertion/constants.py +2 -0
- phoenix/db/insertion/dataset.py +227 -0
- phoenix/db/insertion/document_annotation.py +171 -0
- phoenix/db/insertion/evaluation.py +191 -0
- phoenix/db/insertion/helpers.py +98 -0
- phoenix/db/insertion/span.py +193 -0
- phoenix/db/insertion/span_annotation.py +158 -0
- phoenix/db/insertion/trace_annotation.py +158 -0
- phoenix/db/insertion/types.py +256 -0
- phoenix/db/migrate.py +86 -0
- phoenix/db/migrations/data_migration_scripts/populate_project_sessions.py +199 -0
- phoenix/db/migrations/env.py +114 -0
- phoenix/db/migrations/script.py.mako +26 -0
- phoenix/db/migrations/versions/10460e46d750_datasets.py +317 -0
- phoenix/db/migrations/versions/3be8647b87d8_add_token_columns_to_spans_table.py +126 -0
- phoenix/db/migrations/versions/4ded9e43755f_create_project_sessions_table.py +66 -0
- phoenix/db/migrations/versions/cd164e83824f_users_and_tokens.py +157 -0
- phoenix/db/migrations/versions/cf03bd6bae1d_init.py +280 -0
- phoenix/db/models.py +807 -0
- phoenix/exceptions.py +5 -1
- phoenix/experiments/__init__.py +6 -0
- phoenix/experiments/evaluators/__init__.py +29 -0
- phoenix/experiments/evaluators/base.py +158 -0
- phoenix/experiments/evaluators/code_evaluators.py +184 -0
- phoenix/experiments/evaluators/llm_evaluators.py +473 -0
- phoenix/experiments/evaluators/utils.py +236 -0
- phoenix/experiments/functions.py +772 -0
- phoenix/experiments/tracing.py +86 -0
- phoenix/experiments/types.py +726 -0
- phoenix/experiments/utils.py +25 -0
- phoenix/inferences/__init__.py +0 -0
- phoenix/{datasets → inferences}/errors.py +6 -5
- phoenix/{datasets → inferences}/fixtures.py +49 -42
- phoenix/{datasets/dataset.py → inferences/inferences.py} +121 -105
- phoenix/{datasets → inferences}/schema.py +11 -11
- phoenix/{datasets → inferences}/validation.py +13 -14
- phoenix/logging/__init__.py +3 -0
- phoenix/logging/_config.py +90 -0
- phoenix/logging/_filter.py +6 -0
- phoenix/logging/_formatter.py +69 -0
- phoenix/metrics/__init__.py +5 -4
- phoenix/metrics/binning.py +4 -3
- 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 +9 -3
- phoenix/pointcloud/clustering.py +5 -5
- phoenix/pointcloud/pointcloud.py +7 -5
- phoenix/pointcloud/projectors.py +5 -6
- phoenix/pointcloud/umap_parameters.py +53 -52
- phoenix/server/api/README.md +28 -0
- phoenix/server/api/auth.py +44 -0
- phoenix/server/api/context.py +152 -9
- phoenix/server/api/dataloaders/__init__.py +91 -0
- phoenix/server/api/dataloaders/annotation_summaries.py +139 -0
- phoenix/server/api/dataloaders/average_experiment_run_latency.py +54 -0
- phoenix/server/api/dataloaders/cache/__init__.py +3 -0
- phoenix/server/api/dataloaders/cache/two_tier_cache.py +68 -0
- phoenix/server/api/dataloaders/dataset_example_revisions.py +131 -0
- phoenix/server/api/dataloaders/dataset_example_spans.py +38 -0
- phoenix/server/api/dataloaders/document_evaluation_summaries.py +144 -0
- phoenix/server/api/dataloaders/document_evaluations.py +31 -0
- phoenix/server/api/dataloaders/document_retrieval_metrics.py +89 -0
- phoenix/server/api/dataloaders/experiment_annotation_summaries.py +79 -0
- phoenix/server/api/dataloaders/experiment_error_rates.py +58 -0
- phoenix/server/api/dataloaders/experiment_run_annotations.py +36 -0
- phoenix/server/api/dataloaders/experiment_run_counts.py +49 -0
- phoenix/server/api/dataloaders/experiment_sequence_number.py +44 -0
- phoenix/server/api/dataloaders/latency_ms_quantile.py +188 -0
- phoenix/server/api/dataloaders/min_start_or_max_end_times.py +85 -0
- phoenix/server/api/dataloaders/project_by_name.py +31 -0
- phoenix/server/api/dataloaders/record_counts.py +116 -0
- phoenix/server/api/dataloaders/session_io.py +79 -0
- phoenix/server/api/dataloaders/session_num_traces.py +30 -0
- phoenix/server/api/dataloaders/session_num_traces_with_error.py +32 -0
- phoenix/server/api/dataloaders/session_token_usages.py +41 -0
- phoenix/server/api/dataloaders/session_trace_latency_ms_quantile.py +55 -0
- phoenix/server/api/dataloaders/span_annotations.py +26 -0
- phoenix/server/api/dataloaders/span_dataset_examples.py +31 -0
- phoenix/server/api/dataloaders/span_descendants.py +57 -0
- phoenix/server/api/dataloaders/span_projects.py +33 -0
- phoenix/server/api/dataloaders/token_counts.py +124 -0
- phoenix/server/api/dataloaders/trace_by_trace_ids.py +25 -0
- phoenix/server/api/dataloaders/trace_root_spans.py +32 -0
- phoenix/server/api/dataloaders/user_roles.py +30 -0
- phoenix/server/api/dataloaders/users.py +33 -0
- phoenix/server/api/exceptions.py +48 -0
- phoenix/server/api/helpers/__init__.py +12 -0
- phoenix/server/api/helpers/dataset_helpers.py +217 -0
- phoenix/server/api/helpers/experiment_run_filters.py +763 -0
- phoenix/server/api/helpers/playground_clients.py +948 -0
- phoenix/server/api/helpers/playground_registry.py +70 -0
- phoenix/server/api/helpers/playground_spans.py +455 -0
- phoenix/server/api/input_types/AddExamplesToDatasetInput.py +16 -0
- phoenix/server/api/input_types/AddSpansToDatasetInput.py +14 -0
- phoenix/server/api/input_types/ChatCompletionInput.py +38 -0
- phoenix/server/api/input_types/ChatCompletionMessageInput.py +24 -0
- phoenix/server/api/input_types/ClearProjectInput.py +15 -0
- phoenix/server/api/input_types/ClusterInput.py +2 -2
- phoenix/server/api/input_types/CreateDatasetInput.py +12 -0
- phoenix/server/api/input_types/CreateSpanAnnotationInput.py +18 -0
- phoenix/server/api/input_types/CreateTraceAnnotationInput.py +18 -0
- phoenix/server/api/input_types/DataQualityMetricInput.py +5 -2
- phoenix/server/api/input_types/DatasetExampleInput.py +14 -0
- phoenix/server/api/input_types/DatasetSort.py +17 -0
- phoenix/server/api/input_types/DatasetVersionSort.py +16 -0
- phoenix/server/api/input_types/DeleteAnnotationsInput.py +7 -0
- phoenix/server/api/input_types/DeleteDatasetExamplesInput.py +13 -0
- phoenix/server/api/input_types/DeleteDatasetInput.py +7 -0
- phoenix/server/api/input_types/DeleteExperimentsInput.py +7 -0
- 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 +162 -0
- phoenix/server/api/input_types/PatchAnnotationInput.py +19 -0
- phoenix/server/api/input_types/PatchDatasetExamplesInput.py +35 -0
- phoenix/server/api/input_types/PatchDatasetInput.py +14 -0
- phoenix/server/api/input_types/PerformanceMetricInput.py +5 -2
- phoenix/server/api/input_types/ProjectSessionSort.py +29 -0
- phoenix/server/api/input_types/SpanAnnotationSort.py +17 -0
- phoenix/server/api/input_types/SpanSort.py +134 -69
- phoenix/server/api/input_types/TemplateOptions.py +10 -0
- phoenix/server/api/input_types/TraceAnnotationSort.py +17 -0
- phoenix/server/api/input_types/UserRoleInput.py +9 -0
- phoenix/server/api/mutations/__init__.py +28 -0
- phoenix/server/api/mutations/api_key_mutations.py +167 -0
- phoenix/server/api/mutations/chat_mutations.py +593 -0
- phoenix/server/api/mutations/dataset_mutations.py +591 -0
- phoenix/server/api/mutations/experiment_mutations.py +75 -0
- phoenix/server/api/{types/ExportEventsMutation.py → mutations/export_events_mutations.py} +21 -18
- phoenix/server/api/mutations/project_mutations.py +57 -0
- phoenix/server/api/mutations/span_annotations_mutations.py +128 -0
- phoenix/server/api/mutations/trace_annotations_mutations.py +127 -0
- phoenix/server/api/mutations/user_mutations.py +329 -0
- phoenix/server/api/openapi/__init__.py +0 -0
- phoenix/server/api/openapi/main.py +17 -0
- phoenix/server/api/openapi/schema.py +16 -0
- phoenix/server/api/queries.py +738 -0
- phoenix/server/api/routers/__init__.py +11 -0
- phoenix/server/api/routers/auth.py +284 -0
- phoenix/server/api/routers/embeddings.py +26 -0
- phoenix/server/api/routers/oauth2.py +488 -0
- phoenix/server/api/routers/v1/__init__.py +64 -0
- phoenix/server/api/routers/v1/datasets.py +1017 -0
- phoenix/server/api/routers/v1/evaluations.py +362 -0
- phoenix/server/api/routers/v1/experiment_evaluations.py +115 -0
- phoenix/server/api/routers/v1/experiment_runs.py +167 -0
- phoenix/server/api/routers/v1/experiments.py +308 -0
- phoenix/server/api/routers/v1/pydantic_compat.py +78 -0
- phoenix/server/api/routers/v1/spans.py +267 -0
- phoenix/server/api/routers/v1/traces.py +208 -0
- phoenix/server/api/routers/v1/utils.py +95 -0
- phoenix/server/api/schema.py +44 -241
- phoenix/server/api/subscriptions.py +597 -0
- phoenix/server/api/types/Annotation.py +21 -0
- phoenix/server/api/types/AnnotationSummary.py +55 -0
- phoenix/server/api/types/AnnotatorKind.py +16 -0
- phoenix/server/api/types/ApiKey.py +27 -0
- phoenix/server/api/types/AuthMethod.py +9 -0
- phoenix/server/api/types/ChatCompletionMessageRole.py +11 -0
- phoenix/server/api/types/ChatCompletionSubscriptionPayload.py +46 -0
- phoenix/server/api/types/Cluster.py +25 -24
- phoenix/server/api/types/CreateDatasetPayload.py +8 -0
- phoenix/server/api/types/DataQualityMetric.py +31 -13
- phoenix/server/api/types/Dataset.py +288 -63
- phoenix/server/api/types/DatasetExample.py +85 -0
- phoenix/server/api/types/DatasetExampleRevision.py +34 -0
- phoenix/server/api/types/DatasetVersion.py +14 -0
- phoenix/server/api/types/Dimension.py +32 -31
- phoenix/server/api/types/DocumentEvaluationSummary.py +9 -8
- phoenix/server/api/types/EmbeddingDimension.py +56 -49
- phoenix/server/api/types/Evaluation.py +25 -31
- phoenix/server/api/types/EvaluationSummary.py +30 -50
- phoenix/server/api/types/Event.py +20 -20
- phoenix/server/api/types/ExampleRevisionInterface.py +14 -0
- phoenix/server/api/types/Experiment.py +152 -0
- phoenix/server/api/types/ExperimentAnnotationSummary.py +13 -0
- phoenix/server/api/types/ExperimentComparison.py +17 -0
- phoenix/server/api/types/ExperimentRun.py +119 -0
- phoenix/server/api/types/ExperimentRunAnnotation.py +56 -0
- phoenix/server/api/types/GenerativeModel.py +9 -0
- phoenix/server/api/types/GenerativeProvider.py +85 -0
- phoenix/server/api/types/Inferences.py +80 -0
- phoenix/server/api/types/InferencesRole.py +23 -0
- phoenix/server/api/types/LabelFraction.py +7 -0
- phoenix/server/api/types/MimeType.py +2 -2
- phoenix/server/api/types/Model.py +54 -54
- phoenix/server/api/types/PerformanceMetric.py +8 -5
- phoenix/server/api/types/Project.py +407 -142
- phoenix/server/api/types/ProjectSession.py +139 -0
- phoenix/server/api/types/Segments.py +4 -4
- phoenix/server/api/types/Span.py +221 -176
- phoenix/server/api/types/SpanAnnotation.py +43 -0
- phoenix/server/api/types/SpanIOValue.py +15 -0
- phoenix/server/api/types/SystemApiKey.py +9 -0
- phoenix/server/api/types/TemplateLanguage.py +10 -0
- phoenix/server/api/types/TimeSeries.py +19 -15
- phoenix/server/api/types/TokenUsage.py +11 -0
- phoenix/server/api/types/Trace.py +154 -0
- phoenix/server/api/types/TraceAnnotation.py +45 -0
- phoenix/server/api/types/UMAPPoints.py +7 -7
- phoenix/server/api/types/User.py +60 -0
- phoenix/server/api/types/UserApiKey.py +45 -0
- phoenix/server/api/types/UserRole.py +15 -0
- phoenix/server/api/types/node.py +4 -112
- phoenix/server/api/types/pagination.py +156 -57
- phoenix/server/api/utils.py +34 -0
- phoenix/server/app.py +864 -115
- phoenix/server/bearer_auth.py +163 -0
- phoenix/server/dml_event.py +136 -0
- phoenix/server/dml_event_handler.py +256 -0
- phoenix/server/email/__init__.py +0 -0
- phoenix/server/email/sender.py +97 -0
- phoenix/server/email/templates/__init__.py +0 -0
- phoenix/server/email/templates/password_reset.html +19 -0
- phoenix/server/email/types.py +11 -0
- phoenix/server/grpc_server.py +102 -0
- phoenix/server/jwt_store.py +505 -0
- phoenix/server/main.py +305 -116
- phoenix/server/oauth2.py +52 -0
- phoenix/server/openapi/__init__.py +0 -0
- phoenix/server/prometheus.py +111 -0
- phoenix/server/rate_limiters.py +188 -0
- phoenix/server/static/.vite/manifest.json +87 -0
- phoenix/server/static/assets/components-Cy9nwIvF.js +2125 -0
- phoenix/server/static/assets/index-BKvHIxkk.js +113 -0
- phoenix/server/static/assets/pages-CUi2xCVQ.js +4449 -0
- phoenix/server/static/assets/vendor-DvC8cT4X.js +894 -0
- phoenix/server/static/assets/vendor-DxkFTwjz.css +1 -0
- phoenix/server/static/assets/vendor-arizeai-Do1793cv.js +662 -0
- phoenix/server/static/assets/vendor-codemirror-BzwZPyJM.js +24 -0
- phoenix/server/static/assets/vendor-recharts-_Jb7JjhG.js +59 -0
- phoenix/server/static/assets/vendor-shiki-Cl9QBraO.js +5 -0
- phoenix/server/static/assets/vendor-three-DwGkEfCM.js +2998 -0
- phoenix/server/telemetry.py +68 -0
- phoenix/server/templates/index.html +82 -23
- phoenix/server/thread_server.py +3 -3
- phoenix/server/types.py +275 -0
- phoenix/services.py +27 -18
- phoenix/session/client.py +743 -68
- phoenix/session/data_extractor.py +31 -7
- phoenix/session/evaluation.py +3 -9
- phoenix/session/session.py +263 -219
- phoenix/settings.py +22 -0
- phoenix/trace/__init__.py +2 -22
- phoenix/trace/attributes.py +338 -0
- phoenix/trace/dsl/README.md +116 -0
- phoenix/trace/dsl/filter.py +663 -213
- phoenix/trace/dsl/helpers.py +73 -21
- phoenix/trace/dsl/query.py +574 -201
- phoenix/trace/exporter.py +24 -19
- phoenix/trace/fixtures.py +368 -32
- phoenix/trace/otel.py +71 -219
- phoenix/trace/projects.py +3 -2
- phoenix/trace/schemas.py +33 -11
- phoenix/trace/span_evaluations.py +21 -16
- phoenix/trace/span_json_decoder.py +6 -4
- phoenix/trace/span_json_encoder.py +2 -2
- phoenix/trace/trace_dataset.py +47 -32
- phoenix/trace/utils.py +21 -4
- phoenix/utilities/__init__.py +0 -26
- phoenix/utilities/client.py +132 -0
- phoenix/utilities/deprecation.py +31 -0
- phoenix/utilities/error_handling.py +3 -2
- phoenix/utilities/json.py +109 -0
- phoenix/utilities/logging.py +8 -0
- phoenix/utilities/project.py +2 -2
- phoenix/utilities/re.py +49 -0
- phoenix/utilities/span_store.py +0 -23
- phoenix/utilities/template_formatters.py +99 -0
- phoenix/version.py +1 -1
- arize_phoenix-3.16.1.dist-info/METADATA +0 -495
- arize_phoenix-3.16.1.dist-info/RECORD +0 -178
- phoenix/core/project.py +0 -619
- phoenix/core/traces.py +0 -96
- phoenix/experimental/evals/__init__.py +0 -73
- phoenix/experimental/evals/evaluators.py +0 -413
- phoenix/experimental/evals/functions/__init__.py +0 -4
- phoenix/experimental/evals/functions/classify.py +0 -453
- phoenix/experimental/evals/functions/executor.py +0 -353
- phoenix/experimental/evals/functions/generate.py +0 -138
- phoenix/experimental/evals/functions/processing.py +0 -76
- phoenix/experimental/evals/models/__init__.py +0 -14
- phoenix/experimental/evals/models/anthropic.py +0 -175
- phoenix/experimental/evals/models/base.py +0 -170
- phoenix/experimental/evals/models/bedrock.py +0 -221
- phoenix/experimental/evals/models/litellm.py +0 -134
- phoenix/experimental/evals/models/openai.py +0 -448
- phoenix/experimental/evals/models/rate_limiters.py +0 -246
- phoenix/experimental/evals/models/vertex.py +0 -173
- phoenix/experimental/evals/models/vertexai.py +0 -186
- phoenix/experimental/evals/retrievals.py +0 -96
- phoenix/experimental/evals/templates/__init__.py +0 -50
- phoenix/experimental/evals/templates/default_templates.py +0 -472
- phoenix/experimental/evals/templates/template.py +0 -195
- phoenix/experimental/evals/utils/__init__.py +0 -172
- phoenix/experimental/evals/utils/threads.py +0 -27
- phoenix/server/api/helpers.py +0 -11
- phoenix/server/api/routers/evaluation_handler.py +0 -109
- phoenix/server/api/routers/span_handler.py +0 -70
- phoenix/server/api/routers/trace_handler.py +0 -60
- phoenix/server/api/types/DatasetRole.py +0 -23
- phoenix/server/static/index.css +0 -6
- phoenix/server/static/index.js +0 -7447
- phoenix/storage/span_store/__init__.py +0 -23
- phoenix/storage/span_store/text_file.py +0 -85
- phoenix/trace/dsl/missing.py +0 -60
- phoenix/trace/langchain/__init__.py +0 -3
- phoenix/trace/langchain/instrumentor.py +0 -35
- phoenix/trace/llama_index/__init__.py +0 -3
- phoenix/trace/llama_index/callback.py +0 -102
- phoenix/trace/openai/__init__.py +0 -3
- phoenix/trace/openai/instrumentor.py +0 -30
- {arize_phoenix-3.16.1.dist-info → arize_phoenix-7.7.0.dist-info}/licenses/IP_NOTICE +0 -0
- {arize_phoenix-3.16.1.dist-info → arize_phoenix-7.7.0.dist-info}/licenses/LICENSE +0 -0
- /phoenix/{datasets → db/insertion}/__init__.py +0 -0
- /phoenix/{experimental → db/migrations}/__init__.py +0 -0
- /phoenix/{storage → db/migrations/data_migration_scripts}/__init__.py +0 -0
|
@@ -1,23 +1,25 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
from collections import defaultdict
|
|
3
3
|
from datetime import datetime
|
|
4
|
-
from typing import
|
|
4
|
+
from typing import Optional
|
|
5
5
|
|
|
6
6
|
import strawberry
|
|
7
7
|
from strawberry import ID, UNSET
|
|
8
8
|
from strawberry.types import Info
|
|
9
9
|
|
|
10
10
|
import phoenix.core.model_schema as ms
|
|
11
|
+
from phoenix.server.api.auth import IsNotReadOnly
|
|
11
12
|
from phoenix.server.api.context import Context
|
|
12
13
|
from phoenix.server.api.input_types.ClusterInput import ClusterInput
|
|
13
|
-
from phoenix.server.api.types.
|
|
14
|
-
from phoenix.server.api.types.Event import parse_event_ids_by_dataset_role, unpack_event_id
|
|
14
|
+
from phoenix.server.api.types.Event import parse_event_ids_by_inferences_role, unpack_event_id
|
|
15
15
|
from phoenix.server.api.types.ExportedFile import ExportedFile
|
|
16
|
+
from phoenix.server.api.types.InferencesRole import AncillaryInferencesRole, InferencesRole
|
|
16
17
|
|
|
17
18
|
|
|
18
19
|
@strawberry.type
|
|
19
|
-
class
|
|
20
|
+
class ExportEventsMutationMixin:
|
|
20
21
|
@strawberry.mutation(
|
|
22
|
+
permission_classes=[IsNotReadOnly],
|
|
21
23
|
description=(
|
|
22
24
|
"Given a list of event ids, export the corresponding data subset in Parquet format."
|
|
23
25
|
" File name is optional, but if specified, should be without file extension. By default"
|
|
@@ -27,16 +29,16 @@ class ExportEventsMutation:
|
|
|
27
29
|
async def export_events(
|
|
28
30
|
self,
|
|
29
31
|
info: Info[Context, None],
|
|
30
|
-
event_ids:
|
|
32
|
+
event_ids: list[ID],
|
|
31
33
|
file_name: Optional[str] = UNSET,
|
|
32
34
|
) -> ExportedFile:
|
|
33
35
|
if not isinstance(file_name, str):
|
|
34
36
|
file_name = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
|
|
35
|
-
row_ids =
|
|
37
|
+
row_ids = parse_event_ids_by_inferences_role(event_ids)
|
|
36
38
|
exclude_corpus_row_ids = {}
|
|
37
|
-
for
|
|
38
|
-
if isinstance(
|
|
39
|
-
exclude_corpus_row_ids[
|
|
39
|
+
for inferences_role in list(row_ids.keys()):
|
|
40
|
+
if isinstance(inferences_role, InferencesRole):
|
|
41
|
+
exclude_corpus_row_ids[inferences_role.value] = row_ids[inferences_role]
|
|
40
42
|
path = info.context.export_path
|
|
41
43
|
with open(path / (file_name + ".parquet"), "wb") as fd:
|
|
42
44
|
loop = asyncio.get_running_loop()
|
|
@@ -49,6 +51,7 @@ class ExportEventsMutation:
|
|
|
49
51
|
return ExportedFile(file_name=file_name)
|
|
50
52
|
|
|
51
53
|
@strawberry.mutation(
|
|
54
|
+
permission_classes=[IsNotReadOnly],
|
|
52
55
|
description=(
|
|
53
56
|
"Given a list of clusters, export the corresponding data subset in Parquet format."
|
|
54
57
|
" File name is optional, but if specified, should be without file extension. By default"
|
|
@@ -58,7 +61,7 @@ class ExportEventsMutation:
|
|
|
58
61
|
async def export_clusters(
|
|
59
62
|
self,
|
|
60
63
|
info: Info[Context, None],
|
|
61
|
-
clusters:
|
|
64
|
+
clusters: list[ClusterInput],
|
|
62
65
|
file_name: Optional[str] = UNSET,
|
|
63
66
|
) -> ExportedFile:
|
|
64
67
|
if not isinstance(file_name, str):
|
|
@@ -78,14 +81,14 @@ class ExportEventsMutation:
|
|
|
78
81
|
|
|
79
82
|
|
|
80
83
|
def _unpack_clusters(
|
|
81
|
-
clusters:
|
|
82
|
-
) ->
|
|
83
|
-
row_numbers:
|
|
84
|
-
cluster_ids:
|
|
84
|
+
clusters: list[ClusterInput],
|
|
85
|
+
) -> tuple[dict[ms.InferencesRole, list[int]], dict[ms.InferencesRole, dict[int, str]]]:
|
|
86
|
+
row_numbers: dict[ms.InferencesRole, list[int]] = defaultdict(list)
|
|
87
|
+
cluster_ids: dict[ms.InferencesRole, dict[int, str]] = defaultdict(dict)
|
|
85
88
|
for i, cluster in enumerate(clusters):
|
|
86
|
-
for row_number,
|
|
87
|
-
if isinstance(
|
|
89
|
+
for row_number, inferences_role in map(unpack_event_id, cluster.event_ids):
|
|
90
|
+
if isinstance(inferences_role, AncillaryInferencesRole):
|
|
88
91
|
continue
|
|
89
|
-
row_numbers[
|
|
90
|
-
cluster_ids[
|
|
92
|
+
row_numbers[inferences_role.value].append(row_number)
|
|
93
|
+
cluster_ids[inferences_role.value][row_number] = cluster.id or str(i)
|
|
91
94
|
return row_numbers, cluster_ids
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import strawberry
|
|
2
|
+
from sqlalchemy import delete, select
|
|
3
|
+
from sqlalchemy.orm import load_only
|
|
4
|
+
from strawberry.relay import GlobalID
|
|
5
|
+
from strawberry.types import Info
|
|
6
|
+
|
|
7
|
+
from phoenix.config import DEFAULT_PROJECT_NAME
|
|
8
|
+
from phoenix.db import models
|
|
9
|
+
from phoenix.server.api.auth import IsNotReadOnly
|
|
10
|
+
from phoenix.server.api.context import Context
|
|
11
|
+
from phoenix.server.api.input_types.ClearProjectInput import ClearProjectInput
|
|
12
|
+
from phoenix.server.api.queries import Query
|
|
13
|
+
from phoenix.server.api.types.node import from_global_id_with_expected_type
|
|
14
|
+
from phoenix.server.dml_event import ProjectDeleteEvent, SpanDeleteEvent
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@strawberry.type
|
|
18
|
+
class ProjectMutationMixin:
|
|
19
|
+
@strawberry.mutation(permission_classes=[IsNotReadOnly]) # type: ignore
|
|
20
|
+
async def delete_project(self, info: Info[Context, None], id: GlobalID) -> Query:
|
|
21
|
+
project_id = from_global_id_with_expected_type(global_id=id, expected_type_name="Project")
|
|
22
|
+
async with info.context.db() as session:
|
|
23
|
+
project = await session.scalar(
|
|
24
|
+
select(models.Project)
|
|
25
|
+
.where(models.Project.id == project_id)
|
|
26
|
+
.options(load_only(models.Project.name))
|
|
27
|
+
)
|
|
28
|
+
if project is None:
|
|
29
|
+
raise ValueError(f"Unknown project: {id}")
|
|
30
|
+
if project.name == DEFAULT_PROJECT_NAME:
|
|
31
|
+
raise ValueError(f"Cannot delete the {DEFAULT_PROJECT_NAME} project")
|
|
32
|
+
await session.delete(project)
|
|
33
|
+
info.context.event_queue.put(ProjectDeleteEvent((project_id,)))
|
|
34
|
+
return Query()
|
|
35
|
+
|
|
36
|
+
@strawberry.mutation(permission_classes=[IsNotReadOnly]) # type: ignore
|
|
37
|
+
async def clear_project(self, info: Info[Context, None], input: ClearProjectInput) -> Query:
|
|
38
|
+
project_id = from_global_id_with_expected_type(
|
|
39
|
+
global_id=input.id, expected_type_name="Project"
|
|
40
|
+
)
|
|
41
|
+
delete_statement = (
|
|
42
|
+
delete(models.Trace)
|
|
43
|
+
.where(models.Trace.project_rowid == project_id)
|
|
44
|
+
.returning(models.Trace.project_session_rowid)
|
|
45
|
+
)
|
|
46
|
+
if input.end_time:
|
|
47
|
+
delete_statement = delete_statement.where(models.Trace.start_time < input.end_time)
|
|
48
|
+
async with info.context.db() as session:
|
|
49
|
+
deleted_trace_project_session_ids = await session.scalars(delete_statement)
|
|
50
|
+
if deleted_trace_project_session_ids:
|
|
51
|
+
await session.execute(
|
|
52
|
+
delete(models.ProjectSession).where(
|
|
53
|
+
models.ProjectSession.id.in_(set(deleted_trace_project_session_ids))
|
|
54
|
+
)
|
|
55
|
+
)
|
|
56
|
+
info.context.event_queue.put(SpanDeleteEvent((project_id,)))
|
|
57
|
+
return Query()
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
from collections.abc import Sequence
|
|
2
|
+
|
|
3
|
+
import strawberry
|
|
4
|
+
from sqlalchemy import delete, insert, update
|
|
5
|
+
from strawberry import UNSET
|
|
6
|
+
from strawberry.types import Info
|
|
7
|
+
|
|
8
|
+
from phoenix.db import models
|
|
9
|
+
from phoenix.server.api.auth import IsLocked, IsNotReadOnly
|
|
10
|
+
from phoenix.server.api.context import Context
|
|
11
|
+
from phoenix.server.api.input_types.CreateSpanAnnotationInput import CreateSpanAnnotationInput
|
|
12
|
+
from phoenix.server.api.input_types.DeleteAnnotationsInput import DeleteAnnotationsInput
|
|
13
|
+
from phoenix.server.api.input_types.PatchAnnotationInput import PatchAnnotationInput
|
|
14
|
+
from phoenix.server.api.queries import Query
|
|
15
|
+
from phoenix.server.api.types.node import from_global_id_with_expected_type
|
|
16
|
+
from phoenix.server.api.types.SpanAnnotation import SpanAnnotation, to_gql_span_annotation
|
|
17
|
+
from phoenix.server.dml_event import SpanAnnotationDeleteEvent, SpanAnnotationInsertEvent
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@strawberry.type
|
|
21
|
+
class SpanAnnotationMutationPayload:
|
|
22
|
+
span_annotations: list[SpanAnnotation]
|
|
23
|
+
query: Query
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@strawberry.type
|
|
27
|
+
class SpanAnnotationMutationMixin:
|
|
28
|
+
@strawberry.mutation(permission_classes=[IsNotReadOnly, IsLocked]) # type: ignore
|
|
29
|
+
async def create_span_annotations(
|
|
30
|
+
self, info: Info[Context, None], input: list[CreateSpanAnnotationInput]
|
|
31
|
+
) -> SpanAnnotationMutationPayload:
|
|
32
|
+
inserted_annotations: Sequence[models.SpanAnnotation] = []
|
|
33
|
+
async with info.context.db() as session:
|
|
34
|
+
values_list = [
|
|
35
|
+
dict(
|
|
36
|
+
span_rowid=from_global_id_with_expected_type(annotation.span_id, "Span"),
|
|
37
|
+
name=annotation.name,
|
|
38
|
+
label=annotation.label,
|
|
39
|
+
score=annotation.score,
|
|
40
|
+
explanation=annotation.explanation,
|
|
41
|
+
annotator_kind=annotation.annotator_kind.value,
|
|
42
|
+
metadata_=annotation.metadata,
|
|
43
|
+
)
|
|
44
|
+
for annotation in input
|
|
45
|
+
]
|
|
46
|
+
stmt = (
|
|
47
|
+
insert(models.SpanAnnotation).values(values_list).returning(models.SpanAnnotation)
|
|
48
|
+
)
|
|
49
|
+
result = await session.scalars(stmt)
|
|
50
|
+
inserted_annotations = result.all()
|
|
51
|
+
if inserted_annotations:
|
|
52
|
+
info.context.event_queue.put(
|
|
53
|
+
SpanAnnotationInsertEvent(tuple(anno.id for anno in inserted_annotations))
|
|
54
|
+
)
|
|
55
|
+
return SpanAnnotationMutationPayload(
|
|
56
|
+
span_annotations=[
|
|
57
|
+
to_gql_span_annotation(annotation) for annotation in inserted_annotations
|
|
58
|
+
],
|
|
59
|
+
query=Query(),
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
@strawberry.mutation(permission_classes=[IsNotReadOnly, IsLocked]) # type: ignore
|
|
63
|
+
async def patch_span_annotations(
|
|
64
|
+
self, info: Info[Context, None], input: list[PatchAnnotationInput]
|
|
65
|
+
) -> SpanAnnotationMutationPayload:
|
|
66
|
+
patched_annotations = []
|
|
67
|
+
async with info.context.db() as session:
|
|
68
|
+
for annotation in input:
|
|
69
|
+
span_annotation_id = from_global_id_with_expected_type(
|
|
70
|
+
annotation.annotation_id, "SpanAnnotation"
|
|
71
|
+
)
|
|
72
|
+
patch = {
|
|
73
|
+
column.key: patch_value
|
|
74
|
+
for column, patch_value, column_is_nullable in (
|
|
75
|
+
(models.SpanAnnotation.name, annotation.name, False),
|
|
76
|
+
(
|
|
77
|
+
models.SpanAnnotation.annotator_kind,
|
|
78
|
+
annotation.annotator_kind.value
|
|
79
|
+
if annotation.annotator_kind is not None
|
|
80
|
+
and annotation.annotator_kind is not UNSET
|
|
81
|
+
else None,
|
|
82
|
+
False,
|
|
83
|
+
),
|
|
84
|
+
(models.SpanAnnotation.label, annotation.label, True),
|
|
85
|
+
(models.SpanAnnotation.score, annotation.score, True),
|
|
86
|
+
(models.SpanAnnotation.explanation, annotation.explanation, True),
|
|
87
|
+
(models.SpanAnnotation.metadata_, annotation.metadata, False),
|
|
88
|
+
)
|
|
89
|
+
if patch_value is not UNSET and (patch_value is not None or column_is_nullable)
|
|
90
|
+
}
|
|
91
|
+
span_annotation = await session.scalar(
|
|
92
|
+
update(models.SpanAnnotation)
|
|
93
|
+
.where(models.SpanAnnotation.id == span_annotation_id)
|
|
94
|
+
.values(**patch)
|
|
95
|
+
.returning(models.SpanAnnotation)
|
|
96
|
+
)
|
|
97
|
+
if span_annotation is not None:
|
|
98
|
+
patched_annotations.append(to_gql_span_annotation(span_annotation))
|
|
99
|
+
info.context.event_queue.put(SpanAnnotationInsertEvent((span_annotation.id,)))
|
|
100
|
+
return SpanAnnotationMutationPayload(span_annotations=patched_annotations, query=Query())
|
|
101
|
+
|
|
102
|
+
@strawberry.mutation(permission_classes=[IsNotReadOnly]) # type: ignore
|
|
103
|
+
async def delete_span_annotations(
|
|
104
|
+
self, info: Info[Context, None], input: DeleteAnnotationsInput
|
|
105
|
+
) -> SpanAnnotationMutationPayload:
|
|
106
|
+
span_annotation_ids = [
|
|
107
|
+
from_global_id_with_expected_type(global_id, "SpanAnnotation")
|
|
108
|
+
for global_id in input.annotation_ids
|
|
109
|
+
]
|
|
110
|
+
async with info.context.db() as session:
|
|
111
|
+
stmt = (
|
|
112
|
+
delete(models.SpanAnnotation)
|
|
113
|
+
.where(models.SpanAnnotation.id.in_(span_annotation_ids))
|
|
114
|
+
.returning(models.SpanAnnotation)
|
|
115
|
+
)
|
|
116
|
+
result = await session.scalars(stmt)
|
|
117
|
+
deleted_annotations = result.all()
|
|
118
|
+
|
|
119
|
+
deleted_annotations_gql = [
|
|
120
|
+
to_gql_span_annotation(annotation) for annotation in deleted_annotations
|
|
121
|
+
]
|
|
122
|
+
if deleted_annotations:
|
|
123
|
+
info.context.event_queue.put(
|
|
124
|
+
SpanAnnotationDeleteEvent(tuple(anno.id for anno in deleted_annotations))
|
|
125
|
+
)
|
|
126
|
+
return SpanAnnotationMutationPayload(
|
|
127
|
+
span_annotations=deleted_annotations_gql, query=Query()
|
|
128
|
+
)
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
from collections.abc import Sequence
|
|
2
|
+
|
|
3
|
+
import strawberry
|
|
4
|
+
from sqlalchemy import delete, insert, update
|
|
5
|
+
from strawberry import UNSET
|
|
6
|
+
from strawberry.types import Info
|
|
7
|
+
|
|
8
|
+
from phoenix.db import models
|
|
9
|
+
from phoenix.server.api.auth import IsLocked, IsNotReadOnly
|
|
10
|
+
from phoenix.server.api.context import Context
|
|
11
|
+
from phoenix.server.api.input_types.CreateTraceAnnotationInput import CreateTraceAnnotationInput
|
|
12
|
+
from phoenix.server.api.input_types.DeleteAnnotationsInput import DeleteAnnotationsInput
|
|
13
|
+
from phoenix.server.api.input_types.PatchAnnotationInput import PatchAnnotationInput
|
|
14
|
+
from phoenix.server.api.queries import Query
|
|
15
|
+
from phoenix.server.api.types.node import from_global_id_with_expected_type
|
|
16
|
+
from phoenix.server.api.types.TraceAnnotation import TraceAnnotation, to_gql_trace_annotation
|
|
17
|
+
from phoenix.server.dml_event import TraceAnnotationDeleteEvent, TraceAnnotationInsertEvent
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@strawberry.type
|
|
21
|
+
class TraceAnnotationMutationPayload:
|
|
22
|
+
trace_annotations: list[TraceAnnotation]
|
|
23
|
+
query: Query
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@strawberry.type
|
|
27
|
+
class TraceAnnotationMutationMixin:
|
|
28
|
+
@strawberry.mutation(permission_classes=[IsNotReadOnly, IsLocked]) # type: ignore
|
|
29
|
+
async def create_trace_annotations(
|
|
30
|
+
self, info: Info[Context, None], input: list[CreateTraceAnnotationInput]
|
|
31
|
+
) -> TraceAnnotationMutationPayload:
|
|
32
|
+
inserted_annotations: Sequence[models.TraceAnnotation] = []
|
|
33
|
+
async with info.context.db() as session:
|
|
34
|
+
values_list = [
|
|
35
|
+
dict(
|
|
36
|
+
trace_rowid=from_global_id_with_expected_type(annotation.trace_id, "Trace"),
|
|
37
|
+
name=annotation.name,
|
|
38
|
+
label=annotation.label,
|
|
39
|
+
score=annotation.score,
|
|
40
|
+
explanation=annotation.explanation,
|
|
41
|
+
annotator_kind=annotation.annotator_kind.value,
|
|
42
|
+
metadata_=annotation.metadata,
|
|
43
|
+
)
|
|
44
|
+
for annotation in input
|
|
45
|
+
]
|
|
46
|
+
stmt = (
|
|
47
|
+
insert(models.TraceAnnotation).values(values_list).returning(models.TraceAnnotation)
|
|
48
|
+
)
|
|
49
|
+
result = await session.scalars(stmt)
|
|
50
|
+
inserted_annotations = result.all()
|
|
51
|
+
if inserted_annotations:
|
|
52
|
+
info.context.event_queue.put(
|
|
53
|
+
TraceAnnotationInsertEvent(tuple(anno.id for anno in inserted_annotations))
|
|
54
|
+
)
|
|
55
|
+
return TraceAnnotationMutationPayload(
|
|
56
|
+
trace_annotations=[
|
|
57
|
+
to_gql_trace_annotation(annotation) for annotation in inserted_annotations
|
|
58
|
+
],
|
|
59
|
+
query=Query(),
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
@strawberry.mutation(permission_classes=[IsNotReadOnly, IsLocked]) # type: ignore
|
|
63
|
+
async def patch_trace_annotations(
|
|
64
|
+
self, info: Info[Context, None], input: list[PatchAnnotationInput]
|
|
65
|
+
) -> TraceAnnotationMutationPayload:
|
|
66
|
+
patched_annotations = []
|
|
67
|
+
async with info.context.db() as session:
|
|
68
|
+
for annotation in input:
|
|
69
|
+
trace_annotation_id = from_global_id_with_expected_type(
|
|
70
|
+
annotation.annotation_id, "TraceAnnotation"
|
|
71
|
+
)
|
|
72
|
+
patch = {
|
|
73
|
+
column.key: patch_value
|
|
74
|
+
for column, patch_value, column_is_nullable in (
|
|
75
|
+
(models.TraceAnnotation.name, annotation.name, False),
|
|
76
|
+
(
|
|
77
|
+
models.TraceAnnotation.annotator_kind,
|
|
78
|
+
annotation.annotator_kind.value
|
|
79
|
+
if annotation.annotator_kind is not None
|
|
80
|
+
else None,
|
|
81
|
+
False,
|
|
82
|
+
),
|
|
83
|
+
(models.TraceAnnotation.label, annotation.label, True),
|
|
84
|
+
(models.TraceAnnotation.score, annotation.score, True),
|
|
85
|
+
(models.TraceAnnotation.explanation, annotation.explanation, True),
|
|
86
|
+
(models.TraceAnnotation.metadata_, annotation.metadata, False),
|
|
87
|
+
)
|
|
88
|
+
if patch_value is not UNSET and (patch_value is not None or column_is_nullable)
|
|
89
|
+
}
|
|
90
|
+
trace_annotation = await session.scalar(
|
|
91
|
+
update(models.TraceAnnotation)
|
|
92
|
+
.where(models.TraceAnnotation.id == trace_annotation_id)
|
|
93
|
+
.values(**patch)
|
|
94
|
+
.returning(models.TraceAnnotation)
|
|
95
|
+
)
|
|
96
|
+
if trace_annotation:
|
|
97
|
+
patched_annotations.append(to_gql_trace_annotation(trace_annotation))
|
|
98
|
+
info.context.event_queue.put(TraceAnnotationInsertEvent((trace_annotation.id,)))
|
|
99
|
+
return TraceAnnotationMutationPayload(trace_annotations=patched_annotations, query=Query())
|
|
100
|
+
|
|
101
|
+
@strawberry.mutation(permission_classes=[IsNotReadOnly]) # type: ignore
|
|
102
|
+
async def delete_trace_annotations(
|
|
103
|
+
self, info: Info[Context, None], input: DeleteAnnotationsInput
|
|
104
|
+
) -> TraceAnnotationMutationPayload:
|
|
105
|
+
trace_annotation_ids = [
|
|
106
|
+
from_global_id_with_expected_type(global_id, "TraceAnnotation")
|
|
107
|
+
for global_id in input.annotation_ids
|
|
108
|
+
]
|
|
109
|
+
async with info.context.db() as session:
|
|
110
|
+
stmt = (
|
|
111
|
+
delete(models.TraceAnnotation)
|
|
112
|
+
.where(models.TraceAnnotation.id.in_(trace_annotation_ids))
|
|
113
|
+
.returning(models.TraceAnnotation)
|
|
114
|
+
)
|
|
115
|
+
result = await session.scalars(stmt)
|
|
116
|
+
deleted_annotations = result.all()
|
|
117
|
+
|
|
118
|
+
deleted_annotations_gql = [
|
|
119
|
+
to_gql_trace_annotation(annotation) for annotation in deleted_annotations
|
|
120
|
+
]
|
|
121
|
+
if deleted_annotations:
|
|
122
|
+
info.context.event_queue.put(
|
|
123
|
+
TraceAnnotationDeleteEvent(tuple(anno.id for anno in deleted_annotations))
|
|
124
|
+
)
|
|
125
|
+
return TraceAnnotationMutationPayload(
|
|
126
|
+
trace_annotations=deleted_annotations_gql, query=Query()
|
|
127
|
+
)
|