arize-phoenix 4.15.0__tar.gz → 4.16.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-4.15.0 → arize_phoenix-4.16.0}/PKG-INFO +2 -1
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/pyproject.toml +2 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/db/bulk_inserter.py +129 -2
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/db/helpers.py +23 -1
- arize_phoenix-4.16.0/src/phoenix/db/insertion/constants.py +2 -0
- arize_phoenix-4.16.0/src/phoenix/db/insertion/document_annotation.py +157 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/db/insertion/helpers.py +13 -0
- arize_phoenix-4.16.0/src/phoenix/db/insertion/span_annotation.py +144 -0
- arize_phoenix-4.16.0/src/phoenix/db/insertion/trace_annotation.py +144 -0
- arize_phoenix-4.16.0/src/phoenix/db/insertion/types.py +261 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/experiments/types.py +3 -3
- arize_phoenix-4.16.0/src/phoenix/server/api/input_types/SpanAnnotationSort.py +17 -0
- arize_phoenix-4.16.0/src/phoenix/server/api/input_types/TraceAnnotationSort.py +17 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/routers/v1/evaluations.py +90 -4
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/routers/v1/spans.py +36 -46
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/routers/v1/traces.py +36 -48
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/types/Span.py +22 -3
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/types/Trace.py +21 -4
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/app.py +2 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/static/.vite/manifest.json +14 -14
- arize_phoenix-4.15.0/src/phoenix/server/static/assets/components-kGgeFkHp.js → arize_phoenix-4.16.0/src/phoenix/server/static/assets/components-Ci5kMOk5.js +119 -126
- arize_phoenix-4.15.0/src/phoenix/server/static/assets/index-BctFO6S7.js → arize_phoenix-4.16.0/src/phoenix/server/static/assets/index-BQG5WVX7.js +2 -2
- arize_phoenix-4.15.0/src/phoenix/server/static/assets/pages-DabDCmVd.js → arize_phoenix-4.16.0/src/phoenix/server/static/assets/pages-BrevprVW.js +289 -213
- arize_phoenix-4.15.0/src/phoenix/server/static/assets/vendor-arizeai-B5Hti8OB.js → arize_phoenix-4.16.0/src/phoenix/server/static/assets/vendor-arizeai-DTbiPGp6.js +1 -1
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/trace/dsl/filter.py +2 -6
- arize_phoenix-4.16.0/src/phoenix/version.py +1 -0
- arize_phoenix-4.15.0/src/phoenix/version.py +0 -1
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/.gitignore +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/IP_NOTICE +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/LICENSE +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/README.md +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/examples/manually-instrumented-chatbot/chat-service/chat/__init__.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/examples/manually-instrumented-chatbot/chat-service/chat/app.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/examples/manually-instrumented-chatbot/chat-service/chat/types.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/examples/manually-instrumented-chatbot/frontend/Dockerfile +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/examples/manually-instrumented-chatbot/frontend/Makefile +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/examples/manually-instrumented-chatbot/frontend/__init__.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/examples/manually-instrumented-chatbot/frontend/pyproject.toml +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/examples/manually-instrumented-chatbot/frontend/requirements.txt +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/examples/manually-instrumented-chatbot/frontend/schema.json +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/__init__.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/config.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/core/__init__.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/core/embedding_dimension.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/core/model.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/core/model_schema.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/core/model_schema_adapter.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/datetime_utils.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/db/README.md +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/db/__init__.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/db/alembic.ini +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/db/engines.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/db/insertion/__init__.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/db/insertion/dataset.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/db/insertion/evaluation.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/db/insertion/span.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/db/migrate.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/db/migrations/__init__.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/db/migrations/env.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/db/migrations/script.py.mako +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/db/migrations/types.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/db/migrations/versions/10460e46d750_datasets.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/db/migrations/versions/cf03bd6bae1d_init.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/db/models.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/exceptions.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/experiments/__init__.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/experiments/evaluators/__init__.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/experiments/evaluators/base.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/experiments/evaluators/code_evaluators.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/experiments/evaluators/llm_evaluators.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/experiments/evaluators/utils.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/experiments/functions.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/experiments/tracing.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/experiments/utils.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/inferences/__init__.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/inferences/errors.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/inferences/fixtures.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/inferences/inferences.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/inferences/schema.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/inferences/validation.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/metrics/README.md +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/metrics/__init__.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/metrics/binning.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/metrics/metrics.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/metrics/mixins.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/metrics/retrieval_metrics.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/metrics/timeseries.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/metrics/wrappers.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/pointcloud/__init__.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/pointcloud/clustering.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/pointcloud/pointcloud.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/pointcloud/projectors.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/pointcloud/umap_parameters.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/py.typed +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/__init__.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/__init__.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/context.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/dataloaders/__init__.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/dataloaders/average_experiment_run_latency.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/dataloaders/cache/__init__.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/dataloaders/cache/two_tier_cache.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/dataloaders/dataset_example_revisions.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/dataloaders/dataset_example_spans.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/dataloaders/document_evaluation_summaries.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/dataloaders/document_evaluations.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/dataloaders/document_retrieval_metrics.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/dataloaders/evaluation_summaries.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/dataloaders/experiment_annotation_summaries.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/dataloaders/experiment_error_rates.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/dataloaders/experiment_run_counts.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/dataloaders/experiment_sequence_number.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/dataloaders/latency_ms_quantile.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/dataloaders/min_start_or_max_end_times.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/dataloaders/project_by_name.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/dataloaders/record_counts.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/dataloaders/span_annotations.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/dataloaders/span_dataset_examples.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/dataloaders/span_descendants.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/dataloaders/span_evaluations.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/dataloaders/span_projects.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/dataloaders/token_counts.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/dataloaders/trace_evaluations.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/dataloaders/trace_row_ids.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/helpers/__init__.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/helpers/dataset_helpers.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/input_types/AddExamplesToDatasetInput.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/input_types/AddSpansToDatasetInput.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/input_types/ClearProjectInput.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/input_types/ClusterInput.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/input_types/Coordinates.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/input_types/CreateDatasetInput.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/input_types/CreateSpanAnnotationInput.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/input_types/CreateTraceAnnotationInput.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/input_types/DataQualityMetricInput.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/input_types/DatasetExampleInput.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/input_types/DatasetSort.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/input_types/DatasetVersionSort.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/input_types/DeleteAnnotationsInput.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/input_types/DeleteDatasetExamplesInput.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/input_types/DeleteDatasetInput.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/input_types/DeleteExperimentsInput.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/input_types/DimensionFilter.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/input_types/DimensionInput.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/input_types/Granularity.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/input_types/PatchAnnotationInput.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/input_types/PatchDatasetExamplesInput.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/input_types/PatchDatasetInput.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/input_types/PerformanceMetricInput.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/input_types/SpanSort.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/input_types/TimeRange.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/input_types/__init__.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/interceptor.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/mutations/__init__.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/mutations/auth.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/mutations/dataset_mutations.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/mutations/experiment_mutations.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/mutations/export_events_mutations.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/mutations/project_mutations.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/mutations/span_annotations_mutations.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/mutations/trace_annotations_mutations.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/openapi/__init__.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/openapi/main.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/openapi/schema.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/queries.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/routers/__init__.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/routers/utils.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/routers/v1/__init__.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/routers/v1/datasets.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/routers/v1/experiment_evaluations.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/routers/v1/experiment_runs.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/routers/v1/experiments.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/routers/v1/pydantic_compat.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/routers/v1/utils.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/schema.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/types/Annotation.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/types/AnnotatorKind.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/types/Cluster.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/types/CreateDatasetPayload.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/types/DataQualityMetric.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/types/Dataset.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/types/DatasetExample.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/types/DatasetExampleRevision.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/types/DatasetValues.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/types/DatasetVersion.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/types/Dimension.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/types/DimensionDataType.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/types/DimensionShape.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/types/DimensionType.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/types/DimensionWithValue.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/types/DocumentEvaluationSummary.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/types/DocumentRetrievalMetrics.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/types/EmbeddingDimension.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/types/EmbeddingMetadata.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/types/Evaluation.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/types/EvaluationSummary.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/types/Event.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/types/EventMetadata.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/types/ExampleRevisionInterface.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/types/Experiment.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/types/ExperimentAnnotationSummary.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/types/ExperimentComparison.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/types/ExperimentRun.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/types/ExperimentRunAnnotation.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/types/ExportedFile.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/types/Functionality.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/types/Inferences.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/types/InferencesRole.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/types/MimeType.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/types/Model.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/types/NumericRange.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/types/PerformanceMetric.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/types/Project.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/types/PromptResponse.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/types/Retrieval.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/types/ScalarDriftMetricEnum.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/types/Segments.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/types/SortDir.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/types/SpanAnnotation.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/types/TimeSeries.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/types/TraceAnnotation.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/types/UMAPPoints.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/types/ValidationResult.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/types/VectorDriftMetricEnum.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/types/__init__.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/types/node.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/types/pagination.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/api/utils.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/grpc_server.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/main.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/openapi/__init__.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/prometheus.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/static/apple-touch-icon-114x114.png +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/static/apple-touch-icon-120x120.png +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/static/apple-touch-icon-144x144.png +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/static/apple-touch-icon-152x152.png +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/static/apple-touch-icon-180x180.png +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/static/apple-touch-icon-72x72.png +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/static/apple-touch-icon-76x76.png +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/static/apple-touch-icon.png +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/static/assets/vendor-CP0b0YG0.js +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/static/assets/vendor-DxkFTwjz.css +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/static/assets/vendor-codemirror-DtdPDzrv.js +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/static/assets/vendor-recharts-A0DA1O99.js +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/static/assets/vendor-three-DwGkEfCM.js +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/static/favicon.ico +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/static/modernizr.js +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/telemetry.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/templates/__init__.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/templates/index.html +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/thread_server.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/server/types.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/services.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/session/__init__.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/session/client.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/session/data_extractor.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/session/evaluation.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/session/session.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/settings.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/trace/__init__.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/trace/attributes.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/trace/dsl/README.md +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/trace/dsl/__init__.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/trace/dsl/helpers.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/trace/dsl/query.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/trace/errors.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/trace/evaluation_conventions.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/trace/exporter.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/trace/fixtures.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/trace/langchain/__init__.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/trace/langchain/instrumentor.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/trace/llama_index/__init__.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/trace/llama_index/callback.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/trace/openai/__init__.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/trace/openai/instrumentor.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/trace/otel.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/trace/projects.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/trace/schemas.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/trace/span_evaluations.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/trace/span_json_decoder.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/trace/span_json_encoder.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/trace/trace_dataset.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/trace/utils.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/trace/v1/__init__.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/trace/v1/evaluation_pb2.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/trace/v1/evaluation_pb2.pyi +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/utilities/__init__.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/utilities/client.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/utilities/deprecation.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/utilities/error_handling.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/utilities/json.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/utilities/logging.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/utilities/project.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.0}/src/phoenix/utilities/re.py +0 -0
- {arize_phoenix-4.15.0 → arize_phoenix-4.16.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: 4.
|
|
3
|
+
Version: 4.16.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
|
|
@@ -72,6 +72,7 @@ Requires-Dist: anthropic; extra == 'dev'
|
|
|
72
72
|
Requires-Dist: arize[autoembeddings,llm-evaluation]; extra == 'dev'
|
|
73
73
|
Requires-Dist: asgi-lifespan; extra == 'dev'
|
|
74
74
|
Requires-Dist: asyncpg; extra == 'dev'
|
|
75
|
+
Requires-Dist: faker>=26.0.0; extra == 'dev'
|
|
75
76
|
Requires-Dist: gcsfs; extra == 'dev'
|
|
76
77
|
Requires-Dist: google-cloud-aiplatform>=1.3; extra == 'dev'
|
|
77
78
|
Requires-Dist: hatch; extra == 'dev'
|
|
@@ -93,6 +93,7 @@ dev = [
|
|
|
93
93
|
"anthropic",
|
|
94
94
|
"prometheus_client",
|
|
95
95
|
"asgi-lifespan",
|
|
96
|
+
"Faker>=26.0.0",
|
|
96
97
|
]
|
|
97
98
|
evals = []
|
|
98
99
|
experimental = []
|
|
@@ -171,6 +172,7 @@ dependencies = [
|
|
|
171
172
|
"nest-asyncio", # for executor testing
|
|
172
173
|
"astunparse; python_version<'3.9'", # `ast.unparse(...)` is only available starting with Python 3.9
|
|
173
174
|
"asgi-lifespan",
|
|
175
|
+
"Faker>=26.0.0",
|
|
174
176
|
]
|
|
175
177
|
|
|
176
178
|
[tool.hatch.envs.type]
|
|
@@ -1,26 +1,36 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import logging
|
|
3
|
-
from asyncio import Queue
|
|
3
|
+
from asyncio import Queue, as_completed
|
|
4
|
+
from collections import defaultdict
|
|
4
5
|
from dataclasses import dataclass, field
|
|
5
6
|
from datetime import datetime, timezone
|
|
7
|
+
from functools import singledispatchmethod
|
|
6
8
|
from itertools import islice
|
|
7
9
|
from time import perf_counter
|
|
8
10
|
from typing import (
|
|
9
11
|
Any,
|
|
10
12
|
Awaitable,
|
|
11
13
|
Callable,
|
|
14
|
+
DefaultDict,
|
|
15
|
+
Dict,
|
|
12
16
|
Iterable,
|
|
13
17
|
List,
|
|
18
|
+
Mapping,
|
|
14
19
|
Optional,
|
|
15
20
|
Set,
|
|
16
21
|
Tuple,
|
|
22
|
+
Type,
|
|
17
23
|
cast,
|
|
18
24
|
)
|
|
19
25
|
|
|
20
26
|
from cachetools import LRUCache
|
|
27
|
+
from sqlalchemy import Select, select
|
|
21
28
|
from typing_extensions import TypeAlias
|
|
22
29
|
|
|
23
30
|
import phoenix.trace.v1 as pb
|
|
31
|
+
from phoenix.db import models
|
|
32
|
+
from phoenix.db.insertion.constants import DEFAULT_RETRY_ALLOWANCE, DEFAULT_RETRY_DELAY_SEC
|
|
33
|
+
from phoenix.db.insertion.document_annotation import DocumentAnnotationQueueInserter
|
|
24
34
|
from phoenix.db.insertion.evaluation import (
|
|
25
35
|
EvaluationInsertionEvent,
|
|
26
36
|
InsertEvaluationError,
|
|
@@ -28,6 +38,9 @@ from phoenix.db.insertion.evaluation import (
|
|
|
28
38
|
)
|
|
29
39
|
from phoenix.db.insertion.helpers import DataManipulation, DataManipulationEvent
|
|
30
40
|
from phoenix.db.insertion.span import SpanInsertionEvent, insert_span
|
|
41
|
+
from phoenix.db.insertion.span_annotation import SpanAnnotationQueueInserter
|
|
42
|
+
from phoenix.db.insertion.trace_annotation import TraceAnnotationQueueInserter
|
|
43
|
+
from phoenix.db.insertion.types import Insertables, Precursors
|
|
31
44
|
from phoenix.server.api.dataloaders import CacheForDataLoaders
|
|
32
45
|
from phoenix.server.types import DbSessionFactory
|
|
33
46
|
from phoenix.trace.schemas import Span
|
|
@@ -55,6 +68,8 @@ class BulkInserter:
|
|
|
55
68
|
max_ops_per_transaction: int = 1000,
|
|
56
69
|
max_queue_size: int = 1000,
|
|
57
70
|
enable_prometheus: bool = False,
|
|
71
|
+
retry_delay_sec: float = DEFAULT_RETRY_DELAY_SEC,
|
|
72
|
+
retry_allowance: int = DEFAULT_RETRY_ALLOWANCE,
|
|
58
73
|
) -> None:
|
|
59
74
|
"""
|
|
60
75
|
:param db: A function to initiate a new database session.
|
|
@@ -81,6 +96,9 @@ class BulkInserter:
|
|
|
81
96
|
self._last_updated_at_by_project: LRUCache[ProjectRowId, datetime] = LRUCache(maxsize=100)
|
|
82
97
|
self._cache_for_dataloaders = cache_for_dataloaders
|
|
83
98
|
self._enable_prometheus = enable_prometheus
|
|
99
|
+
self._retry_delay_sec = retry_delay_sec
|
|
100
|
+
self._retry_allowance = retry_allowance
|
|
101
|
+
self._queue_inserters = _QueueInserters(db, self._retry_delay_sec, self._retry_allowance)
|
|
84
102
|
|
|
85
103
|
def last_updated_at(self, project_rowid: Optional[ProjectRowId] = None) -> Optional[datetime]:
|
|
86
104
|
if isinstance(project_rowid, ProjectRowId):
|
|
@@ -90,6 +108,7 @@ class BulkInserter:
|
|
|
90
108
|
async def __aenter__(
|
|
91
109
|
self,
|
|
92
110
|
) -> Tuple[
|
|
111
|
+
Callable[[Any], Awaitable[None]],
|
|
93
112
|
Callable[[Span, str], Awaitable[None]],
|
|
94
113
|
Callable[[pb.Evaluation], Awaitable[None]],
|
|
95
114
|
Callable[[DataManipulation], None],
|
|
@@ -98,6 +117,7 @@ class BulkInserter:
|
|
|
98
117
|
self._operations = Queue(maxsize=self._max_queue_size)
|
|
99
118
|
self._task = asyncio.create_task(self._bulk_insert())
|
|
100
119
|
return (
|
|
120
|
+
self._enqueue,
|
|
101
121
|
self._queue_span,
|
|
102
122
|
self._queue_evaluation,
|
|
103
123
|
self._enqueue_operation,
|
|
@@ -109,6 +129,9 @@ class BulkInserter:
|
|
|
109
129
|
self._task.cancel()
|
|
110
130
|
self._task = None
|
|
111
131
|
|
|
132
|
+
async def _enqueue(self, *items: Any) -> None:
|
|
133
|
+
await self._queue_inserters.enqueue(*items)
|
|
134
|
+
|
|
112
135
|
def _enqueue_operation(self, operation: DataManipulation) -> None:
|
|
113
136
|
cast("Queue[DataManipulation]", self._operations).put_nowait(operation)
|
|
114
137
|
|
|
@@ -124,7 +147,17 @@ class BulkInserter:
|
|
|
124
147
|
assert isinstance(self._operations, Queue)
|
|
125
148
|
spans_buffer, evaluations_buffer = None, None
|
|
126
149
|
# start first insert immediately if the inserter has not run recently
|
|
127
|
-
while
|
|
150
|
+
while (
|
|
151
|
+
self._running
|
|
152
|
+
or not self._queue_inserters.empty
|
|
153
|
+
or not self._operations.empty()
|
|
154
|
+
or self._spans
|
|
155
|
+
or self._evaluations
|
|
156
|
+
):
|
|
157
|
+
if not self._queue_inserters.empty:
|
|
158
|
+
if inserted_ids := await self._queue_inserters.insert():
|
|
159
|
+
for project_rowid in await self._get_project_rowids(inserted_ids):
|
|
160
|
+
self._last_updated_at_by_project[project_rowid] = datetime.now(timezone.utc)
|
|
128
161
|
if self._operations.empty() and not (self._spans or self._evaluations):
|
|
129
162
|
await asyncio.sleep(self._sleep)
|
|
130
163
|
continue
|
|
@@ -244,3 +277,97 @@ class BulkInserter:
|
|
|
244
277
|
BULK_LOADER_EXCEPTIONS.inc()
|
|
245
278
|
logger.exception("Failed to insert evaluations")
|
|
246
279
|
return transaction_result
|
|
280
|
+
|
|
281
|
+
async def _get_project_rowids(
|
|
282
|
+
self,
|
|
283
|
+
inserted_ids: Mapping[Type[models.Base], List[int]],
|
|
284
|
+
) -> Set[int]:
|
|
285
|
+
ans: Set[int] = set()
|
|
286
|
+
if not inserted_ids:
|
|
287
|
+
return ans
|
|
288
|
+
stmt: Select[Tuple[int]]
|
|
289
|
+
for table, ids in inserted_ids.items():
|
|
290
|
+
if not ids:
|
|
291
|
+
continue
|
|
292
|
+
if issubclass(table, models.SpanAnnotation):
|
|
293
|
+
stmt = (
|
|
294
|
+
select(models.Project.id)
|
|
295
|
+
.join(models.Trace)
|
|
296
|
+
.join_from(models.Trace, models.Span)
|
|
297
|
+
.join_from(models.Span, models.SpanAnnotation)
|
|
298
|
+
.where(models.SpanAnnotation.id.in_(ids))
|
|
299
|
+
)
|
|
300
|
+
elif issubclass(table, models.DocumentAnnotation):
|
|
301
|
+
stmt = (
|
|
302
|
+
select(models.Project.id)
|
|
303
|
+
.join(models.Trace)
|
|
304
|
+
.join_from(models.Trace, models.Span)
|
|
305
|
+
.join_from(models.Span, models.DocumentAnnotation)
|
|
306
|
+
.where(models.DocumentAnnotation.id.in_(ids))
|
|
307
|
+
)
|
|
308
|
+
elif issubclass(table, models.TraceAnnotation):
|
|
309
|
+
stmt = (
|
|
310
|
+
select(models.Project.id)
|
|
311
|
+
.join(models.Trace)
|
|
312
|
+
.join_from(models.Trace, models.TraceAnnotation)
|
|
313
|
+
.where(models.TraceAnnotation.id.in_(ids))
|
|
314
|
+
)
|
|
315
|
+
else:
|
|
316
|
+
continue
|
|
317
|
+
async with self._db() as session:
|
|
318
|
+
project_rowids = [_ async for _ in await session.stream_scalars(stmt)]
|
|
319
|
+
ans.update(project_rowids)
|
|
320
|
+
return ans
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
class _QueueInserters:
|
|
324
|
+
def __init__(
|
|
325
|
+
self,
|
|
326
|
+
db: DbSessionFactory,
|
|
327
|
+
retry_delay_sec: float = DEFAULT_RETRY_DELAY_SEC,
|
|
328
|
+
retry_allowance: int = DEFAULT_RETRY_ALLOWANCE,
|
|
329
|
+
) -> None:
|
|
330
|
+
self._db = db
|
|
331
|
+
args = (db, retry_delay_sec, retry_allowance)
|
|
332
|
+
self._span_annotations = SpanAnnotationQueueInserter(*args)
|
|
333
|
+
self._trace_annotations = TraceAnnotationQueueInserter(*args)
|
|
334
|
+
self._document_annotations = DocumentAnnotationQueueInserter(*args)
|
|
335
|
+
self._queues = (
|
|
336
|
+
self._span_annotations,
|
|
337
|
+
self._trace_annotations,
|
|
338
|
+
self._document_annotations,
|
|
339
|
+
)
|
|
340
|
+
|
|
341
|
+
async def insert(self) -> Dict[Type[models.Base], List[int]]:
|
|
342
|
+
ans: DefaultDict[Type[models.Base], List[int]] = defaultdict(list)
|
|
343
|
+
for coro in as_completed([q.insert() for q in self._queues]):
|
|
344
|
+
table, inserted_ids = await coro
|
|
345
|
+
if inserted_ids:
|
|
346
|
+
ans[table].extend(inserted_ids)
|
|
347
|
+
return ans
|
|
348
|
+
|
|
349
|
+
@property
|
|
350
|
+
def empty(self) -> bool:
|
|
351
|
+
return all(q.empty for q in self._queues)
|
|
352
|
+
|
|
353
|
+
async def enqueue(self, *items: Any) -> None:
|
|
354
|
+
for item in items:
|
|
355
|
+
await self._enqueue(item)
|
|
356
|
+
|
|
357
|
+
@singledispatchmethod
|
|
358
|
+
async def _enqueue(self, item: Any) -> None: ...
|
|
359
|
+
|
|
360
|
+
@_enqueue.register(Precursors.SpanAnnotation)
|
|
361
|
+
@_enqueue.register(Insertables.SpanAnnotation)
|
|
362
|
+
async def _(self, item: Precursors.SpanAnnotation) -> None:
|
|
363
|
+
await self._span_annotations.enqueue(item)
|
|
364
|
+
|
|
365
|
+
@_enqueue.register(Precursors.TraceAnnotation)
|
|
366
|
+
@_enqueue.register(Insertables.TraceAnnotation)
|
|
367
|
+
async def _(self, item: Precursors.TraceAnnotation) -> None:
|
|
368
|
+
await self._trace_annotations.enqueue(item)
|
|
369
|
+
|
|
370
|
+
@_enqueue.register(Precursors.DocumentAnnotation)
|
|
371
|
+
@_enqueue.register(Insertables.DocumentAnnotation)
|
|
372
|
+
async def _(self, item: Precursors.DocumentAnnotation) -> None:
|
|
373
|
+
await self._document_annotations.enqueue(item)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from enum import Enum
|
|
2
|
-
from typing import Any, Optional, Tuple
|
|
2
|
+
from typing import Any, Callable, Hashable, Iterable, List, Optional, Set, Tuple, TypeVar
|
|
3
3
|
|
|
4
4
|
from openinference.semconv.trace import (
|
|
5
5
|
OpenInferenceSpanKindValues,
|
|
@@ -80,3 +80,25 @@ def get_project_names_for_experiments(*experiment_ids: int) -> Select[Tuple[Opti
|
|
|
80
80
|
.where(models.Experiment.id.in_(set(experiment_ids)))
|
|
81
81
|
.where(models.Experiment.project_name.isnot(None))
|
|
82
82
|
)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
_AnyT = TypeVar("_AnyT")
|
|
86
|
+
_KeyT = TypeVar("_KeyT", bound=Hashable)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def dedup(
|
|
90
|
+
items: Iterable[_AnyT],
|
|
91
|
+
key: Callable[[_AnyT], _KeyT],
|
|
92
|
+
) -> List[_AnyT]:
|
|
93
|
+
"""
|
|
94
|
+
Discard subsequent duplicates after the first appearance in `items`.
|
|
95
|
+
"""
|
|
96
|
+
ans = []
|
|
97
|
+
seen: Set[_KeyT] = set()
|
|
98
|
+
for item in items:
|
|
99
|
+
if (k := key(item)) in seen:
|
|
100
|
+
continue
|
|
101
|
+
else:
|
|
102
|
+
ans.append(item)
|
|
103
|
+
seen.add(k)
|
|
104
|
+
return ans
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
from typing import Any, List, Mapping, NamedTuple, Optional, Tuple
|
|
3
|
+
|
|
4
|
+
from sqlalchemy import Row, Select, and_, select, tuple_
|
|
5
|
+
from sqlalchemy.ext.asyncio import AsyncSession
|
|
6
|
+
from typing_extensions import TypeAlias
|
|
7
|
+
|
|
8
|
+
from phoenix.db import models
|
|
9
|
+
from phoenix.db.helpers import dedup, num_docs_col
|
|
10
|
+
from phoenix.db.insertion.types import (
|
|
11
|
+
Insertables,
|
|
12
|
+
Postponed,
|
|
13
|
+
Precursors,
|
|
14
|
+
QueueInserter,
|
|
15
|
+
Received,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
_Name: TypeAlias = str
|
|
19
|
+
_SpanId: TypeAlias = str
|
|
20
|
+
_SpanRowId: TypeAlias = int
|
|
21
|
+
_DocumentPosition: TypeAlias = int
|
|
22
|
+
_AnnoRowId: TypeAlias = int
|
|
23
|
+
_NumDocs: TypeAlias = int
|
|
24
|
+
|
|
25
|
+
_Key: TypeAlias = Tuple[_Name, _SpanId, _DocumentPosition]
|
|
26
|
+
_UniqueBy: TypeAlias = Tuple[_Name, _SpanRowId, _DocumentPosition]
|
|
27
|
+
_Existing: TypeAlias = Tuple[
|
|
28
|
+
_SpanRowId,
|
|
29
|
+
_SpanId,
|
|
30
|
+
_NumDocs,
|
|
31
|
+
Optional[_AnnoRowId],
|
|
32
|
+
Optional[_Name],
|
|
33
|
+
Optional[_DocumentPosition],
|
|
34
|
+
Optional[datetime],
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class DocumentAnnotationQueueInserter(
|
|
39
|
+
QueueInserter[
|
|
40
|
+
Precursors.DocumentAnnotation,
|
|
41
|
+
Insertables.DocumentAnnotation,
|
|
42
|
+
models.DocumentAnnotation,
|
|
43
|
+
],
|
|
44
|
+
table=models.DocumentAnnotation,
|
|
45
|
+
unique_by=("name", "span_rowid", "document_position"),
|
|
46
|
+
):
|
|
47
|
+
async def _partition(
|
|
48
|
+
self,
|
|
49
|
+
session: AsyncSession,
|
|
50
|
+
*parcels: Received[Precursors.DocumentAnnotation],
|
|
51
|
+
) -> Tuple[
|
|
52
|
+
List[Received[Insertables.DocumentAnnotation]],
|
|
53
|
+
List[Postponed[Precursors.DocumentAnnotation]],
|
|
54
|
+
List[Received[Precursors.DocumentAnnotation]],
|
|
55
|
+
]:
|
|
56
|
+
to_insert: List[Received[Insertables.DocumentAnnotation]] = []
|
|
57
|
+
to_postpone: List[Postponed[Precursors.DocumentAnnotation]] = []
|
|
58
|
+
to_discard: List[Received[Precursors.DocumentAnnotation]] = []
|
|
59
|
+
|
|
60
|
+
stmt = self._select_existing(*map(_key, parcels))
|
|
61
|
+
existing: List[Row[_Existing]] = [_ async for _ in await session.stream(stmt)]
|
|
62
|
+
existing_spans: Mapping[str, _SpanAttr] = {
|
|
63
|
+
e.span_id: _SpanAttr(e.span_rowid, e.num_docs) for e in existing
|
|
64
|
+
}
|
|
65
|
+
existing_annos: Mapping[_Key, _AnnoAttr] = {
|
|
66
|
+
(e.name, e.span_id, e.document_position): _AnnoAttr(e.span_rowid, e.id, e.updated_at)
|
|
67
|
+
for e in existing
|
|
68
|
+
if e.id is not None
|
|
69
|
+
and e.name is not None
|
|
70
|
+
and e.document_position is not None
|
|
71
|
+
and e.updated_at is not None
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
for p in parcels:
|
|
75
|
+
if (anno := existing_annos.get(_key(p))) is not None:
|
|
76
|
+
if p.received_at <= anno.updated_at:
|
|
77
|
+
to_discard.append(p)
|
|
78
|
+
else:
|
|
79
|
+
to_insert.append(
|
|
80
|
+
Received(
|
|
81
|
+
received_at=p.received_at,
|
|
82
|
+
item=p.item.as_insertable(
|
|
83
|
+
span_rowid=anno.span_rowid,
|
|
84
|
+
id_=anno.id_,
|
|
85
|
+
),
|
|
86
|
+
)
|
|
87
|
+
)
|
|
88
|
+
elif (span := existing_spans.get(p.item.span_id)) is not None:
|
|
89
|
+
if 0 <= p.item.document_position < span.num_docs:
|
|
90
|
+
to_insert.append(
|
|
91
|
+
Received(
|
|
92
|
+
received_at=p.received_at,
|
|
93
|
+
item=p.item.as_insertable(
|
|
94
|
+
span_rowid=span.span_rowid,
|
|
95
|
+
),
|
|
96
|
+
)
|
|
97
|
+
)
|
|
98
|
+
else:
|
|
99
|
+
to_discard.append(p)
|
|
100
|
+
elif isinstance(p, Postponed):
|
|
101
|
+
if p.retries_left > 1:
|
|
102
|
+
to_postpone.append(p.postpone(p.retries_left - 1))
|
|
103
|
+
else:
|
|
104
|
+
to_discard.append(p)
|
|
105
|
+
elif isinstance(p, Received):
|
|
106
|
+
to_postpone.append(p.postpone(self._retry_allowance))
|
|
107
|
+
else:
|
|
108
|
+
to_discard.append(p)
|
|
109
|
+
|
|
110
|
+
assert len(to_insert) + len(to_postpone) + len(to_discard) == len(parcels)
|
|
111
|
+
to_insert = dedup(sorted(to_insert, key=_time, reverse=True), _unique_by)[::-1]
|
|
112
|
+
return to_insert, to_postpone, to_discard
|
|
113
|
+
|
|
114
|
+
def _select_existing(self, *keys: _Key) -> Select[_Existing]:
|
|
115
|
+
anno = self.table
|
|
116
|
+
span = (
|
|
117
|
+
select(models.Span.id, models.Span.span_id, num_docs_col(self._db.dialect))
|
|
118
|
+
.where(models.Span.span_id.in_({span_id for _, span_id, *_ in keys}))
|
|
119
|
+
.cte()
|
|
120
|
+
)
|
|
121
|
+
onclause = and_(
|
|
122
|
+
span.c.id == anno.span_rowid,
|
|
123
|
+
anno.name.in_({name for name, *_ in keys}),
|
|
124
|
+
tuple_(anno.name, span.c.span_id, anno.document_position).in_(keys),
|
|
125
|
+
)
|
|
126
|
+
return select(
|
|
127
|
+
span.c.id.label("span_rowid"),
|
|
128
|
+
span.c.span_id,
|
|
129
|
+
span.c.num_docs,
|
|
130
|
+
anno.id,
|
|
131
|
+
anno.name,
|
|
132
|
+
anno.document_position,
|
|
133
|
+
anno.updated_at,
|
|
134
|
+
).outerjoin_from(span, anno, onclause)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
class _SpanAttr(NamedTuple):
|
|
138
|
+
span_rowid: _SpanRowId
|
|
139
|
+
num_docs: _NumDocs
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
class _AnnoAttr(NamedTuple):
|
|
143
|
+
span_rowid: _SpanRowId
|
|
144
|
+
id_: _AnnoRowId
|
|
145
|
+
updated_at: datetime
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def _key(p: Received[Precursors.DocumentAnnotation]) -> _Key:
|
|
149
|
+
return p.item.obj.name, p.item.span_id, p.item.document_position
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def _unique_by(p: Received[Insertables.DocumentAnnotation]) -> _UniqueBy:
|
|
153
|
+
return p.item.obj.name, p.item.span_rowid, p.item.document_position
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def _time(p: Received[Any]) -> datetime:
|
|
157
|
+
return p.received_at
|
|
@@ -20,6 +20,7 @@ from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
20
20
|
from sqlalchemy.sql.elements import KeyedColumnElement
|
|
21
21
|
from typing_extensions import TypeAlias, assert_never
|
|
22
22
|
|
|
23
|
+
from phoenix.db import models
|
|
23
24
|
from phoenix.db.helpers import SupportedSQLDialect
|
|
24
25
|
from phoenix.db.models import Base
|
|
25
26
|
|
|
@@ -93,3 +94,15 @@ def _clean(
|
|
|
93
94
|
yield "metadata", v
|
|
94
95
|
else:
|
|
95
96
|
yield k, v
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def as_kv(obj: models.Base) -> Iterator[Tuple[str, Any]]:
|
|
100
|
+
for k, c in obj.__table__.c.items():
|
|
101
|
+
if k in ["created_at", "updated_at"]:
|
|
102
|
+
continue
|
|
103
|
+
k = "metadata_" if k == "metadata" else k
|
|
104
|
+
v = getattr(obj, k, None)
|
|
105
|
+
if c.primary_key and v is None:
|
|
106
|
+
# postgresql disallows None for primary key
|
|
107
|
+
continue
|
|
108
|
+
yield k, v
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
from typing import Any, List, Mapping, NamedTuple, Optional, Tuple
|
|
3
|
+
|
|
4
|
+
from sqlalchemy import Row, Select, and_, select, tuple_
|
|
5
|
+
from sqlalchemy.ext.asyncio import AsyncSession
|
|
6
|
+
from typing_extensions import TypeAlias
|
|
7
|
+
|
|
8
|
+
from phoenix.db import models
|
|
9
|
+
from phoenix.db.helpers import dedup
|
|
10
|
+
from phoenix.db.insertion.types import (
|
|
11
|
+
Insertables,
|
|
12
|
+
Postponed,
|
|
13
|
+
Precursors,
|
|
14
|
+
QueueInserter,
|
|
15
|
+
Received,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
_Name: TypeAlias = str
|
|
19
|
+
_SpanId: TypeAlias = str
|
|
20
|
+
_SpanRowId: TypeAlias = int
|
|
21
|
+
_AnnoRowId: TypeAlias = int
|
|
22
|
+
|
|
23
|
+
_Key: TypeAlias = Tuple[_Name, _SpanId]
|
|
24
|
+
_UniqueBy: TypeAlias = Tuple[_Name, _SpanRowId]
|
|
25
|
+
_Existing: TypeAlias = Tuple[
|
|
26
|
+
_SpanRowId,
|
|
27
|
+
_SpanId,
|
|
28
|
+
Optional[_AnnoRowId],
|
|
29
|
+
Optional[_Name],
|
|
30
|
+
Optional[datetime],
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class SpanAnnotationQueueInserter(
|
|
35
|
+
QueueInserter[
|
|
36
|
+
Precursors.SpanAnnotation,
|
|
37
|
+
Insertables.SpanAnnotation,
|
|
38
|
+
models.SpanAnnotation,
|
|
39
|
+
],
|
|
40
|
+
table=models.SpanAnnotation,
|
|
41
|
+
unique_by=("name", "span_rowid"),
|
|
42
|
+
):
|
|
43
|
+
async def _partition(
|
|
44
|
+
self,
|
|
45
|
+
session: AsyncSession,
|
|
46
|
+
*parcels: Received[Precursors.SpanAnnotation],
|
|
47
|
+
) -> Tuple[
|
|
48
|
+
List[Received[Insertables.SpanAnnotation]],
|
|
49
|
+
List[Postponed[Precursors.SpanAnnotation]],
|
|
50
|
+
List[Received[Precursors.SpanAnnotation]],
|
|
51
|
+
]:
|
|
52
|
+
to_insert: List[Received[Insertables.SpanAnnotation]] = []
|
|
53
|
+
to_postpone: List[Postponed[Precursors.SpanAnnotation]] = []
|
|
54
|
+
to_discard: List[Received[Precursors.SpanAnnotation]] = []
|
|
55
|
+
|
|
56
|
+
stmt = self._select_existing(*map(_key, parcels))
|
|
57
|
+
existing: List[Row[_Existing]] = [_ async for _ in await session.stream(stmt)]
|
|
58
|
+
existing_spans: Mapping[str, _SpanAttr] = {
|
|
59
|
+
e.span_id: _SpanAttr(e.span_rowid) for e in existing
|
|
60
|
+
}
|
|
61
|
+
existing_annos: Mapping[_Key, _AnnoAttr] = {
|
|
62
|
+
(e.name, e.span_id): _AnnoAttr(e.span_rowid, e.id, e.updated_at)
|
|
63
|
+
for e in existing
|
|
64
|
+
if e.id is not None and e.name is not None and e.updated_at is not None
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
for p in parcels:
|
|
68
|
+
if (anno := existing_annos.get(_key(p))) is not None:
|
|
69
|
+
if p.received_at <= anno.updated_at:
|
|
70
|
+
to_discard.append(p)
|
|
71
|
+
else:
|
|
72
|
+
to_insert.append(
|
|
73
|
+
Received(
|
|
74
|
+
received_at=p.received_at,
|
|
75
|
+
item=p.item.as_insertable(
|
|
76
|
+
span_rowid=anno.span_rowid,
|
|
77
|
+
id_=anno.id_,
|
|
78
|
+
),
|
|
79
|
+
)
|
|
80
|
+
)
|
|
81
|
+
elif (span := existing_spans.get(p.item.span_id)) is not None:
|
|
82
|
+
to_insert.append(
|
|
83
|
+
Received(
|
|
84
|
+
received_at=p.received_at,
|
|
85
|
+
item=p.item.as_insertable(
|
|
86
|
+
span_rowid=span.span_rowid,
|
|
87
|
+
),
|
|
88
|
+
)
|
|
89
|
+
)
|
|
90
|
+
elif isinstance(p, Postponed):
|
|
91
|
+
if p.retries_left > 1:
|
|
92
|
+
to_postpone.append(p.postpone(p.retries_left - 1))
|
|
93
|
+
else:
|
|
94
|
+
to_discard.append(p)
|
|
95
|
+
elif isinstance(p, Received):
|
|
96
|
+
to_postpone.append(p.postpone(self._retry_allowance))
|
|
97
|
+
else:
|
|
98
|
+
to_discard.append(p)
|
|
99
|
+
|
|
100
|
+
assert len(to_insert) + len(to_postpone) + len(to_discard) == len(parcels)
|
|
101
|
+
to_insert = dedup(sorted(to_insert, key=_time, reverse=True), _unique_by)[::-1]
|
|
102
|
+
return to_insert, to_postpone, to_discard
|
|
103
|
+
|
|
104
|
+
def _select_existing(self, *keys: _Key) -> Select[_Existing]:
|
|
105
|
+
anno = self.table
|
|
106
|
+
span = (
|
|
107
|
+
select(models.Span.id, models.Span.span_id)
|
|
108
|
+
.where(models.Span.span_id.in_({span_id for _, span_id in keys}))
|
|
109
|
+
.cte()
|
|
110
|
+
)
|
|
111
|
+
onclause = and_(
|
|
112
|
+
span.c.id == anno.span_rowid,
|
|
113
|
+
anno.name.in_({name for name, _ in keys}),
|
|
114
|
+
tuple_(anno.name, span.c.span_id).in_(keys),
|
|
115
|
+
)
|
|
116
|
+
return select(
|
|
117
|
+
span.c.id.label("span_rowid"),
|
|
118
|
+
span.c.span_id,
|
|
119
|
+
anno.id,
|
|
120
|
+
anno.name,
|
|
121
|
+
anno.updated_at,
|
|
122
|
+
).outerjoin_from(span, anno, onclause)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
class _SpanAttr(NamedTuple):
|
|
126
|
+
span_rowid: _SpanRowId
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
class _AnnoAttr(NamedTuple):
|
|
130
|
+
span_rowid: _SpanRowId
|
|
131
|
+
id_: _AnnoRowId
|
|
132
|
+
updated_at: datetime
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def _key(p: Received[Precursors.SpanAnnotation]) -> _Key:
|
|
136
|
+
return p.item.obj.name, p.item.span_id
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def _unique_by(p: Received[Insertables.SpanAnnotation]) -> _UniqueBy:
|
|
140
|
+
return p.item.obj.name, p.item.span_rowid
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def _time(p: Received[Any]) -> datetime:
|
|
144
|
+
return p.received_at
|