arize-phoenix 4.15.0__tar.gz → 4.16.1__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.

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