arize-phoenix 7.12.3__py3-none-any.whl → 8.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-7.12.3.dist-info → arize_phoenix-8.0.1.dist-info}/METADATA +31 -28
- {arize_phoenix-7.12.3.dist-info → arize_phoenix-8.0.1.dist-info}/RECORD +70 -47
- phoenix/db/migrations/versions/bc8fea3c2bc8_add_prompt_tables.py +197 -0
- phoenix/db/models.py +307 -0
- phoenix/db/types/__init__.py +0 -0
- phoenix/db/types/identifier.py +7 -0
- phoenix/db/types/model_provider.py +8 -0
- phoenix/server/api/context.py +2 -0
- phoenix/server/api/dataloaders/__init__.py +2 -0
- phoenix/server/api/dataloaders/prompt_version_sequence_number.py +35 -0
- phoenix/server/api/helpers/jsonschema.py +135 -0
- phoenix/server/api/helpers/playground_clients.py +15 -15
- phoenix/server/api/helpers/playground_spans.py +9 -0
- phoenix/server/api/helpers/prompts/__init__.py +0 -0
- phoenix/server/api/helpers/prompts/conversions/__init__.py +0 -0
- phoenix/server/api/helpers/prompts/conversions/anthropic.py +87 -0
- phoenix/server/api/helpers/prompts/conversions/openai.py +78 -0
- phoenix/server/api/helpers/prompts/models.py +575 -0
- phoenix/server/api/input_types/ChatCompletionInput.py +9 -4
- phoenix/server/api/input_types/PromptTemplateOptions.py +10 -0
- phoenix/server/api/input_types/PromptVersionInput.py +133 -0
- phoenix/server/api/mutations/__init__.py +6 -0
- phoenix/server/api/mutations/chat_mutations.py +18 -16
- phoenix/server/api/mutations/prompt_label_mutations.py +191 -0
- phoenix/server/api/mutations/prompt_mutations.py +312 -0
- phoenix/server/api/mutations/prompt_version_tag_mutations.py +148 -0
- phoenix/server/api/mutations/user_mutations.py +7 -6
- phoenix/server/api/openapi/schema.py +1 -0
- phoenix/server/api/queries.py +84 -31
- phoenix/server/api/routers/oauth2.py +3 -2
- phoenix/server/api/routers/v1/__init__.py +2 -0
- phoenix/server/api/routers/v1/datasets.py +1 -1
- phoenix/server/api/routers/v1/experiment_evaluations.py +1 -1
- phoenix/server/api/routers/v1/experiment_runs.py +1 -1
- phoenix/server/api/routers/v1/experiments.py +1 -1
- phoenix/server/api/routers/v1/models.py +45 -0
- phoenix/server/api/routers/v1/prompts.py +415 -0
- phoenix/server/api/routers/v1/spans.py +1 -1
- phoenix/server/api/routers/v1/traces.py +1 -1
- phoenix/server/api/routers/v1/utils.py +1 -1
- phoenix/server/api/subscriptions.py +21 -24
- phoenix/server/api/types/GenerativeProvider.py +4 -4
- phoenix/server/api/types/Identifier.py +15 -0
- phoenix/server/api/types/Project.py +5 -7
- phoenix/server/api/types/Prompt.py +134 -0
- phoenix/server/api/types/PromptLabel.py +41 -0
- phoenix/server/api/types/PromptVersion.py +148 -0
- phoenix/server/api/types/PromptVersionTag.py +27 -0
- phoenix/server/api/types/PromptVersionTemplate.py +148 -0
- phoenix/server/api/types/ResponseFormat.py +9 -0
- phoenix/server/api/types/ToolDefinition.py +9 -0
- phoenix/server/app.py +3 -0
- phoenix/server/static/.vite/manifest.json +45 -45
- phoenix/server/static/assets/components-B-qgPyHv.js +2699 -0
- phoenix/server/static/assets/index-D4KO1IcF.js +1125 -0
- phoenix/server/static/assets/pages-DdcuL3Rh.js +5634 -0
- phoenix/server/static/assets/vendor-DQp7CrDA.js +894 -0
- phoenix/server/static/assets/vendor-arizeai-C1nEIEQq.js +657 -0
- phoenix/server/static/assets/vendor-codemirror-BZXYUIkP.js +24 -0
- phoenix/server/static/assets/vendor-recharts-BUFpwCVD.js +59 -0
- phoenix/server/static/assets/{vendor-shiki-Cl9QBraO.js → vendor-shiki-C8L-c9jT.js} +2 -2
- phoenix/server/static/assets/{vendor-three-DwGkEfCM.js → vendor-three-C-AGeJYv.js} +1 -1
- phoenix/session/client.py +25 -21
- phoenix/utilities/client.py +6 -0
- phoenix/version.py +1 -1
- phoenix/server/api/input_types/TemplateOptions.py +0 -10
- phoenix/server/api/routers/v1/pydantic_compat.py +0 -78
- phoenix/server/api/types/TemplateLanguage.py +0 -10
- phoenix/server/static/assets/components-DckIzNmE.js +0 -2125
- phoenix/server/static/assets/index-Bf25Ogon.js +0 -113
- phoenix/server/static/assets/pages-DL7J9q9w.js +0 -4463
- phoenix/server/static/assets/vendor-DvC8cT4X.js +0 -894
- phoenix/server/static/assets/vendor-arizeai-Do1793cv.js +0 -662
- phoenix/server/static/assets/vendor-codemirror-BzwZPyJM.js +0 -24
- phoenix/server/static/assets/vendor-recharts-_Jb7JjhG.js +0 -59
- {arize_phoenix-7.12.3.dist-info → arize_phoenix-8.0.1.dist-info}/WHEEL +0 -0
- {arize_phoenix-7.12.3.dist-info → arize_phoenix-8.0.1.dist-info}/entry_points.txt +0 -0
- {arize_phoenix-7.12.3.dist-info → arize_phoenix-8.0.1.dist-info}/licenses/IP_NOTICE +0 -0
- {arize_phoenix-7.12.3.dist-info → arize_phoenix-8.0.1.dist-info}/licenses/LICENSE +0 -0
- /phoenix/server/static/assets/{vendor-DxkFTwjz.css → vendor-Cg6lcjUC.css} +0 -0
phoenix/session/client.py
CHANGED
|
@@ -2,7 +2,6 @@ import csv
|
|
|
2
2
|
import gzip
|
|
3
3
|
import logging
|
|
4
4
|
import re
|
|
5
|
-
import weakref
|
|
6
5
|
from collections import Counter
|
|
7
6
|
from collections.abc import Iterable, Mapping, Sequence
|
|
8
7
|
from datetime import datetime
|
|
@@ -84,11 +83,16 @@ class Client(TraceDataExtractor):
|
|
|
84
83
|
if host == "0.0.0.0":
|
|
85
84
|
host = "127.0.0.1"
|
|
86
85
|
base_url = endpoint or get_env_collector_endpoint() or f"http://{host}:{get_env_port()}"
|
|
87
|
-
self.
|
|
88
|
-
self._client = VersionedClient(headers=headers)
|
|
89
|
-
weakref.finalize(self, self._client.close)
|
|
86
|
+
self._client = VersionedClient(headers=headers, base_url=httpx.URL(base_url))
|
|
90
87
|
if warn_if_server_not_running:
|
|
91
88
|
self._warn_if_phoenix_is_not_running()
|
|
89
|
+
try:
|
|
90
|
+
# place import here temporarily before phoenix-client is fully published on pypi
|
|
91
|
+
from phoenix.client.resources.prompts import Prompts
|
|
92
|
+
|
|
93
|
+
self.prompts = Prompts(self._client)
|
|
94
|
+
except ImportError:
|
|
95
|
+
pass
|
|
92
96
|
|
|
93
97
|
@property
|
|
94
98
|
def web_url(self) -> str:
|
|
@@ -105,7 +109,7 @@ class Client(TraceDataExtractor):
|
|
|
105
109
|
|
|
106
110
|
if session := active_session():
|
|
107
111
|
return session.url
|
|
108
|
-
return self.
|
|
112
|
+
return str(self._client.base_url)
|
|
109
113
|
|
|
110
114
|
def query_spans(
|
|
111
115
|
self,
|
|
@@ -148,7 +152,7 @@ class Client(TraceDataExtractor):
|
|
|
148
152
|
try:
|
|
149
153
|
response = self._client.post(
|
|
150
154
|
headers={"accept": "application/json"},
|
|
151
|
-
url=
|
|
155
|
+
url="v1/spans",
|
|
152
156
|
params={
|
|
153
157
|
"project_name": project_name,
|
|
154
158
|
"project-name": project_name, # for backward-compatibility
|
|
@@ -236,7 +240,7 @@ class Client(TraceDataExtractor):
|
|
|
236
240
|
"""
|
|
237
241
|
project_name = project_name or get_env_project_name()
|
|
238
242
|
response = self._client.get(
|
|
239
|
-
url=
|
|
243
|
+
url="v1/evaluations",
|
|
240
244
|
params={
|
|
241
245
|
"project_name": project_name,
|
|
242
246
|
"project-name": project_name, # for backward-compatibility
|
|
@@ -261,10 +265,10 @@ class Client(TraceDataExtractor):
|
|
|
261
265
|
|
|
262
266
|
def _warn_if_phoenix_is_not_running(self) -> None:
|
|
263
267
|
try:
|
|
264
|
-
self._client.get(
|
|
268
|
+
self._client.get("arize_phoenix_version").raise_for_status()
|
|
265
269
|
except Exception:
|
|
266
270
|
logger.warning(
|
|
267
|
-
f"Arize Phoenix is not running on {self.
|
|
271
|
+
f"Arize Phoenix is not running on {self.web_url}. Launch Phoenix "
|
|
268
272
|
f"with `import phoenix as px; px.launch_app()`"
|
|
269
273
|
)
|
|
270
274
|
|
|
@@ -295,7 +299,7 @@ class Client(TraceDataExtractor):
|
|
|
295
299
|
with pa.ipc.new_stream(sink, table.schema) as writer:
|
|
296
300
|
writer.write_table(table)
|
|
297
301
|
self._client.post(
|
|
298
|
-
url=
|
|
302
|
+
url="v1/evaluations",
|
|
299
303
|
content=cast(bytes, sink.getvalue().to_pybytes()),
|
|
300
304
|
headers=headers,
|
|
301
305
|
timeout=timeout,
|
|
@@ -339,7 +343,7 @@ class Client(TraceDataExtractor):
|
|
|
339
343
|
serialized = otlp_span.SerializeToString()
|
|
340
344
|
content = gzip.compress(serialized)
|
|
341
345
|
response = self._client.post(
|
|
342
|
-
url=
|
|
346
|
+
url="v1/traces",
|
|
343
347
|
content=content,
|
|
344
348
|
headers={
|
|
345
349
|
"content-type": "application/x-protobuf",
|
|
@@ -360,7 +364,7 @@ class Client(TraceDataExtractor):
|
|
|
360
364
|
Dataset: The dataset object.
|
|
361
365
|
"""
|
|
362
366
|
response = self._client.get(
|
|
363
|
-
|
|
367
|
+
"v1/datasets",
|
|
364
368
|
params={"name": name},
|
|
365
369
|
)
|
|
366
370
|
response.raise_for_status()
|
|
@@ -402,7 +406,7 @@ class Client(TraceDataExtractor):
|
|
|
402
406
|
raise ValueError("Dataset id or name must be provided.")
|
|
403
407
|
|
|
404
408
|
response = self._client.get(
|
|
405
|
-
|
|
409
|
+
f"v1/datasets/{quote(id)}/examples",
|
|
406
410
|
params={"version_id": version_id} if version_id else None,
|
|
407
411
|
)
|
|
408
412
|
response.raise_for_status()
|
|
@@ -442,7 +446,7 @@ class Client(TraceDataExtractor):
|
|
|
442
446
|
Returns:
|
|
443
447
|
pandas DataFrame
|
|
444
448
|
"""
|
|
445
|
-
url =
|
|
449
|
+
url = f"v1/datasets/{dataset_id}/versions"
|
|
446
450
|
response = self._client.get(url=url, params={"limit": limit})
|
|
447
451
|
response.raise_for_status()
|
|
448
452
|
if not (records := response.json()["data"]):
|
|
@@ -612,7 +616,7 @@ class Client(TraceDataExtractor):
|
|
|
612
616
|
experiment_id (str): ID of the experiment. This can be found in the UI.
|
|
613
617
|
"""
|
|
614
618
|
response = self._client.get(
|
|
615
|
-
url=
|
|
619
|
+
url=f"v1/experiments/{experiment_id}",
|
|
616
620
|
)
|
|
617
621
|
experiment = response.json()["data"]
|
|
618
622
|
return Experiment.from_dict(experiment)
|
|
@@ -676,7 +680,7 @@ class Client(TraceDataExtractor):
|
|
|
676
680
|
assert_never(table)
|
|
677
681
|
print("📤 Uploading dataset...")
|
|
678
682
|
response = self._client.post(
|
|
679
|
-
url=
|
|
683
|
+
url="v1/datasets/upload",
|
|
680
684
|
files={"file": file},
|
|
681
685
|
data={
|
|
682
686
|
"action": action,
|
|
@@ -733,7 +737,7 @@ class Client(TraceDataExtractor):
|
|
|
733
737
|
)
|
|
734
738
|
print("📤 Uploading dataset...")
|
|
735
739
|
response = self._client.post(
|
|
736
|
-
url=
|
|
740
|
+
url="v1/datasets/upload",
|
|
737
741
|
headers={"Content-Encoding": "gzip"},
|
|
738
742
|
json={
|
|
739
743
|
"action": action,
|
|
@@ -756,14 +760,14 @@ class Client(TraceDataExtractor):
|
|
|
756
760
|
raise
|
|
757
761
|
data = response.json()["data"]
|
|
758
762
|
dataset_id = data["dataset_id"]
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
)
|
|
763
|
+
path = f"v1/datasets/{dataset_id}/examples"
|
|
764
|
+
response = self._client.get(path)
|
|
762
765
|
response.raise_for_status()
|
|
763
766
|
data = response.json()["data"]
|
|
764
767
|
version_id = data["version_id"]
|
|
765
768
|
examples = data["examples"]
|
|
766
|
-
|
|
769
|
+
examples_url = urljoin(self.web_url, f"datasets/{dataset_id}/examples")
|
|
770
|
+
print(f"💾 Examples uploaded: {examples_url}")
|
|
767
771
|
print(f"🗄️ Dataset version ID: {version_id}")
|
|
768
772
|
|
|
769
773
|
return Dataset(
|
phoenix/utilities/client.py
CHANGED
|
@@ -27,6 +27,12 @@ class VersionedClient(httpx.Client):
|
|
|
27
27
|
self._client_phoenix_version = phoenix_version
|
|
28
28
|
self._warned_on_minor_version_mismatch = False
|
|
29
29
|
|
|
30
|
+
def __del__(self) -> None:
|
|
31
|
+
try:
|
|
32
|
+
self.close()
|
|
33
|
+
except BaseException:
|
|
34
|
+
pass
|
|
35
|
+
|
|
30
36
|
def _check_version(self, response: httpx.Response) -> None:
|
|
31
37
|
server_version = response.headers.get(PHOENIX_SERVER_VERSION_HEADER)
|
|
32
38
|
|
phoenix/version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "
|
|
1
|
+
__version__ = "8.0.1"
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
from datetime import datetime
|
|
2
|
-
from enum import Enum
|
|
3
|
-
from importlib.metadata import PackageNotFoundError, version
|
|
4
|
-
|
|
5
|
-
from pydantic import BaseModel
|
|
6
|
-
from typing_extensions import assert_never
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
def datetime_encoder(dt: datetime) -> str:
|
|
10
|
-
"""
|
|
11
|
-
Encodes a `datetime` object to an ISO-formatted timestamp string.
|
|
12
|
-
|
|
13
|
-
By default, Pydantic v2 serializes `datetime` objects in a format that
|
|
14
|
-
cannot be parsed by `datetime.fromisoformat`. Adding this encoder to the
|
|
15
|
-
`json_encoders` config for a Pydantic model ensures that the serialized
|
|
16
|
-
`datetime` objects are parseable.
|
|
17
|
-
"""
|
|
18
|
-
return dt.isoformat()
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
class PydanticMajorVersion(Enum):
|
|
22
|
-
"""
|
|
23
|
-
The major version of `pydantic`.
|
|
24
|
-
"""
|
|
25
|
-
|
|
26
|
-
V1 = "v1"
|
|
27
|
-
V2 = "v2"
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
def get_pydantic_major_version() -> PydanticMajorVersion:
|
|
31
|
-
"""
|
|
32
|
-
Returns the major version of `pydantic` or raises an error if `pydantic` is
|
|
33
|
-
not installed.
|
|
34
|
-
"""
|
|
35
|
-
try:
|
|
36
|
-
pydantic_version = version("pydantic")
|
|
37
|
-
except PackageNotFoundError:
|
|
38
|
-
raise RuntimeError("Please install pydantic with `pip install pydantic`.")
|
|
39
|
-
if pydantic_version.startswith("1"):
|
|
40
|
-
return PydanticMajorVersion.V1
|
|
41
|
-
elif pydantic_version.startswith("2"):
|
|
42
|
-
return PydanticMajorVersion.V2
|
|
43
|
-
raise ValueError(f"Unsupported Pydantic version: {pydantic_version}")
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
if (pydantic_major_version := get_pydantic_major_version()) is PydanticMajorVersion.V1:
|
|
47
|
-
|
|
48
|
-
class V1RoutesBaseModel(BaseModel):
|
|
49
|
-
class Config:
|
|
50
|
-
json_encoders = {datetime: datetime_encoder}
|
|
51
|
-
|
|
52
|
-
elif pydantic_major_version is PydanticMajorVersion.V2:
|
|
53
|
-
from pydantic import ConfigDict
|
|
54
|
-
|
|
55
|
-
# `json_encoders` is a configuration setting from Pydantic v1 that was
|
|
56
|
-
# removed in Pydantic v2.0.* but restored in Pydantic v2.1.0 with a
|
|
57
|
-
# deprecation warning. At this time, it remains the simplest way to
|
|
58
|
-
# configure custom JSON serialization for specific data types in a manner
|
|
59
|
-
# that is consistent between Pydantic v1 and v2.
|
|
60
|
-
#
|
|
61
|
-
# For details, see:
|
|
62
|
-
# - https://github.com/pydantic/pydantic/pull/6811
|
|
63
|
-
# - https://github.com/pydantic/pydantic/releases/tag/v2.1.0
|
|
64
|
-
#
|
|
65
|
-
# The assertion below is added in case a future release of Pydantic v2 fully
|
|
66
|
-
# removes the `json_encoders` parameter.
|
|
67
|
-
assert "json_encoders" in ConfigDict.__annotations__, (
|
|
68
|
-
"If you encounter this error with `pydantic==2.0.*`, "
|
|
69
|
-
"please upgrade `pydantic` with `pip install -U pydantic>=2.1.0`. "
|
|
70
|
-
"If you encounter this error with `pydantic>=2.1.0`, "
|
|
71
|
-
"please upgrade `arize-phoenix` with `pip install -U arize-phoenix`, "
|
|
72
|
-
"or downgrade `pydantic` to a version that supports the `json_encoders` config setting."
|
|
73
|
-
)
|
|
74
|
-
|
|
75
|
-
class V1RoutesBaseModel(BaseModel): # type: ignore[no-redef]
|
|
76
|
-
model_config = ConfigDict({"json_encoders": {datetime: datetime_encoder}})
|
|
77
|
-
else:
|
|
78
|
-
assert_never(pydantic_major_version)
|