arize-phoenix 4.12.0__py3-none-any.whl → 4.12.1rc1__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-4.12.0.dist-info → arize_phoenix-4.12.1rc1.dist-info}/METADATA +4 -3
- {arize_phoenix-4.12.0.dist-info → arize_phoenix-4.12.1rc1.dist-info}/RECORD +36 -27
- phoenix/server/api/context.py +3 -7
- phoenix/server/api/openapi/main.py +18 -2
- phoenix/server/api/openapi/schema.py +12 -12
- phoenix/server/api/routers/v1/__init__.py +36 -83
- phoenix/server/api/routers/v1/dataset_examples.py +102 -123
- phoenix/server/api/routers/v1/datasets.py +390 -506
- phoenix/server/api/routers/v1/evaluations.py +73 -66
- phoenix/server/api/routers/v1/experiment_evaluations.py +68 -91
- phoenix/server/api/routers/v1/experiment_runs.py +98 -155
- phoenix/server/api/routers/v1/experiments.py +132 -181
- phoenix/server/api/routers/v1/pydantic_compat.py +78 -0
- phoenix/server/api/routers/v1/spans.py +144 -173
- phoenix/server/api/routers/v1/traces.py +115 -128
- phoenix/server/api/routers/v1/utils.py +95 -0
- phoenix/server/api/types/Project.py +33 -0
- phoenix/server/app.py +172 -176
- phoenix/server/main.py +3 -0
- phoenix/server/static/.vite/manifest.json +78 -0
- phoenix/server/static/assets/components-C8sm_r1F.js +1142 -0
- phoenix/server/static/assets/index-BEKPzgQs.js +100 -0
- phoenix/server/static/assets/pages-bN7juCjh.js +2885 -0
- phoenix/server/static/assets/vendor-CUDAPm8e.js +641 -0
- phoenix/server/static/assets/vendor-DxkFTwjz.css +1 -0
- phoenix/server/static/assets/vendor-arizeai-Do2HOmcL.js +662 -0
- phoenix/server/static/assets/vendor-codemirror-CrdxOlMs.js +12 -0
- phoenix/server/static/assets/vendor-recharts-PKRvByVe.js +59 -0
- phoenix/server/static/assets/vendor-three-DwGkEfCM.js +2998 -0
- phoenix/server/templates/index.html +83 -24
- phoenix/server/thread_server.py +2 -2
- phoenix/session/client.py +3 -2
- phoenix/version.py +1 -1
- phoenix/server/openapi/docs.py +0 -221
- phoenix/server/static/index.css +0 -6
- phoenix/server/static/index.js +0 -8548
- {arize_phoenix-4.12.0.dist-info → arize_phoenix-4.12.1rc1.dist-info}/WHEEL +0 -0
- {arize_phoenix-4.12.0.dist-info → arize_phoenix-4.12.1rc1.dist-info}/licenses/IP_NOTICE +0 -0
- {arize_phoenix-4.12.0.dist-info → arize_phoenix-4.12.1rc1.dist-info}/licenses/LICENSE +0 -0
phoenix/server/app.py
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import contextlib
|
|
2
|
+
import json
|
|
2
3
|
import logging
|
|
3
4
|
from datetime import datetime
|
|
5
|
+
from functools import cached_property
|
|
4
6
|
from pathlib import Path
|
|
5
7
|
from typing import (
|
|
6
8
|
TYPE_CHECKING,
|
|
@@ -19,25 +21,24 @@ from typing import (
|
|
|
19
21
|
)
|
|
20
22
|
|
|
21
23
|
import strawberry
|
|
24
|
+
from fastapi import APIRouter, FastAPI
|
|
25
|
+
from fastapi.middleware.gzip import GZipMiddleware
|
|
26
|
+
from fastapi.responses import FileResponse
|
|
27
|
+
from fastapi.utils import is_body_allowed_for_status_code
|
|
22
28
|
from sqlalchemy.ext.asyncio import (
|
|
23
29
|
AsyncEngine,
|
|
24
30
|
AsyncSession,
|
|
25
31
|
async_sessionmaker,
|
|
26
32
|
)
|
|
27
|
-
from starlette.applications import Starlette
|
|
28
|
-
from starlette.datastructures import QueryParams
|
|
29
|
-
from starlette.endpoints import HTTPEndpoint
|
|
30
33
|
from starlette.exceptions import HTTPException
|
|
31
34
|
from starlette.middleware import Middleware
|
|
32
35
|
from starlette.middleware.base import BaseHTTPMiddleware, RequestResponseEndpoint
|
|
33
36
|
from starlette.requests import Request
|
|
34
|
-
from starlette.responses import
|
|
35
|
-
from starlette.routing import Mount, Route
|
|
37
|
+
from starlette.responses import PlainTextResponse, Response
|
|
36
38
|
from starlette.staticfiles import StaticFiles
|
|
37
39
|
from starlette.templating import Jinja2Templates
|
|
38
40
|
from starlette.types import Scope, StatefulLifespan
|
|
39
|
-
from
|
|
40
|
-
from strawberry.asgi import GraphQL
|
|
41
|
+
from strawberry.fastapi import GraphQLRouter
|
|
41
42
|
from strawberry.schema import BaseSchema
|
|
42
43
|
from typing_extensions import TypeAlias
|
|
43
44
|
|
|
@@ -80,11 +81,10 @@ from phoenix.server.api.dataloaders import (
|
|
|
80
81
|
TraceEvaluationsDataLoader,
|
|
81
82
|
TraceRowIdsDataLoader,
|
|
82
83
|
)
|
|
83
|
-
from phoenix.server.api.
|
|
84
|
-
from phoenix.server.api.routers.v1 import
|
|
84
|
+
from phoenix.server.api.routers.v1 import REST_API_VERSION
|
|
85
|
+
from phoenix.server.api.routers.v1 import router as v1_router
|
|
85
86
|
from phoenix.server.api.schema import schema
|
|
86
87
|
from phoenix.server.grpc_server import GrpcServer
|
|
87
|
-
from phoenix.server.openapi.docs import get_swagger_ui_html
|
|
88
88
|
from phoenix.server.telemetry import initialize_opentelemetry_tracer_provider
|
|
89
89
|
from phoenix.trace.schemas import Span
|
|
90
90
|
|
|
@@ -93,6 +93,8 @@ if TYPE_CHECKING:
|
|
|
93
93
|
|
|
94
94
|
logger = logging.getLogger(__name__)
|
|
95
95
|
|
|
96
|
+
router = APIRouter(include_in_schema=False)
|
|
97
|
+
|
|
96
98
|
templates = Jinja2Templates(directory=SERVER_DIR / "templates")
|
|
97
99
|
|
|
98
100
|
|
|
@@ -103,6 +105,8 @@ class AppConfig(NamedTuple):
|
|
|
103
105
|
min_dist: float
|
|
104
106
|
n_neighbors: int
|
|
105
107
|
n_samples: int
|
|
108
|
+
is_development: bool
|
|
109
|
+
web_manifest_path: Path
|
|
106
110
|
|
|
107
111
|
|
|
108
112
|
class Static(StaticFiles):
|
|
@@ -114,6 +118,19 @@ class Static(StaticFiles):
|
|
|
114
118
|
self._app_config = app_config
|
|
115
119
|
super().__init__(**kwargs)
|
|
116
120
|
|
|
121
|
+
@cached_property
|
|
122
|
+
def _web_manifest(self) -> Dict[str, Any]:
|
|
123
|
+
try:
|
|
124
|
+
with open(self._app_config.web_manifest_path, "r") as f:
|
|
125
|
+
return cast(Dict[str, Any], json.load(f))
|
|
126
|
+
except FileNotFoundError as e:
|
|
127
|
+
if self._app_config.is_development:
|
|
128
|
+
return {}
|
|
129
|
+
raise e
|
|
130
|
+
|
|
131
|
+
def _sanitize_basename(self, basename: str) -> str:
|
|
132
|
+
return basename[:-1] if basename.endswith("/") else basename
|
|
133
|
+
|
|
117
134
|
async def get_response(self, path: str, scope: Scope) -> Response:
|
|
118
135
|
response = None
|
|
119
136
|
try:
|
|
@@ -132,9 +149,11 @@ class Static(StaticFiles):
|
|
|
132
149
|
"min_dist": self._app_config.min_dist,
|
|
133
150
|
"n_neighbors": self._app_config.n_neighbors,
|
|
134
151
|
"n_samples": self._app_config.n_samples,
|
|
135
|
-
"basename": request.scope.get("root_path", ""),
|
|
152
|
+
"basename": self._sanitize_basename(request.scope.get("root_path", "")),
|
|
136
153
|
"platform_version": phoenix.__version__,
|
|
137
154
|
"request": request,
|
|
155
|
+
"is_development": self._app_config.is_development,
|
|
156
|
+
"manifest": self._web_manifest,
|
|
138
157
|
},
|
|
139
158
|
)
|
|
140
159
|
except Exception as e:
|
|
@@ -157,116 +176,20 @@ class HeadersMiddleware(BaseHTTPMiddleware):
|
|
|
157
176
|
ProjectRowId: TypeAlias = int
|
|
158
177
|
|
|
159
178
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
cache_for_dataloaders: Optional[CacheForDataLoaders] = None,
|
|
171
|
-
read_only: bool = False,
|
|
172
|
-
) -> None:
|
|
173
|
-
self.db = db
|
|
174
|
-
self.model = model
|
|
175
|
-
self.corpus = corpus
|
|
176
|
-
self.export_path = export_path
|
|
177
|
-
self.streaming_last_updated_at = streaming_last_updated_at
|
|
178
|
-
self.cache_for_dataloaders = cache_for_dataloaders
|
|
179
|
-
self.read_only = read_only
|
|
180
|
-
super().__init__(schema, graphiql=graphiql)
|
|
181
|
-
|
|
182
|
-
async def get_context(
|
|
183
|
-
self,
|
|
184
|
-
request: Union[Request, WebSocket],
|
|
185
|
-
response: Optional[Response] = None,
|
|
186
|
-
) -> Context:
|
|
187
|
-
return Context(
|
|
188
|
-
request=request,
|
|
189
|
-
response=response,
|
|
190
|
-
db=self.db,
|
|
191
|
-
model=self.model,
|
|
192
|
-
corpus=self.corpus,
|
|
193
|
-
export_path=self.export_path,
|
|
194
|
-
streaming_last_updated_at=self.streaming_last_updated_at,
|
|
195
|
-
data_loaders=DataLoaders(
|
|
196
|
-
average_experiment_run_latency=AverageExperimentRunLatencyDataLoader(self.db),
|
|
197
|
-
dataset_example_revisions=DatasetExampleRevisionsDataLoader(self.db),
|
|
198
|
-
dataset_example_spans=DatasetExampleSpansDataLoader(self.db),
|
|
199
|
-
document_evaluation_summaries=DocumentEvaluationSummaryDataLoader(
|
|
200
|
-
self.db,
|
|
201
|
-
cache_map=self.cache_for_dataloaders.document_evaluation_summary
|
|
202
|
-
if self.cache_for_dataloaders
|
|
203
|
-
else None,
|
|
204
|
-
),
|
|
205
|
-
document_evaluations=DocumentEvaluationsDataLoader(self.db),
|
|
206
|
-
document_retrieval_metrics=DocumentRetrievalMetricsDataLoader(self.db),
|
|
207
|
-
evaluation_summaries=EvaluationSummaryDataLoader(
|
|
208
|
-
self.db,
|
|
209
|
-
cache_map=self.cache_for_dataloaders.evaluation_summary
|
|
210
|
-
if self.cache_for_dataloaders
|
|
211
|
-
else None,
|
|
212
|
-
),
|
|
213
|
-
experiment_annotation_summaries=ExperimentAnnotationSummaryDataLoader(self.db),
|
|
214
|
-
experiment_error_rates=ExperimentErrorRatesDataLoader(self.db),
|
|
215
|
-
experiment_run_counts=ExperimentRunCountsDataLoader(self.db),
|
|
216
|
-
experiment_sequence_number=ExperimentSequenceNumberDataLoader(self.db),
|
|
217
|
-
latency_ms_quantile=LatencyMsQuantileDataLoader(
|
|
218
|
-
self.db,
|
|
219
|
-
cache_map=self.cache_for_dataloaders.latency_ms_quantile
|
|
220
|
-
if self.cache_for_dataloaders
|
|
221
|
-
else None,
|
|
222
|
-
),
|
|
223
|
-
min_start_or_max_end_times=MinStartOrMaxEndTimeDataLoader(
|
|
224
|
-
self.db,
|
|
225
|
-
cache_map=self.cache_for_dataloaders.min_start_or_max_end_time
|
|
226
|
-
if self.cache_for_dataloaders
|
|
227
|
-
else None,
|
|
228
|
-
),
|
|
229
|
-
record_counts=RecordCountDataLoader(
|
|
230
|
-
self.db,
|
|
231
|
-
cache_map=self.cache_for_dataloaders.record_count
|
|
232
|
-
if self.cache_for_dataloaders
|
|
233
|
-
else None,
|
|
234
|
-
),
|
|
235
|
-
span_descendants=SpanDescendantsDataLoader(self.db),
|
|
236
|
-
span_evaluations=SpanEvaluationsDataLoader(self.db),
|
|
237
|
-
span_projects=SpanProjectsDataLoader(self.db),
|
|
238
|
-
token_counts=TokenCountDataLoader(
|
|
239
|
-
self.db,
|
|
240
|
-
cache_map=self.cache_for_dataloaders.token_count
|
|
241
|
-
if self.cache_for_dataloaders
|
|
242
|
-
else None,
|
|
243
|
-
),
|
|
244
|
-
trace_evaluations=TraceEvaluationsDataLoader(self.db),
|
|
245
|
-
trace_row_ids=TraceRowIdsDataLoader(self.db),
|
|
246
|
-
project_by_name=ProjectByNameDataLoader(self.db),
|
|
247
|
-
span_annotations=SpanAnnotationsDataLoader(self.db),
|
|
248
|
-
),
|
|
249
|
-
cache_for_dataloaders=self.cache_for_dataloaders,
|
|
250
|
-
read_only=self.read_only,
|
|
251
|
-
)
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
class Download(HTTPEndpoint):
|
|
255
|
-
path: Path
|
|
256
|
-
|
|
257
|
-
async def get(self, request: Request) -> FileResponse:
|
|
258
|
-
params = QueryParams(request.query_params)
|
|
259
|
-
file = self.path / (params.get("filename", "") + ".parquet")
|
|
260
|
-
if not file.is_file():
|
|
261
|
-
raise HTTPException(status_code=404)
|
|
262
|
-
return FileResponse(
|
|
263
|
-
path=file,
|
|
264
|
-
filename=file.name,
|
|
265
|
-
media_type="application/x-octet-stream",
|
|
266
|
-
)
|
|
179
|
+
@router.get("/exports")
|
|
180
|
+
async def download_exported_file(request: Request, filename: str) -> FileResponse:
|
|
181
|
+
file = request.app.state.export_path / (filename + ".parquet")
|
|
182
|
+
if not file.is_file():
|
|
183
|
+
raise HTTPException(status_code=404)
|
|
184
|
+
return FileResponse(
|
|
185
|
+
path=file,
|
|
186
|
+
filename=file.name,
|
|
187
|
+
media_type="application/x-octet-stream",
|
|
188
|
+
)
|
|
267
189
|
|
|
268
190
|
|
|
269
|
-
|
|
191
|
+
@router.get("/arize_phoenix_version")
|
|
192
|
+
async def version() -> PlainTextResponse:
|
|
270
193
|
return PlainTextResponse(f"{phoenix.__version__}")
|
|
271
194
|
|
|
272
195
|
|
|
@@ -288,9 +211,9 @@ def _lifespan(
|
|
|
288
211
|
enable_prometheus: bool = False,
|
|
289
212
|
clean_ups: Iterable[Callable[[], None]] = (),
|
|
290
213
|
read_only: bool = False,
|
|
291
|
-
) -> StatefulLifespan[
|
|
214
|
+
) -> StatefulLifespan[FastAPI]:
|
|
292
215
|
@contextlib.asynccontextmanager
|
|
293
|
-
async def lifespan(_:
|
|
216
|
+
async def lifespan(_: FastAPI) -> AsyncIterator[Dict[str, Any]]:
|
|
294
217
|
async with bulk_inserter as (
|
|
295
218
|
queue_span,
|
|
296
219
|
queue_evaluation,
|
|
@@ -312,16 +235,90 @@ def _lifespan(
|
|
|
312
235
|
return lifespan
|
|
313
236
|
|
|
314
237
|
|
|
238
|
+
@router.get("/healthz")
|
|
315
239
|
async def check_healthz(_: Request) -> PlainTextResponse:
|
|
316
240
|
return PlainTextResponse("OK")
|
|
317
241
|
|
|
318
242
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
243
|
+
def create_graphql_router(
|
|
244
|
+
*,
|
|
245
|
+
schema: BaseSchema,
|
|
246
|
+
db: Callable[[], AsyncContextManager[AsyncSession]],
|
|
247
|
+
model: Model,
|
|
248
|
+
export_path: Path,
|
|
249
|
+
corpus: Optional[Model] = None,
|
|
250
|
+
streaming_last_updated_at: Callable[[ProjectRowId], Optional[datetime]] = lambda _: None,
|
|
251
|
+
cache_for_dataloaders: Optional[CacheForDataLoaders] = None,
|
|
252
|
+
read_only: bool = False,
|
|
253
|
+
) -> GraphQLRouter: # type: ignore[type-arg]
|
|
254
|
+
def get_context() -> Context:
|
|
255
|
+
return Context(
|
|
256
|
+
db=db,
|
|
257
|
+
model=model,
|
|
258
|
+
corpus=corpus,
|
|
259
|
+
export_path=export_path,
|
|
260
|
+
streaming_last_updated_at=streaming_last_updated_at,
|
|
261
|
+
data_loaders=DataLoaders(
|
|
262
|
+
average_experiment_run_latency=AverageExperimentRunLatencyDataLoader(db),
|
|
263
|
+
dataset_example_revisions=DatasetExampleRevisionsDataLoader(db),
|
|
264
|
+
dataset_example_spans=DatasetExampleSpansDataLoader(db),
|
|
265
|
+
document_evaluation_summaries=DocumentEvaluationSummaryDataLoader(
|
|
266
|
+
db,
|
|
267
|
+
cache_map=cache_for_dataloaders.document_evaluation_summary
|
|
268
|
+
if cache_for_dataloaders
|
|
269
|
+
else None,
|
|
270
|
+
),
|
|
271
|
+
document_evaluations=DocumentEvaluationsDataLoader(db),
|
|
272
|
+
document_retrieval_metrics=DocumentRetrievalMetricsDataLoader(db),
|
|
273
|
+
evaluation_summaries=EvaluationSummaryDataLoader(
|
|
274
|
+
db,
|
|
275
|
+
cache_map=cache_for_dataloaders.evaluation_summary
|
|
276
|
+
if cache_for_dataloaders
|
|
277
|
+
else None,
|
|
278
|
+
),
|
|
279
|
+
experiment_annotation_summaries=ExperimentAnnotationSummaryDataLoader(db),
|
|
280
|
+
experiment_error_rates=ExperimentErrorRatesDataLoader(db),
|
|
281
|
+
experiment_run_counts=ExperimentRunCountsDataLoader(db),
|
|
282
|
+
experiment_sequence_number=ExperimentSequenceNumberDataLoader(db),
|
|
283
|
+
latency_ms_quantile=LatencyMsQuantileDataLoader(
|
|
284
|
+
db,
|
|
285
|
+
cache_map=cache_for_dataloaders.latency_ms_quantile
|
|
286
|
+
if cache_for_dataloaders
|
|
287
|
+
else None,
|
|
288
|
+
),
|
|
289
|
+
min_start_or_max_end_times=MinStartOrMaxEndTimeDataLoader(
|
|
290
|
+
db,
|
|
291
|
+
cache_map=cache_for_dataloaders.min_start_or_max_end_time
|
|
292
|
+
if cache_for_dataloaders
|
|
293
|
+
else None,
|
|
294
|
+
),
|
|
295
|
+
record_counts=RecordCountDataLoader(
|
|
296
|
+
db,
|
|
297
|
+
cache_map=cache_for_dataloaders.record_count if cache_for_dataloaders else None,
|
|
298
|
+
),
|
|
299
|
+
span_annotations=SpanAnnotationsDataLoader(db),
|
|
300
|
+
span_descendants=SpanDescendantsDataLoader(db),
|
|
301
|
+
span_evaluations=SpanEvaluationsDataLoader(db),
|
|
302
|
+
span_projects=SpanProjectsDataLoader(db),
|
|
303
|
+
token_counts=TokenCountDataLoader(
|
|
304
|
+
db,
|
|
305
|
+
cache_map=cache_for_dataloaders.token_count if cache_for_dataloaders else None,
|
|
306
|
+
),
|
|
307
|
+
trace_evaluations=TraceEvaluationsDataLoader(db),
|
|
308
|
+
trace_row_ids=TraceRowIdsDataLoader(db),
|
|
309
|
+
project_by_name=ProjectByNameDataLoader(db),
|
|
310
|
+
),
|
|
311
|
+
cache_for_dataloaders=cache_for_dataloaders,
|
|
312
|
+
read_only=read_only,
|
|
313
|
+
)
|
|
322
314
|
|
|
323
|
-
|
|
324
|
-
|
|
315
|
+
return GraphQLRouter(
|
|
316
|
+
schema,
|
|
317
|
+
graphiql=True,
|
|
318
|
+
context_getter=get_context,
|
|
319
|
+
include_in_schema=False,
|
|
320
|
+
prefix="/graphql",
|
|
321
|
+
)
|
|
325
322
|
|
|
326
323
|
|
|
327
324
|
class SessionFactory:
|
|
@@ -372,6 +369,18 @@ def instrument_engine_if_enabled(engine: AsyncEngine) -> List[Callable[[], None]
|
|
|
372
369
|
return instrumentation_cleanups
|
|
373
370
|
|
|
374
371
|
|
|
372
|
+
async def plain_text_http_exception_handler(request: Request, exc: HTTPException) -> Response:
|
|
373
|
+
"""
|
|
374
|
+
Overrides the default handler for HTTPExceptions to return a plain text
|
|
375
|
+
response instead of a JSON response. For the original source code, see
|
|
376
|
+
https://github.com/tiangolo/fastapi/blob/d3cdd3bbd14109f3b268df7ca496e24bb64593aa/fastapi/exception_handlers.py#L11
|
|
377
|
+
"""
|
|
378
|
+
headers = getattr(exc, "headers", None)
|
|
379
|
+
if not is_body_allowed_for_status_code(exc.status_code):
|
|
380
|
+
return Response(status_code=exc.status_code, headers=headers)
|
|
381
|
+
return PlainTextResponse(str(exc.detail), status_code=exc.status_code, headers=headers)
|
|
382
|
+
|
|
383
|
+
|
|
375
384
|
def create_app(
|
|
376
385
|
db: SessionFactory,
|
|
377
386
|
export_path: Path,
|
|
@@ -379,13 +388,14 @@ def create_app(
|
|
|
379
388
|
umap_params: UMAPParameters,
|
|
380
389
|
corpus: Optional[Model] = None,
|
|
381
390
|
debug: bool = False,
|
|
391
|
+
dev: bool = False,
|
|
382
392
|
read_only: bool = False,
|
|
383
393
|
enable_prometheus: bool = False,
|
|
384
394
|
initial_spans: Optional[Iterable[Union[Span, Tuple[Span, str]]]] = None,
|
|
385
395
|
initial_evaluations: Optional[Iterable[pb.Evaluation]] = None,
|
|
386
396
|
serve_ui: bool = True,
|
|
387
397
|
clean_up_callbacks: List[Callable[[], None]] = [],
|
|
388
|
-
) ->
|
|
398
|
+
) -> FastAPI:
|
|
389
399
|
clean_ups: List[Callable[[], None]] = clean_up_callbacks # To be called at app shutdown.
|
|
390
400
|
initial_batch_of_spans: Iterable[Tuple[Span, str]] = (
|
|
391
401
|
()
|
|
@@ -428,7 +438,7 @@ def create_app(
|
|
|
428
438
|
|
|
429
439
|
strawberry_extensions.append(_OpenTelemetryExtension)
|
|
430
440
|
|
|
431
|
-
|
|
441
|
+
graphql_router = create_graphql_router(
|
|
432
442
|
db=db,
|
|
433
443
|
schema=strawberry.Schema(
|
|
434
444
|
query=schema.query,
|
|
@@ -439,7 +449,6 @@ def create_app(
|
|
|
439
449
|
model=model,
|
|
440
450
|
corpus=corpus,
|
|
441
451
|
export_path=export_path,
|
|
442
|
-
graphiql=True,
|
|
443
452
|
streaming_last_updated_at=bulk_inserter.last_updated_at,
|
|
444
453
|
cache_for_dataloaders=cache_for_dataloaders,
|
|
445
454
|
read_only=read_only,
|
|
@@ -450,7 +459,9 @@ def create_app(
|
|
|
450
459
|
prometheus_middlewares = [Middleware(PrometheusMiddleware)]
|
|
451
460
|
else:
|
|
452
461
|
prometheus_middlewares = []
|
|
453
|
-
app =
|
|
462
|
+
app = FastAPI(
|
|
463
|
+
title="Arize-Phoenix REST API",
|
|
464
|
+
version=REST_API_VERSION,
|
|
454
465
|
lifespan=_lifespan(
|
|
455
466
|
read_only=read_only,
|
|
456
467
|
bulk_inserter=bulk_inserter,
|
|
@@ -462,56 +473,41 @@ def create_app(
|
|
|
462
473
|
Middleware(HeadersMiddleware),
|
|
463
474
|
*prometheus_middlewares,
|
|
464
475
|
],
|
|
476
|
+
exception_handlers={HTTPException: plain_text_http_exception_handler},
|
|
465
477
|
debug=debug,
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
Route("/arize_phoenix_version", version),
|
|
470
|
-
Route("/healthz", check_healthz),
|
|
471
|
-
Route(
|
|
472
|
-
"/exports",
|
|
473
|
-
type(
|
|
474
|
-
"DownloadExports",
|
|
475
|
-
(Download,),
|
|
476
|
-
{"path": export_path},
|
|
477
|
-
),
|
|
478
|
-
),
|
|
479
|
-
Route(
|
|
480
|
-
"/docs",
|
|
481
|
-
api_docs,
|
|
482
|
-
),
|
|
483
|
-
Route(
|
|
484
|
-
"/graphql",
|
|
485
|
-
graphql,
|
|
486
|
-
),
|
|
487
|
-
]
|
|
488
|
-
+ (
|
|
489
|
-
[
|
|
490
|
-
Mount(
|
|
491
|
-
"/",
|
|
492
|
-
app=Static(
|
|
493
|
-
directory=SERVER_DIR / "static",
|
|
494
|
-
app_config=AppConfig(
|
|
495
|
-
has_inferences=model.is_empty is not True,
|
|
496
|
-
has_corpus=corpus is not None,
|
|
497
|
-
min_dist=umap_params.min_dist,
|
|
498
|
-
n_neighbors=umap_params.n_neighbors,
|
|
499
|
-
n_samples=umap_params.n_samples,
|
|
500
|
-
),
|
|
501
|
-
),
|
|
502
|
-
name="static",
|
|
503
|
-
),
|
|
504
|
-
]
|
|
505
|
-
if serve_ui
|
|
506
|
-
else []
|
|
507
|
-
),
|
|
478
|
+
swagger_ui_parameters={
|
|
479
|
+
"defaultModelsExpandDepth": -1, # hides the schema section in the Swagger UI
|
|
480
|
+
},
|
|
508
481
|
)
|
|
509
482
|
app.state.read_only = read_only
|
|
483
|
+
app.state.export_path = export_path
|
|
484
|
+
app.include_router(v1_router)
|
|
485
|
+
app.include_router(router)
|
|
486
|
+
app.include_router(graphql_router)
|
|
487
|
+
app.add_middleware(GZipMiddleware)
|
|
488
|
+
if serve_ui:
|
|
489
|
+
app.mount(
|
|
490
|
+
"/",
|
|
491
|
+
app=Static(
|
|
492
|
+
directory=SERVER_DIR / "static",
|
|
493
|
+
app_config=AppConfig(
|
|
494
|
+
has_inferences=model.is_empty is not True,
|
|
495
|
+
has_corpus=corpus is not None,
|
|
496
|
+
min_dist=umap_params.min_dist,
|
|
497
|
+
n_neighbors=umap_params.n_neighbors,
|
|
498
|
+
n_samples=umap_params.n_samples,
|
|
499
|
+
is_development=dev,
|
|
500
|
+
web_manifest_path=SERVER_DIR / "static" / ".vite" / "manifest.json",
|
|
501
|
+
),
|
|
502
|
+
),
|
|
503
|
+
name="static",
|
|
504
|
+
)
|
|
505
|
+
|
|
510
506
|
app.state.db = db
|
|
511
507
|
if tracer_provider:
|
|
512
|
-
from opentelemetry.instrumentation.
|
|
508
|
+
from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor
|
|
513
509
|
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
clean_ups.append(
|
|
510
|
+
FastAPIInstrumentor().instrument(tracer_provider=tracer_provider)
|
|
511
|
+
FastAPIInstrumentor.instrument_app(app, tracer_provider=tracer_provider)
|
|
512
|
+
clean_ups.append(FastAPIInstrumentor().uninstrument)
|
|
517
513
|
return app
|
phoenix/server/main.py
CHANGED
|
@@ -131,6 +131,8 @@ if __name__ == "__main__":
|
|
|
131
131
|
parser.add_argument("--no-internet", action="store_true")
|
|
132
132
|
parser.add_argument("--umap_params", type=str, required=False, default=DEFAULT_UMAP_PARAMS_STR)
|
|
133
133
|
parser.add_argument("--debug", action="store_true")
|
|
134
|
+
# Whether the app is running in a development environment
|
|
135
|
+
parser.add_argument("--dev", action="store_true")
|
|
134
136
|
subparsers = parser.add_subparsers(dest="command", required=True)
|
|
135
137
|
serve_parser = subparsers.add_parser("serve")
|
|
136
138
|
datasets_parser = subparsers.add_parser("datasets")
|
|
@@ -258,6 +260,7 @@ if __name__ == "__main__":
|
|
|
258
260
|
if corpus_inferences is None
|
|
259
261
|
else create_model_from_inferences(corpus_inferences),
|
|
260
262
|
debug=args.debug,
|
|
263
|
+
dev=args.dev,
|
|
261
264
|
read_only=read_only,
|
|
262
265
|
enable_prometheus=enable_prometheus,
|
|
263
266
|
initial_spans=fixture_spans,
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_components-C8sm_r1F.js": {
|
|
3
|
+
"file": "assets/components-C8sm_r1F.js",
|
|
4
|
+
"name": "components",
|
|
5
|
+
"imports": [
|
|
6
|
+
"_vendor-CUDAPm8e.js",
|
|
7
|
+
"_vendor-arizeai-Do2HOmcL.js",
|
|
8
|
+
"_pages-bN7juCjh.js",
|
|
9
|
+
"_vendor-three-DwGkEfCM.js",
|
|
10
|
+
"_vendor-codemirror-CrdxOlMs.js"
|
|
11
|
+
]
|
|
12
|
+
},
|
|
13
|
+
"_pages-bN7juCjh.js": {
|
|
14
|
+
"file": "assets/pages-bN7juCjh.js",
|
|
15
|
+
"name": "pages",
|
|
16
|
+
"imports": [
|
|
17
|
+
"_vendor-CUDAPm8e.js",
|
|
18
|
+
"_components-C8sm_r1F.js",
|
|
19
|
+
"_vendor-arizeai-Do2HOmcL.js",
|
|
20
|
+
"_vendor-recharts-PKRvByVe.js",
|
|
21
|
+
"_vendor-codemirror-CrdxOlMs.js"
|
|
22
|
+
]
|
|
23
|
+
},
|
|
24
|
+
"_vendor-!~{003}~.js": {
|
|
25
|
+
"file": "assets/vendor-DxkFTwjz.css",
|
|
26
|
+
"src": "_vendor-!~{003}~.js"
|
|
27
|
+
},
|
|
28
|
+
"_vendor-CUDAPm8e.js": {
|
|
29
|
+
"file": "assets/vendor-CUDAPm8e.js",
|
|
30
|
+
"name": "vendor",
|
|
31
|
+
"imports": [
|
|
32
|
+
"_vendor-three-DwGkEfCM.js"
|
|
33
|
+
],
|
|
34
|
+
"css": [
|
|
35
|
+
"assets/vendor-DxkFTwjz.css"
|
|
36
|
+
]
|
|
37
|
+
},
|
|
38
|
+
"_vendor-arizeai-Do2HOmcL.js": {
|
|
39
|
+
"file": "assets/vendor-arizeai-Do2HOmcL.js",
|
|
40
|
+
"name": "vendor-arizeai",
|
|
41
|
+
"imports": [
|
|
42
|
+
"_vendor-CUDAPm8e.js"
|
|
43
|
+
]
|
|
44
|
+
},
|
|
45
|
+
"_vendor-codemirror-CrdxOlMs.js": {
|
|
46
|
+
"file": "assets/vendor-codemirror-CrdxOlMs.js",
|
|
47
|
+
"name": "vendor-codemirror",
|
|
48
|
+
"imports": [
|
|
49
|
+
"_vendor-CUDAPm8e.js"
|
|
50
|
+
]
|
|
51
|
+
},
|
|
52
|
+
"_vendor-recharts-PKRvByVe.js": {
|
|
53
|
+
"file": "assets/vendor-recharts-PKRvByVe.js",
|
|
54
|
+
"name": "vendor-recharts",
|
|
55
|
+
"imports": [
|
|
56
|
+
"_vendor-CUDAPm8e.js"
|
|
57
|
+
]
|
|
58
|
+
},
|
|
59
|
+
"_vendor-three-DwGkEfCM.js": {
|
|
60
|
+
"file": "assets/vendor-three-DwGkEfCM.js",
|
|
61
|
+
"name": "vendor-three"
|
|
62
|
+
},
|
|
63
|
+
"index.tsx": {
|
|
64
|
+
"file": "assets/index-BEKPzgQs.js",
|
|
65
|
+
"name": "index",
|
|
66
|
+
"src": "index.tsx",
|
|
67
|
+
"isEntry": true,
|
|
68
|
+
"imports": [
|
|
69
|
+
"_vendor-CUDAPm8e.js",
|
|
70
|
+
"_vendor-arizeai-Do2HOmcL.js",
|
|
71
|
+
"_components-C8sm_r1F.js",
|
|
72
|
+
"_pages-bN7juCjh.js",
|
|
73
|
+
"_vendor-three-DwGkEfCM.js",
|
|
74
|
+
"_vendor-codemirror-CrdxOlMs.js",
|
|
75
|
+
"_vendor-recharts-PKRvByVe.js"
|
|
76
|
+
]
|
|
77
|
+
}
|
|
78
|
+
}
|