arize-phoenix 3.16.1__py3-none-any.whl → 7.7.0__py3-none-any.whl

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 (338) hide show
  1. arize_phoenix-7.7.0.dist-info/METADATA +261 -0
  2. arize_phoenix-7.7.0.dist-info/RECORD +345 -0
  3. {arize_phoenix-3.16.1.dist-info → arize_phoenix-7.7.0.dist-info}/WHEEL +1 -1
  4. arize_phoenix-7.7.0.dist-info/entry_points.txt +3 -0
  5. phoenix/__init__.py +86 -14
  6. phoenix/auth.py +309 -0
  7. phoenix/config.py +675 -45
  8. phoenix/core/model.py +32 -30
  9. phoenix/core/model_schema.py +102 -109
  10. phoenix/core/model_schema_adapter.py +48 -45
  11. phoenix/datetime_utils.py +24 -3
  12. phoenix/db/README.md +54 -0
  13. phoenix/db/__init__.py +4 -0
  14. phoenix/db/alembic.ini +85 -0
  15. phoenix/db/bulk_inserter.py +294 -0
  16. phoenix/db/engines.py +208 -0
  17. phoenix/db/enums.py +20 -0
  18. phoenix/db/facilitator.py +113 -0
  19. phoenix/db/helpers.py +159 -0
  20. phoenix/db/insertion/constants.py +2 -0
  21. phoenix/db/insertion/dataset.py +227 -0
  22. phoenix/db/insertion/document_annotation.py +171 -0
  23. phoenix/db/insertion/evaluation.py +191 -0
  24. phoenix/db/insertion/helpers.py +98 -0
  25. phoenix/db/insertion/span.py +193 -0
  26. phoenix/db/insertion/span_annotation.py +158 -0
  27. phoenix/db/insertion/trace_annotation.py +158 -0
  28. phoenix/db/insertion/types.py +256 -0
  29. phoenix/db/migrate.py +86 -0
  30. phoenix/db/migrations/data_migration_scripts/populate_project_sessions.py +199 -0
  31. phoenix/db/migrations/env.py +114 -0
  32. phoenix/db/migrations/script.py.mako +26 -0
  33. phoenix/db/migrations/versions/10460e46d750_datasets.py +317 -0
  34. phoenix/db/migrations/versions/3be8647b87d8_add_token_columns_to_spans_table.py +126 -0
  35. phoenix/db/migrations/versions/4ded9e43755f_create_project_sessions_table.py +66 -0
  36. phoenix/db/migrations/versions/cd164e83824f_users_and_tokens.py +157 -0
  37. phoenix/db/migrations/versions/cf03bd6bae1d_init.py +280 -0
  38. phoenix/db/models.py +807 -0
  39. phoenix/exceptions.py +5 -1
  40. phoenix/experiments/__init__.py +6 -0
  41. phoenix/experiments/evaluators/__init__.py +29 -0
  42. phoenix/experiments/evaluators/base.py +158 -0
  43. phoenix/experiments/evaluators/code_evaluators.py +184 -0
  44. phoenix/experiments/evaluators/llm_evaluators.py +473 -0
  45. phoenix/experiments/evaluators/utils.py +236 -0
  46. phoenix/experiments/functions.py +772 -0
  47. phoenix/experiments/tracing.py +86 -0
  48. phoenix/experiments/types.py +726 -0
  49. phoenix/experiments/utils.py +25 -0
  50. phoenix/inferences/__init__.py +0 -0
  51. phoenix/{datasets → inferences}/errors.py +6 -5
  52. phoenix/{datasets → inferences}/fixtures.py +49 -42
  53. phoenix/{datasets/dataset.py → inferences/inferences.py} +121 -105
  54. phoenix/{datasets → inferences}/schema.py +11 -11
  55. phoenix/{datasets → inferences}/validation.py +13 -14
  56. phoenix/logging/__init__.py +3 -0
  57. phoenix/logging/_config.py +90 -0
  58. phoenix/logging/_filter.py +6 -0
  59. phoenix/logging/_formatter.py +69 -0
  60. phoenix/metrics/__init__.py +5 -4
  61. phoenix/metrics/binning.py +4 -3
  62. phoenix/metrics/metrics.py +2 -1
  63. phoenix/metrics/mixins.py +7 -6
  64. phoenix/metrics/retrieval_metrics.py +2 -1
  65. phoenix/metrics/timeseries.py +5 -4
  66. phoenix/metrics/wrappers.py +9 -3
  67. phoenix/pointcloud/clustering.py +5 -5
  68. phoenix/pointcloud/pointcloud.py +7 -5
  69. phoenix/pointcloud/projectors.py +5 -6
  70. phoenix/pointcloud/umap_parameters.py +53 -52
  71. phoenix/server/api/README.md +28 -0
  72. phoenix/server/api/auth.py +44 -0
  73. phoenix/server/api/context.py +152 -9
  74. phoenix/server/api/dataloaders/__init__.py +91 -0
  75. phoenix/server/api/dataloaders/annotation_summaries.py +139 -0
  76. phoenix/server/api/dataloaders/average_experiment_run_latency.py +54 -0
  77. phoenix/server/api/dataloaders/cache/__init__.py +3 -0
  78. phoenix/server/api/dataloaders/cache/two_tier_cache.py +68 -0
  79. phoenix/server/api/dataloaders/dataset_example_revisions.py +131 -0
  80. phoenix/server/api/dataloaders/dataset_example_spans.py +38 -0
  81. phoenix/server/api/dataloaders/document_evaluation_summaries.py +144 -0
  82. phoenix/server/api/dataloaders/document_evaluations.py +31 -0
  83. phoenix/server/api/dataloaders/document_retrieval_metrics.py +89 -0
  84. phoenix/server/api/dataloaders/experiment_annotation_summaries.py +79 -0
  85. phoenix/server/api/dataloaders/experiment_error_rates.py +58 -0
  86. phoenix/server/api/dataloaders/experiment_run_annotations.py +36 -0
  87. phoenix/server/api/dataloaders/experiment_run_counts.py +49 -0
  88. phoenix/server/api/dataloaders/experiment_sequence_number.py +44 -0
  89. phoenix/server/api/dataloaders/latency_ms_quantile.py +188 -0
  90. phoenix/server/api/dataloaders/min_start_or_max_end_times.py +85 -0
  91. phoenix/server/api/dataloaders/project_by_name.py +31 -0
  92. phoenix/server/api/dataloaders/record_counts.py +116 -0
  93. phoenix/server/api/dataloaders/session_io.py +79 -0
  94. phoenix/server/api/dataloaders/session_num_traces.py +30 -0
  95. phoenix/server/api/dataloaders/session_num_traces_with_error.py +32 -0
  96. phoenix/server/api/dataloaders/session_token_usages.py +41 -0
  97. phoenix/server/api/dataloaders/session_trace_latency_ms_quantile.py +55 -0
  98. phoenix/server/api/dataloaders/span_annotations.py +26 -0
  99. phoenix/server/api/dataloaders/span_dataset_examples.py +31 -0
  100. phoenix/server/api/dataloaders/span_descendants.py +57 -0
  101. phoenix/server/api/dataloaders/span_projects.py +33 -0
  102. phoenix/server/api/dataloaders/token_counts.py +124 -0
  103. phoenix/server/api/dataloaders/trace_by_trace_ids.py +25 -0
  104. phoenix/server/api/dataloaders/trace_root_spans.py +32 -0
  105. phoenix/server/api/dataloaders/user_roles.py +30 -0
  106. phoenix/server/api/dataloaders/users.py +33 -0
  107. phoenix/server/api/exceptions.py +48 -0
  108. phoenix/server/api/helpers/__init__.py +12 -0
  109. phoenix/server/api/helpers/dataset_helpers.py +217 -0
  110. phoenix/server/api/helpers/experiment_run_filters.py +763 -0
  111. phoenix/server/api/helpers/playground_clients.py +948 -0
  112. phoenix/server/api/helpers/playground_registry.py +70 -0
  113. phoenix/server/api/helpers/playground_spans.py +455 -0
  114. phoenix/server/api/input_types/AddExamplesToDatasetInput.py +16 -0
  115. phoenix/server/api/input_types/AddSpansToDatasetInput.py +14 -0
  116. phoenix/server/api/input_types/ChatCompletionInput.py +38 -0
  117. phoenix/server/api/input_types/ChatCompletionMessageInput.py +24 -0
  118. phoenix/server/api/input_types/ClearProjectInput.py +15 -0
  119. phoenix/server/api/input_types/ClusterInput.py +2 -2
  120. phoenix/server/api/input_types/CreateDatasetInput.py +12 -0
  121. phoenix/server/api/input_types/CreateSpanAnnotationInput.py +18 -0
  122. phoenix/server/api/input_types/CreateTraceAnnotationInput.py +18 -0
  123. phoenix/server/api/input_types/DataQualityMetricInput.py +5 -2
  124. phoenix/server/api/input_types/DatasetExampleInput.py +14 -0
  125. phoenix/server/api/input_types/DatasetSort.py +17 -0
  126. phoenix/server/api/input_types/DatasetVersionSort.py +16 -0
  127. phoenix/server/api/input_types/DeleteAnnotationsInput.py +7 -0
  128. phoenix/server/api/input_types/DeleteDatasetExamplesInput.py +13 -0
  129. phoenix/server/api/input_types/DeleteDatasetInput.py +7 -0
  130. phoenix/server/api/input_types/DeleteExperimentsInput.py +7 -0
  131. phoenix/server/api/input_types/DimensionFilter.py +4 -4
  132. phoenix/server/api/input_types/GenerativeModelInput.py +17 -0
  133. phoenix/server/api/input_types/Granularity.py +1 -1
  134. phoenix/server/api/input_types/InvocationParameters.py +162 -0
  135. phoenix/server/api/input_types/PatchAnnotationInput.py +19 -0
  136. phoenix/server/api/input_types/PatchDatasetExamplesInput.py +35 -0
  137. phoenix/server/api/input_types/PatchDatasetInput.py +14 -0
  138. phoenix/server/api/input_types/PerformanceMetricInput.py +5 -2
  139. phoenix/server/api/input_types/ProjectSessionSort.py +29 -0
  140. phoenix/server/api/input_types/SpanAnnotationSort.py +17 -0
  141. phoenix/server/api/input_types/SpanSort.py +134 -69
  142. phoenix/server/api/input_types/TemplateOptions.py +10 -0
  143. phoenix/server/api/input_types/TraceAnnotationSort.py +17 -0
  144. phoenix/server/api/input_types/UserRoleInput.py +9 -0
  145. phoenix/server/api/mutations/__init__.py +28 -0
  146. phoenix/server/api/mutations/api_key_mutations.py +167 -0
  147. phoenix/server/api/mutations/chat_mutations.py +593 -0
  148. phoenix/server/api/mutations/dataset_mutations.py +591 -0
  149. phoenix/server/api/mutations/experiment_mutations.py +75 -0
  150. phoenix/server/api/{types/ExportEventsMutation.py → mutations/export_events_mutations.py} +21 -18
  151. phoenix/server/api/mutations/project_mutations.py +57 -0
  152. phoenix/server/api/mutations/span_annotations_mutations.py +128 -0
  153. phoenix/server/api/mutations/trace_annotations_mutations.py +127 -0
  154. phoenix/server/api/mutations/user_mutations.py +329 -0
  155. phoenix/server/api/openapi/__init__.py +0 -0
  156. phoenix/server/api/openapi/main.py +17 -0
  157. phoenix/server/api/openapi/schema.py +16 -0
  158. phoenix/server/api/queries.py +738 -0
  159. phoenix/server/api/routers/__init__.py +11 -0
  160. phoenix/server/api/routers/auth.py +284 -0
  161. phoenix/server/api/routers/embeddings.py +26 -0
  162. phoenix/server/api/routers/oauth2.py +488 -0
  163. phoenix/server/api/routers/v1/__init__.py +64 -0
  164. phoenix/server/api/routers/v1/datasets.py +1017 -0
  165. phoenix/server/api/routers/v1/evaluations.py +362 -0
  166. phoenix/server/api/routers/v1/experiment_evaluations.py +115 -0
  167. phoenix/server/api/routers/v1/experiment_runs.py +167 -0
  168. phoenix/server/api/routers/v1/experiments.py +308 -0
  169. phoenix/server/api/routers/v1/pydantic_compat.py +78 -0
  170. phoenix/server/api/routers/v1/spans.py +267 -0
  171. phoenix/server/api/routers/v1/traces.py +208 -0
  172. phoenix/server/api/routers/v1/utils.py +95 -0
  173. phoenix/server/api/schema.py +44 -241
  174. phoenix/server/api/subscriptions.py +597 -0
  175. phoenix/server/api/types/Annotation.py +21 -0
  176. phoenix/server/api/types/AnnotationSummary.py +55 -0
  177. phoenix/server/api/types/AnnotatorKind.py +16 -0
  178. phoenix/server/api/types/ApiKey.py +27 -0
  179. phoenix/server/api/types/AuthMethod.py +9 -0
  180. phoenix/server/api/types/ChatCompletionMessageRole.py +11 -0
  181. phoenix/server/api/types/ChatCompletionSubscriptionPayload.py +46 -0
  182. phoenix/server/api/types/Cluster.py +25 -24
  183. phoenix/server/api/types/CreateDatasetPayload.py +8 -0
  184. phoenix/server/api/types/DataQualityMetric.py +31 -13
  185. phoenix/server/api/types/Dataset.py +288 -63
  186. phoenix/server/api/types/DatasetExample.py +85 -0
  187. phoenix/server/api/types/DatasetExampleRevision.py +34 -0
  188. phoenix/server/api/types/DatasetVersion.py +14 -0
  189. phoenix/server/api/types/Dimension.py +32 -31
  190. phoenix/server/api/types/DocumentEvaluationSummary.py +9 -8
  191. phoenix/server/api/types/EmbeddingDimension.py +56 -49
  192. phoenix/server/api/types/Evaluation.py +25 -31
  193. phoenix/server/api/types/EvaluationSummary.py +30 -50
  194. phoenix/server/api/types/Event.py +20 -20
  195. phoenix/server/api/types/ExampleRevisionInterface.py +14 -0
  196. phoenix/server/api/types/Experiment.py +152 -0
  197. phoenix/server/api/types/ExperimentAnnotationSummary.py +13 -0
  198. phoenix/server/api/types/ExperimentComparison.py +17 -0
  199. phoenix/server/api/types/ExperimentRun.py +119 -0
  200. phoenix/server/api/types/ExperimentRunAnnotation.py +56 -0
  201. phoenix/server/api/types/GenerativeModel.py +9 -0
  202. phoenix/server/api/types/GenerativeProvider.py +85 -0
  203. phoenix/server/api/types/Inferences.py +80 -0
  204. phoenix/server/api/types/InferencesRole.py +23 -0
  205. phoenix/server/api/types/LabelFraction.py +7 -0
  206. phoenix/server/api/types/MimeType.py +2 -2
  207. phoenix/server/api/types/Model.py +54 -54
  208. phoenix/server/api/types/PerformanceMetric.py +8 -5
  209. phoenix/server/api/types/Project.py +407 -142
  210. phoenix/server/api/types/ProjectSession.py +139 -0
  211. phoenix/server/api/types/Segments.py +4 -4
  212. phoenix/server/api/types/Span.py +221 -176
  213. phoenix/server/api/types/SpanAnnotation.py +43 -0
  214. phoenix/server/api/types/SpanIOValue.py +15 -0
  215. phoenix/server/api/types/SystemApiKey.py +9 -0
  216. phoenix/server/api/types/TemplateLanguage.py +10 -0
  217. phoenix/server/api/types/TimeSeries.py +19 -15
  218. phoenix/server/api/types/TokenUsage.py +11 -0
  219. phoenix/server/api/types/Trace.py +154 -0
  220. phoenix/server/api/types/TraceAnnotation.py +45 -0
  221. phoenix/server/api/types/UMAPPoints.py +7 -7
  222. phoenix/server/api/types/User.py +60 -0
  223. phoenix/server/api/types/UserApiKey.py +45 -0
  224. phoenix/server/api/types/UserRole.py +15 -0
  225. phoenix/server/api/types/node.py +4 -112
  226. phoenix/server/api/types/pagination.py +156 -57
  227. phoenix/server/api/utils.py +34 -0
  228. phoenix/server/app.py +864 -115
  229. phoenix/server/bearer_auth.py +163 -0
  230. phoenix/server/dml_event.py +136 -0
  231. phoenix/server/dml_event_handler.py +256 -0
  232. phoenix/server/email/__init__.py +0 -0
  233. phoenix/server/email/sender.py +97 -0
  234. phoenix/server/email/templates/__init__.py +0 -0
  235. phoenix/server/email/templates/password_reset.html +19 -0
  236. phoenix/server/email/types.py +11 -0
  237. phoenix/server/grpc_server.py +102 -0
  238. phoenix/server/jwt_store.py +505 -0
  239. phoenix/server/main.py +305 -116
  240. phoenix/server/oauth2.py +52 -0
  241. phoenix/server/openapi/__init__.py +0 -0
  242. phoenix/server/prometheus.py +111 -0
  243. phoenix/server/rate_limiters.py +188 -0
  244. phoenix/server/static/.vite/manifest.json +87 -0
  245. phoenix/server/static/assets/components-Cy9nwIvF.js +2125 -0
  246. phoenix/server/static/assets/index-BKvHIxkk.js +113 -0
  247. phoenix/server/static/assets/pages-CUi2xCVQ.js +4449 -0
  248. phoenix/server/static/assets/vendor-DvC8cT4X.js +894 -0
  249. phoenix/server/static/assets/vendor-DxkFTwjz.css +1 -0
  250. phoenix/server/static/assets/vendor-arizeai-Do1793cv.js +662 -0
  251. phoenix/server/static/assets/vendor-codemirror-BzwZPyJM.js +24 -0
  252. phoenix/server/static/assets/vendor-recharts-_Jb7JjhG.js +59 -0
  253. phoenix/server/static/assets/vendor-shiki-Cl9QBraO.js +5 -0
  254. phoenix/server/static/assets/vendor-three-DwGkEfCM.js +2998 -0
  255. phoenix/server/telemetry.py +68 -0
  256. phoenix/server/templates/index.html +82 -23
  257. phoenix/server/thread_server.py +3 -3
  258. phoenix/server/types.py +275 -0
  259. phoenix/services.py +27 -18
  260. phoenix/session/client.py +743 -68
  261. phoenix/session/data_extractor.py +31 -7
  262. phoenix/session/evaluation.py +3 -9
  263. phoenix/session/session.py +263 -219
  264. phoenix/settings.py +22 -0
  265. phoenix/trace/__init__.py +2 -22
  266. phoenix/trace/attributes.py +338 -0
  267. phoenix/trace/dsl/README.md +116 -0
  268. phoenix/trace/dsl/filter.py +663 -213
  269. phoenix/trace/dsl/helpers.py +73 -21
  270. phoenix/trace/dsl/query.py +574 -201
  271. phoenix/trace/exporter.py +24 -19
  272. phoenix/trace/fixtures.py +368 -32
  273. phoenix/trace/otel.py +71 -219
  274. phoenix/trace/projects.py +3 -2
  275. phoenix/trace/schemas.py +33 -11
  276. phoenix/trace/span_evaluations.py +21 -16
  277. phoenix/trace/span_json_decoder.py +6 -4
  278. phoenix/trace/span_json_encoder.py +2 -2
  279. phoenix/trace/trace_dataset.py +47 -32
  280. phoenix/trace/utils.py +21 -4
  281. phoenix/utilities/__init__.py +0 -26
  282. phoenix/utilities/client.py +132 -0
  283. phoenix/utilities/deprecation.py +31 -0
  284. phoenix/utilities/error_handling.py +3 -2
  285. phoenix/utilities/json.py +109 -0
  286. phoenix/utilities/logging.py +8 -0
  287. phoenix/utilities/project.py +2 -2
  288. phoenix/utilities/re.py +49 -0
  289. phoenix/utilities/span_store.py +0 -23
  290. phoenix/utilities/template_formatters.py +99 -0
  291. phoenix/version.py +1 -1
  292. arize_phoenix-3.16.1.dist-info/METADATA +0 -495
  293. arize_phoenix-3.16.1.dist-info/RECORD +0 -178
  294. phoenix/core/project.py +0 -619
  295. phoenix/core/traces.py +0 -96
  296. phoenix/experimental/evals/__init__.py +0 -73
  297. phoenix/experimental/evals/evaluators.py +0 -413
  298. phoenix/experimental/evals/functions/__init__.py +0 -4
  299. phoenix/experimental/evals/functions/classify.py +0 -453
  300. phoenix/experimental/evals/functions/executor.py +0 -353
  301. phoenix/experimental/evals/functions/generate.py +0 -138
  302. phoenix/experimental/evals/functions/processing.py +0 -76
  303. phoenix/experimental/evals/models/__init__.py +0 -14
  304. phoenix/experimental/evals/models/anthropic.py +0 -175
  305. phoenix/experimental/evals/models/base.py +0 -170
  306. phoenix/experimental/evals/models/bedrock.py +0 -221
  307. phoenix/experimental/evals/models/litellm.py +0 -134
  308. phoenix/experimental/evals/models/openai.py +0 -448
  309. phoenix/experimental/evals/models/rate_limiters.py +0 -246
  310. phoenix/experimental/evals/models/vertex.py +0 -173
  311. phoenix/experimental/evals/models/vertexai.py +0 -186
  312. phoenix/experimental/evals/retrievals.py +0 -96
  313. phoenix/experimental/evals/templates/__init__.py +0 -50
  314. phoenix/experimental/evals/templates/default_templates.py +0 -472
  315. phoenix/experimental/evals/templates/template.py +0 -195
  316. phoenix/experimental/evals/utils/__init__.py +0 -172
  317. phoenix/experimental/evals/utils/threads.py +0 -27
  318. phoenix/server/api/helpers.py +0 -11
  319. phoenix/server/api/routers/evaluation_handler.py +0 -109
  320. phoenix/server/api/routers/span_handler.py +0 -70
  321. phoenix/server/api/routers/trace_handler.py +0 -60
  322. phoenix/server/api/types/DatasetRole.py +0 -23
  323. phoenix/server/static/index.css +0 -6
  324. phoenix/server/static/index.js +0 -7447
  325. phoenix/storage/span_store/__init__.py +0 -23
  326. phoenix/storage/span_store/text_file.py +0 -85
  327. phoenix/trace/dsl/missing.py +0 -60
  328. phoenix/trace/langchain/__init__.py +0 -3
  329. phoenix/trace/langchain/instrumentor.py +0 -35
  330. phoenix/trace/llama_index/__init__.py +0 -3
  331. phoenix/trace/llama_index/callback.py +0 -102
  332. phoenix/trace/openai/__init__.py +0 -3
  333. phoenix/trace/openai/instrumentor.py +0 -30
  334. {arize_phoenix-3.16.1.dist-info → arize_phoenix-7.7.0.dist-info}/licenses/IP_NOTICE +0 -0
  335. {arize_phoenix-3.16.1.dist-info → arize_phoenix-7.7.0.dist-info}/licenses/LICENSE +0 -0
  336. /phoenix/{datasets → db/insertion}/__init__.py +0 -0
  337. /phoenix/{experimental → db/migrations}/__init__.py +0 -0
  338. /phoenix/{storage → db/migrations/data_migration_scripts}/__init__.py +0 -0
@@ -1,23 +1,25 @@
1
1
  import asyncio
2
2
  from collections import defaultdict
3
3
  from datetime import datetime
4
- from typing import Dict, List, Optional, Tuple
4
+ from typing import Optional
5
5
 
6
6
  import strawberry
7
7
  from strawberry import ID, UNSET
8
8
  from strawberry.types import Info
9
9
 
10
10
  import phoenix.core.model_schema as ms
11
+ from phoenix.server.api.auth import IsNotReadOnly
11
12
  from phoenix.server.api.context import Context
12
13
  from phoenix.server.api.input_types.ClusterInput import ClusterInput
13
- from phoenix.server.api.types.DatasetRole import AncillaryDatasetRole, DatasetRole
14
- from phoenix.server.api.types.Event import parse_event_ids_by_dataset_role, unpack_event_id
14
+ from phoenix.server.api.types.Event import parse_event_ids_by_inferences_role, unpack_event_id
15
15
  from phoenix.server.api.types.ExportedFile import ExportedFile
16
+ from phoenix.server.api.types.InferencesRole import AncillaryInferencesRole, InferencesRole
16
17
 
17
18
 
18
19
  @strawberry.type
19
- class ExportEventsMutation:
20
+ class ExportEventsMutationMixin:
20
21
  @strawberry.mutation(
22
+ permission_classes=[IsNotReadOnly],
21
23
  description=(
22
24
  "Given a list of event ids, export the corresponding data subset in Parquet format."
23
25
  " File name is optional, but if specified, should be without file extension. By default"
@@ -27,16 +29,16 @@ class ExportEventsMutation:
27
29
  async def export_events(
28
30
  self,
29
31
  info: Info[Context, None],
30
- event_ids: List[ID],
32
+ event_ids: list[ID],
31
33
  file_name: Optional[str] = UNSET,
32
34
  ) -> ExportedFile:
33
35
  if not isinstance(file_name, str):
34
36
  file_name = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
35
- row_ids = parse_event_ids_by_dataset_role(event_ids)
37
+ row_ids = parse_event_ids_by_inferences_role(event_ids)
36
38
  exclude_corpus_row_ids = {}
37
- for dataset_role in list(row_ids.keys()):
38
- if isinstance(dataset_role, DatasetRole):
39
- exclude_corpus_row_ids[dataset_role.value] = row_ids[dataset_role]
39
+ for inferences_role in list(row_ids.keys()):
40
+ if isinstance(inferences_role, InferencesRole):
41
+ exclude_corpus_row_ids[inferences_role.value] = row_ids[inferences_role]
40
42
  path = info.context.export_path
41
43
  with open(path / (file_name + ".parquet"), "wb") as fd:
42
44
  loop = asyncio.get_running_loop()
@@ -49,6 +51,7 @@ class ExportEventsMutation:
49
51
  return ExportedFile(file_name=file_name)
50
52
 
51
53
  @strawberry.mutation(
54
+ permission_classes=[IsNotReadOnly],
52
55
  description=(
53
56
  "Given a list of clusters, export the corresponding data subset in Parquet format."
54
57
  " File name is optional, but if specified, should be without file extension. By default"
@@ -58,7 +61,7 @@ class ExportEventsMutation:
58
61
  async def export_clusters(
59
62
  self,
60
63
  info: Info[Context, None],
61
- clusters: List[ClusterInput],
64
+ clusters: list[ClusterInput],
62
65
  file_name: Optional[str] = UNSET,
63
66
  ) -> ExportedFile:
64
67
  if not isinstance(file_name, str):
@@ -78,14 +81,14 @@ class ExportEventsMutation:
78
81
 
79
82
 
80
83
  def _unpack_clusters(
81
- clusters: List[ClusterInput],
82
- ) -> Tuple[Dict[ms.DatasetRole, List[int]], Dict[ms.DatasetRole, Dict[int, str]]]:
83
- row_numbers: Dict[ms.DatasetRole, List[int]] = defaultdict(list)
84
- cluster_ids: Dict[ms.DatasetRole, Dict[int, str]] = defaultdict(dict)
84
+ clusters: list[ClusterInput],
85
+ ) -> tuple[dict[ms.InferencesRole, list[int]], dict[ms.InferencesRole, dict[int, str]]]:
86
+ row_numbers: dict[ms.InferencesRole, list[int]] = defaultdict(list)
87
+ cluster_ids: dict[ms.InferencesRole, dict[int, str]] = defaultdict(dict)
85
88
  for i, cluster in enumerate(clusters):
86
- for row_number, dataset_role in map(unpack_event_id, cluster.event_ids):
87
- if isinstance(dataset_role, AncillaryDatasetRole):
89
+ for row_number, inferences_role in map(unpack_event_id, cluster.event_ids):
90
+ if isinstance(inferences_role, AncillaryInferencesRole):
88
91
  continue
89
- row_numbers[dataset_role.value].append(row_number)
90
- cluster_ids[dataset_role.value][row_number] = cluster.id or str(i)
92
+ row_numbers[inferences_role.value].append(row_number)
93
+ cluster_ids[inferences_role.value][row_number] = cluster.id or str(i)
91
94
  return row_numbers, cluster_ids
@@ -0,0 +1,57 @@
1
+ import strawberry
2
+ from sqlalchemy import delete, select
3
+ from sqlalchemy.orm import load_only
4
+ from strawberry.relay import GlobalID
5
+ from strawberry.types import Info
6
+
7
+ from phoenix.config import DEFAULT_PROJECT_NAME
8
+ from phoenix.db import models
9
+ from phoenix.server.api.auth import IsNotReadOnly
10
+ from phoenix.server.api.context import Context
11
+ from phoenix.server.api.input_types.ClearProjectInput import ClearProjectInput
12
+ from phoenix.server.api.queries import Query
13
+ from phoenix.server.api.types.node import from_global_id_with_expected_type
14
+ from phoenix.server.dml_event import ProjectDeleteEvent, SpanDeleteEvent
15
+
16
+
17
+ @strawberry.type
18
+ class ProjectMutationMixin:
19
+ @strawberry.mutation(permission_classes=[IsNotReadOnly]) # type: ignore
20
+ async def delete_project(self, info: Info[Context, None], id: GlobalID) -> Query:
21
+ project_id = from_global_id_with_expected_type(global_id=id, expected_type_name="Project")
22
+ async with info.context.db() as session:
23
+ project = await session.scalar(
24
+ select(models.Project)
25
+ .where(models.Project.id == project_id)
26
+ .options(load_only(models.Project.name))
27
+ )
28
+ if project is None:
29
+ raise ValueError(f"Unknown project: {id}")
30
+ if project.name == DEFAULT_PROJECT_NAME:
31
+ raise ValueError(f"Cannot delete the {DEFAULT_PROJECT_NAME} project")
32
+ await session.delete(project)
33
+ info.context.event_queue.put(ProjectDeleteEvent((project_id,)))
34
+ return Query()
35
+
36
+ @strawberry.mutation(permission_classes=[IsNotReadOnly]) # type: ignore
37
+ async def clear_project(self, info: Info[Context, None], input: ClearProjectInput) -> Query:
38
+ project_id = from_global_id_with_expected_type(
39
+ global_id=input.id, expected_type_name="Project"
40
+ )
41
+ delete_statement = (
42
+ delete(models.Trace)
43
+ .where(models.Trace.project_rowid == project_id)
44
+ .returning(models.Trace.project_session_rowid)
45
+ )
46
+ if input.end_time:
47
+ delete_statement = delete_statement.where(models.Trace.start_time < input.end_time)
48
+ async with info.context.db() as session:
49
+ deleted_trace_project_session_ids = await session.scalars(delete_statement)
50
+ if deleted_trace_project_session_ids:
51
+ await session.execute(
52
+ delete(models.ProjectSession).where(
53
+ models.ProjectSession.id.in_(set(deleted_trace_project_session_ids))
54
+ )
55
+ )
56
+ info.context.event_queue.put(SpanDeleteEvent((project_id,)))
57
+ return Query()
@@ -0,0 +1,128 @@
1
+ from collections.abc import Sequence
2
+
3
+ import strawberry
4
+ from sqlalchemy import delete, insert, update
5
+ from strawberry import UNSET
6
+ from strawberry.types import Info
7
+
8
+ from phoenix.db import models
9
+ from phoenix.server.api.auth import IsLocked, IsNotReadOnly
10
+ from phoenix.server.api.context import Context
11
+ from phoenix.server.api.input_types.CreateSpanAnnotationInput import CreateSpanAnnotationInput
12
+ from phoenix.server.api.input_types.DeleteAnnotationsInput import DeleteAnnotationsInput
13
+ from phoenix.server.api.input_types.PatchAnnotationInput import PatchAnnotationInput
14
+ from phoenix.server.api.queries import Query
15
+ from phoenix.server.api.types.node import from_global_id_with_expected_type
16
+ from phoenix.server.api.types.SpanAnnotation import SpanAnnotation, to_gql_span_annotation
17
+ from phoenix.server.dml_event import SpanAnnotationDeleteEvent, SpanAnnotationInsertEvent
18
+
19
+
20
+ @strawberry.type
21
+ class SpanAnnotationMutationPayload:
22
+ span_annotations: list[SpanAnnotation]
23
+ query: Query
24
+
25
+
26
+ @strawberry.type
27
+ class SpanAnnotationMutationMixin:
28
+ @strawberry.mutation(permission_classes=[IsNotReadOnly, IsLocked]) # type: ignore
29
+ async def create_span_annotations(
30
+ self, info: Info[Context, None], input: list[CreateSpanAnnotationInput]
31
+ ) -> SpanAnnotationMutationPayload:
32
+ inserted_annotations: Sequence[models.SpanAnnotation] = []
33
+ async with info.context.db() as session:
34
+ values_list = [
35
+ dict(
36
+ span_rowid=from_global_id_with_expected_type(annotation.span_id, "Span"),
37
+ name=annotation.name,
38
+ label=annotation.label,
39
+ score=annotation.score,
40
+ explanation=annotation.explanation,
41
+ annotator_kind=annotation.annotator_kind.value,
42
+ metadata_=annotation.metadata,
43
+ )
44
+ for annotation in input
45
+ ]
46
+ stmt = (
47
+ insert(models.SpanAnnotation).values(values_list).returning(models.SpanAnnotation)
48
+ )
49
+ result = await session.scalars(stmt)
50
+ inserted_annotations = result.all()
51
+ if inserted_annotations:
52
+ info.context.event_queue.put(
53
+ SpanAnnotationInsertEvent(tuple(anno.id for anno in inserted_annotations))
54
+ )
55
+ return SpanAnnotationMutationPayload(
56
+ span_annotations=[
57
+ to_gql_span_annotation(annotation) for annotation in inserted_annotations
58
+ ],
59
+ query=Query(),
60
+ )
61
+
62
+ @strawberry.mutation(permission_classes=[IsNotReadOnly, IsLocked]) # type: ignore
63
+ async def patch_span_annotations(
64
+ self, info: Info[Context, None], input: list[PatchAnnotationInput]
65
+ ) -> SpanAnnotationMutationPayload:
66
+ patched_annotations = []
67
+ async with info.context.db() as session:
68
+ for annotation in input:
69
+ span_annotation_id = from_global_id_with_expected_type(
70
+ annotation.annotation_id, "SpanAnnotation"
71
+ )
72
+ patch = {
73
+ column.key: patch_value
74
+ for column, patch_value, column_is_nullable in (
75
+ (models.SpanAnnotation.name, annotation.name, False),
76
+ (
77
+ models.SpanAnnotation.annotator_kind,
78
+ annotation.annotator_kind.value
79
+ if annotation.annotator_kind is not None
80
+ and annotation.annotator_kind is not UNSET
81
+ else None,
82
+ False,
83
+ ),
84
+ (models.SpanAnnotation.label, annotation.label, True),
85
+ (models.SpanAnnotation.score, annotation.score, True),
86
+ (models.SpanAnnotation.explanation, annotation.explanation, True),
87
+ (models.SpanAnnotation.metadata_, annotation.metadata, False),
88
+ )
89
+ if patch_value is not UNSET and (patch_value is not None or column_is_nullable)
90
+ }
91
+ span_annotation = await session.scalar(
92
+ update(models.SpanAnnotation)
93
+ .where(models.SpanAnnotation.id == span_annotation_id)
94
+ .values(**patch)
95
+ .returning(models.SpanAnnotation)
96
+ )
97
+ if span_annotation is not None:
98
+ patched_annotations.append(to_gql_span_annotation(span_annotation))
99
+ info.context.event_queue.put(SpanAnnotationInsertEvent((span_annotation.id,)))
100
+ return SpanAnnotationMutationPayload(span_annotations=patched_annotations, query=Query())
101
+
102
+ @strawberry.mutation(permission_classes=[IsNotReadOnly]) # type: ignore
103
+ async def delete_span_annotations(
104
+ self, info: Info[Context, None], input: DeleteAnnotationsInput
105
+ ) -> SpanAnnotationMutationPayload:
106
+ span_annotation_ids = [
107
+ from_global_id_with_expected_type(global_id, "SpanAnnotation")
108
+ for global_id in input.annotation_ids
109
+ ]
110
+ async with info.context.db() as session:
111
+ stmt = (
112
+ delete(models.SpanAnnotation)
113
+ .where(models.SpanAnnotation.id.in_(span_annotation_ids))
114
+ .returning(models.SpanAnnotation)
115
+ )
116
+ result = await session.scalars(stmt)
117
+ deleted_annotations = result.all()
118
+
119
+ deleted_annotations_gql = [
120
+ to_gql_span_annotation(annotation) for annotation in deleted_annotations
121
+ ]
122
+ if deleted_annotations:
123
+ info.context.event_queue.put(
124
+ SpanAnnotationDeleteEvent(tuple(anno.id for anno in deleted_annotations))
125
+ )
126
+ return SpanAnnotationMutationPayload(
127
+ span_annotations=deleted_annotations_gql, query=Query()
128
+ )
@@ -0,0 +1,127 @@
1
+ from collections.abc import Sequence
2
+
3
+ import strawberry
4
+ from sqlalchemy import delete, insert, update
5
+ from strawberry import UNSET
6
+ from strawberry.types import Info
7
+
8
+ from phoenix.db import models
9
+ from phoenix.server.api.auth import IsLocked, IsNotReadOnly
10
+ from phoenix.server.api.context import Context
11
+ from phoenix.server.api.input_types.CreateTraceAnnotationInput import CreateTraceAnnotationInput
12
+ from phoenix.server.api.input_types.DeleteAnnotationsInput import DeleteAnnotationsInput
13
+ from phoenix.server.api.input_types.PatchAnnotationInput import PatchAnnotationInput
14
+ from phoenix.server.api.queries import Query
15
+ from phoenix.server.api.types.node import from_global_id_with_expected_type
16
+ from phoenix.server.api.types.TraceAnnotation import TraceAnnotation, to_gql_trace_annotation
17
+ from phoenix.server.dml_event import TraceAnnotationDeleteEvent, TraceAnnotationInsertEvent
18
+
19
+
20
+ @strawberry.type
21
+ class TraceAnnotationMutationPayload:
22
+ trace_annotations: list[TraceAnnotation]
23
+ query: Query
24
+
25
+
26
+ @strawberry.type
27
+ class TraceAnnotationMutationMixin:
28
+ @strawberry.mutation(permission_classes=[IsNotReadOnly, IsLocked]) # type: ignore
29
+ async def create_trace_annotations(
30
+ self, info: Info[Context, None], input: list[CreateTraceAnnotationInput]
31
+ ) -> TraceAnnotationMutationPayload:
32
+ inserted_annotations: Sequence[models.TraceAnnotation] = []
33
+ async with info.context.db() as session:
34
+ values_list = [
35
+ dict(
36
+ trace_rowid=from_global_id_with_expected_type(annotation.trace_id, "Trace"),
37
+ name=annotation.name,
38
+ label=annotation.label,
39
+ score=annotation.score,
40
+ explanation=annotation.explanation,
41
+ annotator_kind=annotation.annotator_kind.value,
42
+ metadata_=annotation.metadata,
43
+ )
44
+ for annotation in input
45
+ ]
46
+ stmt = (
47
+ insert(models.TraceAnnotation).values(values_list).returning(models.TraceAnnotation)
48
+ )
49
+ result = await session.scalars(stmt)
50
+ inserted_annotations = result.all()
51
+ if inserted_annotations:
52
+ info.context.event_queue.put(
53
+ TraceAnnotationInsertEvent(tuple(anno.id for anno in inserted_annotations))
54
+ )
55
+ return TraceAnnotationMutationPayload(
56
+ trace_annotations=[
57
+ to_gql_trace_annotation(annotation) for annotation in inserted_annotations
58
+ ],
59
+ query=Query(),
60
+ )
61
+
62
+ @strawberry.mutation(permission_classes=[IsNotReadOnly, IsLocked]) # type: ignore
63
+ async def patch_trace_annotations(
64
+ self, info: Info[Context, None], input: list[PatchAnnotationInput]
65
+ ) -> TraceAnnotationMutationPayload:
66
+ patched_annotations = []
67
+ async with info.context.db() as session:
68
+ for annotation in input:
69
+ trace_annotation_id = from_global_id_with_expected_type(
70
+ annotation.annotation_id, "TraceAnnotation"
71
+ )
72
+ patch = {
73
+ column.key: patch_value
74
+ for column, patch_value, column_is_nullable in (
75
+ (models.TraceAnnotation.name, annotation.name, False),
76
+ (
77
+ models.TraceAnnotation.annotator_kind,
78
+ annotation.annotator_kind.value
79
+ if annotation.annotator_kind is not None
80
+ else None,
81
+ False,
82
+ ),
83
+ (models.TraceAnnotation.label, annotation.label, True),
84
+ (models.TraceAnnotation.score, annotation.score, True),
85
+ (models.TraceAnnotation.explanation, annotation.explanation, True),
86
+ (models.TraceAnnotation.metadata_, annotation.metadata, False),
87
+ )
88
+ if patch_value is not UNSET and (patch_value is not None or column_is_nullable)
89
+ }
90
+ trace_annotation = await session.scalar(
91
+ update(models.TraceAnnotation)
92
+ .where(models.TraceAnnotation.id == trace_annotation_id)
93
+ .values(**patch)
94
+ .returning(models.TraceAnnotation)
95
+ )
96
+ if trace_annotation:
97
+ patched_annotations.append(to_gql_trace_annotation(trace_annotation))
98
+ info.context.event_queue.put(TraceAnnotationInsertEvent((trace_annotation.id,)))
99
+ return TraceAnnotationMutationPayload(trace_annotations=patched_annotations, query=Query())
100
+
101
+ @strawberry.mutation(permission_classes=[IsNotReadOnly]) # type: ignore
102
+ async def delete_trace_annotations(
103
+ self, info: Info[Context, None], input: DeleteAnnotationsInput
104
+ ) -> TraceAnnotationMutationPayload:
105
+ trace_annotation_ids = [
106
+ from_global_id_with_expected_type(global_id, "TraceAnnotation")
107
+ for global_id in input.annotation_ids
108
+ ]
109
+ async with info.context.db() as session:
110
+ stmt = (
111
+ delete(models.TraceAnnotation)
112
+ .where(models.TraceAnnotation.id.in_(trace_annotation_ids))
113
+ .returning(models.TraceAnnotation)
114
+ )
115
+ result = await session.scalars(stmt)
116
+ deleted_annotations = result.all()
117
+
118
+ deleted_annotations_gql = [
119
+ to_gql_trace_annotation(annotation) for annotation in deleted_annotations
120
+ ]
121
+ if deleted_annotations:
122
+ info.context.event_queue.put(
123
+ TraceAnnotationDeleteEvent(tuple(anno.id for anno in deleted_annotations))
124
+ )
125
+ return TraceAnnotationMutationPayload(
126
+ trace_annotations=deleted_annotations_gql, query=Query()
127
+ )