arize-phoenix 4.10.2rc0__py3-none-any.whl → 4.10.2rc1__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.10.2rc0.dist-info → arize_phoenix-4.10.2rc1.dist-info}/METADATA +4 -3
- {arize_phoenix-4.10.2rc0.dist-info → arize_phoenix-4.10.2rc1.dist-info}/RECORD +27 -35
- 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 +389 -507
- phoenix/server/api/routers/v1/evaluations.py +74 -64
- phoenix/server/api/routers/v1/experiment_evaluations.py +67 -91
- phoenix/server/api/routers/v1/experiment_runs.py +97 -155
- phoenix/server/api/routers/v1/experiments.py +131 -181
- phoenix/server/api/routers/v1/spans.py +141 -173
- phoenix/server/api/routers/v1/traces.py +113 -128
- phoenix/server/api/routers/v1/utils.py +94 -0
- phoenix/server/api/types/Span.py +0 -1
- phoenix/server/app.py +148 -192
- phoenix/server/main.py +0 -3
- phoenix/server/static/index.css +6 -0
- phoenix/server/static/index.js +8547 -0
- phoenix/server/templates/index.html +25 -76
- phoenix/server/thread_server.py +2 -2
- phoenix/trace/schemas.py +0 -1
- phoenix/version.py +1 -1
- phoenix/server/openapi/docs.py +0 -221
- phoenix/server/static/.vite/manifest.json +0 -78
- phoenix/server/static/assets/components-C8sm_r1F.js +0 -1142
- phoenix/server/static/assets/index-BEKPzgQs.js +0 -100
- phoenix/server/static/assets/pages-bN7juCjh.js +0 -2885
- phoenix/server/static/assets/vendor-CUDAPm8e.js +0 -641
- phoenix/server/static/assets/vendor-DxkFTwjz.css +0 -1
- phoenix/server/static/assets/vendor-arizeai-Do2HOmcL.js +0 -662
- phoenix/server/static/assets/vendor-codemirror-CrdxOlMs.js +0 -12
- phoenix/server/static/assets/vendor-recharts-PKRvByVe.js +0 -59
- phoenix/server/static/assets/vendor-three-DwGkEfCM.js +0 -2998
- {arize_phoenix-4.10.2rc0.dist-info → arize_phoenix-4.10.2rc1.dist-info}/WHEEL +0 -0
- {arize_phoenix-4.10.2rc0.dist-info → arize_phoenix-4.10.2rc1.dist-info}/licenses/IP_NOTICE +0 -0
- {arize_phoenix-4.10.2rc0.dist-info → arize_phoenix-4.10.2rc1.dist-info}/licenses/LICENSE +0 -0
phoenix/server/app.py
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import contextlib
|
|
2
|
-
import json
|
|
3
2
|
import logging
|
|
4
3
|
from datetime import datetime
|
|
5
4
|
from pathlib import Path
|
|
@@ -20,25 +19,24 @@ from typing import (
|
|
|
20
19
|
)
|
|
21
20
|
|
|
22
21
|
import strawberry
|
|
22
|
+
from fastapi import APIRouter, FastAPI
|
|
23
|
+
from fastapi.middleware.gzip import GZipMiddleware
|
|
24
|
+
from fastapi.responses import FileResponse
|
|
25
|
+
from fastapi.utils import is_body_allowed_for_status_code
|
|
23
26
|
from sqlalchemy.ext.asyncio import (
|
|
24
27
|
AsyncEngine,
|
|
25
28
|
AsyncSession,
|
|
26
29
|
async_sessionmaker,
|
|
27
30
|
)
|
|
28
|
-
from starlette.applications import Starlette
|
|
29
|
-
from starlette.datastructures import QueryParams
|
|
30
|
-
from starlette.endpoints import HTTPEndpoint
|
|
31
31
|
from starlette.exceptions import HTTPException
|
|
32
32
|
from starlette.middleware import Middleware
|
|
33
33
|
from starlette.middleware.base import BaseHTTPMiddleware, RequestResponseEndpoint
|
|
34
34
|
from starlette.requests import Request
|
|
35
|
-
from starlette.responses import
|
|
36
|
-
from starlette.routing import Mount, Route
|
|
35
|
+
from starlette.responses import PlainTextResponse, Response
|
|
37
36
|
from starlette.staticfiles import StaticFiles
|
|
38
37
|
from starlette.templating import Jinja2Templates
|
|
39
38
|
from starlette.types import Scope, StatefulLifespan
|
|
40
|
-
from
|
|
41
|
-
from strawberry.asgi import GraphQL
|
|
39
|
+
from strawberry.fastapi import GraphQLRouter
|
|
42
40
|
from strawberry.schema import BaseSchema
|
|
43
41
|
from typing_extensions import TypeAlias
|
|
44
42
|
|
|
@@ -81,11 +79,10 @@ from phoenix.server.api.dataloaders import (
|
|
|
81
79
|
TraceEvaluationsDataLoader,
|
|
82
80
|
TraceRowIdsDataLoader,
|
|
83
81
|
)
|
|
84
|
-
from phoenix.server.api.
|
|
85
|
-
from phoenix.server.api.routers.v1 import
|
|
82
|
+
from phoenix.server.api.routers.v1 import REST_API_VERSION
|
|
83
|
+
from phoenix.server.api.routers.v1 import router as v1_router
|
|
86
84
|
from phoenix.server.api.schema import schema
|
|
87
85
|
from phoenix.server.grpc_server import GrpcServer
|
|
88
|
-
from phoenix.server.openapi.docs import get_swagger_ui_html
|
|
89
86
|
from phoenix.server.telemetry import initialize_opentelemetry_tracer_provider
|
|
90
87
|
from phoenix.trace.schemas import Span
|
|
91
88
|
|
|
@@ -94,6 +91,8 @@ if TYPE_CHECKING:
|
|
|
94
91
|
|
|
95
92
|
logger = logging.getLogger(__name__)
|
|
96
93
|
|
|
94
|
+
router = APIRouter(include_in_schema=False)
|
|
95
|
+
|
|
97
96
|
templates = Jinja2Templates(directory=SERVER_DIR / "templates")
|
|
98
97
|
|
|
99
98
|
|
|
@@ -104,8 +103,6 @@ class AppConfig(NamedTuple):
|
|
|
104
103
|
min_dist: float
|
|
105
104
|
n_neighbors: int
|
|
106
105
|
n_samples: int
|
|
107
|
-
is_development: bool
|
|
108
|
-
manifest_json_path: str
|
|
109
106
|
|
|
110
107
|
|
|
111
108
|
class Static(StaticFiles):
|
|
@@ -115,16 +112,8 @@ class Static(StaticFiles):
|
|
|
115
112
|
|
|
116
113
|
def __init__(self, *, app_config: AppConfig, **kwargs: Any):
|
|
117
114
|
self._app_config = app_config
|
|
118
|
-
self.manifest = self._load_manifest()
|
|
119
115
|
super().__init__(**kwargs)
|
|
120
116
|
|
|
121
|
-
def _load_manifest(self) -> Dict[str, str]:
|
|
122
|
-
try:
|
|
123
|
-
with open(self._app_config.manifest_json_path, "r") as f:
|
|
124
|
-
return json.load(f)
|
|
125
|
-
except (FileNotFoundError, json.JSONDecodeError) as e:
|
|
126
|
-
raise e
|
|
127
|
-
|
|
128
117
|
async def get_response(self, path: str, scope: Scope) -> Response:
|
|
129
118
|
response = None
|
|
130
119
|
try:
|
|
@@ -146,8 +135,6 @@ class Static(StaticFiles):
|
|
|
146
135
|
"basename": request.scope.get("root_path", ""),
|
|
147
136
|
"platform_version": phoenix.__version__,
|
|
148
137
|
"request": request,
|
|
149
|
-
"is_development": self._app_config.is_development,
|
|
150
|
-
"manifest": self.manifest,
|
|
151
138
|
},
|
|
152
139
|
)
|
|
153
140
|
except Exception as e:
|
|
@@ -170,116 +157,20 @@ class HeadersMiddleware(BaseHTTPMiddleware):
|
|
|
170
157
|
ProjectRowId: TypeAlias = int
|
|
171
158
|
|
|
172
159
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
cache_for_dataloaders: Optional[CacheForDataLoaders] = None,
|
|
184
|
-
read_only: bool = False,
|
|
185
|
-
) -> None:
|
|
186
|
-
self.db = db
|
|
187
|
-
self.model = model
|
|
188
|
-
self.corpus = corpus
|
|
189
|
-
self.export_path = export_path
|
|
190
|
-
self.streaming_last_updated_at = streaming_last_updated_at
|
|
191
|
-
self.cache_for_dataloaders = cache_for_dataloaders
|
|
192
|
-
self.read_only = read_only
|
|
193
|
-
super().__init__(schema, graphiql=graphiql)
|
|
194
|
-
|
|
195
|
-
async def get_context(
|
|
196
|
-
self,
|
|
197
|
-
request: Union[Request, WebSocket],
|
|
198
|
-
response: Optional[Response] = None,
|
|
199
|
-
) -> Context:
|
|
200
|
-
return Context(
|
|
201
|
-
request=request,
|
|
202
|
-
response=response,
|
|
203
|
-
db=self.db,
|
|
204
|
-
model=self.model,
|
|
205
|
-
corpus=self.corpus,
|
|
206
|
-
export_path=self.export_path,
|
|
207
|
-
streaming_last_updated_at=self.streaming_last_updated_at,
|
|
208
|
-
data_loaders=DataLoaders(
|
|
209
|
-
average_experiment_run_latency=AverageExperimentRunLatencyDataLoader(self.db),
|
|
210
|
-
dataset_example_revisions=DatasetExampleRevisionsDataLoader(self.db),
|
|
211
|
-
dataset_example_spans=DatasetExampleSpansDataLoader(self.db),
|
|
212
|
-
document_evaluation_summaries=DocumentEvaluationSummaryDataLoader(
|
|
213
|
-
self.db,
|
|
214
|
-
cache_map=self.cache_for_dataloaders.document_evaluation_summary
|
|
215
|
-
if self.cache_for_dataloaders
|
|
216
|
-
else None,
|
|
217
|
-
),
|
|
218
|
-
document_evaluations=DocumentEvaluationsDataLoader(self.db),
|
|
219
|
-
document_retrieval_metrics=DocumentRetrievalMetricsDataLoader(self.db),
|
|
220
|
-
evaluation_summaries=EvaluationSummaryDataLoader(
|
|
221
|
-
self.db,
|
|
222
|
-
cache_map=self.cache_for_dataloaders.evaluation_summary
|
|
223
|
-
if self.cache_for_dataloaders
|
|
224
|
-
else None,
|
|
225
|
-
),
|
|
226
|
-
experiment_annotation_summaries=ExperimentAnnotationSummaryDataLoader(self.db),
|
|
227
|
-
experiment_error_rates=ExperimentErrorRatesDataLoader(self.db),
|
|
228
|
-
experiment_run_counts=ExperimentRunCountsDataLoader(self.db),
|
|
229
|
-
experiment_sequence_number=ExperimentSequenceNumberDataLoader(self.db),
|
|
230
|
-
latency_ms_quantile=LatencyMsQuantileDataLoader(
|
|
231
|
-
self.db,
|
|
232
|
-
cache_map=self.cache_for_dataloaders.latency_ms_quantile
|
|
233
|
-
if self.cache_for_dataloaders
|
|
234
|
-
else None,
|
|
235
|
-
),
|
|
236
|
-
min_start_or_max_end_times=MinStartOrMaxEndTimeDataLoader(
|
|
237
|
-
self.db,
|
|
238
|
-
cache_map=self.cache_for_dataloaders.min_start_or_max_end_time
|
|
239
|
-
if self.cache_for_dataloaders
|
|
240
|
-
else None,
|
|
241
|
-
),
|
|
242
|
-
record_counts=RecordCountDataLoader(
|
|
243
|
-
self.db,
|
|
244
|
-
cache_map=self.cache_for_dataloaders.record_count
|
|
245
|
-
if self.cache_for_dataloaders
|
|
246
|
-
else None,
|
|
247
|
-
),
|
|
248
|
-
span_descendants=SpanDescendantsDataLoader(self.db),
|
|
249
|
-
span_evaluations=SpanEvaluationsDataLoader(self.db),
|
|
250
|
-
span_projects=SpanProjectsDataLoader(self.db),
|
|
251
|
-
token_counts=TokenCountDataLoader(
|
|
252
|
-
self.db,
|
|
253
|
-
cache_map=self.cache_for_dataloaders.token_count
|
|
254
|
-
if self.cache_for_dataloaders
|
|
255
|
-
else None,
|
|
256
|
-
),
|
|
257
|
-
trace_evaluations=TraceEvaluationsDataLoader(self.db),
|
|
258
|
-
trace_row_ids=TraceRowIdsDataLoader(self.db),
|
|
259
|
-
project_by_name=ProjectByNameDataLoader(self.db),
|
|
260
|
-
span_annotations=SpanAnnotationsDataLoader(self.db),
|
|
261
|
-
),
|
|
262
|
-
cache_for_dataloaders=self.cache_for_dataloaders,
|
|
263
|
-
read_only=self.read_only,
|
|
264
|
-
)
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
class Download(HTTPEndpoint):
|
|
268
|
-
path: Path
|
|
269
|
-
|
|
270
|
-
async def get(self, request: Request) -> FileResponse:
|
|
271
|
-
params = QueryParams(request.query_params)
|
|
272
|
-
file = self.path / (params.get("filename", "") + ".parquet")
|
|
273
|
-
if not file.is_file():
|
|
274
|
-
raise HTTPException(status_code=404)
|
|
275
|
-
return FileResponse(
|
|
276
|
-
path=file,
|
|
277
|
-
filename=file.name,
|
|
278
|
-
media_type="application/x-octet-stream",
|
|
279
|
-
)
|
|
160
|
+
@router.get("/exports")
|
|
161
|
+
async def download_exported_file(request: Request, filename: str) -> FileResponse:
|
|
162
|
+
file = request.app.state.export_path / (filename + ".parquet")
|
|
163
|
+
if not file.is_file():
|
|
164
|
+
raise HTTPException(status_code=404)
|
|
165
|
+
return FileResponse(
|
|
166
|
+
path=file,
|
|
167
|
+
filename=file.name,
|
|
168
|
+
media_type="application/x-octet-stream",
|
|
169
|
+
)
|
|
280
170
|
|
|
281
171
|
|
|
282
|
-
|
|
172
|
+
@router.get("/arize_phoenix_version")
|
|
173
|
+
async def version() -> PlainTextResponse:
|
|
283
174
|
return PlainTextResponse(f"{phoenix.__version__}")
|
|
284
175
|
|
|
285
176
|
|
|
@@ -301,9 +192,9 @@ def _lifespan(
|
|
|
301
192
|
enable_prometheus: bool = False,
|
|
302
193
|
clean_ups: Iterable[Callable[[], None]] = (),
|
|
303
194
|
read_only: bool = False,
|
|
304
|
-
) -> StatefulLifespan[
|
|
195
|
+
) -> StatefulLifespan[FastAPI]:
|
|
305
196
|
@contextlib.asynccontextmanager
|
|
306
|
-
async def lifespan(_:
|
|
197
|
+
async def lifespan(_: FastAPI) -> AsyncIterator[Dict[str, Any]]:
|
|
307
198
|
async with bulk_inserter as (
|
|
308
199
|
queue_span,
|
|
309
200
|
queue_evaluation,
|
|
@@ -325,16 +216,89 @@ def _lifespan(
|
|
|
325
216
|
return lifespan
|
|
326
217
|
|
|
327
218
|
|
|
219
|
+
@router.get("/healthz")
|
|
328
220
|
async def check_healthz(_: Request) -> PlainTextResponse:
|
|
329
221
|
return PlainTextResponse("OK")
|
|
330
222
|
|
|
331
223
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
224
|
+
def create_graphql_router(
|
|
225
|
+
*,
|
|
226
|
+
schema: BaseSchema,
|
|
227
|
+
db: Callable[[], AsyncContextManager[AsyncSession]],
|
|
228
|
+
model: Model,
|
|
229
|
+
export_path: Path,
|
|
230
|
+
corpus: Optional[Model] = None,
|
|
231
|
+
streaming_last_updated_at: Callable[[ProjectRowId], Optional[datetime]] = lambda _: None,
|
|
232
|
+
cache_for_dataloaders: Optional[CacheForDataLoaders] = None,
|
|
233
|
+
read_only: bool = False,
|
|
234
|
+
) -> GraphQLRouter: # type: ignore[type-arg]
|
|
235
|
+
context = Context(
|
|
236
|
+
db=db,
|
|
237
|
+
model=model,
|
|
238
|
+
corpus=corpus,
|
|
239
|
+
export_path=export_path,
|
|
240
|
+
streaming_last_updated_at=streaming_last_updated_at,
|
|
241
|
+
data_loaders=DataLoaders(
|
|
242
|
+
average_experiment_run_latency=AverageExperimentRunLatencyDataLoader(db),
|
|
243
|
+
dataset_example_revisions=DatasetExampleRevisionsDataLoader(db),
|
|
244
|
+
dataset_example_spans=DatasetExampleSpansDataLoader(db),
|
|
245
|
+
document_evaluation_summaries=DocumentEvaluationSummaryDataLoader(
|
|
246
|
+
db,
|
|
247
|
+
cache_map=cache_for_dataloaders.document_evaluation_summary
|
|
248
|
+
if cache_for_dataloaders
|
|
249
|
+
else None,
|
|
250
|
+
),
|
|
251
|
+
document_evaluations=DocumentEvaluationsDataLoader(db),
|
|
252
|
+
document_retrieval_metrics=DocumentRetrievalMetricsDataLoader(db),
|
|
253
|
+
evaluation_summaries=EvaluationSummaryDataLoader(
|
|
254
|
+
db,
|
|
255
|
+
cache_map=cache_for_dataloaders.evaluation_summary
|
|
256
|
+
if cache_for_dataloaders
|
|
257
|
+
else None,
|
|
258
|
+
),
|
|
259
|
+
experiment_annotation_summaries=ExperimentAnnotationSummaryDataLoader(db),
|
|
260
|
+
experiment_error_rates=ExperimentErrorRatesDataLoader(db),
|
|
261
|
+
experiment_run_counts=ExperimentRunCountsDataLoader(db),
|
|
262
|
+
experiment_sequence_number=ExperimentSequenceNumberDataLoader(db),
|
|
263
|
+
latency_ms_quantile=LatencyMsQuantileDataLoader(
|
|
264
|
+
db,
|
|
265
|
+
cache_map=cache_for_dataloaders.latency_ms_quantile
|
|
266
|
+
if cache_for_dataloaders
|
|
267
|
+
else None,
|
|
268
|
+
),
|
|
269
|
+
min_start_or_max_end_times=MinStartOrMaxEndTimeDataLoader(
|
|
270
|
+
db,
|
|
271
|
+
cache_map=cache_for_dataloaders.min_start_or_max_end_time
|
|
272
|
+
if cache_for_dataloaders
|
|
273
|
+
else None,
|
|
274
|
+
),
|
|
275
|
+
record_counts=RecordCountDataLoader(
|
|
276
|
+
db,
|
|
277
|
+
cache_map=cache_for_dataloaders.record_count if cache_for_dataloaders else None,
|
|
278
|
+
),
|
|
279
|
+
span_annotations=SpanAnnotationsDataLoader(db),
|
|
280
|
+
span_descendants=SpanDescendantsDataLoader(db),
|
|
281
|
+
span_evaluations=SpanEvaluationsDataLoader(db),
|
|
282
|
+
span_projects=SpanProjectsDataLoader(db),
|
|
283
|
+
token_counts=TokenCountDataLoader(
|
|
284
|
+
db,
|
|
285
|
+
cache_map=cache_for_dataloaders.token_count if cache_for_dataloaders else None,
|
|
286
|
+
),
|
|
287
|
+
trace_evaluations=TraceEvaluationsDataLoader(db),
|
|
288
|
+
trace_row_ids=TraceRowIdsDataLoader(db),
|
|
289
|
+
project_by_name=ProjectByNameDataLoader(db),
|
|
290
|
+
),
|
|
291
|
+
cache_for_dataloaders=cache_for_dataloaders,
|
|
292
|
+
read_only=read_only,
|
|
293
|
+
)
|
|
335
294
|
|
|
336
|
-
|
|
337
|
-
|
|
295
|
+
return GraphQLRouter(
|
|
296
|
+
schema,
|
|
297
|
+
graphiql=True,
|
|
298
|
+
context_getter=lambda: context,
|
|
299
|
+
include_in_schema=False,
|
|
300
|
+
prefix="/graphql",
|
|
301
|
+
)
|
|
338
302
|
|
|
339
303
|
|
|
340
304
|
class SessionFactory:
|
|
@@ -385,6 +349,18 @@ def instrument_engine_if_enabled(engine: AsyncEngine) -> List[Callable[[], None]
|
|
|
385
349
|
return instrumentation_cleanups
|
|
386
350
|
|
|
387
351
|
|
|
352
|
+
async def plain_text_http_exception_handler(request: Request, exc: HTTPException) -> Response:
|
|
353
|
+
"""
|
|
354
|
+
Overrides the default handler for HTTPExceptions to return a plain text
|
|
355
|
+
response instead of a JSON response. For the original source code, see
|
|
356
|
+
https://github.com/tiangolo/fastapi/blob/d3cdd3bbd14109f3b268df7ca496e24bb64593aa/fastapi/exception_handlers.py#L11
|
|
357
|
+
"""
|
|
358
|
+
headers = getattr(exc, "headers", None)
|
|
359
|
+
if not is_body_allowed_for_status_code(exc.status_code):
|
|
360
|
+
return Response(status_code=exc.status_code, headers=headers)
|
|
361
|
+
return PlainTextResponse(str(exc.detail), status_code=exc.status_code, headers=headers)
|
|
362
|
+
|
|
363
|
+
|
|
388
364
|
def create_app(
|
|
389
365
|
db: SessionFactory,
|
|
390
366
|
export_path: Path,
|
|
@@ -392,14 +368,13 @@ def create_app(
|
|
|
392
368
|
umap_params: UMAPParameters,
|
|
393
369
|
corpus: Optional[Model] = None,
|
|
394
370
|
debug: bool = False,
|
|
395
|
-
dev: bool = False,
|
|
396
371
|
read_only: bool = False,
|
|
397
372
|
enable_prometheus: bool = False,
|
|
398
373
|
initial_spans: Optional[Iterable[Union[Span, Tuple[Span, str]]]] = None,
|
|
399
374
|
initial_evaluations: Optional[Iterable[pb.Evaluation]] = None,
|
|
400
375
|
serve_ui: bool = True,
|
|
401
376
|
clean_up_callbacks: List[Callable[[], None]] = [],
|
|
402
|
-
) ->
|
|
377
|
+
) -> FastAPI:
|
|
403
378
|
clean_ups: List[Callable[[], None]] = clean_up_callbacks # To be called at app shutdown.
|
|
404
379
|
initial_batch_of_spans: Iterable[Tuple[Span, str]] = (
|
|
405
380
|
()
|
|
@@ -424,7 +399,6 @@ def create_app(
|
|
|
424
399
|
tracer_provider = None
|
|
425
400
|
strawberry_extensions = schema.get_extensions()
|
|
426
401
|
if server_instrumentation_is_enabled():
|
|
427
|
-
tracer_provider = initialize_opentelemetry_tracer_provider()
|
|
428
402
|
from opentelemetry.trace import TracerProvider
|
|
429
403
|
from strawberry.extensions.tracing import OpenTelemetryExtension
|
|
430
404
|
|
|
@@ -442,7 +416,7 @@ def create_app(
|
|
|
442
416
|
|
|
443
417
|
strawberry_extensions.append(_OpenTelemetryExtension)
|
|
444
418
|
|
|
445
|
-
|
|
419
|
+
graphql_router = create_graphql_router(
|
|
446
420
|
db=db,
|
|
447
421
|
schema=strawberry.Schema(
|
|
448
422
|
query=schema.query,
|
|
@@ -453,7 +427,6 @@ def create_app(
|
|
|
453
427
|
model=model,
|
|
454
428
|
corpus=corpus,
|
|
455
429
|
export_path=export_path,
|
|
456
|
-
graphiql=True,
|
|
457
430
|
streaming_last_updated_at=bulk_inserter.last_updated_at,
|
|
458
431
|
cache_for_dataloaders=cache_for_dataloaders,
|
|
459
432
|
read_only=read_only,
|
|
@@ -464,7 +437,9 @@ def create_app(
|
|
|
464
437
|
prometheus_middlewares = [Middleware(PrometheusMiddleware)]
|
|
465
438
|
else:
|
|
466
439
|
prometheus_middlewares = []
|
|
467
|
-
app =
|
|
440
|
+
app = FastAPI(
|
|
441
|
+
title="Arize-Phoenix REST API",
|
|
442
|
+
version=REST_API_VERSION,
|
|
468
443
|
lifespan=_lifespan(
|
|
469
444
|
read_only=read_only,
|
|
470
445
|
bulk_inserter=bulk_inserter,
|
|
@@ -476,58 +451,39 @@ def create_app(
|
|
|
476
451
|
Middleware(HeadersMiddleware),
|
|
477
452
|
*prometheus_middlewares,
|
|
478
453
|
],
|
|
454
|
+
exception_handlers={HTTPException: plain_text_http_exception_handler},
|
|
479
455
|
debug=debug,
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
Route("/arize_phoenix_version", version),
|
|
484
|
-
Route("/healthz", check_healthz),
|
|
485
|
-
Route(
|
|
486
|
-
"/exports",
|
|
487
|
-
type(
|
|
488
|
-
"DownloadExports",
|
|
489
|
-
(Download,),
|
|
490
|
-
{"path": export_path},
|
|
491
|
-
),
|
|
492
|
-
),
|
|
493
|
-
Route(
|
|
494
|
-
"/docs",
|
|
495
|
-
api_docs,
|
|
496
|
-
),
|
|
497
|
-
Route(
|
|
498
|
-
"/graphql",
|
|
499
|
-
graphql,
|
|
500
|
-
),
|
|
501
|
-
]
|
|
502
|
-
+ (
|
|
503
|
-
[
|
|
504
|
-
Mount(
|
|
505
|
-
"/",
|
|
506
|
-
app=Static(
|
|
507
|
-
directory=SERVER_DIR / "static",
|
|
508
|
-
app_config=AppConfig(
|
|
509
|
-
has_inferences=model.is_empty is not True,
|
|
510
|
-
has_corpus=corpus is not None,
|
|
511
|
-
min_dist=umap_params.min_dist,
|
|
512
|
-
n_neighbors=umap_params.n_neighbors,
|
|
513
|
-
n_samples=umap_params.n_samples,
|
|
514
|
-
is_development=dev,
|
|
515
|
-
manifest_json_path=SERVER_DIR / "static" / ".vite" / "manifest.json",
|
|
516
|
-
),
|
|
517
|
-
),
|
|
518
|
-
name="static",
|
|
519
|
-
),
|
|
520
|
-
]
|
|
521
|
-
if serve_ui
|
|
522
|
-
else []
|
|
523
|
-
),
|
|
456
|
+
swagger_ui_parameters={
|
|
457
|
+
"defaultModelsExpandDepth": -1, # hides the schema section in the Swagger UI
|
|
458
|
+
},
|
|
524
459
|
)
|
|
525
460
|
app.state.read_only = read_only
|
|
461
|
+
app.state.export_path = export_path
|
|
462
|
+
app.include_router(v1_router)
|
|
463
|
+
app.include_router(router)
|
|
464
|
+
app.include_router(graphql_router)
|
|
465
|
+
app.add_middleware(GZipMiddleware)
|
|
466
|
+
if serve_ui:
|
|
467
|
+
app.mount(
|
|
468
|
+
"/",
|
|
469
|
+
app=Static(
|
|
470
|
+
directory=SERVER_DIR / "static",
|
|
471
|
+
app_config=AppConfig(
|
|
472
|
+
has_inferences=model.is_empty is not True,
|
|
473
|
+
has_corpus=corpus is not None,
|
|
474
|
+
min_dist=umap_params.min_dist,
|
|
475
|
+
n_neighbors=umap_params.n_neighbors,
|
|
476
|
+
n_samples=umap_params.n_samples,
|
|
477
|
+
),
|
|
478
|
+
),
|
|
479
|
+
name="static",
|
|
480
|
+
)
|
|
481
|
+
|
|
526
482
|
app.state.db = db
|
|
527
483
|
if tracer_provider:
|
|
528
|
-
from opentelemetry.instrumentation.
|
|
484
|
+
from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor
|
|
529
485
|
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
clean_ups.append(
|
|
486
|
+
FastAPIInstrumentor().instrument(tracer_provider=tracer_provider)
|
|
487
|
+
FastAPIInstrumentor.instrument_app(app, tracer_provider=tracer_provider)
|
|
488
|
+
clean_ups.append(FastAPIInstrumentor().uninstrument)
|
|
533
489
|
return app
|
phoenix/server/main.py
CHANGED
|
@@ -131,8 +131,6 @@ 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")
|
|
136
134
|
subparsers = parser.add_subparsers(dest="command", required=True)
|
|
137
135
|
serve_parser = subparsers.add_parser("serve")
|
|
138
136
|
datasets_parser = subparsers.add_parser("datasets")
|
|
@@ -260,7 +258,6 @@ if __name__ == "__main__":
|
|
|
260
258
|
if corpus_inferences is None
|
|
261
259
|
else create_model_from_inferences(corpus_inferences),
|
|
262
260
|
debug=args.debug,
|
|
263
|
-
dev=args.dev,
|
|
264
261
|
read_only=read_only,
|
|
265
262
|
enable_prometheus=enable_prometheus,
|
|
266
263
|
initial_spans=fixture_spans,
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}main{display:block}h1{font-size:2em;margin:.67em 0}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}button,[type=button],[type=reset],[type=submit]{-webkit-appearance:button}button::-moz-focus-inner,[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner{border-style:none;padding:0}button:-moz-focusring,[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details{display:block}summary{display:list-item}template{display:none}[hidden]{display:none}
|
|
2
|
+
/*! Bundled license information:
|
|
3
|
+
|
|
4
|
+
normalize.css/normalize.css:
|
|
5
|
+
(*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css *)
|
|
6
|
+
*/
|