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
@@ -55,15 +55,40 @@
55
55
  <meta property="og:description" content="AI Observability & Evaluation" />
56
56
  <meta property="og:image" content="https://raw.githubusercontent.com/Arize-ai/phoenix-assets/main/images/socal/social-preview-horizontal.jpg" />
57
57
  <meta name="theme-color" content="#ffffff" />
58
- <link
59
- rel="stylesheet"
60
- href="https://fonts.googleapis.com/css2?family=Roboto:wght@100;300;400;500;700;900&display=swap"
61
- />
58
+ {% if allow_external_resources %}
59
+ <link rel="preconnect" href="https://fonts.googleapis.com">
60
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
61
+ <link href="https://fonts.googleapis.com/css2?family=Geist:wght@100..900&family=Geist+Mono:wght@100..900&display=swap" rel="stylesheet">
62
+ {% endif %}
62
63
  {% if not is_development -%}
63
64
  {% set _ = collect_assets('index.tsx') -%}
64
65
  {{- render_css() -}}
65
66
  {%- endif -%}
66
67
  <script src="{{basename}}/modernizr.js"></script>
68
+ {% if fullstory_org -%}
69
+ <script>
70
+ window['_fs_host'] = 'fullstory.com';
71
+ window['_fs_script'] = 'edge.fullstory.com/s/fs.js';
72
+ window['_fs_org'] = '{{ fullstory_org }}';
73
+ window['_fs_namespace'] = 'FS';
74
+ !function(m,n,e,t,l,o,g,y){var s,f,a=function(h){
75
+ return!(h in m)||(m.console&&m.console.log&&m.console.log('FullStory namespace conflict. Please set window["_fs_namespace"].'),!1)}(e)
76
+ ;function p(b){var h,d=[];function j(){h&&(d.forEach((function(b){var d;try{d=b[h[0]]&&b[h[0]](h[1])}catch(h){return void(b[3]&&b[3](h))}
77
+ d&&d.then?d.then(b[2],b[3]):b[2]&&b[2](d)})),d.length=0)}function r(b){return function(d){h||(h=[b,d],j())}}return b(r(0),r(1)),{
78
+ then:function(b,h){return p((function(r,i){d.push([b,h,r,i]),j()}))}}}a&&(g=m[e]=function(){var b=function(b,d,j,r){function i(i,c){
79
+ h(b,d,j,i,c,r)}r=r||2;var c,u=/Async$/;return u.test(b)?(b=b.replace(u,""),"function"==typeof Promise?new Promise(i):p(i)):h(b,d,j,c,c,r)}
80
+ ;function h(h,d,j,r,i,c){return b._api?b._api(h,d,j,r,i,c):(b.q&&b.q.push([h,d,j,r,i,c]),null)}return b.q=[],b}(),y=function(b){function h(h){
81
+ "function"==typeof h[4]&&h[4](new Error(b))}var d=g.q;if(d){for(var j=0;j<d.length;j++)h(d[j]);d.length=0,d.push=h}},function(){
82
+ (o=n.createElement(t)).async=!0,o.crossOrigin="anonymous",o.src="https://"+l,o.onerror=function(){y("Error loading "+l)}
83
+ ;var b=n.getElementsByTagName(t)[0];b&&b.parentNode?b.parentNode.insertBefore(o,b):n.head.appendChild(o)}(),function(){function b(){}
84
+ function h(b,h,d){g(b,h,d,1)}function d(b,d,j){h("setProperties",{type:b,properties:d},j)}function j(b,h){d("user",b,h)}function r(b,h,d){j({
85
+ uid:b},d),h&&j(h,d)}g.identify=r,g.setUserVars=j,g.identifyAccount=b,g.clearUserCookie=b,g.setVars=d,g.event=function(b,d,j){h("trackEvent",{
86
+ name:b,properties:d},j)},g.anonymize=function(){r(!1)},g.shutdown=function(){h("shutdown")},g.restart=function(){h("restart")},
87
+ g.log=function(b,d){h("log",{level:b,msg:d})},g.consent=function(b){h("setIdentity",{consent:!arguments.length||b})}}(),s="fetch",
88
+ f="XMLHttpRequest",g._w={},g._w[f]=m[f],g._w[s]=m[s],m[s]&&(m[s]=function(){return g._w[s].apply(this,arguments)}),g._v="2.0.0")
89
+ }(window,document,window._fs_namespace,"script",window._fs_script);
90
+ </script>
91
+ {%- endif %}
67
92
  </head>
68
93
  <body>
69
94
  <div id="root"></div>
@@ -85,11 +110,20 @@
85
110
  authenticationEnabled: Boolean("{{authentication_enabled}}" == "True"),
86
111
  oAuth2Idps: {{ oauth2_idps | tojson }},
87
112
  basicAuthDisabled: Boolean("{{basic_auth_disabled}}" == "True"),
88
- websocketsEnabled: Boolean("{{websockets_enabled}}" == "True"),
113
+ ldapEnabled: Boolean("{{ldap_enabled}}" == "True"),
114
+ ldapManualUserCreationEnabled: Boolean("{{ldap_manual_user_creation_enabled}}" == "True"),
115
+ managementUrl: {{management_url | tojson}},
116
+ supportEmail: {{support_email | tojson}},
117
+ hasDbThreshold: Boolean("{{has_db_threshold}}" == "True"),
118
+ allowExternalResources: Boolean("{{allow_external_resources}}" == "True"),
119
+ authErrorMessages: {{auth_error_messages | tojson}},
89
120
  }),
90
121
  writable: false
91
122
  });
92
123
  })()</script>
124
+ {% if scarf_sh_pixel_id -%}
125
+ <img referrerpolicy="no-referrer-when-downgrade" src="https://static.scarf.sh/a.png?x-pxid={{scarf_sh_pixel_id}}" />
126
+ {%- endif %}
93
127
  {% if is_development -%}
94
128
  <script type="module">
95
129
  import RefreshRuntime from 'http://localhost:5173/@react-refresh'
@@ -103,5 +137,5 @@
103
137
  {%- else -%}
104
138
  {{- render_js() -}}
105
139
  {%- endif -%}
106
- </body>
140
+ </body>
107
141
  </html>
@@ -6,7 +6,6 @@ from time import sleep, time
6
6
 
7
7
  from fastapi import FastAPI
8
8
  from uvicorn import Config, Server
9
- from uvicorn.config import LoopSetupType
10
9
 
11
10
 
12
11
  def _nest_asyncio_applied() -> bool:
@@ -31,7 +30,7 @@ class ThreadServer(Server):
31
30
  ) -> None:
32
31
  # Must use asyncio loop if nest_asyncio is applied
33
32
  # Otherwise the app crashes when the server is run in a thread
34
- loop: LoopSetupType = "asyncio" if _nest_asyncio_applied() else "auto"
33
+ loop = "asyncio" if _nest_asyncio_applied() else "auto"
35
34
  config = Config(
36
35
  app=app,
37
36
  host=host,
phoenix/server/types.py CHANGED
@@ -1,5 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import asyncio
3
4
  from abc import ABC, abstractmethod
4
5
  from asyncio import Task, create_task, sleep
5
6
  from collections import defaultdict
@@ -13,8 +14,9 @@ from cachetools import LRUCache
13
14
  from sqlalchemy.ext.asyncio import AsyncSession
14
15
 
15
16
  from phoenix.auth import CanReadToken, ClaimSet, Token, TokenAttributes
16
- from phoenix.db import enums, models
17
+ from phoenix.db import models
17
18
  from phoenix.db.helpers import SupportedSQLDialect
19
+ from phoenix.db.models import UserRoleName
18
20
 
19
21
 
20
22
  class CanSetLastUpdatedAt(Protocol):
@@ -28,14 +30,22 @@ class CanGetLastUpdatedAt(Protocol):
28
30
  class DbSessionFactory:
29
31
  def __init__(
30
32
  self,
31
- db: Callable[[], AbstractAsyncContextManager[AsyncSession]],
33
+ db: Callable[[Optional[asyncio.Lock]], AbstractAsyncContextManager[AsyncSession]],
32
34
  dialect: str,
33
35
  ):
34
36
  self._db = db
35
37
  self.dialect = SupportedSQLDialect(dialect)
38
+ self.lock: Optional[asyncio.Lock] = None
39
+ self.should_not_insert_or_update = False
40
+ """An informational flag that allows different tasks to coordinate whether insert
41
+ and update operations should be allowed. For example, this can be set to True when disk
42
+ usage is high to prevent further writes to the database, and set to False when disk
43
+ usage returns to normal. Note that this flag does not preclude the actual execution of any
44
+ insert or update operations.
45
+ """
36
46
 
37
47
  def __call__(self) -> AbstractAsyncContextManager[AsyncSession]:
38
- return self._db()
48
+ return self._db(self.lock)
39
49
 
40
50
 
41
51
  _AnyT = TypeVar("_AnyT")
@@ -145,7 +155,7 @@ class ApiKey(Token): ...
145
155
 
146
156
  @dataclass(frozen=True)
147
157
  class UserTokenAttributes(TokenAttributes):
148
- user_role: enums.UserRole
158
+ user_role: UserRoleName
149
159
 
150
160
 
151
161
  @dataclass(frozen=True)
@@ -0,0 +1,74 @@
1
+ from typing import Any, Mapping
2
+
3
+
4
+ def prepend_root_path(scope: Mapping[str, Any], path: str) -> str:
5
+ """
6
+ Prepends the ASGI root path to the given path if one is configured.
7
+
8
+ Normalizes the input path by ensuring it has a leading slash and removing
9
+ trailing slashes. The root path is already normalized by get_root_path().
10
+
11
+ Args:
12
+ scope: The ASGI scope dictionary containing the root_path key
13
+ path: The path to prepend the root path to (e.g., "/login", "logout")
14
+
15
+ Returns:
16
+ The normalized path with root path prepended if configured,
17
+ otherwise just the normalized path. Never has a trailing slash
18
+ except when the result is just "/".
19
+
20
+ Examples:
21
+ With root_path="/apps/phoenix":
22
+ - prepend_root_path(request.scope, "/login") -> "/apps/phoenix/login"
23
+ - prepend_root_path(request.scope, "login") -> "/apps/phoenix/login"
24
+ - prepend_root_path(request.scope, "/") -> "/apps/phoenix"
25
+ - prepend_root_path(request.scope, "") -> "/apps/phoenix"
26
+ - prepend_root_path(request.scope, "login/") -> "/apps/phoenix/login"
27
+ - prepend_root_path(request.scope, "/login/") -> "/apps/phoenix/login"
28
+ - prepend_root_path(request.scope, "abc/def/") -> "/apps/phoenix/abc/def"
29
+
30
+ With no root_path:
31
+ - prepend_root_path(request.scope, "/login") -> "/login"
32
+ - prepend_root_path(request.scope, "login") -> "/login"
33
+ - prepend_root_path(request.scope, "/") -> "/"
34
+ - prepend_root_path(request.scope, "") -> "/"
35
+ - prepend_root_path(request.scope, "login/") -> "/login"
36
+ - prepend_root_path(request.scope, "/login/") -> "/login"
37
+ - prepend_root_path(request.scope, "abc/def/") -> "/abc/def"
38
+ """
39
+ path = path if path.startswith("/") else f"/{path}"
40
+ path = path.rstrip("/") or "/"
41
+ root_path = get_root_path(scope)
42
+ if path == "/":
43
+ return root_path or "/"
44
+ return f"{root_path}{path}"
45
+
46
+
47
+ def get_root_path(scope: Mapping[str, Any]) -> str:
48
+ """
49
+ Extracts and normalizes the root path from the ASGI scope.
50
+
51
+ The root path is typically set by reverse proxies or when the application
52
+ is mounted at a sub-path (e.g., "/apps/phoenix" when behind a proxy).
53
+ If present, ensures the path has a leading slash and removes trailing slashes.
54
+
55
+ Args:
56
+ scope: The ASGI scope dictionary containing the root_path key
57
+
58
+ Returns:
59
+ The normalized root path as a string (with leading slash, no trailing slash)
60
+ if configured, otherwise empty string.
61
+
62
+ Examples:
63
+ - Behind proxy at "/apps/phoenix": returns "/apps/phoenix"
64
+ - Missing leading slash "apps/phoenix": returns "/apps/phoenix"
65
+ - With trailing slash "/apps/phoenix/": returns "/apps/phoenix"
66
+ - Direct deployment: returns ""
67
+ - None in scope: returns ""
68
+ """
69
+ root_path = str(scope.get("root_path") or "")
70
+ if not root_path:
71
+ return ""
72
+ if not root_path.startswith("/"):
73
+ root_path = f"/{root_path}"
74
+ return root_path.rstrip("/")
phoenix/session/client.py CHANGED
@@ -19,7 +19,7 @@ from opentelemetry.proto.common.v1.common_pb2 import AnyValue, KeyValue
19
19
  from opentelemetry.proto.resource.v1.resource_pb2 import Resource
20
20
  from opentelemetry.proto.trace.v1.trace_pb2 import ResourceSpans, ScopeSpans
21
21
  from pyarrow import ArrowInvalid, Table
22
- from typing_extensions import TypeAlias, assert_never
22
+ from typing_extensions import TypeAlias, assert_never, deprecated
23
23
 
24
24
  from phoenix.config import (
25
25
  get_env_collector_endpoint,
@@ -68,8 +68,7 @@ class Client(TraceDataExtractor):
68
68
  """
69
69
  if kwargs.pop("use_active_session_if_available", None) is not None:
70
70
  print(
71
- "`use_active_session_if_available` is deprecated "
72
- "and will be removed in the future."
71
+ "`use_active_session_if_available` is deprecated and will be removed in the future."
73
72
  )
74
73
  if kwargs:
75
74
  raise TypeError(f"Unexpected keyword arguments: {', '.join(kwargs)}")
@@ -111,6 +110,7 @@ class Client(TraceDataExtractor):
111
110
  return session.url
112
111
  return str(self._client.base_url)
113
112
 
113
+ @deprecated("Migrate to using client.spans.get_spans_dataframe via arize-phoenix-client")
114
114
  def query_spans(
115
115
  self,
116
116
  *queries: SpanQuery,
@@ -125,6 +125,11 @@ class Client(TraceDataExtractor):
125
125
  orphan_span_as_root_span: bool = True,
126
126
  ) -> Optional[Union[pd.DataFrame, list[pd.DataFrame]]]:
127
127
  """
128
+ .. deprecated::
129
+ This method is deprecated. Use ``client.spans.get_spans_dataframe()`` via
130
+ arize-phoenix-client instead.
131
+ See https://arize-phoenix.readthedocs.io/projects/client/en/latest/
132
+
128
133
  Queries spans from the Phoenix server or active session based on specified criteria.
129
134
 
130
135
  Args:
@@ -223,6 +228,7 @@ class Client(TraceDataExtractor):
223
228
  return None if df.shape == (0, 0) else df
224
229
  return results
225
230
 
231
+ @deprecated("Migrate to using client.spans.get_span_annotations via arize-phoenix-client")
226
232
  def get_evaluations(
227
233
  self,
228
234
  project_name: Optional[str] = None,
@@ -230,6 +236,11 @@ class Client(TraceDataExtractor):
230
236
  timeout: Optional[int] = DEFAULT_TIMEOUT_IN_SECONDS,
231
237
  ) -> list[Evaluations]:
232
238
  """
239
+ .. deprecated::
240
+ This method is deprecated. Use ``client.spans.get_span_annotations()`` via
241
+ arize-phoenix-client instead.
242
+ See https://arize-phoenix.readthedocs.io/projects/client/en/latest/
243
+
233
244
  Retrieves evaluations for a given project from the Phoenix server or active session.
234
245
 
235
246
  Args:
@@ -277,6 +288,7 @@ class Client(TraceDataExtractor):
277
288
  f"with `import phoenix as px; px.launch_app()`"
278
289
  )
279
290
 
291
+ @deprecated("Migrate to using client.spans.log_span_annotations via arize-phoenix-client")
280
292
  def log_evaluations(
281
293
  self,
282
294
  *evals: Evaluations,
@@ -284,6 +296,11 @@ class Client(TraceDataExtractor):
284
296
  **kwargs: Any,
285
297
  ) -> None:
286
298
  """
299
+ .. deprecated::
300
+ This method is deprecated. Use ``client.spans.log_span_annotations()`` via
301
+ arize-phoenix-client instead.
302
+ See https://arize-phoenix.readthedocs.io/projects/client/en/latest/
303
+
287
304
  Logs evaluation data to the Phoenix server.
288
305
 
289
306
  Args:
@@ -310,8 +327,14 @@ class Client(TraceDataExtractor):
310
327
  timeout=timeout,
311
328
  ).raise_for_status()
312
329
 
330
+ @deprecated("Migrate to using client.spans.log_spans via arize-phoenix-client")
313
331
  def log_traces(self, trace_dataset: TraceDataset, project_name: Optional[str] = None) -> None:
314
332
  """
333
+ .. deprecated::
334
+ This method is deprecated. Use ``client.spans.log_spans()`` via
335
+ arize-phoenix-client instead.
336
+ See https://arize-phoenix.readthedocs.io/projects/client/en/latest/
337
+
315
338
  Logs traces from a TraceDataset to the Phoenix server.
316
339
 
317
340
  Args:
@@ -380,6 +403,7 @@ class Client(TraceDataExtractor):
380
403
  dataset = records[0]
381
404
  return str(dataset["id"])
382
405
 
406
+ @deprecated("Migrate to using client.datasets.get_dataset via arize-phoenix-client")
383
407
  def get_dataset(
384
408
  self,
385
409
  *,
@@ -388,6 +412,11 @@ class Client(TraceDataExtractor):
388
412
  version_id: Optional[str] = None,
389
413
  ) -> Dataset:
390
414
  """
415
+ .. deprecated::
416
+ This method is deprecated. Use ``client.datasets.get_dataset()`` via
417
+ arize-phoenix-client instead.
418
+ See https://arize-phoenix.readthedocs.io/projects/client/en/latest/
419
+
391
420
  Gets the dataset for a specific version, or gets the latest version of
392
421
  the dataset if no version is specified.
393
422
 
@@ -434,6 +463,7 @@ class Client(TraceDataExtractor):
434
463
  examples=examples,
435
464
  )
436
465
 
466
+ @deprecated("Migrate to using client.datasets.get_dataset_versions via arize-phoenix-client")
437
467
  def get_dataset_versions(
438
468
  self,
439
469
  dataset_id: str,
@@ -441,6 +471,11 @@ class Client(TraceDataExtractor):
441
471
  limit: Optional[int] = 100,
442
472
  ) -> pd.DataFrame:
443
473
  """
474
+ .. deprecated::
475
+ This method is deprecated. Use ``client.datasets.get_dataset_versions()`` via
476
+ arize-phoenix-client instead.
477
+ See https://arize-phoenix.readthedocs.io/projects/client/en/latest/
478
+
444
479
  Get dataset versions as pandas DataFrame.
445
480
 
446
481
  Args:
@@ -460,6 +495,7 @@ class Client(TraceDataExtractor):
460
495
  df["created_at"] = df["created_at"].apply(datetime.fromisoformat)
461
496
  return df
462
497
 
498
+ @deprecated("Migrate to using client.datasets.create_dataset via arize-phoenix-client")
463
499
  def upload_dataset(
464
500
  self,
465
501
  *,
@@ -475,6 +511,11 @@ class Client(TraceDataExtractor):
475
511
  dataset_description: Optional[str] = None,
476
512
  ) -> Dataset:
477
513
  """
514
+ .. deprecated::
515
+ This method is deprecated. Use ``client.datasets.create_dataset()`` via
516
+ arize-phoenix-client instead.
517
+ See https://arize-phoenix.readthedocs.io/projects/client/en/latest/
518
+
478
519
  Upload examples as dataset to the Phoenix server. If `dataframe` or
479
520
  `csv_file_path` are provided, must also provide `input_keys` (and
480
521
  optionally with `output_keys` or `metadata_keys` or both), which is a
@@ -536,6 +577,7 @@ class Client(TraceDataExtractor):
536
577
  dataset_description=dataset_description,
537
578
  )
538
579
 
580
+ @deprecated("Migrate to using client.datasets.add_examples_to_dataset via arize-phoenix-client")
539
581
  def append_to_dataset(
540
582
  self,
541
583
  *,
@@ -550,6 +592,11 @@ class Client(TraceDataExtractor):
550
592
  metadata: Iterable[Mapping[str, Any]] = (),
551
593
  ) -> Dataset:
552
594
  """
595
+ .. deprecated::
596
+ This method is deprecated. Use ``client.datasets.add_examples_to_dataset()`` via
597
+ arize-phoenix-client instead.
598
+ See https://arize-phoenix.readthedocs.io/projects/client/en/latest/
599
+
553
600
  Append examples to dataset on the Phoenix server. If `dataframe` or
554
601
  `csv_file_path` are provided, must also provide `input_keys` (and
555
602
  optionally with `output_keys` or `metadata_keys` or both), which is a
@@ -610,8 +657,14 @@ class Client(TraceDataExtractor):
610
657
  action="append",
611
658
  )
612
659
 
660
+ @deprecated("Migrate to using client.experiments.get_experiment via arize-phoenix-client")
613
661
  def get_experiment(self, *, experiment_id: str) -> Experiment:
614
662
  """
663
+ .. deprecated::
664
+ This method is deprecated. Use ``client.experiments.get_experiment()`` via
665
+ arize-phoenix-client instead.
666
+ See https://arize-phoenix.readthedocs.io/projects/client/en/latest/
667
+
615
668
  Get an experiment by ID.
616
669
 
617
670
  Retrieve an Experiment object by ID, enables running `evaluate_experiment` after finishing
@@ -3,6 +3,7 @@ from datetime import datetime
3
3
  from typing import Optional, Union, cast
4
4
 
5
5
  import pandas as pd
6
+ from typing_extensions import deprecated
6
7
 
7
8
  from phoenix.trace import Evaluations
8
9
  from phoenix.trace.dsl import SpanQuery
@@ -18,6 +19,7 @@ class TraceDataExtractor(ABC):
18
19
  `Session` so that they both implement the same methods.
19
20
  """
20
21
 
22
+ @deprecated("Migrate to client.spans.get_spans_dataframe() from arize-phoenix-client")
21
23
  @abstractmethod
22
24
  def query_spans(
23
25
  self,
@@ -30,6 +32,7 @@ class TraceDataExtractor(ABC):
30
32
  timeout: Optional[int] = DEFAULT_TIMEOUT_IN_SECONDS,
31
33
  ) -> Optional[Union[pd.DataFrame, list[pd.DataFrame]]]: ...
32
34
 
35
+ @deprecated("Migrate to client.spans.get_spans_dataframe() from arize-phoenix-client")
33
36
  def get_spans_dataframe(
34
37
  self,
35
38
  filter_condition: Optional[str] = None,
@@ -55,11 +58,13 @@ class TraceDataExtractor(ABC):
55
58
  )
56
59
 
57
60
  @abstractmethod
61
+ @deprecated("Migrate to client.spans.get_span_annotations() from arize-phoenix-client")
58
62
  def get_evaluations(
59
63
  self,
60
64
  project_name: Optional[str] = None,
61
65
  ) -> list[Evaluations]: ...
62
66
 
67
+ @deprecated("Migrate to client.spans.get_spans() from arize-phoenix-client")
63
68
  def get_trace_dataset(
64
69
  self,
65
70
  project_name: Optional[str] = None,
@@ -19,17 +19,23 @@ from typing import (
19
19
 
20
20
  import pandas as pd
21
21
  from google.protobuf.wrappers_pb2 import DoubleValue, StringValue
22
+ from typing_extensions import deprecated
22
23
 
23
24
  import phoenix.trace.v1 as pb
24
25
  from phoenix.config import get_env_collector_endpoint, get_env_host, get_env_port
25
26
  from phoenix.session.client import Client
26
- from phoenix.trace.dsl.helpers import get_qa_with_reference, get_retrieved_documents
27
+ from phoenix.trace.dsl.helpers import (
28
+ get_called_tools,
29
+ get_qa_with_reference,
30
+ get_retrieved_documents,
31
+ )
27
32
  from phoenix.trace.exporter import HttpExporter
28
33
  from phoenix.trace.span_evaluations import Evaluations
29
34
 
30
35
  __all__ = [
31
36
  "get_retrieved_documents",
32
37
  "get_qa_with_reference",
38
+ "get_called_tools",
33
39
  "add_evaluations",
34
40
  ]
35
41
 
@@ -131,16 +137,19 @@ def _extract_result(row: "pd.Series[Any]") -> Optional[pb.Evaluation.Result]:
131
137
  )
132
138
 
133
139
 
140
+ @deprecated("Migrate to using client.spans.log_span_annotations via arize-phoenix-client")
134
141
  def log_evaluations(
135
142
  *evals: Evaluations,
136
143
  endpoint: Optional[str] = None,
137
144
  host: Optional[str] = None,
138
145
  port: Optional[int] = None,
139
146
  ) -> None:
140
- logger.warning(
141
- "This `log_evaluations` function is deprecated and will be removed in a future release. "
142
- "Please use `px.Client().log_evaluations(*evaluations)` instead."
143
- )
147
+ """
148
+ .. deprecated::
149
+ This function is deprecated. Use ``client.spans.log_span_annotations()`` via
150
+ arize-phoenix-client instead.
151
+ See https://arize-phoenix.readthedocs.io/projects/client/en/latest/
152
+ """
144
153
  host = host or get_env_host()
145
154
  if host == "0.0.0.0":
146
155
  host = "127.0.0.1"
@@ -12,10 +12,11 @@ from importlib.util import find_spec
12
12
  from itertools import chain
13
13
  from pathlib import Path
14
14
  from tempfile import TemporaryDirectory
15
- from typing import TYPE_CHECKING, Any, NamedTuple, Optional, Union
15
+ from typing import TYPE_CHECKING, Any, Awaitable, Callable, NamedTuple, Optional, Union
16
16
  from urllib.parse import urljoin
17
17
 
18
18
  import pandas as pd
19
+ from typing_extensions import deprecated
19
20
 
20
21
  from phoenix.config import (
21
22
  ENV_NOTEBOOK_ENV,
@@ -25,6 +26,7 @@ from phoenix.config import (
25
26
  ensure_working_dir_if_needed,
26
27
  get_env_database_connection_str,
27
28
  get_env_host,
29
+ get_env_host_root_path,
28
30
  get_env_port,
29
31
  get_exported_files,
30
32
  get_working_dir,
@@ -117,6 +119,7 @@ class Session(TraceDataExtractor, ABC):
117
119
  default_umap_parameters: Optional[Mapping[str, Any]] = None,
118
120
  host: Optional[str] = None,
119
121
  port: Optional[int] = None,
122
+ root_path: Optional[str] = None,
120
123
  notebook_env: Optional[NotebookEnvironment] = None,
121
124
  ):
122
125
  self._database_url = database_url
@@ -132,12 +135,21 @@ class Session(TraceDataExtractor, ABC):
132
135
  self.export_path.mkdir(parents=True, exist_ok=True)
133
136
  self.exported_data = ExportedData()
134
137
  self.notebook_env = notebook_env or _get_notebook_environment()
135
- self.root_path = _get_root_path(self.notebook_env, self.port)
138
+ self.root_path = (
139
+ (get_env_host_root_path() or _get_root_path(self.notebook_env, self.port))
140
+ if root_path is None
141
+ else root_path
142
+ )
143
+ if self.root_path and self.root_path != "/":
144
+ if not self.root_path.startswith("/"):
145
+ self.root_path = f"/{self.root_path}"
146
+ self.root_path = self.root_path.rstrip("/")
136
147
  host = "127.0.0.1" if self.host == "0.0.0.0" else self.host
137
148
  self._client = Client(
138
149
  endpoint=f"http://{host}:{self.port}", warn_if_server_not_running=False
139
150
  )
140
151
 
152
+ @deprecated("Migrate to using client.spans.get_spans_dataframe via arize-phoenix-client")
141
153
  def query_spans(
142
154
  self,
143
155
  *queries: SpanQuery,
@@ -151,6 +163,11 @@ class Session(TraceDataExtractor, ABC):
151
163
  timeout: Optional[int] = DEFAULT_TIMEOUT_IN_SECONDS,
152
164
  ) -> Optional[Union[pd.DataFrame, list[pd.DataFrame]]]:
153
165
  """
166
+ .. deprecated::
167
+ This method is deprecated. Use ``client.spans.get_spans_dataframe()`` via
168
+ arize-phoenix-client instead.
169
+ See https://arize-phoenix.readthedocs.io/projects/client/en/latest/
170
+
154
171
  Queries the spans in the project based on the provided parameters.
155
172
 
156
173
  Parameters
@@ -192,11 +209,17 @@ class Session(TraceDataExtractor, ABC):
192
209
  project_name=project_name,
193
210
  )
194
211
 
212
+ @deprecated("Migrate to using client.spans.get_span_annotations via arize-phoenix-client")
195
213
  def get_evaluations(
196
214
  self,
197
215
  project_name: Optional[str] = None,
198
216
  ) -> list[Evaluations]:
199
217
  """
218
+ .. deprecated::
219
+ This method is deprecated. Use ``client.spans.get_span_annotations()`` via
220
+ arize-phoenix-client instead.
221
+ See https://arize-phoenix.readthedocs.io/projects/client/en/latest/
222
+
200
223
  Get the evaluations for a project.
201
224
 
202
225
  Parameters
@@ -255,7 +278,7 @@ class Session(TraceDataExtractor, ABC):
255
278
  @property
256
279
  def url(self) -> str:
257
280
  """Returns the url for the phoenix app"""
258
- return _get_url(self.host, self.port, self.notebook_env)
281
+ return _get_url(self.host, self.port, self.notebook_env, self.root_path)
259
282
 
260
283
  @property
261
284
  def database_url(self) -> str:
@@ -288,6 +311,7 @@ class ProcessSession(Session):
288
311
  default_umap_parameters=default_umap_parameters,
289
312
  host=host,
290
313
  port=port,
314
+ root_path=root_path,
291
315
  notebook_env=notebook_env,
292
316
  )
293
317
  primary_inferences.to_disc()
@@ -354,6 +378,7 @@ class ThreadSession(Session):
354
378
  default_umap_parameters=default_umap_parameters,
355
379
  host=host,
356
380
  port=port,
381
+ root_path=root_path,
357
382
  notebook_env=notebook_env,
358
383
  )
359
384
  self.model = create_model_from_inferences(
@@ -369,7 +394,10 @@ class ThreadSession(Session):
369
394
  )
370
395
  # Initialize an app service that keeps the server running
371
396
  engine = create_engine_and_run_migrations(database_url)
372
- instrumentation_cleanups = instrument_engine_if_enabled(engine)
397
+ shutdown_callbacks: list[Callable[[], None | Awaitable[None]]] = []
398
+ shutdown_callbacks.extend(instrument_engine_if_enabled(engine))
399
+ # Ensure engine is disposed on shutdown to properly close database connections
400
+ shutdown_callbacks.append(engine.dispose)
373
401
  factory = DbSessionFactory(db=_db(engine), dialect=engine.dialect.name)
374
402
  self.app = create_app(
375
403
  db=factory,
@@ -384,7 +412,7 @@ class ThreadSession(Session):
384
412
  if (trace_dataset and (initial_evaluations := trace_dataset.evaluations))
385
413
  else None
386
414
  ),
387
- shutdown_callbacks=instrumentation_cleanups,
415
+ shutdown_callbacks=shutdown_callbacks,
388
416
  )
389
417
  self.server = ThreadServer(
390
418
  app=self.app,
@@ -436,6 +464,7 @@ def launch_app(
436
464
  default_umap_parameters: Optional[Mapping[str, Any]] = None,
437
465
  host: Optional[str] = None,
438
466
  port: Optional[int] = None,
467
+ root_path: Optional[str] = None,
439
468
  run_in_thread: bool = True,
440
469
  notebook_environment: Optional[Union[NotebookEnvironment, str]] = None,
441
470
  use_temp_dir: bool = True,
@@ -461,6 +490,9 @@ def launch_app(
461
490
  The port on which the server listens. When using traces this should not be
462
491
  used and should instead set the environment variable `PHOENIX_PORT`.
463
492
  Defaults to 6006.
493
+ root_path: str, optional
494
+ The root path to serve the application under (useful when behind a proxy).
495
+ Can also be set using environment variable `PHOENIX_HOST_ROOT_PATH`.
464
496
  run_in_thread: bool, optional, default=True
465
497
  Whether the server should run in a Thread or Process.
466
498
  default_umap_parameters: dict[str, Union[int, float]], optional, default=None
@@ -573,6 +605,7 @@ def launch_app(
573
605
  default_umap_parameters,
574
606
  host=host,
575
607
  port=port,
608
+ root_path=root_path,
576
609
  notebook_env=nb_env,
577
610
  )
578
611
  # TODO: catch exceptions from thread
@@ -586,6 +619,7 @@ def launch_app(
586
619
  default_umap_parameters,
587
620
  host=host,
588
621
  port=port,
622
+ root_path=root_path,
589
623
  notebook_env=nb_env,
590
624
  )
591
625
 
@@ -601,7 +635,7 @@ def launch_app(
601
635
  print(f"🌍 To view the Phoenix app in your browser, visit {_session.url}")
602
636
  if not use_temp_dir:
603
637
  print(f"💽 Your data is being persisted to {get_printable_db_url(database_url)}")
604
- print("📖 For more information on how to use Phoenix, check out https://docs.arize.com/phoenix")
638
+ print("📖 For more information on how to use Phoenix, check out https://arize.com/docs/phoenix")
605
639
  return _session
606
640
 
607
641
 
@@ -636,7 +670,7 @@ def close_app(delete_data: bool = False) -> None:
636
670
  delete_all(prompt_before_delete=False)
637
671
 
638
672
 
639
- def _get_url(host: str, port: int, notebook_env: NotebookEnvironment) -> str:
673
+ def _get_url(host: str, port: int, notebook_env: NotebookEnvironment, root_path: str) -> str:
640
674
  """Determines the IFrame URL based on whether this is in a Colab or in a local notebook"""
641
675
  if notebook_env == NotebookEnvironment.COLAB:
642
676
  from google.colab.output import eval_js
@@ -648,10 +682,12 @@ def _get_url(host: str, port: int, notebook_env: NotebookEnvironment) -> str:
648
682
  if notebook_env == NotebookEnvironment.DATABRICKS:
649
683
  context = _get_databricks_context()
650
684
  return f"{_get_databricks_notebook_base_url(context)}/{port}/"
685
+ if not root_path.startswith("/"):
686
+ root_path = f"/{root_path}"
651
687
  if host == "0.0.0.0" or host == "127.0.0.1":
652
688
  # The app is running locally, so use localhost
653
- return f"http://localhost:{port}/"
654
- return f"http://{host}:{port}/"
689
+ return f"http://localhost:{port}{root_path}"
690
+ return f"http://{host}:{port}{root_path}"
655
691
 
656
692
 
657
693
  def _is_colab() -> bool: