arize-phoenix 4.0.3__py3-none-any.whl → 4.1.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.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: arize-phoenix
3
- Version: 4.0.3
3
+ Version: 4.1.1
4
4
  Summary: AI Observability and Evaluation
5
5
  Project-URL: Documentation, https://docs.arize.com/phoenix/
6
6
  Project-URL: Issues, https://github.com/Arize-ai/phoenix/issues
@@ -1,11 +1,11 @@
1
1
  phoenix/__init__.py,sha256=NyJ6xQhGeEdbHVA72gbQlGo3WElzQxmpQBSME-CZNZI,2389
2
- phoenix/config.py,sha256=DhA70BHG0dKTNGKtONdrLxBpMduqQms4QjPNkANa3VE,6879
2
+ phoenix/config.py,sha256=ZGzdeE_1IJe_WFyRY7hxFbNNtHbZATk2b1pWUxpcTxk,7155
3
3
  phoenix/datetime_utils.py,sha256=oqkxJ5I7ggrCKYTEi8q-akC501calylD26NVOPQQcHw,3305
4
4
  phoenix/exceptions.py,sha256=n2L2KKuecrdflB9MsCdAYCiSEvGJptIsfRkXMoJle7A,169
5
5
  phoenix/py.typed,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
6
6
  phoenix/services.py,sha256=haZUWKuxfI5lm0o61HgW_4B6RTBg9CUbXC8y92ZMsw4,5121
7
7
  phoenix/settings.py,sha256=cO-qgis_S27nHirTobYI9hHPfZH18R--WMmxNdsVUwc,273
8
- phoenix/version.py,sha256=5zeiuQJN6kh6ruLu8rUR2scjLw-LXunQn0VwgH2RhjE,22
8
+ phoenix/version.py,sha256=NtWqZUv_8plp1gndoYX_eAqe7K65oPMh-hIvB4Evdc8,22
9
9
  phoenix/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
10
  phoenix/core/embedding_dimension.py,sha256=zKGbcvwOXgLf-yrJBpQyKtd-LEOPRKHnUToyAU8Owis,87
11
11
  phoenix/core/model.py,sha256=SBO8BZg_CeQuH5LrSgzlQfqMModzirkQePdhnbLw7dE,4756
@@ -18,7 +18,7 @@ phoenix/db/bulk_inserter.py,sha256=jubepj2a40jFy95NB8UFznpkFnlRRwB-iOXZ6DS0au8,9
18
18
  phoenix/db/engines.py,sha256=vLWaZlToMtDI7rJDxSidYkfOoojamxaZxaz8ND3zTus,4770
19
19
  phoenix/db/helpers.py,sha256=L2_jP1iIWpUREhKLYYb4_vf_6v_BiU1E73Z2PczGm6s,1589
20
20
  phoenix/db/migrate.py,sha256=Rd7rnmYLFlSGO3R3rSzXCCvDkYkhxguqDbQNhI6rm5o,2251
21
- phoenix/db/models.py,sha256=Atd61_8I2uiP6tUPW3As4X3UKU2edbS-W4LGGzkJ9KM,12125
21
+ phoenix/db/models.py,sha256=0TMbI69xOcW2a1uWLmwTDANSSoOvuFcBczbrjNSh3Cw,12240
22
22
  phoenix/db/insertion/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
23
23
  phoenix/db/insertion/evaluation.py,sha256=nvKXGWv0XD23G3ISw2u9_SqbwtGaB0Vd63wL59nPlCA,7189
24
24
  phoenix/db/insertion/helpers.py,sha256=2oBbzwx_Q0JJ9WlvbGl_a8hWySHyGhzbMNv-SHtcM-4,2022
@@ -49,7 +49,7 @@ phoenix/pointcloud/umap_parameters.py,sha256=lJsEOrbSuSiqI7g4Yt6xj7kgYxEqoep4ZHW
49
49
  phoenix/server/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
50
50
  phoenix/server/app.py,sha256=29S6klPWr27nfifyr63MpZ3mbq8pu-jwiqT_fTNqbS4,16247
51
51
  phoenix/server/grpc_server.py,sha256=faktLxEtWGlCB1bPR4QwwTsRoQloahKMx0hAWqRGI5s,3379
52
- phoenix/server/main.py,sha256=DXvoSIgnmh6CF6-eYKGf1cSOoZaoABiQfOiRSXK-KP0,10638
52
+ phoenix/server/main.py,sha256=chV26thMufLk96WZ1NqoxiXh_zF7hrnSM3fZjnjCTEw,10809
53
53
  phoenix/server/prometheus.py,sha256=j9DHB2fERuq_ZKmwVaqR-9wx5WcPPuU1Cm5Bhg5241Y,2996
54
54
  phoenix/server/telemetry.py,sha256=T_2OKrxNViAeaANlNspEekg_Y5uZIFWvKAnpz8Aoqvk,2762
55
55
  phoenix/server/thread_server.py,sha256=dP6cm6Cf08jNhDA1TRlVZpziu1YgtPDmaeIJMm725eI,2154
@@ -145,15 +145,15 @@ phoenix/server/static/modernizr.js,sha256=mvK-XtkNqjOral-QvzoqsyOMECXIMu5BQwSVN_
145
145
  phoenix/server/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
146
146
  phoenix/server/templates/index.html,sha256=lO2wGA5XsftPg03rw_VcyaYf_4vegtlWbIT5ms4fA_c,1982
147
147
  phoenix/session/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
148
- phoenix/session/client.py,sha256=gQhnqPTGwzzeVBgduvHSQJPWb4bW1OBKZ1JQ2APEEhU,10097
148
+ phoenix/session/client.py,sha256=4Pm9RtP-FAH99-gLgGHNOdzqLpJ8ROAOgnpjwPW8WHA,10143
149
149
  phoenix/session/data_extractor.py,sha256=dwhiDu-ISaXr8UI9I-CszZhB5BlUNmdDopjFZvMIXMw,2101
150
- phoenix/session/evaluation.py,sha256=mR5HeBDmoS9oCb-X-2lpLCyMRoOgBufofbsjyEqCpMg,5390
150
+ phoenix/session/evaluation.py,sha256=aKeV8UVOyq3b7CYOwt3cWuLz0xzvMjX7vlEPILJ_fcs,5311
151
151
  phoenix/session/session.py,sha256=-OuqBRMT1tcat7qmy3g2mkDxK6krbtyH2mHpLskZ62k,26103
152
152
  phoenix/trace/__init__.py,sha256=ujk_uYjM8gmm-YqnyXxF-kekfwid0bcaPMTtNNcaw6U,407
153
153
  phoenix/trace/attributes.py,sha256=8wZznsBbu-e9AAUh2C3yCTDQu-SIiNTn-v0UsWzq_GA,12364
154
154
  phoenix/trace/errors.py,sha256=wB1z8qdPckngdfU-TORToekvg3344oNFAA83_hC2yFY,180
155
155
  phoenix/trace/evaluation_conventions.py,sha256=t8jydM3U0-T5YpiQKRJ3tWdWGlHtzKyttYdw-ddvPOk,1048
156
- phoenix/trace/exporter.py,sha256=vh2RO1CpP143HxIX94KV0qks8p1x66RE3Tgf8kcBCCg,4519
156
+ phoenix/trace/exporter.py,sha256=D4crJLITTwdo96kav2mHuIJleFQ7hmjDWDuVASdpcao,4658
157
157
  phoenix/trace/fixtures.py,sha256=kupizPlPLoQyCxZfrIU7ZC87dYiL8uEhZEmdia__5qQ,9644
158
158
  phoenix/trace/otel.py,sha256=WA720jvRadiZBAKjsYoPyXzypHwbyEK2OZRVUwtbjB8,9976
159
159
  phoenix/trace/projects.py,sha256=2BwlNjFE-uwpqYtCu5YyBiYZk9wRPpM13vh3-Cv7GkA,2157
@@ -183,8 +183,8 @@ phoenix/utilities/error_handling.py,sha256=7b5rpGFj9EWZ8yrZK1IHvxB89suWk3lggDayU
183
183
  phoenix/utilities/logging.py,sha256=lDXd6EGaamBNcQxL4vP1au9-i_SXe0OraUDiJOcszSw,222
184
184
  phoenix/utilities/project.py,sha256=qWsvKnG1oKhOFUowXf9qiOL2ia7jaFe_ijFFHEt8GJo,431
185
185
  phoenix/utilities/span_store.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
186
- arize_phoenix-4.0.3.dist-info/METADATA,sha256=iwmTF1Om7qivbRvMNDbQjf13vMMk5MfJTXfY6ODmWn8,30464
187
- arize_phoenix-4.0.3.dist-info/WHEEL,sha256=zEMcRr9Kr03x1ozGwg5v9NQBKn3kndp6LSoSlVg-jhU,87
188
- arize_phoenix-4.0.3.dist-info/licenses/IP_NOTICE,sha256=JBqyyCYYxGDfzQ0TtsQgjts41IJoa-hiwDrBjCb9gHM,469
189
- arize_phoenix-4.0.3.dist-info/licenses/LICENSE,sha256=HFkW9REuMOkvKRACuwLPT0hRydHb3zNg-fdFt94td18,3794
190
- arize_phoenix-4.0.3.dist-info/RECORD,,
186
+ arize_phoenix-4.1.1.dist-info/METADATA,sha256=PdPeUgt5sN4MgMN_FSNaAHxX_5uNLyHViDAlXxYC_SI,30464
187
+ arize_phoenix-4.1.1.dist-info/WHEEL,sha256=zEMcRr9Kr03x1ozGwg5v9NQBKn3kndp6LSoSlVg-jhU,87
188
+ arize_phoenix-4.1.1.dist-info/licenses/IP_NOTICE,sha256=JBqyyCYYxGDfzQ0TtsQgjts41IJoa-hiwDrBjCb9gHM,469
189
+ arize_phoenix-4.1.1.dist-info/licenses/LICENSE,sha256=HFkW9REuMOkvKRACuwLPT0hRydHb3zNg-fdFt94td18,3794
190
+ arize_phoenix-4.1.1.dist-info/RECORD,,
phoenix/config.py CHANGED
@@ -10,6 +10,7 @@ logger = getLogger(__name__)
10
10
  ENV_PHOENIX_PORT = "PHOENIX_PORT"
11
11
  ENV_PHOENIX_GRPC_PORT = "PHOENIX_GRPC_PORT"
12
12
  ENV_PHOENIX_HOST = "PHOENIX_HOST"
13
+ ENV_PHOENIX_HOST_ROOT_PATH = "PHOENIX_HOST_ROOT_PATH"
13
14
  ENV_NOTEBOOK_ENV = "PHOENIX_NOTEBOOK_ENV"
14
15
  ENV_PHOENIX_COLLECTOR_ENDPOINT = "PHOENIX_COLLECTOR_ENDPOINT"
15
16
  """
@@ -98,6 +99,8 @@ HOST = "0.0.0.0"
98
99
  """The host the server will run on after launch_app is called."""
99
100
  PORT = 6006
100
101
  """The port the server will run on after launch_app is called."""
102
+ HOST_ROOT_PATH = ""
103
+ """The ASGI root path of the server, i.e. the root path where the web application is mounted"""
101
104
  GRPC_PORT = 4317
102
105
  """The port the gRPC server will run on after launch_app is called.
103
106
  The default network port for OTLP/gRPC is 4317.
@@ -183,6 +186,10 @@ def get_env_host() -> str:
183
186
  return os.getenv(ENV_PHOENIX_HOST) or HOST
184
187
 
185
188
 
189
+ def get_env_host_root_path() -> str:
190
+ return os.getenv(ENV_PHOENIX_HOST_ROOT_PATH) or HOST_ROOT_PATH
191
+
192
+
186
193
  def get_env_collector_endpoint() -> Optional[str]:
187
194
  return os.getenv(ENV_PHOENIX_COLLECTOR_ENDPOINT)
188
195
 
phoenix/db/models.py CHANGED
@@ -3,6 +3,7 @@ from typing import Any, Dict, List, Optional
3
3
 
4
4
  from sqlalchemy import (
5
5
  JSON,
6
+ NUMERIC,
6
7
  TIMESTAMP,
7
8
  CheckConstraint,
8
9
  ColumnElement,
@@ -228,7 +229,13 @@ def _(element: Any, compiler: Any, **kw: Any) -> Any:
228
229
  # See https://docs.sqlalchemy.org/en/20/core/compiler.html
229
230
  start_time, end_time = list(element.clauses)
230
231
  return compiler.process(
231
- func.round((func.extract("EPOCH", end_time) - func.extract("EPOCH", start_time)) * 1000, 1),
232
+ func.round(
233
+ func.cast(
234
+ (func.extract("EPOCH", end_time) - func.extract("EPOCH", start_time)) * 1000,
235
+ NUMERIC,
236
+ ),
237
+ 1,
238
+ ),
232
239
  **kw,
233
240
  )
234
241
 
phoenix/server/main.py CHANGED
@@ -18,6 +18,7 @@ from phoenix.config import (
18
18
  get_env_enable_prometheus,
19
19
  get_env_grpc_port,
20
20
  get_env_host,
21
+ get_env_host_root_path,
21
22
  get_env_port,
22
23
  get_pids_path,
23
24
  get_working_dir,
@@ -67,10 +68,10 @@ _WELCOME_MESSAGE = """
67
68
  | https://docs.arize.com/phoenix
68
69
  |
69
70
  | 🚀 Phoenix Server 🚀
70
- | Phoenix UI: http://{host}:{port}
71
+ | Phoenix UI: http://{host}:{port}/{root_path}
71
72
  | Log traces:
72
73
  | - gRPC: http://{host}:{grpc_port}
73
- | - HTTP: http://{host}:{port}/v1/traces
74
+ | - HTTP: http://{host}:{port}/{root_path}/v1/traces
74
75
  | Storage: {storage}
75
76
  """
76
77
 
@@ -197,7 +198,7 @@ if __name__ == "__main__":
197
198
  host = None
198
199
 
199
200
  port = args.port or get_env_port()
200
-
201
+ host_root_path = get_env_host_root_path()
201
202
  model = create_model_from_datasets(
202
203
  primary_dataset,
203
204
  reference_dataset,
@@ -251,7 +252,7 @@ if __name__ == "__main__":
251
252
  initial_spans=fixture_spans,
252
253
  initial_evaluations=fixture_evals,
253
254
  )
254
- server = Server(config=Config(app, host=host, port=port)) # type: ignore
255
+ server = Server(config=Config(app, host=host, port=port, root_path=host_root_path)) # type: ignore
255
256
  Thread(target=_write_pid_file_when_ready, args=(server,), daemon=True).start()
256
257
 
257
258
  # Print information about the server
@@ -260,6 +261,7 @@ if __name__ == "__main__":
260
261
  "version": phoenix_version,
261
262
  "host": display_host,
262
263
  "port": port,
264
+ "root_path": host_root_path.strip("/"),
263
265
  "grpc_port": get_env_grpc_port(),
264
266
  "storage": get_printable_db_url(db_connection_str),
265
267
  }
phoenix/session/client.py CHANGED
@@ -55,9 +55,9 @@ class Client(TraceDataExtractor):
55
55
  host = get_env_host()
56
56
  if host == "0.0.0.0":
57
57
  host = "127.0.0.1"
58
- self._base_url = (
59
- endpoint or get_env_collector_endpoint() or f"http://{host}:{get_env_port()}"
60
- )
58
+ base_url = endpoint or get_env_collector_endpoint() or f"http://{host}:{get_env_port()}"
59
+ self._base_url = base_url if base_url.endswith("/") else base_url + "/"
60
+
61
61
  self._session = Session()
62
62
  weakref.finalize(self, self._session.close)
63
63
  if warn_if_server_not_running:
@@ -99,7 +99,7 @@ class Client(TraceDataExtractor):
99
99
  )
100
100
  end_time = end_time or stop_time
101
101
  response = self._session.post(
102
- url=urljoin(self._base_url, "/v1/spans"),
102
+ url=urljoin(self._base_url, "v1/spans"),
103
103
  params={"project-name": project_name},
104
104
  json={
105
105
  "queries": [q.to_dict() for q in queries],
@@ -146,7 +146,7 @@ class Client(TraceDataExtractor):
146
146
  """
147
147
  project_name = project_name or get_env_project_name()
148
148
  response = self._session.get(
149
- urljoin(self._base_url, "/v1/evaluations"),
149
+ urljoin(self._base_url, "v1/evaluations"),
150
150
  params={"project-name": project_name},
151
151
  )
152
152
  if response.status_code == 404:
@@ -167,7 +167,7 @@ class Client(TraceDataExtractor):
167
167
 
168
168
  def _warn_if_phoenix_is_not_running(self) -> None:
169
169
  try:
170
- self._session.get(urljoin(self._base_url, "/arize_phoenix_version")).raise_for_status()
170
+ self._session.get(urljoin(self._base_url, "arize_phoenix_version")).raise_for_status()
171
171
  except Exception:
172
172
  logger.warning(
173
173
  f"Arize Phoenix is not running on {self._base_url}. Launch Phoenix "
@@ -198,7 +198,7 @@ class Client(TraceDataExtractor):
198
198
  with pa.ipc.new_stream(sink, table.schema) as writer:
199
199
  writer.write_table(table)
200
200
  self._session.post(
201
- urljoin(self._base_url, "/v1/evaluations"),
201
+ urljoin(self._base_url, "v1/evaluations"),
202
202
  data=cast(bytes, sink.getvalue().to_pybytes()),
203
203
  headers=headers,
204
204
  ).raise_for_status()
@@ -241,7 +241,7 @@ class Client(TraceDataExtractor):
241
241
  serialized = otlp_span.SerializeToString()
242
242
  data = gzip.compress(serialized)
243
243
  self._session.post(
244
- urljoin(self._base_url, "/v1/traces"),
244
+ urljoin(self._base_url, "v1/traces"),
245
245
  data=data,
246
246
  headers={
247
247
  "content-type": "application/x-protobuf",
@@ -17,7 +17,6 @@ from typing import (
17
17
  Union,
18
18
  cast,
19
19
  )
20
- from urllib.parse import urljoin
21
20
 
22
21
  import pandas as pd
23
22
  from google.protobuf.wrappers_pb2 import DoubleValue, StringValue
@@ -147,8 +146,5 @@ def log_evaluations(
147
146
  if host == "0.0.0.0":
148
147
  host = "127.0.0.1"
149
148
  port = port or get_env_port()
150
- endpoint = endpoint or urljoin(
151
- get_env_collector_endpoint() or f"http://{host}:{port}",
152
- "/v1/traces",
153
- )
149
+ endpoint = endpoint or get_env_collector_endpoint() or f"http://{host}:{port}"
154
150
  Client(endpoint=endpoint).log_evaluations(*evals)
phoenix/trace/exporter.py CHANGED
@@ -33,11 +33,11 @@ class _OpenInferenceExporter(OTLPSpanExporter):
33
33
  host = get_env_host()
34
34
  if host == "0.0.0.0":
35
35
  host = "127.0.0.1"
36
- endpoint = urljoin(
37
- get_env_collector_endpoint() or f"http://{host}:{get_env_port()}",
38
- "/v1/traces",
39
- )
40
- _warn_if_phoenix_is_not_running(endpoint)
36
+ base_url = get_env_collector_endpoint() or f"http://{host}:{get_env_port()}"
37
+ base_url = base_url if base_url.endswith("/") else base_url + "/"
38
+ _warn_if_phoenix_is_not_running(base_url)
39
+
40
+ endpoint = urljoin(base_url, "v1/traces")
41
41
  super().__init__(endpoint)
42
42
 
43
43
 
@@ -68,11 +68,12 @@ class HttpExporter:
68
68
  """
69
69
  self._host = host or get_env_host()
70
70
  self._port = port or get_env_port()
71
- self._base_url = (
71
+ base_url = (
72
72
  endpoint
73
73
  or get_env_collector_endpoint()
74
74
  or f"http://{'127.0.0.1' if self._host == '0.0.0.0' else self._host}:{self._port}"
75
75
  )
76
+ self._base_url = base_url if base_url.endswith("/") else base_url + "/"
76
77
  _warn_if_phoenix_is_not_running(self._base_url)
77
78
  self._session = Session()
78
79
  weakref.finalize(self, self._session.close)
@@ -117,16 +118,16 @@ class HttpExporter:
117
118
 
118
119
  def _url(self, message: Message) -> str:
119
120
  if isinstance(message, pb.Evaluation):
120
- return urljoin(self._base_url, "/v1/evaluations")
121
+ return urljoin(self._base_url, "v1/evaluations")
121
122
  logger.exception(f"unrecognized message type: {type(message)}")
122
123
  assert_never(message)
123
124
 
124
125
 
125
- def _warn_if_phoenix_is_not_running(endpoint: str) -> None:
126
+ def _warn_if_phoenix_is_not_running(base_url: str) -> None:
126
127
  try:
127
- requests.get(urljoin(endpoint, "/arize_phoenix_version")).raise_for_status()
128
+ requests.get(urljoin(base_url, "arize_phoenix_version")).raise_for_status()
128
129
  except Exception:
129
130
  logger.warning(
130
- f"Arize Phoenix is not running on {endpoint}. Launch Phoenix "
131
+ f"Arize Phoenix is not running on {base_url}. Launch Phoenix "
131
132
  f"with `import phoenix as px; px.launch_app()`"
132
133
  )
phoenix/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "4.0.3"
1
+ __version__ = "4.1.1"