arize-phoenix 4.9.0__py3-none-any.whl → 4.10.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 (28) hide show
  1. {arize_phoenix-4.9.0.dist-info → arize_phoenix-4.10.0.dist-info}/METADATA +1 -1
  2. {arize_phoenix-4.9.0.dist-info → arize_phoenix-4.10.0.dist-info}/RECORD +28 -20
  3. phoenix/db/insertion/evaluation.py +7 -25
  4. phoenix/db/insertion/helpers.py +54 -13
  5. phoenix/db/insertion/span.py +12 -16
  6. phoenix/pointcloud/umap_parameters.py +52 -52
  7. phoenix/server/api/input_types/CreateSpanAnnotationsInput.py +16 -0
  8. phoenix/server/api/input_types/CreateTraceAnnotationsInput.py +16 -0
  9. phoenix/server/api/input_types/DeleteAnnotationsInput.py +9 -0
  10. phoenix/server/api/input_types/PatchAnnotationsInput.py +17 -0
  11. phoenix/server/api/mutations/__init__.py +8 -1
  12. phoenix/server/api/mutations/span_annotations_mutations.py +108 -0
  13. phoenix/server/api/mutations/trace_annotations_mutations.py +108 -0
  14. phoenix/server/api/queries.py +1 -0
  15. phoenix/server/api/routers/v1/__init__.py +2 -0
  16. phoenix/server/api/routers/v1/experiment_evaluations.py +3 -10
  17. phoenix/server/api/routers/v1/experiments.py +4 -5
  18. phoenix/server/api/routers/v1/spans.py +147 -2
  19. phoenix/server/api/routers/v1/traces.py +150 -1
  20. phoenix/server/api/types/AnnotatorKind.py +7 -1
  21. phoenix/server/api/types/ExperimentRunAnnotation.py +3 -3
  22. phoenix/server/api/types/SpanAnnotation.py +45 -0
  23. phoenix/server/api/types/TraceAnnotation.py +45 -0
  24. phoenix/server/static/index.js +531 -523
  25. phoenix/version.py +1 -1
  26. {arize_phoenix-4.9.0.dist-info → arize_phoenix-4.10.0.dist-info}/WHEEL +0 -0
  27. {arize_phoenix-4.9.0.dist-info → arize_phoenix-4.10.0.dist-info}/licenses/IP_NOTICE +0 -0
  28. {arize_phoenix-4.9.0.dist-info → arize_phoenix-4.10.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.9.0
3
+ Version: 4.10.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
@@ -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=E0Y9rD8RWyBe6e34I0525HrRS_vGhPvve493oPOdtXw,22
8
+ phoenix/version.py,sha256=eiNxh0tSyv9nut-H3lBLi2t5qqpCFRgVfedLjanNppI,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
@@ -21,9 +21,9 @@ phoenix/db/migrate.py,sha256=MuhtNWnR24riROvarvKfbRb4_D5xuQi6P760vBUKl1E,2270
21
21
  phoenix/db/models.py,sha256=7DBWbxY3cx3ve2P1I0kkDKXzlt04zEFJuRPJWsVpH-I,20422
22
22
  phoenix/db/insertion/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
23
23
  phoenix/db/insertion/dataset.py,sha256=_vxy5e6W5jEuvO2fMKbbNCn9JvHkwI4LRKk_10eKFVg,7171
24
- phoenix/db/insertion/evaluation.py,sha256=HoUncZN9ZlIr1QO0uA37SbWhrjmwQVYVJlgFX2VefY8,7211
25
- phoenix/db/insertion/helpers.py,sha256=5AZQSyTGAthyaIl_l5jL4yva1IrTTBG9y2G7l1r2Yyk,1937
26
- phoenix/db/insertion/span.py,sha256=d85O3R_Cc3aVFDJSgLLX66qNCPNbKtDxug_dSKFDfew,5655
24
+ phoenix/db/insertion/evaluation.py,sha256=SoI85N3MYUSeNgjKa5WzFw14OfNjNTjExv-2m3sxaR8,6371
25
+ phoenix/db/insertion/helpers.py,sha256=v8ONIWZu_x1XNWKmz3gNu3839LqlZbFv4gyAYrLKMts,3068
26
+ phoenix/db/insertion/span.py,sha256=T9jOW3lyWte-JGD7wlP2ZqtO0-V57d8z6U_TldnuGuk,5527
27
27
  phoenix/db/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
28
  phoenix/db/migrations/env.py,sha256=QbzB5zrRs6XQQmrYeUpuzeilcMlM-MsbaAgHHYcIHTI,3626
29
29
  phoenix/db/migrations/script.py.mako,sha256=MEqL-2qATlST9TAOeYgscMn1uy6HUS9NFvDgl93dMj8,635
@@ -58,7 +58,7 @@ phoenix/pointcloud/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVG
58
58
  phoenix/pointcloud/clustering.py,sha256=IzcG67kJ2hPP7pcqVmKPSL_6gKRonKdOT3bCtbTOqnk,820
59
59
  phoenix/pointcloud/pointcloud.py,sha256=4zAIkKs2xOUbchpj4XDAV-iPMXrfAJ15TG6rlIYGrao,2145
60
60
  phoenix/pointcloud/projectors.py,sha256=zO_RrtDYSv2rqVOfIP2_9Cv11Dc8EmcZR94xhFcBYPU,1057
61
- phoenix/pointcloud/umap_parameters.py,sha256=lJsEOrbSuSiqI7g4Yt6xj7kgYxEqoep4ZHWLr6VWBqw,1760
61
+ phoenix/pointcloud/umap_parameters.py,sha256=3UQSjrysVOvq2V4KNpTMqNqNiK0BsTZnPBHWZ4fyJtQ,1708
62
62
  phoenix/server/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
63
63
  phoenix/server/app.py,sha256=Ld9NvW7sBT4aJn8CXAB_PIw4c5wlkxCcjT_hzjtn7dM,18478
64
64
  phoenix/server/grpc_server.py,sha256=faktLxEtWGlCB1bPR4QwwTsRoQloahKMx0hAWqRGI5s,3379
@@ -69,7 +69,7 @@ phoenix/server/thread_server.py,sha256=dP6cm6Cf08jNhDA1TRlVZpziu1YgtPDmaeIJMm725
69
69
  phoenix/server/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
70
70
  phoenix/server/api/context.py,sha256=4jcy203Gtx38399FP21iU3HmFsq-50EKFJlX4IW2Los,2878
71
71
  phoenix/server/api/interceptor.py,sha256=ykDnoC_apUd-llVli3m1CW18kNSIgjz2qZ6m5JmPDu8,1294
72
- phoenix/server/api/queries.py,sha256=wp5BlapuxDIoaQJm7mzG0dURfVxR32vXSJVC0JqG4_Y,19845
72
+ phoenix/server/api/queries.py,sha256=eq2xHaQF-x4k6AGSY6b6mU2pie9bj-AJML6P2Mr0_DM,19886
73
73
  phoenix/server/api/schema.py,sha256=BcxdqO5CSGqpKd-AAJHMjFlzaK9oJA8GJuxmMfcdjn4,434
74
74
  phoenix/server/api/utils.py,sha256=Y1lGu8J8r8BSBX9OzffgewI8QMziovbG-ePDvZrrwGI,949
75
75
  phoenix/server/api/dataloaders/__init__.py,sha256=qehXL37vGdw7v5PFs3kbZVIuhuzrVNVeZACDQjYpwyo,4847
@@ -104,43 +104,49 @@ phoenix/server/api/input_types/ClearProjectInput.py,sha256=cpPFRyQ3ffy2dLbCZgYpw
104
104
  phoenix/server/api/input_types/ClusterInput.py,sha256=EL4ftvZxQ8mVdruUPcdhMhByORmSmM8S-X6RPqU6GX0,179
105
105
  phoenix/server/api/input_types/Coordinates.py,sha256=meTwbIjwTfqx5DGD2DBlH9wQzdQVNM5a8x9dp1FfIgA,173
106
106
  phoenix/server/api/input_types/CreateDatasetInput.py,sha256=Q3MwouIx9jTQBRWDju75iMQXEGJCrL4aD4ESQp771nc,248
107
+ phoenix/server/api/input_types/CreateSpanAnnotationsInput.py,sha256=sTs6YdExpaZpTi6ql1BSpUbyT-ArnU5nz4kZaBs3i1w,399
108
+ phoenix/server/api/input_types/CreateTraceAnnotationsInput.py,sha256=wc93I3ZLtzJL237UDUz96w6UY1UwLX76sr0FMeyGD4c,401
107
109
  phoenix/server/api/input_types/DataQualityMetricInput.py,sha256=LazvmQCCM5m9SDZTpyxQXO1rYF4cmsc3lsR2S9S65X4,1292
108
110
  phoenix/server/api/input_types/DatasetExampleInput.py,sha256=9oJ6pCFxFd02IWJuK4YAUvz-jCgFGDUCDDb2--GAzCw,289
109
111
  phoenix/server/api/input_types/DatasetSort.py,sha256=KDKjx5L8WFNwx7O-g1pDzCMMwY-ErgDd1_HkkZBAvCY,333
110
112
  phoenix/server/api/input_types/DatasetVersionSort.py,sha256=w9HyP9rQKsZGiGc2f33ZNmiO9g7FN8r77T7GA85kb40,344
113
+ phoenix/server/api/input_types/DeleteAnnotationsInput.py,sha256=2p9gNrYJzDDYszEdZ2cb6TP_qai6HfOH7QhY0vaXoQQ,166
111
114
  phoenix/server/api/input_types/DeleteDatasetExamplesInput.py,sha256=Pfod1r5BJISRG9w_eu9jFeEhNu2XYfcvlhxQ5HWdHAw,350
112
115
  phoenix/server/api/input_types/DeleteDatasetInput.py,sha256=p7xjCyWnVCIXHnezmDiWhMq-DHcGv7ucp_O7s8fsiKE,127
113
116
  phoenix/server/api/input_types/DeleteExperimentsInput.py,sha256=yUbwMckIBvIL-R9t8K9c3qTWciAXt3Uv_Tio3K2e1uw,166
114
117
  phoenix/server/api/input_types/DimensionFilter.py,sha256=vcXgglSnZcB5pGh-6oEtRmGx95hISgFUR7BEPw01g7U,3143
115
118
  phoenix/server/api/input_types/DimensionInput.py,sha256=Vfx5FmiMKey4-EHDQsQRPzSAMRJMN5oVMLDUl4NKAa8,164
116
119
  phoenix/server/api/input_types/Granularity.py,sha256=6SVfZ5yTZYq1PI6vdpjfkBUc4YilLSkF-k6okuSNbbQ,2301
120
+ phoenix/server/api/input_types/PatchAnnotationsInput.py,sha256=NYlZtZG_ssgvG19FaZpqwUaJ2C1jv1hItU-ERX2_sI8,445
117
121
  phoenix/server/api/input_types/PatchDatasetExamplesInput.py,sha256=E86aBGXDBC83jiEGwV5rilnoeQf6eqCfZ0aAVeIt2VI,890
118
122
  phoenix/server/api/input_types/PatchDatasetInput.py,sha256=OURtTVY8Z_oFEDtKwT1LCMaOK5D4QYo5TVQ6mDrex-g,328
119
123
  phoenix/server/api/input_types/PerformanceMetricInput.py,sha256=fElsLTSEYYgGFGMYTEGcYid39tXUKFdV_JkdHavMcbA,591
120
124
  phoenix/server/api/input_types/SpanSort.py,sha256=BqV0DjI4m3RKFbzsHN47XNhJfFmErFIYg64c8EJAVMo,6312
121
125
  phoenix/server/api/input_types/TimeRange.py,sha256=yzx-gxj8mDeGLft1FzU_x1MVEgIG5Pt6-f8PUVDgipQ,522
122
126
  phoenix/server/api/input_types/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
123
- phoenix/server/api/mutations/__init__.py,sha256=Jcz-pM6SklhEGKcjA7AIB2WJXGhnxGsghrIq131kyDo,502
127
+ phoenix/server/api/mutations/__init__.py,sha256=UKUAhD5NY-ZI7XONnRRkaHoFuuU3idmE4fk6Sjgy18M,776
124
128
  phoenix/server/api/mutations/auth.py,sha256=vPRFoj7J6PV6QeODewG4K0PhoOebS5AfMRpbi_wuhyQ,311
125
129
  phoenix/server/api/mutations/dataset_mutations.py,sha256=CuKhxsYfvwVcdN_9EXhKxB6444BQfObzKzzyfAeg-n8,23199
126
130
  phoenix/server/api/mutations/experiment_mutations.py,sha256=vV2lbJ7ccXZqe-LY7nXx6QxWqhKQE4UNZAFcML-KQ8I,3011
127
131
  phoenix/server/api/mutations/export_events_mutations.py,sha256=t_wYBxaqvBJYRoHslh3Bmoxmwlzoy0u8SsBKWIKN5hE,4028
128
132
  phoenix/server/api/mutations/project_mutations.py,sha256=d_xtYkYfZ5flpVgEkGknKB8rsEux-zZraczzqAs4e8A,2255
133
+ phoenix/server/api/mutations/span_annotations_mutations.py,sha256=Pfaq4y-FGskPit4z_9GvsyWeBwK1g3CDi2UhGKxyjFE,4973
134
+ phoenix/server/api/mutations/trace_annotations_mutations.py,sha256=4xm-zg8PEjwjfVRsWzBD_iiOS94JI6UYtK3fV2dtA4M,5013
129
135
  phoenix/server/api/openapi/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
130
136
  phoenix/server/api/openapi/main.py,sha256=WY0pj3B7siQyyYqKyhqnzWC7P8MtEtiukOBUjGwLXfw,153
131
137
  phoenix/server/api/openapi/schema.py,sha256=uuSYe1Ecu72aXRgTNjyMu-9ZPE13DAHJPKtedS-MsSs,451
132
138
  phoenix/server/api/routers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
133
139
  phoenix/server/api/routers/utils.py,sha256=M41BoH-fl37izhRuN2aX7lWm7jOC20A_3uClv9TVUUY,583
134
- phoenix/server/api/routers/v1/__init__.py,sha256=Ir5fsO6gQXW58HGm7s2sMUq0vya7mfcWneLcLJy6_q8,2895
140
+ phoenix/server/api/routers/v1/__init__.py,sha256=D1EFRWG4PcsTubeF3A3ENlNatCRq26AA52FxW11BGjM,3048
135
141
  phoenix/server/api/routers/v1/dataset_examples.py,sha256=XfqOvDKF1oxb0pkeYfBycwwGt3LnSyyGdMLKC5VKoGQ,6690
136
142
  phoenix/server/api/routers/v1/datasets.py,sha256=r0WcNxF8SKVa3-4rrTIg4Andwr4NmRmW1ybpKuxR9qw,33639
137
143
  phoenix/server/api/routers/v1/evaluations.py,sha256=8g6P_e2BweV3RDU0esFmpkb0L5fCwonQPXiJ0y6HLwg,9126
138
- phoenix/server/api/routers/v1/experiment_evaluations.py,sha256=H_psVyuGUQImo0oxdEAKAMQ-oyVwkVIq5yaMHzHIiPc,5455
144
+ phoenix/server/api/routers/v1/experiment_evaluations.py,sha256=TE1GMSOLN_96uAaJpnRpIH2u9x6_ebtkECgZRHvqt-w,5098
139
145
  phoenix/server/api/routers/v1/experiment_runs.py,sha256=jy4SynmzdtQMoUzlowmG6wsVU14SsLAzfcW4JOhXjeQ,8154
140
- phoenix/server/api/routers/v1/experiments.py,sha256=cG-LyIGRdB1jVTL42Xi2__nsXibVe9Up7m3hFiTIYYY,11886
141
- phoenix/server/api/routers/v1/spans.py,sha256=PFeS3ayKj4cUle0CH-f-CpM1fRi-JicEG7BEtkANzAo,4074
142
- phoenix/server/api/routers/v1/traces.py,sha256=dYEf5pThenAQCgfQljHdrnwd4tC_tAXm6Kvk6GphPYs,2774
143
- phoenix/server/api/types/AnnotatorKind.py,sha256=UmYb2KG0JfxdX0mW1qrXrUoIgjMOncRJr1i8mJki1sE,141
146
+ phoenix/server/api/routers/v1/experiments.py,sha256=uVdmhyJgYI-UqOiRSJ-8OcVpL8a6Z02B5H2Rt_7yboY,11829
147
+ phoenix/server/api/routers/v1/spans.py,sha256=tryWFoJVFRLALzt6dfPmBBhKMS0s3hhlYdTathxVEU4,9638
148
+ phoenix/server/api/routers/v1/traces.py,sha256=PBIrpdJHVJ9gyiukCy1Ck1w0xts0VEHtRKaF7Noa248,8434
149
+ phoenix/server/api/types/AnnotatorKind.py,sha256=rPgGdbN1Gvc109sGQ_ZH-gfJbp93V9wlarzTEJNtUwI,236
144
150
  phoenix/server/api/types/Cluster.py,sha256=ac4YfT1OH3xLVmex7EUmB6b9IpULnhLTt554LR0jglE,5689
145
151
  phoenix/server/api/types/CreateDatasetPayload.py,sha256=R-6zCmuD0f76RU9Giu78xwTHlASQs6Aq8yzvX1Kxc3g,140
146
152
  phoenix/server/api/types/DataQualityMetric.py,sha256=zRKsNvHBu-NdcsunuLhqFpZhi6ks-HMqA1PJD27jTak,590
@@ -167,7 +173,7 @@ phoenix/server/api/types/Experiment.py,sha256=ELYdYFKwgBllxx3cZ_X0XicHjLtshZl0bF
167
173
  phoenix/server/api/types/ExperimentAnnotationSummary.py,sha256=Uk3JtxIrsMoZT5tqc4nJdUOM3XegVzjUyoV3pkjNotE,256
168
174
  phoenix/server/api/types/ExperimentComparison.py,sha256=0sFz6MoBDw39dds0qVyaqhVs9qqO5rkG1FMSjmfBeCc,441
169
175
  phoenix/server/api/types/ExperimentRun.py,sha256=122_SID7SLKPUq2dJ2Y4BBw40DNUtcxo6QCZuO8UbBs,2997
170
- phoenix/server/api/types/ExperimentRunAnnotation.py,sha256=zGstMbS5OxNikEhD8VouY7Ls7YbxKm-0EmqvGeY3-DI,1773
176
+ phoenix/server/api/types/ExperimentRunAnnotation.py,sha256=iBxDaD9DgiF-Qymp5QyxWfJRGYXM1_CeWA_qzsZBqkI,1812
171
177
  phoenix/server/api/types/ExportedFile.py,sha256=e3GTn7B5LgsTbqiwjhMCQH7VsiqXitrBO4aCMS1lHsg,163
172
178
  phoenix/server/api/types/Functionality.py,sha256=tzV9xdhB8zqfsjWxP66NDC7EZsplYkYO7jRbLWJIeeg,382
173
179
  phoenix/server/api/types/Inferences.py,sha256=HWuDZZrXPWVoEy_pA3bRsAOUYsCKgAxf9zshasGqu5Y,3403
@@ -183,8 +189,10 @@ phoenix/server/api/types/ScalarDriftMetricEnum.py,sha256=IUAcRPpgL41WdoIgK6cNk2T
183
189
  phoenix/server/api/types/Segments.py,sha256=m2yoegrxA1Tn7ZAy1rMjjD1isc752MaAXMoffkBlvrM,2921
184
190
  phoenix/server/api/types/SortDir.py,sha256=OUpXhlCzCxPoXSDkJJygEs9Rw9pMymfaZUG5zPTrw4Y,152
185
191
  phoenix/server/api/types/Span.py,sha256=W4Rsg85bgqbDhgYwpjgOTrIQKbkwpFQPpL6nqMyzhCs,13865
192
+ phoenix/server/api/types/SpanAnnotation.py,sha256=n9pehpY-NqJD9KvK03UJYlHLKdies7mxrqdr9i1c5oE,1241
186
193
  phoenix/server/api/types/TimeSeries.py,sha256=wjzuxHFqCey0O7Ys25qiXyuqXK8an-osyNWUE8A_8G4,5227
187
194
  phoenix/server/api/types/Trace.py,sha256=ep-mPexub1ijxAnBvc2KrGsNVXO2SfDR1WxqER2wcD8,2376
195
+ phoenix/server/api/types/TraceAnnotation.py,sha256=OW6A2zr1gomOuG0XQe55dk15XXX2DSM0DzatRbHWH5A,1256
188
196
  phoenix/server/api/types/UMAPPoints.py,sha256=5sOuruzM8saXa8C2XiyUfk2XPrkVGmhqKpclMYRw1dk,1656
189
197
  phoenix/server/api/types/ValidationResult.py,sha256=pHwdYk4J7SJ5xhlWWHg_6qWkfk4rjOx-bSkGHvkDE3Q,142
190
198
  phoenix/server/api/types/VectorDriftMetricEnum.py,sha256=etiJM5ZjQuD-oE7sY-FbdIKY050jk3IU49IMwmfJbEc,188
@@ -203,7 +211,7 @@ phoenix/server/static/apple-touch-icon-76x76.png,sha256=CT_xT12I0u2i0WU8JzBZBuOQ
203
211
  phoenix/server/static/apple-touch-icon.png,sha256=fOfpjqGpWYbJ0eAurKsyoZP1EAs6ZVooBJ_SGk2ZkDs,3801
204
212
  phoenix/server/static/favicon.ico,sha256=bY0vvCKRftemZfPShwZtE93DiiQdaYaozkPGwNFr6H8,34494
205
213
  phoenix/server/static/index.css,sha256=KKGpx4iwF91VGRm0YN-4cn8oC-oIqC6HecoPf0x3ZM8,1885
206
- phoenix/server/static/index.js,sha256=fo34I1yr65xkACAvw2LCNTDFMTpTQjKV3C1_oL1mWYg,3524937
214
+ phoenix/server/static/index.js,sha256=WUcVFCMT2Eo8mZ23tPZQG_DViKcUMC9EIbeLCGdkflw,3525834
207
215
  phoenix/server/static/modernizr.js,sha256=mvK-XtkNqjOral-QvzoqsyOMECXIMu5BQwSVN_wcU9c,2564
208
216
  phoenix/server/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
209
217
  phoenix/server/templates/index.html,sha256=S4z7qSoNSwnKFAH9r96AR-YJEyoKMd-VMWVlJ_IdzME,2039
@@ -248,8 +256,8 @@ phoenix/utilities/logging.py,sha256=lDXd6EGaamBNcQxL4vP1au9-i_SXe0OraUDiJOcszSw,
248
256
  phoenix/utilities/project.py,sha256=qWsvKnG1oKhOFUowXf9qiOL2ia7jaFe_ijFFHEt8GJo,431
249
257
  phoenix/utilities/re.py,sha256=PDve_OLjRTM8yQQJHC8-n3HdIONi7aNils3ZKRZ5uBM,2045
250
258
  phoenix/utilities/span_store.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
251
- arize_phoenix-4.9.0.dist-info/METADATA,sha256=yF2f3TQt507o3KgtWsjLWsM4XtMtm0HSus54sjWZo_0,11451
252
- arize_phoenix-4.9.0.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
253
- arize_phoenix-4.9.0.dist-info/licenses/IP_NOTICE,sha256=JBqyyCYYxGDfzQ0TtsQgjts41IJoa-hiwDrBjCb9gHM,469
254
- arize_phoenix-4.9.0.dist-info/licenses/LICENSE,sha256=HFkW9REuMOkvKRACuwLPT0hRydHb3zNg-fdFt94td18,3794
255
- arize_phoenix-4.9.0.dist-info/RECORD,,
259
+ arize_phoenix-4.10.0.dist-info/METADATA,sha256=l9uPi2r0PKsNM1bkkOLnkwPlKSqwyMD63Hd16Y7LV-Y,11452
260
+ arize_phoenix-4.10.0.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
261
+ arize_phoenix-4.10.0.dist-info/licenses/IP_NOTICE,sha256=JBqyyCYYxGDfzQ0TtsQgjts41IJoa-hiwDrBjCb9gHM,469
262
+ arize_phoenix-4.10.0.dist-info/licenses/LICENSE,sha256=HFkW9REuMOkvKRACuwLPT0hRydHb3zNg-fdFt94td18,3794
263
+ arize_phoenix-4.10.0.dist-info/RECORD,,
@@ -6,7 +6,7 @@ from typing_extensions import assert_never
6
6
 
7
7
  from phoenix.db import models
8
8
  from phoenix.db.helpers import SupportedSQLDialect, num_docs_col
9
- from phoenix.db.insertion.helpers import OnConflict, insert_on_conflict
9
+ from phoenix.db.insertion.helpers import insert_on_conflict
10
10
  from phoenix.exceptions import PhoenixException
11
11
  from phoenix.trace import v1 as pb
12
12
 
@@ -87,18 +87,12 @@ async def _insert_trace_evaluation(
87
87
  metadata_={}, # `metadata_` must match ORM
88
88
  annotator_kind="LLM",
89
89
  )
90
- set_ = dict(values)
91
- set_.pop("metadata_")
92
- set_["metadata"] = values["metadata_"] # `metadata` must match database
93
90
  await session.execute(
94
91
  insert_on_conflict(
92
+ values,
95
93
  dialect=dialect,
96
94
  table=models.TraceAnnotation,
97
- values=values,
98
- constraint="uq_trace_annotations_name_trace_rowid",
99
- column_names=("name", "trace_rowid"),
100
- on_conflict=OnConflict.DO_UPDATE,
101
- set_=set_,
95
+ unique_by=("name", "trace_rowid"),
102
96
  )
103
97
  )
104
98
  return TraceEvaluationInsertionEvent(project_rowid, evaluation_name)
@@ -135,18 +129,12 @@ async def _insert_span_evaluation(
135
129
  metadata_={}, # `metadata_` must match ORM
136
130
  annotator_kind="LLM",
137
131
  )
138
- set_ = dict(values)
139
- set_.pop("metadata_")
140
- set_["metadata"] = values["metadata_"] # `metadata` must match database
141
132
  await session.execute(
142
133
  insert_on_conflict(
134
+ values,
143
135
  dialect=dialect,
144
136
  table=models.SpanAnnotation,
145
- values=values,
146
- constraint="uq_span_annotations_name_span_rowid",
147
- column_names=("name", "span_rowid"),
148
- on_conflict=OnConflict.DO_UPDATE,
149
- set_=set_,
137
+ unique_by=("name", "span_rowid"),
150
138
  )
151
139
  )
152
140
  return SpanEvaluationInsertionEvent(project_rowid, evaluation_name)
@@ -192,18 +180,12 @@ async def _insert_document_evaluation(
192
180
  metadata_={}, # `metadata_` must match ORM
193
181
  annotator_kind="LLM",
194
182
  )
195
- set_ = dict(values)
196
- set_.pop("metadata_")
197
- set_["metadata"] = values["metadata_"] # `metadata` must match database
198
183
  await session.execute(
199
184
  insert_on_conflict(
185
+ values,
200
186
  dialect=dialect,
201
187
  table=models.DocumentAnnotation,
202
- values=values,
203
- constraint="uq_document_annotations_name_span_rowid_document_position",
204
- column_names=("name", "span_rowid", "document_position"),
205
- on_conflict=OnConflict.DO_UPDATE,
206
- set_=set_,
188
+ unique_by=("name", "span_rowid", "document_position"),
207
189
  )
208
190
  )
209
191
  return DocumentEvaluationInsertionEvent(project_rowid, evaluation_name)
@@ -1,14 +1,27 @@
1
1
  from abc import ABC
2
2
  from enum import Enum, auto
3
- from typing import Any, Awaitable, Callable, Mapping, Optional, Sequence
3
+ from typing import (
4
+ Any,
5
+ Awaitable,
6
+ Callable,
7
+ Iterable,
8
+ Iterator,
9
+ Mapping,
10
+ Optional,
11
+ Sequence,
12
+ Tuple,
13
+ Type,
14
+ )
4
15
 
5
16
  from sqlalchemy import Insert
6
17
  from sqlalchemy.dialects.postgresql import insert as insert_postgresql
7
18
  from sqlalchemy.dialects.sqlite import insert as insert_sqlite
8
19
  from sqlalchemy.ext.asyncio import AsyncSession
20
+ from sqlalchemy.sql.elements import KeyedColumnElement
9
21
  from typing_extensions import TypeAlias, assert_never
10
22
 
11
23
  from phoenix.db.helpers import SupportedSQLDialect
24
+ from phoenix.db.models import Base
12
25
 
13
26
 
14
27
  class DataManipulationEvent(ABC):
@@ -26,29 +39,57 @@ class OnConflict(Enum):
26
39
 
27
40
 
28
41
  def insert_on_conflict(
42
+ *records: Mapping[str, Any],
43
+ table: Type[Base],
29
44
  dialect: SupportedSQLDialect,
30
- table: Any,
31
- values: Mapping[str, Any],
32
- constraint: str,
33
- column_names: Sequence[str],
34
- on_conflict: OnConflict = OnConflict.DO_NOTHING,
45
+ unique_by: Sequence[str],
46
+ on_conflict: OnConflict = OnConflict.DO_UPDATE,
35
47
  set_: Optional[Mapping[str, Any]] = None,
36
48
  ) -> Insert:
37
49
  """
38
50
  Dialect specific insertion statement using ON CONFLICT DO syntax.
39
51
  """
52
+ if on_conflict is OnConflict.DO_UPDATE:
53
+ # postegresql rejects duplicate updates for the same record
54
+ seen = set()
55
+ unique_records = []
56
+ for v in reversed(records):
57
+ if (k := tuple(v.get(name) for name in unique_by)) in seen:
58
+ continue
59
+ unique_records.append(v)
60
+ seen.add(k)
61
+ records = tuple(reversed(unique_records))
62
+ constraint = "_".join(("uq", table.__tablename__, *unique_by))
40
63
  if dialect is SupportedSQLDialect.POSTGRESQL:
41
- stmt_postgresql = insert_postgresql(table).values(values)
42
- if on_conflict is OnConflict.DO_NOTHING or not set_:
64
+ stmt_postgresql = insert_postgresql(table).values(records)
65
+ if on_conflict is OnConflict.DO_NOTHING:
43
66
  return stmt_postgresql.on_conflict_do_nothing(constraint=constraint)
44
67
  if on_conflict is OnConflict.DO_UPDATE:
45
- return stmt_postgresql.on_conflict_do_update(constraint=constraint, set_=set_)
68
+ return stmt_postgresql.on_conflict_do_update(
69
+ constraint=constraint,
70
+ set_=set_ if set_ else dict(_clean(stmt_postgresql.excluded.items())),
71
+ )
46
72
  assert_never(on_conflict)
47
73
  if dialect is SupportedSQLDialect.SQLITE:
48
- stmt_sqlite = insert_sqlite(table).values(values)
49
- if on_conflict is OnConflict.DO_NOTHING or not set_:
50
- return stmt_sqlite.on_conflict_do_nothing(column_names)
74
+ stmt_sqlite = insert_sqlite(table).values(records)
75
+ if on_conflict is OnConflict.DO_NOTHING:
76
+ return stmt_sqlite.on_conflict_do_nothing(unique_by)
51
77
  if on_conflict is OnConflict.DO_UPDATE:
52
- return stmt_sqlite.on_conflict_do_update(column_names, set_=set_)
78
+ return stmt_sqlite.on_conflict_do_update(
79
+ unique_by,
80
+ set_=set_ if set_ else dict(_clean(stmt_sqlite.excluded.items())),
81
+ )
53
82
  assert_never(on_conflict)
54
83
  assert_never(dialect)
84
+
85
+
86
+ def _clean(
87
+ kv: Iterable[Tuple[str, KeyedColumnElement[Any]]],
88
+ ) -> Iterator[Tuple[str, KeyedColumnElement[Any]]]:
89
+ for k, v in kv:
90
+ if v.primary_key or v.foreign_keys or k == "created_at":
91
+ continue
92
+ if k == "metadata_":
93
+ yield "metadata", v
94
+ else:
95
+ yield k, v
@@ -26,17 +26,14 @@ async def insert_span(
26
26
  project_name: str,
27
27
  ) -> Optional[SpanInsertionEvent]:
28
28
  dialect = SupportedSQLDialect(session.bind.dialect.name)
29
- project_rowid = await session.scalar(
30
- insert_on_conflict(
31
- dialect=dialect,
32
- table=models.Project,
33
- constraint="uq_projects_name",
34
- column_names=("name",),
35
- values=dict(name=project_name),
36
- on_conflict=OnConflict.DO_UPDATE,
37
- set_=dict(name=project_name),
38
- ).returning(models.Project.id)
39
- )
29
+ if (
30
+ project_rowid := await session.scalar(
31
+ select(models.Project.id).where(models.Project.name == project_name)
32
+ )
33
+ ) is None:
34
+ project_rowid = await session.scalar(
35
+ insert(models.Project).values(dict(name=project_name)).returning(models.Project.id)
36
+ )
40
37
  assert project_rowid is not None
41
38
  if trace := await session.scalar(
42
39
  select(models.Trace).where(models.Trace.trace_id == span.context.trace_id)
@@ -88,11 +85,7 @@ async def insert_span(
88
85
  cumulative_llm_token_count_completion += cast(int, accumulation[2] or 0)
89
86
  span_rowid = await session.scalar(
90
87
  insert_on_conflict(
91
- dialect=dialect,
92
- table=models.Span,
93
- constraint="uq_spans_span_id",
94
- column_names=("span_id",),
95
- values=dict(
88
+ dict(
96
89
  span_id=span.context.span_id,
97
90
  trace_rowid=trace_rowid,
98
91
  parent_id=span.parent_id,
@@ -108,6 +101,9 @@ async def insert_span(
108
101
  cumulative_llm_token_count_prompt=cumulative_llm_token_count_prompt,
109
102
  cumulative_llm_token_count_completion=cumulative_llm_token_count_completion,
110
103
  ),
104
+ dialect=dialect,
105
+ table=models.Span,
106
+ unique_by=("span_id",),
111
107
  on_conflict=OnConflict.DO_NOTHING,
112
108
  ).returning(models.Span.id)
113
109
  )
@@ -1,52 +1,52 @@
1
- from dataclasses import dataclass
2
- from typing import Any, Mapping, Optional
3
-
4
- DEFAULT_MIN_DIST = 0.0
5
- DEFAULT_N_NEIGHBORS = 30
6
- DEFAULT_N_SAMPLES = 500
7
-
8
- MIN_NEIGHBORS = 5
9
- MAX_NEIGHBORS = 100
10
- MIN_SAMPLES = 1
11
- MAX_SAMPLES = 1000
12
- MIN_MIN_DIST = 0.0
13
- MAX_MIN_DIST = 0.99
14
-
15
-
16
- @dataclass
17
- class UMAPParameters:
18
- min_dist: float = DEFAULT_MIN_DIST
19
- n_neighbors: int = DEFAULT_N_NEIGHBORS
20
- n_samples: int = DEFAULT_N_SAMPLES
21
-
22
- def __post_init__(self) -> None:
23
- if not isinstance(self.min_dist, float) or not (
24
- MIN_MIN_DIST <= self.min_dist <= MAX_MIN_DIST
25
- ):
26
- raise ValueError(
27
- f"minDist must be float type, and between {MIN_MIN_DIST} and {MAX_MIN_DIST}"
28
- )
29
-
30
- if not isinstance(self.n_neighbors, int) or not (
31
- MIN_NEIGHBORS <= self.n_neighbors <= MAX_NEIGHBORS
32
- ):
33
- raise ValueError(
34
- f"nNeighbors must be int type, and between {MIN_NEIGHBORS} and {MAX_NEIGHBORS}"
35
- )
36
-
37
- if not isinstance(self.n_samples, int) or not (
38
- MIN_SAMPLES <= self.n_samples <= MAX_SAMPLES
39
- ):
40
- raise ValueError(
41
- f"nSamples must be int type, and between {MIN_SAMPLES} and {MAX_SAMPLES}"
42
- )
43
-
44
-
45
- def get_umap_parameters(default_umap_parameters: Optional[Mapping[str, Any]]) -> UMAPParameters:
46
- if not default_umap_parameters:
47
- return UMAPParameters()
48
- return UMAPParameters(
49
- min_dist=float(default_umap_parameters.get("min_dist", DEFAULT_MIN_DIST)),
50
- n_neighbors=int(default_umap_parameters.get("n_neighbors", DEFAULT_N_NEIGHBORS)),
51
- n_samples=int(default_umap_parameters.get("n_samples", DEFAULT_N_SAMPLES)),
52
- )
1
+ from dataclasses import dataclass
2
+ from typing import Any, Mapping, Optional
3
+
4
+ DEFAULT_MIN_DIST = 0.0
5
+ DEFAULT_N_NEIGHBORS = 30
6
+ DEFAULT_N_SAMPLES = 500
7
+
8
+ MIN_NEIGHBORS = 5
9
+ MAX_NEIGHBORS = 100
10
+ MIN_SAMPLES = 1
11
+ MAX_SAMPLES = 1000
12
+ MIN_MIN_DIST = 0.0
13
+ MAX_MIN_DIST = 0.99
14
+
15
+
16
+ @dataclass
17
+ class UMAPParameters:
18
+ min_dist: float = DEFAULT_MIN_DIST
19
+ n_neighbors: int = DEFAULT_N_NEIGHBORS
20
+ n_samples: int = DEFAULT_N_SAMPLES
21
+
22
+ def __post_init__(self) -> None:
23
+ if not isinstance(self.min_dist, float) or not (
24
+ MIN_MIN_DIST <= self.min_dist <= MAX_MIN_DIST
25
+ ):
26
+ raise ValueError(
27
+ f"minDist must be float type, and between {MIN_MIN_DIST} and {MAX_MIN_DIST}"
28
+ )
29
+
30
+ if not isinstance(self.n_neighbors, int) or not (
31
+ MIN_NEIGHBORS <= self.n_neighbors <= MAX_NEIGHBORS
32
+ ):
33
+ raise ValueError(
34
+ f"nNeighbors must be int type, and between {MIN_NEIGHBORS} and {MAX_NEIGHBORS}"
35
+ )
36
+
37
+ if not isinstance(self.n_samples, int) or not (
38
+ MIN_SAMPLES <= self.n_samples <= MAX_SAMPLES
39
+ ):
40
+ raise ValueError(
41
+ f"nSamples must be int type, and between {MIN_SAMPLES} and {MAX_SAMPLES}"
42
+ )
43
+
44
+
45
+ def get_umap_parameters(default_umap_parameters: Optional[Mapping[str, Any]]) -> UMAPParameters:
46
+ if not default_umap_parameters:
47
+ return UMAPParameters()
48
+ return UMAPParameters(
49
+ min_dist=float(default_umap_parameters.get("min_dist", DEFAULT_MIN_DIST)),
50
+ n_neighbors=int(default_umap_parameters.get("n_neighbors", DEFAULT_N_NEIGHBORS)),
51
+ n_samples=int(default_umap_parameters.get("n_samples", DEFAULT_N_SAMPLES)),
52
+ )
@@ -0,0 +1,16 @@
1
+ from typing import Optional
2
+
3
+ import strawberry
4
+ from strawberry.relay import GlobalID
5
+ from strawberry.scalars import JSON
6
+
7
+
8
+ @strawberry.input
9
+ class CreateSpanAnnotationsInput:
10
+ span_id: GlobalID
11
+ name: str
12
+ annotator_kind: str
13
+ label: Optional[str] = None
14
+ score: Optional[float] = None
15
+ explanation: Optional[str] = None
16
+ metadata: JSON = strawberry.field(default_factory=dict)
@@ -0,0 +1,16 @@
1
+ from typing import Optional
2
+
3
+ import strawberry
4
+ from strawberry.relay import GlobalID
5
+ from strawberry.scalars import JSON
6
+
7
+
8
+ @strawberry.input
9
+ class CreateTraceAnnotationsInput:
10
+ trace_id: GlobalID
11
+ name: str
12
+ annotator_kind: str
13
+ label: Optional[str] = None
14
+ score: Optional[float] = None
15
+ explanation: Optional[str] = None
16
+ metadata: JSON = strawberry.field(default_factory=dict)
@@ -0,0 +1,9 @@
1
+ from typing import List
2
+
3
+ import strawberry
4
+ from strawberry.relay import GlobalID
5
+
6
+
7
+ @strawberry.input
8
+ class DeleteAnnotationsInput:
9
+ annotation_ids: List[GlobalID]
@@ -0,0 +1,17 @@
1
+ from typing import Optional
2
+
3
+ import strawberry
4
+ from strawberry import UNSET
5
+ from strawberry.relay import GlobalID
6
+ from strawberry.scalars import JSON
7
+
8
+
9
+ @strawberry.input
10
+ class PatchAnnotationsInput:
11
+ annotation_id: GlobalID
12
+ name: Optional[str] = UNSET
13
+ annotator_kind: Optional[str] = UNSET
14
+ label: Optional[str] = UNSET
15
+ score: Optional[float] = UNSET
16
+ explanation: Optional[str] = UNSET
17
+ metadata: Optional[JSON] = UNSET
@@ -4,10 +4,17 @@ from phoenix.server.api.mutations.dataset_mutations import DatasetMutationMixin
4
4
  from phoenix.server.api.mutations.experiment_mutations import ExperimentMutationMixin
5
5
  from phoenix.server.api.mutations.export_events_mutations import ExportEventsMutationMixin
6
6
  from phoenix.server.api.mutations.project_mutations import ProjectMutationMixin
7
+ from phoenix.server.api.mutations.span_annotations_mutations import SpanAnnotationMutationMixin
8
+ from phoenix.server.api.mutations.trace_annotations_mutations import TraceAnnotationMutationMixin
7
9
 
8
10
 
9
11
  @strawberry.type
10
12
  class Mutation(
11
- ProjectMutationMixin, DatasetMutationMixin, ExperimentMutationMixin, ExportEventsMutationMixin
13
+ ProjectMutationMixin,
14
+ DatasetMutationMixin,
15
+ ExperimentMutationMixin,
16
+ ExportEventsMutationMixin,
17
+ SpanAnnotationMutationMixin,
18
+ TraceAnnotationMutationMixin,
12
19
  ):
13
20
  pass