arize-phoenix 0.0.24rc0__py3-none-any.whl → 0.0.24rc2__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.1
2
2
  Name: arize-phoenix
3
- Version: 0.0.24rc0
3
+ Version: 0.0.24rc2
4
4
  Summary: ML Observability in your notebook
5
5
  Project-URL: Documentation, https://docs.arize.com/phoenix/
6
6
  Project-URL: Issues, https://github.com/Arize-ai/phoenix/issues
@@ -1,4 +1,4 @@
1
- phoenix/__init__.py,sha256=PIS-tjbGiHDur05VJ2Qbnt1fCvP1QjJj1HpY1XYvp1k,1049
1
+ phoenix/__init__.py,sha256=MDPqkLU2t2D4gPOm1SNfCt1YaQnGF57LQcyGPQRokRk,1049
2
2
  phoenix/config.py,sha256=tjNn9oqDxQmeO85sCchLlTsDiRJ6AoK0CTt_Uc_hrKM,1442
3
3
  phoenix/py.typed,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
4
4
  phoenix/services.py,sha256=pamdcZ9hp9BqgRV0ZIcMsjBYp8HCpIQPdxaXQfQLxYU,3711
@@ -8,10 +8,10 @@ phoenix/core/dimension_data_type.py,sha256=FEBp4p06LlFpAXq-ftxDAFymBtU_pYTFmJjFc
8
8
  phoenix/core/dimension_type.py,sha256=EKFmPzuGr1cn7t4vD-XDk9s836j6U3iRbSu3Z2sO8sM,171
9
9
  phoenix/core/embedding_dimension.py,sha256=zKGbcvwOXgLf-yrJBpQyKtd-LEOPRKHnUToyAU8Owis,87
10
10
  phoenix/core/model.py,sha256=JLAw1kc8Ctrm99E7Nb7eOWghjC9O_V1AFu-e5byD5UY,4638
11
- phoenix/core/model_schema.py,sha256=MAh_OxZDp8XUWMjuXsfwRmPxPZF7JNKlbP1ZYohDMzU,47447
12
- phoenix/core/model_schema_adapter.py,sha256=Tf49ZKcX33vcsatQ7CW4s31cejJd6xAZMfCq9vv1Chs,5522
11
+ phoenix/core/model_schema.py,sha256=nHmNbmfFnJL4a2o40YxE7BL-S5FLGeS4waO_8Jn2W1w,47340
12
+ phoenix/core/model_schema_adapter.py,sha256=Kqr1doD12xtujTtWX-zgPu1HfRcdM1756ZCa3uW0f_Y,7165
13
13
  phoenix/datasets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
- phoenix/datasets/dataset.py,sha256=zKJV_YHBgcObioatpBsY8SXhEjBLXBiW27eObVoTps4,21682
14
+ phoenix/datasets/dataset.py,sha256=J92RSwlbrh-Nj6BwQkO0GsIdSe81MuHr1xz8hwf69GY,21824
15
15
  phoenix/datasets/errors.py,sha256=-Iyk8rsvP_KX-P4gOqjm26slkDq1-9CohK07_LkrYCI,8117
16
16
  phoenix/datasets/fixtures.py,sha256=9rmJgsF50vmuwR7PavNf7kdFsLQiasta6iJEzh7GvkM,15954
17
17
  phoenix/datasets/schema.py,sha256=1sSdtKkN7L61rsb8FNeTxJZG-ysGR7JGgT08WKGuDFs,3658
@@ -26,7 +26,7 @@ phoenix/metrics/wrappers.py,sha256=fCWIcIp30-YZmlzL4hpv2u07QRfCNn4WtI0mcQN0db8,8
26
26
  phoenix/pointcloud/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
27
27
  phoenix/pointcloud/clustering.py,sha256=IzcG67kJ2hPP7pcqVmKPSL_6gKRonKdOT3bCtbTOqnk,820
28
28
  phoenix/pointcloud/pointcloud.py,sha256=Ntj5juwMfwjPqyacPNGyH0lsItqpMTqtKiDdIEufnTY,2196
29
- phoenix/pointcloud/projectors.py,sha256=-FRYi420TrJkibFcMwAsXa8HK4u6EQRxHKslZpeldkw,716
29
+ phoenix/pointcloud/projectors.py,sha256=zO_RrtDYSv2rqVOfIP2_9Cv11Dc8EmcZR94xhFcBYPU,1057
30
30
  phoenix/server/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
31
31
  phoenix/server/app.py,sha256=kWG5YWSnzZ668aA9TNoIeoc6Gxf6fYCgab6ZDAdDsig,4013
32
32
  phoenix/server/main.py,sha256=PUK042dTYCgh18eELtPhldBujUxQLAmrMDJD2Oz8Exk,3035
@@ -63,10 +63,10 @@ phoenix/server/api/types/ExportEventsMutation.py,sha256=NctthWhHFR4wKva1jfyWX4-5
63
63
  phoenix/server/api/types/ExportedFile.py,sha256=e3GTn7B5LgsTbqiwjhMCQH7VsiqXitrBO4aCMS1lHsg,163
64
64
  phoenix/server/api/types/Model.py,sha256=I7liNDDsl1cykJjMQutUI18ZiQ5EXBar3I0a_-C66kw,7228
65
65
  phoenix/server/api/types/NumericRange.py,sha256=afEjgF97Go_OvmjMggbPBt-zGM8IONewAyEiKEHRds0,192
66
- phoenix/server/api/types/PerformanceMetric.py,sha256=_jUkpLCUHP3bl6224Yt_7FOuHG2CS0GET1qajzayjC0,351
66
+ phoenix/server/api/types/PerformanceMetric.py,sha256=W92B7OghEOgzFvmY0LCqpgavHaQggTGshdgfD0yqHX4,350
67
67
  phoenix/server/api/types/PromptResponse.py,sha256=Q8HKtpp8GpUOcxPCzZpkkokidDd6u0aZOv_SuPZZd5Q,630
68
68
  phoenix/server/api/types/ScalarDriftMetricEnum.py,sha256=IUAcRPpgL41WdoIgK6cNk2Te38SspXGyEs-S1fY23_A,232
69
- phoenix/server/api/types/Segments.py,sha256=J5g5sOP74-aW7F9sR3H1EMpRyY4L4QoG8KRT9bUFb_Y,2174
69
+ phoenix/server/api/types/Segments.py,sha256=eUoisp10Y1dCFCSphOjNA52g2Ja2chrvc_q1yMm-b2k,2903
70
70
  phoenix/server/api/types/TimeSeries.py,sha256=pcSjoPLNq3fNiCt6amiZEGtLDF14HPP7HVXA8znvFmQ,5190
71
71
  phoenix/server/api/types/UMAPPoints.py,sha256=GS37oRtFfEqucgMxXp0RtoZaz4D5Ye_lSYQYR3JlMe4,1451
72
72
  phoenix/server/api/types/VectorDriftMetricEnum.py,sha256=etiJM5ZjQuD-oE7sY-FbdIKY050jk3IU49IMwmfJbEc,188
@@ -84,12 +84,12 @@ phoenix/server/static/apple-touch-icon.png,sha256=fOfpjqGpWYbJ0eAurKsyoZP1EAs6ZV
84
84
  phoenix/server/static/favicon.ico,sha256=bY0vvCKRftemZfPShwZtE93DiiQdaYaozkPGwNFr6H8,34494
85
85
  phoenix/server/static/index.css,sha256=jeV8eWPiHUcUmb_0yp_rI1odc-RnxlXVgMT-x9HGWbo,1817
86
86
  phoenix/server/static/index.html,sha256=xPZZH-y4dWlbDutPEV1k0rhmWJtIV-Db9aYP-dEc7wM,703
87
- phoenix/server/static/index.js,sha256=7qQbwDFSRuf1UGGb7Mir60p9E6cF3prq3bGwKhErx7s,2338799
87
+ phoenix/server/static/index.js,sha256=YtwDNwj3GObOQYv8GllsZZ3Q_0Is3aZRQKRp8SWFtJU,2358860
88
88
  phoenix/server/static/modernizr.js,sha256=mvK-XtkNqjOral-QvzoqsyOMECXIMu5BQwSVN_wcU9c,2564
89
89
  phoenix/session/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
90
90
  phoenix/session/session.py,sha256=sHm0qoPexNBF49a6VlGw0Oi81Zkj_EjrJCY_b3VK-Yo,8658
91
- arize_phoenix-0.0.24rc0.dist-info/METADATA,sha256=SuZHDTY1IiqWo8d1Vey5DIfrGN60AQNj6hpCIpRz0wk,10813
92
- arize_phoenix-0.0.24rc0.dist-info/WHEEL,sha256=Fd6mP6ydyRguakwUJ05oBE7fh2IPxgtDN9IwHJ9OqJQ,87
93
- arize_phoenix-0.0.24rc0.dist-info/licenses/IP_NOTICE,sha256=JBqyyCYYxGDfzQ0TtsQgjts41IJoa-hiwDrBjCb9gHM,469
94
- arize_phoenix-0.0.24rc0.dist-info/licenses/LICENSE,sha256=HFkW9REuMOkvKRACuwLPT0hRydHb3zNg-fdFt94td18,3794
95
- arize_phoenix-0.0.24rc0.dist-info/RECORD,,
91
+ arize_phoenix-0.0.24rc2.dist-info/METADATA,sha256=aNkZu5EL2zd-5k11SJnUF1JnoMTYdn9T4V_A0oxa6SM,10813
92
+ arize_phoenix-0.0.24rc2.dist-info/WHEEL,sha256=9QBuHhg6FNW7lppboF2vKVbCGTVzsFykgRQjjlajrhA,87
93
+ arize_phoenix-0.0.24rc2.dist-info/licenses/IP_NOTICE,sha256=JBqyyCYYxGDfzQ0TtsQgjts41IJoa-hiwDrBjCb9gHM,469
94
+ arize_phoenix-0.0.24rc2.dist-info/licenses/LICENSE,sha256=HFkW9REuMOkvKRACuwLPT0hRydHb3zNg-fdFt94td18,3794
95
+ arize_phoenix-0.0.24rc2.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.13.0
2
+ Generator: hatchling 1.18.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
phoenix/__init__.py CHANGED
@@ -3,7 +3,7 @@ from .datasets.fixtures import ExampleDatasets, load_example
3
3
  from .datasets.schema import EmbeddingColumnNames, Schema
4
4
  from .session.session import Session, active_session, close_app, launch_app
5
5
 
6
- __version__ = "0.0.24rc0"
6
+ __version__ = "0.0.24rc2"
7
7
 
8
8
  # module level doc-string
9
9
  __doc__ = """
@@ -599,10 +599,8 @@ class Events(ModelData):
599
599
  @cached_property
600
600
  def time_range(self) -> TimeRange:
601
601
  if self._self_model is None or self.empty:
602
- # NOTE: as of Python 3.8.16, pandas 1.5.3:
603
- # >>> isinstance(pd.NaT, datetime.datetime)
604
- # True
605
- return TimeRange(pd.NaT, pd.NaT) # type: ignore
602
+ now = datetime.now(timezone.utc)
603
+ return TimeRange(now, now)
606
604
  model = cast(Model, self._self_model)
607
605
  min_max = _agg_min_max(model[TIMESTAMP](self))
608
606
  start_time = cast(datetime, min_max.min())
@@ -1,7 +1,9 @@
1
1
  from itertools import chain
2
- from typing import Dict, Iterable, List, Optional, Tuple
2
+ from operator import itemgetter
3
+ from typing import Dict, Iterable, List, Optional, Sized, Tuple
3
4
 
4
5
  import pandas as pd
6
+ from pandas.api.types import is_object_dtype
5
7
  from typing_extensions import TypeAlias, TypeGuard
6
8
 
7
9
  from phoenix import Dataset, EmbeddingColumnNames
@@ -107,8 +109,19 @@ def create_model_from_datasets(*datasets: Optional[Dataset]) -> Model:
107
109
  prediction_score=_take_first_str(prediction_scores),
108
110
  actual_label=_take_first_str(actual_labels),
109
111
  actual_score=_take_first_str(actual_scores),
110
- features=chain(features, translated_embeddings),
111
- tags=tags,
112
+ features=chain(
113
+ *_split_vectors_vs_scalars(
114
+ features,
115
+ *map(itemgetter(1), named_dataframes),
116
+ ),
117
+ translated_embeddings,
118
+ ),
119
+ tags=chain(
120
+ *_split_vectors_vs_scalars(
121
+ tags,
122
+ *map(itemgetter(1), named_dataframes),
123
+ )
124
+ ),
112
125
  prompt=next(map(_translate_embedding, prompts), None),
113
126
  response=next(map(_translate_embedding, responses), None),
114
127
  )(
@@ -137,3 +150,37 @@ def _translate_embedding(
137
150
  link_to_data=embedding.link_to_data_column_name,
138
151
  display_name=display_name,
139
152
  )
153
+
154
+
155
+ def _split_vectors_vs_scalars(
156
+ names: Iterable[str],
157
+ *dataframes: pd.DataFrame,
158
+ ) -> Tuple[List[str], List[Embedding]]:
159
+ """A best-effort attempt at separating vector columns from scalar columns
160
+ by examining the first non-null item of the column from each dataframe. If
161
+ any item is `Iterable` and `Sized`, but not `str`, then the column is
162
+ returned as `Embedding`, else it's returned as scalar.
163
+ """
164
+ scalars: List[str] = []
165
+ vectors: List[Embedding] = []
166
+ # convert to sets for a speedier lookup
167
+ column_names = [set(df.columns) for df in dataframes]
168
+ for name in names:
169
+ for i, df in enumerate(dataframes):
170
+ if df.empty or name not in column_names[i]:
171
+ continue
172
+ series = df.loc[:, name]
173
+ if not is_object_dtype(series):
174
+ continue
175
+ item = series.iat[series.isna().argmin()]
176
+ if (
177
+ isinstance(item, str) # str is scalar, but Iterable
178
+ or not isinstance(item, Iterable)
179
+ or not isinstance(item, Sized)
180
+ ):
181
+ continue
182
+ vectors.append(Embedding(vector=name))
183
+ break
184
+ else:
185
+ scalars.append(name)
186
+ return scalars, vectors
@@ -443,7 +443,11 @@ def _normalize_timestamps(
443
443
  if (timestamp_column_name := schema.timestamp_column_name) is None:
444
444
  timestamp_column_name = "timestamp"
445
445
  schema = replace(schema, timestamp_column_name=timestamp_column_name)
446
- timestamp_column = Series([default_timestamp] * len(dataframe), index=dataframe.index)
446
+ timestamp_column = (
447
+ Series([default_timestamp] * len(dataframe), index=dataframe.index)
448
+ if len(dataframe)
449
+ else Series([default_timestamp]).iloc[:0].set_axis(dataframe.index, axis=0)
450
+ )
447
451
  elif is_numeric_dtype(timestamp_column_dtype := dataframe[timestamp_column_name].dtype):
448
452
  timestamp_column = to_datetime(dataframe[timestamp_column_name], unit="s", utc=True)
449
453
  elif is_datetime64tz_dtype(timestamp_column_dtype):
@@ -11,6 +11,7 @@ with warnings.catch_warnings():
11
11
 
12
12
  warnings.simplefilter("ignore", category=NumbaWarning)
13
13
  from umap import UMAP
14
+
14
15
  Matrix: TypeAlias = npt.NDArray[np.float64]
15
16
 
16
17
 
@@ -24,4 +25,11 @@ class Umap:
24
25
  min_dist: float = 0.1
25
26
 
26
27
  def project(self, mat: Matrix, n_components: int) -> Matrix:
27
- return _center(UMAP(**asdict(self), n_components=n_components).fit_transform(mat))
28
+ config = asdict(self)
29
+ config["n_components"] = n_components
30
+ if len(mat) <= n_components:
31
+ # init='spectral', the default, cannot be used when n_components
32
+ # is greater or equal to the number of samples.
33
+ # see https://github.com/lmcinnes/umap/issues/201#issuecomment-462097103
34
+ config["init"] = "random"
35
+ return _center(UMAP(**config).fit_transform(mat))
@@ -10,4 +10,4 @@ from phoenix.metrics.wrappers import SkEval
10
10
  class PerformanceMetric(Enum):
11
11
  # To become enum values, functions need to be wrapped in partial.
12
12
  # See https://stackoverflow.com/a/40339397
13
- accuracy_score = partial(SkEval.accuracy_score) # type: ignore
13
+ accuracyScore = partial(SkEval.accuracy_score) # type: ignore
@@ -84,5 +84,19 @@ class Segments:
84
84
  )
85
85
 
86
86
  def append(self, other: Segment) -> None:
87
+ if (
88
+ isinstance(other.bin, IntervalBin)
89
+ and not math.isfinite(other.bin.range.start)
90
+ and not math.isfinite(other.bin.range.end)
91
+ and other.counts.primary_value == 0
92
+ and other.counts.reference_value == 0
93
+ ):
94
+ # Skip the interval bin with zero counts if it has -inf and +inf
95
+ # as the endpoints, as it could occur due to all values being
96
+ # missing. Because such bin can exist a priori, the caller may
97
+ # still try to append it, but the bin has no real value at this
98
+ # point (and can cause problems for graphql because of the end
99
+ # points are not serializable to JSON).
100
+ return
87
101
  self.segments.append(other)
88
102
  self.total_counts += other.counts