arize-phoenix 3.16.0__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.0.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 -247
  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 +13 -107
  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.0.dist-info/METADATA +0 -495
  293. arize_phoenix-3.16.0.dist-info/RECORD +0 -178
  294. phoenix/core/project.py +0 -617
  295. phoenix/core/traces.py +0 -100
  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.0.dist-info → arize_phoenix-7.7.0.dist-info}/licenses/IP_NOTICE +0 -0
  335. {arize_phoenix-3.16.0.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,21 +1,25 @@
1
+ from collections.abc import Iterable
1
2
  from dataclasses import replace
2
3
  from datetime import datetime, timedelta
3
4
  from functools import total_ordering
4
- from typing import Iterable, List, Optional, Tuple, Union, cast
5
+ from typing import Optional, Union, cast
5
6
 
6
7
  import pandas as pd
7
8
  import strawberry
8
9
  from strawberry import UNSET
9
10
 
10
- from phoenix.core.model_schema import CONTINUOUS, PRIMARY, REFERENCE, Column, Dataset, Dimension
11
+ from phoenix.core.model_schema import CONTINUOUS, PRIMARY, REFERENCE, Column, Dimension, Inferences
11
12
  from phoenix.metrics import Metric, binning
12
13
  from phoenix.metrics.mixins import UnaryOperator
13
14
  from phoenix.metrics.timeseries import timeseries
14
15
  from phoenix.server.api.input_types.Granularity import Granularity, to_timestamps
15
16
  from phoenix.server.api.input_types.TimeRange import TimeRange
16
17
  from phoenix.server.api.interceptor import GqlValueMediator
17
- from phoenix.server.api.types.DataQualityMetric import DataQualityMetric
18
- from phoenix.server.api.types.DatasetRole import DatasetRole
18
+ from phoenix.server.api.types.DataQualityMetric import (
19
+ DATA_QUALITY_METRIC_FACTORIES,
20
+ DataQualityMetric,
21
+ )
22
+ from phoenix.server.api.types.InferencesRole import InferencesRole
19
23
  from phoenix.server.api.types.ScalarDriftMetricEnum import ScalarDriftMetric
20
24
  from phoenix.server.api.types.VectorDriftMetricEnum import VectorDriftMetric
21
25
 
@@ -39,7 +43,7 @@ def to_gql_datapoints(
39
43
  df: pd.DataFrame,
40
44
  metric: Metric,
41
45
  timestamps: Iterable[datetime],
42
- ) -> List[TimeSeriesDataPoint]:
46
+ ) -> list[TimeSeriesDataPoint]:
43
47
  data = []
44
48
  for timestamp in timestamps:
45
49
  try:
@@ -59,7 +63,7 @@ def to_gql_datapoints(
59
63
  class TimeSeries:
60
64
  """A collection of data points over time"""
61
65
 
62
- data: List[TimeSeriesDataPoint]
66
+ data: list[TimeSeriesDataPoint]
63
67
 
64
68
 
65
69
  def get_timeseries_data(
@@ -67,7 +71,7 @@ def get_timeseries_data(
67
71
  metric: Metric,
68
72
  time_range: TimeRange,
69
73
  granularity: Granularity,
70
- ) -> List[TimeSeriesDataPoint]:
74
+ ) -> list[TimeSeriesDataPoint]:
71
75
  return df.pipe(
72
76
  timeseries(
73
77
  start_time=time_range.start,
@@ -97,16 +101,16 @@ def get_data_quality_timeseries_data(
97
101
  metric: DataQualityMetric,
98
102
  time_range: TimeRange,
99
103
  granularity: Granularity,
100
- dataset_role: DatasetRole,
101
- ) -> List[TimeSeriesDataPoint]:
102
- metric_instance = metric.value()
104
+ inferences_role: InferencesRole,
105
+ ) -> list[TimeSeriesDataPoint]:
106
+ metric_instance = DATA_QUALITY_METRIC_FACTORIES[metric]()
103
107
  if isinstance(metric_instance, UnaryOperator):
104
108
  metric_instance = replace(
105
109
  metric_instance,
106
110
  operand=Column(dimension.name),
107
111
  )
108
112
  df = pd.DataFrame(
109
- {dimension.name: dimension[dataset_role.value]},
113
+ {dimension.name: dimension[inferences_role.value]},
110
114
  copy=False,
111
115
  )
112
116
  return get_timeseries_data(
@@ -128,7 +132,7 @@ def get_drift_timeseries_data(
128
132
  time_range: TimeRange,
129
133
  granularity: Granularity,
130
134
  reference_data: pd.DataFrame,
131
- ) -> List[TimeSeriesDataPoint]:
135
+ ) -> list[TimeSeriesDataPoint]:
132
136
  metric_instance = metric.value()
133
137
  metric_instance = replace(
134
138
  metric_instance,
@@ -160,12 +164,12 @@ class PerformanceTimeSeries(TimeSeries):
160
164
 
161
165
 
162
166
  def ensure_timeseries_parameters(
163
- dataset: Dataset,
167
+ inferences: Inferences,
164
168
  time_range: Optional[TimeRange] = UNSET,
165
169
  granularity: Optional[Granularity] = UNSET,
166
- ) -> Tuple[TimeRange, Granularity]:
170
+ ) -> tuple[TimeRange, Granularity]:
167
171
  if not isinstance(time_range, TimeRange):
168
- start, stop = dataset.time_range
172
+ start, stop = inferences.time_range
169
173
  time_range = TimeRange(start=start, end=stop)
170
174
  if not isinstance(granularity, Granularity):
171
175
  total_minutes = int((time_range.end - time_range.start).total_seconds()) // 60
@@ -0,0 +1,11 @@
1
+ import strawberry
2
+
3
+
4
+ @strawberry.type
5
+ class TokenUsage:
6
+ prompt: int = 0
7
+ completion: int = 0
8
+
9
+ @strawberry.field
10
+ async def total(self) -> int:
11
+ return self.prompt + self.completion
@@ -0,0 +1,154 @@
1
+ from __future__ import annotations
2
+
3
+ from datetime import datetime
4
+ from typing import TYPE_CHECKING, Annotated, Optional, Union
5
+
6
+ import strawberry
7
+ from openinference.semconv.trace import SpanAttributes
8
+ from sqlalchemy import desc, select
9
+ from sqlalchemy.orm import contains_eager
10
+ from strawberry import UNSET, Private, lazy
11
+ from strawberry.relay import Connection, GlobalID, Node, NodeID
12
+ from strawberry.types import Info
13
+
14
+ from phoenix.db import models
15
+ from phoenix.server.api.context import Context
16
+ from phoenix.server.api.input_types.TraceAnnotationSort import TraceAnnotationSort
17
+ from phoenix.server.api.types.pagination import (
18
+ ConnectionArgs,
19
+ CursorString,
20
+ connection_from_list,
21
+ )
22
+ from phoenix.server.api.types.SortDir import SortDir
23
+ from phoenix.server.api.types.Span import Span, to_gql_span
24
+ from phoenix.server.api.types.TraceAnnotation import TraceAnnotation, to_gql_trace_annotation
25
+
26
+ if TYPE_CHECKING:
27
+ from phoenix.server.api.types.ProjectSession import ProjectSession
28
+
29
+
30
+ @strawberry.type
31
+ class Trace(Node):
32
+ id_attr: NodeID[int]
33
+ project_rowid: Private[int]
34
+ project_session_rowid: Private[Optional[int]]
35
+ trace_id: str
36
+ start_time: datetime
37
+ end_time: datetime
38
+
39
+ @strawberry.field
40
+ async def latency_ms(
41
+ self,
42
+ info: Info[Context, None],
43
+ ) -> Optional[float]:
44
+ async with info.context.db() as session:
45
+ latency = await session.scalar(
46
+ select(
47
+ models.Trace.latency_ms,
48
+ ).where(models.Trace.id == self.id_attr)
49
+ )
50
+ return latency
51
+
52
+ @strawberry.field
53
+ async def project_id(self) -> GlobalID:
54
+ from phoenix.server.api.types.Project import Project
55
+
56
+ return GlobalID(type_name=Project.__name__, node_id=str(self.project_rowid))
57
+
58
+ @strawberry.field
59
+ async def project_session_id(self) -> Optional[GlobalID]:
60
+ if self.project_session_rowid is None:
61
+ return None
62
+ from phoenix.server.api.types.ProjectSession import ProjectSession
63
+
64
+ return GlobalID(type_name=ProjectSession.__name__, node_id=str(self.project_session_rowid))
65
+
66
+ @strawberry.field
67
+ async def session(
68
+ self,
69
+ info: Info[Context, None],
70
+ ) -> Union[Annotated["ProjectSession", lazy(".ProjectSession")], None]:
71
+ if self.project_session_rowid is None:
72
+ return None
73
+ from phoenix.server.api.types.ProjectSession import to_gql_project_session
74
+
75
+ stmt = select(models.ProjectSession).filter_by(id=self.project_session_rowid)
76
+ async with info.context.db() as session:
77
+ project_session = await session.scalar(stmt)
78
+ if project_session is None:
79
+ return None
80
+ return to_gql_project_session(project_session)
81
+
82
+ @strawberry.field
83
+ async def root_span(
84
+ self,
85
+ info: Info[Context, None],
86
+ ) -> Optional[Span]:
87
+ span = await info.context.data_loaders.trace_root_spans.load(self.id_attr)
88
+ if span is None:
89
+ return None
90
+ return to_gql_span(span)
91
+
92
+ @strawberry.field
93
+ async def spans(
94
+ self,
95
+ info: Info[Context, None],
96
+ first: Optional[int] = 50,
97
+ last: Optional[int] = UNSET,
98
+ after: Optional[CursorString] = UNSET,
99
+ before: Optional[CursorString] = UNSET,
100
+ ) -> Connection[Span]:
101
+ args = ConnectionArgs(
102
+ first=first,
103
+ after=after if isinstance(after, CursorString) else None,
104
+ last=last,
105
+ before=before if isinstance(before, CursorString) else None,
106
+ )
107
+ stmt = (
108
+ select(models.Span)
109
+ .join(models.Trace)
110
+ .where(models.Trace.id == self.id_attr)
111
+ .options(contains_eager(models.Span.trace).load_only(models.Trace.trace_id))
112
+ # Sort descending because the root span tends to show up later
113
+ # in the ingestion process.
114
+ .order_by(desc(models.Span.id))
115
+ .limit(first)
116
+ )
117
+ async with info.context.db() as session:
118
+ spans = await session.stream_scalars(stmt)
119
+ data = [to_gql_span(span) async for span in spans]
120
+ return connection_from_list(data=data, args=args)
121
+
122
+ @strawberry.field(description="Annotations associated with the trace.") # type: ignore
123
+ async def span_annotations(
124
+ self,
125
+ info: Info[Context, None],
126
+ sort: Optional[TraceAnnotationSort] = None,
127
+ ) -> list[TraceAnnotation]:
128
+ async with info.context.db() as session:
129
+ stmt = select(models.TraceAnnotation).filter_by(span_rowid=self.id_attr)
130
+ if sort:
131
+ sort_col = getattr(models.TraceAnnotation, sort.col.value)
132
+ if sort.dir is SortDir.desc:
133
+ stmt = stmt.order_by(sort_col.desc(), models.TraceAnnotation.id.desc())
134
+ else:
135
+ stmt = stmt.order_by(sort_col.asc(), models.TraceAnnotation.id.asc())
136
+ else:
137
+ stmt = stmt.order_by(models.TraceAnnotation.created_at.desc())
138
+ annotations = await session.scalars(stmt)
139
+ return [to_gql_trace_annotation(annotation) for annotation in annotations]
140
+
141
+
142
+ def to_gql_trace(trace: models.Trace) -> Trace:
143
+ return Trace(
144
+ id_attr=trace.id,
145
+ project_rowid=trace.project_rowid,
146
+ project_session_rowid=trace.project_session_rowid,
147
+ trace_id=trace.trace_id,
148
+ start_time=trace.start_time,
149
+ end_time=trace.end_time,
150
+ )
151
+
152
+
153
+ INPUT_VALUE = SpanAttributes.INPUT_VALUE.split(".")
154
+ OUTPUT_VALUE = SpanAttributes.OUTPUT_VALUE.split(".")
@@ -0,0 +1,45 @@
1
+ from typing import Optional
2
+
3
+ import strawberry
4
+ from strawberry import Private
5
+ from strawberry.relay import GlobalID, Node, NodeID
6
+ from strawberry.scalars import JSON
7
+
8
+ from phoenix.db import models
9
+ from phoenix.server.api.types.AnnotatorKind import AnnotatorKind
10
+
11
+
12
+ @strawberry.type
13
+ class TraceAnnotation(Node):
14
+ id_attr: NodeID[int]
15
+ name: str
16
+ annotator_kind: AnnotatorKind
17
+ label: Optional[str]
18
+ score: Optional[float]
19
+ explanation: Optional[str]
20
+ metadata: JSON
21
+ trace_rowid: Private[Optional[int]]
22
+
23
+ @strawberry.field
24
+ async def trace_id(self) -> GlobalID:
25
+ from phoenix.server.api.types.Trace import Trace
26
+
27
+ return GlobalID(type_name=Trace.__name__, node_id=str(self.trace_rowid))
28
+
29
+
30
+ def to_gql_trace_annotation(
31
+ annotation: models.TraceAnnotation,
32
+ ) -> TraceAnnotation:
33
+ """
34
+ Converts an ORM trace annotation to a GraphQL TraceAnnotation.
35
+ """
36
+ return TraceAnnotation(
37
+ id_attr=annotation.id,
38
+ trace_rowid=annotation.trace_rowid,
39
+ name=annotation.name,
40
+ annotator_kind=AnnotatorKind(annotation.annotator_kind),
41
+ label=annotation.label,
42
+ score=annotation.score,
43
+ explanation=annotation.explanation,
44
+ metadata=annotation.metadata_,
45
+ )
@@ -1,15 +1,15 @@
1
- from typing import List, Union
1
+ from typing import Union
2
2
 
3
3
  import numpy as np
4
4
  import numpy.typing as npt
5
5
  import strawberry
6
+ from strawberry.relay.types import GlobalID
6
7
  from strawberry.scalars import ID
7
8
 
8
9
  from phoenix.server.api.types.Cluster import Cluster
9
10
 
10
11
  from .EmbeddingMetadata import EmbeddingMetadata
11
12
  from .EventMetadata import EventMetadata
12
- from .node import GlobalID
13
13
  from .Retrieval import Retrieval
14
14
 
15
15
 
@@ -57,8 +57,8 @@ class UMAPPoint:
57
57
 
58
58
  @strawberry.type
59
59
  class UMAPPoints:
60
- data: List[UMAPPoint]
61
- reference_data: List[UMAPPoint]
62
- clusters: List[Cluster]
63
- corpus_data: List[UMAPPoint] = strawberry.field(default_factory=list)
64
- context_retrievals: List[Retrieval] = strawberry.field(default_factory=list)
60
+ data: list[UMAPPoint]
61
+ reference_data: list[UMAPPoint]
62
+ clusters: list[Cluster]
63
+ corpus_data: list[UMAPPoint] = strawberry.field(default_factory=list)
64
+ context_retrievals: list[Retrieval] = strawberry.field(default_factory=list)
@@ -0,0 +1,60 @@
1
+ from datetime import datetime
2
+ from typing import Optional
3
+
4
+ import strawberry
5
+ from sqlalchemy import select
6
+ from strawberry import Private
7
+ from strawberry.relay import Node, NodeID
8
+ from strawberry.types import Info
9
+
10
+ from phoenix.db import models
11
+ from phoenix.server.api.context import Context
12
+ from phoenix.server.api.exceptions import NotFound
13
+ from phoenix.server.api.types.AuthMethod import AuthMethod
14
+ from phoenix.server.api.types.UserApiKey import UserApiKey, to_gql_api_key
15
+
16
+ from .UserRole import UserRole, to_gql_user_role
17
+
18
+
19
+ @strawberry.type
20
+ class User(Node):
21
+ id_attr: NodeID[int]
22
+ password_needs_reset: bool
23
+ email: str
24
+ username: str
25
+ profile_picture_url: Optional[str]
26
+ created_at: datetime
27
+ user_role_id: Private[int]
28
+ auth_method: AuthMethod
29
+
30
+ @strawberry.field
31
+ async def role(self, info: Info[Context, None]) -> UserRole:
32
+ role = await info.context.data_loaders.user_roles.load(self.user_role_id)
33
+ if role is None:
34
+ raise NotFound(f"User role with id {self.user_role_id} not found")
35
+ return to_gql_user_role(role)
36
+
37
+ @strawberry.field
38
+ async def api_keys(self, info: Info[Context, None]) -> list[UserApiKey]:
39
+ async with info.context.db() as session:
40
+ api_keys = await session.scalars(
41
+ select(models.ApiKey).where(models.ApiKey.user_id == self.id_attr)
42
+ )
43
+ return [to_gql_api_key(api_key) for api_key in api_keys]
44
+
45
+
46
+ def to_gql_user(user: models.User, api_keys: Optional[list[models.ApiKey]] = None) -> User:
47
+ """
48
+ Converts an ORM user to a GraphQL user.
49
+ """
50
+ assert user.auth_method is not None
51
+ return User(
52
+ id_attr=user.id,
53
+ password_needs_reset=user.reset_password,
54
+ username=user.username,
55
+ email=user.email,
56
+ profile_picture_url=user.profile_picture_url,
57
+ created_at=user.created_at,
58
+ user_role_id=user.user_role_id,
59
+ auth_method=AuthMethod(user.auth_method),
60
+ )
@@ -0,0 +1,45 @@
1
+ from typing import TYPE_CHECKING
2
+
3
+ import strawberry
4
+ from strawberry import Private
5
+ from strawberry.relay import Node, NodeID
6
+ from strawberry.types import Info
7
+ from typing_extensions import Annotated
8
+
9
+ from phoenix.db.models import ApiKey as OrmApiKey
10
+ from phoenix.server.api.context import Context
11
+ from phoenix.server.api.exceptions import NotFound
12
+
13
+ from .ApiKey import ApiKey
14
+
15
+ if TYPE_CHECKING:
16
+ from .User import User
17
+
18
+
19
+ @strawberry.type
20
+ class UserApiKey(ApiKey, Node):
21
+ id_attr: NodeID[int]
22
+ user_id: Private[int]
23
+
24
+ @strawberry.field
25
+ async def user(self, info: Info[Context, None]) -> Annotated["User", strawberry.lazy(".User")]:
26
+ user = await info.context.data_loaders.users.load(self.user_id)
27
+ if user is None:
28
+ raise NotFound(f"User with id {self.user_id} not found")
29
+ from .User import to_gql_user
30
+
31
+ return to_gql_user(user)
32
+
33
+
34
+ def to_gql_api_key(api_key: OrmApiKey) -> UserApiKey:
35
+ """
36
+ Converts an ORM API key to a GraphQL UserApiKey type.
37
+ """
38
+ return UserApiKey(
39
+ id_attr=api_key.id,
40
+ user_id=api_key.user_id,
41
+ name=api_key.name,
42
+ description=api_key.description,
43
+ created_at=api_key.created_at,
44
+ expires_at=api_key.expires_at,
45
+ )
@@ -0,0 +1,15 @@
1
+ import strawberry
2
+ from strawberry.relay import Node, NodeID
3
+
4
+ from phoenix.db import models
5
+
6
+
7
+ @strawberry.type
8
+ class UserRole(Node):
9
+ id_attr: NodeID[int]
10
+ name: str
11
+
12
+
13
+ def to_gql_user_role(role: models.UserRole) -> UserRole:
14
+ """Convert an ORM user role to a GraphQL user role."""
15
+ return UserRole(id_attr=role.id, name=role.name)
@@ -1,119 +1,25 @@
1
- import base64
2
- import dataclasses
3
- from typing import Tuple, Union
1
+ from strawberry.relay import GlobalID
4
2
 
5
- import strawberry
6
- from graphql import GraphQLID
7
- from strawberry.custom_scalar import ScalarDefinition
8
- from strawberry.schema.types.scalar import DEFAULT_SCALAR_REGISTRY
9
3
 
10
-
11
- def to_global_id(type_name: str, node_id: int) -> str:
12
- """
13
- Encode the given id into a global id.
14
-
15
- :param type_name: The type of the node.
16
- :param node_id: The id of the node.
17
- :return: A global id.
18
- """
19
- return base64.b64encode(f"{type_name}:{node_id}".encode("utf-8")).decode()
20
-
21
-
22
- def from_global_id(global_id: str) -> Tuple[str, int]:
4
+ def from_global_id(global_id: GlobalID) -> tuple[str, int]:
23
5
  """
24
6
  Decode the given global id into a type and id.
25
7
 
26
8
  :param global_id: The global id to decode.
27
9
  :return: A tuple of type and id.
28
10
  """
29
- type_name, node_id = base64.b64decode(global_id).decode().split(":")
30
- return type_name, int(node_id)
11
+ return global_id.type_name, int(global_id.node_id)
31
12
 
32
13
 
33
- class GlobalIDValueError(ValueError):
34
- """GlobalID value error, usually related to parsing or serialization."""
35
-
36
-
37
- @dataclasses.dataclass(frozen=True)
38
- class GlobalID:
39
- """Global ID for relay types.
40
- Different from `strawberry.ID`, this ID wraps the original object ID in a string
41
- that contains both its GraphQL type name and the ID itself, and encodes it
42
- to a base64_ string.
43
- This object contains helpers to work with that, including method to retrieve
44
- the python object type or even the encoded node itself.
45
- Attributes:
46
- type_name:
47
- The type name part of the id
48
- node_id:
49
- The node id part of the id
50
- .. _base64:
51
- https://en.wikipedia.org/wiki/Base64
14
+ def from_global_id_with_expected_type(global_id: GlobalID, expected_type_name: str) -> int:
52
15
  """
53
-
54
- type_name: str
55
- node_id: int
56
-
57
- def __post_init__(self) -> None:
58
- if not isinstance(self.type_name, str):
59
- raise GlobalIDValueError(
60
- f"type_name is expected to be a string, found {self.type_name}"
61
- )
62
- try:
63
- # node_id could be numpy.int64, hence the need for coercion
64
- object.__setattr__(self, "node_id", int(self.node_id))
65
- except ValueError:
66
- raise GlobalIDValueError(f"node_id is expected to be an int, found {self.node_id}")
67
-
68
- def __str__(self) -> str:
69
- return to_global_id(self.type_name, self.node_id)
70
-
71
- @classmethod
72
- def from_id(cls, value: Union[str, strawberry.ID]) -> "GlobalID":
73
- """Create a new GlobalID from parsing the given value.
74
- Args:
75
- value:
76
- The value to be parsed, as a base64 string in the "TypeName:NodeID" format
77
- Returns:
78
- An instance of GLobalID
79
- Raises:
80
- GlobalIDValueError:
81
- If the value is not in a GLobalID format
82
- """
83
- try:
84
- type_name, node_id = from_global_id(value)
85
- except ValueError as e:
86
- raise GlobalIDValueError(str(e)) from e
87
-
88
- return cls(type_name=type_name, node_id=node_id)
89
-
90
-
91
- @strawberry.interface(description="A node in the graph with a globally unique ID")
92
- class Node:
93
- """
94
- All types that are relay ready should inherit from this interface and
95
- implement the following methods.
96
-
97
- Attributes:
98
- id_attr:
99
- The raw id field of node. Typically a database id or index
16
+ Decodes the given global id and return the id, checking that the type
17
+ matches the expected type.
100
18
  """
101
-
102
- id_attr: strawberry.Private[int]
103
-
104
- @strawberry.field
105
- def id(self) -> GlobalID:
106
- return GlobalID(type(self).__name__, self.id_attr)
107
-
108
-
109
- # Register our GlobalID scalar
110
- DEFAULT_SCALAR_REGISTRY[GlobalID] = ScalarDefinition(
111
- # Use the same name/description/parse_literal from GraphQLID
112
- # specs expect this type to be "ID".
113
- name="GlobalID",
114
- description=GraphQLID.description,
115
- parse_literal=lambda v, vars=None: GlobalID.from_id(GraphQLID.parse_literal(v, vars)),
116
- parse_value=GlobalID.from_id,
117
- serialize=str,
118
- specified_by_url="https://relay.dev/graphql/objectidentification.htm",
119
- )
19
+ type_name, node_id = from_global_id(global_id)
20
+ if type_name != expected_type_name:
21
+ raise ValueError(
22
+ f"The node id must correspond to a node of type {expected_type_name}, "
23
+ f"but instead corresponds to a node of type: {type_name}"
24
+ )
25
+ return node_id