arize-phoenix 4.25.0__py3-none-any.whl → 4.27.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.
- {arize_phoenix-4.25.0.dist-info → arize_phoenix-4.27.0.dist-info}/METADATA +4 -4
- {arize_phoenix-4.25.0.dist-info → arize_phoenix-4.27.0.dist-info}/RECORD +24 -22
- phoenix/auth.py +45 -0
- phoenix/db/engines.py +1 -1
- phoenix/inferences/fixtures.py +14 -8
- phoenix/server/api/input_types/UserRoleInput.py +9 -0
- phoenix/server/api/mutations/__init__.py +2 -0
- phoenix/server/api/mutations/user_mutations.py +89 -0
- phoenix/server/api/routers/auth.py +52 -0
- phoenix/server/api/routers/v1/experiments.py +55 -1
- phoenix/server/api/routers/v1/utils.py +2 -2
- phoenix/server/app.py +174 -28
- phoenix/server/main.py +71 -7
- phoenix/server/static/.vite/manifest.json +9 -9
- phoenix/server/static/assets/{components-1Ahruijo.js → components-1MfQimGx.js} +3 -3
- phoenix/server/static/assets/index-B263sE2x.js +100 -0
- phoenix/server/static/assets/{pages-CFS6mPnW.js → pages-CqZDVx20.js} +180 -171
- phoenix/session/client.py +17 -1
- phoenix/trace/dsl/helpers.py +3 -1
- phoenix/trace/fixtures.py +47 -4
- phoenix/version.py +1 -1
- phoenix/auth/__init__.py +0 -0
- phoenix/auth/utils.py +0 -15
- phoenix/server/static/assets/index-BEE_RWJx.js +0 -100
- {arize_phoenix-4.25.0.dist-info → arize_phoenix-4.27.0.dist-info}/WHEEL +0 -0
- {arize_phoenix-4.25.0.dist-info → arize_phoenix-4.27.0.dist-info}/licenses/IP_NOTICE +0 -0
- {arize_phoenix-4.25.0.dist-info → arize_phoenix-4.27.0.dist-info}/licenses/LICENSE +0 -0
phoenix/server/app.py
CHANGED
|
@@ -2,19 +2,23 @@ import asyncio
|
|
|
2
2
|
import contextlib
|
|
3
3
|
import json
|
|
4
4
|
import logging
|
|
5
|
+
from datetime import datetime, timedelta, timezone
|
|
5
6
|
from functools import cached_property
|
|
6
7
|
from pathlib import Path
|
|
8
|
+
from types import MethodType
|
|
7
9
|
from typing import (
|
|
8
10
|
TYPE_CHECKING,
|
|
9
11
|
Any,
|
|
10
12
|
AsyncContextManager,
|
|
11
13
|
AsyncIterator,
|
|
14
|
+
Awaitable,
|
|
12
15
|
Callable,
|
|
13
16
|
Dict,
|
|
14
17
|
Iterable,
|
|
15
18
|
List,
|
|
16
19
|
NamedTuple,
|
|
17
20
|
Optional,
|
|
21
|
+
Set,
|
|
18
22
|
Tuple,
|
|
19
23
|
Union,
|
|
20
24
|
cast,
|
|
@@ -25,11 +29,9 @@ from fastapi import APIRouter, FastAPI
|
|
|
25
29
|
from fastapi.middleware.gzip import GZipMiddleware
|
|
26
30
|
from fastapi.responses import FileResponse
|
|
27
31
|
from fastapi.utils import is_body_allowed_for_status_code
|
|
28
|
-
from sqlalchemy
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
async_sessionmaker,
|
|
32
|
-
)
|
|
32
|
+
from sqlalchemy import select
|
|
33
|
+
from sqlalchemy.ext.asyncio import AsyncEngine, AsyncSession, async_sessionmaker
|
|
34
|
+
from starlette.datastructures import State as StarletteState
|
|
33
35
|
from starlette.exceptions import HTTPException
|
|
34
36
|
from starlette.middleware import Middleware
|
|
35
37
|
from starlette.middleware.base import BaseHTTPMiddleware, RequestResponseEndpoint
|
|
@@ -44,12 +46,9 @@ from typing_extensions import TypeAlias
|
|
|
44
46
|
|
|
45
47
|
import phoenix
|
|
46
48
|
import phoenix.trace.v1 as pb
|
|
47
|
-
from phoenix.config import
|
|
48
|
-
DEFAULT_PROJECT_NAME,
|
|
49
|
-
SERVER_DIR,
|
|
50
|
-
server_instrumentation_is_enabled,
|
|
51
|
-
)
|
|
49
|
+
from phoenix.config import DEFAULT_PROJECT_NAME, SERVER_DIR, server_instrumentation_is_enabled
|
|
52
50
|
from phoenix.core.model_schema import Model
|
|
51
|
+
from phoenix.db import models
|
|
53
52
|
from phoenix.db.bulk_inserter import BulkInserter
|
|
54
53
|
from phoenix.db.engines import create_engine
|
|
55
54
|
from phoenix.db.helpers import SupportedSQLDialect
|
|
@@ -80,6 +79,7 @@ from phoenix.server.api.dataloaders import (
|
|
|
80
79
|
TokenCountDataLoader,
|
|
81
80
|
TraceRowIdsDataLoader,
|
|
82
81
|
)
|
|
82
|
+
from phoenix.server.api.routers.auth import router as auth_router
|
|
83
83
|
from phoenix.server.api.routers.v1 import REST_API_VERSION
|
|
84
84
|
from phoenix.server.api.routers.v1 import router as v1_router
|
|
85
85
|
from phoenix.server.api.schema import schema
|
|
@@ -90,9 +90,17 @@ from phoenix.server.telemetry import initialize_opentelemetry_tracer_provider
|
|
|
90
90
|
from phoenix.server.types import (
|
|
91
91
|
CanGetLastUpdatedAt,
|
|
92
92
|
CanPutItem,
|
|
93
|
+
DaemonTask,
|
|
93
94
|
DbSessionFactory,
|
|
94
95
|
LastUpdatedAt,
|
|
95
96
|
)
|
|
97
|
+
from phoenix.trace.fixtures import (
|
|
98
|
+
get_evals_from_fixture,
|
|
99
|
+
get_trace_fixture_by_name,
|
|
100
|
+
load_example_traces,
|
|
101
|
+
reset_fixture_span_ids_and_timestamps,
|
|
102
|
+
)
|
|
103
|
+
from phoenix.trace.otel import decode_otlp_span, encode_span_to_otlp
|
|
96
104
|
from phoenix.trace.schemas import Span
|
|
97
105
|
from phoenix.utilities.client import PHOENIX_SERVER_VERSION_HEADER
|
|
98
106
|
|
|
@@ -100,12 +108,23 @@ if TYPE_CHECKING:
|
|
|
100
108
|
from opentelemetry.trace import TracerProvider
|
|
101
109
|
|
|
102
110
|
logger = logging.getLogger(__name__)
|
|
111
|
+
logger.setLevel(logging.INFO)
|
|
103
112
|
logger.addHandler(logging.NullHandler())
|
|
104
113
|
|
|
105
114
|
router = APIRouter(include_in_schema=False)
|
|
106
115
|
|
|
107
116
|
templates = Jinja2Templates(directory=SERVER_DIR / "templates")
|
|
108
117
|
|
|
118
|
+
"""
|
|
119
|
+
Threshold (in minutes) to determine if database is booted up for the first time.
|
|
120
|
+
|
|
121
|
+
Used to assess whether the `default` project was created recently.
|
|
122
|
+
If so, demo data is automatically ingested upon initial boot up to populate the database.
|
|
123
|
+
"""
|
|
124
|
+
NEW_DB_AGE_THRESHOLD_MINUTES = 2
|
|
125
|
+
|
|
126
|
+
ProjectName: TypeAlias = str
|
|
127
|
+
|
|
109
128
|
|
|
110
129
|
class AppConfig(NamedTuple):
|
|
111
130
|
has_inferences: bool
|
|
@@ -223,9 +242,99 @@ def _db(engine: AsyncEngine) -> Callable[[], AsyncContextManager[AsyncSession]]:
|
|
|
223
242
|
return factory
|
|
224
243
|
|
|
225
244
|
|
|
245
|
+
class Scaffolder(DaemonTask):
|
|
246
|
+
def __init__(
|
|
247
|
+
self,
|
|
248
|
+
db: DbSessionFactory,
|
|
249
|
+
queue_span: Callable[[Span, ProjectName], Awaitable[None]],
|
|
250
|
+
queue_evaluation: Callable[[pb.Evaluation], Awaitable[None]],
|
|
251
|
+
tracing_fixture_names: Set[str] = set(),
|
|
252
|
+
force_fixture_ingestion: bool = False,
|
|
253
|
+
) -> None:
|
|
254
|
+
super().__init__()
|
|
255
|
+
self._db = db
|
|
256
|
+
self._queue_span = queue_span
|
|
257
|
+
self._queue_evaluation = queue_evaluation
|
|
258
|
+
self._tracing_fixtures = set(
|
|
259
|
+
get_trace_fixture_by_name(name) for name in tracing_fixture_names
|
|
260
|
+
)
|
|
261
|
+
self._force_fixture_ingestion = force_fixture_ingestion
|
|
262
|
+
|
|
263
|
+
async def __aenter__(self) -> None:
|
|
264
|
+
await self.start()
|
|
265
|
+
|
|
266
|
+
async def __aexit__(self, *args: Any, **kwargs: Any) -> None:
|
|
267
|
+
await self.stop()
|
|
268
|
+
|
|
269
|
+
async def _run(self) -> None:
|
|
270
|
+
"""
|
|
271
|
+
Main entry point for Scaffolder.
|
|
272
|
+
Determines whether to load fixtures and handles them.
|
|
273
|
+
"""
|
|
274
|
+
if await self._should_load_fixtures():
|
|
275
|
+
logger.info("Loading trace fixtures.")
|
|
276
|
+
await self._handle_tracing_fixtures()
|
|
277
|
+
logger.info("Finished loading fixtures.")
|
|
278
|
+
else:
|
|
279
|
+
logger.info("DB is not new, avoid loading demo fixtures.")
|
|
280
|
+
|
|
281
|
+
async def _should_load_fixtures(self) -> bool:
|
|
282
|
+
if self._force_fixture_ingestion:
|
|
283
|
+
return True
|
|
284
|
+
|
|
285
|
+
async with self._db() as session:
|
|
286
|
+
created_at = await session.scalar(
|
|
287
|
+
select(models.Project.created_at).where(models.Project.name == "default")
|
|
288
|
+
)
|
|
289
|
+
if created_at is None:
|
|
290
|
+
return False
|
|
291
|
+
|
|
292
|
+
is_new_db = datetime.now(timezone.utc) - created_at < timedelta(
|
|
293
|
+
minutes=NEW_DB_AGE_THRESHOLD_MINUTES
|
|
294
|
+
)
|
|
295
|
+
return is_new_db
|
|
296
|
+
|
|
297
|
+
async def _handle_tracing_fixtures(self) -> None:
|
|
298
|
+
"""
|
|
299
|
+
Main handler for processing trace fixtures. Process each fixture by
|
|
300
|
+
loading its trace dataframe, gettting and processings its
|
|
301
|
+
spans and evals, and queuing.
|
|
302
|
+
"""
|
|
303
|
+
loop = asyncio.get_running_loop()
|
|
304
|
+
for fixture in self._tracing_fixtures:
|
|
305
|
+
try:
|
|
306
|
+
trace_ds = await loop.run_in_executor(None, load_example_traces, fixture.name)
|
|
307
|
+
|
|
308
|
+
fixture_spans, fixture_evals = await loop.run_in_executor(
|
|
309
|
+
None,
|
|
310
|
+
reset_fixture_span_ids_and_timestamps,
|
|
311
|
+
(
|
|
312
|
+
# Apply `encode` here because legacy jsonl files contains UUIDs as strings.
|
|
313
|
+
# `encode` removes the hyphens in the UUIDs.
|
|
314
|
+
decode_otlp_span(encode_span_to_otlp(span))
|
|
315
|
+
for span in trace_ds.to_spans()
|
|
316
|
+
),
|
|
317
|
+
get_evals_from_fixture(fixture.name),
|
|
318
|
+
)
|
|
319
|
+
|
|
320
|
+
project_name = fixture.project_name or fixture.name
|
|
321
|
+
logger.info(f"Loading '{project_name}' fixtures...")
|
|
322
|
+
for span in fixture_spans:
|
|
323
|
+
await self._queue_span(span, project_name)
|
|
324
|
+
for evaluation in fixture_evals:
|
|
325
|
+
await self._queue_evaluation(evaluation)
|
|
326
|
+
|
|
327
|
+
except FileNotFoundError:
|
|
328
|
+
logger.warning(f"Fixture file not found for '{fixture.name}'")
|
|
329
|
+
except ValueError as e:
|
|
330
|
+
logger.error(f"Error processing fixture '{fixture.name}': {e}")
|
|
331
|
+
except Exception as e:
|
|
332
|
+
logger.error(f"Unexpected error processing fixture '{fixture.name}': {e}")
|
|
333
|
+
|
|
334
|
+
|
|
226
335
|
def _lifespan(
|
|
227
336
|
*,
|
|
228
|
-
|
|
337
|
+
db: DbSessionFactory,
|
|
229
338
|
bulk_inserter: BulkInserter,
|
|
230
339
|
dml_event_handler: DmlEventHandler,
|
|
231
340
|
tracer_provider: Optional["TracerProvider"] = None,
|
|
@@ -233,11 +342,13 @@ def _lifespan(
|
|
|
233
342
|
startup_callbacks: Iterable[Callable[[], None]] = (),
|
|
234
343
|
shutdown_callbacks: Iterable[Callable[[], None]] = (),
|
|
235
344
|
read_only: bool = False,
|
|
345
|
+
tracing_fixture_names: Set[str] = set(),
|
|
346
|
+
force_fixture_ingestion: bool = False,
|
|
236
347
|
) -> StatefulLifespan[FastAPI]:
|
|
237
348
|
@contextlib.asynccontextmanager
|
|
238
349
|
async def lifespan(_: FastAPI) -> AsyncIterator[Dict[str, Any]]:
|
|
239
350
|
global DB_MUTEX
|
|
240
|
-
DB_MUTEX = asyncio.Lock() if dialect is SupportedSQLDialect.SQLITE else None
|
|
351
|
+
DB_MUTEX = asyncio.Lock() if db.dialect is SupportedSQLDialect.SQLITE else None
|
|
241
352
|
async with bulk_inserter as (
|
|
242
353
|
enqueue,
|
|
243
354
|
queue_span,
|
|
@@ -248,7 +359,13 @@ def _lifespan(
|
|
|
248
359
|
disabled=read_only,
|
|
249
360
|
tracer_provider=tracer_provider,
|
|
250
361
|
enable_prometheus=enable_prometheus,
|
|
251
|
-
), dml_event_handler
|
|
362
|
+
), dml_event_handler, Scaffolder(
|
|
363
|
+
db=db,
|
|
364
|
+
queue_span=queue_span,
|
|
365
|
+
queue_evaluation=queue_evaluation,
|
|
366
|
+
tracing_fixture_names=tracing_fixture_names,
|
|
367
|
+
force_fixture_ingestion=force_fixture_ingestion,
|
|
368
|
+
):
|
|
252
369
|
for callback in startup_callbacks:
|
|
253
370
|
callback()
|
|
254
371
|
yield {
|
|
@@ -314,17 +431,19 @@ def create_graphql_router(
|
|
|
314
431
|
dataset_example_spans=DatasetExampleSpansDataLoader(db),
|
|
315
432
|
document_evaluation_summaries=DocumentEvaluationSummaryDataLoader(
|
|
316
433
|
db,
|
|
317
|
-
cache_map=
|
|
318
|
-
|
|
319
|
-
|
|
434
|
+
cache_map=(
|
|
435
|
+
cache_for_dataloaders.document_evaluation_summary
|
|
436
|
+
if cache_for_dataloaders
|
|
437
|
+
else None
|
|
438
|
+
),
|
|
320
439
|
),
|
|
321
440
|
document_evaluations=DocumentEvaluationsDataLoader(db),
|
|
322
441
|
document_retrieval_metrics=DocumentRetrievalMetricsDataLoader(db),
|
|
323
442
|
annotation_summaries=AnnotationSummaryDataLoader(
|
|
324
443
|
db,
|
|
325
|
-
cache_map=
|
|
326
|
-
|
|
327
|
-
|
|
444
|
+
cache_map=(
|
|
445
|
+
cache_for_dataloaders.annotation_summary if cache_for_dataloaders else None
|
|
446
|
+
),
|
|
328
447
|
),
|
|
329
448
|
experiment_annotation_summaries=ExperimentAnnotationSummaryDataLoader(db),
|
|
330
449
|
experiment_error_rates=ExperimentErrorRatesDataLoader(db),
|
|
@@ -332,15 +451,17 @@ def create_graphql_router(
|
|
|
332
451
|
experiment_sequence_number=ExperimentSequenceNumberDataLoader(db),
|
|
333
452
|
latency_ms_quantile=LatencyMsQuantileDataLoader(
|
|
334
453
|
db,
|
|
335
|
-
cache_map=
|
|
336
|
-
|
|
337
|
-
|
|
454
|
+
cache_map=(
|
|
455
|
+
cache_for_dataloaders.latency_ms_quantile if cache_for_dataloaders else None
|
|
456
|
+
),
|
|
338
457
|
),
|
|
339
458
|
min_start_or_max_end_times=MinStartOrMaxEndTimeDataLoader(
|
|
340
459
|
db,
|
|
341
|
-
cache_map=
|
|
342
|
-
|
|
343
|
-
|
|
460
|
+
cache_map=(
|
|
461
|
+
cache_for_dataloaders.min_start_or_max_end_time
|
|
462
|
+
if cache_for_dataloaders
|
|
463
|
+
else None
|
|
464
|
+
),
|
|
344
465
|
),
|
|
345
466
|
record_counts=RecordCountDataLoader(
|
|
346
467
|
db,
|
|
@@ -435,6 +556,8 @@ def create_app(
|
|
|
435
556
|
startup_callbacks: Iterable[Callable[[], None]] = (),
|
|
436
557
|
shutdown_callbacks: Iterable[Callable[[], None]] = (),
|
|
437
558
|
secret: Optional[str] = None,
|
|
559
|
+
tracing_fixture_names: Set[str] = set(),
|
|
560
|
+
force_fixture_ingestion: bool = False,
|
|
438
561
|
) -> FastAPI:
|
|
439
562
|
startup_callbacks_list: List[Callable[[], None]] = list(startup_callbacks)
|
|
440
563
|
shutdown_callbacks_list: List[Callable[[], None]] = list(shutdown_callbacks)
|
|
@@ -507,11 +630,12 @@ def create_app(
|
|
|
507
630
|
prometheus_middlewares = [Middleware(PrometheusMiddleware)]
|
|
508
631
|
else:
|
|
509
632
|
prometheus_middlewares = []
|
|
633
|
+
|
|
510
634
|
app = FastAPI(
|
|
511
635
|
title="Arize-Phoenix REST API",
|
|
512
636
|
version=REST_API_VERSION,
|
|
513
637
|
lifespan=_lifespan(
|
|
514
|
-
|
|
638
|
+
db=db,
|
|
515
639
|
read_only=read_only,
|
|
516
640
|
bulk_inserter=bulk_inserter,
|
|
517
641
|
dml_event_handler=dml_event_handler,
|
|
@@ -519,6 +643,8 @@ def create_app(
|
|
|
519
643
|
enable_prometheus=enable_prometheus,
|
|
520
644
|
shutdown_callbacks=shutdown_callbacks_list,
|
|
521
645
|
startup_callbacks=startup_callbacks_list,
|
|
646
|
+
tracing_fixture_names=tracing_fixture_names,
|
|
647
|
+
force_fixture_ingestion=force_fixture_ingestion,
|
|
522
648
|
),
|
|
523
649
|
middleware=[
|
|
524
650
|
Middleware(HeadersMiddleware),
|
|
@@ -536,6 +662,8 @@ def create_app(
|
|
|
536
662
|
app.include_router(router)
|
|
537
663
|
app.include_router(graphql_router)
|
|
538
664
|
app.add_middleware(GZipMiddleware)
|
|
665
|
+
if authentication_enabled:
|
|
666
|
+
app.include_router(auth_router)
|
|
539
667
|
if serve_ui:
|
|
540
668
|
app.mount(
|
|
541
669
|
"/",
|
|
@@ -554,8 +682,7 @@ def create_app(
|
|
|
554
682
|
),
|
|
555
683
|
name="static",
|
|
556
684
|
)
|
|
557
|
-
|
|
558
|
-
app.state.db = db
|
|
685
|
+
app = _update_app_state(app, db=db, secret=secret)
|
|
559
686
|
if tracer_provider:
|
|
560
687
|
from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor
|
|
561
688
|
|
|
@@ -563,3 +690,22 @@ def create_app(
|
|
|
563
690
|
FastAPIInstrumentor.instrument_app(app, tracer_provider=tracer_provider)
|
|
564
691
|
shutdown_callbacks_list.append(FastAPIInstrumentor().uninstrument)
|
|
565
692
|
return app
|
|
693
|
+
|
|
694
|
+
|
|
695
|
+
def _update_app_state(app: FastAPI, /, *, db: DbSessionFactory, secret: Optional[str]) -> FastAPI:
|
|
696
|
+
"""
|
|
697
|
+
Dynamically updates the app's `state` to include useful fields and methods
|
|
698
|
+
(at the time of this writing, FastAPI does not support setting this state
|
|
699
|
+
during the creation of the app).
|
|
700
|
+
"""
|
|
701
|
+
app.state.db = db
|
|
702
|
+
app.state._secret = secret
|
|
703
|
+
|
|
704
|
+
def get_secret(self: StarletteState) -> str:
|
|
705
|
+
if (secret := self._secret) is None:
|
|
706
|
+
raise ValueError("app secret is not set")
|
|
707
|
+
assert isinstance(secret, str)
|
|
708
|
+
return secret
|
|
709
|
+
|
|
710
|
+
app.state.get_secret = MethodType(get_secret, app.state)
|
|
711
|
+
return app
|
phoenix/server/main.py
CHANGED
|
@@ -48,6 +48,7 @@ from phoenix.trace.fixtures import (
|
|
|
48
48
|
TRACES_FIXTURES,
|
|
49
49
|
get_dataset_fixtures,
|
|
50
50
|
get_evals_from_fixture,
|
|
51
|
+
get_trace_fixtures_by_project_name,
|
|
51
52
|
load_example_traces,
|
|
52
53
|
reset_fixture_span_ids_and_timestamps,
|
|
53
54
|
send_dataset_fixtures,
|
|
@@ -135,7 +136,7 @@ if __name__ == "__main__":
|
|
|
135
136
|
parser.add_argument("--export_path")
|
|
136
137
|
parser.add_argument("--host", type=str, required=False)
|
|
137
138
|
parser.add_argument("--port", type=int, required=False)
|
|
138
|
-
parser.add_argument("--read-only",
|
|
139
|
+
parser.add_argument("--read-only", action="store_true", required=False) # Default is False
|
|
139
140
|
parser.add_argument("--no-internet", action="store_true")
|
|
140
141
|
parser.add_argument("--umap_params", type=str, required=False, default=DEFAULT_UMAP_PARAMS_STR)
|
|
141
142
|
parser.add_argument("--debug", action="store_true")
|
|
@@ -144,6 +145,43 @@ if __name__ == "__main__":
|
|
|
144
145
|
parser.add_argument("--no-ui", action="store_true")
|
|
145
146
|
subparsers = parser.add_subparsers(dest="command", required=True)
|
|
146
147
|
serve_parser = subparsers.add_parser("serve")
|
|
148
|
+
serve_parser.add_argument(
|
|
149
|
+
"--with-fixture",
|
|
150
|
+
type=str,
|
|
151
|
+
required=False,
|
|
152
|
+
default="",
|
|
153
|
+
help=("Name of an inference fixture. Example: 'fixture1'"),
|
|
154
|
+
)
|
|
155
|
+
serve_parser.add_argument(
|
|
156
|
+
"--with-trace-fixtures",
|
|
157
|
+
type=str,
|
|
158
|
+
required=False,
|
|
159
|
+
default="",
|
|
160
|
+
help=(
|
|
161
|
+
"Comma separated list of tracing fixture names (spaces are ignored). "
|
|
162
|
+
"Example: 'fixture1, fixture2'"
|
|
163
|
+
),
|
|
164
|
+
)
|
|
165
|
+
serve_parser.add_argument(
|
|
166
|
+
"--with-projects",
|
|
167
|
+
type=str,
|
|
168
|
+
required=False,
|
|
169
|
+
default="",
|
|
170
|
+
help=(
|
|
171
|
+
"Comma separated list of project names (spaces are ignored). "
|
|
172
|
+
"Example: 'project1, project2'"
|
|
173
|
+
),
|
|
174
|
+
)
|
|
175
|
+
serve_parser.add_argument(
|
|
176
|
+
"--force-fixture-ingestion",
|
|
177
|
+
action="store_true", # default is False
|
|
178
|
+
required=False,
|
|
179
|
+
help=(
|
|
180
|
+
"Whether or not to check the database age before adding the fixtures. "
|
|
181
|
+
"Default is False, i.e., fixtures will only be added if the "
|
|
182
|
+
"database is new."
|
|
183
|
+
),
|
|
184
|
+
)
|
|
147
185
|
datasets_parser = subparsers.add_parser("datasets")
|
|
148
186
|
datasets_parser.add_argument("--primary", type=str, required=True)
|
|
149
187
|
datasets_parser.add_argument("--reference", type=str, required=False)
|
|
@@ -151,12 +189,14 @@ if __name__ == "__main__":
|
|
|
151
189
|
datasets_parser.add_argument("--trace", type=str, required=False)
|
|
152
190
|
fixture_parser = subparsers.add_parser("fixture")
|
|
153
191
|
fixture_parser.add_argument("fixture", type=str, choices=[fixture.name for fixture in FIXTURES])
|
|
154
|
-
fixture_parser.add_argument("--primary-only",
|
|
192
|
+
fixture_parser.add_argument("--primary-only", action="store_true") # Default is False
|
|
155
193
|
trace_fixture_parser = subparsers.add_parser("trace-fixture")
|
|
156
194
|
trace_fixture_parser.add_argument(
|
|
157
195
|
"fixture", type=str, choices=[fixture.name for fixture in TRACES_FIXTURES]
|
|
158
196
|
)
|
|
159
|
-
trace_fixture_parser.add_argument(
|
|
197
|
+
trace_fixture_parser.add_argument(
|
|
198
|
+
"--simulate-streaming", action="store_true"
|
|
199
|
+
) # Default is False
|
|
160
200
|
demo_parser = subparsers.add_parser("demo")
|
|
161
201
|
demo_parser.add_argument("fixture", type=str, choices=[fixture.name for fixture in FIXTURES])
|
|
162
202
|
demo_parser.add_argument(
|
|
@@ -164,10 +204,12 @@ if __name__ == "__main__":
|
|
|
164
204
|
)
|
|
165
205
|
demo_parser.add_argument("--simulate-streaming", action="store_true")
|
|
166
206
|
args = parser.parse_args()
|
|
207
|
+
|
|
167
208
|
db_connection_str = (
|
|
168
209
|
args.database_url if args.database_url else get_env_database_connection_str()
|
|
169
210
|
)
|
|
170
211
|
export_path = Path(args.export_path) if args.export_path else EXPORT_DIR
|
|
212
|
+
force_fixture_ingestion = False
|
|
171
213
|
if args.command == "datasets":
|
|
172
214
|
primary_inferences_name = args.primary
|
|
173
215
|
reference_inferences_name = args.reference
|
|
@@ -202,7 +244,26 @@ if __name__ == "__main__":
|
|
|
202
244
|
)
|
|
203
245
|
trace_dataset_name = args.trace_fixture
|
|
204
246
|
simulate_streaming = args.simulate_streaming
|
|
205
|
-
|
|
247
|
+
elif args.command == "serve":
|
|
248
|
+
# We use sets to avoid duplicates
|
|
249
|
+
tracing_fixture_names = set()
|
|
250
|
+
if args.with_fixture:
|
|
251
|
+
primary_inferences, reference_inferences, corpus_inferences = get_inferences(
|
|
252
|
+
str(args.with_fixture),
|
|
253
|
+
args.no_internet,
|
|
254
|
+
)
|
|
255
|
+
if args.with_trace_fixtures:
|
|
256
|
+
tracing_fixture_names.update(
|
|
257
|
+
[name.strip() for name in args.with_trace_fixtures.split(",")]
|
|
258
|
+
)
|
|
259
|
+
if args.with_projects:
|
|
260
|
+
project_names = [name.strip() for name in args.with_projects.split(",")]
|
|
261
|
+
tracing_fixture_names.update(
|
|
262
|
+
fixture.name
|
|
263
|
+
for name in project_names
|
|
264
|
+
for fixture in get_trace_fixtures_by_project_name(name)
|
|
265
|
+
)
|
|
266
|
+
force_fixture_ingestion = args.force_fixture_ingestion
|
|
206
267
|
host: Optional[str] = args.host or get_env_host()
|
|
207
268
|
display_host = host or "localhost"
|
|
208
269
|
# If the host is "::", the convention is to bind to all interfaces. However, uvicorn
|
|
@@ -260,6 +321,9 @@ if __name__ == "__main__":
|
|
|
260
321
|
engine = create_engine_and_run_migrations(db_connection_str)
|
|
261
322
|
instrumentation_cleanups = instrument_engine_if_enabled(engine)
|
|
262
323
|
factory = DbSessionFactory(db=_db(engine), dialect=engine.dialect.name)
|
|
324
|
+
corpus_model = (
|
|
325
|
+
None if corpus_inferences is None else create_model_from_inferences(corpus_inferences)
|
|
326
|
+
)
|
|
263
327
|
# Print information about the server
|
|
264
328
|
msg = _WELCOME_MESSAGE.format(
|
|
265
329
|
version=version("arize-phoenix"),
|
|
@@ -278,9 +342,7 @@ if __name__ == "__main__":
|
|
|
278
342
|
model=model,
|
|
279
343
|
authentication_enabled=authentication_enabled,
|
|
280
344
|
umap_params=umap_params,
|
|
281
|
-
corpus=
|
|
282
|
-
if corpus_inferences is None
|
|
283
|
-
else create_model_from_inferences(corpus_inferences),
|
|
345
|
+
corpus=corpus_model,
|
|
284
346
|
debug=args.debug,
|
|
285
347
|
dev=args.dev,
|
|
286
348
|
serve_ui=not args.no_ui,
|
|
@@ -291,6 +353,8 @@ if __name__ == "__main__":
|
|
|
291
353
|
startup_callbacks=[lambda: print(msg)],
|
|
292
354
|
shutdown_callbacks=instrumentation_cleanups,
|
|
293
355
|
secret=secret,
|
|
356
|
+
tracing_fixture_names=tracing_fixture_names,
|
|
357
|
+
force_fixture_ingestion=force_fixture_ingestion,
|
|
294
358
|
)
|
|
295
359
|
server = Server(config=Config(app, host=host, port=port, root_path=host_root_path)) # type: ignore
|
|
296
360
|
Thread(target=_write_pid_file_when_ready, args=(server,), daemon=True).start()
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
{
|
|
2
|
-
"_components-
|
|
3
|
-
"file": "assets/components-
|
|
2
|
+
"_components-1MfQimGx.js": {
|
|
3
|
+
"file": "assets/components-1MfQimGx.js",
|
|
4
4
|
"name": "components",
|
|
5
5
|
"imports": [
|
|
6
6
|
"_vendor-aSQri0vz.js",
|
|
7
7
|
"_vendor-arizeai-CsdcB1NH.js",
|
|
8
|
-
"_pages-
|
|
8
|
+
"_pages-CqZDVx20.js",
|
|
9
9
|
"_vendor-three-DwGkEfCM.js",
|
|
10
10
|
"_vendor-codemirror-CYHkhs7D.js"
|
|
11
11
|
]
|
|
12
12
|
},
|
|
13
|
-
"_pages-
|
|
14
|
-
"file": "assets/pages-
|
|
13
|
+
"_pages-CqZDVx20.js": {
|
|
14
|
+
"file": "assets/pages-CqZDVx20.js",
|
|
15
15
|
"name": "pages",
|
|
16
16
|
"imports": [
|
|
17
17
|
"_vendor-aSQri0vz.js",
|
|
18
|
-
"_components-
|
|
18
|
+
"_components-1MfQimGx.js",
|
|
19
19
|
"_vendor-arizeai-CsdcB1NH.js",
|
|
20
20
|
"_vendor-recharts-B0sannek.js",
|
|
21
21
|
"_vendor-codemirror-CYHkhs7D.js"
|
|
@@ -61,15 +61,15 @@
|
|
|
61
61
|
"name": "vendor-three"
|
|
62
62
|
},
|
|
63
63
|
"index.tsx": {
|
|
64
|
-
"file": "assets/index-
|
|
64
|
+
"file": "assets/index-B263sE2x.js",
|
|
65
65
|
"name": "index",
|
|
66
66
|
"src": "index.tsx",
|
|
67
67
|
"isEntry": true,
|
|
68
68
|
"imports": [
|
|
69
69
|
"_vendor-aSQri0vz.js",
|
|
70
70
|
"_vendor-arizeai-CsdcB1NH.js",
|
|
71
|
-
"_pages-
|
|
72
|
-
"_components-
|
|
71
|
+
"_pages-CqZDVx20.js",
|
|
72
|
+
"_components-1MfQimGx.js",
|
|
73
73
|
"_vendor-three-DwGkEfCM.js",
|
|
74
74
|
"_vendor-recharts-B0sannek.js",
|
|
75
75
|
"_vendor-codemirror-CYHkhs7D.js"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{c as je,p as Dt,d as qe,r as p,j as n,R as W,n as Fn,a as we,C as De,b as U,s as Et,e as Ft,f as ie,g as Se,h as Ke,i as Te,k as Le,l as Vt,m as _t,o as ae,q as Pt,t as Nt,u as Rt,v as s,w as m,x as Fe,$ as P,L as Vn,y as Ot,z as Kt,A as At,B as zt,D as cn,F as Ve,E as se,G as $t,H as Gt,I as _n,S as Bt,J as Qt,Q as dn,K as Ht,M as Ut,N as Zt,P as Ae,O as Pn,T as jt,U as qt,V as Wt,W as Jt,X as Xt,Y as Yt,Z as ea,_ as na,a0 as ta,a1 as We,a2 as Q,a3 as Nn,a4 as aa,a5 as ra,a6 as ia,a7 as la,a8 as oa}from"./vendor-aSQri0vz.js";import{u as sa,_ as q,a as _e,b as $,c as N,T as R,F as Rn,d as Z,I,e as w,f as G,A as ca,g as On,h as C,i as D,j as z,k as da,l as ua,P as ma,R as H,m as Pe,n as pa,o as ga,L as Je,p as J,q as X,r as Ne,s as ha,t as Kn,E as An,v as fa,w as La,x as ya,y as va,z as ba,B as Ca}from"./vendor-arizeai-CsdcB1NH.js";import{u as ka}from"./pages-
|
|
1
|
+
import{c as je,p as Dt,d as qe,r as p,j as n,R as W,n as Fn,a as we,C as De,b as U,s as Et,e as Ft,f as ie,g as Se,h as Ke,i as Te,k as Le,l as Vt,m as _t,o as ae,q as Pt,t as Nt,u as Rt,v as s,w as m,x as Fe,$ as P,L as Vn,y as Ot,z as Kt,A as At,B as zt,D as cn,F as Ve,E as se,G as $t,H as Gt,I as _n,S as Bt,J as Qt,Q as dn,K as Ht,M as Ut,N as Zt,P as Ae,O as Pn,T as jt,U as qt,V as Wt,W as Jt,X as Xt,Y as Yt,Z as ea,_ as na,a0 as ta,a1 as We,a2 as Q,a3 as Nn,a4 as aa,a5 as ra,a6 as ia,a7 as la,a8 as oa}from"./vendor-aSQri0vz.js";import{u as sa,_ as q,a as _e,b as $,c as N,T as R,F as Rn,d as Z,I,e as w,f as G,A as ca,g as On,h as C,i as D,j as z,k as da,l as ua,P as ma,R as H,m as Pe,n as pa,o as ga,L as Je,p as J,q as X,r as Ne,s as ha,t as Kn,E as An,v as fa,w as La,x as ya,y as va,z as ba,B as Ca}from"./vendor-arizeai-CsdcB1NH.js";import{u as ka}from"./pages-CqZDVx20.js";import{V as xa}from"./vendor-three-DwGkEfCM.js";import{j as zn,E as $n,l as Gn,a as Bn,R as Xe,n as Ye,p as wa}from"./vendor-codemirror-CYHkhs7D.js";const Sa=e=>{const t=a=>({markdownDisplayMode:"text",setMarkdownDisplayMode:r=>{a({markdownDisplayMode:r})},traceStreamingEnabled:!0,setTraceStreamingEnabled:r=>{a({traceStreamingEnabled:r})},showSpanAside:!0,setShowSpanAside:r=>{a({showSpanAside:r})},showMetricsInTraceTree:!0,setShowMetricsInTraceTree:r=>{a({showMetricsInTraceTree:r})},...e});return je()(Dt(qe(t),{name:"arize-phoenix-preferences"}))},Qn=p.createContext(null);function Rl({children:e,...t}){const a=p.useRef();return a.current||(a.current=Sa(t)),n(Qn.Provider,{value:a.current,children:e})}function be(e,t){const a=W.useContext(Qn);if(!a)throw new Error("Missing PreferencesContext.Provider in the tree");return Fn(a,e,t)}var A=(e=>(e.primary="primary",e.reference="reference",e.corpus="corpus",e))(A||{});function V(e){throw new Error("Unreachable")}function en(e){return typeof e=="number"||e===null}function Ma(e){return typeof e=="string"||e===null}function Ol(e){return Array.isArray(e)?e.every(t=>typeof t=="string"):!1}function Ta(e){return typeof e=="object"&&e!==null}const nn=p.createContext(null);function Re(){const e=W.useContext(nn);if(e===null)throw new Error("useInferences must be used within a InferencesProvider");return e}function Kl(e){return n(nn.Provider,{value:{primaryInferences:e.primaryInferences,referenceInferences:e.referenceInferences,corpusInferences:e.corpusInferences,getInferencesNameByRole:t=>{var a,r;switch(t){case A.primary:return e.primaryInferences.name;case A.reference:return((a=e.referenceInferences)==null?void 0:a.name)??"reference";case A.corpus:return((r=e.corpusInferences)==null?void 0:r.name)??"corpus";default:V()}}},children:e.children})}const Hn=function(){var e={defaultValue:null,kind:"LocalArgument",name:"clusters"},t={defaultValue:null,kind:"LocalArgument",name:"dataQualityMetricColumnName"},a={defaultValue:null,kind:"LocalArgument",name:"fetchDataQualityMetric"},r={defaultValue:null,kind:"LocalArgument",name:"fetchPerformanceMetric"},i={defaultValue:null,kind:"LocalArgument",name:"performanceMetric"},l=[{alias:null,args:null,kind:"ScalarField",name:"primaryValue",storageKey:null},{alias:null,args:null,kind:"ScalarField",name:"referenceValue",storageKey:null}],o=[{alias:null,args:[{kind:"Variable",name:"clusters",variableName:"clusters"}],concreteType:"Cluster",kind:"LinkedField",name:"clusters",plural:!0,selections:[{alias:null,args:null,kind:"ScalarField",name:"id",storageKey:null},{alias:null,args:null,kind:"ScalarField",name:"eventIds",storageKey:null},{alias:null,args:null,kind:"ScalarField",name:"driftRatio",storageKey:null},{alias:null,args:null,kind:"ScalarField",name:"primaryToCorpusRatio",storageKey:null},{condition:"fetchDataQualityMetric",kind:"Condition",passingValue:!0,selections:[{alias:null,args:[{fields:[{kind:"Variable",name:"columnName",variableName:"dataQualityMetricColumnName"},{kind:"Literal",name:"metric",value:"mean"}],kind:"ObjectValue",name:"metric"}],concreteType:"DatasetValues",kind:"LinkedField",name:"dataQualityMetric",plural:!1,selections:l,storageKey:null}]},{condition:"fetchPerformanceMetric",kind:"Condition",passingValue:!0,selections:[{alias:null,args:[{fields:[{kind:"Variable",name:"metric",variableName:"performanceMetric"}],kind:"ObjectValue",name:"metric"}],concreteType:"DatasetValues",kind:"LinkedField",name:"performanceMetric",plural:!1,selections:l,storageKey:null}]}],storageKey:null}];return{fragment:{argumentDefinitions:[e,t,a,r,i],kind:"Fragment",metadata:null,name:"pointCloudStore_clusterMetricsQuery",selections:o,type:"Query",abstractKey:null},kind:"Request",operation:{argumentDefinitions:[e,a,t,r,i],kind:"Operation",name:"pointCloudStore_clusterMetricsQuery",selections:o},params:{cacheID:"86666967012812887ac0a0149d2d2535",id:null,metadata:{},name:"pointCloudStore_clusterMetricsQuery",operationKind:"query",text:`query pointCloudStore_clusterMetricsQuery(
|
|
2
2
|
$clusters: [ClusterInput!]!
|
|
3
3
|
$fetchDataQualityMetric: Boolean!
|
|
4
4
|
$dataQualityMetricColumnName: String
|
|
@@ -1064,7 +1064,7 @@ fragment ModelEmbeddingsTable_embeddingDimensions_4sIU9C on Query {
|
|
|
1064
1064
|
&:hover {
|
|
1065
1065
|
color: var(--ac-global-color-primary);
|
|
1066
1066
|
}
|
|
1067
|
-
`,children:n(I,{svg:e.isExpanded?n(w.ChevronDownOutline,{}):n(w.ChevronRightOutline,{})})})}function wl(){return s("svg",{xmlns:"http://www.w3.org/2000/svg",xmlnsXlink:"http://www.w3.org/1999/xlink",viewBox:"0 0 305.92 350.13",width:
|
|
1067
|
+
`,children:n(I,{svg:e.isExpanded?n(w.ChevronDownOutline,{}):n(w.ChevronRightOutline,{})})})}function wl(e){const{size:t=28}=e;return s("svg",{xmlns:"http://www.w3.org/2000/svg",xmlnsXlink:"http://www.w3.org/1999/xlink",viewBox:"0 0 305.92 350.13",width:t,height:t,css:m`
|
|
1068
1068
|
.cls-1 {
|
|
1069
1069
|
fill: url(#linear-gradient);
|
|
1070
1070
|
}
|
|
@@ -1217,4 +1217,4 @@ fragment ModelEmbeddingsTable_embeddingDimensions_4sIU9C on Query {
|
|
|
1217
1217
|
right: var(--ac-global-dimension-size-100);
|
|
1218
1218
|
z-index: 1;
|
|
1219
1219
|
}
|
|
1220
|
-
`,children:[n(mr,{text:t}),n(Ll,{value:t})]})}function to({sequenceNumber:e}){return s(Je,{color:"yellow-1000",children:["#",e]})}export{g1 as $,pe as A,e1 as B,v1 as C,Ra as D,E1 as E,ve as F,gt as G,de as H,D1 as I,m1 as J,an as K,dr as L,o1 as M,p1 as N,h1 as O,Wl as P,$l as Q,xe as R,re as S,ql as T,zl as U,Gl as V,Bl as W,s1 as X,f1 as Y,i1 as Z,u1 as _,qa as a,ar as a$,L1 as a0,d1 as a1,er as a2,x1 as a3,I1 as a4,dt as a5,nr as a6,l1 as a7,me as a8,Ei as a9,c1 as aA,Ul as aB,Yl as aC,B1 as aD,lt as aE,Q1 as aF,rl as aG,H1 as aH,G1 as aI,Y1 as aJ,W1 as aK,q1 as aL,X1 as aM,Z1 as aN,U1 as aO,j1 as aP,J1 as aQ,Ql as aR,Kl as aS,$1 as aT,eo as aU,t1 as aV,no as aW,Ka as aX,A1 as aY,Di as aZ,to as a_,Ti as aa,Zl as ab,_i as ac,Pi as ad,Vi as ae,Ni as af,F1 as ag,mr as ah,Xa as ai,n1 as aj,z1 as ak,Cl as al,fl as am,be as an,K1 as ao,P1 as ap,Ol as aq,tl as ar,N1 as as,O1 as at,R1 as au,_1 as av,V1 as aw,kl as ax,Ii as ay,Ya as az,Jl as b,or as b0,Xl as b1,Al as b2,
|
|
1220
|
+
`,children:[n(mr,{text:t}),n(Ll,{value:t})]})}function to({sequenceNumber:e}){return s(Je,{color:"yellow-1000",children:["#",e]})}export{g1 as $,pe as A,e1 as B,v1 as C,Ra as D,E1 as E,ve as F,gt as G,de as H,D1 as I,m1 as J,an as K,dr as L,o1 as M,p1 as N,h1 as O,Wl as P,$l as Q,xe as R,re as S,ql as T,zl as U,Gl as V,Bl as W,s1 as X,f1 as Y,i1 as Z,u1 as _,qa as a,ar as a$,L1 as a0,d1 as a1,er as a2,x1 as a3,I1 as a4,dt as a5,nr as a6,l1 as a7,me as a8,Ei as a9,c1 as aA,Ul as aB,Yl as aC,B1 as aD,lt as aE,Q1 as aF,rl as aG,H1 as aH,G1 as aI,Y1 as aJ,W1 as aK,q1 as aL,X1 as aM,Z1 as aN,U1 as aO,j1 as aP,J1 as aQ,Ql as aR,Kl as aS,$1 as aT,eo as aU,t1 as aV,no as aW,Ka as aX,A1 as aY,Di as aZ,to as a_,Ti as aa,Zl as ab,_i as ac,Pi as ad,Vi as ae,Ni as af,F1 as ag,mr as ah,Xa as ai,n1 as aj,z1 as ak,Cl as al,fl as am,be as an,K1 as ao,P1 as ap,Ol as aq,tl as ar,N1 as as,O1 as at,R1 as au,_1 as av,V1 as aw,kl as ax,Ii as ay,Ya as az,Jl as b,or as b0,Xl as b1,Al as b2,wl as b3,jl as b4,Rl as b5,Hl as b6,a1 as c,B as d,Na as e,y as f,nt as g,V as h,pr as i,w1 as j,S1 as k,M1 as l,C1 as m,k1 as n,T1 as o,Ue as p,b1 as q,y1 as r,Cn as s,ot as t,Re as u,Dr as v,Er as w,qn as x,Rr as y,r1 as z};
|