arize-phoenix 4.4.4rc3__py3-none-any.whl → 4.4.4rc5__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.4.4rc3.dist-info → arize_phoenix-4.4.4rc5.dist-info}/METADATA +2 -2
- {arize_phoenix-4.4.4rc3.dist-info → arize_phoenix-4.4.4rc5.dist-info}/RECORD +33 -28
- phoenix/datasets/evaluators/__init__.py +18 -0
- phoenix/datasets/evaluators/code_evaluators.py +99 -0
- phoenix/datasets/{evaluators.py → evaluators/llm_evaluators.py} +75 -106
- phoenix/datasets/evaluators/utils.py +292 -0
- phoenix/datasets/experiments.py +148 -82
- phoenix/datasets/tracing.py +19 -0
- phoenix/datasets/types.py +18 -52
- phoenix/db/insertion/dataset.py +19 -16
- phoenix/db/migrations/versions/10460e46d750_datasets.py +2 -2
- phoenix/db/models.py +8 -3
- phoenix/server/api/context.py +2 -0
- phoenix/server/api/dataloaders/__init__.py +2 -0
- phoenix/server/api/dataloaders/experiment_run_counts.py +42 -0
- phoenix/server/api/helpers/dataset_helpers.py +8 -7
- phoenix/server/api/input_types/ClearProjectInput.py +15 -0
- phoenix/server/api/mutations/project_mutations.py +9 -4
- phoenix/server/api/routers/v1/datasets.py +146 -42
- phoenix/server/api/routers/v1/experiment_evaluations.py +1 -0
- phoenix/server/api/routers/v1/experiment_runs.py +2 -2
- phoenix/server/api/types/Experiment.py +5 -0
- phoenix/server/api/types/ExperimentRun.py +1 -1
- phoenix/server/api/types/ExperimentRunAnnotation.py +1 -1
- phoenix/server/api/types/Span.py +1 -0
- phoenix/server/app.py +2 -0
- phoenix/server/static/index.js +638 -588
- phoenix/session/client.py +124 -2
- phoenix/trace/schemas.py +1 -2
- phoenix/version.py +1 -1
- {arize_phoenix-4.4.4rc3.dist-info → arize_phoenix-4.4.4rc5.dist-info}/WHEEL +0 -0
- {arize_phoenix-4.4.4rc3.dist-info → arize_phoenix-4.4.4rc5.dist-info}/licenses/IP_NOTICE +0 -0
- {arize_phoenix-4.4.4rc3.dist-info → arize_phoenix-4.4.4rc5.dist-info}/licenses/LICENSE +0 -0
phoenix/session/client.py
CHANGED
|
@@ -15,6 +15,7 @@ from typing import (
|
|
|
15
15
|
Literal,
|
|
16
16
|
Mapping,
|
|
17
17
|
Optional,
|
|
18
|
+
Sequence,
|
|
18
19
|
Tuple,
|
|
19
20
|
Union,
|
|
20
21
|
cast,
|
|
@@ -24,6 +25,7 @@ from urllib.parse import quote, urljoin
|
|
|
24
25
|
import httpx
|
|
25
26
|
import pandas as pd
|
|
26
27
|
import pyarrow as pa
|
|
28
|
+
from httpx import HTTPStatusError
|
|
27
29
|
from opentelemetry.proto.collector.trace.v1.trace_service_pb2 import ExportTraceServiceRequest
|
|
28
30
|
from opentelemetry.proto.common.v1.common_pb2 import AnyValue, KeyValue
|
|
29
31
|
from opentelemetry.proto.resource.v1.resource_pb2 import Resource
|
|
@@ -48,6 +50,8 @@ from phoenix.trace.otel import encode_span_to_otlp
|
|
|
48
50
|
|
|
49
51
|
logger = logging.getLogger(__name__)
|
|
50
52
|
|
|
53
|
+
DatasetAction: TypeAlias = Literal["create", "append"]
|
|
54
|
+
|
|
51
55
|
|
|
52
56
|
class Client(TraceDataExtractor):
|
|
53
57
|
def __init__(
|
|
@@ -88,6 +92,23 @@ class Client(TraceDataExtractor):
|
|
|
88
92
|
if warn_if_server_not_running:
|
|
89
93
|
self._warn_if_phoenix_is_not_running()
|
|
90
94
|
|
|
95
|
+
@property
|
|
96
|
+
def web_url(self) -> str:
|
|
97
|
+
"""
|
|
98
|
+
Return the web URL of the Phoenix UI. This is different from the base
|
|
99
|
+
URL in the cases where there is a proxy like colab
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
Returns:
|
|
103
|
+
str: A fully qualified URL to the Phoenix UI.
|
|
104
|
+
"""
|
|
105
|
+
# Avoid circular import
|
|
106
|
+
from phoenix.session.session import active_session
|
|
107
|
+
|
|
108
|
+
if session := active_session():
|
|
109
|
+
return session.url
|
|
110
|
+
return self._base_url
|
|
111
|
+
|
|
91
112
|
def query_spans(
|
|
92
113
|
self,
|
|
93
114
|
*queries: SpanQuery,
|
|
@@ -407,6 +428,91 @@ class Client(TraceDataExtractor):
|
|
|
407
428
|
index_col="example_id",
|
|
408
429
|
)
|
|
409
430
|
|
|
431
|
+
def create_examples(
|
|
432
|
+
self,
|
|
433
|
+
*,
|
|
434
|
+
dataset_name: str,
|
|
435
|
+
inputs: Iterable[Mapping[str, Any]],
|
|
436
|
+
outputs: Iterable[Mapping[str, Any]] = (),
|
|
437
|
+
metadata: Iterable[Mapping[str, Any]] = (),
|
|
438
|
+
dataset_description: Optional[str] = None,
|
|
439
|
+
) -> Dataset:
|
|
440
|
+
"""
|
|
441
|
+
Upload examples as dataset to the Phoenix server.
|
|
442
|
+
|
|
443
|
+
Args:
|
|
444
|
+
dataset_name: (str): Name of the dataset
|
|
445
|
+
inputs (Iterable[Mapping[str, Any]]): List of dictionaries object each
|
|
446
|
+
corresponding to an example in the dataset.
|
|
447
|
+
outputs (Iterable[Mapping[str, Any]]): List of dictionaries object each
|
|
448
|
+
corresponding to an example in the dataset.
|
|
449
|
+
metadata (Iterable[Mapping[str, Any]]): List of dictionaries object each
|
|
450
|
+
corresponding to an example in the dataset.
|
|
451
|
+
dataset_description: (Optional[str]): Description of the dataset.
|
|
452
|
+
|
|
453
|
+
Returns:
|
|
454
|
+
A Dataset object with the uploaded examples.
|
|
455
|
+
"""
|
|
456
|
+
# convert to list to avoid issues with pandas Series
|
|
457
|
+
inputs, outputs, metadata = list(inputs), list(outputs), list(metadata)
|
|
458
|
+
if not inputs or not _is_all_dict(inputs):
|
|
459
|
+
raise ValueError(
|
|
460
|
+
"`inputs` should be a non-empty sequence containing only dictionary objects"
|
|
461
|
+
)
|
|
462
|
+
for name, seq in {"outputs": outputs, "metadata": metadata}.items():
|
|
463
|
+
if seq and not (len(seq) == len(inputs) and _is_all_dict(seq)):
|
|
464
|
+
raise ValueError(
|
|
465
|
+
f"`{name}` should be a sequence of the same length as `inputs` "
|
|
466
|
+
"containing only dictionary objects"
|
|
467
|
+
)
|
|
468
|
+
action: DatasetAction = "create"
|
|
469
|
+
print("📤 Uploading dataset...")
|
|
470
|
+
response = self._client.post(
|
|
471
|
+
url=urljoin(self._base_url, "v1/datasets/upload"),
|
|
472
|
+
headers={"Content-Encoding": "gzip"},
|
|
473
|
+
json={
|
|
474
|
+
"action": action,
|
|
475
|
+
"name": dataset_name,
|
|
476
|
+
"description": dataset_description,
|
|
477
|
+
"inputs": inputs,
|
|
478
|
+
"outputs": outputs,
|
|
479
|
+
"metadata": metadata,
|
|
480
|
+
},
|
|
481
|
+
params={"sync": True},
|
|
482
|
+
)
|
|
483
|
+
try:
|
|
484
|
+
response.raise_for_status()
|
|
485
|
+
except HTTPStatusError as e:
|
|
486
|
+
if msg := response.text:
|
|
487
|
+
raise DatasetUploadError(msg) from e
|
|
488
|
+
raise
|
|
489
|
+
data = response.json()["data"]
|
|
490
|
+
dataset_id = data["dataset_id"]
|
|
491
|
+
response = self._client.get(
|
|
492
|
+
url=urljoin(self._base_url, f"v1/datasets/{dataset_id}/examples")
|
|
493
|
+
)
|
|
494
|
+
response.raise_for_status()
|
|
495
|
+
data = response.json()["data"]
|
|
496
|
+
version_id = data["version_id"]
|
|
497
|
+
examples = data["examples"]
|
|
498
|
+
print(f"💾 Examples uploaded: {self.web_url}datasets/{dataset_id}/examples")
|
|
499
|
+
print(f"🗄️ Dataset version ID: {version_id}")
|
|
500
|
+
|
|
501
|
+
return Dataset(
|
|
502
|
+
id=dataset_id,
|
|
503
|
+
version_id=version_id,
|
|
504
|
+
examples=[
|
|
505
|
+
Example(
|
|
506
|
+
id=example["id"],
|
|
507
|
+
input=example["input"],
|
|
508
|
+
output=example["output"],
|
|
509
|
+
metadata=example["metadata"],
|
|
510
|
+
updated_at=datetime.fromisoformat(example["updated_at"]),
|
|
511
|
+
)
|
|
512
|
+
for example in examples
|
|
513
|
+
],
|
|
514
|
+
)
|
|
515
|
+
|
|
410
516
|
def upload_dataset(
|
|
411
517
|
self,
|
|
412
518
|
table: Union[str, Path, pd.DataFrame],
|
|
@@ -414,7 +520,7 @@ class Client(TraceDataExtractor):
|
|
|
414
520
|
*,
|
|
415
521
|
name: str,
|
|
416
522
|
input_keys: Iterable[str],
|
|
417
|
-
output_keys: Iterable[str],
|
|
523
|
+
output_keys: Iterable[str] = (),
|
|
418
524
|
metadata_keys: Iterable[str] = (),
|
|
419
525
|
description: Optional[str] = None,
|
|
420
526
|
action: Literal["create", "append"] = "create",
|
|
@@ -457,6 +563,7 @@ class Client(TraceDataExtractor):
|
|
|
457
563
|
file = _prepare_csv(Path(table), keys)
|
|
458
564
|
else:
|
|
459
565
|
assert_never(table)
|
|
566
|
+
print("📤 Uploading dataset...")
|
|
460
567
|
response = self._client.post(
|
|
461
568
|
url=urljoin(self._base_url, "v1/datasets/upload"),
|
|
462
569
|
files={"file": file},
|
|
@@ -470,7 +577,12 @@ class Client(TraceDataExtractor):
|
|
|
470
577
|
},
|
|
471
578
|
params={"sync": True},
|
|
472
579
|
)
|
|
473
|
-
|
|
580
|
+
try:
|
|
581
|
+
response.raise_for_status()
|
|
582
|
+
except HTTPStatusError as e:
|
|
583
|
+
if msg := response.text:
|
|
584
|
+
raise DatasetUploadError(msg) from e
|
|
585
|
+
raise
|
|
474
586
|
data = response.json()["data"]
|
|
475
587
|
dataset_id = data["dataset_id"]
|
|
476
588
|
response = self._client.get(
|
|
@@ -480,6 +592,9 @@ class Client(TraceDataExtractor):
|
|
|
480
592
|
data = response.json()["data"]
|
|
481
593
|
version_id = data["version_id"]
|
|
482
594
|
examples = data["examples"]
|
|
595
|
+
print(f"💾 Examples uploaded: {self.web_url}datasets/{dataset_id}/examples")
|
|
596
|
+
print(f"🗄️ Dataset version ID: {version_id}")
|
|
597
|
+
|
|
483
598
|
return Dataset(
|
|
484
599
|
id=dataset_id,
|
|
485
600
|
version_id=version_id,
|
|
@@ -547,3 +662,10 @@ def _prepare_pyarrow(
|
|
|
547
662
|
|
|
548
663
|
def _to_iso_format(value: Optional[datetime]) -> Optional[str]:
|
|
549
664
|
return value.isoformat() if value else None
|
|
665
|
+
|
|
666
|
+
|
|
667
|
+
def _is_all_dict(seq: Sequence[Any]) -> bool:
|
|
668
|
+
return all(map(lambda obj: isinstance(obj, dict), seq))
|
|
669
|
+
|
|
670
|
+
|
|
671
|
+
class DatasetUploadError(Exception): ...
|
phoenix/trace/schemas.py
CHANGED
|
@@ -29,8 +29,6 @@ class SpanKind(Enum):
|
|
|
29
29
|
"""
|
|
30
30
|
SpanKind is loosely inspired by OpenTelemetry's SpanKind
|
|
31
31
|
It captures the type of work that a Span encapsulates.
|
|
32
|
-
|
|
33
|
-
NB: this is actively under construction
|
|
34
32
|
"""
|
|
35
33
|
|
|
36
34
|
TOOL = "TOOL"
|
|
@@ -40,6 +38,7 @@ class SpanKind(Enum):
|
|
|
40
38
|
EMBEDDING = "EMBEDDING"
|
|
41
39
|
AGENT = "AGENT"
|
|
42
40
|
RERANKER = "RERANKER"
|
|
41
|
+
EVALUATOR = "EVALUATOR"
|
|
43
42
|
UNKNOWN = "UNKNOWN"
|
|
44
43
|
|
|
45
44
|
def __str__(self) -> str:
|
phoenix/version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "4.4.
|
|
1
|
+
__version__ = "4.4.4rc5"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|