arize-phoenix 3.25.0__py3-none-any.whl → 4.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of arize-phoenix might be problematic. Click here for more details.
- {arize_phoenix-3.25.0.dist-info → arize_phoenix-4.0.1.dist-info}/METADATA +26 -4
- {arize_phoenix-3.25.0.dist-info → arize_phoenix-4.0.1.dist-info}/RECORD +80 -75
- phoenix/__init__.py +9 -5
- phoenix/config.py +109 -53
- phoenix/datetime_utils.py +18 -1
- phoenix/db/README.md +25 -0
- phoenix/db/__init__.py +4 -0
- phoenix/db/alembic.ini +119 -0
- phoenix/db/bulk_inserter.py +206 -0
- phoenix/db/engines.py +152 -0
- phoenix/db/helpers.py +47 -0
- phoenix/db/insertion/evaluation.py +209 -0
- phoenix/db/insertion/helpers.py +51 -0
- phoenix/db/insertion/span.py +142 -0
- phoenix/db/migrate.py +71 -0
- phoenix/db/migrations/env.py +121 -0
- phoenix/db/migrations/script.py.mako +26 -0
- phoenix/db/migrations/versions/cf03bd6bae1d_init.py +280 -0
- phoenix/db/models.py +371 -0
- phoenix/exceptions.py +5 -1
- phoenix/server/api/context.py +40 -3
- phoenix/server/api/dataloaders/__init__.py +97 -0
- phoenix/server/api/dataloaders/cache/__init__.py +3 -0
- phoenix/server/api/dataloaders/cache/two_tier_cache.py +67 -0
- phoenix/server/api/dataloaders/document_evaluation_summaries.py +152 -0
- phoenix/server/api/dataloaders/document_evaluations.py +37 -0
- phoenix/server/api/dataloaders/document_retrieval_metrics.py +98 -0
- phoenix/server/api/dataloaders/evaluation_summaries.py +151 -0
- phoenix/server/api/dataloaders/latency_ms_quantile.py +198 -0
- phoenix/server/api/dataloaders/min_start_or_max_end_times.py +93 -0
- phoenix/server/api/dataloaders/record_counts.py +125 -0
- phoenix/server/api/dataloaders/span_descendants.py +64 -0
- phoenix/server/api/dataloaders/span_evaluations.py +37 -0
- phoenix/server/api/dataloaders/token_counts.py +138 -0
- phoenix/server/api/dataloaders/trace_evaluations.py +37 -0
- phoenix/server/api/input_types/SpanSort.py +138 -68
- phoenix/server/api/routers/v1/__init__.py +11 -0
- phoenix/server/api/routers/v1/evaluations.py +275 -0
- phoenix/server/api/routers/v1/spans.py +126 -0
- phoenix/server/api/routers/v1/traces.py +82 -0
- phoenix/server/api/schema.py +112 -48
- phoenix/server/api/types/DocumentEvaluationSummary.py +1 -1
- phoenix/server/api/types/Evaluation.py +29 -12
- phoenix/server/api/types/EvaluationSummary.py +29 -44
- phoenix/server/api/types/MimeType.py +2 -2
- phoenix/server/api/types/Model.py +9 -9
- phoenix/server/api/types/Project.py +240 -171
- phoenix/server/api/types/Span.py +87 -131
- phoenix/server/api/types/Trace.py +29 -20
- phoenix/server/api/types/pagination.py +151 -10
- phoenix/server/app.py +263 -35
- phoenix/server/grpc_server.py +93 -0
- phoenix/server/main.py +75 -60
- phoenix/server/openapi/docs.py +218 -0
- phoenix/server/prometheus.py +23 -7
- phoenix/server/static/index.js +662 -643
- phoenix/server/telemetry.py +68 -0
- phoenix/services.py +4 -0
- phoenix/session/client.py +34 -30
- phoenix/session/data_extractor.py +8 -3
- phoenix/session/session.py +176 -155
- phoenix/settings.py +13 -0
- phoenix/trace/attributes.py +349 -0
- phoenix/trace/dsl/README.md +116 -0
- phoenix/trace/dsl/filter.py +660 -192
- phoenix/trace/dsl/helpers.py +24 -5
- phoenix/trace/dsl/query.py +562 -185
- phoenix/trace/fixtures.py +69 -7
- phoenix/trace/otel.py +44 -200
- phoenix/trace/schemas.py +14 -8
- phoenix/trace/span_evaluations.py +5 -2
- phoenix/utilities/__init__.py +0 -26
- phoenix/utilities/span_store.py +0 -23
- phoenix/version.py +1 -1
- phoenix/core/project.py +0 -773
- phoenix/core/traces.py +0 -96
- phoenix/datasets/dataset.py +0 -214
- phoenix/datasets/fixtures.py +0 -24
- phoenix/datasets/schema.py +0 -31
- phoenix/experimental/evals/__init__.py +0 -73
- phoenix/experimental/evals/evaluators.py +0 -413
- phoenix/experimental/evals/functions/__init__.py +0 -4
- phoenix/experimental/evals/functions/classify.py +0 -453
- phoenix/experimental/evals/functions/executor.py +0 -353
- phoenix/experimental/evals/functions/generate.py +0 -138
- phoenix/experimental/evals/functions/processing.py +0 -76
- phoenix/experimental/evals/models/__init__.py +0 -14
- phoenix/experimental/evals/models/anthropic.py +0 -175
- phoenix/experimental/evals/models/base.py +0 -170
- phoenix/experimental/evals/models/bedrock.py +0 -221
- phoenix/experimental/evals/models/litellm.py +0 -134
- phoenix/experimental/evals/models/openai.py +0 -453
- phoenix/experimental/evals/models/rate_limiters.py +0 -246
- phoenix/experimental/evals/models/vertex.py +0 -173
- phoenix/experimental/evals/models/vertexai.py +0 -186
- phoenix/experimental/evals/retrievals.py +0 -96
- phoenix/experimental/evals/templates/__init__.py +0 -50
- phoenix/experimental/evals/templates/default_templates.py +0 -472
- phoenix/experimental/evals/templates/template.py +0 -195
- phoenix/experimental/evals/utils/__init__.py +0 -172
- phoenix/experimental/evals/utils/threads.py +0 -27
- phoenix/server/api/routers/evaluation_handler.py +0 -110
- phoenix/server/api/routers/span_handler.py +0 -70
- phoenix/server/api/routers/trace_handler.py +0 -60
- phoenix/storage/span_store/__init__.py +0 -23
- phoenix/storage/span_store/text_file.py +0 -85
- phoenix/trace/dsl/missing.py +0 -60
- {arize_phoenix-3.25.0.dist-info → arize_phoenix-4.0.1.dist-info}/WHEEL +0 -0
- {arize_phoenix-3.25.0.dist-info → arize_phoenix-4.0.1.dist-info}/licenses/IP_NOTICE +0 -0
- {arize_phoenix-3.25.0.dist-info → arize_phoenix-4.0.1.dist-info}/licenses/LICENSE +0 -0
- /phoenix/{datasets → db/insertion}/__init__.py +0 -0
- /phoenix/{experimental → db/migrations}/__init__.py +0 -0
- /phoenix/{storage → server/openapi}/__init__.py +0 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from typing import TYPE_CHECKING
|
|
3
|
+
|
|
4
|
+
from phoenix.config import (
|
|
5
|
+
ENV_PHOENIX_SERVER_INSTRUMENTATION_OTLP_TRACE_COLLECTOR_GRPC_ENDPOINT,
|
|
6
|
+
ENV_PHOENIX_SERVER_INSTRUMENTATION_OTLP_TRACE_COLLECTOR_HTTP_ENDPOINT,
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from opentelemetry.trace import TracerProvider
|
|
11
|
+
from logging import getLogger
|
|
12
|
+
|
|
13
|
+
logger = getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def normalize_http_collector_endpoint(endpoint: str) -> str:
|
|
17
|
+
normalized_endpoint = endpoint
|
|
18
|
+
if not normalized_endpoint.startswith("http://") and not normalized_endpoint.startswith(
|
|
19
|
+
"https://"
|
|
20
|
+
):
|
|
21
|
+
logger.warning(
|
|
22
|
+
"HTTP collector endpoint should include the protocol (http:// or https://)."
|
|
23
|
+
"Assuming http."
|
|
24
|
+
)
|
|
25
|
+
# assume http if no protocol is provided
|
|
26
|
+
normalized_endpoint = f"http://{endpoint}"
|
|
27
|
+
if normalized_endpoint.endswith("/v1/traces"):
|
|
28
|
+
logger.warning(
|
|
29
|
+
"HTTP collector endpoint should not include the /v1/traces path. Removing it."
|
|
30
|
+
)
|
|
31
|
+
# remove the /v1/traces path
|
|
32
|
+
normalized_endpoint = normalized_endpoint[: -len("/v1/traces")]
|
|
33
|
+
# remove trailing slashes
|
|
34
|
+
normalized_endpoint = normalized_endpoint.rstrip("/")
|
|
35
|
+
return normalized_endpoint
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def initialize_opentelemetry_tracer_provider() -> "TracerProvider":
|
|
39
|
+
logger.info("Initializing OpenTelemetry tracer provider")
|
|
40
|
+
from opentelemetry.sdk import trace as trace_sdk
|
|
41
|
+
from opentelemetry.sdk.resources import Resource
|
|
42
|
+
from opentelemetry.sdk.trace.export import BatchSpanProcessor
|
|
43
|
+
from opentelemetry.semconv.resource import ResourceAttributes
|
|
44
|
+
|
|
45
|
+
tracer_provider = trace_sdk.TracerProvider(
|
|
46
|
+
resource=Resource(attributes={ResourceAttributes.SERVICE_NAME: "arize-phoenix-server"})
|
|
47
|
+
)
|
|
48
|
+
if http_endpoint := os.getenv(
|
|
49
|
+
ENV_PHOENIX_SERVER_INSTRUMENTATION_OTLP_TRACE_COLLECTOR_HTTP_ENDPOINT
|
|
50
|
+
):
|
|
51
|
+
logger.info(f"Using HTTP collector endpoint: {http_endpoint}")
|
|
52
|
+
http_endpoint = normalize_http_collector_endpoint(http_endpoint) + "/v1/traces"
|
|
53
|
+
from opentelemetry.exporter.otlp.proto.http.trace_exporter import (
|
|
54
|
+
OTLPSpanExporter as HttpExporter,
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
tracer_provider.add_span_processor(BatchSpanProcessor(HttpExporter(http_endpoint)))
|
|
58
|
+
if grpc_endpoint := os.getenv(
|
|
59
|
+
ENV_PHOENIX_SERVER_INSTRUMENTATION_OTLP_TRACE_COLLECTOR_GRPC_ENDPOINT
|
|
60
|
+
):
|
|
61
|
+
logger.info(f"Using gRPC collector endpoint: {grpc_endpoint}")
|
|
62
|
+
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import (
|
|
63
|
+
OTLPSpanExporter as GrpcExporter,
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
tracer_provider.add_span_processor(BatchSpanProcessor(GrpcExporter(grpc_endpoint)))
|
|
67
|
+
logger.info("🔭 OpenTelemetry tracer provider initialized")
|
|
68
|
+
return tracer_provider
|
phoenix/services.py
CHANGED
|
@@ -107,6 +107,7 @@ class AppService(Service):
|
|
|
107
107
|
|
|
108
108
|
def __init__(
|
|
109
109
|
self,
|
|
110
|
+
database_url: str,
|
|
110
111
|
export_path: Path,
|
|
111
112
|
host: str,
|
|
112
113
|
port: int,
|
|
@@ -117,6 +118,7 @@ class AppService(Service):
|
|
|
117
118
|
corpus_dataset_name: Optional[str],
|
|
118
119
|
trace_dataset_name: Optional[str],
|
|
119
120
|
):
|
|
121
|
+
self.database_url = database_url
|
|
120
122
|
self.export_path = export_path
|
|
121
123
|
self.host = host
|
|
122
124
|
self.port = port
|
|
@@ -133,6 +135,8 @@ class AppService(Service):
|
|
|
133
135
|
command = [
|
|
134
136
|
sys.executable,
|
|
135
137
|
"main.py",
|
|
138
|
+
"--database-url",
|
|
139
|
+
self.database_url,
|
|
136
140
|
"--export_path",
|
|
137
141
|
str(self.export_path),
|
|
138
142
|
"--host",
|
phoenix/session/client.py
CHANGED
|
@@ -3,7 +3,7 @@ import logging
|
|
|
3
3
|
import weakref
|
|
4
4
|
from datetime import datetime
|
|
5
5
|
from io import BytesIO
|
|
6
|
-
from typing import List, Optional, Union, cast
|
|
6
|
+
from typing import Any, List, Optional, Union, cast
|
|
7
7
|
from urllib.parse import urljoin
|
|
8
8
|
|
|
9
9
|
import pandas as pd
|
|
@@ -15,14 +15,14 @@ from opentelemetry.proto.trace.v1.trace_pb2 import ResourceSpans, ScopeSpans
|
|
|
15
15
|
from pyarrow import ArrowInvalid
|
|
16
16
|
from requests import Session
|
|
17
17
|
|
|
18
|
-
import phoenix as px
|
|
19
18
|
from phoenix.config import (
|
|
20
19
|
get_env_collector_endpoint,
|
|
21
20
|
get_env_host,
|
|
22
21
|
get_env_port,
|
|
23
22
|
get_env_project_name,
|
|
24
23
|
)
|
|
25
|
-
from phoenix.
|
|
24
|
+
from phoenix.datetime_utils import normalize_datetime
|
|
25
|
+
from phoenix.session.data_extractor import DEFAULT_SPAN_LIMIT, TraceDataExtractor
|
|
26
26
|
from phoenix.trace import Evaluations, TraceDataset
|
|
27
27
|
from phoenix.trace.dsl import SpanQuery
|
|
28
28
|
from phoenix.trace.otel import encode_span_to_otlp
|
|
@@ -35,7 +35,8 @@ class Client(TraceDataExtractor):
|
|
|
35
35
|
self,
|
|
36
36
|
*,
|
|
37
37
|
endpoint: Optional[str] = None,
|
|
38
|
-
|
|
38
|
+
warn_if_server_not_running: bool = True,
|
|
39
|
+
**kwargs: Any, # for backward-compatibility
|
|
39
40
|
):
|
|
40
41
|
"""
|
|
41
42
|
Client for connecting to a Phoenix server.
|
|
@@ -43,12 +44,14 @@ class Client(TraceDataExtractor):
|
|
|
43
44
|
Args:
|
|
44
45
|
endpoint (str, optional): Phoenix server endpoint, e.g. http://localhost:6006. If not
|
|
45
46
|
provided, the endpoint will be inferred from the environment variables.
|
|
46
|
-
use_active_session_if_available (bool, optional): If px.active_session() is available
|
|
47
|
-
in the same runtime, e.g. the same Jupyter notebook, delegate the request to the
|
|
48
|
-
active session instead of making HTTP requests. This argument is set to False if
|
|
49
|
-
endpoint is provided explicitly.
|
|
50
47
|
"""
|
|
51
|
-
|
|
48
|
+
if kwargs.pop("use_active_session_if_available", None) is not None:
|
|
49
|
+
print(
|
|
50
|
+
"`use_active_session_if_available` is deprecated "
|
|
51
|
+
"and will be removed in the future."
|
|
52
|
+
)
|
|
53
|
+
if kwargs:
|
|
54
|
+
raise TypeError(f"Unexpected keyword arguments: {', '.join(kwargs)}")
|
|
52
55
|
host = get_env_host()
|
|
53
56
|
if host == "0.0.0.0":
|
|
54
57
|
host = "127.0.0.1"
|
|
@@ -57,16 +60,19 @@ class Client(TraceDataExtractor):
|
|
|
57
60
|
)
|
|
58
61
|
self._session = Session()
|
|
59
62
|
weakref.finalize(self, self._session.close)
|
|
60
|
-
if
|
|
63
|
+
if warn_if_server_not_running:
|
|
61
64
|
self._warn_if_phoenix_is_not_running()
|
|
62
65
|
|
|
63
66
|
def query_spans(
|
|
64
67
|
self,
|
|
65
68
|
*queries: SpanQuery,
|
|
66
69
|
start_time: Optional[datetime] = None,
|
|
67
|
-
|
|
70
|
+
end_time: Optional[datetime] = None,
|
|
71
|
+
limit: Optional[int] = DEFAULT_SPAN_LIMIT,
|
|
68
72
|
root_spans_only: Optional[bool] = None,
|
|
69
73
|
project_name: Optional[str] = None,
|
|
74
|
+
# Deprecated
|
|
75
|
+
stop_time: Optional[datetime] = None,
|
|
70
76
|
) -> Optional[Union[pd.DataFrame, List[pd.DataFrame]]]:
|
|
71
77
|
"""
|
|
72
78
|
Queries spans from the Phoenix server or active session based on specified criteria.
|
|
@@ -74,7 +80,7 @@ class Client(TraceDataExtractor):
|
|
|
74
80
|
Args:
|
|
75
81
|
queries (SpanQuery): One or more SpanQuery objects defining the query criteria.
|
|
76
82
|
start_time (datetime, optional): The start time for the query range. Default None.
|
|
77
|
-
|
|
83
|
+
end_time (datetime, optional): The end time for the query range. Default None.
|
|
78
84
|
root_spans_only (bool, optional): If True, only root spans are returned. Default None.
|
|
79
85
|
project_name (str, optional): The project name to query spans for. This can be set
|
|
80
86
|
using environment variables. If not provided, falls back to the default project.
|
|
@@ -86,22 +92,21 @@ class Client(TraceDataExtractor):
|
|
|
86
92
|
project_name = project_name or get_env_project_name()
|
|
87
93
|
if not queries:
|
|
88
94
|
queries = (SpanQuery(),)
|
|
89
|
-
if
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
stop_time=stop_time,
|
|
94
|
-
root_spans_only=root_spans_only,
|
|
95
|
-
project_name=project_name,
|
|
95
|
+
if stop_time is not None:
|
|
96
|
+
# Deprecated. Raise a warning
|
|
97
|
+
logger.warning(
|
|
98
|
+
"stop_time is deprecated. Use end_time instead.",
|
|
96
99
|
)
|
|
97
|
-
|
|
100
|
+
end_time = end_time or stop_time
|
|
101
|
+
response = self._session.post(
|
|
98
102
|
url=urljoin(self._base_url, "/v1/spans"),
|
|
103
|
+
params={"project-name": project_name},
|
|
99
104
|
json={
|
|
100
105
|
"queries": [q.to_dict() for q in queries],
|
|
101
|
-
"start_time": _to_iso_format(start_time),
|
|
102
|
-
"
|
|
106
|
+
"start_time": _to_iso_format(normalize_datetime(start_time)),
|
|
107
|
+
"end_time": _to_iso_format(normalize_datetime(end_time)),
|
|
108
|
+
"limit": limit,
|
|
103
109
|
"root_spans_only": root_spans_only,
|
|
104
|
-
"project_name": project_name,
|
|
105
110
|
},
|
|
106
111
|
)
|
|
107
112
|
if response.status_code == 404:
|
|
@@ -140,11 +145,9 @@ class Client(TraceDataExtractor):
|
|
|
140
145
|
empty list if no evaluations are found.
|
|
141
146
|
"""
|
|
142
147
|
project_name = project_name or get_env_project_name()
|
|
143
|
-
if self._use_active_session_if_available and (session := px.active_session()):
|
|
144
|
-
return session.get_evaluations(project_name=project_name)
|
|
145
148
|
response = self._session.get(
|
|
146
149
|
urljoin(self._base_url, "/v1/evaluations"),
|
|
147
|
-
|
|
150
|
+
params={"project-name": project_name},
|
|
148
151
|
)
|
|
149
152
|
if response.status_code == 404:
|
|
150
153
|
logger.info("No evaluations found.")
|
|
@@ -171,7 +174,7 @@ class Client(TraceDataExtractor):
|
|
|
171
174
|
f"with `import phoenix as px; px.launch_app()`"
|
|
172
175
|
)
|
|
173
176
|
|
|
174
|
-
def log_evaluations(self, *evals: Evaluations,
|
|
177
|
+
def log_evaluations(self, *evals: Evaluations, **kwargs: Any) -> None:
|
|
175
178
|
"""
|
|
176
179
|
Logs evaluation data to the Phoenix server.
|
|
177
180
|
|
|
@@ -184,13 +187,14 @@ class Client(TraceDataExtractor):
|
|
|
184
187
|
Returns:
|
|
185
188
|
None
|
|
186
189
|
"""
|
|
187
|
-
project_name
|
|
190
|
+
if kwargs.pop("project_name", None) is not None:
|
|
191
|
+
print("Keyword argument `project_name` is no longer necessary and is ignored.")
|
|
192
|
+
if kwargs:
|
|
193
|
+
raise TypeError(f"Unexpected keyword arguments: {', '.join(kwargs)}")
|
|
188
194
|
for evaluation in evals:
|
|
189
195
|
table = evaluation.to_pyarrow_table()
|
|
190
196
|
sink = pa.BufferOutputStream()
|
|
191
197
|
headers = {"content-type": "application/x-pandas-arrow"}
|
|
192
|
-
if project_name:
|
|
193
|
-
headers["project-name"] = project_name
|
|
194
198
|
with pa.ipc.new_stream(sink, table.schema) as writer:
|
|
195
199
|
writer.write_table(table)
|
|
196
200
|
self._session.post(
|
|
@@ -8,6 +8,8 @@ from phoenix.trace import Evaluations
|
|
|
8
8
|
from phoenix.trace.dsl import SpanQuery
|
|
9
9
|
from phoenix.trace.trace_dataset import TraceDataset
|
|
10
10
|
|
|
11
|
+
DEFAULT_SPAN_LIMIT = 1000
|
|
12
|
+
|
|
11
13
|
|
|
12
14
|
class TraceDataExtractor(ABC):
|
|
13
15
|
"""
|
|
@@ -20,7 +22,8 @@ class TraceDataExtractor(ABC):
|
|
|
20
22
|
self,
|
|
21
23
|
*queries: SpanQuery,
|
|
22
24
|
start_time: Optional[datetime] = None,
|
|
23
|
-
|
|
25
|
+
end_time: Optional[datetime] = None,
|
|
26
|
+
limit: Optional[int] = DEFAULT_SPAN_LIMIT,
|
|
24
27
|
root_spans_only: Optional[bool] = None,
|
|
25
28
|
project_name: Optional[str] = None,
|
|
26
29
|
) -> Optional[Union[pd.DataFrame, List[pd.DataFrame]]]: ...
|
|
@@ -30,7 +33,8 @@ class TraceDataExtractor(ABC):
|
|
|
30
33
|
filter_condition: Optional[str] = None,
|
|
31
34
|
*,
|
|
32
35
|
start_time: Optional[datetime] = None,
|
|
33
|
-
|
|
36
|
+
end_time: Optional[datetime] = None,
|
|
37
|
+
limit: Optional[int] = DEFAULT_SPAN_LIMIT,
|
|
34
38
|
root_spans_only: Optional[bool] = None,
|
|
35
39
|
project_name: Optional[str] = None,
|
|
36
40
|
) -> Optional[pd.DataFrame]:
|
|
@@ -39,7 +43,8 @@ class TraceDataExtractor(ABC):
|
|
|
39
43
|
self.query_spans(
|
|
40
44
|
SpanQuery().where(filter_condition or ""),
|
|
41
45
|
start_time=start_time,
|
|
42
|
-
|
|
46
|
+
end_time=end_time,
|
|
47
|
+
limit=limit,
|
|
43
48
|
root_spans_only=root_spans_only,
|
|
44
49
|
project_name=project_name,
|
|
45
50
|
),
|