arize-phoenix 3.16.1__py3-none-any.whl → 7.7.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.

Potentially problematic release.


This version of arize-phoenix might be problematic. Click here for more details.

Files changed (338) hide show
  1. arize_phoenix-7.7.1.dist-info/METADATA +261 -0
  2. arize_phoenix-7.7.1.dist-info/RECORD +345 -0
  3. {arize_phoenix-3.16.1.dist-info → arize_phoenix-7.7.1.dist-info}/WHEEL +1 -1
  4. arize_phoenix-7.7.1.dist-info/entry_points.txt +3 -0
  5. phoenix/__init__.py +86 -14
  6. phoenix/auth.py +309 -0
  7. phoenix/config.py +675 -45
  8. phoenix/core/model.py +32 -30
  9. phoenix/core/model_schema.py +102 -109
  10. phoenix/core/model_schema_adapter.py +48 -45
  11. phoenix/datetime_utils.py +24 -3
  12. phoenix/db/README.md +54 -0
  13. phoenix/db/__init__.py +4 -0
  14. phoenix/db/alembic.ini +85 -0
  15. phoenix/db/bulk_inserter.py +294 -0
  16. phoenix/db/engines.py +208 -0
  17. phoenix/db/enums.py +20 -0
  18. phoenix/db/facilitator.py +113 -0
  19. phoenix/db/helpers.py +159 -0
  20. phoenix/db/insertion/constants.py +2 -0
  21. phoenix/db/insertion/dataset.py +227 -0
  22. phoenix/db/insertion/document_annotation.py +171 -0
  23. phoenix/db/insertion/evaluation.py +191 -0
  24. phoenix/db/insertion/helpers.py +98 -0
  25. phoenix/db/insertion/span.py +193 -0
  26. phoenix/db/insertion/span_annotation.py +158 -0
  27. phoenix/db/insertion/trace_annotation.py +158 -0
  28. phoenix/db/insertion/types.py +256 -0
  29. phoenix/db/migrate.py +86 -0
  30. phoenix/db/migrations/data_migration_scripts/populate_project_sessions.py +199 -0
  31. phoenix/db/migrations/env.py +114 -0
  32. phoenix/db/migrations/script.py.mako +26 -0
  33. phoenix/db/migrations/versions/10460e46d750_datasets.py +317 -0
  34. phoenix/db/migrations/versions/3be8647b87d8_add_token_columns_to_spans_table.py +126 -0
  35. phoenix/db/migrations/versions/4ded9e43755f_create_project_sessions_table.py +66 -0
  36. phoenix/db/migrations/versions/cd164e83824f_users_and_tokens.py +157 -0
  37. phoenix/db/migrations/versions/cf03bd6bae1d_init.py +280 -0
  38. phoenix/db/models.py +807 -0
  39. phoenix/exceptions.py +5 -1
  40. phoenix/experiments/__init__.py +6 -0
  41. phoenix/experiments/evaluators/__init__.py +29 -0
  42. phoenix/experiments/evaluators/base.py +158 -0
  43. phoenix/experiments/evaluators/code_evaluators.py +184 -0
  44. phoenix/experiments/evaluators/llm_evaluators.py +473 -0
  45. phoenix/experiments/evaluators/utils.py +236 -0
  46. phoenix/experiments/functions.py +772 -0
  47. phoenix/experiments/tracing.py +86 -0
  48. phoenix/experiments/types.py +726 -0
  49. phoenix/experiments/utils.py +25 -0
  50. phoenix/inferences/__init__.py +0 -0
  51. phoenix/{datasets → inferences}/errors.py +6 -5
  52. phoenix/{datasets → inferences}/fixtures.py +49 -42
  53. phoenix/{datasets/dataset.py → inferences/inferences.py} +121 -105
  54. phoenix/{datasets → inferences}/schema.py +11 -11
  55. phoenix/{datasets → inferences}/validation.py +13 -14
  56. phoenix/logging/__init__.py +3 -0
  57. phoenix/logging/_config.py +90 -0
  58. phoenix/logging/_filter.py +6 -0
  59. phoenix/logging/_formatter.py +69 -0
  60. phoenix/metrics/__init__.py +5 -4
  61. phoenix/metrics/binning.py +4 -3
  62. phoenix/metrics/metrics.py +2 -1
  63. phoenix/metrics/mixins.py +7 -6
  64. phoenix/metrics/retrieval_metrics.py +2 -1
  65. phoenix/metrics/timeseries.py +5 -4
  66. phoenix/metrics/wrappers.py +9 -3
  67. phoenix/pointcloud/clustering.py +5 -5
  68. phoenix/pointcloud/pointcloud.py +7 -5
  69. phoenix/pointcloud/projectors.py +5 -6
  70. phoenix/pointcloud/umap_parameters.py +53 -52
  71. phoenix/server/api/README.md +28 -0
  72. phoenix/server/api/auth.py +44 -0
  73. phoenix/server/api/context.py +152 -9
  74. phoenix/server/api/dataloaders/__init__.py +91 -0
  75. phoenix/server/api/dataloaders/annotation_summaries.py +139 -0
  76. phoenix/server/api/dataloaders/average_experiment_run_latency.py +54 -0
  77. phoenix/server/api/dataloaders/cache/__init__.py +3 -0
  78. phoenix/server/api/dataloaders/cache/two_tier_cache.py +68 -0
  79. phoenix/server/api/dataloaders/dataset_example_revisions.py +131 -0
  80. phoenix/server/api/dataloaders/dataset_example_spans.py +38 -0
  81. phoenix/server/api/dataloaders/document_evaluation_summaries.py +144 -0
  82. phoenix/server/api/dataloaders/document_evaluations.py +31 -0
  83. phoenix/server/api/dataloaders/document_retrieval_metrics.py +89 -0
  84. phoenix/server/api/dataloaders/experiment_annotation_summaries.py +79 -0
  85. phoenix/server/api/dataloaders/experiment_error_rates.py +58 -0
  86. phoenix/server/api/dataloaders/experiment_run_annotations.py +36 -0
  87. phoenix/server/api/dataloaders/experiment_run_counts.py +49 -0
  88. phoenix/server/api/dataloaders/experiment_sequence_number.py +44 -0
  89. phoenix/server/api/dataloaders/latency_ms_quantile.py +188 -0
  90. phoenix/server/api/dataloaders/min_start_or_max_end_times.py +85 -0
  91. phoenix/server/api/dataloaders/project_by_name.py +31 -0
  92. phoenix/server/api/dataloaders/record_counts.py +116 -0
  93. phoenix/server/api/dataloaders/session_io.py +79 -0
  94. phoenix/server/api/dataloaders/session_num_traces.py +30 -0
  95. phoenix/server/api/dataloaders/session_num_traces_with_error.py +32 -0
  96. phoenix/server/api/dataloaders/session_token_usages.py +41 -0
  97. phoenix/server/api/dataloaders/session_trace_latency_ms_quantile.py +55 -0
  98. phoenix/server/api/dataloaders/span_annotations.py +26 -0
  99. phoenix/server/api/dataloaders/span_dataset_examples.py +31 -0
  100. phoenix/server/api/dataloaders/span_descendants.py +57 -0
  101. phoenix/server/api/dataloaders/span_projects.py +33 -0
  102. phoenix/server/api/dataloaders/token_counts.py +124 -0
  103. phoenix/server/api/dataloaders/trace_by_trace_ids.py +25 -0
  104. phoenix/server/api/dataloaders/trace_root_spans.py +32 -0
  105. phoenix/server/api/dataloaders/user_roles.py +30 -0
  106. phoenix/server/api/dataloaders/users.py +33 -0
  107. phoenix/server/api/exceptions.py +48 -0
  108. phoenix/server/api/helpers/__init__.py +12 -0
  109. phoenix/server/api/helpers/dataset_helpers.py +217 -0
  110. phoenix/server/api/helpers/experiment_run_filters.py +763 -0
  111. phoenix/server/api/helpers/playground_clients.py +948 -0
  112. phoenix/server/api/helpers/playground_registry.py +70 -0
  113. phoenix/server/api/helpers/playground_spans.py +455 -0
  114. phoenix/server/api/input_types/AddExamplesToDatasetInput.py +16 -0
  115. phoenix/server/api/input_types/AddSpansToDatasetInput.py +14 -0
  116. phoenix/server/api/input_types/ChatCompletionInput.py +38 -0
  117. phoenix/server/api/input_types/ChatCompletionMessageInput.py +24 -0
  118. phoenix/server/api/input_types/ClearProjectInput.py +15 -0
  119. phoenix/server/api/input_types/ClusterInput.py +2 -2
  120. phoenix/server/api/input_types/CreateDatasetInput.py +12 -0
  121. phoenix/server/api/input_types/CreateSpanAnnotationInput.py +18 -0
  122. phoenix/server/api/input_types/CreateTraceAnnotationInput.py +18 -0
  123. phoenix/server/api/input_types/DataQualityMetricInput.py +5 -2
  124. phoenix/server/api/input_types/DatasetExampleInput.py +14 -0
  125. phoenix/server/api/input_types/DatasetSort.py +17 -0
  126. phoenix/server/api/input_types/DatasetVersionSort.py +16 -0
  127. phoenix/server/api/input_types/DeleteAnnotationsInput.py +7 -0
  128. phoenix/server/api/input_types/DeleteDatasetExamplesInput.py +13 -0
  129. phoenix/server/api/input_types/DeleteDatasetInput.py +7 -0
  130. phoenix/server/api/input_types/DeleteExperimentsInput.py +7 -0
  131. phoenix/server/api/input_types/DimensionFilter.py +4 -4
  132. phoenix/server/api/input_types/GenerativeModelInput.py +17 -0
  133. phoenix/server/api/input_types/Granularity.py +1 -1
  134. phoenix/server/api/input_types/InvocationParameters.py +162 -0
  135. phoenix/server/api/input_types/PatchAnnotationInput.py +19 -0
  136. phoenix/server/api/input_types/PatchDatasetExamplesInput.py +35 -0
  137. phoenix/server/api/input_types/PatchDatasetInput.py +14 -0
  138. phoenix/server/api/input_types/PerformanceMetricInput.py +5 -2
  139. phoenix/server/api/input_types/ProjectSessionSort.py +29 -0
  140. phoenix/server/api/input_types/SpanAnnotationSort.py +17 -0
  141. phoenix/server/api/input_types/SpanSort.py +134 -69
  142. phoenix/server/api/input_types/TemplateOptions.py +10 -0
  143. phoenix/server/api/input_types/TraceAnnotationSort.py +17 -0
  144. phoenix/server/api/input_types/UserRoleInput.py +9 -0
  145. phoenix/server/api/mutations/__init__.py +28 -0
  146. phoenix/server/api/mutations/api_key_mutations.py +167 -0
  147. phoenix/server/api/mutations/chat_mutations.py +593 -0
  148. phoenix/server/api/mutations/dataset_mutations.py +591 -0
  149. phoenix/server/api/mutations/experiment_mutations.py +75 -0
  150. phoenix/server/api/{types/ExportEventsMutation.py → mutations/export_events_mutations.py} +21 -18
  151. phoenix/server/api/mutations/project_mutations.py +57 -0
  152. phoenix/server/api/mutations/span_annotations_mutations.py +128 -0
  153. phoenix/server/api/mutations/trace_annotations_mutations.py +127 -0
  154. phoenix/server/api/mutations/user_mutations.py +329 -0
  155. phoenix/server/api/openapi/__init__.py +0 -0
  156. phoenix/server/api/openapi/main.py +17 -0
  157. phoenix/server/api/openapi/schema.py +16 -0
  158. phoenix/server/api/queries.py +738 -0
  159. phoenix/server/api/routers/__init__.py +11 -0
  160. phoenix/server/api/routers/auth.py +284 -0
  161. phoenix/server/api/routers/embeddings.py +26 -0
  162. phoenix/server/api/routers/oauth2.py +488 -0
  163. phoenix/server/api/routers/v1/__init__.py +64 -0
  164. phoenix/server/api/routers/v1/datasets.py +1017 -0
  165. phoenix/server/api/routers/v1/evaluations.py +362 -0
  166. phoenix/server/api/routers/v1/experiment_evaluations.py +115 -0
  167. phoenix/server/api/routers/v1/experiment_runs.py +167 -0
  168. phoenix/server/api/routers/v1/experiments.py +308 -0
  169. phoenix/server/api/routers/v1/pydantic_compat.py +78 -0
  170. phoenix/server/api/routers/v1/spans.py +267 -0
  171. phoenix/server/api/routers/v1/traces.py +208 -0
  172. phoenix/server/api/routers/v1/utils.py +95 -0
  173. phoenix/server/api/schema.py +44 -241
  174. phoenix/server/api/subscriptions.py +597 -0
  175. phoenix/server/api/types/Annotation.py +21 -0
  176. phoenix/server/api/types/AnnotationSummary.py +55 -0
  177. phoenix/server/api/types/AnnotatorKind.py +16 -0
  178. phoenix/server/api/types/ApiKey.py +27 -0
  179. phoenix/server/api/types/AuthMethod.py +9 -0
  180. phoenix/server/api/types/ChatCompletionMessageRole.py +11 -0
  181. phoenix/server/api/types/ChatCompletionSubscriptionPayload.py +46 -0
  182. phoenix/server/api/types/Cluster.py +25 -24
  183. phoenix/server/api/types/CreateDatasetPayload.py +8 -0
  184. phoenix/server/api/types/DataQualityMetric.py +31 -13
  185. phoenix/server/api/types/Dataset.py +288 -63
  186. phoenix/server/api/types/DatasetExample.py +85 -0
  187. phoenix/server/api/types/DatasetExampleRevision.py +34 -0
  188. phoenix/server/api/types/DatasetVersion.py +14 -0
  189. phoenix/server/api/types/Dimension.py +32 -31
  190. phoenix/server/api/types/DocumentEvaluationSummary.py +9 -8
  191. phoenix/server/api/types/EmbeddingDimension.py +56 -49
  192. phoenix/server/api/types/Evaluation.py +25 -31
  193. phoenix/server/api/types/EvaluationSummary.py +30 -50
  194. phoenix/server/api/types/Event.py +20 -20
  195. phoenix/server/api/types/ExampleRevisionInterface.py +14 -0
  196. phoenix/server/api/types/Experiment.py +152 -0
  197. phoenix/server/api/types/ExperimentAnnotationSummary.py +13 -0
  198. phoenix/server/api/types/ExperimentComparison.py +17 -0
  199. phoenix/server/api/types/ExperimentRun.py +119 -0
  200. phoenix/server/api/types/ExperimentRunAnnotation.py +56 -0
  201. phoenix/server/api/types/GenerativeModel.py +9 -0
  202. phoenix/server/api/types/GenerativeProvider.py +85 -0
  203. phoenix/server/api/types/Inferences.py +80 -0
  204. phoenix/server/api/types/InferencesRole.py +23 -0
  205. phoenix/server/api/types/LabelFraction.py +7 -0
  206. phoenix/server/api/types/MimeType.py +2 -2
  207. phoenix/server/api/types/Model.py +54 -54
  208. phoenix/server/api/types/PerformanceMetric.py +8 -5
  209. phoenix/server/api/types/Project.py +407 -142
  210. phoenix/server/api/types/ProjectSession.py +139 -0
  211. phoenix/server/api/types/Segments.py +4 -4
  212. phoenix/server/api/types/Span.py +221 -176
  213. phoenix/server/api/types/SpanAnnotation.py +43 -0
  214. phoenix/server/api/types/SpanIOValue.py +15 -0
  215. phoenix/server/api/types/SystemApiKey.py +9 -0
  216. phoenix/server/api/types/TemplateLanguage.py +10 -0
  217. phoenix/server/api/types/TimeSeries.py +19 -15
  218. phoenix/server/api/types/TokenUsage.py +11 -0
  219. phoenix/server/api/types/Trace.py +154 -0
  220. phoenix/server/api/types/TraceAnnotation.py +45 -0
  221. phoenix/server/api/types/UMAPPoints.py +7 -7
  222. phoenix/server/api/types/User.py +60 -0
  223. phoenix/server/api/types/UserApiKey.py +45 -0
  224. phoenix/server/api/types/UserRole.py +15 -0
  225. phoenix/server/api/types/node.py +4 -112
  226. phoenix/server/api/types/pagination.py +156 -57
  227. phoenix/server/api/utils.py +34 -0
  228. phoenix/server/app.py +864 -115
  229. phoenix/server/bearer_auth.py +163 -0
  230. phoenix/server/dml_event.py +136 -0
  231. phoenix/server/dml_event_handler.py +256 -0
  232. phoenix/server/email/__init__.py +0 -0
  233. phoenix/server/email/sender.py +97 -0
  234. phoenix/server/email/templates/__init__.py +0 -0
  235. phoenix/server/email/templates/password_reset.html +19 -0
  236. phoenix/server/email/types.py +11 -0
  237. phoenix/server/grpc_server.py +102 -0
  238. phoenix/server/jwt_store.py +505 -0
  239. phoenix/server/main.py +305 -116
  240. phoenix/server/oauth2.py +52 -0
  241. phoenix/server/openapi/__init__.py +0 -0
  242. phoenix/server/prometheus.py +111 -0
  243. phoenix/server/rate_limiters.py +188 -0
  244. phoenix/server/static/.vite/manifest.json +87 -0
  245. phoenix/server/static/assets/components-Cy9nwIvF.js +2125 -0
  246. phoenix/server/static/assets/index-BKvHIxkk.js +113 -0
  247. phoenix/server/static/assets/pages-CUi2xCVQ.js +4449 -0
  248. phoenix/server/static/assets/vendor-DvC8cT4X.js +894 -0
  249. phoenix/server/static/assets/vendor-DxkFTwjz.css +1 -0
  250. phoenix/server/static/assets/vendor-arizeai-Do1793cv.js +662 -0
  251. phoenix/server/static/assets/vendor-codemirror-BzwZPyJM.js +24 -0
  252. phoenix/server/static/assets/vendor-recharts-_Jb7JjhG.js +59 -0
  253. phoenix/server/static/assets/vendor-shiki-Cl9QBraO.js +5 -0
  254. phoenix/server/static/assets/vendor-three-DwGkEfCM.js +2998 -0
  255. phoenix/server/telemetry.py +68 -0
  256. phoenix/server/templates/index.html +82 -23
  257. phoenix/server/thread_server.py +3 -3
  258. phoenix/server/types.py +275 -0
  259. phoenix/services.py +27 -18
  260. phoenix/session/client.py +743 -68
  261. phoenix/session/data_extractor.py +31 -7
  262. phoenix/session/evaluation.py +3 -9
  263. phoenix/session/session.py +263 -219
  264. phoenix/settings.py +22 -0
  265. phoenix/trace/__init__.py +2 -22
  266. phoenix/trace/attributes.py +338 -0
  267. phoenix/trace/dsl/README.md +116 -0
  268. phoenix/trace/dsl/filter.py +663 -213
  269. phoenix/trace/dsl/helpers.py +73 -21
  270. phoenix/trace/dsl/query.py +574 -201
  271. phoenix/trace/exporter.py +24 -19
  272. phoenix/trace/fixtures.py +368 -32
  273. phoenix/trace/otel.py +71 -219
  274. phoenix/trace/projects.py +3 -2
  275. phoenix/trace/schemas.py +33 -11
  276. phoenix/trace/span_evaluations.py +21 -16
  277. phoenix/trace/span_json_decoder.py +6 -4
  278. phoenix/trace/span_json_encoder.py +2 -2
  279. phoenix/trace/trace_dataset.py +47 -32
  280. phoenix/trace/utils.py +21 -4
  281. phoenix/utilities/__init__.py +0 -26
  282. phoenix/utilities/client.py +132 -0
  283. phoenix/utilities/deprecation.py +31 -0
  284. phoenix/utilities/error_handling.py +3 -2
  285. phoenix/utilities/json.py +109 -0
  286. phoenix/utilities/logging.py +8 -0
  287. phoenix/utilities/project.py +2 -2
  288. phoenix/utilities/re.py +49 -0
  289. phoenix/utilities/span_store.py +0 -23
  290. phoenix/utilities/template_formatters.py +99 -0
  291. phoenix/version.py +1 -1
  292. arize_phoenix-3.16.1.dist-info/METADATA +0 -495
  293. arize_phoenix-3.16.1.dist-info/RECORD +0 -178
  294. phoenix/core/project.py +0 -619
  295. phoenix/core/traces.py +0 -96
  296. phoenix/experimental/evals/__init__.py +0 -73
  297. phoenix/experimental/evals/evaluators.py +0 -413
  298. phoenix/experimental/evals/functions/__init__.py +0 -4
  299. phoenix/experimental/evals/functions/classify.py +0 -453
  300. phoenix/experimental/evals/functions/executor.py +0 -353
  301. phoenix/experimental/evals/functions/generate.py +0 -138
  302. phoenix/experimental/evals/functions/processing.py +0 -76
  303. phoenix/experimental/evals/models/__init__.py +0 -14
  304. phoenix/experimental/evals/models/anthropic.py +0 -175
  305. phoenix/experimental/evals/models/base.py +0 -170
  306. phoenix/experimental/evals/models/bedrock.py +0 -221
  307. phoenix/experimental/evals/models/litellm.py +0 -134
  308. phoenix/experimental/evals/models/openai.py +0 -448
  309. phoenix/experimental/evals/models/rate_limiters.py +0 -246
  310. phoenix/experimental/evals/models/vertex.py +0 -173
  311. phoenix/experimental/evals/models/vertexai.py +0 -186
  312. phoenix/experimental/evals/retrievals.py +0 -96
  313. phoenix/experimental/evals/templates/__init__.py +0 -50
  314. phoenix/experimental/evals/templates/default_templates.py +0 -472
  315. phoenix/experimental/evals/templates/template.py +0 -195
  316. phoenix/experimental/evals/utils/__init__.py +0 -172
  317. phoenix/experimental/evals/utils/threads.py +0 -27
  318. phoenix/server/api/helpers.py +0 -11
  319. phoenix/server/api/routers/evaluation_handler.py +0 -109
  320. phoenix/server/api/routers/span_handler.py +0 -70
  321. phoenix/server/api/routers/trace_handler.py +0 -60
  322. phoenix/server/api/types/DatasetRole.py +0 -23
  323. phoenix/server/static/index.css +0 -6
  324. phoenix/server/static/index.js +0 -7447
  325. phoenix/storage/span_store/__init__.py +0 -23
  326. phoenix/storage/span_store/text_file.py +0 -85
  327. phoenix/trace/dsl/missing.py +0 -60
  328. phoenix/trace/langchain/__init__.py +0 -3
  329. phoenix/trace/langchain/instrumentor.py +0 -35
  330. phoenix/trace/llama_index/__init__.py +0 -3
  331. phoenix/trace/llama_index/callback.py +0 -102
  332. phoenix/trace/openai/__init__.py +0 -3
  333. phoenix/trace/openai/instrumentor.py +0 -30
  334. {arize_phoenix-3.16.1.dist-info → arize_phoenix-7.7.1.dist-info}/licenses/IP_NOTICE +0 -0
  335. {arize_phoenix-3.16.1.dist-info → arize_phoenix-7.7.1.dist-info}/licenses/LICENSE +0 -0
  336. /phoenix/{datasets → db/insertion}/__init__.py +0 -0
  337. /phoenix/{experimental → db/migrations}/__init__.py +0 -0
  338. /phoenix/{storage → db/migrations/data_migration_scripts}/__init__.py +0 -0
@@ -1,26 +1,19 @@
1
1
  import json
2
2
  import logging
3
3
  import os
4
+ import shutil
4
5
  import warnings
5
6
  from abc import ABC, abstractmethod
6
7
  from collections import UserList
8
+ from collections.abc import Iterable, Mapping
7
9
  from datetime import datetime
8
10
  from enum import Enum
9
11
  from importlib.util import find_spec
12
+ from itertools import chain
10
13
  from pathlib import Path
11
14
  from tempfile import TemporaryDirectory
12
- from threading import Thread
13
- from typing import (
14
- TYPE_CHECKING,
15
- Any,
16
- Iterable,
17
- List,
18
- Mapping,
19
- NamedTuple,
20
- Optional,
21
- Set,
22
- Union,
23
- )
15
+ from typing import TYPE_CHECKING, Any, NamedTuple, Optional, Union
16
+ from urllib.parse import urljoin
24
17
 
25
18
  import pandas as pd
26
19
 
@@ -29,26 +22,32 @@ from phoenix.config import (
29
22
  ENV_PHOENIX_COLLECTOR_ENDPOINT,
30
23
  ENV_PHOENIX_HOST,
31
24
  ENV_PHOENIX_PORT,
25
+ ensure_working_dir,
26
+ get_env_database_connection_str,
27
+ get_env_enable_websockets,
32
28
  get_env_host,
33
29
  get_env_port,
34
- get_env_project_name,
35
30
  get_exported_files,
31
+ get_working_dir,
36
32
  )
37
- from phoenix.core.model_schema_adapter import create_model_from_datasets
38
- from phoenix.core.traces import Traces
39
- from phoenix.datasets.dataset import EMPTY_DATASET, Dataset
33
+ from phoenix.core.model_schema_adapter import create_model_from_inferences
34
+ from phoenix.inferences.inferences import EMPTY_INFERENCES, Inferences
40
35
  from phoenix.pointcloud.umap_parameters import get_umap_parameters
41
- from phoenix.server.app import create_app
36
+ from phoenix.server.app import (
37
+ _db,
38
+ create_app,
39
+ create_engine_and_run_migrations,
40
+ instrument_engine_if_enabled,
41
+ )
42
42
  from phoenix.server.thread_server import ThreadServer
43
+ from phoenix.server.types import DbSessionFactory
43
44
  from phoenix.services import AppService
44
45
  from phoenix.session.client import Client
45
- from phoenix.session.data_extractor import TraceDataExtractor
46
+ from phoenix.session.data_extractor import DEFAULT_SPAN_LIMIT, TraceDataExtractor
46
47
  from phoenix.session.evaluation import encode_evaluations
47
48
  from phoenix.trace import Evaluations
48
49
  from phoenix.trace.dsl.query import SpanQuery
49
50
  from phoenix.trace.trace_dataset import TraceDataset
50
- from phoenix.utilities import query_spans
51
- from phoenix.utilities.span_store import get_span_store, load_traces_data_from_store
52
51
 
53
52
  try:
54
53
  from IPython.display import IFrame # type: ignore
@@ -64,6 +63,13 @@ if TYPE_CHECKING:
64
63
  else:
65
64
  _BaseList = UserList
66
65
 
66
+ # Temporary directory for the duration of the session
67
+ global _session_working_dir
68
+ _session_working_dir: Optional["TemporaryDirectory[str]"] = None
69
+
70
+
71
+ DEFAULT_TIMEOUT_IN_SECONDS = 5
72
+
67
73
 
68
74
  class NotebookEnvironment(Enum):
69
75
  COLAB = "colab"
@@ -74,8 +80,8 @@ class NotebookEnvironment(Enum):
74
80
 
75
81
  class ExportedData(_BaseList):
76
82
  def __init__(self) -> None:
77
- self.paths: Set[Path] = set()
78
- self.names: List[str] = []
83
+ self.paths: set[Path] = set()
84
+ self.names: list[str] = []
79
85
  super().__init__()
80
86
 
81
87
  def __repr__(self) -> str:
@@ -95,50 +101,30 @@ class Session(TraceDataExtractor, ABC):
95
101
  """Session that maintains a 1-1 shared state with the Phoenix App."""
96
102
 
97
103
  trace_dataset: Optional[TraceDataset]
98
- traces: Optional[Traces]
99
104
  notebook_env: NotebookEnvironment
100
105
  """The notebook environment that the session is running in."""
101
106
 
102
- def __dir__(self) -> List[str]:
107
+ def __dir__(self) -> list[str]:
103
108
  return ["exports", "view", "url"]
104
109
 
105
110
  def __init__(
106
111
  self,
107
- primary_dataset: Dataset,
108
- reference_dataset: Optional[Dataset] = None,
109
- corpus_dataset: Optional[Dataset] = None,
112
+ database_url: str,
113
+ primary_inferences: Inferences,
114
+ reference_inferences: Optional[Inferences] = None,
115
+ corpus_inferences: Optional[Inferences] = None,
110
116
  trace_dataset: Optional[TraceDataset] = None,
111
117
  default_umap_parameters: Optional[Mapping[str, Any]] = None,
112
118
  host: Optional[str] = None,
113
119
  port: Optional[int] = None,
114
120
  notebook_env: Optional[NotebookEnvironment] = None,
115
121
  ):
116
- self.primary_dataset = primary_dataset
117
- self.reference_dataset = reference_dataset
118
- self.corpus_dataset = corpus_dataset
122
+ self._database_url = database_url
123
+ self.primary_inferences = primary_inferences
124
+ self.reference_inferences = reference_inferences
125
+ self.corpus_inferences = corpus_inferences
119
126
  self.trace_dataset = trace_dataset
120
127
  self.umap_parameters = get_umap_parameters(default_umap_parameters)
121
- self.model = create_model_from_datasets(
122
- primary_dataset,
123
- reference_dataset,
124
- )
125
-
126
- self.corpus = (
127
- create_model_from_datasets(
128
- corpus_dataset,
129
- )
130
- if corpus_dataset is not None
131
- else None
132
- )
133
-
134
- self.traces = Traces()
135
- if trace_dataset:
136
- for span in trace_dataset.to_spans():
137
- self.traces.put(span)
138
- for evaluations in trace_dataset.evaluations:
139
- for pb_evaluation in encode_evaluations(evaluations):
140
- self.traces.put(pb_evaluation)
141
-
142
128
  self.host = host or get_env_host()
143
129
  self.port = port or get_env_port()
144
130
  self.temp_dir = TemporaryDirectory()
@@ -147,6 +133,88 @@ class Session(TraceDataExtractor, ABC):
147
133
  self.exported_data = ExportedData()
148
134
  self.notebook_env = notebook_env or _get_notebook_environment()
149
135
  self.root_path = _get_root_path(self.notebook_env, self.port)
136
+ host = "127.0.0.1" if self.host == "0.0.0.0" else self.host
137
+ self._client = Client(
138
+ endpoint=f"http://{host}:{self.port}", warn_if_server_not_running=False
139
+ )
140
+
141
+ def query_spans(
142
+ self,
143
+ *queries: SpanQuery,
144
+ start_time: Optional[datetime] = None,
145
+ end_time: Optional[datetime] = None,
146
+ limit: Optional[int] = DEFAULT_SPAN_LIMIT,
147
+ root_spans_only: Optional[bool] = None,
148
+ project_name: Optional[str] = None,
149
+ # Deprecated fields
150
+ stop_time: Optional[datetime] = None,
151
+ timeout: Optional[int] = DEFAULT_TIMEOUT_IN_SECONDS,
152
+ ) -> Optional[Union[pd.DataFrame, list[pd.DataFrame]]]:
153
+ """
154
+ Queries the spans in the project based on the provided parameters.
155
+
156
+ Parameters
157
+ ----------
158
+ queries : *SpanQuery
159
+ Variable-length argument list of SpanQuery objects representing
160
+ the queries to be executed.
161
+
162
+ start_time : datetime, optional
163
+ datetime representing the start time of the query.
164
+
165
+ end_time : datetime, optional
166
+ datetime representing the end time of the query.
167
+
168
+ root_spans_only : boolean, optional
169
+ whether to include only root spans in the results.
170
+
171
+ project_name : string, optional
172
+ name of the project to query. Defaults to the project name set
173
+ in the environment variable `PHOENIX_PROJECT_NAME` or 'default' if not set.
174
+
175
+ Returns:
176
+ results : DataFrame
177
+ DataFrame or list of DataFrames containing the query results.
178
+ """
179
+ if stop_time is not None:
180
+ warnings.warn(
181
+ "The `stop_time` parameter is deprecated and will be removed in a future release. "
182
+ "Please use `end_time` instead.",
183
+ DeprecationWarning,
184
+ )
185
+ end_time = stop_time
186
+ return self._client.query_spans(
187
+ *queries,
188
+ start_time=start_time,
189
+ end_time=end_time,
190
+ limit=limit,
191
+ root_spans_only=root_spans_only,
192
+ project_name=project_name,
193
+ )
194
+
195
+ def get_evaluations(
196
+ self,
197
+ project_name: Optional[str] = None,
198
+ ) -> list[Evaluations]:
199
+ """
200
+ Get the evaluations for a project.
201
+
202
+ Parameters
203
+ ----------
204
+ project_name : str, optional
205
+ The name of the project. If not provided, the project name set
206
+ in the environment variable `PHOENIX_PROJECT_NAME` will be used.
207
+ Otherwise, 'default' will be used.
208
+
209
+ Returns
210
+ -------
211
+ evaluations : list[Evaluations]
212
+ A list of evaluations for the specified project.
213
+
214
+ """
215
+ return self._client.get_evaluations(
216
+ project_name=project_name,
217
+ )
150
218
 
151
219
  @abstractmethod
152
220
  def end(self) -> None:
@@ -170,23 +238,29 @@ class Session(TraceDataExtractor, ABC):
170
238
  self.exported_data.add(files)
171
239
  return self.exported_data
172
240
 
173
- def view(self, height: int = 1000) -> "IFrame":
174
- """
175
- Returns an IFrame that can be displayed in a notebook to view the app.
241
+ def view(self, *, height: int = 1000, slug: str = "") -> "IFrame":
242
+ """View the session in a notebook embedded iFrame.
176
243
 
177
- Parameters
178
- ----------
179
- height : int, optional
180
- The height of the IFrame in pixels. Defaults to 1000.
244
+ Args:
245
+ slug (str, optional): the path of the app to view
246
+ height (int, optional): the height of the iFrame in px. Defaults to 1000.
247
+
248
+ Returns:
249
+ IFrame: the iFrame will be rendered in the notebook
181
250
  """
251
+ url_to_view = urljoin(self.url, slug)
182
252
  print(f"📺 Opening a view to the Phoenix app. The app is running at {self.url}")
183
- return IFrame(src=self.url, width="100%", height=height)
253
+ return IFrame(src=url_to_view, width="100%", height=height)
184
254
 
185
255
  @property
186
256
  def url(self) -> str:
187
257
  """Returns the url for the phoenix app"""
188
258
  return _get_url(self.host, self.port, self.notebook_env)
189
259
 
260
+ @property
261
+ def database_url(self) -> str:
262
+ return self._database_url
263
+
190
264
 
191
265
  _session: Optional[Session] = None
192
266
 
@@ -194,9 +268,11 @@ _session: Optional[Session] = None
194
268
  class ProcessSession(Session):
195
269
  def __init__(
196
270
  self,
197
- primary_dataset: Dataset,
198
- reference_dataset: Optional[Dataset] = None,
199
- corpus_dataset: Optional[Dataset] = None,
271
+ database_url: str,
272
+ primary_inferences: Inferences,
273
+ enable_websockets: bool,
274
+ reference_inferences: Optional[Inferences] = None,
275
+ corpus_inferences: Optional[Inferences] = None,
200
276
  trace_dataset: Optional[TraceDataset] = None,
201
277
  default_umap_parameters: Optional[Mapping[str, Any]] = None,
202
278
  host: Optional[str] = None,
@@ -205,20 +281,21 @@ class ProcessSession(Session):
205
281
  notebook_env: Optional[NotebookEnvironment] = None,
206
282
  ) -> None:
207
283
  super().__init__(
208
- primary_dataset=primary_dataset,
209
- reference_dataset=reference_dataset,
210
- corpus_dataset=corpus_dataset,
284
+ database_url=database_url,
285
+ primary_inferences=primary_inferences,
286
+ reference_inferences=reference_inferences,
287
+ corpus_inferences=corpus_inferences,
211
288
  trace_dataset=trace_dataset,
212
289
  default_umap_parameters=default_umap_parameters,
213
290
  host=host,
214
291
  port=port,
215
292
  notebook_env=notebook_env,
216
293
  )
217
- primary_dataset.to_disc()
218
- if isinstance(reference_dataset, Dataset):
219
- reference_dataset.to_disc()
220
- if isinstance(corpus_dataset, Dataset):
221
- corpus_dataset.to_disc()
294
+ primary_inferences.to_disc()
295
+ if isinstance(reference_inferences, Inferences):
296
+ reference_inferences.to_disc()
297
+ if isinstance(corpus_inferences, Inferences):
298
+ corpus_inferences.to_disc()
222
299
  if isinstance(trace_dataset, TraceDataset):
223
300
  trace_dataset.to_disc()
224
301
  umap_params_str = (
@@ -228,26 +305,23 @@ class ProcessSession(Session):
228
305
  )
229
306
  # Initialize an app service that keeps the server running
230
307
  self.app_service = AppService(
231
- self.export_path,
232
- self.host,
233
- self.port,
234
- self.root_path,
235
- self.primary_dataset.name,
236
- umap_params_str,
237
- reference_dataset_name=(
238
- self.reference_dataset.name if self.reference_dataset is not None else None
308
+ database_url=database_url,
309
+ export_path=self.export_path,
310
+ host=self.host,
311
+ port=self.port,
312
+ root_path=self.root_path,
313
+ primary_inferences_name=self.primary_inferences.name,
314
+ umap_params=umap_params_str,
315
+ reference_inferences_name=(
316
+ self.reference_inferences.name if self.reference_inferences is not None else None
239
317
  ),
240
- corpus_dataset_name=(
241
- self.corpus_dataset.name if self.corpus_dataset is not None else None
318
+ corpus_inferences_name=(
319
+ self.corpus_inferences.name if self.corpus_inferences is not None else None
242
320
  ),
243
321
  trace_dataset_name=(
244
322
  self.trace_dataset.name if self.trace_dataset is not None else None
245
323
  ),
246
- )
247
- host = "127.0.0.1" if self.host == "0.0.0.0" else self.host
248
- self._client = Client(
249
- endpoint=f"http://{host}:{self.port}",
250
- use_active_session_if_available=False,
324
+ enable_websockets=enable_websockets,
251
325
  )
252
326
 
253
327
  @property
@@ -258,35 +332,15 @@ class ProcessSession(Session):
258
332
  self.app_service.stop()
259
333
  self.temp_dir.cleanup()
260
334
 
261
- def query_spans(
262
- self,
263
- *queries: SpanQuery,
264
- start_time: Optional[datetime] = None,
265
- stop_time: Optional[datetime] = None,
266
- root_spans_only: Optional[bool] = None,
267
- project_name: Optional[str] = None,
268
- ) -> Optional[Union[pd.DataFrame, List[pd.DataFrame]]]:
269
- return self._client.query_spans(
270
- *queries,
271
- start_time=start_time,
272
- stop_time=stop_time,
273
- root_spans_only=root_spans_only,
274
- project_name=project_name,
275
- )
276
-
277
- def get_evaluations(
278
- self,
279
- project_name: Optional[str] = None,
280
- ) -> List[Evaluations]:
281
- return self._client.get_evaluations()
282
-
283
335
 
284
336
  class ThreadSession(Session):
285
337
  def __init__(
286
338
  self,
287
- primary_dataset: Dataset,
288
- reference_dataset: Optional[Dataset] = None,
289
- corpus_dataset: Optional[Dataset] = None,
339
+ database_url: str,
340
+ primary_inferences: Inferences,
341
+ enable_websockets: bool,
342
+ reference_inferences: Optional[Inferences] = None,
343
+ corpus_inferences: Optional[Inferences] = None,
290
344
  trace_dataset: Optional[TraceDataset] = None,
291
345
  default_umap_parameters: Optional[Mapping[str, Any]] = None,
292
346
  host: Optional[str] = None,
@@ -295,29 +349,46 @@ class ThreadSession(Session):
295
349
  notebook_env: Optional[NotebookEnvironment] = None,
296
350
  ):
297
351
  super().__init__(
298
- primary_dataset=primary_dataset,
299
- reference_dataset=reference_dataset,
300
- corpus_dataset=corpus_dataset,
352
+ database_url=database_url,
353
+ primary_inferences=primary_inferences,
354
+ reference_inferences=reference_inferences,
355
+ corpus_inferences=corpus_inferences,
301
356
  trace_dataset=trace_dataset,
302
357
  default_umap_parameters=default_umap_parameters,
303
358
  host=host,
304
359
  port=port,
305
360
  notebook_env=notebook_env,
306
361
  )
307
- if span_store := get_span_store():
308
- Thread(
309
- target=load_traces_data_from_store,
310
- args=(self.traces, span_store),
311
- daemon=True,
312
- ).start()
362
+ self.model = create_model_from_inferences(
363
+ primary_inferences,
364
+ reference_inferences,
365
+ )
366
+ self.corpus = (
367
+ create_model_from_inferences(
368
+ corpus_inferences,
369
+ )
370
+ if corpus_inferences is not None
371
+ else None
372
+ )
313
373
  # Initialize an app service that keeps the server running
374
+ engine = create_engine_and_run_migrations(database_url)
375
+ instrumentation_cleanups = instrument_engine_if_enabled(engine)
376
+ factory = DbSessionFactory(db=_db(engine), dialect=engine.dialect.name)
314
377
  self.app = create_app(
378
+ db=factory,
315
379
  export_path=self.export_path,
316
380
  model=self.model,
381
+ authentication_enabled=False,
382
+ enable_websockets=enable_websockets,
317
383
  corpus=self.corpus,
318
- traces=self.traces,
319
384
  umap_params=self.umap_parameters,
320
- span_store=span_store,
385
+ initial_spans=trace_dataset.to_spans() if trace_dataset else None,
386
+ initial_evaluations=(
387
+ chain.from_iterable(map(encode_evaluations, initial_evaluations))
388
+ if (trace_dataset and (initial_evaluations := trace_dataset.evaluations))
389
+ else None
390
+ ),
391
+ shutdown_callbacks=instrumentation_cleanups,
321
392
  )
322
393
  self.server = ThreadServer(
323
394
  app=self.app,
@@ -336,103 +407,43 @@ class ThreadSession(Session):
336
407
  self.server.close()
337
408
  self.temp_dir.cleanup()
338
409
 
339
- def query_spans(
340
- self,
341
- *queries: SpanQuery,
342
- start_time: Optional[datetime] = None,
343
- stop_time: Optional[datetime] = None,
344
- root_spans_only: Optional[bool] = None,
345
- project_name: Optional[str] = None,
346
- ) -> Optional[Union[pd.DataFrame, List[pd.DataFrame]]]:
347
- """
348
- Queries the spans in the project based on the provided parameters.
349
-
350
- Parameters
351
- ----------
352
- queries : *SpanQuery
353
- Variable-length argument list of SpanQuery objects representing
354
- the queries to be executed.
355
-
356
- start_time : datetime, optional
357
- datetime representing the start time of the query.
358
-
359
- stop_time : datetime, optional
360
- datetime representing the stop time of the query.
361
410
 
362
- root_spans_only : boolean, optional
363
- whether to include only root spans in the results.
364
-
365
- project_name : string, optional
366
- name of the project to query. Defaults to the project name set
367
- in the environment variable `PHOENIX_PROJECT_NAME` or 'default' if not set.
368
-
369
- Returns:
370
- results : DataFrame
371
- DataFrame or list of DataFrames containing the query results.
372
- """
373
- if not (traces := self.traces) or not (
374
- project := traces.get_project(project_name or get_env_project_name())
375
- ):
376
- return None
377
- if not queries:
378
- queries = (SpanQuery(),)
379
- valid_eval_names = project.get_span_evaluation_names() if project else ()
380
- queries = tuple(
381
- SpanQuery.from_dict(
382
- query.to_dict(),
383
- evals=project,
384
- valid_eval_names=valid_eval_names,
411
+ def delete_all(prompt_before_delete: Optional[bool] = True) -> None:
412
+ """
413
+ Deletes the entire contents of the working directory. This will delete, traces, evaluations,
414
+ and any other data stored in the working directory.
415
+ """
416
+ global _session_working_dir
417
+ working_dir = get_working_dir()
418
+ directories_to_delete = []
419
+ if working_dir.exists():
420
+ directories_to_delete.append(working_dir)
421
+ if _session_working_dir is not None:
422
+ directories_to_delete.append(Path(_session_working_dir.name))
423
+
424
+ # Loop through directories to delete
425
+ for directory in directories_to_delete:
426
+ if prompt_before_delete:
427
+ input(
428
+ f"You have data at {directory}. Are you sure you want to delete?"
429
+ + " This cannot be undone. Press Enter to delete, Escape to cancel."
385
430
  )
386
- for query in queries
387
- )
388
- results = query_spans(
389
- project,
390
- *queries,
391
- start_time=start_time,
392
- stop_time=stop_time,
393
- root_spans_only=root_spans_only,
394
- )
395
- if len(results) == 1:
396
- df = results[0]
397
- return None if df.shape == (0, 0) else df
398
- return results
399
-
400
- def get_evaluations(
401
- self,
402
- project_name: Optional[str] = None,
403
- ) -> List[Evaluations]:
404
- """
405
- Get the evaluations for a project.
406
-
407
- Parameters
408
- ----------
409
- project_name : str, optional
410
- The name of the project. If not provided, the project name set
411
- in the environment variable `PHOENIX_PROJECT_NAME` will be used.
412
- Otherwise, 'default' will be used.
413
-
414
- Returns
415
- -------
416
- evaluations : List[Evaluations]
417
- A list of evaluations for the specified project.
418
-
419
- """
420
- project_name = project_name or get_env_project_name()
421
- if not (traces := self.traces) or not (project := traces.get_project(project_name)):
422
- return []
423
- return project.export_evaluations()
431
+ shutil.rmtree(directory)
432
+ _session_working_dir = None
424
433
 
425
434
 
426
435
  def launch_app(
427
- primary: Optional[Dataset] = None,
428
- reference: Optional[Dataset] = None,
429
- corpus: Optional[Dataset] = None,
436
+ primary: Optional[Inferences] = None,
437
+ reference: Optional[Inferences] = None,
438
+ corpus: Optional[Inferences] = None,
430
439
  trace: Optional[TraceDataset] = None,
431
440
  default_umap_parameters: Optional[Mapping[str, Any]] = None,
432
441
  host: Optional[str] = None,
433
442
  port: Optional[int] = None,
434
443
  run_in_thread: bool = True,
435
444
  notebook_environment: Optional[Union[NotebookEnvironment, str]] = None,
445
+ use_temp_dir: bool = True,
446
+ enable_websockets: Optional[bool] = None,
436
447
  ) -> Optional[Session]:
437
448
  """
438
449
  Launches the phoenix application and returns a session to interact with.
@@ -447,7 +458,7 @@ def launch_app(
447
458
  corpus : Dataset, optional
448
459
  The dataset containing corpus for LLM context retrieval.
449
460
  trace: TraceDataset, optional
450
- **Experimental** The trace dataset containing the trace data.
461
+ The trace dataset containing the trace data.
451
462
  host: str, optional
452
463
  The host on which the server runs. It can also be set using environment
453
464
  variable `PHOENIX_HOST`, otherwise it defaults to `127.0.0.1`.
@@ -457,13 +468,18 @@ def launch_app(
457
468
  Defaults to 6006.
458
469
  run_in_thread: bool, optional, default=True
459
470
  Whether the server should run in a Thread or Process.
460
- default_umap_parameters: Dict[str, Union[int, float]], optional, default=None
471
+ default_umap_parameters: dict[str, Union[int, float]], optional, default=None
461
472
  User specified default UMAP parameters
462
473
  eg: {"n_neighbors": 10, "n_samples": 5, "min_dist": 0.5}
463
474
  notebook_environment: str, optional, default=None
464
475
  The environment the notebook is running in. This is either 'local', 'colab', or 'sagemaker'.
465
476
  If not provided, phoenix will try to infer the environment. This is only needed if
466
477
  there is a failure to infer the environment.
478
+ use_temp_dir: bool, optional, default=True
479
+ Whether to use a temporary directory to store the data. If set to False, the data will be
480
+ stored in the directory specified by PHOENIX_WORKING_DIR environment variable via SQLite.
481
+ enable_websockets: bool, optional, default=False
482
+ Whether to enable websockets.
467
483
 
468
484
  Returns
469
485
  -------
@@ -473,17 +489,21 @@ def launch_app(
473
489
  Examples
474
490
  --------
475
491
  >>> import phoenix as px
476
- >>> # construct a dataset to analyze
477
- >>> dataset = px.Dataset(...)
478
- >>> session = px.launch_app(dataset)
492
+ >>> # construct an inference set to analyze
493
+ >>> inferences = px.Inferences(...)
494
+ >>> session = px.launch_app(inferences)
479
495
  """
480
496
  global _session
481
497
 
498
+ # First we must ensure that the working directory is setup
499
+ # NB: this is because the working directory can be deleted by the user
500
+ ensure_working_dir()
501
+
482
502
  # Stopgap solution to allow the app to run without a primary dataset
483
503
  if primary is None:
484
- # Dummy dataset
485
- # TODO: pass through the lack of a primary dataset to the app
486
- primary = EMPTY_DATASET
504
+ # Dummy inferences
505
+ # TODO: pass through the lack of a primary inferences to the app
506
+ primary = EMPTY_INFERENCES
487
507
 
488
508
  if _session is not None and _session.active:
489
509
  logger.warning(
@@ -533,10 +553,23 @@ def launch_app(
533
553
 
534
554
  host = host or get_env_host()
535
555
  port = port or get_env_port()
556
+ if use_temp_dir:
557
+ global _session_working_dir
558
+ _session_working_dir = _session_working_dir or TemporaryDirectory()
559
+ database_url = f"sqlite:///{_session_working_dir.name}/phoenix.db"
560
+ else:
561
+ database_url = get_env_database_connection_str()
562
+
563
+ enable_websockets_env = get_env_enable_websockets() or False
564
+ enable_websockets = (
565
+ enable_websockets if enable_websockets is not None else enable_websockets_env
566
+ )
536
567
 
537
568
  if run_in_thread:
538
569
  _session = ThreadSession(
570
+ database_url,
539
571
  primary,
572
+ enable_websockets,
540
573
  reference,
541
574
  corpus,
542
575
  trace,
@@ -548,7 +581,9 @@ def launch_app(
548
581
  # TODO: catch exceptions from thread
549
582
  else:
550
583
  _session = ProcessSession(
584
+ database_url,
551
585
  primary,
586
+ enable_websockets,
552
587
  reference,
553
588
  corpus,
554
589
  trace,
@@ -568,7 +603,8 @@ def launch_app(
568
603
  return None
569
604
 
570
605
  print(f"🌍 To view the Phoenix app in your browser, visit {_session.url}")
571
- print("📺 To view the Phoenix app in a notebook, run `px.active_session().view()`")
606
+ if not use_temp_dir:
607
+ print(f"💽 Your data is being persisted to {database_url}")
572
608
  print("📖 For more information on how to use Phoenix, check out https://docs.arize.com/phoenix")
573
609
  return _session
574
610
 
@@ -582,10 +618,15 @@ def active_session() -> Optional[Session]:
582
618
  return None
583
619
 
584
620
 
585
- def close_app() -> None:
621
+ def close_app(delete_data: bool = False) -> None:
586
622
  """
587
623
  Closes the phoenix application.
588
624
  The application server is shut down and will no longer be accessible.
625
+
626
+ Parameters
627
+ ----------
628
+ delete_data : bool, optional
629
+ If set to true, all stored phoenix data, including traces and evaluations. Default False.
589
630
  """
590
631
  global _session
591
632
  if _session is None:
@@ -594,12 +635,15 @@ def close_app() -> None:
594
635
  _session.end()
595
636
  _session = None
596
637
  logger.info("Session closed")
638
+ if delete_data:
639
+ logger.info("Deleting all data")
640
+ delete_all(prompt_before_delete=False)
597
641
 
598
642
 
599
643
  def _get_url(host: str, port: int, notebook_env: NotebookEnvironment) -> str:
600
644
  """Determines the IFrame URL based on whether this is in a Colab or in a local notebook"""
601
645
  if notebook_env == NotebookEnvironment.COLAB:
602
- from google.colab.output import eval_js # type: ignore
646
+ from google.colab.output import eval_js
603
647
 
604
648
  return str(eval_js(f"google.colab.kernel.proxyPort({port}, {{'cache': true}})"))
605
649
  if notebook_env == NotebookEnvironment.SAGEMAKER:
@@ -617,7 +661,7 @@ def _get_url(host: str, port: int, notebook_env: NotebookEnvironment) -> str:
617
661
  def _is_colab() -> bool:
618
662
  """Determines whether this is in a Colab"""
619
663
  try:
620
- import google.colab # type: ignore # noqa: F401
664
+ import google.colab # noqa: F401
621
665
  except ImportError:
622
666
  return False
623
667
  try: