arize-phoenix 3.18.1__tar.gz → 3.19.0__tar.gz
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-3.18.1 → arize_phoenix-3.19.0}/PKG-INFO +2 -1
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/pyproject.toml +1 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/core/project.py +152 -11
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/api/types/Evaluation.py +21 -1
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/api/types/Project.py +53 -3
- arize_phoenix-3.19.0/src/phoenix/server/api/types/Trace.py +47 -0
- arize_phoenix-3.19.0/src/phoenix/server/static/index.js +7472 -0
- arize_phoenix-3.19.0/src/phoenix/trace/__init__.py +15 -0
- arize_phoenix-3.19.0/src/phoenix/version.py +1 -0
- arize_phoenix-3.18.1/src/phoenix/server/static/index.js +0 -7452
- arize_phoenix-3.18.1/src/phoenix/trace/__init__.py +0 -35
- arize_phoenix-3.18.1/src/phoenix/version.py +0 -1
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/.gitignore +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/IP_NOTICE +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/LICENSE +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/README.md +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/__init__.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/config.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/core/__init__.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/core/embedding_dimension.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/core/model.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/core/model_schema.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/core/model_schema_adapter.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/core/traces.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/datasets/__init__.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/datasets/dataset.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/datasets/errors.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/datasets/fixtures.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/datasets/schema.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/datasets/validation.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/datetime_utils.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/exceptions.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/experimental/__init__.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/experimental/evals/__init__.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/experimental/evals/evaluators.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/experimental/evals/functions/__init__.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/experimental/evals/functions/classify.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/experimental/evals/functions/executor.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/experimental/evals/functions/generate.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/experimental/evals/functions/processing.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/experimental/evals/models/__init__.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/experimental/evals/models/anthropic.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/experimental/evals/models/base.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/experimental/evals/models/bedrock.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/experimental/evals/models/litellm.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/experimental/evals/models/openai.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/experimental/evals/models/rate_limiters.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/experimental/evals/models/vertex.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/experimental/evals/models/vertexai.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/experimental/evals/retrievals.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/experimental/evals/templates/__init__.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/experimental/evals/templates/default_templates.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/experimental/evals/templates/template.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/experimental/evals/utils/__init__.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/experimental/evals/utils/threads.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/metrics/README.md +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/metrics/__init__.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/metrics/binning.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/metrics/metrics.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/metrics/mixins.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/metrics/retrieval_metrics.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/metrics/timeseries.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/metrics/wrappers.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/pointcloud/__init__.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/pointcloud/clustering.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/pointcloud/pointcloud.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/pointcloud/projectors.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/pointcloud/umap_parameters.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/py.typed +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/__init__.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/api/__init__.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/api/context.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/api/helpers.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/api/input_types/ClusterInput.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/api/input_types/Coordinates.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/api/input_types/DataQualityMetricInput.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/api/input_types/DimensionFilter.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/api/input_types/DimensionInput.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/api/input_types/Granularity.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/api/input_types/PerformanceMetricInput.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/api/input_types/SpanSort.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/api/input_types/TimeRange.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/api/input_types/__init__.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/api/interceptor.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/api/routers/__init__.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/api/routers/evaluation_handler.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/api/routers/span_handler.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/api/routers/trace_handler.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/api/routers/utils.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/api/schema.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/api/types/Cluster.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/api/types/DataQualityMetric.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/api/types/Dataset.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/api/types/DatasetRole.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/api/types/DatasetValues.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/api/types/Dimension.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/api/types/DimensionDataType.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/api/types/DimensionShape.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/api/types/DimensionType.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/api/types/DimensionWithValue.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/api/types/DocumentEvaluationSummary.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/api/types/DocumentRetrievalMetrics.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/api/types/EmbeddingDimension.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/api/types/EmbeddingMetadata.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/api/types/EvaluationSummary.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/api/types/Event.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/api/types/EventMetadata.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/api/types/ExportEventsMutation.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/api/types/ExportedFile.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/api/types/Functionality.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/api/types/MimeType.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/api/types/Model.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/api/types/NumericRange.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/api/types/PerformanceMetric.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/api/types/PromptResponse.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/api/types/Retrieval.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/api/types/ScalarDriftMetricEnum.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/api/types/Segments.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/api/types/SortDir.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/api/types/Span.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/api/types/TimeSeries.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/api/types/UMAPPoints.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/api/types/ValidationResult.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/api/types/VectorDriftMetricEnum.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/api/types/__init__.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/api/types/node.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/api/types/pagination.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/app.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/main.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/prometheus.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/static/apple-touch-icon-114x114.png +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/static/apple-touch-icon-120x120.png +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/static/apple-touch-icon-144x144.png +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/static/apple-touch-icon-152x152.png +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/static/apple-touch-icon-180x180.png +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/static/apple-touch-icon-72x72.png +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/static/apple-touch-icon-76x76.png +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/static/apple-touch-icon.png +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/static/favicon.ico +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/static/index.css +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/static/modernizr.js +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/templates/__init__.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/templates/index.html +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/server/thread_server.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/services.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/session/__init__.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/session/client.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/session/data_extractor.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/session/evaluation.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/session/session.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/storage/__init__.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/storage/span_store/__init__.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/storage/span_store/text_file.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/trace/dsl/__init__.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/trace/dsl/filter.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/trace/dsl/helpers.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/trace/dsl/missing.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/trace/dsl/query.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/trace/errors.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/trace/evaluation_conventions.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/trace/exporter.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/trace/fixtures.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/trace/langchain/__init__.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/trace/langchain/instrumentor.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/trace/llama_index/__init__.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/trace/llama_index/callback.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/trace/openai/__init__.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/trace/openai/instrumentor.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/trace/otel.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/trace/projects.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/trace/schemas.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/trace/span_evaluations.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/trace/span_json_decoder.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/trace/span_json_encoder.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/trace/trace_dataset.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/trace/utils.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/trace/v1/__init__.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/trace/v1/evaluation_pb2.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/trace/v1/evaluation_pb2.pyi +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/utilities/__init__.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/utilities/error_handling.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/utilities/logging.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/utilities/project.py +0 -0
- {arize_phoenix-3.18.1 → arize_phoenix-3.19.0}/src/phoenix/utilities/span_store.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: arize-phoenix
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.19.0
|
|
4
4
|
Summary: AI Observability and Evaluation
|
|
5
5
|
Project-URL: Documentation, https://docs.arize.com/phoenix/
|
|
6
6
|
Project-URL: Issues, https://github.com/Arize-ai/phoenix/issues
|
|
@@ -20,6 +20,7 @@ Requires-Python: <3.13,>=3.8
|
|
|
20
20
|
Requires-Dist: hdbscan>=0.8.33
|
|
21
21
|
Requires-Dist: jinja2
|
|
22
22
|
Requires-Dist: numpy
|
|
23
|
+
Requires-Dist: openinference-instrumentation
|
|
23
24
|
Requires-Dist: openinference-instrumentation-langchain>=0.1.12
|
|
24
25
|
Requires-Dist: openinference-instrumentation-llama-index>=1.2.0
|
|
25
26
|
Requires-Dist: openinference-instrumentation-openai>=0.1.4
|
|
@@ -46,6 +46,7 @@ dependencies = [
|
|
|
46
46
|
"opentelemetry-proto",
|
|
47
47
|
"opentelemetry-exporter-otlp",
|
|
48
48
|
"openinference-semantic-conventions>=0.1.5",
|
|
49
|
+
"openinference-instrumentation",
|
|
49
50
|
"openinference-instrumentation-langchain>=0.1.12",
|
|
50
51
|
"openinference-instrumentation-llama-index>=1.2.0",
|
|
51
52
|
"openinference-instrumentation-openai>=0.1.4",
|
|
@@ -111,9 +111,20 @@ class Project:
|
|
|
111
111
|
def add_eval(self, pb_eval: pb.Evaluation) -> None:
|
|
112
112
|
self._evals.add(pb_eval)
|
|
113
113
|
|
|
114
|
+
def has_trace(self, trace_id: TraceID) -> bool:
|
|
115
|
+
return self._spans.has_trace(trace_id)
|
|
116
|
+
|
|
114
117
|
def get_trace(self, trace_id: TraceID) -> Iterator[WrappedSpan]:
|
|
115
118
|
yield from self._spans.get_trace(trace_id)
|
|
116
119
|
|
|
120
|
+
def get_trace_ids(
|
|
121
|
+
self,
|
|
122
|
+
start_time: Optional[datetime] = None,
|
|
123
|
+
stop_time: Optional[datetime] = None,
|
|
124
|
+
trace_ids: Optional[Iterable[TraceID]] = None,
|
|
125
|
+
) -> Iterator[TraceID]:
|
|
126
|
+
yield from self._spans.get_trace_ids(start_time, stop_time, trace_ids)
|
|
127
|
+
|
|
117
128
|
def get_spans(
|
|
118
129
|
self,
|
|
119
130
|
start_time: Optional[datetime] = None,
|
|
@@ -155,6 +166,21 @@ class Project:
|
|
|
155
166
|
def right_open_time_range(self) -> Tuple[Optional[datetime], Optional[datetime]]:
|
|
156
167
|
return self._spans.right_open_time_range
|
|
157
168
|
|
|
169
|
+
def get_trace_evaluation(self, trace_id: TraceID, name: str) -> Optional[pb.Evaluation]:
|
|
170
|
+
return self._evals.get_trace_evaluation(trace_id, name)
|
|
171
|
+
|
|
172
|
+
def get_trace_evaluation_names(self) -> List[EvaluationName]:
|
|
173
|
+
return self._evals.get_trace_evaluation_names()
|
|
174
|
+
|
|
175
|
+
def get_trace_evaluation_labels(self, name: EvaluationName) -> Tuple[str, ...]:
|
|
176
|
+
return self._evals.get_trace_evaluation_labels(name)
|
|
177
|
+
|
|
178
|
+
def get_trace_evaluation_trace_ids(self, name: EvaluationName) -> Tuple[TraceID, ...]:
|
|
179
|
+
return self._evals.get_trace_evaluation_trace_ids(name)
|
|
180
|
+
|
|
181
|
+
def get_evaluations_by_trace_id(self, trace_id: TraceID) -> List[pb.Evaluation]:
|
|
182
|
+
return self._evals.get_evaluations_by_trace_id(trace_id)
|
|
183
|
+
|
|
158
184
|
def get_span_evaluation(self, span_id: SpanID, name: str) -> Optional[pb.Evaluation]:
|
|
159
185
|
return self._evals.get_span_evaluation(span_id, name)
|
|
160
186
|
|
|
@@ -201,12 +227,43 @@ class Project:
|
|
|
201
227
|
return self._is_archived
|
|
202
228
|
|
|
203
229
|
|
|
230
|
+
class _Trace:
|
|
231
|
+
def __init__(self, span: WrappedSpan) -> None:
|
|
232
|
+
self._trace_id: TraceID = span.context.trace_id
|
|
233
|
+
self._min_start_time: datetime = span.start_time
|
|
234
|
+
self._max_end_time: datetime = span.end_time
|
|
235
|
+
self._spans: List[WrappedSpan] = [span]
|
|
236
|
+
|
|
237
|
+
@property
|
|
238
|
+
def trace_id(self) -> TraceID:
|
|
239
|
+
return self._trace_id
|
|
240
|
+
|
|
241
|
+
@property
|
|
242
|
+
def start_time(self) -> datetime:
|
|
243
|
+
return self._min_start_time
|
|
244
|
+
|
|
245
|
+
@property
|
|
246
|
+
def latency_ms(self) -> float:
|
|
247
|
+
return (self._max_end_time - self._min_start_time).total_seconds() * 1000
|
|
248
|
+
|
|
249
|
+
def add(self, span: WrappedSpan) -> None:
|
|
250
|
+
self._min_start_time = min(self._min_start_time, span.start_time)
|
|
251
|
+
self._max_end_time = max(self._max_end_time, span.end_time)
|
|
252
|
+
self._spans.append(span)
|
|
253
|
+
|
|
254
|
+
def __eq__(self, other: Any) -> bool:
|
|
255
|
+
return self is other
|
|
256
|
+
|
|
257
|
+
def __iter__(self) -> Iterator[WrappedSpan]:
|
|
258
|
+
yield from self._spans
|
|
259
|
+
|
|
260
|
+
|
|
204
261
|
class _Spans:
|
|
205
262
|
def __init__(self) -> None:
|
|
206
263
|
self._lock = RLock()
|
|
207
264
|
self._spans: Dict[SpanID, WrappedSpan] = {}
|
|
208
265
|
self._parent_span_ids: Dict[SpanID, _ParentSpanID] = {}
|
|
209
|
-
self._traces:
|
|
266
|
+
self._traces: Dict[TraceID, _Trace] = {}
|
|
210
267
|
self._child_spans: DefaultDict[SpanID, Set[WrappedSpan]] = defaultdict(set)
|
|
211
268
|
self._num_documents: DefaultDict[SpanID, int] = defaultdict(int)
|
|
212
269
|
self._start_time_sorted_spans: SortedKeyList[WrappedSpan] = SortedKeyList(
|
|
@@ -221,12 +278,18 @@ class _Spans:
|
|
|
221
278
|
(or will not arrive). For spans whose parent is not None, the root span status
|
|
222
279
|
is temporary and will be revoked when its parent span arrives.
|
|
223
280
|
"""
|
|
224
|
-
self.
|
|
225
|
-
key=lambda
|
|
281
|
+
self._latency_sorted_traces: SortedKeyList[_Trace] = SortedKeyList(
|
|
282
|
+
key=lambda trace: trace.latency_ms,
|
|
283
|
+
)
|
|
284
|
+
self._start_time_sorted_traces: SortedKeyList[_Trace] = SortedKeyList(
|
|
285
|
+
key=lambda trace: trace.start_time,
|
|
226
286
|
)
|
|
227
287
|
self._token_count_total: int = 0
|
|
228
288
|
self._last_updated_at: Optional[datetime] = None
|
|
229
289
|
|
|
290
|
+
def has_trace(self, trace_id: TraceID) -> bool:
|
|
291
|
+
return trace_id in self._traces
|
|
292
|
+
|
|
230
293
|
def get_trace(self, trace_id: TraceID) -> Iterator[WrappedSpan]:
|
|
231
294
|
with self._lock:
|
|
232
295
|
# make a copy because source data can mutate during iteration
|
|
@@ -236,6 +299,46 @@ class _Spans:
|
|
|
236
299
|
for span in spans:
|
|
237
300
|
yield span
|
|
238
301
|
|
|
302
|
+
def get_trace_ids(
|
|
303
|
+
self,
|
|
304
|
+
start_time: Optional[datetime] = None,
|
|
305
|
+
stop_time: Optional[datetime] = None,
|
|
306
|
+
trace_ids: Optional[Iterable[TraceID]] = None,
|
|
307
|
+
) -> Iterator[TraceID]:
|
|
308
|
+
if not self._spans:
|
|
309
|
+
return
|
|
310
|
+
if start_time is None or stop_time is None:
|
|
311
|
+
min_start_time, max_stop_time = cast(
|
|
312
|
+
Tuple[datetime, datetime],
|
|
313
|
+
self.right_open_time_range,
|
|
314
|
+
)
|
|
315
|
+
start_time = start_time or min_start_time
|
|
316
|
+
stop_time = stop_time or max_stop_time
|
|
317
|
+
if trace_ids is not None:
|
|
318
|
+
with self._lock:
|
|
319
|
+
traces = tuple(
|
|
320
|
+
trace
|
|
321
|
+
for trace_id in trace_ids
|
|
322
|
+
if (
|
|
323
|
+
(trace := self._traces.get(trace_id))
|
|
324
|
+
and start_time <= trace.start_time < stop_time
|
|
325
|
+
)
|
|
326
|
+
)
|
|
327
|
+
else:
|
|
328
|
+
sorted_traces = self._start_time_sorted_traces
|
|
329
|
+
# make a copy because source data can mutate during iteration
|
|
330
|
+
with self._lock:
|
|
331
|
+
traces = tuple(
|
|
332
|
+
sorted_traces.irange_key(
|
|
333
|
+
start_time.astimezone(timezone.utc),
|
|
334
|
+
stop_time.astimezone(timezone.utc),
|
|
335
|
+
inclusive=(True, False),
|
|
336
|
+
reverse=True, # most recent traces first
|
|
337
|
+
)
|
|
338
|
+
)
|
|
339
|
+
for trace in traces:
|
|
340
|
+
yield trace.trace_id
|
|
341
|
+
|
|
239
342
|
def get_spans(
|
|
240
343
|
self,
|
|
241
344
|
start_time: Optional[datetime] = None,
|
|
@@ -289,15 +392,15 @@ class _Spans:
|
|
|
289
392
|
def root_span_latency_ms_quantiles(self, probability: float) -> Optional[float]:
|
|
290
393
|
"""Root span latency quantiles in milliseconds"""
|
|
291
394
|
with self._lock:
|
|
292
|
-
|
|
293
|
-
if not (n := len(
|
|
395
|
+
traces = self._latency_sorted_traces
|
|
396
|
+
if not (n := len(traces)):
|
|
294
397
|
return None
|
|
295
398
|
if probability >= 1:
|
|
296
|
-
return cast(float,
|
|
399
|
+
return cast(float, traces[-1].latency_ms)
|
|
297
400
|
if probability <= 0:
|
|
298
|
-
return cast(float,
|
|
401
|
+
return cast(float, traces[0].latency_ms)
|
|
299
402
|
k = max(0, round(n * probability) - 1)
|
|
300
|
-
return cast(float,
|
|
403
|
+
return cast(float, traces[k].latency_ms)
|
|
301
404
|
|
|
302
405
|
def get_descendant_spans(self, span_id: SpanID) -> Iterator[WrappedSpan]:
|
|
303
406
|
for span in self._get_descendant_spans(span_id):
|
|
@@ -373,7 +476,6 @@ class _Spans:
|
|
|
373
476
|
# A root span is a span whose parent span is not in our collection.
|
|
374
477
|
# Now that their parent span has arrived, they are no longer root spans.
|
|
375
478
|
self._start_time_sorted_root_spans.remove(child_span)
|
|
376
|
-
self._latency_sorted_root_spans.remove(child_span)
|
|
377
479
|
|
|
378
480
|
# Add computed attributes to span
|
|
379
481
|
start_time = span.start_time
|
|
@@ -383,11 +485,10 @@ class _Spans:
|
|
|
383
485
|
|
|
384
486
|
# Store the new span (after adding computed attributes)
|
|
385
487
|
self._spans[span_id] = span
|
|
386
|
-
self.
|
|
488
|
+
self._add_span_to_trace(span)
|
|
387
489
|
self._start_time_sorted_spans.add(span)
|
|
388
490
|
if parent_span_id is None or parent_span_id not in self._spans:
|
|
389
491
|
self._start_time_sorted_root_spans.add(span)
|
|
390
|
-
self._latency_sorted_root_spans.add(span)
|
|
391
492
|
self._propagate_cumulative_values(span)
|
|
392
493
|
self._update_cached_statistics(span)
|
|
393
494
|
|
|
@@ -395,6 +496,18 @@ class _Spans:
|
|
|
395
496
|
# when they should refresh the page.
|
|
396
497
|
self._last_updated_at = datetime.now(timezone.utc)
|
|
397
498
|
|
|
499
|
+
def _add_span_to_trace(self, span: WrappedSpan) -> None:
|
|
500
|
+
trace_id = span.context.trace_id
|
|
501
|
+
if (trace := self._traces.get(trace_id)) is None:
|
|
502
|
+
self._traces[trace_id] = trace = _Trace(span)
|
|
503
|
+
else:
|
|
504
|
+
# Must remove trace before mutating it.
|
|
505
|
+
self._latency_sorted_traces.remove(trace)
|
|
506
|
+
self._start_time_sorted_traces.remove(trace)
|
|
507
|
+
trace.add(span)
|
|
508
|
+
self._latency_sorted_traces.add(trace)
|
|
509
|
+
self._start_time_sorted_traces.add(trace)
|
|
510
|
+
|
|
398
511
|
def _update_cached_statistics(self, span: WrappedSpan) -> None:
|
|
399
512
|
# Update statistics for quick access later
|
|
400
513
|
span_id = span.context.span_id
|
|
@@ -444,6 +557,7 @@ class _Evals:
|
|
|
444
557
|
self._evaluations_by_trace_id: DefaultDict[TraceID, Dict[EvaluationName, pb.Evaluation]] = (
|
|
445
558
|
defaultdict(dict)
|
|
446
559
|
)
|
|
560
|
+
self._trace_evaluation_labels: DefaultDict[EvaluationName, Set[str]] = defaultdict(set)
|
|
447
561
|
self._span_evaluations_by_name: DefaultDict[EvaluationName, Dict[SpanID, pb.Evaluation]] = (
|
|
448
562
|
defaultdict(dict)
|
|
449
563
|
)
|
|
@@ -484,6 +598,9 @@ class _Evals:
|
|
|
484
598
|
trace_id = TraceID(subject_id.trace_id)
|
|
485
599
|
self._evaluations_by_trace_id[trace_id][name] = evaluation
|
|
486
600
|
self._trace_evaluations_by_name[name][trace_id] = evaluation
|
|
601
|
+
if evaluation.result.HasField("label"):
|
|
602
|
+
label = evaluation.result.label.value
|
|
603
|
+
self._trace_evaluation_labels[name].add(label)
|
|
487
604
|
elif subject_id_kind is None:
|
|
488
605
|
logger.warning(
|
|
489
606
|
f"discarding evaluation with missing subject_id: {MessageToDict(evaluation)}"
|
|
@@ -496,6 +613,30 @@ class _Evals:
|
|
|
496
613
|
def last_updated_at(self) -> Optional[datetime]:
|
|
497
614
|
return self._last_updated_at
|
|
498
615
|
|
|
616
|
+
def get_trace_evaluation(self, trace_id: TraceID, name: str) -> Optional[pb.Evaluation]:
|
|
617
|
+
with self._lock:
|
|
618
|
+
trace_evaluations = self._evaluations_by_trace_id.get(trace_id)
|
|
619
|
+
return trace_evaluations.get(name) if trace_evaluations else None
|
|
620
|
+
|
|
621
|
+
def get_trace_evaluation_names(self) -> List[EvaluationName]:
|
|
622
|
+
with self._lock:
|
|
623
|
+
return list(self._trace_evaluations_by_name)
|
|
624
|
+
|
|
625
|
+
def get_trace_evaluation_labels(self, name: EvaluationName) -> Tuple[str, ...]:
|
|
626
|
+
with self._lock:
|
|
627
|
+
labels = self._trace_evaluation_labels.get(name)
|
|
628
|
+
return tuple(labels) if labels else ()
|
|
629
|
+
|
|
630
|
+
def get_trace_evaluation_trace_ids(self, name: EvaluationName) -> Tuple[TraceID, ...]:
|
|
631
|
+
with self._lock:
|
|
632
|
+
trace_evaluations = self._trace_evaluations_by_name.get(name)
|
|
633
|
+
return tuple(trace_evaluations.keys()) if trace_evaluations else ()
|
|
634
|
+
|
|
635
|
+
def get_evaluations_by_trace_id(self, trace_id: TraceID) -> List[pb.Evaluation]:
|
|
636
|
+
with self._lock:
|
|
637
|
+
evaluations = self._evaluations_by_trace_id.get(trace_id)
|
|
638
|
+
return list(evaluations.values()) if evaluations else []
|
|
639
|
+
|
|
499
640
|
def get_span_evaluation(self, span_id: SpanID, name: str) -> Optional[pb.Evaluation]:
|
|
500
641
|
with self._lock:
|
|
501
642
|
span_evaluations = self._evaluations_by_span_id.get(span_id)
|
|
@@ -3,7 +3,7 @@ from typing import Optional
|
|
|
3
3
|
import strawberry
|
|
4
4
|
|
|
5
5
|
import phoenix.trace.v1 as pb
|
|
6
|
-
from phoenix.trace.schemas import SpanID
|
|
6
|
+
from phoenix.trace.schemas import SpanID, TraceID
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
@strawberry.interface
|
|
@@ -24,6 +24,26 @@ class Evaluation:
|
|
|
24
24
|
)
|
|
25
25
|
|
|
26
26
|
|
|
27
|
+
@strawberry.type
|
|
28
|
+
class TraceEvaluation(Evaluation):
|
|
29
|
+
trace_id: strawberry.Private[TraceID]
|
|
30
|
+
|
|
31
|
+
@staticmethod
|
|
32
|
+
def from_pb_evaluation(evaluation: pb.Evaluation) -> "TraceEvaluation":
|
|
33
|
+
result = evaluation.result
|
|
34
|
+
score = result.score.value if result.HasField("score") else None
|
|
35
|
+
label = result.label.value if result.HasField("label") else None
|
|
36
|
+
explanation = result.explanation.value if result.HasField("explanation") else None
|
|
37
|
+
trace_id = TraceID(evaluation.subject_id.trace_id)
|
|
38
|
+
return TraceEvaluation(
|
|
39
|
+
name=evaluation.name,
|
|
40
|
+
score=score,
|
|
41
|
+
label=label,
|
|
42
|
+
explanation=explanation,
|
|
43
|
+
trace_id=trace_id,
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
|
|
27
47
|
@strawberry.type
|
|
28
48
|
class SpanEvaluation(Evaluation):
|
|
29
49
|
span_id: strawberry.Private[SpanID]
|
|
@@ -19,6 +19,7 @@ from phoenix.server.api.types.pagination import (
|
|
|
19
19
|
connection_from_list,
|
|
20
20
|
)
|
|
21
21
|
from phoenix.server.api.types.Span import Span, to_gql_span
|
|
22
|
+
from phoenix.server.api.types.Trace import Trace
|
|
22
23
|
from phoenix.server.api.types.ValidationResult import ValidationResult
|
|
23
24
|
from phoenix.trace.dsl import SpanFilter
|
|
24
25
|
from phoenix.trace.schemas import SpanID, TraceID
|
|
@@ -69,6 +70,12 @@ class Project(Node):
|
|
|
69
70
|
def latency_ms_p99(self) -> Optional[float]:
|
|
70
71
|
return self.project.root_span_latency_ms_quantiles(0.99)
|
|
71
72
|
|
|
73
|
+
@strawberry.field
|
|
74
|
+
def trace(self, trace_id: ID) -> Optional[Trace]:
|
|
75
|
+
if self.project.has_trace(TraceID(trace_id)):
|
|
76
|
+
return Trace(trace_id=trace_id, project=self.project)
|
|
77
|
+
return None
|
|
78
|
+
|
|
72
79
|
@strawberry.field
|
|
73
80
|
def spans(
|
|
74
81
|
self,
|
|
@@ -88,7 +95,12 @@ class Project(Node):
|
|
|
88
95
|
last=last,
|
|
89
96
|
before=before if isinstance(before, Cursor) else None,
|
|
90
97
|
)
|
|
91
|
-
if
|
|
98
|
+
start_time = time_range.start if time_range else None
|
|
99
|
+
stop_time = time_range.end if time_range else None
|
|
100
|
+
if not (project := self.project).span_count(
|
|
101
|
+
start_time=start_time,
|
|
102
|
+
stop_time=stop_time,
|
|
103
|
+
):
|
|
92
104
|
return connection_from_list(data=[], args=args)
|
|
93
105
|
predicate = (
|
|
94
106
|
SpanFilter(
|
|
@@ -100,8 +112,8 @@ class Project(Node):
|
|
|
100
112
|
)
|
|
101
113
|
if not trace_ids:
|
|
102
114
|
spans = project.get_spans(
|
|
103
|
-
start_time=
|
|
104
|
-
stop_time=
|
|
115
|
+
start_time=start_time,
|
|
116
|
+
stop_time=stop_time,
|
|
105
117
|
root_spans_only=root_spans_only,
|
|
106
118
|
)
|
|
107
119
|
else:
|
|
@@ -115,6 +127,13 @@ class Project(Node):
|
|
|
115
127
|
data = [to_gql_span(span, project) for span in spans]
|
|
116
128
|
return connection_from_list(data=data, args=args)
|
|
117
129
|
|
|
130
|
+
@strawberry.field(
|
|
131
|
+
description="Names of all available evaluations for traces. "
|
|
132
|
+
"(The list contains no duplicates.)"
|
|
133
|
+
) # type: ignore
|
|
134
|
+
def trace_evaluation_names(self) -> List[str]:
|
|
135
|
+
return self.project.get_trace_evaluation_names()
|
|
136
|
+
|
|
118
137
|
@strawberry.field(
|
|
119
138
|
description="Names of all available evaluations for spans. "
|
|
120
139
|
"(The list contains no duplicates.)"
|
|
@@ -133,6 +152,37 @@ class Project(Node):
|
|
|
133
152
|
None if span_id is UNSET else SpanID(span_id),
|
|
134
153
|
)
|
|
135
154
|
|
|
155
|
+
@strawberry.field
|
|
156
|
+
def trace_evaluation_summary(
|
|
157
|
+
self,
|
|
158
|
+
evaluation_name: str,
|
|
159
|
+
time_range: Optional[TimeRange] = UNSET,
|
|
160
|
+
) -> Optional[EvaluationSummary]:
|
|
161
|
+
project = self.project
|
|
162
|
+
eval_trace_ids = project.get_trace_evaluation_trace_ids(evaluation_name)
|
|
163
|
+
if not eval_trace_ids:
|
|
164
|
+
return None
|
|
165
|
+
trace_ids = project.get_trace_ids(
|
|
166
|
+
start_time=time_range.start if time_range else None,
|
|
167
|
+
stop_time=time_range.end if time_range else None,
|
|
168
|
+
trace_ids=eval_trace_ids,
|
|
169
|
+
)
|
|
170
|
+
evaluations = tuple(
|
|
171
|
+
evaluation
|
|
172
|
+
for trace_id in trace_ids
|
|
173
|
+
if (
|
|
174
|
+
evaluation := project.get_trace_evaluation(
|
|
175
|
+
trace_id,
|
|
176
|
+
evaluation_name,
|
|
177
|
+
)
|
|
178
|
+
)
|
|
179
|
+
is not None
|
|
180
|
+
)
|
|
181
|
+
if not evaluations:
|
|
182
|
+
return None
|
|
183
|
+
labels = project.get_trace_evaluation_labels(evaluation_name)
|
|
184
|
+
return EvaluationSummary(evaluations, labels)
|
|
185
|
+
|
|
136
186
|
@strawberry.field
|
|
137
187
|
def span_evaluation_summary(
|
|
138
188
|
self,
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
from typing import List, Optional
|
|
2
|
+
|
|
3
|
+
import strawberry
|
|
4
|
+
from strawberry import ID, UNSET, Private
|
|
5
|
+
|
|
6
|
+
from phoenix.core.project import Project
|
|
7
|
+
from phoenix.server.api.types.Evaluation import TraceEvaluation
|
|
8
|
+
from phoenix.server.api.types.pagination import (
|
|
9
|
+
Connection,
|
|
10
|
+
ConnectionArgs,
|
|
11
|
+
Cursor,
|
|
12
|
+
connection_from_list,
|
|
13
|
+
)
|
|
14
|
+
from phoenix.server.api.types.Span import Span, to_gql_span
|
|
15
|
+
from phoenix.trace.schemas import TraceID
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@strawberry.type
|
|
19
|
+
class Trace:
|
|
20
|
+
trace_id: ID
|
|
21
|
+
project: Private[Project]
|
|
22
|
+
|
|
23
|
+
@strawberry.field
|
|
24
|
+
def spans(
|
|
25
|
+
self,
|
|
26
|
+
first: Optional[int] = 50,
|
|
27
|
+
last: Optional[int] = UNSET,
|
|
28
|
+
after: Optional[Cursor] = UNSET,
|
|
29
|
+
before: Optional[Cursor] = UNSET,
|
|
30
|
+
) -> Connection[Span]:
|
|
31
|
+
args = ConnectionArgs(
|
|
32
|
+
first=first,
|
|
33
|
+
after=after if isinstance(after, Cursor) else None,
|
|
34
|
+
last=last,
|
|
35
|
+
before=before if isinstance(before, Cursor) else None,
|
|
36
|
+
)
|
|
37
|
+
spans = sorted(
|
|
38
|
+
self.project.get_trace(TraceID(self.trace_id)),
|
|
39
|
+
key=lambda span: span.start_time,
|
|
40
|
+
)
|
|
41
|
+
data = [to_gql_span(span, self.project) for span in spans]
|
|
42
|
+
return connection_from_list(data=data, args=args)
|
|
43
|
+
|
|
44
|
+
@strawberry.field(description="Evaluations associated with the trace") # type: ignore
|
|
45
|
+
def trace_evaluations(self) -> List[TraceEvaluation]:
|
|
46
|
+
evaluations = self.project.get_evaluations_by_trace_id(TraceID(self.trace_id))
|
|
47
|
+
return [TraceEvaluation.from_pb_evaluation(evaluation) for evaluation in evaluations]
|