arize-phoenix 10.15.0__tar.gz → 11.0.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-10.15.0 → arize_phoenix-11.0.0}/.gitignore +3 -1
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/PKG-INFO +2 -2
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/pyproject.toml +1 -1
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/config.py +5 -2
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/datetime_utils.py +8 -1
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/db/bulk_inserter.py +40 -1
- arize_phoenix-11.0.0/src/phoenix/db/facilitator.py +522 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/db/insertion/helpers.py +15 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/db/insertion/span.py +3 -1
- arize_phoenix-11.0.0/src/phoenix/db/migrations/versions/a20694b15f82_cost.py +196 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/db/models.py +267 -9
- arize_phoenix-11.0.0/src/phoenix/db/types/token_price_customization.py +29 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/context.py +38 -4
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/dataloaders/__init__.py +41 -5
- arize_phoenix-11.0.0/src/phoenix/server/api/dataloaders/last_used_times_by_generative_model_id.py +35 -0
- arize_phoenix-11.0.0/src/phoenix/server/api/dataloaders/span_cost_by_span.py +24 -0
- arize_phoenix-11.0.0/src/phoenix/server/api/dataloaders/span_cost_detail_summary_entries_by_generative_model.py +56 -0
- arize_phoenix-11.0.0/src/phoenix/server/api/dataloaders/span_cost_detail_summary_entries_by_project_session.py +57 -0
- arize_phoenix-11.0.0/src/phoenix/server/api/dataloaders/span_cost_detail_summary_entries_by_span.py +43 -0
- arize_phoenix-11.0.0/src/phoenix/server/api/dataloaders/span_cost_detail_summary_entries_by_trace.py +56 -0
- arize_phoenix-11.0.0/src/phoenix/server/api/dataloaders/span_cost_details_by_span_cost.py +27 -0
- arize_phoenix-11.0.0/src/phoenix/server/api/dataloaders/span_cost_summary_by_experiment.py +58 -0
- arize_phoenix-11.0.0/src/phoenix/server/api/dataloaders/span_cost_summary_by_experiment_run.py +58 -0
- arize_phoenix-11.0.0/src/phoenix/server/api/dataloaders/span_cost_summary_by_generative_model.py +55 -0
- arize_phoenix-11.0.0/src/phoenix/server/api/dataloaders/span_cost_summary_by_project.py +140 -0
- arize_phoenix-11.0.0/src/phoenix/server/api/dataloaders/span_cost_summary_by_project_session.py +56 -0
- arize_phoenix-11.0.0/src/phoenix/server/api/dataloaders/span_cost_summary_by_trace.py +55 -0
- arize_phoenix-11.0.0/src/phoenix/server/api/dataloaders/span_costs.py +35 -0
- arize_phoenix-11.0.0/src/phoenix/server/api/dataloaders/types.py +29 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/helpers/playground_clients.py +103 -12
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/input_types/ProjectSessionSort.py +3 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/input_types/SpanSort.py +17 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/mutations/__init__.py +2 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/mutations/chat_mutations.py +17 -0
- arize_phoenix-11.0.0/src/phoenix/server/api/mutations/model_mutations.py +208 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/queries.py +82 -41
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/routers/v1/traces.py +11 -4
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/subscriptions.py +36 -2
- arize_phoenix-11.0.0/src/phoenix/server/api/types/CostBreakdown.py +15 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/Experiment.py +59 -1
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/ExperimentRun.py +58 -4
- arize_phoenix-11.0.0/src/phoenix/server/api/types/GenerativeModel.py +150 -0
- arize_phoenix-10.15.0/src/phoenix/server/api/types/Model.py → arize_phoenix-11.0.0/src/phoenix/server/api/types/InferenceModel.py +1 -1
- arize_phoenix-11.0.0/src/phoenix/server/api/types/ModelInterface.py +11 -0
- arize_phoenix-11.0.0/src/phoenix/server/api/types/PlaygroundModel.py +10 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/Project.py +42 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/ProjectSession.py +44 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/Span.py +137 -0
- arize_phoenix-11.0.0/src/phoenix/server/api/types/SpanCostDetailSummaryEntry.py +10 -0
- arize_phoenix-11.0.0/src/phoenix/server/api/types/SpanCostSummary.py +10 -0
- arize_phoenix-11.0.0/src/phoenix/server/api/types/TokenPrice.py +16 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/TokenUsage.py +3 -3
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/Trace.py +41 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/app.py +59 -0
- arize_phoenix-11.0.0/src/phoenix/server/cost_tracking/cost_details_calculator.py +190 -0
- arize_phoenix-11.0.0/src/phoenix/server/cost_tracking/cost_model_lookup.py +151 -0
- arize_phoenix-11.0.0/src/phoenix/server/cost_tracking/helpers.py +68 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/cost_tracking/model_cost_manifest.json +59 -329
- arize_phoenix-11.0.0/src/phoenix/server/cost_tracking/regex_specificity.py +397 -0
- arize_phoenix-11.0.0/src/phoenix/server/cost_tracking/token_cost_calculator.py +57 -0
- arize_phoenix-11.0.0/src/phoenix/server/daemons/generative_model_store.py +51 -0
- arize_phoenix-11.0.0/src/phoenix/server/daemons/span_cost_calculator.py +103 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/dml_event_handler.py +1 -0
- arize_phoenix-11.0.0/src/phoenix/server/static/.vite/manifest.json +87 -0
- arize_phoenix-11.0.0/src/phoenix/server/static/assets/components-BnK9kodr.js +5055 -0
- arize_phoenix-10.15.0/src/phoenix/server/static/assets/index-DIlhmbjB.js → arize_phoenix-11.0.0/src/phoenix/server/static/assets/index-S3YKLmbo.js +13 -13
- arize_phoenix-10.15.0/src/phoenix/server/static/assets/pages-YX47cEoQ.js → arize_phoenix-11.0.0/src/phoenix/server/static/assets/pages-BW6PBHZb.js +811 -419
- arize_phoenix-10.15.0/src/phoenix/server/static/assets/vendor-DCZoBorz.js → arize_phoenix-11.0.0/src/phoenix/server/static/assets/vendor-DqQvHbPa.js +147 -147
- arize_phoenix-10.15.0/src/phoenix/server/static/assets/vendor-arizeai-Ckci3irT.js → arize_phoenix-11.0.0/src/phoenix/server/static/assets/vendor-arizeai-CLX44PFA.js +1 -1
- arize_phoenix-10.15.0/src/phoenix/server/static/assets/vendor-codemirror-BODM513D.js → arize_phoenix-11.0.0/src/phoenix/server/static/assets/vendor-codemirror-Du3XyJnB.js +1 -1
- arize_phoenix-10.15.0/src/phoenix/server/static/assets/vendor-recharts-C9O2a-N3.js → arize_phoenix-11.0.0/src/phoenix/server/static/assets/vendor-recharts-B2PJDrnX.js +25 -25
- arize_phoenix-10.15.0/src/phoenix/server/static/assets/vendor-shiki-Dq54rRC7.js → arize_phoenix-11.0.0/src/phoenix/server/static/assets/vendor-shiki-CNbrFjf9.js +1 -1
- arize_phoenix-11.0.0/src/phoenix/utilities/span_store.py +0 -0
- arize_phoenix-11.0.0/src/phoenix/version.py +1 -0
- arize_phoenix-10.15.0/src/phoenix/db/facilitator.py +0 -263
- arize_phoenix-10.15.0/src/phoenix/server/api/types/GenerativeModel.py +0 -9
- arize_phoenix-10.15.0/src/phoenix/server/cost_tracking/cost_lookup.py +0 -255
- arize_phoenix-10.15.0/src/phoenix/server/static/.vite/manifest.json +0 -87
- arize_phoenix-10.15.0/src/phoenix/server/static/assets/components-SpUMF1qV.js +0 -4509
- arize_phoenix-10.15.0/src/phoenix/version.py +0 -1
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/IP_NOTICE +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/LICENSE +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/README.md +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/__init__.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/auth.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/core/__init__.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/core/embedding_dimension.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/core/model.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/core/model_schema.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/core/model_schema_adapter.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/db/README.md +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/db/__init__.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/db/alembic.ini +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/db/constants.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/db/engines.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/db/enums.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/db/helpers.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/db/insertion/__init__.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/db/insertion/constants.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/db/insertion/dataset.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/db/insertion/document_annotation.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/db/insertion/evaluation.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/db/insertion/span_annotation.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/db/insertion/trace_annotation.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/db/insertion/types.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/db/migrate.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/db/migrations/__init__.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/db/migrations/data_migration_scripts/__init__.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/db/migrations/data_migration_scripts/populate_project_sessions.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/db/migrations/env.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/db/migrations/script.py.mako +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/db/migrations/versions/10460e46d750_datasets.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/db/migrations/versions/2f9d1a65945f_annotation_config_migration.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/db/migrations/versions/3be8647b87d8_add_token_columns_to_spans_table.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/db/migrations/versions/4ded9e43755f_create_project_sessions_table.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/db/migrations/versions/6a88424799fe_update_users_with_auth_method.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/db/migrations/versions/8a3764fe7f1a_change_jsonb_to_json_for_prompts.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/db/migrations/versions/bb8139330879_create_project_trace_retention_policies_table.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/db/migrations/versions/bc8fea3c2bc8_add_prompt_tables.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/db/migrations/versions/cd164e83824f_users_and_tokens.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/db/migrations/versions/cf03bd6bae1d_init.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/db/pg_config.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/db/types/__init__.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/db/types/annotation_configs.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/db/types/db_models.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/db/types/identifier.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/db/types/model_provider.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/db/types/trace_retention.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/exceptions.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/experiments/__init__.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/experiments/evaluators/__init__.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/experiments/evaluators/base.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/experiments/evaluators/code_evaluators.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/experiments/evaluators/llm_evaluators.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/experiments/evaluators/utils.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/experiments/functions.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/experiments/tracing.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/experiments/types.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/experiments/utils.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/inferences/__init__.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/inferences/errors.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/inferences/fixtures.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/inferences/inferences.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/inferences/schema.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/inferences/validation.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/logging/__init__.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/logging/_config.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/logging/_filter.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/logging/_formatter.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/metrics/README.md +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/metrics/__init__.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/metrics/binning.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/metrics/metrics.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/metrics/mixins.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/metrics/retrieval_metrics.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/metrics/timeseries.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/metrics/wrappers.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/pointcloud/__init__.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/pointcloud/clustering.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/pointcloud/pointcloud.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/pointcloud/projectors.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/pointcloud/umap_parameters.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/py.typed +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/__init__.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/README.md +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/__init__.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/auth.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/dataloaders/annotation_summaries.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/dataloaders/average_experiment_run_latency.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/dataloaders/cache/__init__.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/dataloaders/cache/two_tier_cache.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/dataloaders/dataset_example_revisions.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/dataloaders/dataset_example_spans.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/dataloaders/document_evaluation_summaries.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/dataloaders/document_evaluations.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/dataloaders/document_retrieval_metrics.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/dataloaders/experiment_annotation_summaries.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/dataloaders/experiment_error_rates.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/dataloaders/experiment_run_annotations.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/dataloaders/experiment_run_counts.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/dataloaders/experiment_sequence_number.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/dataloaders/latency_ms_quantile.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/dataloaders/min_start_or_max_end_times.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/dataloaders/num_child_spans.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/dataloaders/num_spans_per_trace.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/dataloaders/project_by_name.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/dataloaders/project_ids_by_trace_retention_policy_id.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/dataloaders/prompt_version_sequence_number.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/dataloaders/record_counts.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/dataloaders/session_io.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/dataloaders/session_num_traces.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/dataloaders/session_num_traces_with_error.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/dataloaders/session_token_usages.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/dataloaders/session_trace_latency_ms_quantile.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/dataloaders/span_annotations.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/dataloaders/span_by_id.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/dataloaders/span_dataset_examples.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/dataloaders/span_descendants.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/dataloaders/span_projects.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/dataloaders/table_fields.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/dataloaders/token_counts.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/dataloaders/trace_by_trace_ids.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/dataloaders/trace_retention_policy_id_by_project_id.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/dataloaders/trace_root_spans.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/dataloaders/user_roles.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/dataloaders/users.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/exceptions.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/helpers/__init__.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/helpers/annotations.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/helpers/dataset_helpers.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/helpers/experiment_run_filters.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/helpers/playground_registry.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/helpers/playground_spans.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/helpers/prompts/__init__.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/helpers/prompts/conversions/__init__.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/helpers/prompts/conversions/anthropic.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/helpers/prompts/conversions/aws.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/helpers/prompts/conversions/openai.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/helpers/prompts/models.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/input_types/AddExamplesToDatasetInput.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/input_types/AddSpansToDatasetInput.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/input_types/ChatCompletionInput.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/input_types/ChatCompletionMessageInput.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/input_types/ClearProjectInput.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/input_types/ClusterInput.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/input_types/Coordinates.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/input_types/CreateDatasetInput.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/input_types/CreateSpanAnnotationInput.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/input_types/CreateTraceAnnotationInput.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/input_types/DataQualityMetricInput.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/input_types/DatasetExampleInput.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/input_types/DatasetFilter.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/input_types/DatasetSort.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/input_types/DatasetVersionSort.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/input_types/DeleteAnnotationsInput.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/input_types/DeleteDatasetExamplesInput.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/input_types/DeleteDatasetInput.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/input_types/DeleteExperimentsInput.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/input_types/DimensionFilter.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/input_types/DimensionInput.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/input_types/GenerativeCredentialInput.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/input_types/GenerativeModelInput.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/input_types/Granularity.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/input_types/InvocationParameters.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/input_types/PatchAnnotationInput.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/input_types/PatchDatasetExamplesInput.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/input_types/PatchDatasetInput.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/input_types/PerformanceMetricInput.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/input_types/ProjectFilter.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/input_types/ProjectSort.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/input_types/PromptTemplateOptions.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/input_types/PromptVersionInput.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/input_types/SpanAnnotationFilter.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/input_types/SpanAnnotationSort.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/input_types/TimeRange.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/input_types/TraceAnnotationSort.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/input_types/UserRoleInput.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/input_types/__init__.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/interceptor.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/mutations/annotation_config_mutations.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/mutations/api_key_mutations.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/mutations/dataset_mutations.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/mutations/experiment_mutations.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/mutations/export_events_mutations.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/mutations/project_mutations.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/mutations/project_trace_retention_policy_mutations.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/mutations/prompt_label_mutations.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/mutations/prompt_mutations.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/mutations/prompt_version_tag_mutations.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/mutations/span_annotations_mutations.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/mutations/trace_annotations_mutations.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/mutations/trace_mutations.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/mutations/user_mutations.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/openapi/__init__.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/openapi/main.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/openapi/schema.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/routers/__init__.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/routers/auth.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/routers/embeddings.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/routers/oauth2.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/routers/utils.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/routers/v1/__init__.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/routers/v1/annotation_configs.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/routers/v1/annotations.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/routers/v1/datasets.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/routers/v1/evaluations.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/routers/v1/experiment_evaluations.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/routers/v1/experiment_runs.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/routers/v1/experiments.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/routers/v1/models.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/routers/v1/projects.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/routers/v1/prompts.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/routers/v1/spans.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/routers/v1/users.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/routers/v1/utils.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/schema.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/Annotation.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/AnnotationConfig.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/AnnotationSource.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/AnnotationSummary.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/AnnotatorKind.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/ApiKey.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/AuthMethod.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/ChatCompletionMessageRole.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/ChatCompletionSubscriptionPayload.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/Cluster.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/CreateDatasetPayload.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/CronExpression.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/DataQualityMetric.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/Dataset.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/DatasetExample.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/DatasetExampleRevision.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/DatasetValues.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/DatasetVersion.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/Dimension.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/DimensionDataType.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/DimensionShape.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/DimensionType.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/DimensionWithValue.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/DocumentEvaluationSummary.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/DocumentRetrievalMetrics.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/EmbeddingDimension.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/EmbeddingMetadata.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/Evaluation.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/EvaluationSummary.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/Event.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/EventMetadata.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/ExampleRevisionInterface.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/ExperimentAnnotationSummary.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/ExperimentComparison.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/ExperimentRunAnnotation.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/ExportedFile.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/Functionality.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/GenerativeProvider.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/Identifier.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/Inferences.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/InferencesRole.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/LabelFraction.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/MimeType.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/NumericRange.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/PerformanceMetric.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/ProjectTraceRetentionPolicy.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/Prompt.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/PromptLabel.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/PromptResponse.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/PromptVersion.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/PromptVersionTag.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/PromptVersionTemplate.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/ResponseFormat.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/Retrieval.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/ScalarDriftMetricEnum.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/Segments.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/SortDir.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/SpanAnnotation.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/SpanIOValue.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/SystemApiKey.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/TimeSeries.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/TokenCountPromptDetails.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/ToolDefinition.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/TraceAnnotation.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/UMAPPoints.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/User.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/UserApiKey.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/UserRole.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/ValidationResult.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/VectorDriftMetricEnum.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/__init__.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/node.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/types/pagination.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/api/utils.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/authorization.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/bearer_auth.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/cost_tracking/__init__.py +0 -0
- {arize_phoenix-10.15.0/src/phoenix/server/email → arize_phoenix-11.0.0/src/phoenix/server/daemons}/__init__.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/dml_event.py +0 -0
- {arize_phoenix-10.15.0/src/phoenix/server/email/templates → arize_phoenix-11.0.0/src/phoenix/server/email}/__init__.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/email/sender.py +0 -0
- {arize_phoenix-10.15.0/src/phoenix/server/middleware → arize_phoenix-11.0.0/src/phoenix/server/email/templates}/__init__.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/email/templates/password_reset.html +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/email/templates/welcome.html +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/email/types.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/grpc_server.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/jwt_store.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/main.py +0 -0
- {arize_phoenix-10.15.0/src/phoenix/server/openapi → arize_phoenix-11.0.0/src/phoenix/server/middleware}/__init__.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/middleware/gzip.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/oauth2.py +0 -0
- {arize_phoenix-10.15.0/src/phoenix/server/templates → arize_phoenix-11.0.0/src/phoenix/server/openapi}/__init__.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/prometheus.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/rate_limiters.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/retention.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/static/apple-touch-icon-114x114.png +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/static/apple-touch-icon-120x120.png +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/static/apple-touch-icon-144x144.png +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/static/apple-touch-icon-152x152.png +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/static/apple-touch-icon-180x180.png +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/static/apple-touch-icon-72x72.png +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/static/apple-touch-icon-76x76.png +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/static/apple-touch-icon.png +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/static/assets/vendor-WIZid84E.css +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/static/assets/vendor-three-C5WAXd5r.js +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/static/favicon.ico +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/static/modernizr.js +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/telemetry.py +0 -0
- {arize_phoenix-10.15.0/src/phoenix/session → arize_phoenix-11.0.0/src/phoenix/server/templates}/__init__.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/templates/index.html +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/thread_server.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/server/types.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/services.py +0 -0
- /arize_phoenix-10.15.0/src/phoenix/utilities/span_store.py → /arize_phoenix-11.0.0/src/phoenix/session/__init__.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/session/client.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/session/data_extractor.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/session/evaluation.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/session/session.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/settings.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/trace/__init__.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/trace/attributes.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/trace/dsl/README.md +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/trace/dsl/__init__.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/trace/dsl/filter.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/trace/dsl/helpers.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/trace/dsl/query.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/trace/errors.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/trace/evaluation_conventions.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/trace/exporter.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/trace/fixtures.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/trace/otel.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/trace/projects.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/trace/schemas.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/trace/span_evaluations.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/trace/span_json_decoder.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/trace/span_json_encoder.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/trace/trace_dataset.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/trace/utils.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/trace/v1/__init__.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/trace/v1/evaluation_pb2.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/trace/v1/evaluation_pb2.pyi +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/utilities/__init__.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/utilities/client.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/utilities/deprecation.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/utilities/error_handling.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/utilities/json.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/utilities/logging.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/utilities/project.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/utilities/re.py +0 -0
- {arize_phoenix-10.15.0 → arize_phoenix-11.0.0}/src/phoenix/utilities/template_formatters.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: arize-phoenix
|
|
3
|
-
Version:
|
|
3
|
+
Version: 11.0.0
|
|
4
4
|
Summary: AI Observability and Evaluation
|
|
5
5
|
Project-URL: Documentation, https://arize.com/docs/phoenix/
|
|
6
6
|
Project-URL: Issues, https://github.com/Arize-ai/phoenix/issues
|
|
@@ -33,7 +33,7 @@ Requires-Dist: httpx
|
|
|
33
33
|
Requires-Dist: jinja2
|
|
34
34
|
Requires-Dist: numpy!=2.0.0
|
|
35
35
|
Requires-Dist: openinference-instrumentation>=0.1.32
|
|
36
|
-
Requires-Dist: openinference-semantic-conventions>=0.1.
|
|
36
|
+
Requires-Dist: openinference-semantic-conventions>=0.1.20
|
|
37
37
|
Requires-Dist: opentelemetry-exporter-otlp
|
|
38
38
|
Requires-Dist: opentelemetry-proto>=1.12.0
|
|
39
39
|
Requires-Dist: opentelemetry-sdk
|
|
@@ -43,7 +43,7 @@ dependencies = [
|
|
|
43
43
|
"opentelemetry-proto>=1.12.0", # needed to avoid this issue: https://github.com/Arize-ai/phoenix/issues/2695
|
|
44
44
|
"opentelemetry-exporter-otlp",
|
|
45
45
|
"opentelemetry-semantic-conventions",
|
|
46
|
-
"openinference-semantic-conventions>=0.1.
|
|
46
|
+
"openinference-semantic-conventions>=0.1.20",
|
|
47
47
|
"openinference-instrumentation>=0.1.32",
|
|
48
48
|
"sqlalchemy[asyncio]>=2.0.4, <3",
|
|
49
49
|
"alembic>=1.3.0, <2",
|
|
@@ -135,8 +135,11 @@ ENV_PHOENIX_DANGEROUSLY_DISABLE_MIGRATIONS = "PHOENIX_DANGEROUSLY_DISABLE_MIGRAT
|
|
|
135
135
|
"""
|
|
136
136
|
Whether or not to disable migrations. Defaults to None / False.
|
|
137
137
|
|
|
138
|
-
This should only be used by developers working on the Phoenix server that need
|
|
139
|
-
switching between branches without having to run migrations.
|
|
138
|
+
This should only be used by developers working on the Phoenix server that need
|
|
139
|
+
to be switching between branches without having to run migrations.
|
|
140
|
+
|
|
141
|
+
This can also be useful if a migration fails and you want to put the applicaiton
|
|
142
|
+
in a running state.
|
|
140
143
|
"""
|
|
141
144
|
|
|
142
145
|
# Phoenix server OpenTelemetry instrumentation environment variables
|
|
@@ -28,7 +28,7 @@ def normalize_datetime(
|
|
|
28
28
|
"""
|
|
29
29
|
if not isinstance(dt, datetime):
|
|
30
30
|
return None
|
|
31
|
-
if
|
|
31
|
+
if not is_timezone_aware(dt):
|
|
32
32
|
dt = dt.replace(tzinfo=tz if tz else _LOCAL_TIMEZONE)
|
|
33
33
|
return dt.astimezone(timezone.utc)
|
|
34
34
|
|
|
@@ -106,3 +106,10 @@ def right_open_time_range(
|
|
|
106
106
|
floor_to_minute(min_time) if min_time else None,
|
|
107
107
|
floor_to_minute(max_time + timedelta(minutes=1)) if max_time else None,
|
|
108
108
|
)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def is_timezone_aware(dt: datetime) -> bool:
|
|
112
|
+
"""
|
|
113
|
+
Returns True if the datetime is timezone-aware, False otherwise.
|
|
114
|
+
"""
|
|
115
|
+
return dt.tzinfo is not None and dt.tzinfo.utcoffset(dt) is not None
|
|
@@ -8,6 +8,7 @@ from itertools import islice
|
|
|
8
8
|
from time import perf_counter
|
|
9
9
|
from typing import Any, Optional, cast
|
|
10
10
|
|
|
11
|
+
from openinference.semconv.trace import SpanAttributes
|
|
11
12
|
from typing_extensions import TypeAlias
|
|
12
13
|
|
|
13
14
|
import phoenix.trace.v1 as pb
|
|
@@ -17,11 +18,19 @@ from phoenix.db.insertion.evaluation import (
|
|
|
17
18
|
InsertEvaluationError,
|
|
18
19
|
insert_evaluation,
|
|
19
20
|
)
|
|
20
|
-
from phoenix.db.insertion.helpers import
|
|
21
|
+
from phoenix.db.insertion.helpers import (
|
|
22
|
+
DataManipulation,
|
|
23
|
+
DataManipulationEvent,
|
|
24
|
+
should_calculate_span_cost,
|
|
25
|
+
)
|
|
21
26
|
from phoenix.db.insertion.span import SpanInsertionEvent, insert_span
|
|
22
27
|
from phoenix.db.insertion.span_annotation import SpanAnnotationQueueInserter
|
|
23
28
|
from phoenix.db.insertion.trace_annotation import TraceAnnotationQueueInserter
|
|
24
29
|
from phoenix.db.insertion.types import Insertables, Precursors
|
|
30
|
+
from phoenix.server.daemons.span_cost_calculator import (
|
|
31
|
+
SpanCostCalculator,
|
|
32
|
+
SpanCostCalculatorQueueItem,
|
|
33
|
+
)
|
|
25
34
|
from phoenix.server.dml_event import DmlEvent, SpanInsertEvent
|
|
26
35
|
from phoenix.server.types import CanPutItem, DbSessionFactory
|
|
27
36
|
from phoenix.trace.schemas import Span
|
|
@@ -42,6 +51,7 @@ class BulkInserter:
|
|
|
42
51
|
db: DbSessionFactory,
|
|
43
52
|
*,
|
|
44
53
|
event_queue: CanPutItem[DmlEvent],
|
|
54
|
+
span_cost_calculator: SpanCostCalculator,
|
|
45
55
|
initial_batch_of_spans: Optional[Iterable[tuple[Span, str]]] = None,
|
|
46
56
|
initial_batch_of_evaluations: Optional[Iterable[pb.Evaluation]] = None,
|
|
47
57
|
sleep: float = 0.1,
|
|
@@ -78,6 +88,7 @@ class BulkInserter:
|
|
|
78
88
|
self._retry_delay_sec = retry_delay_sec
|
|
79
89
|
self._retry_allowance = retry_allowance
|
|
80
90
|
self._queue_inserters = _QueueInserters(db, self._retry_delay_sec, self._retry_allowance)
|
|
91
|
+
self._span_cost_calculator = span_cost_calculator
|
|
81
92
|
|
|
82
93
|
async def __aenter__(
|
|
83
94
|
self,
|
|
@@ -175,6 +186,7 @@ class BulkInserter:
|
|
|
175
186
|
|
|
176
187
|
async def _insert_spans(self, spans: list[tuple[Span, str]]) -> None:
|
|
177
188
|
project_ids = set()
|
|
189
|
+
span_cost_calculator_queue: list[SpanCostCalculatorQueueItem] = []
|
|
178
190
|
for i in range(0, len(spans), self._max_ops_per_transaction):
|
|
179
191
|
try:
|
|
180
192
|
start = perf_counter()
|
|
@@ -198,6 +210,16 @@ class BulkInserter:
|
|
|
198
210
|
)
|
|
199
211
|
if result is not None:
|
|
200
212
|
project_ids.add(result.project_rowid)
|
|
213
|
+
if should_calculate_span_cost(span.attributes):
|
|
214
|
+
span_cost_calculator_queue.append(
|
|
215
|
+
SpanCostCalculatorQueueItem(
|
|
216
|
+
span_rowid=result.span_rowid,
|
|
217
|
+
trace_rowid=result.trace_rowid,
|
|
218
|
+
attributes=span.attributes,
|
|
219
|
+
span_start_time=span.start_time,
|
|
220
|
+
)
|
|
221
|
+
)
|
|
222
|
+
|
|
201
223
|
if self._enable_prometheus:
|
|
202
224
|
from phoenix.server.prometheus import BULK_LOADER_INSERTION_TIME
|
|
203
225
|
|
|
@@ -209,6 +231,8 @@ class BulkInserter:
|
|
|
209
231
|
BULK_LOADER_EXCEPTIONS.inc()
|
|
210
232
|
logger.exception("Failed to insert spans")
|
|
211
233
|
self._event_queue.put(SpanInsertEvent(tuple(project_ids)))
|
|
234
|
+
for item in span_cost_calculator_queue:
|
|
235
|
+
self._span_cost_calculator.put_nowait(item)
|
|
212
236
|
|
|
213
237
|
async def _insert_evaluations(self, evaluations: list[pb.Evaluation]) -> None:
|
|
214
238
|
for i in range(0, len(evaluations), self._max_ops_per_transaction):
|
|
@@ -292,3 +316,18 @@ class _QueueInserters:
|
|
|
292
316
|
@_enqueue.register(Insertables.DocumentAnnotation)
|
|
293
317
|
async def _(self, item: Precursors.DocumentAnnotation) -> None:
|
|
294
318
|
await self._document_annotations.enqueue(item)
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
LLM_MODEL_NAME = SpanAttributes.LLM_MODEL_NAME
|
|
322
|
+
LLM_PROVIDER = SpanAttributes.LLM_PROVIDER
|
|
323
|
+
LLM_TOKEN_COUNT_COMPLETION = SpanAttributes.LLM_TOKEN_COUNT_COMPLETION
|
|
324
|
+
LLM_TOKEN_COUNT_COMPLETION_DETAILS_AUDIO = SpanAttributes.LLM_TOKEN_COUNT_COMPLETION_DETAILS_AUDIO
|
|
325
|
+
LLM_TOKEN_COUNT_COMPLETION_DETAILS_REASONING = (
|
|
326
|
+
SpanAttributes.LLM_TOKEN_COUNT_COMPLETION_DETAILS_REASONING
|
|
327
|
+
)
|
|
328
|
+
LLM_TOKEN_COUNT_PROMPT = SpanAttributes.LLM_TOKEN_COUNT_PROMPT
|
|
329
|
+
LLM_TOKEN_COUNT_PROMPT_DETAILS_AUDIO = SpanAttributes.LLM_TOKEN_COUNT_PROMPT_DETAILS_AUDIO
|
|
330
|
+
LLM_TOKEN_COUNT_PROMPT_DETAILS_CACHE_READ = SpanAttributes.LLM_TOKEN_COUNT_PROMPT_DETAILS_CACHE_READ
|
|
331
|
+
LLM_TOKEN_COUNT_PROMPT_DETAILS_CACHE_WRITE = (
|
|
332
|
+
SpanAttributes.LLM_TOKEN_COUNT_PROMPT_DETAILS_CACHE_WRITE
|
|
333
|
+
)
|
|
@@ -0,0 +1,522 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import json
|
|
5
|
+
import logging
|
|
6
|
+
import re
|
|
7
|
+
import secrets
|
|
8
|
+
from asyncio import gather
|
|
9
|
+
from datetime import datetime, timedelta, timezone
|
|
10
|
+
from functools import partial
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from typing import NamedTuple, Optional, Union
|
|
13
|
+
|
|
14
|
+
import sqlalchemy as sa
|
|
15
|
+
from sqlalchemy import select
|
|
16
|
+
from sqlalchemy.orm import InstrumentedAttribute, joinedload
|
|
17
|
+
from sqlalchemy.sql.dml import ReturningDelete
|
|
18
|
+
|
|
19
|
+
from phoenix import config
|
|
20
|
+
from phoenix.auth import (
|
|
21
|
+
DEFAULT_ADMIN_EMAIL,
|
|
22
|
+
DEFAULT_ADMIN_USERNAME,
|
|
23
|
+
DEFAULT_SECRET_LENGTH,
|
|
24
|
+
DEFAULT_SYSTEM_EMAIL,
|
|
25
|
+
DEFAULT_SYSTEM_USERNAME,
|
|
26
|
+
compute_password_hash,
|
|
27
|
+
)
|
|
28
|
+
from phoenix.config import (
|
|
29
|
+
get_env_admins,
|
|
30
|
+
get_env_default_admin_initial_password,
|
|
31
|
+
get_env_disable_basic_auth,
|
|
32
|
+
)
|
|
33
|
+
from phoenix.db import models
|
|
34
|
+
from phoenix.db.constants import DEFAULT_PROJECT_TRACE_RETENTION_POLICY_ID
|
|
35
|
+
from phoenix.db.enums import ENUM_COLUMNS
|
|
36
|
+
from phoenix.db.types.trace_retention import (
|
|
37
|
+
MaxDaysRule,
|
|
38
|
+
TraceRetentionCronExpression,
|
|
39
|
+
TraceRetentionRule,
|
|
40
|
+
)
|
|
41
|
+
from phoenix.server.email.types import WelcomeEmailSender
|
|
42
|
+
from phoenix.server.types import DbSessionFactory
|
|
43
|
+
|
|
44
|
+
logger = logging.getLogger(__name__)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class Facilitator:
|
|
48
|
+
"""
|
|
49
|
+
Facilitates the creation of database records necessary for Phoenix to function. This includes
|
|
50
|
+
ensuring that all enum values are present in their respective tables, ensuring that all user
|
|
51
|
+
roles are present, and ensuring that the admin user has a password hash. These tasks will be
|
|
52
|
+
carried out as callbacks at the very beginning of Starlette's lifespan process.
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
def __init__(
|
|
56
|
+
self,
|
|
57
|
+
*,
|
|
58
|
+
db: DbSessionFactory,
|
|
59
|
+
email_sender: Optional[WelcomeEmailSender] = None,
|
|
60
|
+
) -> None:
|
|
61
|
+
self._db = db
|
|
62
|
+
self._email_sender = email_sender
|
|
63
|
+
|
|
64
|
+
async def __call__(self) -> None:
|
|
65
|
+
for fn in (
|
|
66
|
+
_ensure_enums,
|
|
67
|
+
_ensure_user_roles,
|
|
68
|
+
_get_system_user_id,
|
|
69
|
+
partial(_ensure_admins, email_sender=self._email_sender),
|
|
70
|
+
_ensure_default_project_trace_retention_policy,
|
|
71
|
+
_ensure_model_costs,
|
|
72
|
+
_delete_expired_childless_records,
|
|
73
|
+
):
|
|
74
|
+
await fn(self._db)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
async def _ensure_enums(db: DbSessionFactory) -> None:
|
|
78
|
+
"""
|
|
79
|
+
Ensure that all enum values are present in their respective tables. If any values are missing,
|
|
80
|
+
they will be added. If any values are present in the database but not in the enum, an error will
|
|
81
|
+
be raised. This function is idempotent: it will not add duplicate values to the database.
|
|
82
|
+
"""
|
|
83
|
+
for column in ENUM_COLUMNS:
|
|
84
|
+
table = column.class_
|
|
85
|
+
assert isinstance(column.type, sa.Enum)
|
|
86
|
+
async with db() as session:
|
|
87
|
+
existing = set(await session.scalars(sa.select(column)))
|
|
88
|
+
expected = set(column.type.enums)
|
|
89
|
+
if unexpected := existing - expected:
|
|
90
|
+
raise ValueError(f"Unexpected values in {table.name}.{column.key}: {unexpected}")
|
|
91
|
+
if not (missing := expected - existing):
|
|
92
|
+
continue
|
|
93
|
+
await session.execute(sa.insert(table), [{column.key: v} for v in missing])
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
async def _ensure_user_roles(db: DbSessionFactory) -> None:
|
|
97
|
+
"""
|
|
98
|
+
Ensure that the system and admin roles are present in the database. If they are not, they will
|
|
99
|
+
be added. The system user will have the email "system@localhost" and the admin user will have
|
|
100
|
+
the email "admin@localhost".
|
|
101
|
+
"""
|
|
102
|
+
async with db() as session:
|
|
103
|
+
role_ids: dict[models.UserRoleName, int] = {
|
|
104
|
+
name: id_
|
|
105
|
+
async for name, id_ in await session.stream(
|
|
106
|
+
sa.select(models.UserRole.name, models.UserRole.id)
|
|
107
|
+
)
|
|
108
|
+
}
|
|
109
|
+
existing_roles: list[models.UserRoleName] = [
|
|
110
|
+
name
|
|
111
|
+
async for name in await session.stream_scalars(
|
|
112
|
+
sa.select(sa.distinct(models.UserRole.name)).join_from(models.User, models.UserRole)
|
|
113
|
+
)
|
|
114
|
+
]
|
|
115
|
+
if (
|
|
116
|
+
"SYSTEM" not in existing_roles
|
|
117
|
+
and (system_role_id := role_ids.get("SYSTEM")) is not None
|
|
118
|
+
):
|
|
119
|
+
system_user = models.LocalUser(
|
|
120
|
+
user_role_id=system_role_id,
|
|
121
|
+
username=DEFAULT_SYSTEM_USERNAME,
|
|
122
|
+
email=DEFAULT_SYSTEM_EMAIL,
|
|
123
|
+
reset_password=False,
|
|
124
|
+
password_salt=secrets.token_bytes(DEFAULT_SECRET_LENGTH),
|
|
125
|
+
password_hash=secrets.token_bytes(DEFAULT_SECRET_LENGTH),
|
|
126
|
+
)
|
|
127
|
+
session.add(system_user)
|
|
128
|
+
if "ADMIN" not in existing_roles and (admin_role_id := role_ids.get("ADMIN")) is not None:
|
|
129
|
+
salt = secrets.token_bytes(DEFAULT_SECRET_LENGTH)
|
|
130
|
+
password = get_env_default_admin_initial_password()
|
|
131
|
+
compute = partial(compute_password_hash, password=password, salt=salt)
|
|
132
|
+
loop = asyncio.get_running_loop()
|
|
133
|
+
hash_ = await loop.run_in_executor(None, compute)
|
|
134
|
+
admin_user = models.LocalUser(
|
|
135
|
+
user_role_id=admin_role_id,
|
|
136
|
+
username=DEFAULT_ADMIN_USERNAME,
|
|
137
|
+
email=DEFAULT_ADMIN_EMAIL,
|
|
138
|
+
password_salt=salt,
|
|
139
|
+
password_hash=hash_,
|
|
140
|
+
reset_password=True,
|
|
141
|
+
)
|
|
142
|
+
session.add(admin_user)
|
|
143
|
+
await session.flush()
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
async def _get_system_user_id(db: DbSessionFactory) -> None:
|
|
147
|
+
"""
|
|
148
|
+
Set the system user ID in the config. This is used to identify the system user in the database.
|
|
149
|
+
"""
|
|
150
|
+
async with db() as session:
|
|
151
|
+
system_user_id = await session.scalar(
|
|
152
|
+
sa.select(models.User.id)
|
|
153
|
+
.join(models.UserRole)
|
|
154
|
+
.where(models.UserRole.name == "SYSTEM")
|
|
155
|
+
.order_by(models.User.id)
|
|
156
|
+
.limit(1)
|
|
157
|
+
)
|
|
158
|
+
if system_user_id is None:
|
|
159
|
+
raise ValueError("System user not found in database")
|
|
160
|
+
config.SYSTEM_USER_ID = system_user_id
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
async def _ensure_admins(
|
|
164
|
+
db: DbSessionFactory,
|
|
165
|
+
*,
|
|
166
|
+
email_sender: Optional[WelcomeEmailSender] = None,
|
|
167
|
+
) -> None:
|
|
168
|
+
"""
|
|
169
|
+
Ensure that all startup admin users are present in the database. If any are missing, they will
|
|
170
|
+
be added. Existing records will not be modified.
|
|
171
|
+
"""
|
|
172
|
+
if not (admins := get_env_admins()):
|
|
173
|
+
return
|
|
174
|
+
disable_basic_auth = get_env_disable_basic_auth()
|
|
175
|
+
async with db() as session:
|
|
176
|
+
existing_emails = set(
|
|
177
|
+
await session.scalars(
|
|
178
|
+
sa.select(models.User.email).where(models.User.email.in_(admins.keys()))
|
|
179
|
+
)
|
|
180
|
+
)
|
|
181
|
+
admins = {
|
|
182
|
+
email: username for email, username in admins.items() if email not in existing_emails
|
|
183
|
+
}
|
|
184
|
+
if not admins:
|
|
185
|
+
return
|
|
186
|
+
existing_usernames = set(
|
|
187
|
+
await session.scalars(
|
|
188
|
+
sa.select(models.User.username).where(models.User.username.in_(admins.values()))
|
|
189
|
+
)
|
|
190
|
+
)
|
|
191
|
+
admins = {
|
|
192
|
+
email: username
|
|
193
|
+
for email, username in admins.items()
|
|
194
|
+
if username not in existing_usernames
|
|
195
|
+
}
|
|
196
|
+
if not admins:
|
|
197
|
+
return
|
|
198
|
+
admin_role_id = await session.scalar(sa.select(models.UserRole.id).filter_by(name="ADMIN"))
|
|
199
|
+
assert admin_role_id is not None, "Admin role not found in database"
|
|
200
|
+
user: models.User
|
|
201
|
+
for email, username in admins.items():
|
|
202
|
+
if not disable_basic_auth:
|
|
203
|
+
user = models.LocalUser(
|
|
204
|
+
email=email,
|
|
205
|
+
username=username,
|
|
206
|
+
password_salt=secrets.token_bytes(DEFAULT_SECRET_LENGTH),
|
|
207
|
+
password_hash=secrets.token_bytes(DEFAULT_SECRET_LENGTH),
|
|
208
|
+
)
|
|
209
|
+
else:
|
|
210
|
+
user = models.OAuth2User(
|
|
211
|
+
email=email,
|
|
212
|
+
username=username,
|
|
213
|
+
)
|
|
214
|
+
user.user_role_id = admin_role_id
|
|
215
|
+
session.add(user)
|
|
216
|
+
await session.flush()
|
|
217
|
+
if email_sender is None:
|
|
218
|
+
return
|
|
219
|
+
for exc in await gather(
|
|
220
|
+
*(email_sender.send_welcome_email(email, username) for email, username in admins.items()),
|
|
221
|
+
return_exceptions=True,
|
|
222
|
+
):
|
|
223
|
+
if isinstance(exc, Exception):
|
|
224
|
+
logger.error(f"Failed to send welcome email: {exc}")
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
_CHILDLESS_RECORD_DELETION_GRACE_PERIOD_DAYS = 1
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
def _stmt_to_delete_expired_childless_records(
|
|
231
|
+
table: type[models.Base],
|
|
232
|
+
foreign_key: Union[InstrumentedAttribute[int], InstrumentedAttribute[Optional[int]]],
|
|
233
|
+
) -> ReturningDelete[tuple[int]]:
|
|
234
|
+
"""
|
|
235
|
+
Creates a SQLAlchemy DELETE statement to permanently remove childless records.
|
|
236
|
+
|
|
237
|
+
Args:
|
|
238
|
+
table: The table model class that has a deleted_at column
|
|
239
|
+
foreign_key: The foreign key attribute to check for child relationships
|
|
240
|
+
|
|
241
|
+
Returns:
|
|
242
|
+
A DELETE statement that removes childless records marked for deletion more than
|
|
243
|
+
_CHILDLESS_RECORD_DELETION_GRACE_PERIOD_DAYS days ago
|
|
244
|
+
""" # noqa: E501
|
|
245
|
+
if not hasattr(table, "deleted_at"):
|
|
246
|
+
raise TypeError("Table must have a 'deleted_at' column")
|
|
247
|
+
cutoff_time = datetime.now(timezone.utc) - timedelta(
|
|
248
|
+
days=_CHILDLESS_RECORD_DELETION_GRACE_PERIOD_DAYS
|
|
249
|
+
)
|
|
250
|
+
return (
|
|
251
|
+
sa.delete(table)
|
|
252
|
+
.where(table.deleted_at.isnot(None))
|
|
253
|
+
.where(table.deleted_at < cutoff_time)
|
|
254
|
+
.where(~sa.exists().where(table.id == foreign_key))
|
|
255
|
+
.returning(table.id)
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
async def _delete_expired_childless_records_on_generative_models(
|
|
260
|
+
db: DbSessionFactory,
|
|
261
|
+
) -> None:
|
|
262
|
+
"""
|
|
263
|
+
Permanently deletes childless GenerativeModel records that have been marked for deletion.
|
|
264
|
+
|
|
265
|
+
This function removes GenerativeModel records that:
|
|
266
|
+
- Have been marked for deletion (deleted_at is not NULL)
|
|
267
|
+
- Were marked more than 1 day ago (grace period expired)
|
|
268
|
+
- Have no associated SpanCost records (childless)
|
|
269
|
+
|
|
270
|
+
This cleanup is necessary to remove orphaned records that may have been left behind
|
|
271
|
+
due to previous migrations or deletions.
|
|
272
|
+
""" # noqa: E501
|
|
273
|
+
stmt = _stmt_to_delete_expired_childless_records(
|
|
274
|
+
models.GenerativeModel,
|
|
275
|
+
models.SpanCost.model_id,
|
|
276
|
+
)
|
|
277
|
+
async with db() as session:
|
|
278
|
+
result = (await session.scalars(stmt)).all()
|
|
279
|
+
if result:
|
|
280
|
+
logger.info(f"Permanently deleted {len(result)} expired childless GenerativeModel records")
|
|
281
|
+
else:
|
|
282
|
+
logger.debug("No expired childless GenerativeModel records found for permanent deletion")
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
async def _delete_expired_childless_records(
|
|
286
|
+
db: DbSessionFactory,
|
|
287
|
+
) -> None:
|
|
288
|
+
"""
|
|
289
|
+
Permanently deletes childless records across all relevant tables.
|
|
290
|
+
|
|
291
|
+
This function runs the deletion process for all table types that support soft deletion,
|
|
292
|
+
handling any exceptions that occur during the process. Only records that have been
|
|
293
|
+
marked for deletion for more than the grace period (1 day) are permanently removed.
|
|
294
|
+
""" # noqa: E501
|
|
295
|
+
exceptions = await gather(
|
|
296
|
+
_delete_expired_childless_records_on_generative_models(db),
|
|
297
|
+
return_exceptions=True,
|
|
298
|
+
)
|
|
299
|
+
for exc in exceptions:
|
|
300
|
+
if isinstance(exc, Exception):
|
|
301
|
+
logger.error(f"Failed to delete childless records: {exc}")
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
async def _ensure_default_project_trace_retention_policy(db: DbSessionFactory) -> None:
|
|
305
|
+
"""
|
|
306
|
+
Ensures the default trace retention policy (id=1) exists in the database. Default policy
|
|
307
|
+
applies to all projects without a specific policy (i.e. foreign key is null).
|
|
308
|
+
|
|
309
|
+
This function checks for the presence of the default trace retention policy and
|
|
310
|
+
creates it if missing. The default trace retention policy:
|
|
311
|
+
|
|
312
|
+
- Has ID=0
|
|
313
|
+
- Is named "Default"
|
|
314
|
+
- Runs every Sunday at midnight UTC (cron: "0 0 * * 0")
|
|
315
|
+
- Retains traces indefinitely
|
|
316
|
+
|
|
317
|
+
If the default policy already exists, this function makes no changes.
|
|
318
|
+
|
|
319
|
+
Args:
|
|
320
|
+
db (DbSessionFactory): An async SQLAlchemy session factory.
|
|
321
|
+
|
|
322
|
+
Returns:
|
|
323
|
+
None
|
|
324
|
+
"""
|
|
325
|
+
assert DEFAULT_PROJECT_TRACE_RETENTION_POLICY_ID == 0
|
|
326
|
+
async with db() as session:
|
|
327
|
+
if await session.scalar(
|
|
328
|
+
sa.select(
|
|
329
|
+
sa.exists().where(
|
|
330
|
+
models.ProjectTraceRetentionPolicy.id
|
|
331
|
+
== DEFAULT_PROJECT_TRACE_RETENTION_POLICY_ID
|
|
332
|
+
)
|
|
333
|
+
)
|
|
334
|
+
):
|
|
335
|
+
return
|
|
336
|
+
cron_expression = TraceRetentionCronExpression(root="0 0 * * 0")
|
|
337
|
+
rule = TraceRetentionRule(root=MaxDaysRule(max_days=0))
|
|
338
|
+
await session.execute(
|
|
339
|
+
sa.insert(models.ProjectTraceRetentionPolicy),
|
|
340
|
+
[
|
|
341
|
+
{
|
|
342
|
+
"id": DEFAULT_PROJECT_TRACE_RETENTION_POLICY_ID,
|
|
343
|
+
"name": "Default",
|
|
344
|
+
"cron_expression": cron_expression,
|
|
345
|
+
"rule": rule,
|
|
346
|
+
}
|
|
347
|
+
],
|
|
348
|
+
)
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
_COST_MODEL_MANIFEST: Path = (
|
|
352
|
+
Path(__file__).parent.parent / "server" / "cost_tracking" / "model_cost_manifest.json"
|
|
353
|
+
)
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
class _TokenTypeKey(NamedTuple):
|
|
357
|
+
"""
|
|
358
|
+
Composite key for uniquely identifying token price configurations.
|
|
359
|
+
|
|
360
|
+
Token prices are differentiated by both their type (e.g., "input", "output", "audio")
|
|
361
|
+
and whether they represent prompt tokens (input to the model) or completion tokens
|
|
362
|
+
(output from the model). Some token types like "audio" can exist in both categories.
|
|
363
|
+
|
|
364
|
+
Attributes:
|
|
365
|
+
token_type: The category of token (e.g., "input", "output", "audio", "cache_write")
|
|
366
|
+
is_prompt: True if these are prompt/input tokens, False if completion/output tokens
|
|
367
|
+
"""
|
|
368
|
+
|
|
369
|
+
token_type: str
|
|
370
|
+
is_prompt: bool
|
|
371
|
+
|
|
372
|
+
|
|
373
|
+
async def _ensure_model_costs(db: DbSessionFactory) -> None:
|
|
374
|
+
"""
|
|
375
|
+
Ensures that built-in generative models and their token pricing information are up-to-date
|
|
376
|
+
in the database based on the model cost manifest file.
|
|
377
|
+
|
|
378
|
+
This function performs a comprehensive synchronization between the database and the manifest:
|
|
379
|
+
|
|
380
|
+
1. **Model Management**: Creates new built-in models from the manifest or updates existing ones
|
|
381
|
+
2. **Token Price Synchronization**: Ensures all token prices match the manifest rates
|
|
382
|
+
3. **Cleanup**: Soft-deletes built-in models no longer present in the manifest
|
|
383
|
+
|
|
384
|
+
The function handles different token types including:
|
|
385
|
+
- Input tokens (prompt): Standard input tokens for generation
|
|
386
|
+
- Cache write tokens (prompt): Tokens written to cache systems
|
|
387
|
+
- Cache read tokens (prompt): Tokens read from cache systems
|
|
388
|
+
- Output tokens (non-prompt): Generated response tokens
|
|
389
|
+
- Audio tokens (both prompt and non-prompt): Audio processing tokens
|
|
390
|
+
|
|
391
|
+
Token prices are uniquely identified by (token_type, is_prompt) pairs to handle
|
|
392
|
+
cases like audio tokens that can be both prompt and non-prompt.
|
|
393
|
+
|
|
394
|
+
Args:
|
|
395
|
+
db (DbSessionFactory): Database session factory for database operations
|
|
396
|
+
|
|
397
|
+
Returns:
|
|
398
|
+
None
|
|
399
|
+
|
|
400
|
+
Raises:
|
|
401
|
+
FileNotFoundError: If the model cost manifest file is not found
|
|
402
|
+
json.JSONDecodeError: If the manifest file contains invalid JSON
|
|
403
|
+
ValueError: If manifest data is malformed or missing required fields
|
|
404
|
+
"""
|
|
405
|
+
# Load the authoritative model cost data from the manifest file
|
|
406
|
+
with open(_COST_MODEL_MANIFEST) as f:
|
|
407
|
+
manifest = json.load(f)
|
|
408
|
+
|
|
409
|
+
# Define all supported token types with their prompt/non-prompt classification
|
|
410
|
+
# This determines how tokens are categorized for billing purposes
|
|
411
|
+
token_types: list[_TokenTypeKey] = [
|
|
412
|
+
_TokenTypeKey("input", True), # Standard input tokens
|
|
413
|
+
_TokenTypeKey("cache_write", True), # Tokens written to cache
|
|
414
|
+
_TokenTypeKey("cache_read", True), # Tokens read from cache
|
|
415
|
+
_TokenTypeKey("output", False), # Generated output tokens
|
|
416
|
+
_TokenTypeKey("audio", True), # Audio input tokens
|
|
417
|
+
_TokenTypeKey("audio", False), # Audio output tokens
|
|
418
|
+
]
|
|
419
|
+
|
|
420
|
+
async with db() as session:
|
|
421
|
+
# Fetch all existing built-in models with their token prices eagerly loaded
|
|
422
|
+
# Using .unique() to deduplicate models when multiple token prices are joined
|
|
423
|
+
built_in_models = {
|
|
424
|
+
omodel.name: omodel
|
|
425
|
+
for omodel in (
|
|
426
|
+
await session.scalars(
|
|
427
|
+
select(models.GenerativeModel)
|
|
428
|
+
.where(models.GenerativeModel.deleted_at.is_(None))
|
|
429
|
+
.where(models.GenerativeModel.is_built_in.is_(True))
|
|
430
|
+
.options(joinedload(models.GenerativeModel.token_prices))
|
|
431
|
+
)
|
|
432
|
+
).unique()
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
seen_names: set[str] = set()
|
|
436
|
+
seen_patterns: set[tuple[re.Pattern[str], str]] = set()
|
|
437
|
+
|
|
438
|
+
# Process each model in the manifest
|
|
439
|
+
for model_data in manifest:
|
|
440
|
+
name = str(model_data.get("model") or "").strip()
|
|
441
|
+
if not name:
|
|
442
|
+
logger.warning("Skipping model with empty name in manifest")
|
|
443
|
+
continue
|
|
444
|
+
if name in seen_names:
|
|
445
|
+
logger.warning(f"Skipping model '{name}' with duplicate name in manifest")
|
|
446
|
+
continue
|
|
447
|
+
seen_names.add(name)
|
|
448
|
+
regex = str(model_data.get("regex") or "").strip()
|
|
449
|
+
try:
|
|
450
|
+
pattern = re.compile(regex)
|
|
451
|
+
except re.error as e:
|
|
452
|
+
logger.warning(f"Skipping model '{name}' with invalid regex: {e}")
|
|
453
|
+
continue
|
|
454
|
+
provider = str(model_data.get("provider") or "").strip()
|
|
455
|
+
if (pattern, provider) in seen_patterns:
|
|
456
|
+
logger.warning(
|
|
457
|
+
f"Skipping model '{name}' with duplicate name_pattern/provider combination"
|
|
458
|
+
)
|
|
459
|
+
continue
|
|
460
|
+
seen_patterns.add((pattern, provider))
|
|
461
|
+
# Remove model from built_in_models dict (for cleanup tracking)
|
|
462
|
+
# or create new model if not found
|
|
463
|
+
model = built_in_models.pop(model_data["model"], None)
|
|
464
|
+
if model is None:
|
|
465
|
+
# Create new built-in model from manifest data
|
|
466
|
+
model = models.GenerativeModel(
|
|
467
|
+
name=name,
|
|
468
|
+
provider=provider,
|
|
469
|
+
name_pattern=pattern,
|
|
470
|
+
is_built_in=True,
|
|
471
|
+
)
|
|
472
|
+
session.add(model)
|
|
473
|
+
else:
|
|
474
|
+
# Update existing model's metadata from manifest
|
|
475
|
+
model.provider = provider
|
|
476
|
+
model.name_pattern = pattern
|
|
477
|
+
|
|
478
|
+
# Create lookup table for existing token prices by (token_type, is_prompt)
|
|
479
|
+
# Using pop() during iteration allows us to track which prices are no longer needed
|
|
480
|
+
token_prices = {
|
|
481
|
+
_TokenTypeKey(token_price.token_type, token_price.is_prompt): token_price
|
|
482
|
+
for token_price in model.token_prices
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
# Synchronize token prices for all supported token types
|
|
486
|
+
for token_type, is_prompt in token_types:
|
|
487
|
+
# Skip if this token type has no rate in the manifest
|
|
488
|
+
if not (base_rate := model_data.get(token_type)):
|
|
489
|
+
continue
|
|
490
|
+
|
|
491
|
+
key = _TokenTypeKey(token_type, is_prompt)
|
|
492
|
+
# Remove from tracking dict and get existing price (if any)
|
|
493
|
+
if not (token_price := token_prices.pop(key, None)):
|
|
494
|
+
# Create new token price if it doesn't exist
|
|
495
|
+
token_price = models.TokenPrice(
|
|
496
|
+
token_type=token_type,
|
|
497
|
+
is_prompt=is_prompt,
|
|
498
|
+
base_rate=base_rate,
|
|
499
|
+
)
|
|
500
|
+
model.token_prices.append(token_price)
|
|
501
|
+
elif token_price.base_rate != base_rate:
|
|
502
|
+
# Update existing price if rate has changed
|
|
503
|
+
token_price.base_rate = base_rate
|
|
504
|
+
|
|
505
|
+
# Remove any token prices that are no longer in the manifest
|
|
506
|
+
# These are prices that weren't popped from the token_prices dict above
|
|
507
|
+
for token_price in token_prices.values():
|
|
508
|
+
model.token_prices.remove(token_price)
|
|
509
|
+
|
|
510
|
+
# Clean up built-in models that are no longer in the manifest
|
|
511
|
+
# These are models that weren't popped from built_in_models dict above
|
|
512
|
+
remaining_models = list(built_in_models.values())
|
|
513
|
+
if not remaining_models:
|
|
514
|
+
return
|
|
515
|
+
|
|
516
|
+
# Soft delete obsolete built-in models
|
|
517
|
+
async with db() as session:
|
|
518
|
+
await session.execute(
|
|
519
|
+
sa.update(models.GenerativeModel)
|
|
520
|
+
.values(deleted_at=sa.func.now())
|
|
521
|
+
.where(models.GenerativeModel.id.in_([m.id for m in remaining_models]))
|
|
522
|
+
)
|