arize-phoenix 3.14.2__py3-none-any.whl → 3.15.0__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: 3.14.2
3
+ Version: 3.15.0
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,17 +1,17 @@
1
1
  phoenix/__init__.py,sha256=mrgR7rvpc7LnBeyLzCX9wmRP4kJSJdfKDbj2zDiDjG8,2311
2
- phoenix/config.py,sha256=eJ7V0eQMc1vT_0LRF1HDXMWbnGLYa4c36WHYfUHrNAE,3872
2
+ phoenix/config.py,sha256=iGZeRwpvQG-JOzlfv642f98rCAHQ1SpGiEvgJsxg-1g,4682
3
3
  phoenix/datetime_utils.py,sha256=D955QLrkgrrSdUM6NyqbCeAu2SMsjhR5rHVQEsVUdng,2773
4
4
  phoenix/exceptions.py,sha256=X5k9ipUDfwSCwZB-H5zFJLas86Gf9tAx0W4l5TZxp5k,108
5
5
  phoenix/py.typed,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
6
6
  phoenix/services.py,sha256=f6AeyKTuOpy9RCcTCjVH3gx5nYZhbTMFOuv1WSUOB5o,4992
7
- phoenix/version.py,sha256=f8-0K-K9GknTfMcWvP5jj3XhIXV87K09GjV-81wN-ec,23
7
+ phoenix/version.py,sha256=J-RNnUtG3KXQUxCskuOvUbJtBakEXz0p3uLA1teKUpk,23
8
8
  phoenix/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
9
  phoenix/core/embedding_dimension.py,sha256=zKGbcvwOXgLf-yrJBpQyKtd-LEOPRKHnUToyAU8Owis,87
10
10
  phoenix/core/model.py,sha256=C-kDATyJEgP-oqYVKOiQM76Ljs66F6VZdT93_b8kTGk,4725
11
11
  phoenix/core/model_schema.py,sha256=lQaTvKS34yurHOJ53YD020uURLfgG3dqKC1NLQftOjA,50222
12
12
  phoenix/core/model_schema_adapter.py,sha256=3GkyzqUST4fYi-Bgs8qAam5hwMCdQRZTDLjZ9Bnzdm4,8268
13
- phoenix/core/project.py,sha256=z-Yrwyg50TqP48mZ8nQC2ZSxrebrJL_OoMp5EIZi_NE,24635
14
- phoenix/core/traces.py,sha256=_AiOt1XRNMU_XTRXZBsjdYuF_zHn87Vm80mW0Y7PA9Q,2935
13
+ phoenix/core/project.py,sha256=KBntQewZ02XkU9GIHFlncTHjPFokTeCTMY5pQpg8HkE,24817
14
+ phoenix/core/traces.py,sha256=54Xsp-rBMMdeT8KDVrK1M7g4QGXHFlKgVfVEs5KnQzg,3549
15
15
  phoenix/datasets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
16
  phoenix/datasets/dataset.py,sha256=scKVZ7zc6Dpc_ntt-pWhzY-KWqOJEwKePuyNnKSVTGE,30515
17
17
  phoenix/datasets/errors.py,sha256=cGp9vxnw4SewFoWBV3ZGMkhE0Kh73lPIv3Ppz_H_RoA,8261
@@ -55,14 +55,14 @@ phoenix/pointcloud/pointcloud.py,sha256=4zAIkKs2xOUbchpj4XDAV-iPMXrfAJ15TG6rlIYG
55
55
  phoenix/pointcloud/projectors.py,sha256=zO_RrtDYSv2rqVOfIP2_9Cv11Dc8EmcZR94xhFcBYPU,1057
56
56
  phoenix/pointcloud/umap_parameters.py,sha256=lJsEOrbSuSiqI7g4Yt6xj7kgYxEqoep4ZHWLr6VWBqw,1760
57
57
  phoenix/server/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
58
- phoenix/server/app.py,sha256=cNEskfuSyG7XGdt802VZin-keJk78f8Fm0jaFE94Py8,6887
59
- phoenix/server/main.py,sha256=nprpPH6eBAKwJ7OjY1bZxQtcukfJpv7b_IuTVwchZWM,10351
58
+ phoenix/server/app.py,sha256=7yGzmItFLoTFa5CBZwz4Qb2VZbVbczh_3qRqTTtkaKw,6888
59
+ phoenix/server/main.py,sha256=wrKegfYm-5APU0CqPqpEE_3MUlSgU2LPfpEkYSd870E,9457
60
60
  phoenix/server/thread_server.py,sha256=dP6cm6Cf08jNhDA1TRlVZpziu1YgtPDmaeIJMm725eI,2154
61
61
  phoenix/server/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
62
62
  phoenix/server/api/context.py,sha256=wjCzq4QlszKG1iN-xgu5rRLYPqdvTFqX02aFYPipNoQ,512
63
63
  phoenix/server/api/helpers.py,sha256=_V1eVkchZmTkhOfRC4QqR1sUB2xtIxdsMJkDouZq_IE,251
64
64
  phoenix/server/api/interceptor.py,sha256=ykDnoC_apUd-llVli3m1CW18kNSIgjz2qZ6m5JmPDu8,1294
65
- phoenix/server/api/schema.py,sha256=wYwmxM9tqZVd4OK8KN3KusVibThjaC4YSC-GnBlO-TY,7969
65
+ phoenix/server/api/schema.py,sha256=UpYm8wFwHeQfSX25WwDkhBPilIjiXQ4PSoQUclv3IHc,8839
66
66
  phoenix/server/api/input_types/ClusterInput.py,sha256=EL4ftvZxQ8mVdruUPcdhMhByORmSmM8S-X6RPqU6GX0,179
67
67
  phoenix/server/api/input_types/Coordinates.py,sha256=meTwbIjwTfqx5DGD2DBlH9wQzdQVNM5a8x9dp1FfIgA,173
68
68
  phoenix/server/api/input_types/DataQualityMetricInput.py,sha256=LazvmQCCM5m9SDZTpyxQXO1rYF4cmsc3lsR2S9S65X4,1292
@@ -74,9 +74,9 @@ phoenix/server/api/input_types/SpanSort.py,sha256=3ken7KaDUwoZfhaSiP9QRhkNPgGrCY
74
74
  phoenix/server/api/input_types/TimeRange.py,sha256=yzx-gxj8mDeGLft1FzU_x1MVEgIG5Pt6-f8PUVDgipQ,522
75
75
  phoenix/server/api/input_types/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
76
76
  phoenix/server/api/routers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
77
- phoenix/server/api/routers/evaluation_handler.py,sha256=viXigPYCOzN8bgmu_OcfEwl8jHkwarAw65bnGpvlR98,3852
78
- phoenix/server/api/routers/span_handler.py,sha256=CdW8pYQW2y2eSW5Y-d6ce2pgmo4v16vGC6ohVo1bkwg,2398
79
- phoenix/server/api/routers/trace_handler.py,sha256=GVEl5y3QvnElmUVJCPUtQnVAbC6kOvL6JjOfx53JCLI,2412
77
+ phoenix/server/api/routers/evaluation_handler.py,sha256=IkVKe2CMEaHNb_k_eGq1PWBURfbhcg0KjI7m0Eh-9wc,3949
78
+ phoenix/server/api/routers/span_handler.py,sha256=IM4eiQ7GMU7JVyf0oMbrzEcItVudLy_CeYaWcwHOby4,2387
79
+ phoenix/server/api/routers/trace_handler.py,sha256=0Y9QlePySJZyhKJLWM-m1e837HMZm5QcKR-iXshQdG4,2413
80
80
  phoenix/server/api/routers/utils.py,sha256=M41BoH-fl37izhRuN2aX7lWm7jOC20A_3uClv9TVUUY,583
81
81
  phoenix/server/api/types/Cluster.py,sha256=R08ZKrLl1KK8colxHU57N5XIOTMUwg5ZI50ofPoxxSM,5618
82
82
  phoenix/server/api/types/DataQualityMetric.py,sha256=zRKsNvHBu-NdcsunuLhqFpZhi6ks-HMqA1PJD27jTak,590
@@ -109,7 +109,7 @@ phoenix/server/api/types/Retrieval.py,sha256=OhMK2ncjoyp5h1yjKhjlKpoTbQrMHuxmgSF
109
109
  phoenix/server/api/types/ScalarDriftMetricEnum.py,sha256=IUAcRPpgL41WdoIgK6cNk2Te38SspXGyEs-S1fY23_A,232
110
110
  phoenix/server/api/types/Segments.py,sha256=B6UUWjalZONjWjl_l61A6USPSu15ICXRgzZ4m3vA1yw,2921
111
111
  phoenix/server/api/types/SortDir.py,sha256=OUpXhlCzCxPoXSDkJJygEs9Rw9pMymfaZUG5zPTrw4Y,152
112
- phoenix/server/api/types/Span.py,sha256=obTJMMeSUD8qIen_XIKW0PDdadlFu2pj4dPpxjb7uI8,12328
112
+ phoenix/server/api/types/Span.py,sha256=VvwYVlX4kOEFDPj63nHaOOilJTQqooSqRZ8HWsF0jgA,12317
113
113
  phoenix/server/api/types/TimeSeries.py,sha256=QbLfxHnwYsMsirpq4tx9us6ha7YtAVzK4m8mAL3fMt0,5200
114
114
  phoenix/server/api/types/UMAPPoints.py,sha256=8l9RJXi308qty4MdHb2pBbiU6ZuLbrRRxXNbPhXoxKI,1639
115
115
  phoenix/server/api/types/ValidationResult.py,sha256=pHwdYk4J7SJ5xhlWWHg_6qWkfk4rjOx-bSkGHvkDE3Q,142
@@ -127,25 +127,25 @@ phoenix/server/static/apple-touch-icon-76x76.png,sha256=CT_xT12I0u2i0WU8JzBZBuOQ
127
127
  phoenix/server/static/apple-touch-icon.png,sha256=fOfpjqGpWYbJ0eAurKsyoZP1EAs6ZVooBJ_SGk2ZkDs,3801
128
128
  phoenix/server/static/favicon.ico,sha256=bY0vvCKRftemZfPShwZtE93DiiQdaYaozkPGwNFr6H8,34494
129
129
  phoenix/server/static/index.css,sha256=KKGpx4iwF91VGRm0YN-4cn8oC-oIqC6HecoPf0x3ZM8,1885
130
- phoenix/server/static/index.js,sha256=-z9E12Tquch7keYjnWNreqYiDvwwCa7f3Q95hoRtlqM,3175772
130
+ phoenix/server/static/index.js,sha256=BiowVdHNX_auo5iceVwOMavsVQFFXSh-FG0HH8ybheQ,3176868
131
131
  phoenix/server/static/modernizr.js,sha256=mvK-XtkNqjOral-QvzoqsyOMECXIMu5BQwSVN_wcU9c,2564
132
132
  phoenix/server/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
133
133
  phoenix/server/templates/index.html,sha256=lO2wGA5XsftPg03rw_VcyaYf_4vegtlWbIT5ms4fA_c,1982
134
134
  phoenix/session/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
135
- phoenix/session/client.py,sha256=9qlybwGGdPHql7n6Mye8feuh5_5AMq34xSajvcPn2yg,5853
135
+ phoenix/session/client.py,sha256=EMhzmsqquZbuuH0NX137npYLVJWEKI5OieeCBsVGh3A,7933
136
136
  phoenix/session/data_extractor.py,sha256=0Kf-2mKY_YbYoD2fZkAYpKdFgsXrC3OKQ5d2iZsGgAI,1947
137
137
  phoenix/session/evaluation.py,sha256=YCv1XkWHi7vM_W5V7rorrrAxadv78wuMPeCVJvf5-oE,5444
138
- phoenix/session/session.py,sha256=1RV6FBNqNDDrPFYU2qLffmI4RCRKy22KCLZFcH9oqJA,24556
138
+ phoenix/session/session.py,sha256=9NsZCvrozDfFNc2b4dhadSuYHAO7rJLCvrgA0qangqg,24919
139
139
  phoenix/storage/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
140
- phoenix/storage/spanstore/__init__.py,sha256=Q1tfrRcYCTVbxQGWGCkfb2i1YTweiYixQZ-kNG1ViZQ,228
141
- phoenix/storage/spanstore/text_file.py,sha256=Fzpl_UDVN6_Qa8kpjhDkjdO7xb_I3g-UuTseenkV42c,2853
142
- phoenix/trace/__init__.py,sha256=DOuudYVyWlhUnIy-E_aqvJ6ulmk_q7ghuctuXQCGCJA,763
140
+ phoenix/storage/span_store/__init__.py,sha256=ib-1BWPX4zMfIxS_qC-intyZciGMBJkAOcpb06d3jgQ,586
141
+ phoenix/storage/span_store/text_file.py,sha256=Fzpl_UDVN6_Qa8kpjhDkjdO7xb_I3g-UuTseenkV42c,2853
142
+ phoenix/trace/__init__.py,sha256=hXo7FzA-utf7CD9PiZQYfQ-0irqHVzfSA4j_RLSmKK4,891
143
143
  phoenix/trace/errors.py,sha256=wB1z8qdPckngdfU-TORToekvg3344oNFAA83_hC2yFY,180
144
144
  phoenix/trace/evaluation_conventions.py,sha256=t8jydM3U0-T5YpiQKRJ3tWdWGlHtzKyttYdw-ddvPOk,1048
145
145
  phoenix/trace/exporter.py,sha256=vh2RO1CpP143HxIX94KV0qks8p1x66RE3Tgf8kcBCCg,4519
146
146
  phoenix/trace/fixtures.py,sha256=HOjuYOB_xtR7JUeLz7WpEroiGj4E5_SxVLSjBYUy8RQ,7055
147
147
  phoenix/trace/otel.py,sha256=mpuj_eOdBUPAcslpxk8XZflb9kkzpMJ8X9acJS8ACPA,15322
148
- phoenix/trace/projects.py,sha256=uIicJWWBAVwiRY-8EH2YlQmCUzsdspTxsz-ceK35m8E,1826
148
+ phoenix/trace/projects.py,sha256=2BwlNjFE-uwpqYtCu5YyBiYZk9wRPpM13vh3-Cv7GkA,2157
149
149
  phoenix/trace/schemas.py,sha256=6PVPnQIIDsWijwCwU19TGKG3xhFCYFY9K_5IqR5dWF4,5904
150
150
  phoenix/trace/span_evaluations.py,sha256=T67grfU71iANMM0g6dp2OQ_ZjtkON2viZz95_U9FLQA,12954
151
151
  phoenix/trace/span_json_decoder.py,sha256=IAFakPRqSMYxTPKYFMiXYxm7U-FipdN8_xbvapDS0Qc,3131
@@ -154,7 +154,7 @@ phoenix/trace/trace_dataset.py,sha256=RpHIfZLbMmULOIb-fKXJkQLhIdC0sJlAOTjlyJppMY
154
154
  phoenix/trace/utils.py,sha256=7LurVGXn245cjj4MJsc7v6jq4DSJkpK6YGBfIaSywuw,1307
155
155
  phoenix/trace/dsl/__init__.py,sha256=WIQIjJg362XD3s50OsPJJ0xbDsGp41bSv7vDllLrPuA,144
156
156
  phoenix/trace/dsl/filter.py,sha256=paLpcSMnHdgCfcvcroaqOoCe2retAZ5ocp_5cNTnv9s,14167
157
- phoenix/trace/dsl/helpers.py,sha256=CP6WaJpP7_WdI1Yoip7tDWcYDXZRg6xgNBRS2gojjMc,1728
157
+ phoenix/trace/dsl/helpers.py,sha256=TG8EFZAjvRwjXpxitEGAc4QpF3vn4jpqhI_Tcwp5mE4,2134
158
158
  phoenix/trace/dsl/missing.py,sha256=BWPOHr2_tBkPDgVeq8GVXXVbNbJiBelu4NtwHBg6mTE,1435
159
159
  phoenix/trace/dsl/query.py,sha256=k0guhWBEo6L7ZJH5FJs2-iGSnWXdUUqu09gd-8M4CGg,14783
160
160
  phoenix/trace/langchain/__init__.py,sha256=F37GfD1pd5Kuw7R7iRUM1zXXpO8xEcycNZh5dwqBXNk,109
@@ -169,9 +169,10 @@ phoenix/trace/v1/evaluation_pb2.pyi,sha256=cCbbx06gwQmaH14s3J1X25TtaARh-k1abbxQd
169
169
  phoenix/utilities/__init__.py,sha256=8w1Ivw0KO9YKWrhcdnO73cSVqP9VHAp0pSfsi_oDiuQ,672
170
170
  phoenix/utilities/error_handling.py,sha256=7b5rpGFj9EWZ8yrZK1IHvxB89suWk3lggDayUQcvZds,1946
171
171
  phoenix/utilities/logging.py,sha256=lDXd6EGaamBNcQxL4vP1au9-i_SXe0OraUDiJOcszSw,222
172
- phoenix/utilities/project.py,sha256=AzyuKxh3IByoKapA-AIRzZNFw_c0zh9RNjhh3BT_YWI,416
173
- arize_phoenix-3.14.2.dist-info/METADATA,sha256=cW_o29Zdw_iIxdLHoi3SD3eW76e-gKTy3Svhhy9PsR8,29204
174
- arize_phoenix-3.14.2.dist-info/WHEEL,sha256=TJPnKdtrSue7xZ_AVGkp9YXcvDrobsjBds1du3Nx6dc,87
175
- arize_phoenix-3.14.2.dist-info/licenses/IP_NOTICE,sha256=JBqyyCYYxGDfzQ0TtsQgjts41IJoa-hiwDrBjCb9gHM,469
176
- arize_phoenix-3.14.2.dist-info/licenses/LICENSE,sha256=HFkW9REuMOkvKRACuwLPT0hRydHb3zNg-fdFt94td18,3794
177
- arize_phoenix-3.14.2.dist-info/RECORD,,
172
+ phoenix/utilities/project.py,sha256=qWsvKnG1oKhOFUowXf9qiOL2ia7jaFe_ijFFHEt8GJo,431
173
+ phoenix/utilities/span_store.py,sha256=13UK0rE4wQd70yl___WsDRnH0ru-xErng9_Ml7zfEwE,978
174
+ arize_phoenix-3.15.0.dist-info/METADATA,sha256=gKH9s1rkv3nk2_cIE_C2RJBhDdWBzyES0a_v-4gVuhU,29204
175
+ arize_phoenix-3.15.0.dist-info/WHEEL,sha256=TJPnKdtrSue7xZ_AVGkp9YXcvDrobsjBds1du3Nx6dc,87
176
+ arize_phoenix-3.15.0.dist-info/licenses/IP_NOTICE,sha256=JBqyyCYYxGDfzQ0TtsQgjts41IJoa-hiwDrBjCb9gHM,469
177
+ arize_phoenix-3.15.0.dist-info/licenses/LICENSE,sha256=HFkW9REuMOkvKRACuwLPT0hRydHb3zNg-fdFt94td18,3794
178
+ arize_phoenix-3.15.0.dist-info/RECORD,,
phoenix/config.py CHANGED
@@ -1,5 +1,6 @@
1
1
  import os
2
2
  import tempfile
3
+ from enum import Enum
3
4
  from pathlib import Path
4
5
  from typing import List, Optional
5
6
 
@@ -21,6 +22,11 @@ ENV_PHOENIX_PROJECT_NAME = "PHOENIX_PROJECT_NAME"
21
22
  """
22
23
  The project name to use when logging traces and evals. defaults to 'default'.
23
24
  """
25
+ ENV_SPAN_STORAGE_TYPE = "__DANGEROUS__PHOENIX_SPAN_STORAGE_TYPE"
26
+ """
27
+ **EXPERIMENTAL**
28
+ The type of span storage to use.
29
+ """
24
30
 
25
31
 
26
32
  def _get_temp_path() -> Path:
@@ -127,4 +133,27 @@ def get_env_collector_endpoint() -> Optional[str]:
127
133
 
128
134
 
129
135
  def get_env_project_name() -> str:
130
- return os.getenv(ENV_PHOENIX_PROJECT_NAME) or "default"
136
+ return os.getenv(ENV_PHOENIX_PROJECT_NAME) or DEFAULT_PROJECT_NAME
137
+
138
+
139
+ def get_env_span_storage_type() -> Optional["SpanStorageType"]:
140
+ """
141
+ Get the type of span storage to use.
142
+ """
143
+ if not (env_type_str := os.getenv(ENV_SPAN_STORAGE_TYPE)):
144
+ return None
145
+ try:
146
+ return SpanStorageType(env_type_str.lower())
147
+ except ValueError:
148
+ raise ValueError(
149
+ f"⚠️ Invalid span storage type value `{env_type_str}` defined by the "
150
+ f"environment variable `{ENV_SPAN_STORAGE_TYPE}`. Valid values are: "
151
+ f"{', '.join(t.value for t in SpanStorageType)}."
152
+ )
153
+
154
+
155
+ class SpanStorageType(Enum):
156
+ TEXT_FILES = "text-files"
157
+
158
+
159
+ DEFAULT_PROJECT_NAME = "default"
phoenix/core/project.py CHANGED
@@ -91,6 +91,7 @@ class Project:
91
91
  def __init__(self) -> None:
92
92
  self._spans = _Spans()
93
93
  self._evals = _Evals()
94
+ self._is_archived = False
94
95
 
95
96
  @property
96
97
  def last_updated_at(self) -> Optional[datetime]:
@@ -192,6 +193,13 @@ class Project:
192
193
  def export_evaluations(self) -> List[Evaluations]:
193
194
  return self._evals.export_evaluations()
194
195
 
196
+ def archive(self) -> None:
197
+ self._is_archived = True
198
+
199
+ @property
200
+ def is_archived(self) -> bool:
201
+ return self._is_archived
202
+
195
203
 
196
204
  class _Spans:
197
205
  def __init__(self) -> None:
phoenix/core/traces.py CHANGED
@@ -8,13 +8,13 @@ from typing import DefaultDict, Iterator, Optional, Tuple, Union
8
8
  from typing_extensions import assert_never
9
9
 
10
10
  import phoenix.trace.v1 as pb
11
+ from phoenix.config import DEFAULT_PROJECT_NAME
11
12
  from phoenix.core.project import (
12
13
  END_OF_QUEUE,
13
14
  Project,
14
15
  _ProjectName,
15
16
  )
16
17
  from phoenix.trace.schemas import Span
17
- from phoenix.utilities.project import DEFAULT_PROJECT_NAME
18
18
 
19
19
  _SpanItem = Tuple[Span, _ProjectName]
20
20
  _EvalItem = Tuple[pb.Evaluation, _ProjectName]
@@ -38,10 +38,26 @@ class Traces:
38
38
  with self._lock:
39
39
  return self._projects.get(project_name)
40
40
 
41
- def get_projects(self) -> Iterator[Tuple[str, "Project"]]:
41
+ def get_projects(self) -> Iterator[Tuple[int, str, "Project"]]:
42
42
  with self._lock:
43
- projects = tuple(self._projects.items())
44
- yield from projects
43
+ for project_id, (project_name, project) in enumerate(self._projects.items()):
44
+ if project.is_archived:
45
+ continue
46
+ yield project_id, project_name, project
47
+
48
+ def archive_project(self, id: int) -> Optional["Project"]:
49
+ with self._lock:
50
+ active_projects = {
51
+ project_id: project
52
+ for project_id, _, project in self.get_projects()
53
+ if not project.is_archived
54
+ }
55
+ if len(active_projects) <= 1:
56
+ return None
57
+ if project := active_projects.get(id):
58
+ project.archive()
59
+ return project
60
+ return None
45
61
 
46
62
  def put(
47
63
  self,
@@ -15,11 +15,11 @@ from starlette.status import (
15
15
  )
16
16
 
17
17
  import phoenix.trace.v1 as pb
18
+ from phoenix.config import DEFAULT_PROJECT_NAME
18
19
  from phoenix.core.traces import Traces
19
20
  from phoenix.server.api.routers.utils import table_to_bytes
20
21
  from phoenix.session.evaluation import encode_evaluations
21
22
  from phoenix.trace.span_evaluations import Evaluations
22
- from phoenix.utilities.project import DEFAULT_PROJECT_NAME
23
23
 
24
24
 
25
25
  class EvaluationHandler(HTTPEndpoint):
@@ -27,6 +27,7 @@ class EvaluationHandler(HTTPEndpoint):
27
27
 
28
28
  async def post(self, request: Request) -> Response:
29
29
  content_type = request.headers.get("content-type")
30
+ project_name = request.headers.get("project-name", DEFAULT_PROJECT_NAME)
30
31
  if content_type == "application/x-pandas-arrow":
31
32
  return await self._process_pyarrow(request)
32
33
  if content_type != "application/x-protobuf":
@@ -51,7 +52,7 @@ class EvaluationHandler(HTTPEndpoint):
51
52
  content="Request body is invalid",
52
53
  status_code=HTTP_422_UNPROCESSABLE_ENTITY,
53
54
  )
54
- self.traces.put(evaluation)
55
+ self.traces.put(evaluation, project_name=project_name)
55
56
  return Response()
56
57
 
57
58
  async def get(self, request: Request) -> Response:
@@ -7,11 +7,11 @@ from starlette.requests import Request
7
7
  from starlette.responses import Response, StreamingResponse
8
8
  from starlette.status import HTTP_404_NOT_FOUND, HTTP_422_UNPROCESSABLE_ENTITY
9
9
 
10
+ from phoenix.config import DEFAULT_PROJECT_NAME
10
11
  from phoenix.core.traces import Traces
11
12
  from phoenix.server.api.routers.utils import df_to_bytes, from_iso_format
12
13
  from phoenix.trace.dsl import SpanQuery
13
14
  from phoenix.utilities import query_spans
14
- from phoenix.utilities.project import DEFAULT_PROJECT_NAME
15
15
 
16
16
 
17
17
  class SpanHandler(HTTPEndpoint):
@@ -14,7 +14,7 @@ from starlette.responses import Response
14
14
  from starlette.status import HTTP_415_UNSUPPORTED_MEDIA_TYPE, HTTP_422_UNPROCESSABLE_ENTITY
15
15
 
16
16
  from phoenix.core.traces import Traces
17
- from phoenix.storage.spanstore import SpanStore
17
+ from phoenix.storage.span_store import SpanStore
18
18
  from phoenix.trace.otel import decode
19
19
  from phoenix.utilities.project import get_project_name
20
20
 
@@ -56,8 +56,8 @@ class Query:
56
56
  []
57
57
  if (traces := info.context.traces) is None
58
58
  else [
59
- Project(id_attr=i, name=name, project=project)
60
- for i, (name, project) in enumerate(traces.get_projects())
59
+ Project(id_attr=project_id, name=project_name, project=project)
60
+ for project_id, project_name, project in traces.get_projects()
61
61
  ]
62
62
  )
63
63
  return connection_from_list(data=data, args=args)
@@ -86,8 +86,11 @@ class Query:
86
86
  return to_gql_embedding_dimension(node_id, embedding_dimension)
87
87
  elif type_name == "Project":
88
88
  if (traces := info.context.traces) is not None:
89
- projects = list(traces.get_projects())
90
- if node_id < len(projects):
89
+ projects = {
90
+ project_id: (project_name, project)
91
+ for project_id, project_name, project in traces.get_projects()
92
+ }
93
+ if node_id in projects:
91
94
  name, project = projects[node_id]
92
95
  return Project(id_attr=node_id, name=name, project=project)
93
96
  raise Exception(f"Unknown project: {id}")
@@ -224,7 +227,26 @@ class Query:
224
227
 
225
228
 
226
229
  @strawberry.type
227
- class Mutation(ExportEventsMutation): ...
230
+ class Mutation(ExportEventsMutation):
231
+ @strawberry.mutation
232
+ def delete_project(self, info: Info[Context, None], id: GlobalID) -> Query:
233
+ if (traces := info.context.traces) is None:
234
+ return Query()
235
+ type_name, node_id = from_global_id(str(id))
236
+ if type_name != "Project":
237
+ return Query()
238
+ traces.archive_project(node_id)
239
+ return Query()
240
+
241
+ @strawberry.mutation
242
+ def archive_project(self, info: Info[Context, None], id: GlobalID) -> Query:
243
+ if (traces := info.context.traces) is None:
244
+ return Query()
245
+ type_name, node_id = from_global_id(str(id))
246
+ if type_name != "Project":
247
+ return Query()
248
+ traces.archive_project(node_id)
249
+ return Query()
228
250
 
229
251
 
230
252
  schema = strawberry.Schema(query=Query, mutation=Mutation)
@@ -10,6 +10,7 @@ from strawberry import ID, UNSET
10
10
  from strawberry.types import Info
11
11
 
12
12
  import phoenix.trace.schemas as trace_schema
13
+ from phoenix.config import DEFAULT_PROJECT_NAME
13
14
  from phoenix.core.project import Project, WrappedSpan
14
15
  from phoenix.metrics.retrieval_metrics import RetrievalMetrics
15
16
  from phoenix.server.api.context import Context
@@ -17,7 +18,6 @@ from phoenix.server.api.types.DocumentRetrievalMetrics import DocumentRetrievalM
17
18
  from phoenix.server.api.types.Evaluation import DocumentEvaluation, SpanEvaluation
18
19
  from phoenix.server.api.types.MimeType import MimeType
19
20
  from phoenix.trace.schemas import ComputedAttributes, SpanID
20
- from phoenix.utilities.project import DEFAULT_PROJECT_NAME
21
21
 
22
22
  EMBEDDING_EMBEDDINGS = SpanAttributes.EMBEDDING_EMBEDDINGS
23
23
  EMBEDDING_VECTOR = EmbeddingAttributes.EMBEDDING_VECTOR
phoenix/server/app.py CHANGED
@@ -28,7 +28,7 @@ from phoenix.server.api.routers.evaluation_handler import EvaluationHandler
28
28
  from phoenix.server.api.routers.span_handler import SpanHandler
29
29
  from phoenix.server.api.routers.trace_handler import TraceHandler
30
30
  from phoenix.server.api.schema import schema
31
- from phoenix.storage.spanstore import SpanStore
31
+ from phoenix.storage.span_store import SpanStore
32
32
 
33
33
  logger = logging.getLogger(__name__)
34
34
 
phoenix/server/main.py CHANGED
@@ -16,7 +16,6 @@ from phoenix.config import (
16
16
  get_env_host,
17
17
  get_env_port,
18
18
  get_pids_path,
19
- get_storage_dir,
20
19
  )
21
20
  from phoenix.core.model_schema_adapter import create_model_from_datasets
22
21
  from phoenix.core.traces import Traces
@@ -29,8 +28,7 @@ from phoenix.pointcloud.umap_parameters import (
29
28
  UMAPParameters,
30
29
  )
31
30
  from phoenix.server.app import create_app
32
- from phoenix.storage.spanstore import SpanStore
33
- from phoenix.storage.spanstore.text_file import TextFileSpanStoreImpl
31
+ from phoenix.storage.span_store import SpanStore
34
32
  from phoenix.trace.fixtures import (
35
33
  TRACES_FIXTURES,
36
34
  _download_traces_fixture,
@@ -39,7 +37,7 @@ from phoenix.trace.fixtures import (
39
37
  )
40
38
  from phoenix.trace.otel import decode, encode
41
39
  from phoenix.trace.span_json_decoder import json_string_to_span
42
- from phoenix.utilities.project import get_project_name
40
+ from phoenix.utilities.span_store import get_span_store, load_traces_data_from_store
43
41
 
44
42
  logger = logging.getLogger(__name__)
45
43
 
@@ -108,15 +106,6 @@ def _load_items(
108
106
  queue.put(item)
109
107
 
110
108
 
111
- def _load_from_store(traces: Traces, span_store: SpanStore) -> None:
112
- for traces_data in span_store.load():
113
- for resource_spans in traces_data.resource_spans:
114
- project_name = get_project_name(resource_spans.resource.attributes)
115
- for scope_span in resource_spans.scope_spans:
116
- for span in scope_span.spans:
117
- traces.put(decode(span), project_name=project_name)
118
-
119
-
120
109
  DEFAULT_UMAP_PARAMS_STR = f"{DEFAULT_MIN_DIST},{DEFAULT_N_NEIGHBORS},{DEFAULT_N_SAMPLES}"
121
110
 
122
111
  if __name__ == "__main__":
@@ -142,8 +131,6 @@ if __name__ == "__main__":
142
131
  parser.add_argument("--debug", action="store_false")
143
132
  subparsers = parser.add_subparsers(dest="command", required=True)
144
133
  serve_parser = subparsers.add_parser("serve")
145
- experimental_parser = subparsers.add_parser("extremely-dangerous-experimental-span-storage")
146
- experimental_parser.add_argument("--storage-path", type=str, required=False)
147
134
  datasets_parser = subparsers.add_parser("datasets")
148
135
  datasets_parser.add_argument("--primary", type=str, required=True)
149
136
  datasets_parser.add_argument("--reference", type=str, required=False)
@@ -200,19 +187,14 @@ if __name__ == "__main__":
200
187
  )
201
188
  trace_dataset_name = args.trace_fixture
202
189
  simulate_streaming = args.simulate_streaming
203
- elif args.command == "extremely-dangerous-experimental-span-storage":
204
- span_store_path = (
205
- get_storage_dir() if args.storage_path is None else Path(args.storage_path)
206
- )
207
- span_store = TextFileSpanStoreImpl(span_store_path)
208
190
 
209
191
  model = create_model_from_datasets(
210
192
  primary_dataset,
211
193
  reference_dataset,
212
194
  )
213
195
  traces = Traces()
214
- if span_store:
215
- Thread(target=_load_from_store, args=(traces, span_store), daemon=True).start()
196
+ if span_store := get_span_store():
197
+ Thread(target=load_traces_data_from_store, args=(traces, span_store), daemon=True).start()
216
198
  if trace_dataset_name is not None:
217
199
  fixture_spans = list(
218
200
  # Apply `encode` here because legacy jsonl files contains UUIDs as strings.