arize-phoenix 10.0.4__py3-none-any.whl → 12.28.1__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.
Files changed (276) hide show
  1. {arize_phoenix-10.0.4.dist-info → arize_phoenix-12.28.1.dist-info}/METADATA +124 -72
  2. arize_phoenix-12.28.1.dist-info/RECORD +499 -0
  3. {arize_phoenix-10.0.4.dist-info → arize_phoenix-12.28.1.dist-info}/WHEEL +1 -1
  4. {arize_phoenix-10.0.4.dist-info → arize_phoenix-12.28.1.dist-info}/licenses/IP_NOTICE +1 -1
  5. phoenix/__generated__/__init__.py +0 -0
  6. phoenix/__generated__/classification_evaluator_configs/__init__.py +20 -0
  7. phoenix/__generated__/classification_evaluator_configs/_document_relevance_classification_evaluator_config.py +17 -0
  8. phoenix/__generated__/classification_evaluator_configs/_hallucination_classification_evaluator_config.py +17 -0
  9. phoenix/__generated__/classification_evaluator_configs/_models.py +18 -0
  10. phoenix/__generated__/classification_evaluator_configs/_tool_selection_classification_evaluator_config.py +17 -0
  11. phoenix/__init__.py +5 -4
  12. phoenix/auth.py +39 -2
  13. phoenix/config.py +1763 -91
  14. phoenix/datetime_utils.py +120 -2
  15. phoenix/db/README.md +595 -25
  16. phoenix/db/bulk_inserter.py +145 -103
  17. phoenix/db/engines.py +140 -33
  18. phoenix/db/enums.py +3 -12
  19. phoenix/db/facilitator.py +302 -35
  20. phoenix/db/helpers.py +1000 -65
  21. phoenix/db/iam_auth.py +64 -0
  22. phoenix/db/insertion/dataset.py +135 -2
  23. phoenix/db/insertion/document_annotation.py +9 -6
  24. phoenix/db/insertion/evaluation.py +2 -3
  25. phoenix/db/insertion/helpers.py +17 -2
  26. phoenix/db/insertion/session_annotation.py +176 -0
  27. phoenix/db/insertion/span.py +15 -11
  28. phoenix/db/insertion/span_annotation.py +3 -4
  29. phoenix/db/insertion/trace_annotation.py +3 -4
  30. phoenix/db/insertion/types.py +50 -20
  31. phoenix/db/migrations/versions/01a8342c9cdf_add_user_id_on_datasets.py +40 -0
  32. phoenix/db/migrations/versions/0df286449799_add_session_annotations_table.py +105 -0
  33. phoenix/db/migrations/versions/272b66ff50f8_drop_single_indices.py +119 -0
  34. phoenix/db/migrations/versions/58228d933c91_dataset_labels.py +67 -0
  35. phoenix/db/migrations/versions/699f655af132_experiment_tags.py +57 -0
  36. phoenix/db/migrations/versions/735d3d93c33e_add_composite_indices.py +41 -0
  37. phoenix/db/migrations/versions/a20694b15f82_cost.py +196 -0
  38. phoenix/db/migrations/versions/ab513d89518b_add_user_id_on_dataset_versions.py +40 -0
  39. phoenix/db/migrations/versions/d0690a79ea51_users_on_experiments.py +40 -0
  40. phoenix/db/migrations/versions/deb2c81c0bb2_dataset_splits.py +139 -0
  41. phoenix/db/migrations/versions/e76cbd66ffc3_add_experiments_dataset_examples.py +87 -0
  42. phoenix/db/models.py +669 -56
  43. phoenix/db/pg_config.py +10 -0
  44. phoenix/db/types/model_provider.py +4 -0
  45. phoenix/db/types/token_price_customization.py +29 -0
  46. phoenix/db/types/trace_retention.py +23 -15
  47. phoenix/experiments/evaluators/utils.py +3 -3
  48. phoenix/experiments/functions.py +160 -52
  49. phoenix/experiments/tracing.py +2 -2
  50. phoenix/experiments/types.py +1 -1
  51. phoenix/inferences/inferences.py +1 -2
  52. phoenix/server/api/auth.py +38 -7
  53. phoenix/server/api/auth_messages.py +46 -0
  54. phoenix/server/api/context.py +100 -4
  55. phoenix/server/api/dataloaders/__init__.py +79 -5
  56. phoenix/server/api/dataloaders/annotation_configs_by_project.py +31 -0
  57. phoenix/server/api/dataloaders/annotation_summaries.py +60 -8
  58. phoenix/server/api/dataloaders/average_experiment_repeated_run_group_latency.py +50 -0
  59. phoenix/server/api/dataloaders/average_experiment_run_latency.py +17 -24
  60. phoenix/server/api/dataloaders/cache/two_tier_cache.py +1 -2
  61. phoenix/server/api/dataloaders/dataset_dataset_splits.py +52 -0
  62. phoenix/server/api/dataloaders/dataset_example_revisions.py +0 -1
  63. phoenix/server/api/dataloaders/dataset_example_splits.py +40 -0
  64. phoenix/server/api/dataloaders/dataset_examples_and_versions_by_experiment_run.py +47 -0
  65. phoenix/server/api/dataloaders/dataset_labels.py +36 -0
  66. phoenix/server/api/dataloaders/document_evaluation_summaries.py +2 -2
  67. phoenix/server/api/dataloaders/document_evaluations.py +6 -9
  68. phoenix/server/api/dataloaders/experiment_annotation_summaries.py +88 -34
  69. phoenix/server/api/dataloaders/experiment_dataset_splits.py +43 -0
  70. phoenix/server/api/dataloaders/experiment_error_rates.py +21 -28
  71. phoenix/server/api/dataloaders/experiment_repeated_run_group_annotation_summaries.py +77 -0
  72. phoenix/server/api/dataloaders/experiment_repeated_run_groups.py +57 -0
  73. phoenix/server/api/dataloaders/experiment_runs_by_experiment_and_example.py +44 -0
  74. phoenix/server/api/dataloaders/last_used_times_by_generative_model_id.py +35 -0
  75. phoenix/server/api/dataloaders/latency_ms_quantile.py +40 -8
  76. phoenix/server/api/dataloaders/record_counts.py +37 -10
  77. phoenix/server/api/dataloaders/session_annotations_by_session.py +29 -0
  78. phoenix/server/api/dataloaders/span_cost_by_span.py +24 -0
  79. phoenix/server/api/dataloaders/span_cost_detail_summary_entries_by_generative_model.py +56 -0
  80. phoenix/server/api/dataloaders/span_cost_detail_summary_entries_by_project_session.py +57 -0
  81. phoenix/server/api/dataloaders/span_cost_detail_summary_entries_by_span.py +43 -0
  82. phoenix/server/api/dataloaders/span_cost_detail_summary_entries_by_trace.py +56 -0
  83. phoenix/server/api/dataloaders/span_cost_details_by_span_cost.py +27 -0
  84. phoenix/server/api/dataloaders/span_cost_summary_by_experiment.py +57 -0
  85. phoenix/server/api/dataloaders/span_cost_summary_by_experiment_repeated_run_group.py +64 -0
  86. phoenix/server/api/dataloaders/span_cost_summary_by_experiment_run.py +58 -0
  87. phoenix/server/api/dataloaders/span_cost_summary_by_generative_model.py +55 -0
  88. phoenix/server/api/dataloaders/span_cost_summary_by_project.py +152 -0
  89. phoenix/server/api/dataloaders/span_cost_summary_by_project_session.py +56 -0
  90. phoenix/server/api/dataloaders/span_cost_summary_by_trace.py +55 -0
  91. phoenix/server/api/dataloaders/span_costs.py +29 -0
  92. phoenix/server/api/dataloaders/table_fields.py +2 -2
  93. phoenix/server/api/dataloaders/token_prices_by_model.py +30 -0
  94. phoenix/server/api/dataloaders/trace_annotations_by_trace.py +27 -0
  95. phoenix/server/api/dataloaders/types.py +29 -0
  96. phoenix/server/api/exceptions.py +11 -1
  97. phoenix/server/api/helpers/dataset_helpers.py +5 -1
  98. phoenix/server/api/helpers/playground_clients.py +1243 -292
  99. phoenix/server/api/helpers/playground_registry.py +2 -2
  100. phoenix/server/api/helpers/playground_spans.py +8 -4
  101. phoenix/server/api/helpers/playground_users.py +26 -0
  102. phoenix/server/api/helpers/prompts/conversions/aws.py +83 -0
  103. phoenix/server/api/helpers/prompts/conversions/google.py +103 -0
  104. phoenix/server/api/helpers/prompts/models.py +205 -22
  105. phoenix/server/api/input_types/{SpanAnnotationFilter.py → AnnotationFilter.py} +22 -14
  106. phoenix/server/api/input_types/ChatCompletionInput.py +6 -2
  107. phoenix/server/api/input_types/CreateProjectInput.py +27 -0
  108. phoenix/server/api/input_types/CreateProjectSessionAnnotationInput.py +37 -0
  109. phoenix/server/api/input_types/DatasetFilter.py +17 -0
  110. phoenix/server/api/input_types/ExperimentRunSort.py +237 -0
  111. phoenix/server/api/input_types/GenerativeCredentialInput.py +9 -0
  112. phoenix/server/api/input_types/GenerativeModelInput.py +5 -0
  113. phoenix/server/api/input_types/ProjectSessionSort.py +161 -1
  114. phoenix/server/api/input_types/PromptFilter.py +14 -0
  115. phoenix/server/api/input_types/PromptVersionInput.py +52 -1
  116. phoenix/server/api/input_types/SpanSort.py +44 -7
  117. phoenix/server/api/input_types/TimeBinConfig.py +23 -0
  118. phoenix/server/api/input_types/UpdateAnnotationInput.py +34 -0
  119. phoenix/server/api/input_types/UserRoleInput.py +1 -0
  120. phoenix/server/api/mutations/__init__.py +10 -0
  121. phoenix/server/api/mutations/annotation_config_mutations.py +8 -8
  122. phoenix/server/api/mutations/api_key_mutations.py +19 -23
  123. phoenix/server/api/mutations/chat_mutations.py +154 -47
  124. phoenix/server/api/mutations/dataset_label_mutations.py +243 -0
  125. phoenix/server/api/mutations/dataset_mutations.py +21 -16
  126. phoenix/server/api/mutations/dataset_split_mutations.py +351 -0
  127. phoenix/server/api/mutations/experiment_mutations.py +2 -2
  128. phoenix/server/api/mutations/export_events_mutations.py +3 -3
  129. phoenix/server/api/mutations/model_mutations.py +210 -0
  130. phoenix/server/api/mutations/project_mutations.py +49 -10
  131. phoenix/server/api/mutations/project_session_annotations_mutations.py +158 -0
  132. phoenix/server/api/mutations/project_trace_retention_policy_mutations.py +8 -4
  133. phoenix/server/api/mutations/prompt_label_mutations.py +74 -65
  134. phoenix/server/api/mutations/prompt_mutations.py +65 -129
  135. phoenix/server/api/mutations/prompt_version_tag_mutations.py +11 -8
  136. phoenix/server/api/mutations/span_annotations_mutations.py +15 -10
  137. phoenix/server/api/mutations/trace_annotations_mutations.py +14 -10
  138. phoenix/server/api/mutations/trace_mutations.py +47 -3
  139. phoenix/server/api/mutations/user_mutations.py +66 -41
  140. phoenix/server/api/queries.py +768 -293
  141. phoenix/server/api/routers/__init__.py +2 -2
  142. phoenix/server/api/routers/auth.py +154 -88
  143. phoenix/server/api/routers/ldap.py +229 -0
  144. phoenix/server/api/routers/oauth2.py +369 -106
  145. phoenix/server/api/routers/v1/__init__.py +24 -4
  146. phoenix/server/api/routers/v1/annotation_configs.py +23 -31
  147. phoenix/server/api/routers/v1/annotations.py +481 -17
  148. phoenix/server/api/routers/v1/datasets.py +395 -81
  149. phoenix/server/api/routers/v1/documents.py +142 -0
  150. phoenix/server/api/routers/v1/evaluations.py +24 -31
  151. phoenix/server/api/routers/v1/experiment_evaluations.py +19 -8
  152. phoenix/server/api/routers/v1/experiment_runs.py +337 -59
  153. phoenix/server/api/routers/v1/experiments.py +479 -48
  154. phoenix/server/api/routers/v1/models.py +7 -0
  155. phoenix/server/api/routers/v1/projects.py +18 -49
  156. phoenix/server/api/routers/v1/prompts.py +54 -40
  157. phoenix/server/api/routers/v1/sessions.py +108 -0
  158. phoenix/server/api/routers/v1/spans.py +1091 -81
  159. phoenix/server/api/routers/v1/traces.py +132 -78
  160. phoenix/server/api/routers/v1/users.py +389 -0
  161. phoenix/server/api/routers/v1/utils.py +3 -7
  162. phoenix/server/api/subscriptions.py +305 -88
  163. phoenix/server/api/types/Annotation.py +90 -23
  164. phoenix/server/api/types/ApiKey.py +13 -17
  165. phoenix/server/api/types/AuthMethod.py +1 -0
  166. phoenix/server/api/types/ChatCompletionSubscriptionPayload.py +1 -0
  167. phoenix/server/api/types/CostBreakdown.py +12 -0
  168. phoenix/server/api/types/Dataset.py +226 -72
  169. phoenix/server/api/types/DatasetExample.py +88 -18
  170. phoenix/server/api/types/DatasetExperimentAnnotationSummary.py +10 -0
  171. phoenix/server/api/types/DatasetLabel.py +57 -0
  172. phoenix/server/api/types/DatasetSplit.py +98 -0
  173. phoenix/server/api/types/DatasetVersion.py +49 -4
  174. phoenix/server/api/types/DocumentAnnotation.py +212 -0
  175. phoenix/server/api/types/Experiment.py +264 -59
  176. phoenix/server/api/types/ExperimentComparison.py +5 -10
  177. phoenix/server/api/types/ExperimentRepeatedRunGroup.py +155 -0
  178. phoenix/server/api/types/ExperimentRepeatedRunGroupAnnotationSummary.py +9 -0
  179. phoenix/server/api/types/ExperimentRun.py +169 -65
  180. phoenix/server/api/types/ExperimentRunAnnotation.py +158 -39
  181. phoenix/server/api/types/GenerativeModel.py +245 -3
  182. phoenix/server/api/types/GenerativeProvider.py +70 -11
  183. phoenix/server/api/types/{Model.py → InferenceModel.py} +1 -1
  184. phoenix/server/api/types/ModelInterface.py +16 -0
  185. phoenix/server/api/types/PlaygroundModel.py +20 -0
  186. phoenix/server/api/types/Project.py +1278 -216
  187. phoenix/server/api/types/ProjectSession.py +188 -28
  188. phoenix/server/api/types/ProjectSessionAnnotation.py +187 -0
  189. phoenix/server/api/types/ProjectTraceRetentionPolicy.py +1 -1
  190. phoenix/server/api/types/Prompt.py +119 -39
  191. phoenix/server/api/types/PromptLabel.py +42 -25
  192. phoenix/server/api/types/PromptVersion.py +11 -8
  193. phoenix/server/api/types/PromptVersionTag.py +65 -25
  194. phoenix/server/api/types/ServerStatus.py +6 -0
  195. phoenix/server/api/types/Span.py +167 -123
  196. phoenix/server/api/types/SpanAnnotation.py +189 -42
  197. phoenix/server/api/types/SpanCostDetailSummaryEntry.py +10 -0
  198. phoenix/server/api/types/SpanCostSummary.py +10 -0
  199. phoenix/server/api/types/SystemApiKey.py +65 -1
  200. phoenix/server/api/types/TokenPrice.py +16 -0
  201. phoenix/server/api/types/TokenUsage.py +3 -3
  202. phoenix/server/api/types/Trace.py +223 -51
  203. phoenix/server/api/types/TraceAnnotation.py +149 -50
  204. phoenix/server/api/types/User.py +137 -32
  205. phoenix/server/api/types/UserApiKey.py +73 -26
  206. phoenix/server/api/types/node.py +10 -0
  207. phoenix/server/api/types/pagination.py +11 -2
  208. phoenix/server/app.py +290 -45
  209. phoenix/server/authorization.py +38 -3
  210. phoenix/server/bearer_auth.py +34 -24
  211. phoenix/server/cost_tracking/cost_details_calculator.py +196 -0
  212. phoenix/server/cost_tracking/cost_model_lookup.py +179 -0
  213. phoenix/server/cost_tracking/helpers.py +68 -0
  214. phoenix/server/cost_tracking/model_cost_manifest.json +3657 -830
  215. phoenix/server/cost_tracking/regex_specificity.py +397 -0
  216. phoenix/server/cost_tracking/token_cost_calculator.py +57 -0
  217. phoenix/server/daemons/__init__.py +0 -0
  218. phoenix/server/daemons/db_disk_usage_monitor.py +214 -0
  219. phoenix/server/daemons/generative_model_store.py +103 -0
  220. phoenix/server/daemons/span_cost_calculator.py +99 -0
  221. phoenix/server/dml_event.py +17 -0
  222. phoenix/server/dml_event_handler.py +5 -0
  223. phoenix/server/email/sender.py +56 -3
  224. phoenix/server/email/templates/db_disk_usage_notification.html +19 -0
  225. phoenix/server/email/types.py +11 -0
  226. phoenix/server/experiments/__init__.py +0 -0
  227. phoenix/server/experiments/utils.py +14 -0
  228. phoenix/server/grpc_server.py +11 -11
  229. phoenix/server/jwt_store.py +17 -15
  230. phoenix/server/ldap.py +1449 -0
  231. phoenix/server/main.py +26 -10
  232. phoenix/server/oauth2.py +330 -12
  233. phoenix/server/prometheus.py +66 -6
  234. phoenix/server/rate_limiters.py +4 -9
  235. phoenix/server/retention.py +33 -20
  236. phoenix/server/session_filters.py +49 -0
  237. phoenix/server/static/.vite/manifest.json +55 -51
  238. phoenix/server/static/assets/components-BreFUQQa.js +6702 -0
  239. phoenix/server/static/assets/{index-E0M82BdE.js → index-CTQoemZv.js} +140 -56
  240. phoenix/server/static/assets/pages-DBE5iYM3.js +9524 -0
  241. phoenix/server/static/assets/vendor-BGzfc4EU.css +1 -0
  242. phoenix/server/static/assets/vendor-DCE4v-Ot.js +920 -0
  243. phoenix/server/static/assets/vendor-codemirror-D5f205eT.js +25 -0
  244. phoenix/server/static/assets/vendor-recharts-V9cwpXsm.js +37 -0
  245. phoenix/server/static/assets/vendor-shiki-Do--csgv.js +5 -0
  246. phoenix/server/static/assets/vendor-three-CmB8bl_y.js +3840 -0
  247. phoenix/server/templates/index.html +40 -6
  248. phoenix/server/thread_server.py +1 -2
  249. phoenix/server/types.py +14 -4
  250. phoenix/server/utils.py +74 -0
  251. phoenix/session/client.py +56 -3
  252. phoenix/session/data_extractor.py +5 -0
  253. phoenix/session/evaluation.py +14 -5
  254. phoenix/session/session.py +45 -9
  255. phoenix/settings.py +5 -0
  256. phoenix/trace/attributes.py +80 -13
  257. phoenix/trace/dsl/helpers.py +90 -1
  258. phoenix/trace/dsl/query.py +8 -6
  259. phoenix/trace/projects.py +5 -0
  260. phoenix/utilities/template_formatters.py +1 -1
  261. phoenix/version.py +1 -1
  262. arize_phoenix-10.0.4.dist-info/RECORD +0 -405
  263. phoenix/server/api/types/Evaluation.py +0 -39
  264. phoenix/server/cost_tracking/cost_lookup.py +0 -255
  265. phoenix/server/static/assets/components-DULKeDfL.js +0 -4365
  266. phoenix/server/static/assets/pages-Cl0A-0U2.js +0 -7430
  267. phoenix/server/static/assets/vendor-WIZid84E.css +0 -1
  268. phoenix/server/static/assets/vendor-arizeai-Dy-0mSNw.js +0 -649
  269. phoenix/server/static/assets/vendor-codemirror-DBtifKNr.js +0 -33
  270. phoenix/server/static/assets/vendor-oB4u9zuV.js +0 -905
  271. phoenix/server/static/assets/vendor-recharts-D-T4KPz2.js +0 -59
  272. phoenix/server/static/assets/vendor-shiki-BMn4O_9F.js +0 -5
  273. phoenix/server/static/assets/vendor-three-C5WAXd5r.js +0 -2998
  274. phoenix/utilities/deprecation.py +0 -31
  275. {arize_phoenix-10.0.4.dist-info → arize_phoenix-12.28.1.dist-info}/entry_points.txt +0 -0
  276. {arize_phoenix-10.0.4.dist-info → arize_phoenix-12.28.1.dist-info}/licenses/LICENSE +0 -0
@@ -1,7 +1,8 @@
1
- from typing import Optional
1
+ from datetime import datetime
2
+ from math import isfinite
3
+ from typing import TYPE_CHECKING, Annotated, Optional
2
4
 
3
5
  import strawberry
4
- from strawberry import Private
5
6
  from strawberry.relay import GlobalID, Node, NodeID
6
7
  from strawberry.scalars import JSON
7
8
  from strawberry.types import Info
@@ -12,56 +13,202 @@ from phoenix.server.api.context import Context
12
13
  from .Annotation import Annotation
13
14
  from .AnnotationSource import AnnotationSource
14
15
  from .AnnotatorKind import AnnotatorKind
15
- from .User import User, to_gql_user
16
+
17
+ if TYPE_CHECKING:
18
+ from .Span import Span
19
+ from .User import User
16
20
 
17
21
 
18
22
  @strawberry.type
19
23
  class SpanAnnotation(Node, Annotation):
20
- id_attr: NodeID[int]
21
- user_id: Private[Optional[int]]
22
- annotator_kind: AnnotatorKind
23
- metadata: JSON
24
- span_rowid: Private[Optional[int]]
25
- source: AnnotationSource
26
- identifier: str
24
+ id: NodeID[int]
25
+ db_record: strawberry.Private[Optional[models.SpanAnnotation]] = None
26
+
27
+ def __post_init__(self) -> None:
28
+ if self.db_record and self.id != self.db_record.id:
29
+ raise ValueError("SpanAnnotation ID mismatch")
30
+
31
+ @strawberry.field(description="Name of the annotation, e.g. 'helpfulness' or 'relevance'.") # type: ignore
32
+ async def name(
33
+ self,
34
+ info: Info[Context, None],
35
+ ) -> str:
36
+ if self.db_record:
37
+ val = self.db_record.name
38
+ else:
39
+ val = await info.context.data_loaders.span_annotation_fields.load(
40
+ (self.id, models.SpanAnnotation.name),
41
+ )
42
+ return val
43
+
44
+ @strawberry.field(description="The kind of annotator that produced the annotation.") # type: ignore
45
+ async def annotator_kind(
46
+ self,
47
+ info: Info[Context, None],
48
+ ) -> AnnotatorKind:
49
+ if self.db_record:
50
+ val = self.db_record.annotator_kind
51
+ else:
52
+ val = await info.context.data_loaders.span_annotation_fields.load(
53
+ (self.id, models.SpanAnnotation.annotator_kind),
54
+ )
55
+ return AnnotatorKind(val)
56
+
57
+ @strawberry.field(
58
+ description="Value of the annotation in the form of a string, e.g. "
59
+ "'helpful' or 'not helpful'. Note that the label is not necessarily binary."
60
+ ) # type: ignore
61
+ async def label(
62
+ self,
63
+ info: Info[Context, None],
64
+ ) -> Optional[str]:
65
+ if self.db_record:
66
+ val = self.db_record.label
67
+ else:
68
+ val = await info.context.data_loaders.span_annotation_fields.load(
69
+ (self.id, models.SpanAnnotation.label),
70
+ )
71
+ return val
72
+
73
+ @strawberry.field(
74
+ description="Value of the annotation in the form of a numeric score.",
75
+ ) # type: ignore
76
+ async def score(
77
+ self,
78
+ info: Info[Context, None],
79
+ ) -> Optional[float]:
80
+ if self.db_record:
81
+ val = self.db_record.score
82
+ else:
83
+ val = await info.context.data_loaders.span_annotation_fields.load(
84
+ (self.id, models.SpanAnnotation.score),
85
+ )
86
+ return val if val is not None and isfinite(val) else None
87
+
88
+ @strawberry.field(
89
+ description="The annotator's explanation for the annotation result (i.e. "
90
+ "score or label, or both) given to the subject."
91
+ ) # type: ignore
92
+ async def explanation(
93
+ self,
94
+ info: Info[Context, None],
95
+ ) -> Optional[str]:
96
+ if self.db_record:
97
+ val = self.db_record.explanation
98
+ else:
99
+ val = await info.context.data_loaders.span_annotation_fields.load(
100
+ (self.id, models.SpanAnnotation.explanation),
101
+ )
102
+ return val
103
+
104
+ @strawberry.field(description="Metadata about the annotation.") # type: ignore
105
+ async def metadata(
106
+ self,
107
+ info: Info[Context, None],
108
+ ) -> JSON:
109
+ if self.db_record:
110
+ val = self.db_record.metadata_
111
+ else:
112
+ val = await info.context.data_loaders.span_annotation_fields.load(
113
+ (self.id, models.SpanAnnotation.metadata_),
114
+ )
115
+ return val
116
+
117
+ @strawberry.field(description="The source of the annotation.") # type: ignore
118
+ async def source(
119
+ self,
120
+ info: Info[Context, None],
121
+ ) -> AnnotationSource:
122
+ if self.db_record:
123
+ val = self.db_record.source
124
+ else:
125
+ val = await info.context.data_loaders.span_annotation_fields.load(
126
+ (self.id, models.SpanAnnotation.source),
127
+ )
128
+ return AnnotationSource(val)
129
+
130
+ @strawberry.field(description="The identifier of the annotation.") # type: ignore
131
+ async def identifier(
132
+ self,
133
+ info: Info[Context, None],
134
+ ) -> str:
135
+ if self.db_record:
136
+ val = self.db_record.identifier
137
+ else:
138
+ val = await info.context.data_loaders.span_annotation_fields.load(
139
+ (self.id, models.SpanAnnotation.identifier),
140
+ )
141
+ return val
142
+
143
+ @strawberry.field(description="The date and time when the annotation was created.") # type: ignore
144
+ async def created_at(
145
+ self,
146
+ info: Info[Context, None],
147
+ ) -> datetime:
148
+ if self.db_record:
149
+ val = self.db_record.created_at
150
+ else:
151
+ val = await info.context.data_loaders.span_annotation_fields.load(
152
+ (self.id, models.SpanAnnotation.created_at),
153
+ )
154
+ return val
155
+
156
+ @strawberry.field(description="The date and time when the annotation was last updated.") # type: ignore
157
+ async def updated_at(
158
+ self,
159
+ info: Info[Context, None],
160
+ ) -> datetime:
161
+ if self.db_record:
162
+ val = self.db_record.updated_at
163
+ else:
164
+ val = await info.context.data_loaders.span_annotation_fields.load(
165
+ (self.id, models.SpanAnnotation.updated_at),
166
+ )
167
+ return val
27
168
 
28
169
  @strawberry.field
29
- async def span_id(self) -> GlobalID:
170
+ async def span_id(
171
+ self,
172
+ info: Info[Context, None],
173
+ ) -> GlobalID:
30
174
  from phoenix.server.api.types.Span import Span
31
175
 
32
- return GlobalID(type_name=Span.__name__, node_id=str(self.span_rowid))
176
+ if self.db_record:
177
+ span_rowid = self.db_record.span_rowid
178
+ else:
179
+ span_rowid = await info.context.data_loaders.span_annotation_fields.load(
180
+ (self.id, models.SpanAnnotation.span_rowid),
181
+ )
182
+ return GlobalID(type_name=Span.__name__, node_id=str(span_rowid))
33
183
 
34
- @strawberry.field
184
+ @strawberry.field(description="The span associated with the annotation.") # type: ignore
185
+ async def span(
186
+ self,
187
+ info: Info[Context, None],
188
+ ) -> Annotated["Span", strawberry.lazy(".Span")]:
189
+ if self.db_record:
190
+ span_rowid = self.db_record.span_rowid
191
+ else:
192
+ span_rowid = await info.context.data_loaders.span_annotation_fields.load(
193
+ (self.id, models.SpanAnnotation.span_rowid),
194
+ )
195
+ from .Span import Span
196
+
197
+ return Span(id=span_rowid)
198
+
199
+ @strawberry.field(description="The user that produced the annotation.") # type: ignore
35
200
  async def user(
36
201
  self,
37
202
  info: Info[Context, None],
38
- ) -> Optional[User]:
39
- if self.user_id is None:
203
+ ) -> Optional[Annotated["User", strawberry.lazy(".User")]]:
204
+ if self.db_record:
205
+ user_id = self.db_record.user_id
206
+ else:
207
+ user_id = await info.context.data_loaders.span_annotation_fields.load(
208
+ (self.id, models.SpanAnnotation.user_id),
209
+ )
210
+ if user_id is None:
40
211
  return None
41
- user = await info.context.data_loaders.users.load(self.user_id)
42
- if user is None:
43
- return None
44
- return to_gql_user(user)
45
-
46
-
47
- def to_gql_span_annotation(
48
- annotation: models.SpanAnnotation,
49
- ) -> SpanAnnotation:
50
- """
51
- Converts an ORM span annotation to a GraphQL SpanAnnotation.
52
- """
53
- return SpanAnnotation(
54
- id_attr=annotation.id,
55
- user_id=annotation.user_id,
56
- span_rowid=annotation.span_rowid,
57
- name=annotation.name,
58
- annotator_kind=AnnotatorKind(annotation.annotator_kind),
59
- label=annotation.label,
60
- score=annotation.score,
61
- explanation=annotation.explanation,
62
- metadata=annotation.metadata_,
63
- source=AnnotationSource(annotation.source),
64
- identifier=annotation.identifier,
65
- created_at=annotation.created_at,
66
- updated_at=annotation.updated_at,
67
- )
212
+ from .User import User
213
+
214
+ return User(id=user_id)
@@ -0,0 +1,10 @@
1
+ import strawberry
2
+
3
+ from phoenix.server.api.types.CostBreakdown import CostBreakdown
4
+
5
+
6
+ @strawberry.type
7
+ class SpanCostDetailSummaryEntry:
8
+ token_type: str
9
+ is_prompt: bool
10
+ value: CostBreakdown = strawberry.field(default_factory=CostBreakdown)
@@ -0,0 +1,10 @@
1
+ import strawberry
2
+
3
+ from phoenix.server.api.types.CostBreakdown import CostBreakdown
4
+
5
+
6
+ @strawberry.type
7
+ class SpanCostSummary:
8
+ prompt: CostBreakdown = strawberry.field(default_factory=CostBreakdown)
9
+ completion: CostBreakdown = strawberry.field(default_factory=CostBreakdown)
10
+ total: CostBreakdown = strawberry.field(default_factory=CostBreakdown)
@@ -1,9 +1,73 @@
1
+ from datetime import datetime
2
+ from typing import Optional
3
+
1
4
  import strawberry
2
5
  from strawberry.relay import Node, NodeID
6
+ from strawberry.types import Info
7
+
8
+ from phoenix.db.models import ApiKey as OrmApiKey
9
+ from phoenix.server.api.context import Context
3
10
 
4
11
  from .ApiKey import ApiKey
5
12
 
6
13
 
7
14
  @strawberry.type
8
15
  class SystemApiKey(ApiKey, Node):
9
- id_attr: NodeID[int]
16
+ id: NodeID[int]
17
+ db_record: strawberry.Private[Optional[OrmApiKey]] = None
18
+
19
+ def __post_init__(self) -> None:
20
+ if self.db_record and self.id != self.db_record.id:
21
+ raise ValueError("SystemApiKey ID mismatch")
22
+
23
+ @strawberry.field(description="Name of the API key.") # type: ignore
24
+ async def name(
25
+ self,
26
+ info: Info[Context, None],
27
+ ) -> str:
28
+ if self.db_record:
29
+ val = self.db_record.name
30
+ else:
31
+ val = await info.context.data_loaders.user_api_key_fields.load(
32
+ (self.id, OrmApiKey.name),
33
+ )
34
+ return val
35
+
36
+ @strawberry.field(description="Description of the API key.") # type: ignore
37
+ async def description(
38
+ self,
39
+ info: Info[Context, None],
40
+ ) -> Optional[str]:
41
+ if self.db_record:
42
+ val = self.db_record.description
43
+ else:
44
+ val = await info.context.data_loaders.user_api_key_fields.load(
45
+ (self.id, OrmApiKey.description),
46
+ )
47
+ return val
48
+
49
+ @strawberry.field(description="The date and time the API key was created.") # type: ignore
50
+ async def created_at(
51
+ self,
52
+ info: Info[Context, None],
53
+ ) -> datetime:
54
+ if self.db_record:
55
+ val = self.db_record.created_at
56
+ else:
57
+ val = await info.context.data_loaders.user_api_key_fields.load(
58
+ (self.id, OrmApiKey.created_at),
59
+ )
60
+ return val
61
+
62
+ @strawberry.field(description="The date and time the API key will expire.") # type: ignore
63
+ async def expires_at(
64
+ self,
65
+ info: Info[Context, None],
66
+ ) -> Optional[datetime]:
67
+ if self.db_record:
68
+ val = self.db_record.expires_at
69
+ else:
70
+ val = await info.context.data_loaders.user_api_key_fields.load(
71
+ (self.id, OrmApiKey.expires_at),
72
+ )
73
+ return val
@@ -0,0 +1,16 @@
1
+ from enum import Enum
2
+
3
+ import strawberry
4
+
5
+
6
+ class TokenKind(Enum):
7
+ PROMPT = "prompt"
8
+ COMPLETION = "completion"
9
+
10
+
11
+ @strawberry.type
12
+ class TokenPrice:
13
+ token_type: str
14
+ kind: TokenKind
15
+ cost_per_million_tokens: float
16
+ cost_per_token: float
@@ -3,9 +3,9 @@ import strawberry
3
3
 
4
4
  @strawberry.type
5
5
  class TokenUsage:
6
- prompt: int = 0
7
- completion: int = 0
6
+ prompt: float = 0
7
+ completion: float = 0
8
8
 
9
9
  @strawberry.field
10
- async def total(self) -> int:
10
+ async def total(self) -> float:
11
11
  return self.prompt + self.completion