arize-phoenix 11.4.0__py3-none-any.whl → 11.6.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 (42) hide show
  1. {arize_phoenix-11.4.0.dist-info → arize_phoenix-11.6.0.dist-info}/METADATA +2 -2
  2. {arize_phoenix-11.4.0.dist-info → arize_phoenix-11.6.0.dist-info}/RECORD +42 -40
  3. phoenix/config.py +51 -2
  4. phoenix/server/api/auth.py +1 -1
  5. phoenix/server/api/queries.py +52 -44
  6. phoenix/server/api/routers/v1/annotation_configs.py +4 -1
  7. phoenix/server/api/routers/v1/datasets.py +3 -1
  8. phoenix/server/api/routers/v1/evaluations.py +3 -1
  9. phoenix/server/api/routers/v1/experiment_runs.py +3 -1
  10. phoenix/server/api/routers/v1/experiments.py +3 -1
  11. phoenix/server/api/routers/v1/projects.py +4 -1
  12. phoenix/server/api/routers/v1/prompts.py +4 -1
  13. phoenix/server/api/routers/v1/spans.py +6 -3
  14. phoenix/server/api/routers/v1/traces.py +4 -1
  15. phoenix/server/api/routers/v1/users.py +2 -2
  16. phoenix/server/api/types/Span.py +0 -99
  17. phoenix/server/app.py +47 -12
  18. phoenix/server/authorization.py +9 -0
  19. phoenix/server/bearer_auth.py +18 -15
  20. phoenix/server/cost_tracking/cost_model_lookup.py +1 -1
  21. phoenix/server/cost_tracking/model_cost_manifest.json +107 -107
  22. phoenix/server/daemons/db_disk_usage_monitor.py +215 -0
  23. phoenix/server/email/sender.py +25 -0
  24. phoenix/server/email/templates/db_disk_usage_notification.html +16 -0
  25. phoenix/server/email/types.py +11 -0
  26. phoenix/server/grpc_server.py +3 -3
  27. phoenix/server/prometheus.py +22 -0
  28. phoenix/server/static/.vite/manifest.json +44 -44
  29. phoenix/server/static/assets/{components-CVcMbu2U.js → components-mOUBHJ12.js} +297 -298
  30. phoenix/server/static/assets/{index-Dz7I-Hpn.js → index-CQ_A6K_M.js} +2 -2
  31. phoenix/server/static/assets/{pages-QK2o2V7x.js → pages-CCsLkNZY.js} +517 -498
  32. phoenix/server/static/assets/{vendor-pg5m6BWE.js → vendor-DRWIRkSJ.js} +1 -1
  33. phoenix/server/static/assets/{vendor-arizeai-BwMsgSAG.js → vendor-arizeai-DUhQaeau.js} +1 -1
  34. phoenix/server/static/assets/{vendor-codemirror-BwSDEu2g.js → vendor-codemirror-D_6Q6Auv.js} +1 -1
  35. phoenix/server/static/assets/{vendor-recharts-SW3HwAtG.js → vendor-recharts-BNBwj7vz.js} +1 -1
  36. phoenix/server/static/assets/{vendor-shiki-BsdYoDvs.js → vendor-shiki-k1qj_XjP.js} +1 -1
  37. phoenix/server/types.py +11 -2
  38. phoenix/version.py +1 -1
  39. {arize_phoenix-11.4.0.dist-info → arize_phoenix-11.6.0.dist-info}/WHEEL +0 -0
  40. {arize_phoenix-11.4.0.dist-info → arize_phoenix-11.6.0.dist-info}/entry_points.txt +0 -0
  41. {arize_phoenix-11.4.0.dist-info → arize_phoenix-11.6.0.dist-info}/licenses/IP_NOTICE +0 -0
  42. {arize_phoenix-11.4.0.dist-info → arize_phoenix-11.6.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: arize-phoenix
3
- Version: 11.4.0
3
+ Version: 11.6.0
4
4
  Summary: AI Observability and Evaluation
5
5
  Project-URL: Documentation, https://arize.com/docs/phoenix/
6
6
  Project-URL: Issues, https://github.com/Arize-ai/phoenix/issues
@@ -39,6 +39,7 @@ Requires-Dist: opentelemetry-proto>=1.12.0
39
39
  Requires-Dist: opentelemetry-sdk
40
40
  Requires-Dist: opentelemetry-semantic-conventions
41
41
  Requires-Dist: pandas>=1.0
42
+ Requires-Dist: prometheus-client
42
43
  Requires-Dist: protobuf<6.0,>=4.25.8
43
44
  Requires-Dist: psutil
44
45
  Requires-Dist: pyarrow
@@ -96,7 +97,6 @@ Requires-Dist: pandas-stubs==2.2.2.240603; extra == 'dev'
96
97
  Requires-Dist: pandas>=1.0; extra == 'dev'
97
98
  Requires-Dist: portpicker; extra == 'dev'
98
99
  Requires-Dist: pre-commit; extra == 'dev'
99
- Requires-Dist: prometheus-client; extra == 'dev'
100
100
  Requires-Dist: psycopg[binary,pool]; extra == 'dev'
101
101
  Requires-Dist: pytest-asyncio; extra == 'dev'
102
102
  Requires-Dist: pytest-cov; extra == 'dev'
@@ -1,12 +1,12 @@
1
1
  phoenix/__init__.py,sha256=xkpXH76HFbEDCq8IhiFp-2GnEHx39xPMdOpV5Skew1w,5481
2
2
  phoenix/auth.py,sha256=yW78f1xWNjTE30ACGUM14nOd5BzkukhlzA9B45kSUkM,11053
3
- phoenix/config.py,sha256=iRwfpewHsQq0iUaidGHVEGeq4V1arzEbn3fqjxmBk1s,58129
3
+ phoenix/config.py,sha256=Xir2ke9AZluThsYeaiq57a8GyQOuumjIqqqeCh8PKw8,60350
4
4
  phoenix/datetime_utils.py,sha256=fpISOdaeDBdfIa-psFp6FJyAUPWEsiT5s3-_aLV12bg,3576
5
5
  phoenix/exceptions.py,sha256=n2L2KKuecrdflB9MsCdAYCiSEvGJptIsfRkXMoJle7A,169
6
6
  phoenix/py.typed,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
7
7
  phoenix/services.py,sha256=ngkyKGVatX3cO2WJdo2hKdaVKP-xJCMvqthvga6kJss,5196
8
8
  phoenix/settings.py,sha256=2kHfT3BNOVd4dAO1bq-syEQbHSG8oX2-7NhOwK2QREk,896
9
- phoenix/version.py,sha256=BwRWbRM_tZXVkDcgICneVKgWcL8fV17tU6AnkSrIQbU,23
9
+ phoenix/version.py,sha256=kjhthIE5r_ArzQulbcqnrRj4ewlV2jNJYfo-PPrxloM,23
10
10
  phoenix/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
11
  phoenix/core/embedding_dimension.py,sha256=zKGbcvwOXgLf-yrJBpQyKtd-LEOPRKHnUToyAU8Owis,87
12
12
  phoenix/core/model.py,sha256=qBFraOtmwCCnWJltKNP18DDG0mULXigytlFsa6YOz6k,4837
@@ -91,28 +91,28 @@ phoenix/pointcloud/pointcloud.py,sha256=SN_1wXZcwKrtSnHGZLDZGx71orqE1WyVF7E-D58d
91
91
  phoenix/pointcloud/projectors.py,sha256=TQgwc9cJDjJkin1WZyZzgl3HsYrLLiyWD7Czy4jNW3U,1088
92
92
  phoenix/pointcloud/umap_parameters.py,sha256=db_WEPoamuWtopZx7tQfAXPnoE0MS8FkAV0_ThjEx_Q,1735
93
93
  phoenix/server/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
94
- phoenix/server/app.py,sha256=bnD2bdKb4s8TLePmwcgyoeShVKN_w-U2J4CAPQ8MfHc,45325
95
- phoenix/server/authorization.py,sha256=fofeRwuoodCUB3DQYPCuAgIyeiwopXW0tkH_KZvU0Rg,1848
96
- phoenix/server/bearer_auth.py,sha256=b2iHV2nwvWlZJ2O_nWOzHctJ0aUrEIOygIDrO7VOCSw,6700
94
+ phoenix/server/app.py,sha256=GwItmVRwSM5JspXIHwEO1hXjRAqQRQ4djZfbzJjnh3Q,46694
95
+ phoenix/server/authorization.py,sha256=AGpQT6HpPn2ROOxxVBvjPV1393KF4v-K5IHJ4JaTOHM,2175
96
+ phoenix/server/bearer_auth.py,sha256=f4v4W94KyTdGGCPsK1tXOe0vouPuvanAEa03XSdCvPE,6650
97
97
  phoenix/server/dml_event.py,sha256=MjJmVEKytq75chBOSyvYDusUnEbg1pHpIjR3pZkUaJA,2838
98
98
  phoenix/server/dml_event_handler.py,sha256=gkDIONyTz9sLbSA6qOZCigiO5val-fvVcLzDrWNcVcg,8306
99
- phoenix/server/grpc_server.py,sha256=dod29zE_Zlir7NyLcdVM8GH3P8sy-9ykzfaBfVifyE4,4656
99
+ phoenix/server/grpc_server.py,sha256=ahHC394gFZYM3h4FmjQxZwL-a4x3mWmV2EdXYFlNEC8,4676
100
100
  phoenix/server/jwt_store.py,sha256=B6uVildN_dQDTG_-aHHvuVSI7wIVK1yvED-_y6se2GU,16905
101
101
  phoenix/server/main.py,sha256=UBwxrQIEE7ci-SbE6GAlRYmbMHooI6JYG6sG-UpBFFs,18905
102
102
  phoenix/server/oauth2.py,sha256=GvUqZBoZ5dG-l2G1RMl1SUcN10jNAjaMXFznMSWz2Zs,3336
103
- phoenix/server/prometheus.py,sha256=1KjvSfjSa2-BPjDybVMM_Kag316CsN-Zwt64YNr_snc,7825
103
+ phoenix/server/prometheus.py,sha256=c7G_5Rvb7teCzBHuEvwHMZjE2iYrsLLYAcg2mPU8y_c,8678
104
104
  phoenix/server/rate_limiters.py,sha256=cFc73D2NaxqNZZDbwfIDw4So-fRVOJPBtqxOZ8Qky_s,7155
105
105
  phoenix/server/retention.py,sha256=MQe1FWuc_NxhqgIq5q2hfFhWT8ddAmpppgI74xYEQ6c,3064
106
106
  phoenix/server/telemetry.py,sha256=4EluDDrhdDPxAjaW6lVSbi73xkB5XeUCZWOmZGdk0hg,2755
107
107
  phoenix/server/thread_server.py,sha256=Ea2AWreN1lwJsT2wYvGaRaiXrzBqH4kgkZpx0FO5Ocw,2144
108
- phoenix/server/types.py,sha256=b17xahdt6uwDdUYul0xctu7TbBC65AjarlhUzOiXFNE,7443
108
+ phoenix/server/types.py,sha256=j8erl9iRNaR8t0DCQG84-uDVbHy9Qnm7T2EuTtDNNsU,8013
109
109
  phoenix/server/api/README.md,sha256=Pyq1PLPgTzXAswrfIhGXrjI3Skq8it2jTVnanT6Ba4Q,1162
110
110
  phoenix/server/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
111
- phoenix/server/api/auth.py,sha256=cvKH2FQLL7PasiqZMHgu9P4qchhEG7a7P9Nxy35FoIQ,1551
111
+ phoenix/server/api/auth.py,sha256=Bf21wayr-Jrp0ZF9RgbOi9_M91eHE1Tclq9lDYtrkTU,1575
112
112
  phoenix/server/api/context.py,sha256=mqsq_8Ru50e-PxKWNTzh9zptb1PFjYFUf58uW59UYL0,8996
113
113
  phoenix/server/api/exceptions.py,sha256=TA0JuY2YRnj35qGuMSQ8d0ToHum9gWm9W--3fSKHrX0,1171
114
114
  phoenix/server/api/interceptor.py,sha256=ykDnoC_apUd-llVli3m1CW18kNSIgjz2qZ6m5JmPDu8,1294
115
- phoenix/server/api/queries.py,sha256=jd7iz0BBX13bMIOLCkAdBOjkEsfjoV0qC27FhP_8WhQ,44874
115
+ phoenix/server/api/queries.py,sha256=fvbdyhJ57I6DPrNEBkWwhw8BRF7DyIZ3LtYwXwI7yVw,45651
116
116
  phoenix/server/api/schema.py,sha256=fcs36xQwFF_Qe41_5cWR8wYpDvOrnbcyTeo5WNMbDsA,1702
117
117
  phoenix/server/api/subscriptions.py,sha256=ZOGNsLVr5TNjCWgbzO7Eq6Ls_NRdJH9AxC0cW_v0vhM,25332
118
118
  phoenix/server/api/utils.py,sha256=quCBRcusc6PUq9tJq7M8PgwFZp7nXgVAxtbw8feribY,833
@@ -252,19 +252,19 @@ phoenix/server/api/routers/embeddings.py,sha256=BpZGJee0pdL0W5Rp1L0b30dEtZTgJeVq
252
252
  phoenix/server/api/routers/oauth2.py,sha256=EUoBeh4Ix-Uwt_q_RD75xbMcdVdd0xJLDYjELdVHBTw,24051
253
253
  phoenix/server/api/routers/utils.py,sha256=M41BoH-fl37izhRuN2aX7lWm7jOC20A_3uClv9TVUUY,583
254
254
  phoenix/server/api/routers/v1/__init__.py,sha256=ngLMPjC7lgZxgKy_Is33KxTRnMzSqy25qTTChCVx_Mo,2696
255
- phoenix/server/api/routers/v1/annotation_configs.py,sha256=rZ3yJm7m75BVegSjSHqsdqf7n26roGg7vYYiiKfWA3A,15898
255
+ phoenix/server/api/routers/v1/annotation_configs.py,sha256=xp5lJmKYlRsINCUrRD9-lTAElw2v4hdFndS5BWrxICA,16048
256
256
  phoenix/server/api/routers/v1/annotations.py,sha256=fVl2qeh_ZbWXGvFBTZgeL7aGkkINIScdjuyxnOoSzNM,6817
257
- phoenix/server/api/routers/v1/datasets.py,sha256=8Fj3rIi25cry5ue6A07ctWHKVU3Noea554P6vl99S4c,37627
258
- phoenix/server/api/routers/v1/evaluations.py,sha256=GFTo42aIEX0Htn0EjjoE1JZDYlvryeZ_CK9kowhwzGw,12830
257
+ phoenix/server/api/routers/v1/datasets.py,sha256=CnmO2fe-hNPPpLx6L1jzeLdTNrpabkKuepIihIL6u_s,37734
258
+ phoenix/server/api/routers/v1/evaluations.py,sha256=ni_OJcroE93ZmKoU8I8LYqEgCngG6TyHXpFlcYzoabQ,12937
259
259
  phoenix/server/api/routers/v1/experiment_evaluations.py,sha256=_xnVqFCwZoOUPravdPixZLSQiU1H3sB5EzMknB7E1CI,4837
260
- phoenix/server/api/routers/v1/experiment_runs.py,sha256=FreGzzprPpJ_DBHUkdUckca6EGCrnvgVpqk3CLT7wRc,7000
261
- phoenix/server/api/routers/v1/experiments.py,sha256=V9_sxqLTE1MKGFu9H3FEdGKr70lYMbGZx813MGaavfQ,20430
260
+ phoenix/server/api/routers/v1/experiment_runs.py,sha256=LZeCQWQIEOZ9jK5Gp_C4JbiYY6AmnnWe85cVcvdkCLE,7107
261
+ phoenix/server/api/routers/v1/experiments.py,sha256=osy0JG_iVSCkoRi__0tjldfS5zzBDvNfv-GimbP4ShA,20537
262
262
  phoenix/server/api/routers/v1/models.py,sha256=p3gJN-9SWiUYTUTft4bZMsZVCBNTb4nN1Foy68eRZzQ,1997
263
- phoenix/server/api/routers/v1/projects.py,sha256=LFWxHYPRZy-1EvroNylL635vU1UuDbcuRo1oD26yBnw,12551
264
- phoenix/server/api/routers/v1/prompts.py,sha256=aBOUBwLDzZDIzJQkxJcR8ZKnakNJOLMwzsLKINSs1mA,26545
265
- phoenix/server/api/routers/v1/spans.py,sha256=HhZtXsNTdOmMXWtMkz3VUb3aqpGsVAU5XOYi2KfvGMc,44106
266
- phoenix/server/api/routers/v1/traces.py,sha256=6zlk7NZs2TSL2Yoq2Gni6oRO5T5p6bKV-nUz5Q6M3F8,8411
267
- phoenix/server/api/routers/v1/users.py,sha256=ZcW3if0L8-lUusTzET7fhlhvnmiCICDrGimzB7i3irc,11947
263
+ phoenix/server/api/routers/v1/projects.py,sha256=32GwTLsaFgQLVNdjrlrGe90XT3pIX1N7-zX9D9_J_4w,12701
264
+ phoenix/server/api/routers/v1/prompts.py,sha256=chRYcLkOYDJdJfVZVukVTUyIRnLPvsJCg41CuPxOIU8,26695
265
+ phoenix/server/api/routers/v1/spans.py,sha256=oFoDT2XLB4chsiFQIa0fAsY2rQOa4ApioH232_utJLo,44226
266
+ phoenix/server/api/routers/v1/traces.py,sha256=63T-WYiwh8X3Sp6u_OFfA9zLLKk6cNsnciiDyUzKLVk,8561
267
+ phoenix/server/api/routers/v1/users.py,sha256=hUZCe7ctJqEkSJBe046a0OAFMLZodtyO7NLP7U6S8Pg,11986
268
268
  phoenix/server/api/routers/v1/utils.py,sha256=oXIOGPzPTkE0ZWUTRCoRIQQ7wTzoSwtWFaUSjlGBqts,4960
269
269
  phoenix/server/api/types/Annotation.py,sha256=gsl8CwjIbDUbZRj4d9USwZ_w_Tkz4i7zuZh9ftV80jA,1132
270
270
  phoenix/server/api/types/AnnotationConfig.py,sha256=TPukZUgvFC17W93Vnme21EhswasBMR-ZiuSWteiWZOU,3891
@@ -332,7 +332,7 @@ phoenix/server/api/types/Retrieval.py,sha256=OhMK2ncjoyp5h1yjKhjlKpoTbQrMHuxmgSF
332
332
  phoenix/server/api/types/ScalarDriftMetricEnum.py,sha256=IUAcRPpgL41WdoIgK6cNk2Te38SspXGyEs-S1fY23_A,232
333
333
  phoenix/server/api/types/Segments.py,sha256=vT2v0efoa5cuBKxLtxTnsUP5YJJCZfTloM71Spu0tMI,2915
334
334
  phoenix/server/api/types/SortDir.py,sha256=OUpXhlCzCxPoXSDkJJygEs9Rw9pMymfaZUG5zPTrw4Y,152
335
- phoenix/server/api/types/Span.py,sha256=C0gTw9cx-6MKdMPCbrBjyyYRgXBpXB8wrR41lOhFPZE,36253
335
+ phoenix/server/api/types/Span.py,sha256=0o1lyceeZhEeBLBdd8gYo324nQ1P6eTPOi3aKdZZUd4,32015
336
336
  phoenix/server/api/types/SpanAnnotation.py,sha256=uPWu7Z8rmpfKhaaxbged4_o00pPCR3nkn7Gji9vB8jY,1959
337
337
  phoenix/server/api/types/SpanCostDetailSummaryEntry.py,sha256=RXAdOC6MFyR9mwaoj8lMMdI3_9r3z6mR2izJvlsj12U,252
338
338
  phoenix/server/api/types/SpanCostSummary.py,sha256=wo03FCMcFzB5m4P5kvA5jzi9ACLbht38ozQbDJUh94g,357
@@ -356,18 +356,20 @@ phoenix/server/api/types/node.py,sha256=BLl_IOFr0zrqUxaAtGLGui5aeM5VNVXFTzGeAKrz
356
356
  phoenix/server/api/types/pagination.py,sha256=BXm46gXZfrBS4hpiLvVSEdsbb29ctUMVJYjKXlOLxUA,9064
357
357
  phoenix/server/cost_tracking/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
358
358
  phoenix/server/cost_tracking/cost_details_calculator.py,sha256=ywWQO6foRZC0CmbNPGpa3DaPoWzuIp3ke9s4NqHLuUw,8736
359
- phoenix/server/cost_tracking/cost_model_lookup.py,sha256=ys-jZY3cSE2_-f1glFhYgOd60kQdDL07MnChaxojTLo,6800
359
+ phoenix/server/cost_tracking/cost_model_lookup.py,sha256=jhtVdnQBzrTUHeOGPWgOebk-Io5hpJ1vAgWOu8ojeJ4,6801
360
360
  phoenix/server/cost_tracking/helpers.py,sha256=Pk6ECjnYreTxrldtRwxnwFcxIPVsvDq_yAwDA_spkOc,2122
361
- phoenix/server/cost_tracking/model_cost_manifest.json,sha256=UgtshWqK3KV4tsgboS0Z4xj08PEnCwubaMhliN1fquk,54092
361
+ phoenix/server/cost_tracking/model_cost_manifest.json,sha256=sMXOjssVwcJkmdMapA5-eYjXIboUu8FDosuXGL3q1Cw,53862
362
362
  phoenix/server/cost_tracking/regex_specificity.py,sha256=9kqWuQ68C-hlwW25hr7BhFlRt5y2Nnpy0Ax3n9UN6Xk,11622
363
363
  phoenix/server/cost_tracking/token_cost_calculator.py,sha256=2JEZnvusx2-xbhp8krp9EarjWuyGH2KO4e-ZwJX-K0s,1598
364
364
  phoenix/server/daemons/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
365
+ phoenix/server/daemons/db_disk_usage_monitor.py,sha256=_MckKf9GbQ3Is4WZ3RmwJmvVElkF9Ipss3yNHjF8R3c,8016
365
366
  phoenix/server/daemons/generative_model_store.py,sha256=CkMG0jFWtxcUNP_7iFTgzHPyl5IgnXUwwJb7584pmkI,1566
366
367
  phoenix/server/daemons/span_cost_calculator.py,sha256=0BXMe9sHN8k5RjIQjCBzZdwvFuBHu8zDqAJc8rXbQA0,3199
367
368
  phoenix/server/email/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
368
- phoenix/server/email/sender.py,sha256=kH94CtAQACyu9KgtVBLmJwMNICxY1XVtbfthibAOC-8,4067
369
- phoenix/server/email/types.py,sha256=IO2bTtCh-1cve-xiM4MWnunCCVNOQ3Z2cqTqF7vH-do,466
369
+ phoenix/server/email/sender.py,sha256=mTZUdf_M9GRiA2_MXmWO6hXvQHXbuRUyea-_YoTC5Mo,4974
370
+ phoenix/server/email/types.py,sha256=f1XXk4OQJlLSCHweujrGlkZic7CtbUSnfdPXzqP9WRI,772
370
371
  phoenix/server/email/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
372
+ phoenix/server/email/templates/db_disk_usage_notification.html,sha256=VsGW_yPXPgspwp_xhFYANoqDENaO3En36qSw26l4fh4,733
371
373
  phoenix/server/email/templates/password_reset.html,sha256=jv0Pe-06JloPZcubRWxPdAFHYEn9eDj_4SjmuoIwshI,441
372
374
  phoenix/server/email/templates/welcome.html,sha256=AyVsIOtpmyYwWmmkXjuEgXwkbsag4YHHKfkmOTiNo-M,316
373
375
  phoenix/server/middleware/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -383,16 +385,16 @@ phoenix/server/static/apple-touch-icon-76x76.png,sha256=CT_xT12I0u2i0WU8JzBZBuOQ
383
385
  phoenix/server/static/apple-touch-icon.png,sha256=fOfpjqGpWYbJ0eAurKsyoZP1EAs6ZVooBJ_SGk2ZkDs,3801
384
386
  phoenix/server/static/favicon.ico,sha256=bY0vvCKRftemZfPShwZtE93DiiQdaYaozkPGwNFr6H8,34494
385
387
  phoenix/server/static/modernizr.js,sha256=mvK-XtkNqjOral-QvzoqsyOMECXIMu5BQwSVN_wcU9c,2564
386
- phoenix/server/static/.vite/manifest.json,sha256=QgtR93dPPpen9hQbyvYjBmBrFMA9bClIjBKoqgW_VGU,2165
387
- phoenix/server/static/assets/components-CVcMbu2U.js,sha256=vN025v6OiThd5R7WDDvcP_78vGyFJsmlMRF_3Y_FROU,613683
388
- phoenix/server/static/assets/index-Dz7I-Hpn.js,sha256=HEPv8kZxjJnc9peoT-p7Tq20hQ6zZfWXaqijRW0ABGo,61540
389
- phoenix/server/static/assets/pages-QK2o2V7x.js,sha256=wQUm3smWw9ij4guETW88q4j0NTMgjd1ZTgv80CTF5Fg,1142749
388
+ phoenix/server/static/.vite/manifest.json,sha256=Zj-tml_8YSPL9TgLhBQlJtU8VvoayudhofQOJ0SZwrc,2165
389
+ phoenix/server/static/assets/components-mOUBHJ12.js,sha256=0CP0snc1584_nGtYOZ2-TzS61eorXGcw19V2nXysysc,613664
390
+ phoenix/server/static/assets/index-CQ_A6K_M.js,sha256=McgJhbcluGJTW8reudv1UCVYW2cFTpJJ10Tl-xfizSU,61726
391
+ phoenix/server/static/assets/pages-CCsLkNZY.js,sha256=zgD05qvSU39V6nYtxslmXXk_8zZHfANMDpO3GL1_4JA,1146914
392
+ phoenix/server/static/assets/vendor-DRWIRkSJ.js,sha256=f56XLATSYmnWXn7652x9UsGk4jOQygtd7bfaXtI4I_o,2738792
390
393
  phoenix/server/static/assets/vendor-WIZid84E.css,sha256=spZD2r7XL5GfLO13ln-IuXfnjAref8l6g_n_AvxxOlI,5517
391
- phoenix/server/static/assets/vendor-arizeai-BwMsgSAG.js,sha256=kkuIy24gRn9HkPcoR964N8ZR72gGuYE4HYmDpl_hgHw,181769
392
- phoenix/server/static/assets/vendor-codemirror-BwSDEu2g.js,sha256=bBRglOrI4AC3NxOMI0aEq6kycgR3o0gbolog5Z273ZE,781264
393
- phoenix/server/static/assets/vendor-pg5m6BWE.js,sha256=TYLzU6I-FwnFZ_oJFLCTeP5dJRggWcO8hrVhRGLqiBw,2738792
394
- phoenix/server/static/assets/vendor-recharts-SW3HwAtG.js,sha256=dw7SMNDQnsLfznqxkkKg8Uf9_DMyk73R0-fvvDMiq9c,282150
395
- phoenix/server/static/assets/vendor-shiki-BsdYoDvs.js,sha256=vYHnybQvrJ8VPU0iBpEOd-BohB9gs3gWwY9wAr65i40,8980312
394
+ phoenix/server/static/assets/vendor-arizeai-DUhQaeau.js,sha256=FtPCxnjNFpPwea0mcq1qokn2T5MQWpp-yxL-_ZbaUZw,181769
395
+ phoenix/server/static/assets/vendor-codemirror-D_6Q6Auv.js,sha256=poYtDd52iZVllnYDEqBUCz9n3h9o8DWzIsfhpP1q9pU,781264
396
+ phoenix/server/static/assets/vendor-recharts-BNBwj7vz.js,sha256=mskT3kobCNuJlVio5idqsqw0dJ-v94a9D0wXmKHV94o,282150
397
+ phoenix/server/static/assets/vendor-shiki-k1qj_XjP.js,sha256=fQi82DMPyJAp6Ng4MlL1THL26gUcYKDOM6XB5-JpoqE,8980312
396
398
  phoenix/server/static/assets/vendor-three-C5WAXd5r.js,sha256=ELkg06u70N7h8oFmvqdoHyPuUf9VgGEWeT4LKFx4VWo,620975
397
399
  phoenix/server/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
398
400
  phoenix/server/templates/index.html,sha256=rTdJZOlbZmm1dMCrHWikAwcecZDxduPU5zCFd2h2cbs,6819
@@ -433,9 +435,9 @@ phoenix/utilities/project.py,sha256=auVpARXkDb-JgeX5f2aStyFIkeKvGwN9l7qrFeJMVxI,
433
435
  phoenix/utilities/re.py,sha256=6YyUWIkv0zc2SigsxfOWIHzdpjKA_TZo2iqKq7zJKvw,2081
434
436
  phoenix/utilities/span_store.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
435
437
  phoenix/utilities/template_formatters.py,sha256=gh9PJD6WEGw7TEYXfSst1UR4pWWwmjxMLrDVQ_CkpkQ,2779
436
- arize_phoenix-11.4.0.dist-info/METADATA,sha256=DpVGzCavFMw9wI6djANYOCL2eo7LmUgj2TLjo7WeGkA,27777
437
- arize_phoenix-11.4.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
438
- arize_phoenix-11.4.0.dist-info/entry_points.txt,sha256=Pgpn8Upxx9P8z8joPXZWl2LlnAlGc3gcQoVchb06X1Q,94
439
- arize_phoenix-11.4.0.dist-info/licenses/IP_NOTICE,sha256=JBqyyCYYxGDfzQ0TtsQgjts41IJoa-hiwDrBjCb9gHM,469
440
- arize_phoenix-11.4.0.dist-info/licenses/LICENSE,sha256=HFkW9REuMOkvKRACuwLPT0hRydHb3zNg-fdFt94td18,3794
441
- arize_phoenix-11.4.0.dist-info/RECORD,,
438
+ arize_phoenix-11.6.0.dist-info/METADATA,sha256=yvDNlFfsf6bNEXlrDyo0qflVgYt5T5UjmB9Y-Se7ZKY,27761
439
+ arize_phoenix-11.6.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
440
+ arize_phoenix-11.6.0.dist-info/entry_points.txt,sha256=Pgpn8Upxx9P8z8joPXZWl2LlnAlGc3gcQoVchb06X1Q,94
441
+ arize_phoenix-11.6.0.dist-info/licenses/IP_NOTICE,sha256=JBqyyCYYxGDfzQ0TtsQgjts41IJoa-hiwDrBjCb9gHM,469
442
+ arize_phoenix-11.6.0.dist-info/licenses/LICENSE,sha256=HFkW9REuMOkvKRACuwLPT0hRydHb3zNg-fdFt94td18,3794
443
+ arize_phoenix-11.6.0.dist-info/RECORD,,
phoenix/config.py CHANGED
@@ -106,7 +106,24 @@ ENV_PHOENIX_DATABASE_ALLOCATED_STORAGE_CAPACITY_GIBIBYTES = (
106
106
  )
107
107
  """
108
108
  The allocated storage capacity for the Phoenix database in gibibytes (2^30 bytes). Use float for
109
- fractional value. This is currently used only by the UI for informational displays.
109
+ fractional value.
110
+ """
111
+ ENV_PHOENIX_DATABASE_USAGE_EMAIL_WARNING_THRESHOLD_PERCENTAGE = (
112
+ "PHOENIX_DATABASE_USAGE_EMAIL_WARNING_THRESHOLD_PERCENTAGE"
113
+ )
114
+ """
115
+ The percentage of the allocated storage capacity that, when exceeded, triggers a email notifications
116
+ to admin users with valid email addresses. Must be specified in conjunction with allocated storage
117
+ capacity. This is a percentage value between 0 and 100. This setting is ignored if SMTP is not
118
+ configured.
119
+ """
120
+ ENV_PHOENIX_DATABASE_USAGE_INSERTION_BLOCKING_THRESHOLD_PERCENTAGE = (
121
+ "PHOENIX_DATABASE_USAGE_INSERTION_BLOCKING_THRESHOLD_PERCENTAGE"
122
+ )
123
+ """
124
+ The percentage of the allocated storage capacity that blocks insertions and updates of database
125
+ records when exceeded. Deletions are not blocked. Must be specified in conjunction with allocated
126
+ storage capacity. This is a percentage value between 0 and 100.
110
127
  """
111
128
  ENV_PHOENIX_ENABLE_PROMETHEUS = "PHOENIX_ENABLE_PROMETHEUS"
112
129
  """
@@ -1312,7 +1329,36 @@ def get_env_database_schema() -> Optional[str]:
1312
1329
 
1313
1330
 
1314
1331
  def get_env_database_allocated_storage_capacity_gibibytes() -> Optional[float]:
1315
- return _float_val(ENV_PHOENIX_DATABASE_ALLOCATED_STORAGE_CAPACITY_GIBIBYTES)
1332
+ ans = _float_val(ENV_PHOENIX_DATABASE_ALLOCATED_STORAGE_CAPACITY_GIBIBYTES)
1333
+ if ans is not None and ans <= 0:
1334
+ raise ValueError(
1335
+ f"Invalid value for environment variable "
1336
+ f"{ENV_PHOENIX_DATABASE_ALLOCATED_STORAGE_CAPACITY_GIBIBYTES}: "
1337
+ f"{ans}. Value must be a positive number."
1338
+ )
1339
+ return ans
1340
+
1341
+
1342
+ def get_env_database_usage_email_warning_threshold_percentage() -> Optional[float]:
1343
+ ans = _float_val(ENV_PHOENIX_DATABASE_USAGE_EMAIL_WARNING_THRESHOLD_PERCENTAGE)
1344
+ if ans is not None and not (0 <= ans <= 100):
1345
+ raise ValueError(
1346
+ f"Invalid value for environment variable "
1347
+ f"{ENV_PHOENIX_DATABASE_USAGE_EMAIL_WARNING_THRESHOLD_PERCENTAGE}: "
1348
+ f"{ans}. Value must be a percentage between 0 and 100."
1349
+ )
1350
+ return ans
1351
+
1352
+
1353
+ def get_env_database_usage_insertion_blocking_threshold_percentage() -> Optional[float]:
1354
+ ans = _float_val(ENV_PHOENIX_DATABASE_USAGE_INSERTION_BLOCKING_THRESHOLD_PERCENTAGE)
1355
+ if ans is not None and not (0 <= ans <= 100):
1356
+ raise ValueError(
1357
+ f"Invalid value for environment variable "
1358
+ f"{ENV_PHOENIX_DATABASE_USAGE_INSERTION_BLOCKING_THRESHOLD_PERCENTAGE}: "
1359
+ f"{ans}. Value must be a percentage between 0 and 100."
1360
+ )
1361
+ return ans
1316
1362
 
1317
1363
 
1318
1364
  def get_env_enable_prometheus() -> bool:
@@ -1558,6 +1604,9 @@ def verify_server_environment_variables() -> None:
1558
1604
  get_env_root_url()
1559
1605
  get_env_phoenix_secret()
1560
1606
  get_env_phoenix_admin_secret()
1607
+ get_env_database_allocated_storage_capacity_gibibytes()
1608
+ get_env_database_usage_email_warning_threshold_percentage()
1609
+ get_env_database_usage_insertion_blocking_threshold_percentage()
1561
1610
 
1562
1611
  # Notify users about deprecated environment variables if they are being used.
1563
1612
  if os.getenv("PHOENIX_ENABLE_WEBSOCKETS") is not None:
@@ -29,7 +29,7 @@ class IsLocked(Authorization):
29
29
  message = "Operations that write or modify data are locked"
30
30
 
31
31
  def has_permission(self, source: Any, info: Info, **kwargs: Any) -> bool:
32
- return not info.context.locked
32
+ return not info.context.db.should_not_insert_or_update
33
33
 
34
34
 
35
35
  MSG_ADMIN_ONLY = "Only admin can perform this action"
@@ -25,7 +25,7 @@ from phoenix.db.helpers import SupportedSQLDialect, exclude_experiment_projects
25
25
  from phoenix.pointcloud.clustering import Hdbscan
26
26
  from phoenix.server.api.auth import MSG_ADMIN_ONLY, IsAdmin
27
27
  from phoenix.server.api.context import Context
28
- from phoenix.server.api.exceptions import NotFound, Unauthorized
28
+ from phoenix.server.api.exceptions import BadRequest, NotFound, Unauthorized
29
29
  from phoenix.server.api.helpers import ensure_list
30
30
  from phoenix.server.api.helpers.experiment_run_filters import (
31
31
  ExperimentRunFilterConditionSyntaxError,
@@ -62,7 +62,13 @@ from phoenix.server.api.types.GenerativeProvider import GenerativeProvider, Gene
62
62
  from phoenix.server.api.types.InferenceModel import InferenceModel
63
63
  from phoenix.server.api.types.InferencesRole import AncillaryInferencesRole, InferencesRole
64
64
  from phoenix.server.api.types.node import from_global_id, from_global_id_with_expected_type
65
- from phoenix.server.api.types.pagination import ConnectionArgs, CursorString, connection_from_list
65
+ from phoenix.server.api.types.pagination import (
66
+ ConnectionArgs,
67
+ Cursor,
68
+ CursorString,
69
+ connection_from_cursors_and_nodes,
70
+ connection_from_list,
71
+ )
66
72
  from phoenix.server.api.types.PlaygroundModel import PlaygroundModel
67
73
  from phoenix.server.api.types.Project import Project
68
74
  from phoenix.server.api.types.ProjectSession import ProjectSession, to_gql_project_session
@@ -329,27 +335,22 @@ class Query:
329
335
  async def compare_experiments(
330
336
  self,
331
337
  info: Info[Context, None],
332
- experiment_ids: list[GlobalID],
338
+ baseline_experiment_id: GlobalID,
339
+ compare_experiment_ids: list[GlobalID],
333
340
  first: Optional[int] = 50,
334
341
  after: Optional[CursorString] = UNSET,
335
342
  filter_condition: Optional[str] = UNSET,
336
343
  ) -> Connection[ExperimentComparison]:
337
- # Handle empty experiment_ids gracefully
338
- if not experiment_ids:
339
- return connection_from_list(
340
- data=[],
341
- args=ConnectionArgs(
342
- first=first,
343
- after=after if isinstance(after, CursorString) else None,
344
- ),
345
- )
346
-
347
- experiment_ids_ = [
344
+ if baseline_experiment_id in compare_experiment_ids:
345
+ raise BadRequest("Compare experiment IDs cannot contain the baseline experiment ID")
346
+ if len(set(compare_experiment_ids)) < len(compare_experiment_ids):
347
+ raise BadRequest("Compare experiment IDs must be unique")
348
+ experiment_ids = [
348
349
  from_global_id_with_expected_type(experiment_id, models.Experiment.__name__)
349
- for experiment_id in experiment_ids
350
+ for experiment_id in (baseline_experiment_id, *compare_experiment_ids)
350
351
  ]
351
- if len(set(experiment_ids_)) != len(experiment_ids_):
352
- raise ValueError("Experiment IDs must be unique.")
352
+ cursor = Cursor.from_string(after) if after else None
353
+ page_size = first or 50
353
354
 
354
355
  async with info.context.db() as session:
355
356
  validation_result = (
@@ -366,18 +367,18 @@ class Query:
366
367
  models.Experiment.dataset_version_id == models.DatasetVersion.id,
367
368
  )
368
369
  .where(
369
- models.Experiment.id.in_(experiment_ids_),
370
+ models.Experiment.id.in_(experiment_ids),
370
371
  )
371
372
  )
372
373
  ).first()
373
374
  if validation_result is None:
374
- raise ValueError("No experiments could be found for input IDs.")
375
+ raise NotFound("No experiments could be found for input IDs.")
375
376
 
376
377
  num_datasets, dataset_id, version_id, num_resolved_experiment_ids = validation_result
377
378
  if num_datasets != 1:
378
- raise ValueError("Experiments must belong to the same dataset.")
379
- if num_resolved_experiment_ids != len(experiment_ids_):
380
- raise ValueError("Unable to resolve one or more experiment IDs.")
379
+ raise BadRequest("Experiments must belong to the same dataset.")
380
+ if num_resolved_experiment_ids != len(experiment_ids):
381
+ raise NotFound("Unable to resolve one or more experiment IDs.")
381
382
 
382
383
  revision_ids = (
383
384
  select(func.max(models.DatasetExampleRevision.id))
@@ -407,16 +408,21 @@ class Query:
407
408
  ),
408
409
  )
409
410
  .order_by(models.DatasetExample.id.desc())
411
+ .limit(page_size + 1)
410
412
  )
413
+ if cursor is not None:
414
+ examples_query = examples_query.where(models.DatasetExample.id < cursor.rowid)
411
415
 
412
416
  if filter_condition:
413
417
  examples_query = update_examples_query_with_filter_condition(
414
418
  query=examples_query,
415
419
  filter_condition=filter_condition,
416
- experiment_ids=experiment_ids_,
420
+ experiment_ids=experiment_ids,
417
421
  )
418
422
 
419
423
  examples = (await session.scalars(examples_query)).all()
424
+ has_next_page = len(examples) > page_size
425
+ examples = examples[:page_size]
420
426
 
421
427
  ExampleID: TypeAlias = int
422
428
  ExperimentID: TypeAlias = int
@@ -430,17 +436,20 @@ class Query:
430
436
  models.ExperimentRun.dataset_example_id.in_(
431
437
  example.id for example in examples
432
438
  ),
433
- models.ExperimentRun.experiment_id.in_(experiment_ids_),
439
+ models.ExperimentRun.experiment_id.in_(experiment_ids),
434
440
  )
435
441
  )
436
442
  .options(joinedload(models.ExperimentRun.trace).load_only(models.Trace.trace_id))
443
+ .order_by(
444
+ models.ExperimentRun.repetition_number.asc()
445
+ ) # repetitions are not currently implemented, but this ensures that the repetitions will be properly ordered once implemented # noqa: E501
437
446
  ):
438
447
  runs[run.dataset_example_id][run.experiment_id].append(run)
439
448
 
440
- experiment_comparisons = []
449
+ cursors_and_nodes = []
441
450
  for example in examples:
442
451
  run_comparison_items = []
443
- for experiment_id in experiment_ids_:
452
+ for experiment_id in experiment_ids:
444
453
  run_comparison_items.append(
445
454
  RunComparisonItem(
446
455
  experiment_id=GlobalID(Experiment.__name__, str(experiment_id)),
@@ -452,23 +461,21 @@ class Query:
452
461
  ],
453
462
  )
454
463
  )
455
- experiment_comparisons.append(
456
- ExperimentComparison(
464
+ experiment_comparison = ExperimentComparison(
465
+ id_attr=example.id,
466
+ example=DatasetExample(
457
467
  id_attr=example.id,
458
- example=DatasetExample(
459
- id_attr=example.id,
460
- created_at=example.created_at,
461
- version_id=version_id,
462
- ),
463
- run_comparison_items=run_comparison_items,
464
- )
468
+ created_at=example.created_at,
469
+ version_id=version_id,
470
+ ),
471
+ run_comparison_items=run_comparison_items,
465
472
  )
466
- return connection_from_list(
467
- data=experiment_comparisons,
468
- args=ConnectionArgs(
469
- first=first,
470
- after=after if isinstance(after, CursorString) else None,
471
- ),
473
+ cursors_and_nodes.append((Cursor(rowid=example.id), experiment_comparison))
474
+
475
+ return connection_from_cursors_and_nodes(
476
+ cursors_and_nodes=cursors_and_nodes,
477
+ has_previous_page=False, # set to false since we are only doing forward pagination (https://relay.dev/graphql/connections.htm#sec-undefined.PageInfo.Fields) # noqa: E501
478
+ has_next_page=has_next_page,
472
479
  )
473
480
 
474
481
  @strawberry.field
@@ -977,13 +984,14 @@ class Query:
977
984
  # stats = cast(Iterable[tuple[str, int]], await session.execute(stmt))
978
985
  # stats = _consolidate_sqlite_db_table_stats(stats)
979
986
  elif info.context.db.dialect is SupportedSQLDialect.POSTGRESQL:
980
- stmt = text(f"""\
987
+ nspname = getenv(ENV_PHOENIX_SQL_DATABASE_SCHEMA) or "public"
988
+ stmt = text("""\
981
989
  SELECT c.relname, pg_total_relation_size(c.oid)
982
990
  FROM pg_class as c
983
991
  INNER JOIN pg_namespace as n ON n.oid = c.relnamespace
984
992
  WHERE c.relkind = 'r'
985
- AND n.nspname = '{getenv(ENV_PHOENIX_SQL_DATABASE_SCHEMA) or "public"}';
986
- """)
993
+ AND n.nspname = :nspname;
994
+ """).bindparams(nspname=nspname)
987
995
  try:
988
996
  async with info.context.db() as session:
989
997
  stats = cast(Iterable[tuple[str, int]], await session.execute(stmt))
@@ -1,7 +1,7 @@
1
1
  import logging
2
2
  from typing import Annotated, List, Literal, Optional, Union
3
3
 
4
- from fastapi import APIRouter, HTTPException, Path, Query
4
+ from fastapi import APIRouter, Depends, HTTPException, Path, Query
5
5
  from pydantic import Field, RootModel
6
6
  from sqlalchemy import delete, select
7
7
  from sqlalchemy.exc import IntegrityError as PostgreSQLIntegrityError
@@ -44,6 +44,7 @@ from phoenix.server.api.types.AnnotationConfig import (
44
44
  from phoenix.server.api.types.AnnotationConfig import (
45
45
  FreeformAnnotationConfig as FreeformAnnotationConfigType,
46
46
  )
47
+ from phoenix.server.authorization import is_not_locked
47
48
 
48
49
  logger = logging.getLogger(__name__)
49
50
 
@@ -268,6 +269,7 @@ async def get_annotation_config_by_name_or_id(
268
269
 
269
270
  @router.post(
270
271
  "/annotation_configs",
272
+ dependencies=[Depends(is_not_locked)],
271
273
  summary="Create an annotation configuration",
272
274
  )
273
275
  async def create_annotation_config(
@@ -302,6 +304,7 @@ async def create_annotation_config(
302
304
 
303
305
  @router.put(
304
306
  "/annotation_configs/{config_id}",
307
+ dependencies=[Depends(is_not_locked)],
305
308
  summary="Update an annotation configuration",
306
309
  )
307
310
  async def update_annotation_config(
@@ -15,7 +15,7 @@ from typing import Any, Optional, Union, cast
15
15
 
16
16
  import pandas as pd
17
17
  import pyarrow as pa
18
- from fastapi import APIRouter, BackgroundTasks, HTTPException, Path, Query
18
+ from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException, Path, Query
19
19
  from fastapi.responses import PlainTextResponse, StreamingResponse
20
20
  from sqlalchemy import and_, delete, func, select
21
21
  from sqlalchemy.ext.asyncio import AsyncSession
@@ -47,6 +47,7 @@ from phoenix.server.api.types.DatasetExample import DatasetExample as DatasetExa
47
47
  from phoenix.server.api.types.DatasetVersion import DatasetVersion as DatasetVersionNodeType
48
48
  from phoenix.server.api.types.node import from_global_id_with_expected_type
49
49
  from phoenix.server.api.utils import delete_projects, delete_traces
50
+ from phoenix.server.authorization import is_not_locked
50
51
  from phoenix.server.dml_event import DatasetInsertEvent
51
52
 
52
53
  from .models import V1RoutesBaseModel
@@ -326,6 +327,7 @@ class UploadDatasetResponseBody(ResponseBody[UploadDatasetData]):
326
327
 
327
328
  @router.post(
328
329
  "/datasets/upload",
330
+ dependencies=[Depends(is_not_locked)],
329
331
  operation_id="uploadDataset",
330
332
  summary="Upload dataset from JSON, CSV, or PyArrow",
331
333
  responses=add_errors_to_responses(
@@ -5,7 +5,7 @@ from typing import Any, Iterator, Optional, Union, cast
5
5
 
6
6
  import pandas as pd
7
7
  import pyarrow as pa
8
- from fastapi import APIRouter, Header, HTTPException, Query
8
+ from fastapi import APIRouter, Depends, Header, HTTPException, Query
9
9
  from google.protobuf.message import DecodeError
10
10
  from pandas import DataFrame
11
11
  from sqlalchemy import select
@@ -28,6 +28,7 @@ from phoenix.db import models
28
28
  from phoenix.db.insertion.types import Precursors
29
29
  from phoenix.exceptions import PhoenixEvaluationNameIsMissing
30
30
  from phoenix.server.api.routers.utils import table_to_bytes
31
+ from phoenix.server.authorization import is_not_locked
31
32
  from phoenix.server.types import DbSessionFactory
32
33
  from phoenix.trace.span_evaluations import (
33
34
  DocumentEvaluations,
@@ -45,6 +46,7 @@ router = APIRouter(tags=["traces"], include_in_schema=True)
45
46
 
46
47
  @router.post(
47
48
  "/evaluations",
49
+ dependencies=[Depends(is_not_locked)],
48
50
  operation_id="addEvaluations",
49
51
  summary="Add span, trace, or document evaluations",
50
52
  status_code=HTTP_204_NO_CONTENT,
@@ -1,7 +1,7 @@
1
1
  from datetime import datetime
2
2
  from typing import Any, Optional
3
3
 
4
- from fastapi import APIRouter, HTTPException
4
+ from fastapi import APIRouter, Depends, HTTPException
5
5
  from pydantic import Field
6
6
  from sqlalchemy import select
7
7
  from sqlalchemy.exc import IntegrityError as PostgreSQLIntegrityError
@@ -13,6 +13,7 @@ from strawberry.relay import GlobalID
13
13
  from phoenix.db import models
14
14
  from phoenix.db.models import ExperimentRunOutput
15
15
  from phoenix.server.api.types.node import from_global_id_with_expected_type
16
+ from phoenix.server.authorization import is_not_locked
16
17
  from phoenix.server.dml_event import ExperimentRunInsertEvent
17
18
 
18
19
  from .models import V1RoutesBaseModel
@@ -52,6 +53,7 @@ class CreateExperimentRunResponseBody(ResponseBody[CreateExperimentRunResponseBo
52
53
 
53
54
  @router.post(
54
55
  "/experiments/{experiment_id}/runs",
56
+ dependencies=[Depends(is_not_locked)],
55
57
  operation_id="createExperimentRun",
56
58
  summary="Create run for an experiment",
57
59
  response_description="Experiment run created successfully",
@@ -4,7 +4,7 @@ from random import getrandbits
4
4
  from typing import Any, Optional
5
5
 
6
6
  import pandas as pd
7
- from fastapi import APIRouter, HTTPException, Path, Response
7
+ from fastapi import APIRouter, Depends, HTTPException, Path, Response
8
8
  from pydantic import Field
9
9
  from sqlalchemy import and_, func, select
10
10
  from sqlalchemy.ext.asyncio import AsyncSession
@@ -18,6 +18,7 @@ from phoenix.db import models
18
18
  from phoenix.db.helpers import SupportedSQLDialect
19
19
  from phoenix.db.insertion.helpers import insert_on_conflict
20
20
  from phoenix.server.api.types.node import from_global_id_with_expected_type
21
+ from phoenix.server.authorization import is_not_locked
21
22
  from phoenix.server.dml_event import ExperimentInsertEvent
22
23
 
23
24
  from .models import V1RoutesBaseModel
@@ -86,6 +87,7 @@ class CreateExperimentResponseBody(ResponseBody[Experiment]):
86
87
 
87
88
  @router.post(
88
89
  "/datasets/{dataset_id}/experiments",
90
+ dependencies=[Depends(is_not_locked)],
89
91
  operation_id="createExperiment",
90
92
  summary="Create experiment on a dataset",
91
93
  responses=add_errors_to_responses(
@@ -1,6 +1,6 @@
1
1
  from typing import Optional
2
2
 
3
- from fastapi import APIRouter, HTTPException, Path, Query
3
+ from fastapi import APIRouter, Depends, HTTPException, Path, Query
4
4
  from pydantic import Field
5
5
  from sqlalchemy import select
6
6
  from starlette.requests import Request
@@ -23,6 +23,7 @@ from phoenix.server.api.routers.v1.utils import (
23
23
  add_errors_to_responses,
24
24
  )
25
25
  from phoenix.server.api.types.Project import Project as ProjectNodeType
26
+ from phoenix.server.authorization import is_not_locked
26
27
 
27
28
  router = APIRouter(tags=["projects"])
28
29
 
@@ -173,6 +174,7 @@ async def get_project(
173
174
 
174
175
  @router.post(
175
176
  "/projects",
177
+ dependencies=[Depends(is_not_locked)],
176
178
  operation_id="createProject",
177
179
  summary="Create a new project", # noqa: E501
178
180
  description="Create a new project with the specified configuration.", # noqa: E501
@@ -213,6 +215,7 @@ async def create_project(
213
215
 
214
216
  @router.put(
215
217
  "/projects/{project_identifier}",
218
+ dependencies=[Depends(is_not_locked)],
216
219
  operation_id="updateProject",
217
220
  summary="Update a project by ID or name", # noqa: E501
218
221
  description="Update an existing project with new configuration. Project names cannot be changed. The project identifier is either project ID or project name. Note: When using a project name as the identifier, it cannot contain slash (/), question mark (?), or pound sign (#) characters.", # noqa: E501