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

Files changed (30) hide show
  1. {arize_phoenix-4.22.1.dist-info → arize_phoenix-4.24.0.dist-info}/METADATA +2 -2
  2. {arize_phoenix-4.22.1.dist-info → arize_phoenix-4.24.0.dist-info}/RECORD +29 -24
  3. phoenix/db/migrations/future_versions/cd164e83824f_users_and_tokens.py +1 -1
  4. phoenix/db/models.py +4 -0
  5. phoenix/experiments/functions.py +8 -0
  6. phoenix/server/api/mutations/dataset_mutations.py +52 -12
  7. phoenix/server/api/queries.py +104 -0
  8. phoenix/server/api/types/ApiKey.py +16 -0
  9. phoenix/server/api/types/Span.py +20 -2
  10. phoenix/server/api/types/SystemApiKey.py +9 -0
  11. phoenix/server/api/types/User.py +16 -0
  12. phoenix/server/api/types/UserApiKey.py +11 -0
  13. phoenix/server/api/types/UserRole.py +8 -0
  14. phoenix/server/app.py +5 -0
  15. phoenix/server/main.py +12 -0
  16. phoenix/server/static/.vite/manifest.json +31 -31
  17. phoenix/server/static/assets/{components-BC3-LP_a.js → components-DzA9gIHT.js} +48 -48
  18. phoenix/server/static/assets/index-BuTlV4Gk.js +100 -0
  19. phoenix/server/static/assets/{pages--n2933VW.js → pages-DzkUGFGV.js} +230 -203
  20. phoenix/server/static/assets/{vendor-BMWfu6zp.js → vendor-CIqy43_9.js} +1 -1
  21. phoenix/server/static/assets/{vendor-arizeai-Sj74jm5V.js → vendor-arizeai-B1YgcWL8.js} +1 -1
  22. phoenix/server/static/assets/{vendor-codemirror-DO3VqEcD.js → vendor-codemirror-_bcwCA1C.js} +1 -1
  23. phoenix/server/static/assets/{vendor-recharts-BGN0SxgJ.js → vendor-recharts-C3pM_Wlg.js} +1 -1
  24. phoenix/server/templates/index.html +2 -1
  25. phoenix/session/session.py +1 -0
  26. phoenix/version.py +1 -1
  27. phoenix/server/static/assets/index-BjJvafYL.js +0 -100
  28. {arize_phoenix-4.22.1.dist-info → arize_phoenix-4.24.0.dist-info}/WHEEL +0 -0
  29. {arize_phoenix-4.22.1.dist-info → arize_phoenix-4.24.0.dist-info}/licenses/IP_NOTICE +0 -0
  30. {arize_phoenix-4.22.1.dist-info → arize_phoenix-4.24.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: arize-phoenix
3
- Version: 4.22.1
3
+ Version: 4.24.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
@@ -80,7 +80,7 @@ Requires-Dist: jupyter; extra == 'dev'
80
80
  Requires-Dist: langchain>=0.0.334; extra == 'dev'
81
81
  Requires-Dist: litellm>=1.0.3; extra == 'dev'
82
82
  Requires-Dist: llama-index>=0.10.3; extra == 'dev'
83
- Requires-Dist: mypy==1.11.0; extra == 'dev'
83
+ Requires-Dist: mypy==1.11.1; extra == 'dev'
84
84
  Requires-Dist: nbqa; extra == 'dev'
85
85
  Requires-Dist: pandas-stubs==2.0.3.230814; (python_version < '3.9') and extra == 'dev'
86
86
  Requires-Dist: pandas-stubs==2.2.2.240603; (python_version >= '3.9') and extra == 'dev'
@@ -5,7 +5,7 @@ phoenix/exceptions.py,sha256=n2L2KKuecrdflB9MsCdAYCiSEvGJptIsfRkXMoJle7A,169
5
5
  phoenix/py.typed,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
6
6
  phoenix/services.py,sha256=aTxhcOA1pZHB6U-B3TEcp6fqDF5oT0xCUvEUNMZVTUQ,5175
7
7
  phoenix/settings.py,sha256=cO-qgis_S27nHirTobYI9hHPfZH18R--WMmxNdsVUwc,273
8
- phoenix/version.py,sha256=o6NOndzGr8AzXGIlB0Kpj1jAyiWB77iB92rO-Vlh2y0,23
8
+ phoenix/version.py,sha256=l7f0EI2kXBLXXp82SILFQvXoX83QSluu_cmoTReAP9g,23
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=km_a--PBHOuA337ClRw9xqhOHhrUT6Rl9pz_zV0JYkQ,4843
@@ -18,7 +18,7 @@ phoenix/db/bulk_inserter.py,sha256=qgg8pt5k4VnHKOE0-KoReXVAfXRhLt-sMZihI-b4X9I,1
18
18
  phoenix/db/engines.py,sha256=R3btYTSOSd6BwRA59EmhhojL0HCQ7NnzFIXQrPYS0iU,4812
19
19
  phoenix/db/helpers.py,sha256=2zSc4n5IJfu-CaOFoBfqTB35M1nTFcAc8tqLsNtF2Jw,3488
20
20
  phoenix/db/migrate.py,sha256=MuhtNWnR24riROvarvKfbRb4_D5xuQi6P760vBUKl1E,2270
21
- phoenix/db/models.py,sha256=C_s1TAgMRi2eExc48NwInErsfSzVhNZtj4ow23jUKSc,23352
21
+ phoenix/db/models.py,sha256=96XA9m3vV-HpQDggHqGWPNvAOEMANediIbvvqAUaY7U,23686
22
22
  phoenix/db/insertion/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
23
23
  phoenix/db/insertion/constants.py,sha256=8wifm7X-1XvroZ__R2Gc96NsgLhTDn0zXl4lehlXtcA,70
24
24
  phoenix/db/insertion/dataset.py,sha256=_vxy5e6W5jEuvO2fMKbbNCn9JvHkwI4LRKk_10eKFVg,7171
@@ -33,13 +33,13 @@ phoenix/db/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3h
33
33
  phoenix/db/migrations/env.py,sha256=QbzB5zrRs6XQQmrYeUpuzeilcMlM-MsbaAgHHYcIHTI,3626
34
34
  phoenix/db/migrations/script.py.mako,sha256=MEqL-2qATlST9TAOeYgscMn1uy6HUS9NFvDgl93dMj8,635
35
35
  phoenix/db/migrations/future_versions/README.md,sha256=3QtDx40SAD-IITjbdlKR2N_CBxT5y37C1OQs05EDt7o,184
36
- phoenix/db/migrations/future_versions/cd164e83824f_users_and_tokens.py,sha256=L3UlrrT9_mgIakkjRl4MfSHd5dNmZi0D0jizi5V4dTI,8795
36
+ phoenix/db/migrations/future_versions/cd164e83824f_users_and_tokens.py,sha256=6iSewwJCLbGWG1qojJHDiwM-6GIddgsLlGosVdSo6s8,8794
37
37
  phoenix/db/migrations/versions/.gitignore,sha256=chLdMrfkICZvLY7lCEcuqF32sVp61Jml4PodFryEU94,33
38
38
  phoenix/db/migrations/versions/10460e46d750_datasets.py,sha256=eZAyz720DmpOd7RnuxDN2dVNXVuMrdlCA7eAOxyMtfs,8695
39
39
  phoenix/db/migrations/versions/3be8647b87d8_add_token_columns_to_spans_table.py,sha256=x6oKFwn7Zmite4G0trDQPpMCn0I7jejuBcN3-ivEuDg,3938
40
40
  phoenix/db/migrations/versions/cf03bd6bae1d_init.py,sha256=09cpofqje8zi4eQFfUn-i21x7VcsUYOfLKKUlrtKrGc,8662
41
41
  phoenix/experiments/__init__.py,sha256=6JGwgUd7xCbGpuHqYZlsmErmYvVgv7N_j43bn3dUqsk,123
42
- phoenix/experiments/functions.py,sha256=WnyBaO6UEesQ1P77GXy-brQSSY9NF1EpAULbtbr4mHo,32228
42
+ phoenix/experiments/functions.py,sha256=B60_JT0jmLFQbkweZc2Px1q1vzE3Q_w2EI5jRgT19Rk,32589
43
43
  phoenix/experiments/tracing.py,sha256=wVpt8Ie9WNPoi1djJdcrkwCokHdTO0bicXViLg3O-1Y,2831
44
44
  phoenix/experiments/types.py,sha256=HegeRSLyx2lESlzAc2PXYQJVHBFbCLwqQQmPcDMdUnM,23433
45
45
  phoenix/experiments/utils.py,sha256=wLu5Kvt1b4a8rGPRWq5G8RQ9XSiV8fCIVm51zWBI3-g,758
@@ -68,11 +68,11 @@ phoenix/pointcloud/pointcloud.py,sha256=4zAIkKs2xOUbchpj4XDAV-iPMXrfAJ15TG6rlIYG
68
68
  phoenix/pointcloud/projectors.py,sha256=zO_RrtDYSv2rqVOfIP2_9Cv11Dc8EmcZR94xhFcBYPU,1057
69
69
  phoenix/pointcloud/umap_parameters.py,sha256=3UQSjrysVOvq2V4KNpTMqNqNiK0BsTZnPBHWZ4fyJtQ,1708
70
70
  phoenix/server/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
71
- phoenix/server/app.py,sha256=fZYS5Jttj70iHnyDMivXs74oZMAx_gQgdWyNUXs59jE,19407
71
+ phoenix/server/app.py,sha256=A0IIC7ONjBlRWqfAjoCqfoVS0xcnPfWk3gmxphgAjcM,19674
72
72
  phoenix/server/dml_event.py,sha256=MpjCFqljxvgb9OB5Cez9vJesb3oHb3XxXictynBfcis,2851
73
73
  phoenix/server/dml_event_handler.py,sha256=6p-PucctivelVHfO-_9zNxWZYPr_eGjDF3bKjLtc5co,8251
74
74
  phoenix/server/grpc_server.py,sha256=jllxDNkpLQxDkvej4RhTokobowbvydF-SU8gSw1MTCc,3378
75
- phoenix/server/main.py,sha256=dvjv3g8ANpkvSGCUN02S2Yse643Nlwrp_bj4iXBSVTE,11082
75
+ phoenix/server/main.py,sha256=xxG650qi2bIX6HCcfSiLd1QyImiBoWbsVJ55m21GyNg,11471
76
76
  phoenix/server/prometheus.py,sha256=j9DHB2fERuq_ZKmwVaqR-9wx5WcPPuU1Cm5Bhg5241Y,2996
77
77
  phoenix/server/telemetry.py,sha256=T_2OKrxNViAeaANlNspEekg_Y5uZIFWvKAnpz8Aoqvk,2762
78
78
  phoenix/server/thread_server.py,sha256=RwXQGP_QhGD7le6WB7xEygEEuwBl5Ck_Zo8xGIYGi9M,2135
@@ -80,7 +80,7 @@ phoenix/server/types.py,sha256=UCCkwEzUAbRdu-hZpG7A2hdPM09onBezaXNtWX4A7og,3431
80
80
  phoenix/server/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
81
81
  phoenix/server/api/context.py,sha256=2-kJpoix-OISxyAhoI5FFEnQMt9ad-3HQ3VOFCjdbxU,2799
82
82
  phoenix/server/api/interceptor.py,sha256=ykDnoC_apUd-llVli3m1CW18kNSIgjz2qZ6m5JmPDu8,1294
83
- phoenix/server/api/queries.py,sha256=Nuw74Nh1XhDkLNV8hTO3WPPNeqcSlNhUF76r5HaytGc,20268
83
+ phoenix/server/api/queries.py,sha256=cO47wUByLDTjrt4N28kVkQbxbJXusZ8TTCkXiIcEuaU,23804
84
84
  phoenix/server/api/schema.py,sha256=BcxdqO5CSGqpKd-AAJHMjFlzaK9oJA8GJuxmMfcdjn4,434
85
85
  phoenix/server/api/utils.py,sha256=Kl47G-1A7QKTDrc75BU2QK6HupsG6MWuXxy351FOfKQ,858
86
86
  phoenix/server/api/dataloaders/__init__.py,sha256=TrOGnU_SD_vEIxOE_dm8HrD5C2ScLFQ4xQ7f8r-E76s,3064
@@ -139,7 +139,7 @@ phoenix/server/api/input_types/TraceAnnotationSort.py,sha256=BzwiUnMh2VsgQYnhDlb
139
139
  phoenix/server/api/input_types/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
140
140
  phoenix/server/api/mutations/__init__.py,sha256=UKUAhD5NY-ZI7XONnRRkaHoFuuU3idmE4fk6Sjgy18M,776
141
141
  phoenix/server/api/mutations/auth.py,sha256=vPRFoj7J6PV6QeODewG4K0PhoOebS5AfMRpbi_wuhyQ,311
142
- phoenix/server/api/mutations/dataset_mutations.py,sha256=p3cqYCLb6zf_Dx8ju0R8FMLT5ZBW_ZQXDyP1iw1zA3E,25280
142
+ phoenix/server/api/mutations/dataset_mutations.py,sha256=0feBUW_07FEIx6uzepjxfRVhk5lAck0AkrqS1GVdoF4,27041
143
143
  phoenix/server/api/mutations/experiment_mutations.py,sha256=OXtLYdLA33RGy1MFctfv6ug2sODcDElhJph_J9vkIjk,3157
144
144
  phoenix/server/api/mutations/export_events_mutations.py,sha256=t_wYBxaqvBJYRoHslh3Bmoxmwlzoy0u8SsBKWIKN5hE,4028
145
145
  phoenix/server/api/mutations/project_mutations.py,sha256=MLm7I97lJ85hTuc1tq8sdYA8Ps5WKMV-bGqeeN-Ey90,2279
@@ -163,6 +163,7 @@ phoenix/server/api/routers/v1/utils.py,sha256=xvl2v-BKUkqmFVMmgmmWGFKuRBTrUdoiAe
163
163
  phoenix/server/api/types/Annotation.py,sha256=7Ym7iuVcbwHlw2yIRylz4nATAF_Cm-Z17qcjiooj1cc,751
164
164
  phoenix/server/api/types/AnnotationSummary.py,sha256=8B2LIROqcrPOi8hvYygsblKvSEBfSrysnKOV7F36hgA,1518
165
165
  phoenix/server/api/types/AnnotatorKind.py,sha256=rPgGdbN1Gvc109sGQ_ZH-gfJbp93V9wlarzTEJNtUwI,236
166
+ phoenix/server/api/types/ApiKey.py,sha256=8RnWRlAQ8RIT4wGXh-UDy5SsR130KbbuN5BTpgLaKWk,519
166
167
  phoenix/server/api/types/Cluster.py,sha256=ac4YfT1OH3xLVmex7EUmB6b9IpULnhLTt554LR0jglE,5689
167
168
  phoenix/server/api/types/CreateDatasetPayload.py,sha256=R-6zCmuD0f76RU9Giu78xwTHlASQs6Aq8yzvX1Kxc3g,140
168
169
  phoenix/server/api/types/DataQualityMetric.py,sha256=zRKsNvHBu-NdcsunuLhqFpZhi6ks-HMqA1PJD27jTak,590
@@ -205,12 +206,16 @@ phoenix/server/api/types/Retrieval.py,sha256=OhMK2ncjoyp5h1yjKhjlKpoTbQrMHuxmgSF
205
206
  phoenix/server/api/types/ScalarDriftMetricEnum.py,sha256=IUAcRPpgL41WdoIgK6cNk2Te38SspXGyEs-S1fY23_A,232
206
207
  phoenix/server/api/types/Segments.py,sha256=m2yoegrxA1Tn7ZAy1rMjjD1isc752MaAXMoffkBlvrM,2921
207
208
  phoenix/server/api/types/SortDir.py,sha256=OUpXhlCzCxPoXSDkJJygEs9Rw9pMymfaZUG5zPTrw4Y,152
208
- phoenix/server/api/types/Span.py,sha256=ypzCF70a22QH7e7N8UQbO3FPtsPnAUxqqnq7UlcdGV4,14373
209
+ phoenix/server/api/types/Span.py,sha256=NzO1khZQS9LRoY23RciUaxLUR9WJF5pcV-pv8cnQPJA,15053
209
210
  phoenix/server/api/types/SpanAnnotation.py,sha256=6b5G-b_OoRvDL2ayWk7MkbqarLK-F-pQMx21CpUuNGY,1168
211
+ phoenix/server/api/types/SystemApiKey.py,sha256=2ym8EgsTBIvxx1l9xZ-2YMovz58ZwYb_MaHBTJ9NH2E,166
210
212
  phoenix/server/api/types/TimeSeries.py,sha256=wjzuxHFqCey0O7Ys25qiXyuqXK8an-osyNWUE8A_8G4,5227
211
213
  phoenix/server/api/types/Trace.py,sha256=-nh3A-S_BlQK1VSSOTWqM85l-WwJsRHifxeDi0sFWZE,3246
212
214
  phoenix/server/api/types/TraceAnnotation.py,sha256=OW6A2zr1gomOuG0XQe55dk15XXX2DSM0DzatRbHWH5A,1256
213
215
  phoenix/server/api/types/UMAPPoints.py,sha256=5sOuruzM8saXa8C2XiyUfk2XPrkVGmhqKpclMYRw1dk,1656
216
+ phoenix/server/api/types/User.py,sha256=j04JLq51GBqjcAuZfErUn05bB3nSpy-DlNL2jm4AaHA,300
217
+ phoenix/server/api/types/UserApiKey.py,sha256=ZHfCHHxPUE5CSKiQuCqzlY7GkSZ5OzvcORoBMRPA3gg,227
218
+ phoenix/server/api/types/UserRole.py,sha256=VydiFaNIjcuYtvrkBykhWc2nXvHWWhAUsZ9D1Tyqdng,140
214
219
  phoenix/server/api/types/ValidationResult.py,sha256=pHwdYk4J7SJ5xhlWWHg_6qWkfk4rjOx-bSkGHvkDE3Q,142
215
220
  phoenix/server/api/types/VectorDriftMetricEnum.py,sha256=etiJM5ZjQuD-oE7sY-FbdIKY050jk3IU49IMwmfJbEc,188
216
221
  phoenix/server/api/types/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -227,23 +232,23 @@ phoenix/server/static/apple-touch-icon-76x76.png,sha256=CT_xT12I0u2i0WU8JzBZBuOQ
227
232
  phoenix/server/static/apple-touch-icon.png,sha256=fOfpjqGpWYbJ0eAurKsyoZP1EAs6ZVooBJ_SGk2ZkDs,3801
228
233
  phoenix/server/static/favicon.ico,sha256=bY0vvCKRftemZfPShwZtE93DiiQdaYaozkPGwNFr6H8,34494
229
234
  phoenix/server/static/modernizr.js,sha256=mvK-XtkNqjOral-QvzoqsyOMECXIMu5BQwSVN_wcU9c,2564
230
- phoenix/server/static/.vite/manifest.json,sha256=D9OZ5VZQ3XozxyFU4FF1fd4MmUGkyB_xa67tlUi1NWI,1929
231
- phoenix/server/static/assets/components-BC3-LP_a.js,sha256=LnC6sDg6caKtsMyIno5Dw7Ure5BGAReRrsn5XBCcP50,187118
232
- phoenix/server/static/assets/index-BjJvafYL.js,sha256=dz-kVZPp63OEi2l0SYVU5PeimOsUgW3VQQdYdnoZLQE,7362
233
- phoenix/server/static/assets/pages--n2933VW.js,sha256=WJZ6L_bWgzgJc3EAcbwbzuGADKEcZfMBwSVjDHhKslQ,452799
234
- phoenix/server/static/assets/vendor-BMWfu6zp.js,sha256=AAVTM5SjGUI_CmAWFUFmhpp5VDhvCD-MrEoh-pXXADY,1355423
235
+ phoenix/server/static/.vite/manifest.json,sha256=Sc2AOYCyZmm4BdNQ7itmmI9AFoBxJzfMoZC8YoWh1gA,1929
236
+ phoenix/server/static/assets/components-DzA9gIHT.js,sha256=miEpsrzpn_BM4W1HFe2dvNJJILaO8sq677NhjhiL8w4,187160
237
+ phoenix/server/static/assets/index-BuTlV4Gk.js,sha256=JsAPpelKgf1a9JtrnyKLgJn4w3vUzYLCk5bsCXnCnkM,7466
238
+ phoenix/server/static/assets/pages-DzkUGFGV.js,sha256=qX2Q1wyfONVCfbx7uPd2W33MIZ4B561SIl0TO2LDK1Y,457253
239
+ phoenix/server/static/assets/vendor-CIqy43_9.js,sha256=YclKUblIZ8JB6hhl36BtG_7FEsrNYbgnsW0d0w6zIxk,1355423
235
240
  phoenix/server/static/assets/vendor-DxkFTwjz.css,sha256=nZrkr0u6NNElFGvpWHk9GTHeGoibCXCli1bE7mXZGZg,1816
236
- phoenix/server/static/assets/vendor-arizeai-Sj74jm5V.js,sha256=9lD4YeMt5WtyfrqIApcH9WFQxyJJUtth0syWabkzX-I,304008
237
- phoenix/server/static/assets/vendor-codemirror-DO3VqEcD.js,sha256=M7t6xd6WpgKes25OOeGyxT1MU1dDrEKdmUBHgy5zslw,503031
238
- phoenix/server/static/assets/vendor-recharts-BGN0SxgJ.js,sha256=L9LAYSjuf0GHh1_PQh9bF4l9euWCDVQcnQN1RgMDMBw,282859
241
+ phoenix/server/static/assets/vendor-arizeai-B1YgcWL8.js,sha256=b-Q3bHiEkWo29daqYevZItyECmgFu0LMjYgpbDK3mSc,304008
242
+ phoenix/server/static/assets/vendor-codemirror-_bcwCA1C.js,sha256=oqAOjM0IviW-Si9fscZsSTR3_aj2vdp8H6acoyIFzek,503031
243
+ phoenix/server/static/assets/vendor-recharts-C3pM_Wlg.js,sha256=gnMIx0IktJjLzrgDehKdRebp3EkFAGli_067pIMVXFY,282859
239
244
  phoenix/server/static/assets/vendor-three-DwGkEfCM.js,sha256=0D12ZgKzfKCTSdSTKJBFR2RZO_xxeMXrqDp0AszZqHY,620972
240
245
  phoenix/server/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
241
- phoenix/server/templates/index.html,sha256=gVpjB8pCMiubdMh2DA9mTCtV5AVTXJH_9u5PmG2t7Vk,4238
246
+ phoenix/server/templates/index.html,sha256=dAm0IClgJUdT5AOmjZvtgMg8F_xGrRGv95SAkUyx_kg,4325
242
247
  phoenix/session/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
243
248
  phoenix/session/client.py,sha256=C-NpmDkcyGZHR0vv5gWtteUi01cIorjWnqie9WuZb9s,32663
244
249
  phoenix/session/data_extractor.py,sha256=gkEM3WWZAlWGMfRgQopAQlid4cSi6GNco-sdrGir0qc,2788
245
250
  phoenix/session/evaluation.py,sha256=aKeV8UVOyq3b7CYOwt3cWuLz0xzvMjX7vlEPILJ_fcs,5311
246
- phoenix/session/session.py,sha256=l10fiotlO1b-SFehcm8N3aVupdFUYYLiLSBrOCJO9as,26911
251
+ phoenix/session/session.py,sha256=LOdcO7_XMArUMnyRlikLMZq41jgZ0Vl_BxDEpYxF4UU,26953
247
252
  phoenix/trace/__init__.py,sha256=ujk_uYjM8gmm-YqnyXxF-kekfwid0bcaPMTtNNcaw6U,407
248
253
  phoenix/trace/attributes.py,sha256=B_OrzVaxZwFkrAFXZyicYoIti1UdUysURsvUS2GyW1U,12488
249
254
  phoenix/trace/errors.py,sha256=wB1z8qdPckngdfU-TORToekvg3344oNFAA83_hC2yFY,180
@@ -281,8 +286,8 @@ phoenix/utilities/logging.py,sha256=lDXd6EGaamBNcQxL4vP1au9-i_SXe0OraUDiJOcszSw,
281
286
  phoenix/utilities/project.py,sha256=8IJuMM4yUMoooPi37sictGj8Etu9rGmq6RFtc9848cQ,436
282
287
  phoenix/utilities/re.py,sha256=PDve_OLjRTM8yQQJHC8-n3HdIONi7aNils3ZKRZ5uBM,2045
283
288
  phoenix/utilities/span_store.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
284
- arize_phoenix-4.22.1.dist-info/METADATA,sha256=aMe9GmDUEAXZE2A5wixJeuulWvcq7dA7U4FGnGVVCf8,11902
285
- arize_phoenix-4.22.1.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
286
- arize_phoenix-4.22.1.dist-info/licenses/IP_NOTICE,sha256=JBqyyCYYxGDfzQ0TtsQgjts41IJoa-hiwDrBjCb9gHM,469
287
- arize_phoenix-4.22.1.dist-info/licenses/LICENSE,sha256=HFkW9REuMOkvKRACuwLPT0hRydHb3zNg-fdFt94td18,3794
288
- arize_phoenix-4.22.1.dist-info/RECORD,,
289
+ arize_phoenix-4.24.0.dist-info/METADATA,sha256=EPfELiqfJFn2mwDGfD5En4FTu66BEa_cmlyblNqkvBI,11902
290
+ arize_phoenix-4.24.0.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
291
+ arize_phoenix-4.24.0.dist-info/licenses/IP_NOTICE,sha256=JBqyyCYYxGDfzQ0TtsQgjts41IJoa-hiwDrBjCb9gHM,469
292
+ arize_phoenix-4.24.0.dist-info/licenses/LICENSE,sha256=HFkW9REuMOkvKRACuwLPT0hRydHb3zNg-fdFt94td18,3794
293
+ arize_phoenix-4.24.0.dist-info/RECORD,,
@@ -150,7 +150,7 @@ async def insert_roles_and_users(connection: AsyncConnection) -> None:
150
150
  user to the `users` table.
151
151
  """
152
152
  await connection.execute(
153
- insert(UserRole).values([{"role": "SYSTEM"}, {"role": "ADMIN"}, {"role": "GENERAL"}])
153
+ insert(UserRole).values([{"role": "SYSTEM"}, {"role": "ADMIN"}, {"role": "MEMBER"}])
154
154
  )
155
155
  system_user_role_id = sa.select(UserRole.id).where(UserRole.role == "SYSTEM").scalar_subquery()
156
156
  admin_user_role_id = sa.select(UserRole.id).where(UserRole.role == "ADMIN").scalar_subquery()
phoenix/db/models.py CHANGED
@@ -626,6 +626,7 @@ if ENABLE_AUTH:
626
626
  __tablename__ = "user_roles"
627
627
  id: Mapped[int] = mapped_column(primary_key=True)
628
628
  role: Mapped[str] = mapped_column(unique=True)
629
+ users: Mapped[List["User"]] = relationship("User", back_populates="role")
629
630
 
630
631
  class User(Base):
631
632
  __tablename__ = "users"
@@ -634,6 +635,7 @@ if ENABLE_AUTH:
634
635
  ForeignKey("user_roles.id"),
635
636
  index=True,
636
637
  )
638
+ role: Mapped["UserRole"] = relationship("UserRole", back_populates="users")
637
639
  username: Mapped[Optional[str]] = mapped_column(nullable=True, unique=True, index=True)
638
640
  email: Mapped[str] = mapped_column(nullable=False, unique=True, index=True)
639
641
  auth_method: Mapped[str] = mapped_column(
@@ -646,6 +648,7 @@ if ENABLE_AUTH:
646
648
  UtcTimeStamp, server_default=func.now(), onupdate=func.now()
647
649
  )
648
650
  deleted_at: Mapped[Optional[datetime]] = mapped_column(UtcTimeStamp)
651
+ api_keys: Mapped[List["APIKey"]] = relationship("APIKey", back_populates="user")
649
652
 
650
653
  class APIKey(Base):
651
654
  __tablename__ = "api_keys"
@@ -654,6 +657,7 @@ if ENABLE_AUTH:
654
657
  ForeignKey("users.id"),
655
658
  index=True,
656
659
  )
660
+ user: Mapped["User"] = relationship("User", back_populates="api_keys")
657
661
  name: Mapped[str]
658
662
  description: Mapped[Optional[str]]
659
663
  created_at: Mapped[datetime] = mapped_column(UtcTimeStamp, server_default=func.now())
@@ -108,6 +108,7 @@ def run_experiment(
108
108
  rate_limit_errors: Optional[RateLimitErrors] = None,
109
109
  dry_run: Union[bool, int] = False,
110
110
  print_summary: bool = True,
111
+ concurrency: int = 3,
111
112
  ) -> RanExperiment:
112
113
  """
113
114
  Runs an experiment using a given set of dataset of examples.
@@ -158,6 +159,9 @@ def run_experiment(
158
159
  examples of the given size. Defaults to False.
159
160
  print_summary (bool): Whether to print a summary of the experiment and evaluation results.
160
161
  Defaults to True.
162
+ concurrency (int): Specifies the concurrency for task execution. In order to enable
163
+ concurrent task execution, the task callable must be a coroutine function.
164
+ Defaults to 3.
161
165
 
162
166
  Returns:
163
167
  RanExperiment: The results of the experiment and evaluation. Additional evaluations can be
@@ -389,6 +393,7 @@ def run_experiment(
389
393
  exit_on_error=False,
390
394
  fallback_return_value=None,
391
395
  tqdm_bar_format=get_tqdm_progress_bar_formatter("running tasks"),
396
+ concurrency=concurrency,
392
397
  )
393
398
 
394
399
  test_cases = [
@@ -414,6 +419,7 @@ def run_experiment(
414
419
  dry_run=dry_run,
415
420
  print_summary=print_summary,
416
421
  rate_limit_errors=rate_limit_errors,
422
+ concurrency=concurrency,
417
423
  )
418
424
  if print_summary:
419
425
  print(ran_experiment)
@@ -427,6 +433,7 @@ def evaluate_experiment(
427
433
  dry_run: Union[bool, int] = False,
428
434
  print_summary: bool = True,
429
435
  rate_limit_errors: Optional[RateLimitErrors] = None,
436
+ concurrency: int = 3,
430
437
  ) -> RanExperiment:
431
438
  if not dry_run and _is_dry_run(experiment):
432
439
  dry_run = True
@@ -628,6 +635,7 @@ def evaluate_experiment(
628
635
  exit_on_error=False,
629
636
  fallback_return_value=None,
630
637
  tqdm_bar_format=get_tqdm_progress_bar_formatter("running experiment evaluations"),
638
+ concurrency=concurrency,
631
639
  )
632
640
  eval_runs, _execution_details = executor.run(evaluation_input)
633
641
  eval_summary = EvaluationSummary.from_eval_runs(
@@ -230,7 +230,7 @@ class DatasetMutationMixin:
230
230
  ) -> DatasetMutationPayload:
231
231
  dataset_id = input.dataset_id
232
232
  # Extract the span rowids from the input examples if they exist
233
- span_ids = span_ids = [example.span_id for example in input.examples if example.span_id]
233
+ span_ids = [example.span_id for example in input.examples if example.span_id]
234
234
  span_rowids = {
235
235
  from_global_id_with_expected_type(global_id=span_id, expected_type_name=Span.__name__)
236
236
  for span_id in set(span_ids)
@@ -260,6 +260,8 @@ class DatasetMutationMixin:
260
260
  )
261
261
  .returning(models.DatasetVersion.id)
262
262
  )
263
+
264
+ # Fetch spans and span annotations
263
265
  spans = (
264
266
  await session.execute(
265
267
  select(models.Span.id)
@@ -267,9 +269,36 @@ class DatasetMutationMixin:
267
269
  .where(models.Span.id.in_(span_rowids))
268
270
  )
269
271
  ).all()
270
- # Just validate that the number of spans matches the number of span_ids
271
- # to ensure that the span_ids are valid
272
- assert len(spans) == len(span_rowids)
272
+
273
+ span_annotations = (
274
+ await session.execute(
275
+ select(
276
+ models.SpanAnnotation.span_rowid,
277
+ models.SpanAnnotation.name,
278
+ models.SpanAnnotation.label,
279
+ models.SpanAnnotation.score,
280
+ models.SpanAnnotation.explanation,
281
+ models.SpanAnnotation.metadata_,
282
+ models.SpanAnnotation.annotator_kind,
283
+ )
284
+ .select_from(models.SpanAnnotation)
285
+ .where(models.SpanAnnotation.span_rowid.in_(span_rowids))
286
+ )
287
+ ).all()
288
+
289
+ span_annotations_by_span: Dict[int, Dict[Any, Any]] = {span.id: {} for span in spans}
290
+ for annotation in span_annotations:
291
+ span_id = annotation.span_rowid
292
+ if span_id not in span_annotations_by_span:
293
+ span_annotations_by_span[span_id] = dict()
294
+ span_annotations_by_span[span_id][annotation.name] = {
295
+ "label": annotation.label,
296
+ "score": annotation.score,
297
+ "explanation": annotation.explanation,
298
+ "metadata": annotation.metadata_,
299
+ "annotator_kind": annotation.annotator_kind,
300
+ }
301
+
273
302
  DatasetExample = models.DatasetExample
274
303
  dataset_example_rowids = (
275
304
  await session.scalars(
@@ -291,21 +320,32 @@ class DatasetMutationMixin:
291
320
  assert len(dataset_example_rowids) == len(input.examples)
292
321
  assert all(map(lambda id: isinstance(id, int), dataset_example_rowids))
293
322
  DatasetExampleRevision = models.DatasetExampleRevision
294
- await session.execute(
295
- insert(DatasetExampleRevision),
296
- [
323
+
324
+ dataset_example_revisions = []
325
+ for dataset_example_rowid, example in zip(dataset_example_rowids, input.examples):
326
+ span_annotation = {}
327
+ if example.span_id:
328
+ span_id = from_global_id_with_expected_type(
329
+ global_id=example.span_id,
330
+ expected_type_name=Span.__name__,
331
+ )
332
+ span_annotation = span_annotations_by_span.get(span_id, {})
333
+ dataset_example_revisions.append(
297
334
  {
298
335
  DatasetExampleRevision.dataset_example_id.key: dataset_example_rowid,
299
336
  DatasetExampleRevision.dataset_version_id.key: dataset_version_rowid,
300
337
  DatasetExampleRevision.input.key: example.input,
301
338
  DatasetExampleRevision.output.key: example.output,
302
- DatasetExampleRevision.metadata_.key: example.metadata,
339
+ DatasetExampleRevision.metadata_.key: {
340
+ **(example.metadata or {}),
341
+ "annotations": span_annotation,
342
+ },
303
343
  DatasetExampleRevision.revision_kind.key: "CREATE",
304
344
  }
305
- for dataset_example_rowid, example in zip(
306
- dataset_example_rowids, input.examples
307
- )
308
- ],
345
+ )
346
+ await session.execute(
347
+ insert(DatasetExampleRevision),
348
+ dataset_example_revisions,
309
349
  )
310
350
  info.context.event_queue.put(DatasetInsertEvent((dataset.id,)))
311
351
  return DatasetMutationPayload(dataset=to_gql_dataset(dataset))
@@ -66,11 +66,115 @@ from phoenix.server.api.types.pagination import (
66
66
  from phoenix.server.api.types.Project import Project
67
67
  from phoenix.server.api.types.SortDir import SortDir
68
68
  from phoenix.server.api.types.Span import Span, to_gql_span
69
+ from phoenix.server.api.types.SystemApiKey import SystemApiKey
69
70
  from phoenix.server.api.types.Trace import Trace
71
+ from phoenix.server.api.types.User import User
72
+ from phoenix.server.api.types.UserApiKey import UserApiKey
73
+ from phoenix.server.api.types.UserRole import UserRole
70
74
 
71
75
 
72
76
  @strawberry.type
73
77
  class Query:
78
+ @strawberry.field
79
+ async def users(
80
+ self,
81
+ info: Info[Context, None],
82
+ first: Optional[int] = 50,
83
+ last: Optional[int] = UNSET,
84
+ after: Optional[CursorString] = UNSET,
85
+ before: Optional[CursorString] = UNSET,
86
+ ) -> Connection[User]:
87
+ args = ConnectionArgs(
88
+ first=first,
89
+ after=after if isinstance(after, CursorString) else None,
90
+ last=last,
91
+ before=before if isinstance(before, CursorString) else None,
92
+ )
93
+ stmt = (
94
+ select(models.User)
95
+ .where(models.UserRole.role != "SYSTEM")
96
+ .order_by(models.User.email)
97
+ .options(joinedload(models.User.role))
98
+ )
99
+ async with info.context.db() as session:
100
+ users = await session.stream_scalars(stmt)
101
+ data = [
102
+ User(
103
+ id_attr=user.id,
104
+ email=user.email,
105
+ username=user.username,
106
+ created_at=user.created_at,
107
+ role=UserRole(
108
+ id_attr=user.role.id,
109
+ role=user.role.role,
110
+ ),
111
+ )
112
+ async for user in users
113
+ ]
114
+ return connection_from_list(data=data, args=args)
115
+
116
+ @strawberry.field
117
+ async def user_roles(
118
+ self,
119
+ info: Info[Context, None],
120
+ ) -> List[UserRole]:
121
+ async with info.context.db() as session:
122
+ roles = await session.scalars(
123
+ select(models.UserRole).where(models.UserRole.role != "SYSTEM")
124
+ )
125
+ return [
126
+ UserRole(
127
+ id_attr=role.id,
128
+ role=role.role,
129
+ )
130
+ for role in roles
131
+ ]
132
+
133
+ @strawberry.field
134
+ async def user_api_keys(self, info: Info[Context, None]) -> List[UserApiKey]:
135
+ # TODO(auth): add access control
136
+ stmt = (
137
+ select(models.APIKey)
138
+ .join(models.User)
139
+ .join(models.UserRole)
140
+ .where(models.UserRole.role != "SYSTEM")
141
+ )
142
+ async with info.context.db() as session:
143
+ api_keys = await session.scalars(stmt)
144
+ return [
145
+ UserApiKey(
146
+ id_attr=api_key.id,
147
+ user_id=api_key.user_id,
148
+ name=api_key.name,
149
+ description=api_key.description,
150
+ created_at=api_key.created_at,
151
+ expires_at=api_key.expires_at,
152
+ )
153
+ for api_key in api_keys
154
+ ]
155
+
156
+ @strawberry.field
157
+ async def system_api_keys(self, info: Info[Context, None]) -> List[SystemApiKey]:
158
+ # TODO(auth): add access control
159
+ stmt = (
160
+ select(models.APIKey)
161
+ .join(models.User)
162
+ .join(models.UserRole)
163
+ .where(models.UserRole.role == "SYSTEM")
164
+ )
165
+ async with info.context.db() as session:
166
+ api_keys = await session.scalars(stmt)
167
+ return [
168
+ SystemApiKey(
169
+ id_attr=api_key.id,
170
+ name=api_key.name,
171
+ description=api_key.description,
172
+ created_at=api_key.created_at,
173
+ expires_at=api_key.expires_at,
174
+ )
175
+ for api_key in api_keys
176
+ ]
177
+
74
178
  @strawberry.field
75
179
  async def projects(
76
180
  self,
@@ -0,0 +1,16 @@
1
+ from datetime import datetime
2
+ from typing import Optional
3
+
4
+ import strawberry
5
+
6
+
7
+ @strawberry.interface
8
+ class ApiKey:
9
+ name: str = strawberry.field(description="Name of the API key.")
10
+ description: Optional[str] = strawberry.field(description="Description of the API key.")
11
+ created_at: datetime = strawberry.field(
12
+ description="The date and time the API key was created."
13
+ )
14
+ expires_at: Optional[datetime] = strawberry.field(
15
+ description="The date and time the API key will expire."
16
+ )
@@ -232,7 +232,7 @@ class Span(Node):
232
232
  @strawberry.field(
233
233
  description="The span's attributes translated into an example revision for a dataset",
234
234
  ) # type: ignore
235
- def as_example_revision(self) -> SpanAsExampleRevision:
235
+ async def as_example_revision(self, info: Info[Context, None]) -> SpanAsExampleRevision:
236
236
  db_span = self.db_span
237
237
  attributes = db_span.attributes
238
238
  span_io = _SpanIO(
@@ -248,10 +248,28 @@ class Span(Node):
248
248
  llm_output_messages=get_attribute_value(attributes, LLM_OUTPUT_MESSAGES),
249
249
  retrieval_documents=get_attribute_value(attributes, RETRIEVAL_DOCUMENTS),
250
250
  )
251
+
252
+ # Fetch annotations associated with this span
253
+ span_annotations = await self.span_annotations(info)
254
+ annotations = dict()
255
+ for annotation in span_annotations:
256
+ annotations[annotation.name] = {
257
+ "label": annotation.label,
258
+ "score": annotation.score,
259
+ "explanation": annotation.explanation,
260
+ "metadata": annotation.metadata,
261
+ "annotator_kind": annotation.annotator_kind.value,
262
+ }
263
+ # Merge annotations into the metadata
264
+ metadata = {
265
+ **attributes,
266
+ "annotations": annotations,
267
+ }
268
+
251
269
  return SpanAsExampleRevision(
252
270
  input=get_dataset_example_input(span_io),
253
271
  output=get_dataset_example_output(span_io),
254
- metadata=attributes,
272
+ metadata=metadata,
255
273
  )
256
274
 
257
275
  @strawberry.field(description="The project that this span belongs to.") # type: ignore
@@ -0,0 +1,9 @@
1
+ import strawberry
2
+ from strawberry.relay import Node, NodeID
3
+
4
+ from .ApiKey import ApiKey
5
+
6
+
7
+ @strawberry.type
8
+ class SystemApiKey(ApiKey, Node):
9
+ id_attr: NodeID[int]
@@ -0,0 +1,16 @@
1
+ from datetime import datetime
2
+ from typing import Optional
3
+
4
+ import strawberry
5
+ from strawberry.relay import Node, NodeID
6
+
7
+ from .UserRole import UserRole
8
+
9
+
10
+ @strawberry.type
11
+ class User(Node):
12
+ id_attr: NodeID[int]
13
+ email: str
14
+ username: Optional[str]
15
+ created_at: datetime
16
+ role: UserRole
@@ -0,0 +1,11 @@
1
+ import strawberry
2
+ from strawberry import Private
3
+ from strawberry.relay.types import Node, NodeID
4
+
5
+ from .ApiKey import ApiKey
6
+
7
+
8
+ @strawberry.type
9
+ class UserApiKey(ApiKey, Node):
10
+ id_attr: NodeID[int]
11
+ user_id: Private[int]
@@ -0,0 +1,8 @@
1
+ import strawberry
2
+ from strawberry.relay import Node, NodeID
3
+
4
+
5
+ @strawberry.type
6
+ class UserRole(Node):
7
+ id_attr: NodeID[int]
8
+ role: str
phoenix/server/app.py CHANGED
@@ -115,6 +115,8 @@ class AppConfig(NamedTuple):
115
115
  n_samples: int
116
116
  is_development: bool
117
117
  web_manifest_path: Path
118
+ authentication_enabled: bool
119
+ """ Whether authentication is enabled """
118
120
 
119
121
 
120
122
  class Static(StaticFiles):
@@ -162,6 +164,7 @@ class Static(StaticFiles):
162
164
  "request": request,
163
165
  "is_development": self._app_config.is_development,
164
166
  "manifest": self._web_manifest,
167
+ "authentication_enabled": self._app_config.authentication_enabled,
165
168
  },
166
169
  )
167
170
  except Exception as e:
@@ -395,6 +398,7 @@ def create_app(
395
398
  db: DbSessionFactory,
396
399
  export_path: Path,
397
400
  model: Model,
401
+ authentication_enabled: bool,
398
402
  umap_params: UMAPParameters,
399
403
  corpus: Optional[Model] = None,
400
404
  debug: bool = False,
@@ -515,6 +519,7 @@ def create_app(
515
519
  n_neighbors=umap_params.n_neighbors,
516
520
  n_samples=umap_params.n_samples,
517
521
  is_development=dev,
522
+ authentication_enabled=authentication_enabled,
518
523
  web_manifest_path=SERVER_DIR / "static" / ".vite" / "manifest.json",
519
524
  ),
520
525
  ),
phoenix/server/main.py CHANGED
@@ -13,6 +13,7 @@ from uvicorn import Config, Server
13
13
  import phoenix.trace.v1 as pb
14
14
  from phoenix.config import (
15
15
  EXPORT_DIR,
16
+ get_auth_settings,
16
17
  get_env_database_connection_str,
17
18
  get_env_enable_prometheus,
18
19
  get_env_grpc_port,
@@ -80,6 +81,11 @@ _WELCOME_MESSAGE = """
80
81
  | Storage: {storage}
81
82
  """
82
83
 
84
+ _EXPERIMENTAL_WARNING = """
85
+ 🚨 WARNING: Phoenix is running in experimental mode. 🚨
86
+ | Authentication enabled: {auth_enabled}
87
+ """
88
+
83
89
 
84
90
  def _write_pid_file_when_ready(
85
91
  server: Server,
@@ -212,6 +218,8 @@ if __name__ == "__main__":
212
218
  reference_inferences,
213
219
  )
214
220
 
221
+ authentication_enabled, auth_secret = get_auth_settings()
222
+
215
223
  fixture_spans: List[Span] = []
216
224
  fixture_evals: List[pb.Evaluation] = []
217
225
  if trace_dataset_name is not None:
@@ -251,6 +259,7 @@ if __name__ == "__main__":
251
259
  db=factory,
252
260
  export_path=export_path,
253
261
  model=model,
262
+ authentication_enabled=authentication_enabled,
254
263
  umap_params=umap_params,
255
264
  corpus=None
256
265
  if corpus_inferences is None
@@ -278,5 +287,8 @@ if __name__ == "__main__":
278
287
  )
279
288
  )
280
289
 
290
+ if authentication_enabled:
291
+ print(_EXPERIMENTAL_WARNING.format(auth_enabled=authentication_enabled))
292
+
281
293
  # Start the server
282
294
  server.run()