arize-phoenix 4.21.0__py3-none-any.whl → 4.22.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of arize-phoenix might be problematic. Click here for more details.
- {arize_phoenix-4.21.0.dist-info → arize_phoenix-4.22.1.dist-info}/METADATA +1 -1
- {arize_phoenix-4.21.0.dist-info → arize_phoenix-4.22.1.dist-info}/RECORD +25 -25
- phoenix/config.py +59 -1
- phoenix/db/migrations/future_versions/README.md +4 -0
- phoenix/db/migrations/future_versions/cd164e83824f_users_and_tokens.py +292 -0
- phoenix/db/migrations/versions/.gitignore +1 -0
- phoenix/db/models.py +61 -0
- phoenix/experiments/functions.py +4 -4
- phoenix/experiments/types.py +3 -3
- phoenix/server/api/context.py +0 -6
- phoenix/server/api/dataloaders/__init__.py +0 -9
- phoenix/server/api/routers/v1/experiment_runs.py +7 -2
- phoenix/server/api/types/Evaluation.py +1 -26
- phoenix/server/api/types/Project.py +1 -60
- phoenix/server/api/types/Span.py +1 -9
- phoenix/server/app.py +0 -11
- phoenix/server/dml_event_handler.py +0 -3
- phoenix/server/static/.vite/manifest.json +9 -9
- phoenix/server/static/assets/{components-D2V-mOGq.js → components-BC3-LP_a.js} +44 -44
- phoenix/server/static/assets/{index-B52Z3aZG.js → index-BjJvafYL.js} +1 -1
- phoenix/server/static/assets/{pages-CChOjmat.js → pages--n2933VW.js} +214 -195
- phoenix/version.py +1 -1
- phoenix/server/api/dataloaders/evaluation_summaries.py +0 -149
- phoenix/server/api/dataloaders/span_evaluations.py +0 -35
- phoenix/server/api/dataloaders/trace_evaluations.py +0 -35
- {arize_phoenix-4.21.0.dist-info → arize_phoenix-4.22.1.dist-info}/WHEEL +0 -0
- {arize_phoenix-4.21.0.dist-info → arize_phoenix-4.22.1.dist-info}/licenses/IP_NOTICE +0 -0
- {arize_phoenix-4.21.0.dist-info → arize_phoenix-4.22.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
phoenix/__init__.py,sha256=TGNWqm2UW-l67yIRpOtmqGHVAmdoobSNqUsiTtip7uQ,1542
|
|
2
|
-
phoenix/config.py,sha256=
|
|
2
|
+
phoenix/config.py,sha256=wYA_8GSSz5rnpfIWDjeBL9ehKuTy9jqXaMZnxUqRYEU,10131
|
|
3
3
|
phoenix/datetime_utils.py,sha256=yDKjwX2Vtqw9h5F_ProtP-TsXidM43uIvmJ_pOzYc9A,3405
|
|
4
4
|
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=
|
|
8
|
+
phoenix/version.py,sha256=o6NOndzGr8AzXGIlB0Kpj1jAyiWB77iB92rO-Vlh2y0,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=
|
|
21
|
+
phoenix/db/models.py,sha256=C_s1TAgMRi2eExc48NwInErsfSzVhNZtj4ow23jUKSc,23352
|
|
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
|
|
@@ -32,13 +32,16 @@ phoenix/db/insertion/types.py,sha256=nQYYnpzcPxj2kdUoXfKE8ilOKlx1zpKLPc40OGuBlfk
|
|
|
32
32
|
phoenix/db/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
33
33
|
phoenix/db/migrations/env.py,sha256=QbzB5zrRs6XQQmrYeUpuzeilcMlM-MsbaAgHHYcIHTI,3626
|
|
34
34
|
phoenix/db/migrations/script.py.mako,sha256=MEqL-2qATlST9TAOeYgscMn1uy6HUS9NFvDgl93dMj8,635
|
|
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
|
|
37
|
+
phoenix/db/migrations/versions/.gitignore,sha256=chLdMrfkICZvLY7lCEcuqF32sVp61Jml4PodFryEU94,33
|
|
35
38
|
phoenix/db/migrations/versions/10460e46d750_datasets.py,sha256=eZAyz720DmpOd7RnuxDN2dVNXVuMrdlCA7eAOxyMtfs,8695
|
|
36
39
|
phoenix/db/migrations/versions/3be8647b87d8_add_token_columns_to_spans_table.py,sha256=x6oKFwn7Zmite4G0trDQPpMCn0I7jejuBcN3-ivEuDg,3938
|
|
37
40
|
phoenix/db/migrations/versions/cf03bd6bae1d_init.py,sha256=09cpofqje8zi4eQFfUn-i21x7VcsUYOfLKKUlrtKrGc,8662
|
|
38
41
|
phoenix/experiments/__init__.py,sha256=6JGwgUd7xCbGpuHqYZlsmErmYvVgv7N_j43bn3dUqsk,123
|
|
39
|
-
phoenix/experiments/functions.py,sha256=
|
|
42
|
+
phoenix/experiments/functions.py,sha256=WnyBaO6UEesQ1P77GXy-brQSSY9NF1EpAULbtbr4mHo,32228
|
|
40
43
|
phoenix/experiments/tracing.py,sha256=wVpt8Ie9WNPoi1djJdcrkwCokHdTO0bicXViLg3O-1Y,2831
|
|
41
|
-
phoenix/experiments/types.py,sha256=
|
|
44
|
+
phoenix/experiments/types.py,sha256=HegeRSLyx2lESlzAc2PXYQJVHBFbCLwqQQmPcDMdUnM,23433
|
|
42
45
|
phoenix/experiments/utils.py,sha256=wLu5Kvt1b4a8rGPRWq5G8RQ9XSiV8fCIVm51zWBI3-g,758
|
|
43
46
|
phoenix/experiments/evaluators/__init__.py,sha256=j63fi3fa3U7-itVPHa82GowhjQRU-wO6yhO34u_lhsA,714
|
|
44
47
|
phoenix/experiments/evaluators/base.py,sha256=jAwJs-V7jCp2UBChL0S3813Xyd9GN4rU4IEhX0nkFGs,5549
|
|
@@ -65,9 +68,9 @@ phoenix/pointcloud/pointcloud.py,sha256=4zAIkKs2xOUbchpj4XDAV-iPMXrfAJ15TG6rlIYG
|
|
|
65
68
|
phoenix/pointcloud/projectors.py,sha256=zO_RrtDYSv2rqVOfIP2_9Cv11Dc8EmcZR94xhFcBYPU,1057
|
|
66
69
|
phoenix/pointcloud/umap_parameters.py,sha256=3UQSjrysVOvq2V4KNpTMqNqNiK0BsTZnPBHWZ4fyJtQ,1708
|
|
67
70
|
phoenix/server/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
68
|
-
phoenix/server/app.py,sha256=
|
|
71
|
+
phoenix/server/app.py,sha256=fZYS5Jttj70iHnyDMivXs74oZMAx_gQgdWyNUXs59jE,19407
|
|
69
72
|
phoenix/server/dml_event.py,sha256=MpjCFqljxvgb9OB5Cez9vJesb3oHb3XxXictynBfcis,2851
|
|
70
|
-
phoenix/server/dml_event_handler.py,sha256=
|
|
73
|
+
phoenix/server/dml_event_handler.py,sha256=6p-PucctivelVHfO-_9zNxWZYPr_eGjDF3bKjLtc5co,8251
|
|
71
74
|
phoenix/server/grpc_server.py,sha256=jllxDNkpLQxDkvej4RhTokobowbvydF-SU8gSw1MTCc,3378
|
|
72
75
|
phoenix/server/main.py,sha256=dvjv3g8ANpkvSGCUN02S2Yse643Nlwrp_bj4iXBSVTE,11082
|
|
73
76
|
phoenix/server/prometheus.py,sha256=j9DHB2fERuq_ZKmwVaqR-9wx5WcPPuU1Cm5Bhg5241Y,2996
|
|
@@ -75,12 +78,12 @@ phoenix/server/telemetry.py,sha256=T_2OKrxNViAeaANlNspEekg_Y5uZIFWvKAnpz8Aoqvk,2
|
|
|
75
78
|
phoenix/server/thread_server.py,sha256=RwXQGP_QhGD7le6WB7xEygEEuwBl5Ck_Zo8xGIYGi9M,2135
|
|
76
79
|
phoenix/server/types.py,sha256=UCCkwEzUAbRdu-hZpG7A2hdPM09onBezaXNtWX4A7og,3431
|
|
77
80
|
phoenix/server/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
78
|
-
phoenix/server/api/context.py,sha256=
|
|
81
|
+
phoenix/server/api/context.py,sha256=2-kJpoix-OISxyAhoI5FFEnQMt9ad-3HQ3VOFCjdbxU,2799
|
|
79
82
|
phoenix/server/api/interceptor.py,sha256=ykDnoC_apUd-llVli3m1CW18kNSIgjz2qZ6m5JmPDu8,1294
|
|
80
83
|
phoenix/server/api/queries.py,sha256=Nuw74Nh1XhDkLNV8hTO3WPPNeqcSlNhUF76r5HaytGc,20268
|
|
81
84
|
phoenix/server/api/schema.py,sha256=BcxdqO5CSGqpKd-AAJHMjFlzaK9oJA8GJuxmMfcdjn4,434
|
|
82
85
|
phoenix/server/api/utils.py,sha256=Kl47G-1A7QKTDrc75BU2QK6HupsG6MWuXxy351FOfKQ,858
|
|
83
|
-
phoenix/server/api/dataloaders/__init__.py,sha256=
|
|
86
|
+
phoenix/server/api/dataloaders/__init__.py,sha256=TrOGnU_SD_vEIxOE_dm8HrD5C2ScLFQ4xQ7f8r-E76s,3064
|
|
84
87
|
phoenix/server/api/dataloaders/annotation_summaries.py,sha256=Wv8AORZoGd5TJ4Y-em8iqJu87AMpZP7lWOTr-SML-x8,5560
|
|
85
88
|
phoenix/server/api/dataloaders/average_experiment_run_latency.py,sha256=q091UmkXx37OBKh7L-GJ5LXHyRXfX2w4XTk1NMHtPpw,1827
|
|
86
89
|
phoenix/server/api/dataloaders/dataset_example_revisions.py,sha256=i0g8F4akEf3kQOzAvBjO27QwXNsq-kJEM8dtzduxQgY,3720
|
|
@@ -88,7 +91,6 @@ phoenix/server/api/dataloaders/dataset_example_spans.py,sha256=-TjdyyJv2c2JiN1OX
|
|
|
88
91
|
phoenix/server/api/dataloaders/document_evaluation_summaries.py,sha256=5XOom2KRAmCwPmtlraiZOSl3vhfaW-eiiYkmetAEalw,5616
|
|
89
92
|
phoenix/server/api/dataloaders/document_evaluations.py,sha256=V6sE34jON_qFxt7eArJbktykAsty-gnBZHlEkORcj0E,1296
|
|
90
93
|
phoenix/server/api/dataloaders/document_retrieval_metrics.py,sha256=JqDqkUuoeG6WfcmWSrmQptfF6IPX8XgzYzyECXTAjgg,4202
|
|
91
|
-
phoenix/server/api/dataloaders/evaluation_summaries.py,sha256=FEfUMKgk0uqQlJCS5ynmjkBoJVkqW9EVQ8vhgQ2ReKY,5656
|
|
92
94
|
phoenix/server/api/dataloaders/experiment_annotation_summaries.py,sha256=qDEBRo0XKJMYBYlXBgJ-69jwPK-0r4pi9ZhbjC_vx6M,2813
|
|
93
95
|
phoenix/server/api/dataloaders/experiment_error_rates.py,sha256=wWTFOO2UxGIYUu53nnzzLk04-mJxw-BQgJELA9gT5bY,1949
|
|
94
96
|
phoenix/server/api/dataloaders/experiment_run_counts.py,sha256=8VlKRaXwD56-7q_uonRr7L6QlEkyEQubkFKmKx6vuz0,1661
|
|
@@ -100,10 +102,8 @@ phoenix/server/api/dataloaders/record_counts.py,sha256=64OsyiQRDZASlibpQAXtRkzyA
|
|
|
100
102
|
phoenix/server/api/dataloaders/span_annotations.py,sha256=v3vGkLGTn-n4khxXZY2btgvfXitvytWgBahzrrWEz0I,1078
|
|
101
103
|
phoenix/server/api/dataloaders/span_dataset_examples.py,sha256=BtLZp11fyyeaWGGBPZj2StzFM0m5jxt52zB2nFMVybo,1306
|
|
102
104
|
phoenix/server/api/dataloaders/span_descendants.py,sha256=b7jGTn0Hi22gv2yskloLnf3BG3upS9z5hnKLMT9Sxac,2094
|
|
103
|
-
phoenix/server/api/dataloaders/span_evaluations.py,sha256=IfwXW23GQaWti8F49wSJocWf7Tklf2ZJ0F6aB4cSVHs,1248
|
|
104
105
|
phoenix/server/api/dataloaders/span_projects.py,sha256=LbQWiboCFqq4CHS18OzvRUwL9yORqP26fh5p7JbpFdg,1244
|
|
105
106
|
phoenix/server/api/dataloaders/token_counts.py,sha256=6gDVely8BYiCBdmiq1ECO0lMChUYPIlsZbB34rmL1xM,4684
|
|
106
|
-
phoenix/server/api/dataloaders/trace_evaluations.py,sha256=vraPehNsausR4dbdvq-HudRVNARJUbep3T-Ud9jwWYY,1262
|
|
107
107
|
phoenix/server/api/dataloaders/trace_row_ids.py,sha256=RODX4NULlBzMxHMrsq0dp1ij6ZlLH4ZzQBnafGdxOvU,1100
|
|
108
108
|
phoenix/server/api/dataloaders/cache/__init__.py,sha256=SYoOM9n8FJaMdQarma5d1blu-jIg2GB8Shqg5ezSzZ8,106
|
|
109
109
|
phoenix/server/api/dataloaders/cache/two_tier_cache.py,sha256=I38L1RsOis98OQftE7n1Q9QBZfFJO6OW_qIINkuJllo,2295
|
|
@@ -154,7 +154,7 @@ phoenix/server/api/routers/v1/__init__.py,sha256=nb49zcOdAi3DSGuC9gUubN9Yri-o7-W
|
|
|
154
154
|
phoenix/server/api/routers/v1/datasets.py,sha256=pyLtVEGnjwxh1wJySBOUFrsjtawatfpaF8F3WijK8qU,37049
|
|
155
155
|
phoenix/server/api/routers/v1/evaluations.py,sha256=FSfz9MTi8s65F07abDXlb9-y97fDZSYbqsCXpimwO7g,12628
|
|
156
156
|
phoenix/server/api/routers/v1/experiment_evaluations.py,sha256=RTQnjupjmh07xowjq77ajbuAZhzIEfYxA4ZtECvGwOU,4844
|
|
157
|
-
phoenix/server/api/routers/v1/experiment_runs.py,sha256=
|
|
157
|
+
phoenix/server/api/routers/v1/experiment_runs.py,sha256=0G7GgGcZv9dzK47tsPp-p4k5O7W4F_aNRrsNuJN7mho,6393
|
|
158
158
|
phoenix/server/api/routers/v1/experiments.py,sha256=GeT3Rya4bdaCr6sCf2Vx6fQ_gfMX5XyFHmODCSJiCfU,9951
|
|
159
159
|
phoenix/server/api/routers/v1/pydantic_compat.py,sha256=FeK8oe2brqu-djsoqRxiKL4tw5cHmi89OHVfCFxYsAo,2890
|
|
160
160
|
phoenix/server/api/routers/v1/spans.py,sha256=Hd63VHQUqSy0VHsYQ5DPLf5WwKALMXZOIh_ig_5MStc,8780
|
|
@@ -180,7 +180,7 @@ phoenix/server/api/types/DocumentEvaluationSummary.py,sha256=EpgKn0uiH2Vbpyltc1M
|
|
|
180
180
|
phoenix/server/api/types/DocumentRetrievalMetrics.py,sha256=amkpC3H5IU5-9GvO0telpbq00m6lIcv_2v446OpwFwc,1822
|
|
181
181
|
phoenix/server/api/types/EmbeddingDimension.py,sha256=2OTVzAcfY-2xnJLl7122EAaqJyp0sob1v9-ryaNWknw,18961
|
|
182
182
|
phoenix/server/api/types/EmbeddingMetadata.py,sha256=fJvNNYCbkf3SJalArLy9rcBq9Uj1SNac60zjqe1PFnM,461
|
|
183
|
-
phoenix/server/api/types/Evaluation.py,sha256=
|
|
183
|
+
phoenix/server/api/types/Evaluation.py,sha256=rLJptUSRUPPx9sdUyc4UPWxzkr9gcKtkpAS5Zi_EyFQ,2406
|
|
184
184
|
phoenix/server/api/types/EvaluationSummary.py,sha256=N1DhPXGhBbOOQakF43OGuZ5fl4vye7Uc-HnW5M262F8,1518
|
|
185
185
|
phoenix/server/api/types/Event.py,sha256=XdYgaIxcVIW-YFViCkxj5l9OaVNepyIrCtm5Iqg2le8,3989
|
|
186
186
|
phoenix/server/api/types/EventMetadata.py,sha256=-J0tYF9eZTHwCjwxQHY7Gckr2_MNW5OoWT1mydweZNM,635
|
|
@@ -199,13 +199,13 @@ phoenix/server/api/types/MimeType.py,sha256=Zpi6zCalkSFgsvhzvOs-O1gYA04usAi9H__Q
|
|
|
199
199
|
phoenix/server/api/types/Model.py,sha256=BRIzH5xSGiDrAUYvhwDpwxT6--ddS3Xr3vCvP8_vzdo,8051
|
|
200
200
|
phoenix/server/api/types/NumericRange.py,sha256=afEjgF97Go_OvmjMggbPBt-zGM8IONewAyEiKEHRds0,192
|
|
201
201
|
phoenix/server/api/types/PerformanceMetric.py,sha256=W92B7OghEOgzFvmY0LCqpgavHaQggTGshdgfD0yqHX4,350
|
|
202
|
-
phoenix/server/api/types/Project.py,sha256=
|
|
202
|
+
phoenix/server/api/types/Project.py,sha256=CZ5Hl9fNeHiW8MfSbzXGBYP3A7jw0GubWqtHmzW-bUM,13299
|
|
203
203
|
phoenix/server/api/types/PromptResponse.py,sha256=Q8HKtpp8GpUOcxPCzZpkkokidDd6u0aZOv_SuPZZd5Q,630
|
|
204
204
|
phoenix/server/api/types/Retrieval.py,sha256=OhMK2ncjoyp5h1yjKhjlKpoTbQrMHuxmgSFw-AO1rWw,285
|
|
205
205
|
phoenix/server/api/types/ScalarDriftMetricEnum.py,sha256=IUAcRPpgL41WdoIgK6cNk2Te38SspXGyEs-S1fY23_A,232
|
|
206
206
|
phoenix/server/api/types/Segments.py,sha256=m2yoegrxA1Tn7ZAy1rMjjD1isc752MaAXMoffkBlvrM,2921
|
|
207
207
|
phoenix/server/api/types/SortDir.py,sha256=OUpXhlCzCxPoXSDkJJygEs9Rw9pMymfaZUG5zPTrw4Y,152
|
|
208
|
-
phoenix/server/api/types/Span.py,sha256=
|
|
208
|
+
phoenix/server/api/types/Span.py,sha256=ypzCF70a22QH7e7N8UQbO3FPtsPnAUxqqnq7UlcdGV4,14373
|
|
209
209
|
phoenix/server/api/types/SpanAnnotation.py,sha256=6b5G-b_OoRvDL2ayWk7MkbqarLK-F-pQMx21CpUuNGY,1168
|
|
210
210
|
phoenix/server/api/types/TimeSeries.py,sha256=wjzuxHFqCey0O7Ys25qiXyuqXK8an-osyNWUE8A_8G4,5227
|
|
211
211
|
phoenix/server/api/types/Trace.py,sha256=-nh3A-S_BlQK1VSSOTWqM85l-WwJsRHifxeDi0sFWZE,3246
|
|
@@ -227,10 +227,10 @@ phoenix/server/static/apple-touch-icon-76x76.png,sha256=CT_xT12I0u2i0WU8JzBZBuOQ
|
|
|
227
227
|
phoenix/server/static/apple-touch-icon.png,sha256=fOfpjqGpWYbJ0eAurKsyoZP1EAs6ZVooBJ_SGk2ZkDs,3801
|
|
228
228
|
phoenix/server/static/favicon.ico,sha256=bY0vvCKRftemZfPShwZtE93DiiQdaYaozkPGwNFr6H8,34494
|
|
229
229
|
phoenix/server/static/modernizr.js,sha256=mvK-XtkNqjOral-QvzoqsyOMECXIMu5BQwSVN_wcU9c,2564
|
|
230
|
-
phoenix/server/static/.vite/manifest.json,sha256=
|
|
231
|
-
phoenix/server/static/assets/components-
|
|
232
|
-
phoenix/server/static/assets/index-
|
|
233
|
-
phoenix/server/static/assets/pages
|
|
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
234
|
phoenix/server/static/assets/vendor-BMWfu6zp.js,sha256=AAVTM5SjGUI_CmAWFUFmhpp5VDhvCD-MrEoh-pXXADY,1355423
|
|
235
235
|
phoenix/server/static/assets/vendor-DxkFTwjz.css,sha256=nZrkr0u6NNElFGvpWHk9GTHeGoibCXCli1bE7mXZGZg,1816
|
|
236
236
|
phoenix/server/static/assets/vendor-arizeai-Sj74jm5V.js,sha256=9lD4YeMt5WtyfrqIApcH9WFQxyJJUtth0syWabkzX-I,304008
|
|
@@ -281,8 +281,8 @@ phoenix/utilities/logging.py,sha256=lDXd6EGaamBNcQxL4vP1au9-i_SXe0OraUDiJOcszSw,
|
|
|
281
281
|
phoenix/utilities/project.py,sha256=8IJuMM4yUMoooPi37sictGj8Etu9rGmq6RFtc9848cQ,436
|
|
282
282
|
phoenix/utilities/re.py,sha256=PDve_OLjRTM8yQQJHC8-n3HdIONi7aNils3ZKRZ5uBM,2045
|
|
283
283
|
phoenix/utilities/span_store.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
284
|
-
arize_phoenix-4.
|
|
285
|
-
arize_phoenix-4.
|
|
286
|
-
arize_phoenix-4.
|
|
287
|
-
arize_phoenix-4.
|
|
288
|
-
arize_phoenix-4.
|
|
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,,
|
phoenix/config.py
CHANGED
|
@@ -2,7 +2,7 @@ import os
|
|
|
2
2
|
import tempfile
|
|
3
3
|
from logging import getLogger
|
|
4
4
|
from pathlib import Path
|
|
5
|
-
from typing import Dict, List, Optional
|
|
5
|
+
from typing import Dict, List, Optional, Tuple
|
|
6
6
|
|
|
7
7
|
from .utilities.re import parse_env_headers
|
|
8
8
|
|
|
@@ -60,6 +60,11 @@ ENV_PHOENIX_SERVER_INSTRUMENTATION_OTLP_TRACE_COLLECTOR_GRPC_ENDPOINT = (
|
|
|
60
60
|
"PHOENIX_SERVER_INSTRUMENTATION_OTLP_TRACE_COLLECTOR_GRPC_ENDPOINT"
|
|
61
61
|
)
|
|
62
62
|
|
|
63
|
+
# Auth is under active development. Phoenix users are strongly advised not to
|
|
64
|
+
# set these environment variables until the feature is officially released.
|
|
65
|
+
ENV_DANGEROUSLY_SET_PHOENIX_ENABLE_AUTH = "DANGEROUSLY_SET_PHOENIX_ENABLE_AUTH"
|
|
66
|
+
ENV_DANGEROUSLY_SET_PHOENIX_SECRET = "DANGEROUSLY_SET_PHOENIX_SECRET"
|
|
67
|
+
|
|
63
68
|
|
|
64
69
|
def server_instrumentation_is_enabled() -> bool:
|
|
65
70
|
return bool(
|
|
@@ -100,6 +105,57 @@ def get_working_dir() -> Path:
|
|
|
100
105
|
return Path.home().resolve() / ".phoenix"
|
|
101
106
|
|
|
102
107
|
|
|
108
|
+
def get_boolean_env_var(env_var: str) -> Optional[bool]:
|
|
109
|
+
"""
|
|
110
|
+
Parses a boolean environment variable, returning None if the variable is not set.
|
|
111
|
+
"""
|
|
112
|
+
if (value := os.environ.get(env_var)) is None:
|
|
113
|
+
return None
|
|
114
|
+
assert (lower := value.lower()) in (
|
|
115
|
+
"true",
|
|
116
|
+
"false",
|
|
117
|
+
), f"{env_var} must be set to TRUE or FALSE (case-insensitive)"
|
|
118
|
+
return lower == "true"
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def get_env_enable_auth() -> bool:
|
|
122
|
+
"""
|
|
123
|
+
Gets the value of the DANGEROUSLY_SET_PHOENIX_ENABLE_AUTH environment variable.
|
|
124
|
+
"""
|
|
125
|
+
return get_boolean_env_var(ENV_DANGEROUSLY_SET_PHOENIX_ENABLE_AUTH) is True
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def get_env_phoenix_secret() -> Optional[str]:
|
|
129
|
+
"""
|
|
130
|
+
Gets the value of the DANGEROUSLY_SET_PHOENIX_SECRET environment variable
|
|
131
|
+
and performs validation.
|
|
132
|
+
"""
|
|
133
|
+
phoenix_secret = os.environ.get(ENV_DANGEROUSLY_SET_PHOENIX_SECRET)
|
|
134
|
+
if phoenix_secret is None:
|
|
135
|
+
return None
|
|
136
|
+
# todo: add validation for the phoenix secret
|
|
137
|
+
return phoenix_secret
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def get_auth_settings() -> Tuple[bool, Optional[str]]:
|
|
141
|
+
"""
|
|
142
|
+
Gets auth settings and performs validation.
|
|
143
|
+
"""
|
|
144
|
+
enable_auth = get_env_enable_auth()
|
|
145
|
+
phoenix_secret = get_env_phoenix_secret()
|
|
146
|
+
if enable_auth:
|
|
147
|
+
assert phoenix_secret, (
|
|
148
|
+
"DANGEROUSLY_SET_PHOENIX_SECRET must be set "
|
|
149
|
+
"when auth is enabled with DANGEROUSLY_SET_PHOENIX_ENABLE_AUTH"
|
|
150
|
+
)
|
|
151
|
+
else:
|
|
152
|
+
assert not phoenix_secret, (
|
|
153
|
+
"DANGEROUSLY_SET_PHOENIX_SECRET cannot be set "
|
|
154
|
+
"unless auth is enabled with DANGEROUSLY_SET_PHOENIX_ENABLE_AUTH"
|
|
155
|
+
)
|
|
156
|
+
return enable_auth, phoenix_secret
|
|
157
|
+
|
|
158
|
+
|
|
103
159
|
PHOENIX_DIR = Path(__file__).resolve().parent
|
|
104
160
|
# Server config
|
|
105
161
|
SERVER_DIR = PHOENIX_DIR / "server"
|
|
@@ -123,6 +179,8 @@ EXPORT_DIR = ROOT_DIR / "exports"
|
|
|
123
179
|
INFERENCES_DIR = ROOT_DIR / "inferences"
|
|
124
180
|
TRACE_DATASETS_DIR = ROOT_DIR / "trace_datasets"
|
|
125
181
|
|
|
182
|
+
ENABLE_AUTH, PHOENIX_SECRET = get_auth_settings()
|
|
183
|
+
|
|
126
184
|
|
|
127
185
|
def ensure_working_dir() -> None:
|
|
128
186
|
"""
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
"""users and tokens
|
|
2
|
+
|
|
3
|
+
Revision ID: cd164e83824f
|
|
4
|
+
Revises: 10460e46d750
|
|
5
|
+
Create Date: 2024-08-01 18:36:52.157604
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from datetime import datetime, timezone
|
|
10
|
+
from typing import Any, Dict, List, Optional, Sequence, TypedDict, Union
|
|
11
|
+
|
|
12
|
+
import sqlalchemy as sa
|
|
13
|
+
from alembic import op
|
|
14
|
+
from phoenix.datetime_utils import normalize_datetime
|
|
15
|
+
from sqlalchemy import (
|
|
16
|
+
JSON,
|
|
17
|
+
TIMESTAMP,
|
|
18
|
+
CheckConstraint,
|
|
19
|
+
Dialect,
|
|
20
|
+
ForeignKey,
|
|
21
|
+
MetaData,
|
|
22
|
+
TypeDecorator,
|
|
23
|
+
func,
|
|
24
|
+
insert,
|
|
25
|
+
)
|
|
26
|
+
from sqlalchemy.dialects import postgresql
|
|
27
|
+
from sqlalchemy.ext.asyncio.engine import AsyncConnection
|
|
28
|
+
from sqlalchemy.ext.compiler import compiles
|
|
29
|
+
from sqlalchemy.orm import (
|
|
30
|
+
DeclarativeBase,
|
|
31
|
+
Mapped,
|
|
32
|
+
mapped_column,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class JSONB(JSON):
|
|
37
|
+
# See https://docs.sqlalchemy.org/en/20/core/custom_types.html
|
|
38
|
+
__visit_name__ = "JSONB"
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@compiles(JSONB, "sqlite") # type: ignore
|
|
42
|
+
def _(*args: Any, **kwargs: Any) -> str:
|
|
43
|
+
# See https://docs.sqlalchemy.org/en/20/core/custom_types.html
|
|
44
|
+
return "JSONB"
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
JSON_ = (
|
|
48
|
+
JSON()
|
|
49
|
+
.with_variant(
|
|
50
|
+
postgresql.JSONB(), # type: ignore
|
|
51
|
+
"postgresql",
|
|
52
|
+
)
|
|
53
|
+
.with_variant(
|
|
54
|
+
JSONB(),
|
|
55
|
+
"sqlite",
|
|
56
|
+
)
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class JsonDict(TypeDecorator[Dict[str, Any]]):
|
|
61
|
+
# See # See https://docs.sqlalchemy.org/en/20/core/custom_types.html
|
|
62
|
+
cache_ok = True
|
|
63
|
+
impl = JSON_
|
|
64
|
+
|
|
65
|
+
def process_bind_param(self, value: Optional[Dict[str, Any]], _: Dialect) -> Dict[str, Any]:
|
|
66
|
+
return value if isinstance(value, dict) else {}
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class JsonList(TypeDecorator[List[Any]]):
|
|
70
|
+
# See # See https://docs.sqlalchemy.org/en/20/core/custom_types.html
|
|
71
|
+
cache_ok = True
|
|
72
|
+
impl = JSON_
|
|
73
|
+
|
|
74
|
+
def process_bind_param(self, value: Optional[List[Any]], _: Dialect) -> List[Any]:
|
|
75
|
+
return value if isinstance(value, list) else []
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class UtcTimeStamp(TypeDecorator[datetime]):
|
|
79
|
+
# See # See https://docs.sqlalchemy.org/en/20/core/custom_types.html
|
|
80
|
+
cache_ok = True
|
|
81
|
+
impl = TIMESTAMP(timezone=True)
|
|
82
|
+
|
|
83
|
+
def process_bind_param(self, value: Optional[datetime], _: Dialect) -> Optional[datetime]:
|
|
84
|
+
return normalize_datetime(value)
|
|
85
|
+
|
|
86
|
+
def process_result_value(self, value: Optional[Any], _: Dialect) -> Optional[datetime]:
|
|
87
|
+
return normalize_datetime(value, timezone.utc)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class ExperimentRunOutput(TypedDict, total=False):
|
|
91
|
+
task_output: Any
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class Base(DeclarativeBase):
|
|
95
|
+
# Enforce best practices for naming constraints
|
|
96
|
+
# https://alembic.sqlalchemy.org/en/latest/naming.html#integration-of-naming-conventions-into-operations-autogenerate
|
|
97
|
+
metadata = MetaData(
|
|
98
|
+
naming_convention={
|
|
99
|
+
"ix": "ix_%(table_name)s_%(column_0_N_name)s",
|
|
100
|
+
"uq": "uq_%(table_name)s_%(column_0_N_name)s",
|
|
101
|
+
"ck": "ck_%(table_name)s_`%(constraint_name)s`",
|
|
102
|
+
"fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
|
|
103
|
+
"pk": "pk_%(table_name)s",
|
|
104
|
+
}
|
|
105
|
+
)
|
|
106
|
+
type_annotation_map = {
|
|
107
|
+
Dict[str, Any]: JsonDict,
|
|
108
|
+
List[Dict[str, Any]]: JsonList,
|
|
109
|
+
ExperimentRunOutput: JsonDict,
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
class UserRole(Base):
|
|
114
|
+
__tablename__ = "user_roles"
|
|
115
|
+
id: Mapped[int] = mapped_column(primary_key=True)
|
|
116
|
+
role: Mapped[str] = mapped_column(unique=True)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
class User(Base):
|
|
120
|
+
__tablename__ = "users"
|
|
121
|
+
id: Mapped[int] = mapped_column(primary_key=True)
|
|
122
|
+
user_role_id: Mapped[int] = mapped_column(
|
|
123
|
+
ForeignKey("user_roles.id"),
|
|
124
|
+
index=True,
|
|
125
|
+
)
|
|
126
|
+
username: Mapped[Optional[str]] = mapped_column(nullable=True, unique=True, index=True)
|
|
127
|
+
email: Mapped[str] = mapped_column(nullable=False, unique=True, index=True)
|
|
128
|
+
auth_method: Mapped[str] = mapped_column(
|
|
129
|
+
CheckConstraint("auth_method IN ('LOCAL')", name="valid_auth_method")
|
|
130
|
+
)
|
|
131
|
+
password_hash: Mapped[Optional[str]]
|
|
132
|
+
reset_password: Mapped[bool]
|
|
133
|
+
created_at: Mapped[datetime] = mapped_column(UtcTimeStamp, server_default=func.now())
|
|
134
|
+
updated_at: Mapped[datetime] = mapped_column(
|
|
135
|
+
UtcTimeStamp, server_default=func.now(), onupdate=func.now()
|
|
136
|
+
)
|
|
137
|
+
deleted_at: Mapped[Optional[datetime]] = mapped_column(UtcTimeStamp)
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
# revision identifiers, used by Alembic.
|
|
141
|
+
revision: str = "cd164e83824f"
|
|
142
|
+
down_revision: Union[str, None] = "3be8647b87d8"
|
|
143
|
+
branch_labels: Union[str, Sequence[str], None] = None
|
|
144
|
+
depends_on: Union[str, Sequence[str], None] = None
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
async def insert_roles_and_users(connection: AsyncConnection) -> None:
|
|
148
|
+
"""
|
|
149
|
+
Populates the `user_roles` table and adds a system user and initial admin
|
|
150
|
+
user to the `users` table.
|
|
151
|
+
"""
|
|
152
|
+
await connection.execute(
|
|
153
|
+
insert(UserRole).values([{"role": "SYSTEM"}, {"role": "ADMIN"}, {"role": "GENERAL"}])
|
|
154
|
+
)
|
|
155
|
+
system_user_role_id = sa.select(UserRole.id).where(UserRole.role == "SYSTEM").scalar_subquery()
|
|
156
|
+
admin_user_role_id = sa.select(UserRole.id).where(UserRole.role == "ADMIN").scalar_subquery()
|
|
157
|
+
await connection.execute(
|
|
158
|
+
insert(User).values(
|
|
159
|
+
[
|
|
160
|
+
{
|
|
161
|
+
"user_role_id": system_user_role_id,
|
|
162
|
+
"username": None,
|
|
163
|
+
"email": "system@localhost",
|
|
164
|
+
"auth_method": "LOCAL",
|
|
165
|
+
"password_hash": None,
|
|
166
|
+
"reset_password": False,
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
"user_role_id": admin_user_role_id,
|
|
170
|
+
"username": "admin",
|
|
171
|
+
"email": "admin@localhost",
|
|
172
|
+
"auth_method": "LOCAL",
|
|
173
|
+
"password_hash": None, # todo: replace this with the hashed PHOENIX_SECRET
|
|
174
|
+
"reset_password": True,
|
|
175
|
+
},
|
|
176
|
+
]
|
|
177
|
+
)
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def upgrade() -> None:
|
|
182
|
+
op.create_table(
|
|
183
|
+
"user_roles",
|
|
184
|
+
sa.Column("id", sa.Integer, primary_key=True),
|
|
185
|
+
sa.Column(
|
|
186
|
+
"role",
|
|
187
|
+
sa.String,
|
|
188
|
+
nullable=False,
|
|
189
|
+
unique=True,
|
|
190
|
+
),
|
|
191
|
+
)
|
|
192
|
+
op.create_table(
|
|
193
|
+
"users",
|
|
194
|
+
sa.Column("id", sa.Integer, primary_key=True),
|
|
195
|
+
sa.Column(
|
|
196
|
+
"user_role_id",
|
|
197
|
+
sa.Integer,
|
|
198
|
+
sa.ForeignKey("user_roles.id"),
|
|
199
|
+
nullable=False,
|
|
200
|
+
index=True,
|
|
201
|
+
),
|
|
202
|
+
sa.Column("username", sa.String, nullable=True, unique=True, index=True),
|
|
203
|
+
sa.Column("email", sa.String, nullable=False, unique=True, index=True),
|
|
204
|
+
sa.Column(
|
|
205
|
+
"auth_method",
|
|
206
|
+
sa.String,
|
|
207
|
+
sa.CheckConstraint("auth_method IN ('LOCAL')", "valid_auth_method"),
|
|
208
|
+
nullable=False,
|
|
209
|
+
),
|
|
210
|
+
sa.Column("password_hash", sa.String, nullable=True),
|
|
211
|
+
sa.Column("reset_password", sa.Boolean, nullable=False),
|
|
212
|
+
sa.Column(
|
|
213
|
+
"created_at",
|
|
214
|
+
sa.TIMESTAMP(timezone=True),
|
|
215
|
+
nullable=False,
|
|
216
|
+
server_default=sa.func.now(),
|
|
217
|
+
),
|
|
218
|
+
sa.Column(
|
|
219
|
+
"updated_at",
|
|
220
|
+
sa.TIMESTAMP(timezone=True),
|
|
221
|
+
nullable=False,
|
|
222
|
+
server_default=sa.func.now(),
|
|
223
|
+
onupdate=sa.func.now(),
|
|
224
|
+
),
|
|
225
|
+
sa.Column(
|
|
226
|
+
"deleted_at",
|
|
227
|
+
sa.TIMESTAMP(timezone=True),
|
|
228
|
+
nullable=True,
|
|
229
|
+
),
|
|
230
|
+
)
|
|
231
|
+
op.create_table(
|
|
232
|
+
"api_keys",
|
|
233
|
+
sa.Column("id", sa.Integer, primary_key=True),
|
|
234
|
+
sa.Column(
|
|
235
|
+
"user_id",
|
|
236
|
+
sa.Integer,
|
|
237
|
+
sa.ForeignKey("users.id"),
|
|
238
|
+
nullable=False,
|
|
239
|
+
index=True,
|
|
240
|
+
),
|
|
241
|
+
sa.Column("name", sa.String, nullable=False),
|
|
242
|
+
sa.Column("description", sa.String, nullable=True),
|
|
243
|
+
sa.Column(
|
|
244
|
+
"created_at",
|
|
245
|
+
sa.TIMESTAMP(timezone=True),
|
|
246
|
+
nullable=False,
|
|
247
|
+
server_default=sa.func.now(),
|
|
248
|
+
),
|
|
249
|
+
sa.Column(
|
|
250
|
+
"expires_at",
|
|
251
|
+
sa.TIMESTAMP(timezone=True),
|
|
252
|
+
nullable=True,
|
|
253
|
+
),
|
|
254
|
+
)
|
|
255
|
+
op.create_table(
|
|
256
|
+
"audit_api_keys",
|
|
257
|
+
sa.Column("id", sa.Integer, primary_key=True),
|
|
258
|
+
sa.Column(
|
|
259
|
+
"api_key_id",
|
|
260
|
+
sa.Integer,
|
|
261
|
+
sa.ForeignKey("api_keys.id"),
|
|
262
|
+
nullable=False,
|
|
263
|
+
index=True,
|
|
264
|
+
),
|
|
265
|
+
sa.Column(
|
|
266
|
+
"user_id",
|
|
267
|
+
sa.Integer,
|
|
268
|
+
sa.ForeignKey("users.id"),
|
|
269
|
+
nullable=False,
|
|
270
|
+
index=True,
|
|
271
|
+
),
|
|
272
|
+
sa.Column(
|
|
273
|
+
"action",
|
|
274
|
+
sa.String,
|
|
275
|
+
sa.CheckConstraint("action IN ('CREATE', 'DELETE')", "valid_action"),
|
|
276
|
+
nullable=False,
|
|
277
|
+
),
|
|
278
|
+
sa.Column(
|
|
279
|
+
"created_at",
|
|
280
|
+
sa.TIMESTAMP(timezone=True),
|
|
281
|
+
nullable=False,
|
|
282
|
+
server_default=sa.func.now(),
|
|
283
|
+
),
|
|
284
|
+
)
|
|
285
|
+
op.run_async(insert_roles_and_users)
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
def downgrade() -> None:
|
|
289
|
+
op.drop_table("audit_api_keys")
|
|
290
|
+
op.drop_table("api_keys")
|
|
291
|
+
op.drop_table("users")
|
|
292
|
+
op.drop_table("user_roles")
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
cd164e83824f_users_and_tokens.py
|
phoenix/db/models.py
CHANGED
|
@@ -34,6 +34,7 @@ from sqlalchemy.orm import (
|
|
|
34
34
|
)
|
|
35
35
|
from sqlalchemy.sql import expression
|
|
36
36
|
|
|
37
|
+
from phoenix.config import ENABLE_AUTH
|
|
37
38
|
from phoenix.datetime_utils import normalize_datetime
|
|
38
39
|
|
|
39
40
|
|
|
@@ -616,3 +617,63 @@ class ExperimentRunAnnotation(Base):
|
|
|
616
617
|
"name",
|
|
617
618
|
),
|
|
618
619
|
)
|
|
620
|
+
|
|
621
|
+
|
|
622
|
+
# todo: unnest the following models when auth is released (https://github.com/Arize-ai/phoenix/issues/4183)
|
|
623
|
+
if ENABLE_AUTH:
|
|
624
|
+
|
|
625
|
+
class UserRole(Base):
|
|
626
|
+
__tablename__ = "user_roles"
|
|
627
|
+
id: Mapped[int] = mapped_column(primary_key=True)
|
|
628
|
+
role: Mapped[str] = mapped_column(unique=True)
|
|
629
|
+
|
|
630
|
+
class User(Base):
|
|
631
|
+
__tablename__ = "users"
|
|
632
|
+
id: Mapped[int] = mapped_column(primary_key=True)
|
|
633
|
+
user_role_id: Mapped[int] = mapped_column(
|
|
634
|
+
ForeignKey("user_roles.id"),
|
|
635
|
+
index=True,
|
|
636
|
+
)
|
|
637
|
+
username: Mapped[Optional[str]] = mapped_column(nullable=True, unique=True, index=True)
|
|
638
|
+
email: Mapped[str] = mapped_column(nullable=False, unique=True, index=True)
|
|
639
|
+
auth_method: Mapped[str] = mapped_column(
|
|
640
|
+
CheckConstraint("auth_method IN ('LOCAL')", name="valid_auth_method")
|
|
641
|
+
)
|
|
642
|
+
password_hash: Mapped[Optional[str]]
|
|
643
|
+
reset_password: Mapped[bool]
|
|
644
|
+
created_at: Mapped[datetime] = mapped_column(UtcTimeStamp, server_default=func.now())
|
|
645
|
+
updated_at: Mapped[datetime] = mapped_column(
|
|
646
|
+
UtcTimeStamp, server_default=func.now(), onupdate=func.now()
|
|
647
|
+
)
|
|
648
|
+
deleted_at: Mapped[Optional[datetime]] = mapped_column(UtcTimeStamp)
|
|
649
|
+
|
|
650
|
+
class APIKey(Base):
|
|
651
|
+
__tablename__ = "api_keys"
|
|
652
|
+
id: Mapped[int] = mapped_column(primary_key=True)
|
|
653
|
+
user_id: Mapped[int] = mapped_column(
|
|
654
|
+
ForeignKey("users.id"),
|
|
655
|
+
index=True,
|
|
656
|
+
)
|
|
657
|
+
name: Mapped[str]
|
|
658
|
+
description: Mapped[Optional[str]]
|
|
659
|
+
created_at: Mapped[datetime] = mapped_column(UtcTimeStamp, server_default=func.now())
|
|
660
|
+
expires_at: Mapped[Optional[datetime]] = mapped_column(UtcTimeStamp)
|
|
661
|
+
|
|
662
|
+
# todo: standardize audit table format (https://github.com/Arize-ai/phoenix/issues/4185)
|
|
663
|
+
class AuditAPIKey(Base):
|
|
664
|
+
__tablename__ = "audit_api_keys"
|
|
665
|
+
id: Mapped[int] = mapped_column(primary_key=True)
|
|
666
|
+
api_key_id: Mapped[int] = mapped_column(
|
|
667
|
+
ForeignKey("api_keys.id"),
|
|
668
|
+
nullable=False,
|
|
669
|
+
index=True,
|
|
670
|
+
)
|
|
671
|
+
user_id: Mapped[int] = mapped_column(
|
|
672
|
+
ForeignKey("users.id"),
|
|
673
|
+
nullable=False,
|
|
674
|
+
index=True,
|
|
675
|
+
)
|
|
676
|
+
action: Mapped[str] = mapped_column(
|
|
677
|
+
CheckConstraint("action IN ('CREATE', 'DELETE')", name="valid_action")
|
|
678
|
+
)
|
|
679
|
+
created_at: Mapped[datetime] = mapped_column(UtcTimeStamp, server_default=func.now())
|
phoenix/experiments/functions.py
CHANGED
|
@@ -447,14 +447,14 @@ def evaluate_experiment(
|
|
|
447
447
|
)
|
|
448
448
|
if not dataset.examples:
|
|
449
449
|
raise ValueError(f"Dataset has no examples: {dataset_id=}, {dataset_version_id=}")
|
|
450
|
-
experiment_runs =
|
|
451
|
-
ExperimentRun.from_dict(exp_run)
|
|
450
|
+
experiment_runs = {
|
|
451
|
+
exp_run["id"]: ExperimentRun.from_dict(exp_run)
|
|
452
452
|
for exp_run in sync_client.get(f"/v1/experiments/{experiment.id}/runs").json()["data"]
|
|
453
|
-
|
|
453
|
+
}
|
|
454
454
|
if not experiment_runs:
|
|
455
455
|
raise ValueError("Experiment has not been run")
|
|
456
456
|
params = ExperimentParameters(n_examples=len(dataset.examples))
|
|
457
|
-
task_summary = TaskSummary.from_task_runs(params, experiment_runs)
|
|
457
|
+
task_summary = TaskSummary.from_task_runs(params, experiment_runs.values())
|
|
458
458
|
ran_experiment = object.__new__(RanExperiment)
|
|
459
459
|
ran_experiment.__init__( # type: ignore[misc]
|
|
460
460
|
dataset=dataset,
|
phoenix/experiments/types.py
CHANGED
|
@@ -167,7 +167,7 @@ class Dataset:
|
|
|
167
167
|
def from_dict(cls, obj: Mapping[str, Any]) -> Dataset:
|
|
168
168
|
examples = tuple(map(Example.from_dict, obj.get("examples") or ()))
|
|
169
169
|
return cls(
|
|
170
|
-
id=obj["
|
|
170
|
+
id=obj["dataset_id"],
|
|
171
171
|
version_id=obj["version_id"],
|
|
172
172
|
examples={ex.id: ex for ex in examples},
|
|
173
173
|
)
|
|
@@ -225,7 +225,7 @@ class ExperimentRun:
|
|
|
225
225
|
)
|
|
226
226
|
|
|
227
227
|
def __post_init__(self) -> None:
|
|
228
|
-
if
|
|
228
|
+
if self.output is None and self.error is None:
|
|
229
229
|
raise ValueError("Must specify exactly one of experiment_run_output or error")
|
|
230
230
|
|
|
231
231
|
|
|
@@ -284,7 +284,7 @@ class ExperimentEvaluationRun:
|
|
|
284
284
|
)
|
|
285
285
|
|
|
286
286
|
def __post_init__(self) -> None:
|
|
287
|
-
if
|
|
287
|
+
if self.result is None and self.error is None:
|
|
288
288
|
raise ValueError("Must specify either result or error")
|
|
289
289
|
|
|
290
290
|
|