arize-phoenix 3.24.0__py3-none-any.whl → 4.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

Files changed (113) hide show
  1. {arize_phoenix-3.24.0.dist-info → arize_phoenix-4.0.0.dist-info}/METADATA +26 -4
  2. {arize_phoenix-3.24.0.dist-info → arize_phoenix-4.0.0.dist-info}/RECORD +80 -75
  3. phoenix/__init__.py +9 -5
  4. phoenix/config.py +109 -53
  5. phoenix/datetime_utils.py +18 -1
  6. phoenix/db/README.md +25 -0
  7. phoenix/db/__init__.py +4 -0
  8. phoenix/db/alembic.ini +119 -0
  9. phoenix/db/bulk_inserter.py +206 -0
  10. phoenix/db/engines.py +152 -0
  11. phoenix/db/helpers.py +47 -0
  12. phoenix/db/insertion/evaluation.py +209 -0
  13. phoenix/db/insertion/helpers.py +54 -0
  14. phoenix/db/insertion/span.py +142 -0
  15. phoenix/db/migrate.py +71 -0
  16. phoenix/db/migrations/env.py +121 -0
  17. phoenix/db/migrations/script.py.mako +26 -0
  18. phoenix/db/migrations/versions/cf03bd6bae1d_init.py +280 -0
  19. phoenix/db/models.py +371 -0
  20. phoenix/exceptions.py +5 -1
  21. phoenix/server/api/context.py +40 -3
  22. phoenix/server/api/dataloaders/__init__.py +97 -0
  23. phoenix/server/api/dataloaders/cache/__init__.py +3 -0
  24. phoenix/server/api/dataloaders/cache/two_tier_cache.py +67 -0
  25. phoenix/server/api/dataloaders/document_evaluation_summaries.py +152 -0
  26. phoenix/server/api/dataloaders/document_evaluations.py +37 -0
  27. phoenix/server/api/dataloaders/document_retrieval_metrics.py +98 -0
  28. phoenix/server/api/dataloaders/evaluation_summaries.py +151 -0
  29. phoenix/server/api/dataloaders/latency_ms_quantile.py +198 -0
  30. phoenix/server/api/dataloaders/min_start_or_max_end_times.py +93 -0
  31. phoenix/server/api/dataloaders/record_counts.py +125 -0
  32. phoenix/server/api/dataloaders/span_descendants.py +64 -0
  33. phoenix/server/api/dataloaders/span_evaluations.py +37 -0
  34. phoenix/server/api/dataloaders/token_counts.py +138 -0
  35. phoenix/server/api/dataloaders/trace_evaluations.py +37 -0
  36. phoenix/server/api/input_types/SpanSort.py +138 -68
  37. phoenix/server/api/routers/v1/__init__.py +11 -0
  38. phoenix/server/api/routers/v1/evaluations.py +275 -0
  39. phoenix/server/api/routers/v1/spans.py +126 -0
  40. phoenix/server/api/routers/v1/traces.py +82 -0
  41. phoenix/server/api/schema.py +112 -48
  42. phoenix/server/api/types/DocumentEvaluationSummary.py +1 -1
  43. phoenix/server/api/types/Evaluation.py +29 -12
  44. phoenix/server/api/types/EvaluationSummary.py +29 -44
  45. phoenix/server/api/types/MimeType.py +2 -2
  46. phoenix/server/api/types/Model.py +9 -9
  47. phoenix/server/api/types/Project.py +240 -171
  48. phoenix/server/api/types/Span.py +87 -131
  49. phoenix/server/api/types/Trace.py +29 -20
  50. phoenix/server/api/types/pagination.py +151 -10
  51. phoenix/server/app.py +263 -35
  52. phoenix/server/grpc_server.py +93 -0
  53. phoenix/server/main.py +75 -60
  54. phoenix/server/openapi/docs.py +218 -0
  55. phoenix/server/prometheus.py +23 -7
  56. phoenix/server/static/index.js +662 -643
  57. phoenix/server/telemetry.py +68 -0
  58. phoenix/services.py +4 -0
  59. phoenix/session/client.py +34 -30
  60. phoenix/session/data_extractor.py +8 -3
  61. phoenix/session/session.py +176 -155
  62. phoenix/settings.py +13 -0
  63. phoenix/trace/attributes.py +349 -0
  64. phoenix/trace/dsl/README.md +116 -0
  65. phoenix/trace/dsl/filter.py +660 -192
  66. phoenix/trace/dsl/helpers.py +24 -5
  67. phoenix/trace/dsl/query.py +562 -185
  68. phoenix/trace/fixtures.py +69 -7
  69. phoenix/trace/otel.py +33 -199
  70. phoenix/trace/schemas.py +14 -8
  71. phoenix/trace/span_evaluations.py +5 -2
  72. phoenix/utilities/__init__.py +0 -26
  73. phoenix/utilities/span_store.py +0 -23
  74. phoenix/version.py +1 -1
  75. phoenix/core/project.py +0 -773
  76. phoenix/core/traces.py +0 -96
  77. phoenix/datasets/dataset.py +0 -214
  78. phoenix/datasets/fixtures.py +0 -24
  79. phoenix/datasets/schema.py +0 -31
  80. phoenix/experimental/evals/__init__.py +0 -73
  81. phoenix/experimental/evals/evaluators.py +0 -413
  82. phoenix/experimental/evals/functions/__init__.py +0 -4
  83. phoenix/experimental/evals/functions/classify.py +0 -453
  84. phoenix/experimental/evals/functions/executor.py +0 -353
  85. phoenix/experimental/evals/functions/generate.py +0 -138
  86. phoenix/experimental/evals/functions/processing.py +0 -76
  87. phoenix/experimental/evals/models/__init__.py +0 -14
  88. phoenix/experimental/evals/models/anthropic.py +0 -175
  89. phoenix/experimental/evals/models/base.py +0 -170
  90. phoenix/experimental/evals/models/bedrock.py +0 -221
  91. phoenix/experimental/evals/models/litellm.py +0 -134
  92. phoenix/experimental/evals/models/openai.py +0 -453
  93. phoenix/experimental/evals/models/rate_limiters.py +0 -246
  94. phoenix/experimental/evals/models/vertex.py +0 -173
  95. phoenix/experimental/evals/models/vertexai.py +0 -186
  96. phoenix/experimental/evals/retrievals.py +0 -96
  97. phoenix/experimental/evals/templates/__init__.py +0 -50
  98. phoenix/experimental/evals/templates/default_templates.py +0 -472
  99. phoenix/experimental/evals/templates/template.py +0 -195
  100. phoenix/experimental/evals/utils/__init__.py +0 -172
  101. phoenix/experimental/evals/utils/threads.py +0 -27
  102. phoenix/server/api/routers/evaluation_handler.py +0 -110
  103. phoenix/server/api/routers/span_handler.py +0 -70
  104. phoenix/server/api/routers/trace_handler.py +0 -60
  105. phoenix/storage/span_store/__init__.py +0 -23
  106. phoenix/storage/span_store/text_file.py +0 -85
  107. phoenix/trace/dsl/missing.py +0 -60
  108. {arize_phoenix-3.24.0.dist-info → arize_phoenix-4.0.0.dist-info}/WHEEL +0 -0
  109. {arize_phoenix-3.24.0.dist-info → arize_phoenix-4.0.0.dist-info}/licenses/IP_NOTICE +0 -0
  110. {arize_phoenix-3.24.0.dist-info → arize_phoenix-4.0.0.dist-info}/licenses/LICENSE +0 -0
  111. /phoenix/{datasets → db/insertion}/__init__.py +0 -0
  112. /phoenix/{experimental → db/migrations}/__init__.py +0 -0
  113. /phoenix/{storage → server/openapi}/__init__.py +0 -0
@@ -1,15 +1,16 @@
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
7
8
  from datetime import datetime
8
9
  from enum import Enum
9
10
  from importlib.util import find_spec
11
+ from itertools import chain
10
12
  from pathlib import Path
11
13
  from tempfile import TemporaryDirectory
12
- from threading import Thread
13
14
  from typing import (
14
15
  TYPE_CHECKING,
15
16
  Any,
@@ -29,26 +30,25 @@ from phoenix.config import (
29
30
  ENV_PHOENIX_COLLECTOR_ENDPOINT,
30
31
  ENV_PHOENIX_HOST,
31
32
  ENV_PHOENIX_PORT,
33
+ ensure_working_dir,
34
+ get_env_database_connection_str,
32
35
  get_env_host,
33
36
  get_env_port,
34
- get_env_project_name,
35
37
  get_exported_files,
38
+ get_working_dir,
36
39
  )
37
40
  from phoenix.core.model_schema_adapter import create_model_from_datasets
38
- from phoenix.core.traces import Traces
39
41
  from phoenix.inferences.inferences import EMPTY_INFERENCES, Inferences
40
42
  from phoenix.pointcloud.umap_parameters import get_umap_parameters
41
43
  from phoenix.server.app import create_app
42
44
  from phoenix.server.thread_server import ThreadServer
43
45
  from phoenix.services import AppService
44
46
  from phoenix.session.client import Client
45
- from phoenix.session.data_extractor import TraceDataExtractor
47
+ from phoenix.session.data_extractor import DEFAULT_SPAN_LIMIT, TraceDataExtractor
46
48
  from phoenix.session.evaluation import encode_evaluations
47
49
  from phoenix.trace import Evaluations
48
50
  from phoenix.trace.dsl.query import SpanQuery
49
51
  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
52
 
53
53
  try:
54
54
  from IPython.display import IFrame # type: ignore
@@ -64,6 +64,10 @@ if TYPE_CHECKING:
64
64
  else:
65
65
  _BaseList = UserList
66
66
 
67
+ # Temporary directory for the duration of the session
68
+ global _session_working_dir
69
+ _session_working_dir: Optional["TemporaryDirectory[str]"] = None
70
+
67
71
 
68
72
  class NotebookEnvironment(Enum):
69
73
  COLAB = "colab"
@@ -95,7 +99,6 @@ class Session(TraceDataExtractor, ABC):
95
99
  """Session that maintains a 1-1 shared state with the Phoenix App."""
96
100
 
97
101
  trace_dataset: Optional[TraceDataset]
98
- traces: Optional[Traces]
99
102
  notebook_env: NotebookEnvironment
100
103
  """The notebook environment that the session is running in."""
101
104
 
@@ -104,6 +107,7 @@ class Session(TraceDataExtractor, ABC):
104
107
 
105
108
  def __init__(
106
109
  self,
110
+ database_url: str,
107
111
  primary_dataset: Inferences,
108
112
  reference_dataset: Optional[Inferences] = None,
109
113
  corpus_dataset: Optional[Inferences] = None,
@@ -113,32 +117,12 @@ class Session(TraceDataExtractor, ABC):
113
117
  port: Optional[int] = None,
114
118
  notebook_env: Optional[NotebookEnvironment] = None,
115
119
  ):
120
+ self._database_url = database_url
116
121
  self.primary_dataset = primary_dataset
117
122
  self.reference_dataset = reference_dataset
118
123
  self.corpus_dataset = corpus_dataset
119
124
  self.trace_dataset = trace_dataset
120
125
  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
126
  self.host = host or get_env_host()
143
127
  self.port = port or get_env_port()
144
128
  self.temp_dir = TemporaryDirectory()
@@ -147,6 +131,87 @@ class Session(TraceDataExtractor, ABC):
147
131
  self.exported_data = ExportedData()
148
132
  self.notebook_env = notebook_env or _get_notebook_environment()
149
133
  self.root_path = _get_root_path(self.notebook_env, self.port)
134
+ host = "127.0.0.1" if self.host == "0.0.0.0" else self.host
135
+ self._client = Client(
136
+ endpoint=f"http://{host}:{self.port}", warn_if_server_not_running=False
137
+ )
138
+
139
+ def query_spans(
140
+ self,
141
+ *queries: SpanQuery,
142
+ start_time: Optional[datetime] = None,
143
+ end_time: Optional[datetime] = None,
144
+ limit: Optional[int] = DEFAULT_SPAN_LIMIT,
145
+ root_spans_only: Optional[bool] = None,
146
+ project_name: Optional[str] = None,
147
+ # Deprecated fields
148
+ stop_time: Optional[datetime] = None,
149
+ ) -> Optional[Union[pd.DataFrame, List[pd.DataFrame]]]:
150
+ """
151
+ Queries the spans in the project based on the provided parameters.
152
+
153
+ Parameters
154
+ ----------
155
+ queries : *SpanQuery
156
+ Variable-length argument list of SpanQuery objects representing
157
+ the queries to be executed.
158
+
159
+ start_time : datetime, optional
160
+ datetime representing the start time of the query.
161
+
162
+ end_time : datetime, optional
163
+ datetime representing the end time of the query.
164
+
165
+ root_spans_only : boolean, optional
166
+ whether to include only root spans in the results.
167
+
168
+ project_name : string, optional
169
+ name of the project to query. Defaults to the project name set
170
+ in the environment variable `PHOENIX_PROJECT_NAME` or 'default' if not set.
171
+
172
+ Returns:
173
+ results : DataFrame
174
+ DataFrame or list of DataFrames containing the query results.
175
+ """
176
+ if stop_time is not None:
177
+ warnings.warn(
178
+ "The `stop_time` parameter is deprecated and will be removed in a future release. "
179
+ "Please use `end_time` instead.",
180
+ DeprecationWarning,
181
+ )
182
+ end_time = stop_time
183
+ return self._client.query_spans(
184
+ *queries,
185
+ start_time=start_time,
186
+ end_time=end_time,
187
+ limit=limit,
188
+ root_spans_only=root_spans_only,
189
+ project_name=project_name,
190
+ )
191
+
192
+ def get_evaluations(
193
+ self,
194
+ project_name: Optional[str] = None,
195
+ ) -> List[Evaluations]:
196
+ """
197
+ Get the evaluations for a project.
198
+
199
+ Parameters
200
+ ----------
201
+ project_name : str, optional
202
+ The name of the project. If not provided, the project name set
203
+ in the environment variable `PHOENIX_PROJECT_NAME` will be used.
204
+ Otherwise, 'default' will be used.
205
+
206
+ Returns
207
+ -------
208
+ evaluations : List[Evaluations]
209
+ A list of evaluations for the specified project.
210
+
211
+ """
212
+ return self._client.get_evaluations(
213
+ project_name=project_name,
214
+ )
150
215
 
151
216
  @abstractmethod
152
217
  def end(self) -> None:
@@ -187,6 +252,10 @@ class Session(TraceDataExtractor, ABC):
187
252
  """Returns the url for the phoenix app"""
188
253
  return _get_url(self.host, self.port, self.notebook_env)
189
254
 
255
+ @property
256
+ def database_url(self) -> str:
257
+ return self._database_url
258
+
190
259
 
191
260
  _session: Optional[Session] = None
192
261
 
@@ -194,6 +263,7 @@ _session: Optional[Session] = None
194
263
  class ProcessSession(Session):
195
264
  def __init__(
196
265
  self,
266
+ database_url: str,
197
267
  primary_dataset: Inferences,
198
268
  reference_dataset: Optional[Inferences] = None,
199
269
  corpus_dataset: Optional[Inferences] = None,
@@ -205,6 +275,7 @@ class ProcessSession(Session):
205
275
  notebook_env: Optional[NotebookEnvironment] = None,
206
276
  ) -> None:
207
277
  super().__init__(
278
+ database_url=database_url,
208
279
  primary_dataset=primary_dataset,
209
280
  reference_dataset=reference_dataset,
210
281
  corpus_dataset=corpus_dataset,
@@ -228,12 +299,13 @@ class ProcessSession(Session):
228
299
  )
229
300
  # Initialize an app service that keeps the server running
230
301
  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,
302
+ database_url=database_url,
303
+ export_path=self.export_path,
304
+ host=self.host,
305
+ port=self.port,
306
+ root_path=self.root_path,
307
+ primary_dataset_name=self.primary_dataset.name,
308
+ umap_params=umap_params_str,
237
309
  reference_dataset_name=(
238
310
  self.reference_dataset.name if self.reference_dataset is not None else None
239
311
  ),
@@ -244,11 +316,6 @@ class ProcessSession(Session):
244
316
  self.trace_dataset.name if self.trace_dataset is not None else None
245
317
  ),
246
318
  )
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,
251
- )
252
319
 
253
320
  @property
254
321
  def active(self) -> bool:
@@ -258,32 +325,11 @@ class ProcessSession(Session):
258
325
  self.app_service.stop()
259
326
  self.temp_dir.cleanup()
260
327
 
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
328
 
284
329
  class ThreadSession(Session):
285
330
  def __init__(
286
331
  self,
332
+ database_url: str,
287
333
  primary_dataset: Inferences,
288
334
  reference_dataset: Optional[Inferences] = None,
289
335
  corpus_dataset: Optional[Inferences] = None,
@@ -295,6 +341,7 @@ class ThreadSession(Session):
295
341
  notebook_env: Optional[NotebookEnvironment] = None,
296
342
  ):
297
343
  super().__init__(
344
+ database_url=database_url,
298
345
  primary_dataset=primary_dataset,
299
346
  reference_dataset=reference_dataset,
300
347
  corpus_dataset=corpus_dataset,
@@ -304,20 +351,30 @@ class ThreadSession(Session):
304
351
  port=port,
305
352
  notebook_env=notebook_env,
306
353
  )
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()
354
+ self.model = create_model_from_datasets(
355
+ primary_dataset,
356
+ reference_dataset,
357
+ )
358
+ self.corpus = (
359
+ create_model_from_datasets(
360
+ corpus_dataset,
361
+ )
362
+ if corpus_dataset is not None
363
+ else None
364
+ )
313
365
  # Initialize an app service that keeps the server running
314
366
  self.app = create_app(
367
+ database_url=database_url,
315
368
  export_path=self.export_path,
316
369
  model=self.model,
317
370
  corpus=self.corpus,
318
- traces=self.traces,
319
371
  umap_params=self.umap_parameters,
320
- span_store=span_store,
372
+ initial_spans=trace_dataset.to_spans() if trace_dataset else None,
373
+ initial_evaluations=(
374
+ chain.from_iterable(map(encode_evaluations, initial_evaluations))
375
+ if (trace_dataset and (initial_evaluations := trace_dataset.evaluations))
376
+ else None
377
+ ),
321
378
  )
322
379
  self.server = ThreadServer(
323
380
  app=self.app,
@@ -336,91 +393,29 @@ class ThreadSession(Session):
336
393
  self.server.close()
337
394
  self.temp_dir.cleanup()
338
395
 
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
396
 
359
- stop_time : datetime, optional
360
- datetime representing the stop time of the query.
361
-
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,
397
+ def delete_all(prompt_before_delete: Optional[bool] = True) -> None:
398
+ """
399
+ Deletes the entire contents of the working directory. This will delete, traces, evaluations,
400
+ and any other data stored in the working directory.
401
+ """
402
+ global _session_working_dir
403
+ working_dir = get_working_dir()
404
+ directories_to_delete = []
405
+ if working_dir.exists():
406
+ directories_to_delete.append(working_dir)
407
+ if _session_working_dir is not None:
408
+ directories_to_delete.append(Path(_session_working_dir.name))
409
+
410
+ # Loop through directories to delete
411
+ for directory in directories_to_delete:
412
+ if prompt_before_delete:
413
+ input(
414
+ f"You have data at {directory}. Are you sure you want to delete?"
415
+ + " This cannot be undone. Press Enter to delete, Escape to cancel."
385
416
  )
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()
417
+ shutil.rmtree(directory)
418
+ _session_working_dir = None
424
419
 
425
420
 
426
421
  def launch_app(
@@ -433,6 +428,7 @@ def launch_app(
433
428
  port: Optional[int] = None,
434
429
  run_in_thread: bool = True,
435
430
  notebook_environment: Optional[Union[NotebookEnvironment, str]] = None,
431
+ use_temp_dir: bool = True,
436
432
  ) -> Optional[Session]:
437
433
  """
438
434
  Launches the phoenix application and returns a session to interact with.
@@ -464,6 +460,10 @@ def launch_app(
464
460
  The environment the notebook is running in. This is either 'local', 'colab', or 'sagemaker'.
465
461
  If not provided, phoenix will try to infer the environment. This is only needed if
466
462
  there is a failure to infer the environment.
463
+ use_temp_dir: bool, optional, default=True
464
+ Whether to use a temporary directory to store the data. If set to False, the data will be
465
+ stored in the directory specified by PHOENIX_WORKING_DIR environment variable via SQLite.
466
+
467
467
 
468
468
  Returns
469
469
  -------
@@ -479,7 +479,11 @@ def launch_app(
479
479
  """
480
480
  global _session
481
481
 
482
- # Stopgap solution to allow the app to run without a primary inferences
482
+ # First we must ensure that the working directory is setup
483
+ # NB: this is because the working directory can be deleted by the user
484
+ ensure_working_dir()
485
+
486
+ # Stopgap solution to allow the app to run without a primary dataset
483
487
  if primary is None:
484
488
  # Dummy inferences
485
489
  # TODO: pass through the lack of a primary inferences to the app
@@ -533,9 +537,16 @@ def launch_app(
533
537
 
534
538
  host = host or get_env_host()
535
539
  port = port or get_env_port()
540
+ if use_temp_dir:
541
+ global _session_working_dir
542
+ _session_working_dir = _session_working_dir or TemporaryDirectory()
543
+ database_url = f"sqlite:///{_session_working_dir.name}/phoenix.db"
544
+ else:
545
+ database_url = get_env_database_connection_str()
536
546
 
537
547
  if run_in_thread:
538
548
  _session = ThreadSession(
549
+ database_url,
539
550
  primary,
540
551
  reference,
541
552
  corpus,
@@ -548,6 +559,7 @@ def launch_app(
548
559
  # TODO: catch exceptions from thread
549
560
  else:
550
561
  _session = ProcessSession(
562
+ database_url,
551
563
  primary,
552
564
  reference,
553
565
  corpus,
@@ -568,7 +580,8 @@ def launch_app(
568
580
  return None
569
581
 
570
582
  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()`")
583
+ if not use_temp_dir:
584
+ print(f"💽 Your data is being persisted to {database_url}")
572
585
  print("📖 For more information on how to use Phoenix, check out https://docs.arize.com/phoenix")
573
586
  return _session
574
587
 
@@ -582,10 +595,15 @@ def active_session() -> Optional[Session]:
582
595
  return None
583
596
 
584
597
 
585
- def close_app() -> None:
598
+ def close_app(delete_data: bool = False) -> None:
586
599
  """
587
600
  Closes the phoenix application.
588
601
  The application server is shut down and will no longer be accessible.
602
+
603
+ Parameters
604
+ ----------
605
+ delete_data : bool, optional
606
+ If set to true, all stored phoenix data, including traces and evaluations. Default False.
589
607
  """
590
608
  global _session
591
609
  if _session is None:
@@ -594,6 +612,9 @@ def close_app() -> None:
594
612
  _session.end()
595
613
  _session = None
596
614
  logger.info("Session closed")
615
+ if delete_data:
616
+ logger.info("Deleting all data")
617
+ delete_all(prompt_before_delete=False)
597
618
 
598
619
 
599
620
  def _get_url(host: str, port: int, notebook_env: NotebookEnvironment) -> str:
phoenix/settings.py ADDED
@@ -0,0 +1,13 @@
1
+ from dataclasses import dataclass, field
2
+
3
+
4
+ @dataclass
5
+ class _Settings:
6
+ """Settings for Phoenix, lazily initialized."""
7
+
8
+ # By default, don't log migrations
9
+ log_migrations: bool = field(default=False)
10
+
11
+
12
+ # Singleton instance of the settings
13
+ Settings = _Settings()