arize-phoenix 11.23.1__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 (221) hide show
  1. {arize_phoenix-11.23.1.dist-info → arize_phoenix-12.28.1.dist-info}/METADATA +61 -36
  2. {arize_phoenix-11.23.1.dist-info → arize_phoenix-12.28.1.dist-info}/RECORD +212 -162
  3. {arize_phoenix-11.23.1.dist-info → arize_phoenix-12.28.1.dist-info}/WHEEL +1 -1
  4. {arize_phoenix-11.23.1.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 +2 -1
  12. phoenix/auth.py +27 -2
  13. phoenix/config.py +1594 -81
  14. phoenix/db/README.md +546 -28
  15. phoenix/db/bulk_inserter.py +119 -116
  16. phoenix/db/engines.py +140 -33
  17. phoenix/db/facilitator.py +22 -1
  18. phoenix/db/helpers.py +818 -65
  19. phoenix/db/iam_auth.py +64 -0
  20. phoenix/db/insertion/dataset.py +133 -1
  21. phoenix/db/insertion/document_annotation.py +9 -6
  22. phoenix/db/insertion/evaluation.py +2 -3
  23. phoenix/db/insertion/helpers.py +2 -2
  24. phoenix/db/insertion/session_annotation.py +176 -0
  25. phoenix/db/insertion/span_annotation.py +3 -4
  26. phoenix/db/insertion/trace_annotation.py +3 -4
  27. phoenix/db/insertion/types.py +41 -18
  28. phoenix/db/migrations/versions/01a8342c9cdf_add_user_id_on_datasets.py +40 -0
  29. phoenix/db/migrations/versions/0df286449799_add_session_annotations_table.py +105 -0
  30. phoenix/db/migrations/versions/272b66ff50f8_drop_single_indices.py +119 -0
  31. phoenix/db/migrations/versions/58228d933c91_dataset_labels.py +67 -0
  32. phoenix/db/migrations/versions/699f655af132_experiment_tags.py +57 -0
  33. phoenix/db/migrations/versions/735d3d93c33e_add_composite_indices.py +41 -0
  34. phoenix/db/migrations/versions/ab513d89518b_add_user_id_on_dataset_versions.py +40 -0
  35. phoenix/db/migrations/versions/d0690a79ea51_users_on_experiments.py +40 -0
  36. phoenix/db/migrations/versions/deb2c81c0bb2_dataset_splits.py +139 -0
  37. phoenix/db/migrations/versions/e76cbd66ffc3_add_experiments_dataset_examples.py +87 -0
  38. phoenix/db/models.py +364 -56
  39. phoenix/db/pg_config.py +10 -0
  40. phoenix/db/types/trace_retention.py +7 -6
  41. phoenix/experiments/functions.py +69 -19
  42. phoenix/inferences/inferences.py +1 -2
  43. phoenix/server/api/auth.py +9 -0
  44. phoenix/server/api/auth_messages.py +46 -0
  45. phoenix/server/api/context.py +60 -0
  46. phoenix/server/api/dataloaders/__init__.py +36 -0
  47. phoenix/server/api/dataloaders/annotation_summaries.py +60 -8
  48. phoenix/server/api/dataloaders/average_experiment_repeated_run_group_latency.py +50 -0
  49. phoenix/server/api/dataloaders/average_experiment_run_latency.py +17 -24
  50. phoenix/server/api/dataloaders/cache/two_tier_cache.py +1 -2
  51. phoenix/server/api/dataloaders/dataset_dataset_splits.py +52 -0
  52. phoenix/server/api/dataloaders/dataset_example_revisions.py +0 -1
  53. phoenix/server/api/dataloaders/dataset_example_splits.py +40 -0
  54. phoenix/server/api/dataloaders/dataset_examples_and_versions_by_experiment_run.py +47 -0
  55. phoenix/server/api/dataloaders/dataset_labels.py +36 -0
  56. phoenix/server/api/dataloaders/document_evaluation_summaries.py +2 -2
  57. phoenix/server/api/dataloaders/document_evaluations.py +6 -9
  58. phoenix/server/api/dataloaders/experiment_annotation_summaries.py +88 -34
  59. phoenix/server/api/dataloaders/experiment_dataset_splits.py +43 -0
  60. phoenix/server/api/dataloaders/experiment_error_rates.py +21 -28
  61. phoenix/server/api/dataloaders/experiment_repeated_run_group_annotation_summaries.py +77 -0
  62. phoenix/server/api/dataloaders/experiment_repeated_run_groups.py +57 -0
  63. phoenix/server/api/dataloaders/experiment_runs_by_experiment_and_example.py +44 -0
  64. phoenix/server/api/dataloaders/latency_ms_quantile.py +40 -8
  65. phoenix/server/api/dataloaders/record_counts.py +37 -10
  66. phoenix/server/api/dataloaders/session_annotations_by_session.py +29 -0
  67. phoenix/server/api/dataloaders/span_cost_summary_by_experiment_repeated_run_group.py +64 -0
  68. phoenix/server/api/dataloaders/span_cost_summary_by_project.py +28 -14
  69. phoenix/server/api/dataloaders/span_costs.py +3 -9
  70. phoenix/server/api/dataloaders/table_fields.py +2 -2
  71. phoenix/server/api/dataloaders/token_prices_by_model.py +30 -0
  72. phoenix/server/api/dataloaders/trace_annotations_by_trace.py +27 -0
  73. phoenix/server/api/exceptions.py +5 -1
  74. phoenix/server/api/helpers/playground_clients.py +263 -83
  75. phoenix/server/api/helpers/playground_spans.py +2 -1
  76. phoenix/server/api/helpers/playground_users.py +26 -0
  77. phoenix/server/api/helpers/prompts/conversions/google.py +103 -0
  78. phoenix/server/api/helpers/prompts/models.py +61 -19
  79. phoenix/server/api/input_types/{SpanAnnotationFilter.py → AnnotationFilter.py} +22 -14
  80. phoenix/server/api/input_types/ChatCompletionInput.py +3 -0
  81. phoenix/server/api/input_types/CreateProjectSessionAnnotationInput.py +37 -0
  82. phoenix/server/api/input_types/DatasetFilter.py +5 -2
  83. phoenix/server/api/input_types/ExperimentRunSort.py +237 -0
  84. phoenix/server/api/input_types/GenerativeModelInput.py +3 -0
  85. phoenix/server/api/input_types/ProjectSessionSort.py +158 -1
  86. phoenix/server/api/input_types/PromptVersionInput.py +47 -1
  87. phoenix/server/api/input_types/SpanSort.py +3 -2
  88. phoenix/server/api/input_types/UpdateAnnotationInput.py +34 -0
  89. phoenix/server/api/input_types/UserRoleInput.py +1 -0
  90. phoenix/server/api/mutations/__init__.py +8 -0
  91. phoenix/server/api/mutations/annotation_config_mutations.py +8 -8
  92. phoenix/server/api/mutations/api_key_mutations.py +15 -20
  93. phoenix/server/api/mutations/chat_mutations.py +106 -37
  94. phoenix/server/api/mutations/dataset_label_mutations.py +243 -0
  95. phoenix/server/api/mutations/dataset_mutations.py +21 -16
  96. phoenix/server/api/mutations/dataset_split_mutations.py +351 -0
  97. phoenix/server/api/mutations/experiment_mutations.py +2 -2
  98. phoenix/server/api/mutations/export_events_mutations.py +3 -3
  99. phoenix/server/api/mutations/model_mutations.py +11 -9
  100. phoenix/server/api/mutations/project_mutations.py +4 -4
  101. phoenix/server/api/mutations/project_session_annotations_mutations.py +158 -0
  102. phoenix/server/api/mutations/project_trace_retention_policy_mutations.py +8 -4
  103. phoenix/server/api/mutations/prompt_label_mutations.py +74 -65
  104. phoenix/server/api/mutations/prompt_mutations.py +65 -129
  105. phoenix/server/api/mutations/prompt_version_tag_mutations.py +11 -8
  106. phoenix/server/api/mutations/span_annotations_mutations.py +15 -10
  107. phoenix/server/api/mutations/trace_annotations_mutations.py +13 -8
  108. phoenix/server/api/mutations/trace_mutations.py +3 -3
  109. phoenix/server/api/mutations/user_mutations.py +55 -26
  110. phoenix/server/api/queries.py +501 -617
  111. phoenix/server/api/routers/__init__.py +2 -2
  112. phoenix/server/api/routers/auth.py +141 -87
  113. phoenix/server/api/routers/ldap.py +229 -0
  114. phoenix/server/api/routers/oauth2.py +349 -101
  115. phoenix/server/api/routers/v1/__init__.py +22 -4
  116. phoenix/server/api/routers/v1/annotation_configs.py +19 -30
  117. phoenix/server/api/routers/v1/annotations.py +455 -13
  118. phoenix/server/api/routers/v1/datasets.py +355 -68
  119. phoenix/server/api/routers/v1/documents.py +142 -0
  120. phoenix/server/api/routers/v1/evaluations.py +20 -28
  121. phoenix/server/api/routers/v1/experiment_evaluations.py +16 -6
  122. phoenix/server/api/routers/v1/experiment_runs.py +335 -59
  123. phoenix/server/api/routers/v1/experiments.py +475 -47
  124. phoenix/server/api/routers/v1/projects.py +16 -50
  125. phoenix/server/api/routers/v1/prompts.py +50 -39
  126. phoenix/server/api/routers/v1/sessions.py +108 -0
  127. phoenix/server/api/routers/v1/spans.py +156 -96
  128. phoenix/server/api/routers/v1/traces.py +51 -77
  129. phoenix/server/api/routers/v1/users.py +64 -24
  130. phoenix/server/api/routers/v1/utils.py +3 -7
  131. phoenix/server/api/subscriptions.py +257 -93
  132. phoenix/server/api/types/Annotation.py +90 -23
  133. phoenix/server/api/types/ApiKey.py +13 -17
  134. phoenix/server/api/types/AuthMethod.py +1 -0
  135. phoenix/server/api/types/ChatCompletionSubscriptionPayload.py +1 -0
  136. phoenix/server/api/types/Dataset.py +199 -72
  137. phoenix/server/api/types/DatasetExample.py +88 -18
  138. phoenix/server/api/types/DatasetExperimentAnnotationSummary.py +10 -0
  139. phoenix/server/api/types/DatasetLabel.py +57 -0
  140. phoenix/server/api/types/DatasetSplit.py +98 -0
  141. phoenix/server/api/types/DatasetVersion.py +49 -4
  142. phoenix/server/api/types/DocumentAnnotation.py +212 -0
  143. phoenix/server/api/types/Experiment.py +215 -68
  144. phoenix/server/api/types/ExperimentComparison.py +3 -9
  145. phoenix/server/api/types/ExperimentRepeatedRunGroup.py +155 -0
  146. phoenix/server/api/types/ExperimentRepeatedRunGroupAnnotationSummary.py +9 -0
  147. phoenix/server/api/types/ExperimentRun.py +120 -70
  148. phoenix/server/api/types/ExperimentRunAnnotation.py +158 -39
  149. phoenix/server/api/types/GenerativeModel.py +95 -42
  150. phoenix/server/api/types/GenerativeProvider.py +1 -1
  151. phoenix/server/api/types/ModelInterface.py +7 -2
  152. phoenix/server/api/types/PlaygroundModel.py +12 -2
  153. phoenix/server/api/types/Project.py +218 -185
  154. phoenix/server/api/types/ProjectSession.py +146 -29
  155. phoenix/server/api/types/ProjectSessionAnnotation.py +187 -0
  156. phoenix/server/api/types/ProjectTraceRetentionPolicy.py +1 -1
  157. phoenix/server/api/types/Prompt.py +119 -39
  158. phoenix/server/api/types/PromptLabel.py +42 -25
  159. phoenix/server/api/types/PromptVersion.py +11 -8
  160. phoenix/server/api/types/PromptVersionTag.py +65 -25
  161. phoenix/server/api/types/Span.py +130 -123
  162. phoenix/server/api/types/SpanAnnotation.py +189 -42
  163. phoenix/server/api/types/SystemApiKey.py +65 -1
  164. phoenix/server/api/types/Trace.py +184 -53
  165. phoenix/server/api/types/TraceAnnotation.py +149 -50
  166. phoenix/server/api/types/User.py +128 -33
  167. phoenix/server/api/types/UserApiKey.py +73 -26
  168. phoenix/server/api/types/node.py +10 -0
  169. phoenix/server/api/types/pagination.py +11 -2
  170. phoenix/server/app.py +154 -36
  171. phoenix/server/authorization.py +5 -4
  172. phoenix/server/bearer_auth.py +13 -5
  173. phoenix/server/cost_tracking/cost_model_lookup.py +42 -14
  174. phoenix/server/cost_tracking/model_cost_manifest.json +1085 -194
  175. phoenix/server/daemons/generative_model_store.py +61 -9
  176. phoenix/server/daemons/span_cost_calculator.py +10 -8
  177. phoenix/server/dml_event.py +13 -0
  178. phoenix/server/email/sender.py +29 -2
  179. phoenix/server/grpc_server.py +9 -9
  180. phoenix/server/jwt_store.py +8 -6
  181. phoenix/server/ldap.py +1449 -0
  182. phoenix/server/main.py +9 -3
  183. phoenix/server/oauth2.py +330 -12
  184. phoenix/server/prometheus.py +43 -6
  185. phoenix/server/rate_limiters.py +4 -9
  186. phoenix/server/retention.py +33 -20
  187. phoenix/server/session_filters.py +49 -0
  188. phoenix/server/static/.vite/manifest.json +51 -53
  189. phoenix/server/static/assets/components-BreFUQQa.js +6702 -0
  190. phoenix/server/static/assets/{index-BPCwGQr8.js → index-CTQoemZv.js} +42 -35
  191. phoenix/server/static/assets/pages-DBE5iYM3.js +9524 -0
  192. phoenix/server/static/assets/vendor-BGzfc4EU.css +1 -0
  193. phoenix/server/static/assets/vendor-DCE4v-Ot.js +920 -0
  194. phoenix/server/static/assets/vendor-codemirror-D5f205eT.js +25 -0
  195. phoenix/server/static/assets/{vendor-recharts-Bw30oz1A.js → vendor-recharts-V9cwpXsm.js} +7 -7
  196. phoenix/server/static/assets/{vendor-shiki-DZajAPeq.js → vendor-shiki-Do--csgv.js} +1 -1
  197. phoenix/server/static/assets/vendor-three-CmB8bl_y.js +3840 -0
  198. phoenix/server/templates/index.html +7 -1
  199. phoenix/server/thread_server.py +1 -2
  200. phoenix/server/utils.py +74 -0
  201. phoenix/session/client.py +55 -1
  202. phoenix/session/data_extractor.py +5 -0
  203. phoenix/session/evaluation.py +8 -4
  204. phoenix/session/session.py +44 -8
  205. phoenix/settings.py +2 -0
  206. phoenix/trace/attributes.py +80 -13
  207. phoenix/trace/dsl/query.py +2 -0
  208. phoenix/trace/projects.py +5 -0
  209. phoenix/utilities/template_formatters.py +1 -1
  210. phoenix/version.py +1 -1
  211. phoenix/server/api/types/Evaluation.py +0 -39
  212. phoenix/server/static/assets/components-D0DWAf0l.js +0 -5650
  213. phoenix/server/static/assets/pages-Creyamao.js +0 -8612
  214. phoenix/server/static/assets/vendor-CU36oj8y.js +0 -905
  215. phoenix/server/static/assets/vendor-CqDb5u4o.css +0 -1
  216. phoenix/server/static/assets/vendor-arizeai-Ctgw0e1G.js +0 -168
  217. phoenix/server/static/assets/vendor-codemirror-Cojjzqb9.js +0 -25
  218. phoenix/server/static/assets/vendor-three-BLWp5bic.js +0 -2998
  219. phoenix/utilities/deprecation.py +0 -31
  220. {arize_phoenix-11.23.1.dist-info → arize_phoenix-12.28.1.dist-info}/entry_points.txt +0 -0
  221. {arize_phoenix-11.23.1.dist-info → arize_phoenix-12.28.1.dist-info}/licenses/LICENSE +0 -0
@@ -110,14 +110,20 @@
110
110
  authenticationEnabled: Boolean("{{authentication_enabled}}" == "True"),
111
111
  oAuth2Idps: {{ oauth2_idps | tojson }},
112
112
  basicAuthDisabled: Boolean("{{basic_auth_disabled}}" == "True"),
113
+ ldapEnabled: Boolean("{{ldap_enabled}}" == "True"),
114
+ ldapManualUserCreationEnabled: Boolean("{{ldap_manual_user_creation_enabled}}" == "True"),
113
115
  managementUrl: {{management_url | tojson}},
114
116
  supportEmail: {{support_email | tojson}},
115
117
  hasDbThreshold: Boolean("{{has_db_threshold}}" == "True"),
116
118
  allowExternalResources: Boolean("{{allow_external_resources}}" == "True"),
119
+ authErrorMessages: {{auth_error_messages | tojson}},
117
120
  }),
118
121
  writable: false
119
122
  });
120
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 %}
121
127
  {% if is_development -%}
122
128
  <script type="module">
123
129
  import RefreshRuntime from 'http://localhost:5173/@react-refresh'
@@ -131,5 +137,5 @@
131
137
  {%- else -%}
132
138
  {{- render_js() -}}
133
139
  {%- endif -%}
134
- </body>
140
+ </body>
135
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,
@@ -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,
@@ -110,6 +110,7 @@ class Client(TraceDataExtractor):
110
110
  return session.url
111
111
  return str(self._client.base_url)
112
112
 
113
+ @deprecated("Migrate to using client.spans.get_spans_dataframe via arize-phoenix-client")
113
114
  def query_spans(
114
115
  self,
115
116
  *queries: SpanQuery,
@@ -124,6 +125,11 @@ class Client(TraceDataExtractor):
124
125
  orphan_span_as_root_span: bool = True,
125
126
  ) -> Optional[Union[pd.DataFrame, list[pd.DataFrame]]]:
126
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
+
127
133
  Queries spans from the Phoenix server or active session based on specified criteria.
128
134
 
129
135
  Args:
@@ -222,6 +228,7 @@ class Client(TraceDataExtractor):
222
228
  return None if df.shape == (0, 0) else df
223
229
  return results
224
230
 
231
+ @deprecated("Migrate to using client.spans.get_span_annotations via arize-phoenix-client")
225
232
  def get_evaluations(
226
233
  self,
227
234
  project_name: Optional[str] = None,
@@ -229,6 +236,11 @@ class Client(TraceDataExtractor):
229
236
  timeout: Optional[int] = DEFAULT_TIMEOUT_IN_SECONDS,
230
237
  ) -> list[Evaluations]:
231
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
+
232
244
  Retrieves evaluations for a given project from the Phoenix server or active session.
233
245
 
234
246
  Args:
@@ -276,6 +288,7 @@ class Client(TraceDataExtractor):
276
288
  f"with `import phoenix as px; px.launch_app()`"
277
289
  )
278
290
 
291
+ @deprecated("Migrate to using client.spans.log_span_annotations via arize-phoenix-client")
279
292
  def log_evaluations(
280
293
  self,
281
294
  *evals: Evaluations,
@@ -283,6 +296,11 @@ class Client(TraceDataExtractor):
283
296
  **kwargs: Any,
284
297
  ) -> None:
285
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
+
286
304
  Logs evaluation data to the Phoenix server.
287
305
 
288
306
  Args:
@@ -309,8 +327,14 @@ class Client(TraceDataExtractor):
309
327
  timeout=timeout,
310
328
  ).raise_for_status()
311
329
 
330
+ @deprecated("Migrate to using client.spans.log_spans via arize-phoenix-client")
312
331
  def log_traces(self, trace_dataset: TraceDataset, project_name: Optional[str] = None) -> None:
313
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
+
314
338
  Logs traces from a TraceDataset to the Phoenix server.
315
339
 
316
340
  Args:
@@ -379,6 +403,7 @@ class Client(TraceDataExtractor):
379
403
  dataset = records[0]
380
404
  return str(dataset["id"])
381
405
 
406
+ @deprecated("Migrate to using client.datasets.get_dataset via arize-phoenix-client")
382
407
  def get_dataset(
383
408
  self,
384
409
  *,
@@ -387,6 +412,11 @@ class Client(TraceDataExtractor):
387
412
  version_id: Optional[str] = None,
388
413
  ) -> Dataset:
389
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
+
390
420
  Gets the dataset for a specific version, or gets the latest version of
391
421
  the dataset if no version is specified.
392
422
 
@@ -433,6 +463,7 @@ class Client(TraceDataExtractor):
433
463
  examples=examples,
434
464
  )
435
465
 
466
+ @deprecated("Migrate to using client.datasets.get_dataset_versions via arize-phoenix-client")
436
467
  def get_dataset_versions(
437
468
  self,
438
469
  dataset_id: str,
@@ -440,6 +471,11 @@ class Client(TraceDataExtractor):
440
471
  limit: Optional[int] = 100,
441
472
  ) -> pd.DataFrame:
442
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
+
443
479
  Get dataset versions as pandas DataFrame.
444
480
 
445
481
  Args:
@@ -459,6 +495,7 @@ class Client(TraceDataExtractor):
459
495
  df["created_at"] = df["created_at"].apply(datetime.fromisoformat)
460
496
  return df
461
497
 
498
+ @deprecated("Migrate to using client.datasets.create_dataset via arize-phoenix-client")
462
499
  def upload_dataset(
463
500
  self,
464
501
  *,
@@ -474,6 +511,11 @@ class Client(TraceDataExtractor):
474
511
  dataset_description: Optional[str] = None,
475
512
  ) -> Dataset:
476
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
+
477
519
  Upload examples as dataset to the Phoenix server. If `dataframe` or
478
520
  `csv_file_path` are provided, must also provide `input_keys` (and
479
521
  optionally with `output_keys` or `metadata_keys` or both), which is a
@@ -535,6 +577,7 @@ class Client(TraceDataExtractor):
535
577
  dataset_description=dataset_description,
536
578
  )
537
579
 
580
+ @deprecated("Migrate to using client.datasets.add_examples_to_dataset via arize-phoenix-client")
538
581
  def append_to_dataset(
539
582
  self,
540
583
  *,
@@ -549,6 +592,11 @@ class Client(TraceDataExtractor):
549
592
  metadata: Iterable[Mapping[str, Any]] = (),
550
593
  ) -> Dataset:
551
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
+
552
600
  Append examples to dataset on the Phoenix server. If `dataframe` or
553
601
  `csv_file_path` are provided, must also provide `input_keys` (and
554
602
  optionally with `output_keys` or `metadata_keys` or both), which is a
@@ -609,8 +657,14 @@ class Client(TraceDataExtractor):
609
657
  action="append",
610
658
  )
611
659
 
660
+ @deprecated("Migrate to using client.experiments.get_experiment via arize-phoenix-client")
612
661
  def get_experiment(self, *, experiment_id: str) -> Experiment:
613
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
+
614
668
  Get an experiment by ID.
615
669
 
616
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,6 +19,7 @@ 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
@@ -136,16 +137,19 @@ def _extract_result(row: "pd.Series[Any]") -> Optional[pb.Evaluation.Result]:
136
137
  )
137
138
 
138
139
 
140
+ @deprecated("Migrate to using client.spans.log_span_annotations via arize-phoenix-client")
139
141
  def log_evaluations(
140
142
  *evals: Evaluations,
141
143
  endpoint: Optional[str] = None,
142
144
  host: Optional[str] = None,
143
145
  port: Optional[int] = None,
144
146
  ) -> None:
145
- logger.warning(
146
- "This `log_evaluations` function is deprecated and will be removed in a future release. "
147
- "Please use `px.Client().log_evaluations(*evaluations)` instead."
148
- )
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
+ """
149
153
  host = host or get_env_host()
150
154
  if host == "0.0.0.0":
151
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
 
@@ -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:
phoenix/settings.py CHANGED
@@ -21,6 +21,8 @@ class _Settings:
21
21
  disable_migrations: bool = field(default=False)
22
22
  # FullStory organization ID for web analytics tracking
23
23
  fullstory_org: Optional[str] = field(default=None)
24
+ # Scarf.sh pixel ID for open-source analytics and usage
25
+ scarf_sh_pixel_id: Optional[str] = field(default=None)
24
26
 
25
27
 
26
28
  # Singleton instance of the settings