arize-phoenix 4.24.0__tar.gz → 4.25.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.24.0 → arize_phoenix-4.25.0}/.gitignore +3 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/PKG-INFO +10 -6
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/README.md +1 -2
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/examples/manually-instrumented-chatbot/frontend/requirements.txt +1 -1
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/pyproject.toml +18 -13
- arize_phoenix-4.25.0/src/phoenix/auth/utils.py +15 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/db/engines.py +15 -2
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/db/insertion/dataset.py +1 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/db/migrate.py +21 -10
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/db/migrations/future_versions/cd164e83824f_users_and_tokens.py +7 -6
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/db/migrations/versions/3be8647b87d8_add_token_columns_to_spans_table.py +4 -12
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/db/models.py +1 -1
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/inferences/fixtures.py +1 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/inferences/inferences.py +1 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/metrics/__init__.py +1 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/context.py +14 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/mutations/__init__.py +2 -0
- arize_phoenix-4.25.0/src/phoenix/server/api/mutations/api_key_mutations.py +119 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/mutations/auth.py +7 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/queries.py +7 -6
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/routers/v1/datasets.py +1 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/routers/v1/spans.py +1 -1
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/types/UserRole.py +1 -1
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/app.py +36 -7
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/main.py +24 -19
- arize_phoenix-4.25.0/src/phoenix/server/static/.vite/manifest.json +78 -0
- arize_phoenix-4.24.0/src/phoenix/server/static/assets/components-DzA9gIHT.js → arize_phoenix-4.25.0/src/phoenix/server/static/assets/components-1Ahruijo.js +4 -4
- arize_phoenix-4.24.0/src/phoenix/server/static/assets/index-BuTlV4Gk.js → arize_phoenix-4.25.0/src/phoenix/server/static/assets/index-BEE_RWJx.js +2 -2
- arize_phoenix-4.24.0/src/phoenix/server/static/assets/pages-DzkUGFGV.js → arize_phoenix-4.25.0/src/phoenix/server/static/assets/pages-CFS6mPnW.js +263 -220
- arize_phoenix-4.24.0/src/phoenix/server/static/assets/vendor-CIqy43_9.js → arize_phoenix-4.25.0/src/phoenix/server/static/assets/vendor-aSQri0vz.js +58 -58
- arize_phoenix-4.24.0/src/phoenix/server/static/assets/vendor-arizeai-B1YgcWL8.js → arize_phoenix-4.25.0/src/phoenix/server/static/assets/vendor-arizeai-CsdcB1NH.js +1 -1
- arize_phoenix-4.24.0/src/phoenix/server/static/assets/vendor-codemirror-_bcwCA1C.js → arize_phoenix-4.25.0/src/phoenix/server/static/assets/vendor-codemirror-CYHkhs7D.js +1 -1
- arize_phoenix-4.24.0/src/phoenix/server/static/assets/vendor-recharts-C3pM_Wlg.js → arize_phoenix-4.25.0/src/phoenix/server/static/assets/vendor-recharts-B0sannek.js +1 -1
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/types.py +12 -4
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/services.py +1 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/session/client.py +1 -1
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/session/evaluation.py +1 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/session/session.py +2 -1
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/trace/fixtures.py +37 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/trace/langchain/instrumentor.py +1 -1
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/trace/llama_index/callback.py +1 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/trace/openai/instrumentor.py +1 -0
- arize_phoenix-4.25.0/src/phoenix/utilities/span_store.py +0 -0
- arize_phoenix-4.25.0/src/phoenix/version.py +1 -0
- arize_phoenix-4.24.0/src/phoenix/server/static/.vite/manifest.json +0 -78
- arize_phoenix-4.24.0/src/phoenix/version.py +0 -1
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/IP_NOTICE +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/LICENSE +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/examples/manually-instrumented-chatbot/chat-service/chat/__init__.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/examples/manually-instrumented-chatbot/chat-service/chat/app.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/examples/manually-instrumented-chatbot/chat-service/chat/types.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/examples/manually-instrumented-chatbot/frontend/Dockerfile +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/examples/manually-instrumented-chatbot/frontend/Makefile +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/examples/manually-instrumented-chatbot/frontend/__init__.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/examples/manually-instrumented-chatbot/frontend/pyproject.toml +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/examples/manually-instrumented-chatbot/frontend/schema.json +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/__init__.py +0 -0
- {arize_phoenix-4.24.0/src/phoenix/core → arize_phoenix-4.25.0/src/phoenix/auth}/__init__.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/config.py +0 -0
- {arize_phoenix-4.24.0/src/phoenix/db/insertion → arize_phoenix-4.25.0/src/phoenix/core}/__init__.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/core/embedding_dimension.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/core/model.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/core/model_schema.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/core/model_schema_adapter.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/datetime_utils.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/db/README.md +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/db/__init__.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/db/alembic.ini +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/db/bulk_inserter.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/db/helpers.py +0 -0
- {arize_phoenix-4.24.0/src/phoenix/db/migrations → arize_phoenix-4.25.0/src/phoenix/db/insertion}/__init__.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/db/insertion/constants.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/db/insertion/document_annotation.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/db/insertion/evaluation.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/db/insertion/helpers.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/db/insertion/span.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/db/insertion/span_annotation.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/db/insertion/trace_annotation.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/db/insertion/types.py +0 -0
- {arize_phoenix-4.24.0/src/phoenix/inferences → arize_phoenix-4.25.0/src/phoenix/db/migrations}/__init__.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/db/migrations/env.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/db/migrations/future_versions/README.md +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/db/migrations/script.py.mako +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/db/migrations/versions/.gitignore +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/db/migrations/versions/10460e46d750_datasets.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/db/migrations/versions/cf03bd6bae1d_init.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/exceptions.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/experiments/__init__.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/experiments/evaluators/__init__.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/experiments/evaluators/base.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/experiments/evaluators/code_evaluators.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/experiments/evaluators/llm_evaluators.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/experiments/evaluators/utils.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/experiments/functions.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/experiments/tracing.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/experiments/types.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/experiments/utils.py +0 -0
- {arize_phoenix-4.24.0/src/phoenix/server → arize_phoenix-4.25.0/src/phoenix/inferences}/__init__.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/inferences/errors.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/inferences/schema.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/inferences/validation.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/metrics/README.md +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/metrics/binning.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/metrics/metrics.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/metrics/mixins.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/metrics/retrieval_metrics.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/metrics/timeseries.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/metrics/wrappers.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/pointcloud/__init__.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/pointcloud/clustering.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/pointcloud/pointcloud.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/pointcloud/projectors.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/pointcloud/umap_parameters.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/py.typed +0 -0
- {arize_phoenix-4.24.0/src/phoenix/server/api → arize_phoenix-4.25.0/src/phoenix/server}/__init__.py +0 -0
- {arize_phoenix-4.24.0/src/phoenix/server/api/input_types → arize_phoenix-4.25.0/src/phoenix/server/api}/__init__.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/dataloaders/__init__.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/dataloaders/annotation_summaries.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/dataloaders/average_experiment_run_latency.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/dataloaders/cache/__init__.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/dataloaders/cache/two_tier_cache.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/dataloaders/dataset_example_revisions.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/dataloaders/dataset_example_spans.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/dataloaders/document_evaluation_summaries.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/dataloaders/document_evaluations.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/dataloaders/document_retrieval_metrics.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/dataloaders/experiment_annotation_summaries.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/dataloaders/experiment_error_rates.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/dataloaders/experiment_run_counts.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/dataloaders/experiment_sequence_number.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/dataloaders/latency_ms_quantile.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/dataloaders/min_start_or_max_end_times.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/dataloaders/project_by_name.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/dataloaders/record_counts.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/dataloaders/span_annotations.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/dataloaders/span_dataset_examples.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/dataloaders/span_descendants.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/dataloaders/span_projects.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/dataloaders/token_counts.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/dataloaders/trace_row_ids.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/helpers/__init__.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/helpers/dataset_helpers.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/input_types/AddExamplesToDatasetInput.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/input_types/AddSpansToDatasetInput.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/input_types/ClearProjectInput.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/input_types/ClusterInput.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/input_types/Coordinates.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/input_types/CreateDatasetInput.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/input_types/CreateSpanAnnotationInput.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/input_types/CreateTraceAnnotationInput.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/input_types/DataQualityMetricInput.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/input_types/DatasetExampleInput.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/input_types/DatasetSort.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/input_types/DatasetVersionSort.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/input_types/DeleteAnnotationsInput.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/input_types/DeleteDatasetExamplesInput.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/input_types/DeleteDatasetInput.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/input_types/DeleteExperimentsInput.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/input_types/DimensionFilter.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/input_types/DimensionInput.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/input_types/Granularity.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/input_types/PatchAnnotationInput.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/input_types/PatchDatasetExamplesInput.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/input_types/PatchDatasetInput.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/input_types/PerformanceMetricInput.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/input_types/SpanAnnotationSort.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/input_types/SpanSort.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/input_types/TimeRange.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/input_types/TraceAnnotationSort.py +0 -0
- {arize_phoenix-4.24.0/src/phoenix/server/api/openapi → arize_phoenix-4.25.0/src/phoenix/server/api/input_types}/__init__.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/interceptor.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/mutations/dataset_mutations.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/mutations/experiment_mutations.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/mutations/export_events_mutations.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/mutations/project_mutations.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/mutations/span_annotations_mutations.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/mutations/trace_annotations_mutations.py +0 -0
- {arize_phoenix-4.24.0/src/phoenix/server/api/routers → arize_phoenix-4.25.0/src/phoenix/server/api/openapi}/__init__.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/openapi/main.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/openapi/schema.py +0 -0
- {arize_phoenix-4.24.0/src/phoenix/server/api/types → arize_phoenix-4.25.0/src/phoenix/server/api/routers}/__init__.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/routers/utils.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/routers/v1/__init__.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/routers/v1/evaluations.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/routers/v1/experiment_evaluations.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/routers/v1/experiment_runs.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/routers/v1/experiments.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/routers/v1/pydantic_compat.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/routers/v1/traces.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/routers/v1/utils.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/schema.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/types/Annotation.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/types/AnnotationSummary.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/types/AnnotatorKind.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/types/ApiKey.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/types/Cluster.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/types/CreateDatasetPayload.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/types/DataQualityMetric.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/types/Dataset.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/types/DatasetExample.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/types/DatasetExampleRevision.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/types/DatasetValues.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/types/DatasetVersion.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/types/Dimension.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/types/DimensionDataType.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/types/DimensionShape.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/types/DimensionType.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/types/DimensionWithValue.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/types/DocumentEvaluationSummary.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/types/DocumentRetrievalMetrics.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/types/EmbeddingDimension.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/types/EmbeddingMetadata.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/types/Evaluation.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/types/EvaluationSummary.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/types/Event.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/types/EventMetadata.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/types/ExampleRevisionInterface.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/types/Experiment.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/types/ExperimentAnnotationSummary.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/types/ExperimentComparison.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/types/ExperimentRun.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/types/ExperimentRunAnnotation.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/types/ExportedFile.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/types/Functionality.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/types/Inferences.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/types/InferencesRole.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/types/LabelFraction.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/types/MimeType.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/types/Model.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/types/NumericRange.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/types/PerformanceMetric.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/types/Project.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/types/PromptResponse.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/types/Retrieval.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/types/ScalarDriftMetricEnum.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/types/Segments.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/types/SortDir.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/types/Span.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/types/SpanAnnotation.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/types/SystemApiKey.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/types/TimeSeries.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/types/Trace.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/types/TraceAnnotation.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/types/UMAPPoints.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/types/User.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/types/UserApiKey.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/types/ValidationResult.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/types/VectorDriftMetricEnum.py +0 -0
- {arize_phoenix-4.24.0/src/phoenix/server/openapi → arize_phoenix-4.25.0/src/phoenix/server/api/types}/__init__.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/types/node.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/types/pagination.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/api/utils.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/dml_event.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/dml_event_handler.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/grpc_server.py +0 -0
- {arize_phoenix-4.24.0/src/phoenix/server/templates → arize_phoenix-4.25.0/src/phoenix/server/openapi}/__init__.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/prometheus.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/static/apple-touch-icon-114x114.png +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/static/apple-touch-icon-120x120.png +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/static/apple-touch-icon-144x144.png +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/static/apple-touch-icon-152x152.png +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/static/apple-touch-icon-180x180.png +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/static/apple-touch-icon-72x72.png +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/static/apple-touch-icon-76x76.png +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/static/apple-touch-icon.png +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/static/assets/vendor-DxkFTwjz.css +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/static/assets/vendor-three-DwGkEfCM.js +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/static/favicon.ico +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/static/modernizr.js +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/telemetry.py +0 -0
- {arize_phoenix-4.24.0/src/phoenix/session → arize_phoenix-4.25.0/src/phoenix/server/templates}/__init__.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/templates/index.html +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/server/thread_server.py +0 -0
- {arize_phoenix-4.24.0/src/phoenix/utilities → arize_phoenix-4.25.0/src/phoenix/session}/__init__.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/session/data_extractor.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/settings.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/trace/__init__.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/trace/attributes.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/trace/dsl/README.md +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/trace/dsl/__init__.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/trace/dsl/filter.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/trace/dsl/helpers.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/trace/dsl/query.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/trace/errors.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/trace/evaluation_conventions.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/trace/exporter.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/trace/langchain/__init__.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/trace/llama_index/__init__.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/trace/openai/__init__.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/trace/otel.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/trace/projects.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/trace/schemas.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/trace/span_evaluations.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/trace/span_json_decoder.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/trace/span_json_encoder.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/trace/trace_dataset.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/trace/utils.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/trace/v1/__init__.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/trace/v1/evaluation_pb2.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/trace/v1/evaluation_pb2.pyi +0 -0
- /arize_phoenix-4.24.0/src/phoenix/utilities/span_store.py → /arize_phoenix-4.25.0/src/phoenix/utilities/__init__.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/utilities/client.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/utilities/deprecation.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/utilities/error_handling.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/utilities/json.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/utilities/logging.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/utilities/project.py +0 -0
- {arize_phoenix-4.24.0 → arize_phoenix-4.25.0}/src/phoenix/utilities/re.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: arize-phoenix
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.25.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
|
|
@@ -42,9 +42,11 @@ Requires-Dist: protobuf<6.0,>=3.20
|
|
|
42
42
|
Requires-Dist: psutil
|
|
43
43
|
Requires-Dist: pyarrow
|
|
44
44
|
Requires-Dist: pydantic!=2.0.*,<3,>=1.0
|
|
45
|
+
Requires-Dist: pyjwt
|
|
45
46
|
Requires-Dist: python-multipart
|
|
46
47
|
Requires-Dist: scikit-learn
|
|
47
|
-
Requires-Dist: scipy
|
|
48
|
+
Requires-Dist: scipy!=1.14.1; platform_system == 'Darwin'
|
|
49
|
+
Requires-Dist: scipy; platform_system != 'Darwin'
|
|
48
50
|
Requires-Dist: sqlalchemy[asyncio]<3,>=2.0.4
|
|
49
51
|
Requires-Dist: sqlean-py>=3.45.1
|
|
50
52
|
Requires-Dist: starlette
|
|
@@ -85,14 +87,16 @@ Requires-Dist: nbqa; extra == 'dev'
|
|
|
85
87
|
Requires-Dist: pandas-stubs==2.0.3.230814; (python_version < '3.9') and extra == 'dev'
|
|
86
88
|
Requires-Dist: pandas-stubs==2.2.2.240603; (python_version >= '3.9') and extra == 'dev'
|
|
87
89
|
Requires-Dist: pandas>=1.0; extra == 'dev'
|
|
90
|
+
Requires-Dist: portpicker; extra == 'dev'
|
|
88
91
|
Requires-Dist: pre-commit; extra == 'dev'
|
|
89
92
|
Requires-Dist: prometheus-client; extra == 'dev'
|
|
90
93
|
Requires-Dist: psycopg[binary]; extra == 'dev'
|
|
91
94
|
Requires-Dist: pytest-asyncio; extra == 'dev'
|
|
92
95
|
Requires-Dist: pytest-cov; extra == 'dev'
|
|
93
96
|
Requires-Dist: pytest-postgresql; extra == 'dev'
|
|
94
|
-
Requires-Dist: pytest
|
|
95
|
-
Requires-Dist:
|
|
97
|
+
Requires-Dist: pytest-xdist; extra == 'dev'
|
|
98
|
+
Requires-Dist: pytest==8.3.2; extra == 'dev'
|
|
99
|
+
Requires-Dist: ruff==0.6.1; extra == 'dev'
|
|
96
100
|
Requires-Dist: strawberry-graphql[debug-server,opentelemetry]==0.236.0; extra == 'dev'
|
|
97
101
|
Requires-Dist: tabulate; extra == 'dev'
|
|
98
102
|
Requires-Dist: types-tabulate; extra == 'dev'
|
|
@@ -107,6 +111,7 @@ Requires-Dist: llama-index-readers-file==0.1.25; extra == 'llama-index'
|
|
|
107
111
|
Requires-Dist: llama-index==0.10.51; extra == 'llama-index'
|
|
108
112
|
Provides-Extra: pg
|
|
109
113
|
Requires-Dist: asyncpg; extra == 'pg'
|
|
114
|
+
Provides-Extra: test
|
|
110
115
|
Description-Content-Type: text/markdown
|
|
111
116
|
|
|
112
117
|
<p align="center">
|
|
@@ -144,9 +149,8 @@ Phoenix is an open-source AI observability platform designed for experimentation
|
|
|
144
149
|
- **_Evaluation_** - Leverage LLMs to benchmark your application's performance using response and retrieval evals.
|
|
145
150
|
- **_Datasets_** - Create versioned datasets of examples for experimentation, evaluation, and fine-tuning.
|
|
146
151
|
- **_Experiments_** - Track and evaluate changes to prompts, LLMs, and retrieval.
|
|
147
|
-
- **_Inference Analysis_** - Visualize inferences and embeddings using dimensionality reduction and clustering to identify drift and performance degradation.
|
|
148
152
|
|
|
149
|
-
Phoenix is vendor and language agnostic with out-of-the-box support for popular frameworks (🦙LlamaIndex, 🦜⛓LangChain, 🧩DSPy) and LLM providers (OpenAI, Bedrock, and more). For details on auto-instrumentation, check out the [OpenInference](https://github.com/Arize-ai/openinference) project.
|
|
153
|
+
Phoenix is vendor and language agnostic with out-of-the-box support for popular frameworks (🦙LlamaIndex, 🦜⛓LangChain, Haystack, 🧩DSPy) and LLM providers (OpenAI, Bedrock, and more). For details on auto-instrumentation, check out the [OpenInference](https://github.com/Arize-ai/openinference) project.
|
|
150
154
|
|
|
151
155
|
Phoenix runs practically anywhere, including your Jupyter notebook, local machine, containerized deployment, or in the cloud.
|
|
152
156
|
|
|
@@ -33,9 +33,8 @@ Phoenix is an open-source AI observability platform designed for experimentation
|
|
|
33
33
|
- **_Evaluation_** - Leverage LLMs to benchmark your application's performance using response and retrieval evals.
|
|
34
34
|
- **_Datasets_** - Create versioned datasets of examples for experimentation, evaluation, and fine-tuning.
|
|
35
35
|
- **_Experiments_** - Track and evaluate changes to prompts, LLMs, and retrieval.
|
|
36
|
-
- **_Inference Analysis_** - Visualize inferences and embeddings using dimensionality reduction and clustering to identify drift and performance degradation.
|
|
37
36
|
|
|
38
|
-
Phoenix is vendor and language agnostic with out-of-the-box support for popular frameworks (🦙LlamaIndex, 🦜⛓LangChain, 🧩DSPy) and LLM providers (OpenAI, Bedrock, and more). For details on auto-instrumentation, check out the [OpenInference](https://github.com/Arize-ai/openinference) project.
|
|
37
|
+
Phoenix is vendor and language agnostic with out-of-the-box support for popular frameworks (🦙LlamaIndex, 🦜⛓LangChain, Haystack, 🧩DSPy) and LLM providers (OpenAI, Bedrock, and more). For details on auto-instrumentation, check out the [OpenInference](https://github.com/Arize-ai/openinference) project.
|
|
39
38
|
|
|
40
39
|
Phoenix runs practically anywhere, including your Jupyter notebook, local machine, containerized deployment, or in the cloud.
|
|
41
40
|
|
|
@@ -36,7 +36,8 @@ dependencies = [
|
|
|
36
36
|
"typing-extensions>=4.5; python_version<'3.12'",
|
|
37
37
|
# A minimum version of typing-extensions==4.6.0 is needed to avoid this issue on Python 3.12: https://github.com/Azure/azure-sdk-for-python/issues/33442#issuecomment-1847886784
|
|
38
38
|
"typing-extensions>=4.6; python_version>='3.12'",
|
|
39
|
-
"scipy",
|
|
39
|
+
"scipy!=1.14.1; platform_system == 'Darwin'", # MacOS installation issue: https://github.com/scipy/scipy/issues/21424
|
|
40
|
+
"scipy; platform_system != 'Darwin'",
|
|
40
41
|
"wrapt",
|
|
41
42
|
"protobuf>=3.20, <6.0",
|
|
42
43
|
"grpcio",
|
|
@@ -60,7 +61,8 @@ dependencies = [
|
|
|
60
61
|
"python-multipart", # see https://www.starlette.io/#dependencies
|
|
61
62
|
"arize-phoenix-evals>=0.13.1",
|
|
62
63
|
"fastapi",
|
|
63
|
-
"pydantic>=1.0,!=2.0.*,<3
|
|
64
|
+
"pydantic>=1.0,!=2.0.*,<3", # exclude 2.0.* since it does not support the `json_encoders` configuration setting
|
|
65
|
+
"pyjwt",
|
|
64
66
|
]
|
|
65
67
|
dynamic = ["version"]
|
|
66
68
|
|
|
@@ -70,14 +72,15 @@ dev = [
|
|
|
70
72
|
"hatch",
|
|
71
73
|
"jupyter",
|
|
72
74
|
"nbqa",
|
|
73
|
-
"ruff==0.
|
|
75
|
+
"ruff==0.6.1",
|
|
74
76
|
"mypy==1.11.1",
|
|
75
77
|
"pandas>=1.0",
|
|
76
78
|
"tabulate", # used by DataFrame.to_markdown()
|
|
77
79
|
"types-tabulate",
|
|
78
80
|
"pandas-stubs==2.2.2.240603; python_version>='3.9'",
|
|
79
81
|
"pandas-stubs==2.0.3.230814; python_version<'3.9'",
|
|
80
|
-
"pytest==8.3.
|
|
82
|
+
"pytest==8.3.2",
|
|
83
|
+
"pytest-xdist",
|
|
81
84
|
"pytest-asyncio",
|
|
82
85
|
"pytest-cov",
|
|
83
86
|
"pytest-postgresql",
|
|
@@ -94,6 +97,7 @@ dev = [
|
|
|
94
97
|
"prometheus_client",
|
|
95
98
|
"asgi-lifespan",
|
|
96
99
|
"Faker>=26.0.0",
|
|
100
|
+
"portpicker",
|
|
97
101
|
"uvloop; platform_system != 'Windows'",
|
|
98
102
|
]
|
|
99
103
|
evals = []
|
|
@@ -121,6 +125,8 @@ container = [
|
|
|
121
125
|
"strawberry-graphql[opentelemetry]==0.236.0", # need to pin version because we're monkey-patching
|
|
122
126
|
"uvloop; platform_system != 'Windows'",
|
|
123
127
|
]
|
|
128
|
+
test = [
|
|
129
|
+
]
|
|
124
130
|
|
|
125
131
|
[project.urls]
|
|
126
132
|
Documentation = "https://docs.arize.com/phoenix/"
|
|
@@ -151,7 +157,8 @@ dependencies = [
|
|
|
151
157
|
"numpy",
|
|
152
158
|
"pandas==2.2.2; python_version>='3.9'",
|
|
153
159
|
"pandas==1.4.0; python_version<'3.9'",
|
|
154
|
-
"pytest==8.3.
|
|
160
|
+
"pytest==8.3.2",
|
|
161
|
+
"pytest-xdist",
|
|
155
162
|
"pytest-asyncio",
|
|
156
163
|
"pytest-cov",
|
|
157
164
|
"pytest-postgresql",
|
|
@@ -179,7 +186,7 @@ dependencies = [
|
|
|
179
186
|
|
|
180
187
|
[tool.hatch.envs.type]
|
|
181
188
|
dependencies = [
|
|
182
|
-
"mypy==1.11.
|
|
189
|
+
"mypy==1.11.1",
|
|
183
190
|
"tenacity",
|
|
184
191
|
"pandas>=1.0",
|
|
185
192
|
"pandas-stubs==2.0.3.230814",
|
|
@@ -214,7 +221,7 @@ python = ["3.8", "3.9", "3.12"]
|
|
|
214
221
|
[tool.hatch.envs.style]
|
|
215
222
|
detached = true
|
|
216
223
|
dependencies = [
|
|
217
|
-
"ruff==0.
|
|
224
|
+
"ruff==0.6.1",
|
|
218
225
|
]
|
|
219
226
|
|
|
220
227
|
[[tool.hatch.envs.style.matrix]]
|
|
@@ -234,7 +241,7 @@ dependencies = [
|
|
|
234
241
|
]
|
|
235
242
|
|
|
236
243
|
[tool.hatch.envs.default.scripts]
|
|
237
|
-
tests = "pytest {args}"
|
|
244
|
+
tests = "pytest -n auto {args}"
|
|
238
245
|
coverage = "pytest --cov-report=term-missing --cov-config=pyproject.toml --cov=src/phoenix --cov=tests {args}"
|
|
239
246
|
|
|
240
247
|
[[tool.hatch.envs.test.matrix]]
|
|
@@ -246,6 +253,8 @@ addopts = [
|
|
|
246
253
|
"-rA",
|
|
247
254
|
"--import-mode=importlib",
|
|
248
255
|
"--doctest-modules",
|
|
256
|
+
"--new-first",
|
|
257
|
+
"--showlocals",
|
|
249
258
|
]
|
|
250
259
|
testpaths = [
|
|
251
260
|
"tests",
|
|
@@ -363,9 +372,6 @@ ignore-setters = false
|
|
|
363
372
|
|
|
364
373
|
[tool.mypy]
|
|
365
374
|
plugins = ["strawberry.ext.mypy_plugin", "pydantic.mypy"]
|
|
366
|
-
disallow_untyped_calls = true
|
|
367
|
-
disallow_untyped_defs = true
|
|
368
|
-
disallow_incomplete_defs = true
|
|
369
375
|
strict = true
|
|
370
376
|
exclude = [
|
|
371
377
|
"api_reference",
|
|
@@ -413,7 +419,6 @@ exclude = [
|
|
|
413
419
|
"*.pyi",
|
|
414
420
|
"docs/",
|
|
415
421
|
]
|
|
416
|
-
extend-include = ["*.ipynb"]
|
|
417
422
|
line-length = 100
|
|
418
423
|
target-version = "py38"
|
|
419
424
|
|
|
@@ -427,4 +432,4 @@ select = ["E", "F", "W", "I", "NPY201"]
|
|
|
427
432
|
force-single-line = false
|
|
428
433
|
|
|
429
434
|
[tool.ruff.format]
|
|
430
|
-
line-ending = "
|
|
435
|
+
line-ending = "native"
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from hashlib import pbkdf2_hmac
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def compute_password_hash(password: str, salt: str) -> str:
|
|
5
|
+
"""
|
|
6
|
+
Salts and hashes a password using PBKDF2, HMAC, and SHA256.
|
|
7
|
+
"""
|
|
8
|
+
password_bytes = password.encode("utf-8")
|
|
9
|
+
salt_bytes = salt.encode("utf-8")
|
|
10
|
+
password_hash_bytes = pbkdf2_hmac("sha256", password_bytes, salt_bytes, NUM_ITERATIONS)
|
|
11
|
+
password_hash = password_hash_bytes.hex()
|
|
12
|
+
return password_hash
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
NUM_ITERATIONS = 1_000_000
|
|
@@ -7,6 +7,7 @@ from typing import Any
|
|
|
7
7
|
|
|
8
8
|
import aiosqlite
|
|
9
9
|
import numpy as np
|
|
10
|
+
import sqlalchemy
|
|
10
11
|
import sqlean
|
|
11
12
|
from sqlalchemy import URL, StaticPool, event, make_url
|
|
12
13
|
from sqlalchemy.ext.asyncio import AsyncEngine, create_async_engine
|
|
@@ -15,6 +16,7 @@ from typing_extensions import assert_never
|
|
|
15
16
|
from phoenix.db.helpers import SupportedSQLDialect
|
|
16
17
|
from phoenix.db.migrate import migrate_in_thread
|
|
17
18
|
from phoenix.db.models import init_models
|
|
19
|
+
from phoenix.settings import Settings
|
|
18
20
|
|
|
19
21
|
sqlean.extensions.enable("text", "stats")
|
|
20
22
|
|
|
@@ -118,7 +120,13 @@ def aio_sqlite_engine(
|
|
|
118
120
|
else:
|
|
119
121
|
asyncio.create_task(init_models(engine))
|
|
120
122
|
else:
|
|
121
|
-
|
|
123
|
+
sync_engine = sqlalchemy.create_engine(
|
|
124
|
+
url=url.set(drivername="sqlite"),
|
|
125
|
+
echo=Settings.log_migrations,
|
|
126
|
+
json_serializer=_dumps,
|
|
127
|
+
creator=lambda: sqlean.connect(f"file:{database}", uri=True),
|
|
128
|
+
)
|
|
129
|
+
migrate_in_thread(sync_engine)
|
|
122
130
|
return engine
|
|
123
131
|
|
|
124
132
|
|
|
@@ -130,7 +138,12 @@ def aio_postgresql_engine(
|
|
|
130
138
|
engine = create_async_engine(url=url, echo=echo, json_serializer=_dumps)
|
|
131
139
|
if not migrate:
|
|
132
140
|
return engine
|
|
133
|
-
|
|
141
|
+
sync_engine = sqlalchemy.create_engine(
|
|
142
|
+
url=url.set(drivername="postgresql"),
|
|
143
|
+
echo=Settings.log_migrations,
|
|
144
|
+
json_serializer=_dumps,
|
|
145
|
+
)
|
|
146
|
+
migrate_in_thread(sync_engine)
|
|
134
147
|
return engine
|
|
135
148
|
|
|
136
149
|
|
|
@@ -1,25 +1,34 @@
|
|
|
1
|
+
import codecs
|
|
1
2
|
import logging
|
|
3
|
+
import sys
|
|
2
4
|
from pathlib import Path
|
|
3
|
-
from queue import Empty,
|
|
5
|
+
from queue import Empty, SimpleQueue
|
|
4
6
|
from threading import Thread
|
|
5
7
|
from typing import Optional
|
|
6
8
|
|
|
7
9
|
from alembic import command
|
|
8
10
|
from alembic.config import Config
|
|
9
|
-
from sqlalchemy import
|
|
11
|
+
from sqlalchemy import Engine
|
|
10
12
|
|
|
11
13
|
from phoenix.exceptions import PhoenixMigrationError
|
|
12
14
|
from phoenix.settings import Settings
|
|
13
15
|
|
|
14
16
|
logger = logging.getLogger(__name__)
|
|
17
|
+
logger.addHandler(logging.NullHandler())
|
|
15
18
|
|
|
16
19
|
|
|
17
20
|
def printif(condition: bool, text: str) -> None:
|
|
18
|
-
if condition:
|
|
19
|
-
|
|
21
|
+
if not condition:
|
|
22
|
+
return
|
|
23
|
+
if sys.platform.startswith("win"):
|
|
24
|
+
text = codecs.encode(text, "ascii", errors="ignore").decode("ascii").strip()
|
|
25
|
+
print(text)
|
|
20
26
|
|
|
21
27
|
|
|
22
|
-
def migrate(
|
|
28
|
+
def migrate(
|
|
29
|
+
engine: Engine,
|
|
30
|
+
error_queue: Optional["SimpleQueue[BaseException]"] = None,
|
|
31
|
+
) -> None:
|
|
23
32
|
"""
|
|
24
33
|
Runs migrations on the database.
|
|
25
34
|
NB: Migrate only works on non-memory databases.
|
|
@@ -37,24 +46,26 @@ def migrate(url: URL, error_queue: Optional["Queue[Exception]"] = None) -> None:
|
|
|
37
46
|
# Explicitly set the migration directory
|
|
38
47
|
scripts_location = str(Path(__file__).parent.resolve() / "migrations")
|
|
39
48
|
alembic_cfg.set_main_option("script_location", scripts_location)
|
|
40
|
-
|
|
49
|
+
url = str(engine.url).replace("%", "%%")
|
|
50
|
+
alembic_cfg.set_main_option("sqlalchemy.url", url)
|
|
51
|
+
alembic_cfg.attributes["connection"] = engine.connect()
|
|
41
52
|
command.upgrade(alembic_cfg, "head")
|
|
42
53
|
printif(log_migrations, "---------------------------")
|
|
43
54
|
printif(log_migrations, "✅ Migrations complete.")
|
|
44
|
-
except
|
|
55
|
+
except BaseException as e:
|
|
45
56
|
if error_queue:
|
|
46
57
|
error_queue.put(e)
|
|
47
58
|
raise e
|
|
48
59
|
|
|
49
60
|
|
|
50
|
-
def migrate_in_thread(
|
|
61
|
+
def migrate_in_thread(engine: Engine) -> None:
|
|
51
62
|
"""
|
|
52
63
|
Runs migrations on the database in a separate thread.
|
|
53
64
|
This is needed because depending on the context (notebook)
|
|
54
65
|
the migration process can fail to execute in the main thread.
|
|
55
66
|
"""
|
|
56
|
-
error_queue:
|
|
57
|
-
t = Thread(target=migrate, args=(
|
|
67
|
+
error_queue: SimpleQueue[BaseException] = SimpleQueue()
|
|
68
|
+
t = Thread(target=migrate, args=(engine, error_queue))
|
|
58
69
|
t.start()
|
|
59
70
|
t.join()
|
|
60
71
|
|
|
@@ -11,7 +11,6 @@ from typing import Any, Dict, List, Optional, Sequence, TypedDict, Union
|
|
|
11
11
|
|
|
12
12
|
import sqlalchemy as sa
|
|
13
13
|
from alembic import op
|
|
14
|
-
from phoenix.datetime_utils import normalize_datetime
|
|
15
14
|
from sqlalchemy import (
|
|
16
15
|
JSON,
|
|
17
16
|
TIMESTAMP,
|
|
@@ -32,6 +31,8 @@ from sqlalchemy.orm import (
|
|
|
32
31
|
mapped_column,
|
|
33
32
|
)
|
|
34
33
|
|
|
34
|
+
from phoenix.datetime_utils import normalize_datetime
|
|
35
|
+
|
|
35
36
|
|
|
36
37
|
class JSONB(JSON):
|
|
37
38
|
# See https://docs.sqlalchemy.org/en/20/core/custom_types.html
|
|
@@ -113,7 +114,7 @@ class Base(DeclarativeBase):
|
|
|
113
114
|
class UserRole(Base):
|
|
114
115
|
__tablename__ = "user_roles"
|
|
115
116
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
116
|
-
|
|
117
|
+
name: Mapped[str] = mapped_column(unique=True)
|
|
117
118
|
|
|
118
119
|
|
|
119
120
|
class User(Base):
|
|
@@ -150,10 +151,10 @@ async def insert_roles_and_users(connection: AsyncConnection) -> None:
|
|
|
150
151
|
user to the `users` table.
|
|
151
152
|
"""
|
|
152
153
|
await connection.execute(
|
|
153
|
-
insert(UserRole).values([{"
|
|
154
|
+
insert(UserRole).values([{"name": "SYSTEM"}, {"name": "ADMIN"}, {"name": "MEMBER"}])
|
|
154
155
|
)
|
|
155
|
-
system_user_role_id = sa.select(UserRole.id).where(UserRole.
|
|
156
|
-
admin_user_role_id = sa.select(UserRole.id).where(UserRole.
|
|
156
|
+
system_user_role_id = sa.select(UserRole.id).where(UserRole.name == "SYSTEM").scalar_subquery()
|
|
157
|
+
admin_user_role_id = sa.select(UserRole.id).where(UserRole.name == "ADMIN").scalar_subquery()
|
|
157
158
|
await connection.execute(
|
|
158
159
|
insert(User).values(
|
|
159
160
|
[
|
|
@@ -183,7 +184,7 @@ def upgrade() -> None:
|
|
|
183
184
|
"user_roles",
|
|
184
185
|
sa.Column("id", sa.Integer, primary_key=True),
|
|
185
186
|
sa.Column(
|
|
186
|
-
"
|
|
187
|
+
"name",
|
|
187
188
|
sa.String,
|
|
188
189
|
nullable=False,
|
|
189
190
|
unique=True,
|
|
@@ -19,7 +19,6 @@ from sqlalchemy import (
|
|
|
19
19
|
update,
|
|
20
20
|
)
|
|
21
21
|
from sqlalchemy.dialects import postgresql
|
|
22
|
-
from sqlalchemy.ext.asyncio.engine import AsyncConnection
|
|
23
22
|
from sqlalchemy.ext.compiler import compiles
|
|
24
23
|
from sqlalchemy.orm import (
|
|
25
24
|
DeclarativeBase,
|
|
@@ -111,11 +110,10 @@ LLM_TOKEN_COUNT_PROMPT = SpanAttributes.LLM_TOKEN_COUNT_PROMPT.split(".")
|
|
|
111
110
|
LLM_TOKEN_COUNT_COMPLETION = SpanAttributes.LLM_TOKEN_COUNT_COMPLETION.split(".")
|
|
112
111
|
|
|
113
112
|
|
|
114
|
-
|
|
115
|
-
"""
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
await connection.execute(
|
|
113
|
+
def upgrade() -> None:
|
|
114
|
+
op.add_column("spans", sa.Column("llm_token_count_prompt", sa.Integer, nullable=True))
|
|
115
|
+
op.add_column("spans", sa.Column("llm_token_count_completion", sa.Integer, nullable=True))
|
|
116
|
+
op.execute(
|
|
119
117
|
update(Span).values(
|
|
120
118
|
llm_token_count_prompt=Span.attributes[LLM_TOKEN_COUNT_PROMPT].as_float(),
|
|
121
119
|
llm_token_count_completion=Span.attributes[LLM_TOKEN_COUNT_COMPLETION].as_float(),
|
|
@@ -123,12 +121,6 @@ async def get_token_counts_from_attributes(connection: AsyncConnection) -> None:
|
|
|
123
121
|
)
|
|
124
122
|
|
|
125
123
|
|
|
126
|
-
def upgrade() -> None:
|
|
127
|
-
op.add_column("spans", sa.Column("llm_token_count_prompt", sa.Integer, nullable=True))
|
|
128
|
-
op.add_column("spans", sa.Column("llm_token_count_completion", sa.Integer, nullable=True))
|
|
129
|
-
op.run_async(get_token_counts_from_attributes)
|
|
130
|
-
|
|
131
|
-
|
|
132
124
|
def downgrade() -> None:
|
|
133
125
|
op.drop_column("spans", "llm_token_count_completion")
|
|
134
126
|
op.drop_column("spans", "llm_token_count_prompt")
|
|
@@ -625,7 +625,7 @@ if ENABLE_AUTH:
|
|
|
625
625
|
class UserRole(Base):
|
|
626
626
|
__tablename__ = "user_roles"
|
|
627
627
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
628
|
-
|
|
628
|
+
name: Mapped[str] = mapped_column(unique=True)
|
|
629
629
|
users: Mapped[List["User"]] = relationship("User", back_populates="role")
|
|
630
630
|
|
|
631
631
|
class User(Base):
|
|
@@ -74,3 +74,17 @@ class Context(BaseContext):
|
|
|
74
74
|
event_queue: CanPutItem[DmlEvent] = _NoOp()
|
|
75
75
|
corpus: Optional[Model] = None
|
|
76
76
|
read_only: bool = False
|
|
77
|
+
secret: Optional[str] = None
|
|
78
|
+
|
|
79
|
+
def get_secret(self) -> str:
|
|
80
|
+
"""A type safe way to get the application secret. Throws an error if the secret is not set.
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
str: the phoenix secret
|
|
84
|
+
"""
|
|
85
|
+
if self.secret is None:
|
|
86
|
+
raise ValueError(
|
|
87
|
+
"Application secret not set."
|
|
88
|
+
" Please set the PHOENIX_SECRET environment variable and re-deploy the application."
|
|
89
|
+
)
|
|
90
|
+
return self.secret
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import strawberry
|
|
2
2
|
|
|
3
|
+
from phoenix.server.api.mutations.api_key_mutations import ApiKeyMutationMixin
|
|
3
4
|
from phoenix.server.api.mutations.dataset_mutations import DatasetMutationMixin
|
|
4
5
|
from phoenix.server.api.mutations.experiment_mutations import ExperimentMutationMixin
|
|
5
6
|
from phoenix.server.api.mutations.export_events_mutations import ExportEventsMutationMixin
|
|
@@ -16,5 +17,6 @@ class Mutation(
|
|
|
16
17
|
ExportEventsMutationMixin,
|
|
17
18
|
SpanAnnotationMutationMixin,
|
|
18
19
|
TraceAnnotationMutationMixin,
|
|
20
|
+
ApiKeyMutationMixin,
|
|
19
21
|
):
|
|
20
22
|
pass
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
from typing import Any, Dict, Optional
|
|
3
|
+
|
|
4
|
+
import jwt
|
|
5
|
+
import strawberry
|
|
6
|
+
from sqlalchemy import insert, select
|
|
7
|
+
from strawberry import UNSET
|
|
8
|
+
from strawberry.types import Info
|
|
9
|
+
|
|
10
|
+
from phoenix.db import models
|
|
11
|
+
from phoenix.server.api.context import Context
|
|
12
|
+
from phoenix.server.api.mutations.auth import HasSecret, IsAuthenticated
|
|
13
|
+
from phoenix.server.api.queries import Query
|
|
14
|
+
from phoenix.server.api.types.SystemApiKey import SystemApiKey
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@strawberry.type
|
|
18
|
+
class CreateSystemApiKeyMutationPayload:
|
|
19
|
+
jwt: str
|
|
20
|
+
api_key: SystemApiKey
|
|
21
|
+
query: Query
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@strawberry.input
|
|
25
|
+
class CreateApiKeyInput:
|
|
26
|
+
name: str
|
|
27
|
+
description: Optional[str] = UNSET
|
|
28
|
+
expires_at: Optional[datetime] = UNSET
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@strawberry.type
|
|
32
|
+
class ApiKeyMutationMixin:
|
|
33
|
+
@strawberry.mutation(permission_classes=[HasSecret, IsAuthenticated]) # type: ignore
|
|
34
|
+
async def create_system_api_key(
|
|
35
|
+
self, info: Info[Context, None], input: CreateApiKeyInput
|
|
36
|
+
) -> CreateSystemApiKeyMutationPayload:
|
|
37
|
+
# TODO(auth): safe guard against auth being disabled and secret not being set
|
|
38
|
+
async with info.context.db() as session:
|
|
39
|
+
# Get the system user - note this could be pushed into a dataloader
|
|
40
|
+
system_user = await session.scalar(
|
|
41
|
+
select(models.User)
|
|
42
|
+
.join(models.UserRole) # Join User with UserRole
|
|
43
|
+
.where(models.UserRole.name == "SYSTEM") # Filter where role is SYSTEM
|
|
44
|
+
.limit(1)
|
|
45
|
+
)
|
|
46
|
+
if system_user is None:
|
|
47
|
+
raise ValueError("System user not found")
|
|
48
|
+
|
|
49
|
+
insert_stmt = (
|
|
50
|
+
insert(models.APIKey)
|
|
51
|
+
.values(
|
|
52
|
+
user_id=system_user.id,
|
|
53
|
+
name=input.name,
|
|
54
|
+
description=input.description or None,
|
|
55
|
+
expires_at=input.expires_at or None,
|
|
56
|
+
)
|
|
57
|
+
.returning(models.APIKey)
|
|
58
|
+
)
|
|
59
|
+
api_key = await session.scalar(insert_stmt)
|
|
60
|
+
assert api_key is not None
|
|
61
|
+
|
|
62
|
+
encoded_jwt = create_jwt(
|
|
63
|
+
secret=info.context.get_secret(),
|
|
64
|
+
name=api_key.name,
|
|
65
|
+
id=api_key.id,
|
|
66
|
+
description=api_key.description,
|
|
67
|
+
iat=api_key.created_at,
|
|
68
|
+
exp=api_key.expires_at,
|
|
69
|
+
)
|
|
70
|
+
return CreateSystemApiKeyMutationPayload(
|
|
71
|
+
jwt=encoded_jwt,
|
|
72
|
+
api_key=SystemApiKey(
|
|
73
|
+
id_attr=api_key.id,
|
|
74
|
+
name=api_key.name,
|
|
75
|
+
description=api_key.description,
|
|
76
|
+
created_at=api_key.created_at,
|
|
77
|
+
expires_at=api_key.expires_at,
|
|
78
|
+
),
|
|
79
|
+
query=Query(),
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def create_jwt(
|
|
84
|
+
*,
|
|
85
|
+
secret: str,
|
|
86
|
+
algorithm: str = "HS256",
|
|
87
|
+
name: str,
|
|
88
|
+
description: Optional[str],
|
|
89
|
+
iat: datetime,
|
|
90
|
+
exp: Optional[datetime],
|
|
91
|
+
id: int,
|
|
92
|
+
) -> str:
|
|
93
|
+
"""Create a signed JSON Web Token for authentication
|
|
94
|
+
|
|
95
|
+
Args:
|
|
96
|
+
secret (str): the secret to sign with
|
|
97
|
+
name (str): name of the key / token
|
|
98
|
+
description (Optional[str]): description of the token
|
|
99
|
+
iat (datetime): the issued at time
|
|
100
|
+
exp (Optional[datetime]): the expiry, if set
|
|
101
|
+
id (int): the id of the key
|
|
102
|
+
algorithm (str, optional): the algorithm to use. Defaults to "HS256".
|
|
103
|
+
|
|
104
|
+
Returns:
|
|
105
|
+
str: The encoded JWT
|
|
106
|
+
"""
|
|
107
|
+
payload: Dict[str, Any] = {
|
|
108
|
+
"name": name,
|
|
109
|
+
"description": description,
|
|
110
|
+
"iat": iat.utcnow(),
|
|
111
|
+
"id": id,
|
|
112
|
+
}
|
|
113
|
+
if exp is not None:
|
|
114
|
+
payload["exp"] = exp.utcnow()
|
|
115
|
+
|
|
116
|
+
# Encode the payload to create the JWT
|
|
117
|
+
token = jwt.encode(payload, secret, algorithm=algorithm)
|
|
118
|
+
|
|
119
|
+
return token
|
|
@@ -9,3 +9,10 @@ class IsAuthenticated(BasePermission):
|
|
|
9
9
|
|
|
10
10
|
async def has_permission(self, source: Any, info: Info, **kwargs: Any) -> bool:
|
|
11
11
|
return not info.context.read_only
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class HasSecret(BasePermission):
|
|
15
|
+
message = "Application secret is not set"
|
|
16
|
+
|
|
17
|
+
async def has_permission(self, source: Any, info: Info, **kwargs: Any) -> bool:
|
|
18
|
+
return info.context.secret is not None
|