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
phoenix/server/api/types/Span.py
CHANGED
|
@@ -1,36 +1,41 @@
|
|
|
1
1
|
import json
|
|
2
|
-
from collections import
|
|
2
|
+
from collections.abc import Mapping, Sized
|
|
3
3
|
from datetime import datetime
|
|
4
4
|
from enum import Enum
|
|
5
|
-
from typing import
|
|
5
|
+
from typing import TYPE_CHECKING, Any, Optional, cast
|
|
6
6
|
|
|
7
7
|
import numpy as np
|
|
8
8
|
import strawberry
|
|
9
|
-
from openinference.semconv.trace import
|
|
9
|
+
from openinference.semconv.trace import SpanAttributes
|
|
10
10
|
from strawberry import ID, UNSET
|
|
11
|
+
from strawberry.relay import Node, NodeID
|
|
11
12
|
from strawberry.types import Info
|
|
13
|
+
from typing_extensions import Annotated
|
|
12
14
|
|
|
13
15
|
import phoenix.trace.schemas as trace_schema
|
|
14
|
-
from phoenix.
|
|
15
|
-
from phoenix.core.project import Project, WrappedSpan
|
|
16
|
-
from phoenix.metrics.retrieval_metrics import RetrievalMetrics
|
|
16
|
+
from phoenix.db import models
|
|
17
17
|
from phoenix.server.api.context import Context
|
|
18
|
+
from phoenix.server.api.helpers.dataset_helpers import (
|
|
19
|
+
get_dataset_example_input,
|
|
20
|
+
get_dataset_example_output,
|
|
21
|
+
)
|
|
22
|
+
from phoenix.server.api.input_types.InvocationParameters import InvocationParameter
|
|
23
|
+
from phoenix.server.api.input_types.SpanAnnotationSort import (
|
|
24
|
+
SpanAnnotationColumn,
|
|
25
|
+
SpanAnnotationSort,
|
|
26
|
+
)
|
|
18
27
|
from phoenix.server.api.types.DocumentRetrievalMetrics import DocumentRetrievalMetrics
|
|
19
|
-
from phoenix.server.api.types.Evaluation import DocumentEvaluation
|
|
28
|
+
from phoenix.server.api.types.Evaluation import DocumentEvaluation
|
|
29
|
+
from phoenix.server.api.types.ExampleRevisionInterface import ExampleRevision
|
|
30
|
+
from phoenix.server.api.types.GenerativeProvider import GenerativeProvider
|
|
20
31
|
from phoenix.server.api.types.MimeType import MimeType
|
|
21
|
-
from phoenix.
|
|
32
|
+
from phoenix.server.api.types.SortDir import SortDir
|
|
33
|
+
from phoenix.server.api.types.SpanAnnotation import SpanAnnotation, to_gql_span_annotation
|
|
34
|
+
from phoenix.server.api.types.SpanIOValue import SpanIOValue
|
|
35
|
+
from phoenix.trace.attributes import get_attribute_value
|
|
22
36
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
INPUT_MIME_TYPE = SpanAttributes.INPUT_MIME_TYPE
|
|
26
|
-
INPUT_VALUE = SpanAttributes.INPUT_VALUE
|
|
27
|
-
LLM_TOKEN_COUNT_COMPLETION = SpanAttributes.LLM_TOKEN_COUNT_COMPLETION
|
|
28
|
-
LLM_TOKEN_COUNT_PROMPT = SpanAttributes.LLM_TOKEN_COUNT_PROMPT
|
|
29
|
-
LLM_TOKEN_COUNT_TOTAL = SpanAttributes.LLM_TOKEN_COUNT_TOTAL
|
|
30
|
-
METADATA = SpanAttributes.METADATA
|
|
31
|
-
OUTPUT_MIME_TYPE = SpanAttributes.OUTPUT_MIME_TYPE
|
|
32
|
-
OUTPUT_VALUE = SpanAttributes.OUTPUT_VALUE
|
|
33
|
-
RETRIEVAL_DOCUMENTS = SpanAttributes.RETRIEVAL_DOCUMENTS
|
|
37
|
+
if TYPE_CHECKING:
|
|
38
|
+
from phoenix.server.api.types.Project import Project
|
|
34
39
|
|
|
35
40
|
|
|
36
41
|
@strawberry.enum
|
|
@@ -41,18 +46,22 @@ class SpanKind(Enum):
|
|
|
41
46
|
NB: this is actively under construction
|
|
42
47
|
"""
|
|
43
48
|
|
|
44
|
-
chain =
|
|
45
|
-
tool =
|
|
46
|
-
llm =
|
|
47
|
-
retriever =
|
|
48
|
-
embedding =
|
|
49
|
-
agent =
|
|
50
|
-
reranker =
|
|
51
|
-
|
|
49
|
+
chain = "CHAIN"
|
|
50
|
+
tool = "TOOL"
|
|
51
|
+
llm = "LLM"
|
|
52
|
+
retriever = "RETRIEVER"
|
|
53
|
+
embedding = "EMBEDDING"
|
|
54
|
+
agent = "AGENT"
|
|
55
|
+
reranker = "RERANKER"
|
|
56
|
+
evaluator = "EVALUATOR"
|
|
57
|
+
guardrail = "GUARDRAIL"
|
|
58
|
+
unknown = "UNKNOWN"
|
|
52
59
|
|
|
53
60
|
@classmethod
|
|
54
61
|
def _missing_(cls, v: Any) -> Optional["SpanKind"]:
|
|
55
|
-
|
|
62
|
+
if v and isinstance(v, str) and v.isascii() and not v.isupper():
|
|
63
|
+
return cls(v.upper())
|
|
64
|
+
return cls.unknown
|
|
56
65
|
|
|
57
66
|
|
|
58
67
|
@strawberry.type
|
|
@@ -61,17 +70,11 @@ class SpanContext:
|
|
|
61
70
|
span_id: ID
|
|
62
71
|
|
|
63
72
|
|
|
64
|
-
@strawberry.type
|
|
65
|
-
class SpanIOValue:
|
|
66
|
-
mime_type: MimeType
|
|
67
|
-
value: str
|
|
68
|
-
|
|
69
|
-
|
|
70
73
|
@strawberry.enum
|
|
71
74
|
class SpanStatusCode(Enum):
|
|
72
|
-
OK =
|
|
73
|
-
ERROR =
|
|
74
|
-
UNSET =
|
|
75
|
+
OK = "OK"
|
|
76
|
+
ERROR = "ERROR"
|
|
77
|
+
UNSET = "UNSET"
|
|
75
78
|
|
|
76
79
|
@classmethod
|
|
77
80
|
def _missing_(cls, v: Any) -> Optional["SpanStatusCode"]:
|
|
@@ -85,19 +88,24 @@ class SpanEvent:
|
|
|
85
88
|
timestamp: datetime
|
|
86
89
|
|
|
87
90
|
@staticmethod
|
|
88
|
-
def
|
|
89
|
-
event:
|
|
91
|
+
def from_dict(
|
|
92
|
+
event: Mapping[str, Any],
|
|
90
93
|
) -> "SpanEvent":
|
|
91
94
|
return SpanEvent(
|
|
92
|
-
name=event
|
|
93
|
-
message=cast(str, event
|
|
94
|
-
timestamp=event
|
|
95
|
+
name=event["name"],
|
|
96
|
+
message=cast(str, event["attributes"].get(trace_schema.EXCEPTION_MESSAGE) or ""),
|
|
97
|
+
timestamp=datetime.fromisoformat(event["timestamp"]),
|
|
95
98
|
)
|
|
96
99
|
|
|
97
100
|
|
|
98
101
|
@strawberry.type
|
|
99
|
-
class
|
|
100
|
-
|
|
102
|
+
class SpanAsExampleRevision(ExampleRevision): ...
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
@strawberry.type
|
|
106
|
+
class Span(Node):
|
|
107
|
+
id_attr: NodeID[int]
|
|
108
|
+
db_span: strawberry.Private[models.Span]
|
|
101
109
|
name: str
|
|
102
110
|
status_code: SpanStatusCode
|
|
103
111
|
status_message: str
|
|
@@ -121,7 +129,7 @@ class Span:
|
|
|
121
129
|
token_count_completion: Optional[int]
|
|
122
130
|
input: Optional[SpanIOValue]
|
|
123
131
|
output: Optional[SpanIOValue]
|
|
124
|
-
events:
|
|
132
|
+
events: list[SpanEvent]
|
|
125
133
|
cumulative_token_count_total: Optional[int] = strawberry.field(
|
|
126
134
|
description="Cumulative (prompt plus completion) token count from "
|
|
127
135
|
"self and all descendant spans (children, grandchildren, etc.)",
|
|
@@ -140,23 +148,27 @@ class Span:
|
|
|
140
148
|
)
|
|
141
149
|
|
|
142
150
|
@strawberry.field(
|
|
143
|
-
description=
|
|
144
|
-
|
|
145
|
-
|
|
151
|
+
description=(
|
|
152
|
+
"Annotations associated with the span. This encompasses both "
|
|
153
|
+
"LLM and human annotations."
|
|
154
|
+
)
|
|
146
155
|
) # type: ignore
|
|
147
|
-
def
|
|
156
|
+
async def span_annotations(
|
|
148
157
|
self,
|
|
149
158
|
info: Info[Context, None],
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
)
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
159
|
+
sort: Optional[SpanAnnotationSort] = UNSET,
|
|
160
|
+
) -> list[SpanAnnotation]:
|
|
161
|
+
span_id = self.id_attr
|
|
162
|
+
annotations = await info.context.data_loaders.span_annotations.load(span_id)
|
|
163
|
+
sort_key = SpanAnnotationColumn.name.value
|
|
164
|
+
sort_descending = False
|
|
165
|
+
if sort:
|
|
166
|
+
sort_key = sort.col.value
|
|
167
|
+
sort_descending = sort.dir is SortDir.desc
|
|
168
|
+
annotations.sort(
|
|
169
|
+
key=lambda annotation: getattr(annotation, sort_key), reverse=sort_descending
|
|
170
|
+
)
|
|
171
|
+
return [to_gql_span_annotation(annotation) for annotation in annotations]
|
|
160
172
|
|
|
161
173
|
@strawberry.field(
|
|
162
174
|
description="Evaluations of the documents associated with the span, e.g. "
|
|
@@ -166,76 +178,131 @@ class Span:
|
|
|
166
178
|
"a list, and each evaluation is identified by its document's (zero-based) "
|
|
167
179
|
"index in that list."
|
|
168
180
|
) # type: ignore
|
|
169
|
-
def document_evaluations(
|
|
170
|
-
self
|
|
171
|
-
info: Info[Context, None],
|
|
172
|
-
) -> List[DocumentEvaluation]:
|
|
173
|
-
if not (traces := info.context.traces) or not (
|
|
174
|
-
project := traces.get_project(DEFAULT_PROJECT_NAME)
|
|
175
|
-
):
|
|
176
|
-
return []
|
|
177
|
-
span_id = SpanID(str(self.context.span_id))
|
|
178
|
-
return [
|
|
179
|
-
DocumentEvaluation.from_pb_evaluation(evaluation)
|
|
180
|
-
for evaluation in project.get_document_evaluations_by_span_id(span_id)
|
|
181
|
-
]
|
|
181
|
+
async def document_evaluations(self, info: Info[Context, None]) -> list[DocumentEvaluation]:
|
|
182
|
+
return await info.context.data_loaders.document_evaluations.load(self.id_attr)
|
|
182
183
|
|
|
183
184
|
@strawberry.field(
|
|
184
185
|
description="Retrieval metrics: NDCG@K, Precision@K, Reciprocal Rank, etc.",
|
|
185
186
|
) # type: ignore
|
|
186
|
-
def document_retrieval_metrics(
|
|
187
|
+
async def document_retrieval_metrics(
|
|
187
188
|
self,
|
|
188
189
|
info: Info[Context, None],
|
|
189
190
|
evaluation_name: Optional[str] = UNSET,
|
|
190
|
-
) ->
|
|
191
|
+
) -> list[DocumentRetrievalMetrics]:
|
|
191
192
|
if not self.num_documents:
|
|
192
193
|
return []
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
return []
|
|
197
|
-
if evaluation_name is UNSET:
|
|
198
|
-
evaluation_names = all_document_evaluation_names
|
|
199
|
-
elif evaluation_name not in all_document_evaluation_names:
|
|
200
|
-
return []
|
|
201
|
-
else:
|
|
202
|
-
evaluation_names = [evaluation_name]
|
|
203
|
-
retrieval_metrics = []
|
|
204
|
-
for name in evaluation_names:
|
|
205
|
-
evaluation_scores = self.project.get_document_evaluation_scores(
|
|
206
|
-
span_id=span_id,
|
|
207
|
-
evaluation_name=name,
|
|
208
|
-
num_documents=self.num_documents,
|
|
209
|
-
)
|
|
210
|
-
retrieval_metrics.append(
|
|
211
|
-
DocumentRetrievalMetrics(
|
|
212
|
-
evaluation_name=name,
|
|
213
|
-
metrics=RetrievalMetrics(evaluation_scores),
|
|
214
|
-
)
|
|
215
|
-
)
|
|
216
|
-
return retrieval_metrics
|
|
194
|
+
return await info.context.data_loaders.document_retrieval_metrics.load(
|
|
195
|
+
(self.id_attr, evaluation_name or None, self.num_documents),
|
|
196
|
+
)
|
|
217
197
|
|
|
218
198
|
@strawberry.field(
|
|
219
199
|
description="All descendant spans (children, grandchildren, etc.)",
|
|
220
200
|
) # type: ignore
|
|
221
|
-
def descendants(
|
|
201
|
+
async def descendants(
|
|
202
|
+
self,
|
|
203
|
+
info: Info[Context, None],
|
|
204
|
+
) -> list["Span"]:
|
|
205
|
+
span_id = str(self.context.span_id)
|
|
206
|
+
spans = await info.context.data_loaders.span_descendants.load(span_id)
|
|
207
|
+
return [to_gql_span(span) for span in spans]
|
|
208
|
+
|
|
209
|
+
@strawberry.field(
|
|
210
|
+
description="The span's attributes translated into an example revision for a dataset",
|
|
211
|
+
) # type: ignore
|
|
212
|
+
async def as_example_revision(self, info: Info[Context, None]) -> SpanAsExampleRevision:
|
|
213
|
+
span = self.db_span
|
|
214
|
+
|
|
215
|
+
# Fetch annotations associated with this span
|
|
216
|
+
span_annotations = await self.span_annotations(info)
|
|
217
|
+
annotations = dict()
|
|
218
|
+
for annotation in span_annotations:
|
|
219
|
+
annotations[annotation.name] = {
|
|
220
|
+
"label": annotation.label,
|
|
221
|
+
"score": annotation.score,
|
|
222
|
+
"explanation": annotation.explanation,
|
|
223
|
+
"metadata": annotation.metadata,
|
|
224
|
+
"annotator_kind": annotation.annotator_kind.value,
|
|
225
|
+
}
|
|
226
|
+
# Merge annotations into the metadata
|
|
227
|
+
metadata = {
|
|
228
|
+
"span_kind": span.span_kind,
|
|
229
|
+
**({"annotations": annotations} if annotations else {}),
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
return SpanAsExampleRevision(
|
|
233
|
+
input=get_dataset_example_input(span),
|
|
234
|
+
output=get_dataset_example_output(span),
|
|
235
|
+
metadata=metadata,
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
@strawberry.field(description="The project that this span belongs to.") # type: ignore
|
|
239
|
+
async def project(
|
|
222
240
|
self,
|
|
223
241
|
info: Info[Context, None],
|
|
224
|
-
) ->
|
|
242
|
+
) -> Annotated[
|
|
243
|
+
"Project", strawberry.lazy("phoenix.server.api.types.Project")
|
|
244
|
+
]: # use lazy types to avoid circular import: https://strawberry.rocks/docs/types/lazy
|
|
245
|
+
from phoenix.server.api.types.Project import to_gql_project
|
|
246
|
+
|
|
247
|
+
span_id = self.id_attr
|
|
248
|
+
project = await info.context.data_loaders.span_projects.load(span_id)
|
|
249
|
+
return to_gql_project(project)
|
|
250
|
+
|
|
251
|
+
@strawberry.field(description="Indicates if the span is contained in any dataset") # type: ignore
|
|
252
|
+
async def contained_in_dataset(self, info: Info[Context, None]) -> bool:
|
|
253
|
+
examples = await info.context.data_loaders.span_dataset_examples.load(self.id_attr)
|
|
254
|
+
return bool(examples)
|
|
255
|
+
|
|
256
|
+
@strawberry.field(description="Invocation parameters for the span") # type: ignore
|
|
257
|
+
async def invocation_parameters(self, info: Info[Context, None]) -> list[InvocationParameter]:
|
|
258
|
+
from phoenix.server.api.helpers.playground_clients import OpenAIStreamingClient
|
|
259
|
+
from phoenix.server.api.helpers.playground_registry import PLAYGROUND_CLIENT_REGISTRY
|
|
260
|
+
|
|
261
|
+
db_span = self.db_span
|
|
262
|
+
attributes = db_span.attributes
|
|
263
|
+
llm_provider = GenerativeProvider.get_model_provider_from_attributes(attributes)
|
|
264
|
+
if llm_provider is None:
|
|
265
|
+
return []
|
|
266
|
+
llm_model = get_attribute_value(attributes, SpanAttributes.LLM_MODEL_NAME)
|
|
267
|
+
invocation_parameters = get_attribute_value(
|
|
268
|
+
attributes, SpanAttributes.LLM_INVOCATION_PARAMETERS
|
|
269
|
+
)
|
|
270
|
+
if invocation_parameters is None:
|
|
271
|
+
return []
|
|
272
|
+
invocation_parameters = json.loads(invocation_parameters)
|
|
273
|
+
# find the client class for the provider, if there is no client class or provider,
|
|
274
|
+
# return openai as default
|
|
275
|
+
client_class = PLAYGROUND_CLIENT_REGISTRY.get_client(llm_provider, llm_model)
|
|
276
|
+
if not client_class:
|
|
277
|
+
client_class = OpenAIStreamingClient
|
|
278
|
+
supported_invocation_parameters = client_class.supported_invocation_parameters()
|
|
279
|
+
# filter supported invocation parameters down to those whose canonical_name is in the
|
|
280
|
+
# invocation_parameters keys
|
|
225
281
|
return [
|
|
226
|
-
|
|
227
|
-
for
|
|
282
|
+
ip
|
|
283
|
+
for ip in supported_invocation_parameters
|
|
284
|
+
if (
|
|
285
|
+
ip.canonical_name in invocation_parameters
|
|
286
|
+
or ip.invocation_name in invocation_parameters
|
|
287
|
+
)
|
|
228
288
|
]
|
|
229
289
|
|
|
230
290
|
|
|
231
|
-
def to_gql_span(span:
|
|
232
|
-
events:
|
|
233
|
-
input_value =
|
|
234
|
-
|
|
235
|
-
|
|
291
|
+
def to_gql_span(span: models.Span) -> Span:
|
|
292
|
+
events: list[SpanEvent] = list(map(SpanEvent.from_dict, span.events))
|
|
293
|
+
input_value = get_attribute_value(span.attributes, INPUT_VALUE)
|
|
294
|
+
if input_value is not None:
|
|
295
|
+
input_value = str(input_value)
|
|
296
|
+
assert input_value is None or isinstance(input_value, str)
|
|
297
|
+
output_value = get_attribute_value(span.attributes, OUTPUT_VALUE)
|
|
298
|
+
if output_value is not None:
|
|
299
|
+
output_value = str(output_value)
|
|
300
|
+
assert output_value is None or isinstance(output_value, str)
|
|
301
|
+
retrieval_documents = get_attribute_value(span.attributes, RETRIEVAL_DOCUMENTS)
|
|
236
302
|
num_documents = len(retrieval_documents) if isinstance(retrieval_documents, Sized) else None
|
|
237
303
|
return Span(
|
|
238
|
-
|
|
304
|
+
id_attr=span.id,
|
|
305
|
+
db_span=span,
|
|
239
306
|
name=span.name,
|
|
240
307
|
status_code=SpanStatusCode(span.status_code),
|
|
241
308
|
status_message=span.status_message,
|
|
@@ -243,50 +310,30 @@ def to_gql_span(span: WrappedSpan, project: Project) -> "Span":
|
|
|
243
310
|
span_kind=SpanKind(span.span_kind),
|
|
244
311
|
start_time=span.start_time,
|
|
245
312
|
end_time=span.end_time,
|
|
246
|
-
latency_ms=
|
|
313
|
+
latency_ms=span.latency_ms,
|
|
247
314
|
context=SpanContext(
|
|
248
|
-
trace_id=cast(ID, span.
|
|
249
|
-
span_id=cast(ID, span.
|
|
315
|
+
trace_id=cast(ID, span.trace.trace_id),
|
|
316
|
+
span_id=cast(ID, span.span_id),
|
|
250
317
|
),
|
|
251
|
-
attributes=json.dumps(
|
|
252
|
-
|
|
253
|
-
cls=_JSONEncoder,
|
|
254
|
-
),
|
|
255
|
-
metadata=_convert_metadata_to_string(span.attributes.get(METADATA)),
|
|
318
|
+
attributes=json.dumps(_hide_embedding_vectors(span.attributes), cls=_JSONEncoder),
|
|
319
|
+
metadata=_convert_metadata_to_string(get_attribute_value(span.attributes, METADATA)),
|
|
256
320
|
num_documents=num_documents,
|
|
257
|
-
token_count_total=
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
),
|
|
265
|
-
token_count_completion=cast(
|
|
266
|
-
Optional[int],
|
|
267
|
-
span.attributes.get(LLM_TOKEN_COUNT_COMPLETION),
|
|
268
|
-
),
|
|
269
|
-
cumulative_token_count_total=cast(
|
|
270
|
-
Optional[int],
|
|
271
|
-
span[ComputedAttributes.CUMULATIVE_LLM_TOKEN_COUNT_TOTAL],
|
|
272
|
-
),
|
|
273
|
-
cumulative_token_count_prompt=cast(
|
|
274
|
-
Optional[int],
|
|
275
|
-
span[ComputedAttributes.CUMULATIVE_LLM_TOKEN_COUNT_PROMPT],
|
|
276
|
-
),
|
|
277
|
-
cumulative_token_count_completion=cast(
|
|
278
|
-
Optional[int],
|
|
279
|
-
span[ComputedAttributes.CUMULATIVE_LLM_TOKEN_COUNT_COMPLETION],
|
|
280
|
-
),
|
|
321
|
+
token_count_total=span.llm_token_count_total,
|
|
322
|
+
token_count_prompt=span.llm_token_count_prompt,
|
|
323
|
+
token_count_completion=span.llm_token_count_completion,
|
|
324
|
+
cumulative_token_count_total=span.cumulative_llm_token_count_prompt
|
|
325
|
+
+ span.cumulative_llm_token_count_completion,
|
|
326
|
+
cumulative_token_count_prompt=span.cumulative_llm_token_count_prompt,
|
|
327
|
+
cumulative_token_count_completion=span.cumulative_llm_token_count_completion,
|
|
281
328
|
propagated_status_code=(
|
|
282
329
|
SpanStatusCode.ERROR
|
|
283
|
-
if span
|
|
330
|
+
if span.cumulative_error_count
|
|
284
331
|
else SpanStatusCode(span.status_code)
|
|
285
332
|
),
|
|
286
333
|
events=events,
|
|
287
334
|
input=(
|
|
288
335
|
SpanIOValue(
|
|
289
|
-
mime_type=MimeType(span.attributes
|
|
336
|
+
mime_type=MimeType(get_attribute_value(span.attributes, INPUT_MIME_TYPE)),
|
|
290
337
|
value=input_value,
|
|
291
338
|
)
|
|
292
339
|
if input_value is not None
|
|
@@ -294,7 +341,7 @@ def to_gql_span(span: WrappedSpan, project: Project) -> "Span":
|
|
|
294
341
|
),
|
|
295
342
|
output=(
|
|
296
343
|
SpanIOValue(
|
|
297
|
-
mime_type=MimeType(span.attributes
|
|
344
|
+
mime_type=MimeType(get_attribute_value(span.attributes, OUTPUT_MIME_TYPE)),
|
|
298
345
|
value=output_value,
|
|
299
346
|
)
|
|
300
347
|
if output_value is not None
|
|
@@ -303,6 +350,29 @@ def to_gql_span(span: WrappedSpan, project: Project) -> "Span":
|
|
|
303
350
|
)
|
|
304
351
|
|
|
305
352
|
|
|
353
|
+
def _hide_embedding_vectors(attributes: Mapping[str, Any]) -> Mapping[str, Any]:
|
|
354
|
+
if not (
|
|
355
|
+
isinstance(em := attributes.get("embedding"), dict)
|
|
356
|
+
and isinstance(embeddings := em.get("embeddings"), list)
|
|
357
|
+
and embeddings
|
|
358
|
+
):
|
|
359
|
+
return attributes
|
|
360
|
+
embeddings = embeddings.copy()
|
|
361
|
+
for i, embedding in enumerate(embeddings):
|
|
362
|
+
if not (
|
|
363
|
+
isinstance(embedding, dict)
|
|
364
|
+
and isinstance(emb := embedding.get("embedding"), dict)
|
|
365
|
+
and isinstance(vector := emb.get("vector"), list)
|
|
366
|
+
and vector
|
|
367
|
+
):
|
|
368
|
+
continue
|
|
369
|
+
embeddings[i] = {
|
|
370
|
+
**embedding,
|
|
371
|
+
"embedding": {**emb, "vector": f"<{len(vector)} dimensional vector>"},
|
|
372
|
+
}
|
|
373
|
+
return {**attributes, "embedding": {**em, "embeddings": embeddings}}
|
|
374
|
+
|
|
375
|
+
|
|
306
376
|
class _JSONEncoder(json.JSONEncoder):
|
|
307
377
|
def default(self, obj: Any) -> Any:
|
|
308
378
|
if isinstance(obj, datetime):
|
|
@@ -318,39 +388,6 @@ class _JSONEncoder(json.JSONEncoder):
|
|
|
318
388
|
return super().default(obj)
|
|
319
389
|
|
|
320
390
|
|
|
321
|
-
def _trie() -> DefaultDict[str, Any]:
|
|
322
|
-
return defaultdict(_trie)
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
def _nested_attributes(
|
|
326
|
-
attributes: Mapping[str, Any],
|
|
327
|
-
) -> DefaultDict[str, Any]:
|
|
328
|
-
nested_attributes = _trie()
|
|
329
|
-
for attribute_name, attribute_value in attributes.items():
|
|
330
|
-
trie = nested_attributes
|
|
331
|
-
keys = attribute_name.split(".")
|
|
332
|
-
for key in keys[:-1]:
|
|
333
|
-
trie = trie[key]
|
|
334
|
-
trie[keys[-1]] = attribute_value
|
|
335
|
-
return nested_attributes
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
def _hide_embedding_vectors(
|
|
339
|
-
attributes: Mapping[str, Any],
|
|
340
|
-
) -> Dict[str, Any]:
|
|
341
|
-
_attributes = dict(attributes)
|
|
342
|
-
if not isinstance((embeddings := _attributes.get(EMBEDDING_EMBEDDINGS)), Iterable):
|
|
343
|
-
return _attributes
|
|
344
|
-
_embeddings = []
|
|
345
|
-
for embedding in embeddings:
|
|
346
|
-
_embedding = dict(embedding)
|
|
347
|
-
if isinstance((vector := _embedding.get(EMBEDDING_VECTOR)), Sized):
|
|
348
|
-
_embedding[EMBEDDING_VECTOR] = f"<{len(vector)} dimensional vector>"
|
|
349
|
-
_embeddings.append(_embedding)
|
|
350
|
-
_attributes[EMBEDDING_EMBEDDINGS] = _embeddings
|
|
351
|
-
return _attributes
|
|
352
|
-
|
|
353
|
-
|
|
354
391
|
def _convert_metadata_to_string(metadata: Any) -> Optional[str]:
|
|
355
392
|
"""
|
|
356
393
|
Converts metadata to a string representation.
|
|
@@ -362,3 +399,11 @@ def _convert_metadata_to_string(metadata: Any) -> Optional[str]:
|
|
|
362
399
|
return json.dumps(metadata)
|
|
363
400
|
except Exception:
|
|
364
401
|
return str(metadata)
|
|
402
|
+
|
|
403
|
+
|
|
404
|
+
INPUT_MIME_TYPE = SpanAttributes.INPUT_MIME_TYPE
|
|
405
|
+
INPUT_VALUE = SpanAttributes.INPUT_VALUE
|
|
406
|
+
METADATA = SpanAttributes.METADATA
|
|
407
|
+
OUTPUT_MIME_TYPE = SpanAttributes.OUTPUT_MIME_TYPE
|
|
408
|
+
OUTPUT_VALUE = SpanAttributes.OUTPUT_VALUE
|
|
409
|
+
RETRIEVAL_DOCUMENTS = SpanAttributes.RETRIEVAL_DOCUMENTS
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
import strawberry
|
|
4
|
+
from strawberry import Private
|
|
5
|
+
from strawberry.relay import GlobalID, Node, NodeID
|
|
6
|
+
from strawberry.scalars import JSON
|
|
7
|
+
|
|
8
|
+
from phoenix.db import models
|
|
9
|
+
|
|
10
|
+
from .Annotation import Annotation
|
|
11
|
+
from .AnnotatorKind import AnnotatorKind
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@strawberry.type
|
|
15
|
+
class SpanAnnotation(Node, Annotation):
|
|
16
|
+
id_attr: NodeID[int]
|
|
17
|
+
annotator_kind: AnnotatorKind
|
|
18
|
+
metadata: JSON
|
|
19
|
+
span_rowid: Private[Optional[int]]
|
|
20
|
+
|
|
21
|
+
@strawberry.field
|
|
22
|
+
async def span_id(self) -> GlobalID:
|
|
23
|
+
from phoenix.server.api.types.Span import Span
|
|
24
|
+
|
|
25
|
+
return GlobalID(type_name=Span.__name__, node_id=str(self.span_rowid))
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def to_gql_span_annotation(
|
|
29
|
+
annotation: models.SpanAnnotation,
|
|
30
|
+
) -> SpanAnnotation:
|
|
31
|
+
"""
|
|
32
|
+
Converts an ORM span annotation to a GraphQL SpanAnnotation.
|
|
33
|
+
"""
|
|
34
|
+
return SpanAnnotation(
|
|
35
|
+
id_attr=annotation.id,
|
|
36
|
+
span_rowid=annotation.span_rowid,
|
|
37
|
+
name=annotation.name,
|
|
38
|
+
annotator_kind=AnnotatorKind(annotation.annotator_kind),
|
|
39
|
+
label=annotation.label,
|
|
40
|
+
score=annotation.score,
|
|
41
|
+
explanation=annotation.explanation,
|
|
42
|
+
metadata=annotation.metadata_,
|
|
43
|
+
)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import strawberry
|
|
2
|
+
|
|
3
|
+
from phoenix.server.api.types.MimeType import MimeType
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@strawberry.type
|
|
7
|
+
class SpanIOValue:
|
|
8
|
+
mime_type: MimeType
|
|
9
|
+
value: str
|
|
10
|
+
|
|
11
|
+
@strawberry.field(
|
|
12
|
+
description="Truncate value up to `chars` characters, appending '...' if truncated.",
|
|
13
|
+
) # type: ignore
|
|
14
|
+
def truncated_value(self, chars: int = 100) -> str:
|
|
15
|
+
return f"{self.value[: max(0, chars - 3)]}..." if len(self.value) > chars else self.value
|