arize-phoenix 3.25.0__py3-none-any.whl → 4.0.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.
- {arize_phoenix-3.25.0.dist-info → arize_phoenix-4.0.1.dist-info}/METADATA +26 -4
- {arize_phoenix-3.25.0.dist-info → arize_phoenix-4.0.1.dist-info}/RECORD +80 -75
- phoenix/__init__.py +9 -5
- phoenix/config.py +109 -53
- phoenix/datetime_utils.py +18 -1
- phoenix/db/README.md +25 -0
- phoenix/db/__init__.py +4 -0
- phoenix/db/alembic.ini +119 -0
- phoenix/db/bulk_inserter.py +206 -0
- phoenix/db/engines.py +152 -0
- phoenix/db/helpers.py +47 -0
- phoenix/db/insertion/evaluation.py +209 -0
- phoenix/db/insertion/helpers.py +51 -0
- phoenix/db/insertion/span.py +142 -0
- phoenix/db/migrate.py +71 -0
- phoenix/db/migrations/env.py +121 -0
- phoenix/db/migrations/script.py.mako +26 -0
- phoenix/db/migrations/versions/cf03bd6bae1d_init.py +280 -0
- phoenix/db/models.py +371 -0
- phoenix/exceptions.py +5 -1
- phoenix/server/api/context.py +40 -3
- phoenix/server/api/dataloaders/__init__.py +97 -0
- phoenix/server/api/dataloaders/cache/__init__.py +3 -0
- phoenix/server/api/dataloaders/cache/two_tier_cache.py +67 -0
- phoenix/server/api/dataloaders/document_evaluation_summaries.py +152 -0
- phoenix/server/api/dataloaders/document_evaluations.py +37 -0
- phoenix/server/api/dataloaders/document_retrieval_metrics.py +98 -0
- phoenix/server/api/dataloaders/evaluation_summaries.py +151 -0
- phoenix/server/api/dataloaders/latency_ms_quantile.py +198 -0
- phoenix/server/api/dataloaders/min_start_or_max_end_times.py +93 -0
- phoenix/server/api/dataloaders/record_counts.py +125 -0
- phoenix/server/api/dataloaders/span_descendants.py +64 -0
- phoenix/server/api/dataloaders/span_evaluations.py +37 -0
- phoenix/server/api/dataloaders/token_counts.py +138 -0
- phoenix/server/api/dataloaders/trace_evaluations.py +37 -0
- phoenix/server/api/input_types/SpanSort.py +138 -68
- phoenix/server/api/routers/v1/__init__.py +11 -0
- phoenix/server/api/routers/v1/evaluations.py +275 -0
- phoenix/server/api/routers/v1/spans.py +126 -0
- phoenix/server/api/routers/v1/traces.py +82 -0
- phoenix/server/api/schema.py +112 -48
- phoenix/server/api/types/DocumentEvaluationSummary.py +1 -1
- phoenix/server/api/types/Evaluation.py +29 -12
- phoenix/server/api/types/EvaluationSummary.py +29 -44
- phoenix/server/api/types/MimeType.py +2 -2
- phoenix/server/api/types/Model.py +9 -9
- phoenix/server/api/types/Project.py +240 -171
- phoenix/server/api/types/Span.py +87 -131
- phoenix/server/api/types/Trace.py +29 -20
- phoenix/server/api/types/pagination.py +151 -10
- phoenix/server/app.py +263 -35
- phoenix/server/grpc_server.py +93 -0
- phoenix/server/main.py +75 -60
- phoenix/server/openapi/docs.py +218 -0
- phoenix/server/prometheus.py +23 -7
- phoenix/server/static/index.js +662 -643
- phoenix/server/telemetry.py +68 -0
- phoenix/services.py +4 -0
- phoenix/session/client.py +34 -30
- phoenix/session/data_extractor.py +8 -3
- phoenix/session/session.py +176 -155
- phoenix/settings.py +13 -0
- phoenix/trace/attributes.py +349 -0
- phoenix/trace/dsl/README.md +116 -0
- phoenix/trace/dsl/filter.py +660 -192
- phoenix/trace/dsl/helpers.py +24 -5
- phoenix/trace/dsl/query.py +562 -185
- phoenix/trace/fixtures.py +69 -7
- phoenix/trace/otel.py +44 -200
- phoenix/trace/schemas.py +14 -8
- phoenix/trace/span_evaluations.py +5 -2
- phoenix/utilities/__init__.py +0 -26
- phoenix/utilities/span_store.py +0 -23
- phoenix/version.py +1 -1
- phoenix/core/project.py +0 -773
- phoenix/core/traces.py +0 -96
- phoenix/datasets/dataset.py +0 -214
- phoenix/datasets/fixtures.py +0 -24
- phoenix/datasets/schema.py +0 -31
- phoenix/experimental/evals/__init__.py +0 -73
- phoenix/experimental/evals/evaluators.py +0 -413
- phoenix/experimental/evals/functions/__init__.py +0 -4
- phoenix/experimental/evals/functions/classify.py +0 -453
- phoenix/experimental/evals/functions/executor.py +0 -353
- phoenix/experimental/evals/functions/generate.py +0 -138
- phoenix/experimental/evals/functions/processing.py +0 -76
- phoenix/experimental/evals/models/__init__.py +0 -14
- phoenix/experimental/evals/models/anthropic.py +0 -175
- phoenix/experimental/evals/models/base.py +0 -170
- phoenix/experimental/evals/models/bedrock.py +0 -221
- phoenix/experimental/evals/models/litellm.py +0 -134
- phoenix/experimental/evals/models/openai.py +0 -453
- phoenix/experimental/evals/models/rate_limiters.py +0 -246
- phoenix/experimental/evals/models/vertex.py +0 -173
- phoenix/experimental/evals/models/vertexai.py +0 -186
- phoenix/experimental/evals/retrievals.py +0 -96
- phoenix/experimental/evals/templates/__init__.py +0 -50
- phoenix/experimental/evals/templates/default_templates.py +0 -472
- phoenix/experimental/evals/templates/template.py +0 -195
- phoenix/experimental/evals/utils/__init__.py +0 -172
- phoenix/experimental/evals/utils/threads.py +0 -27
- phoenix/server/api/routers/evaluation_handler.py +0 -110
- phoenix/server/api/routers/span_handler.py +0 -70
- phoenix/server/api/routers/trace_handler.py +0 -60
- phoenix/storage/span_store/__init__.py +0 -23
- phoenix/storage/span_store/text_file.py +0 -85
- phoenix/trace/dsl/missing.py +0 -60
- {arize_phoenix-3.25.0.dist-info → arize_phoenix-4.0.1.dist-info}/WHEEL +0 -0
- {arize_phoenix-3.25.0.dist-info → arize_phoenix-4.0.1.dist-info}/licenses/IP_NOTICE +0 -0
- {arize_phoenix-3.25.0.dist-info → arize_phoenix-4.0.1.dist-info}/licenses/LICENSE +0 -0
- /phoenix/{datasets → db/insertion}/__init__.py +0 -0
- /phoenix/{experimental → db/migrations}/__init__.py +0 -0
- /phoenix/{storage → server/openapi}/__init__.py +0 -0
phoenix/session/session.py
CHANGED
|
@@ -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
|
-
|
|
232
|
-
self.
|
|
233
|
-
self.
|
|
234
|
-
self.
|
|
235
|
-
self.
|
|
236
|
-
|
|
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
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
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
|
-
|
|
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
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
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
|
-
|
|
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
|
-
#
|
|
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
|
-
|
|
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()
|