arize-phoenix 2.0.0__py3-none-any.whl → 2.2.0rc0__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 (34) hide show
  1. {arize_phoenix-2.0.0.dist-info → arize_phoenix-2.2.0rc0.dist-info}/METADATA +5 -1
  2. {arize_phoenix-2.0.0.dist-info → arize_phoenix-2.2.0rc0.dist-info}/RECORD +31 -29
  3. phoenix/__init__.py +2 -2
  4. phoenix/core/evals.py +29 -8
  5. phoenix/core/traces.py +45 -34
  6. phoenix/experimental/evals/__init__.py +4 -1
  7. phoenix/experimental/evals/evaluators.py +85 -8
  8. phoenix/experimental/evals/functions/classify.py +16 -41
  9. phoenix/experimental/evals/functions/executor.py +1 -0
  10. phoenix/experimental/evals/models/anthropic.py +171 -0
  11. phoenix/experimental/evals/models/vertex.py +155 -0
  12. phoenix/experimental/evals/templates/__init__.py +2 -0
  13. phoenix/experimental/evals/templates/default_templates.py +12 -0
  14. phoenix/experimental/evals/utils/__init__.py +64 -2
  15. phoenix/server/api/schema.py +24 -0
  16. phoenix/server/app.py +6 -5
  17. phoenix/server/main.py +6 -7
  18. phoenix/server/span_handler.py +7 -7
  19. phoenix/server/static/index.js +586 -499
  20. phoenix/server/templates/index.html +5 -1
  21. phoenix/server/trace_handler.py +56 -0
  22. phoenix/session/session.py +2 -1
  23. phoenix/trace/exporter.py +4 -3
  24. phoenix/trace/langchain/tracer.py +14 -4
  25. phoenix/trace/otel.py +409 -0
  26. phoenix/trace/semantic_conventions.py +2 -0
  27. phoenix/trace/v1/__init__.py +0 -4
  28. phoenix/version.py +1 -0
  29. phoenix/trace/v1/trace_pb2.py +0 -54
  30. phoenix/trace/v1/trace_pb2.pyi +0 -361
  31. phoenix/trace/v1/utils.py +0 -538
  32. {arize_phoenix-2.0.0.dist-info → arize_phoenix-2.2.0rc0.dist-info}/WHEEL +0 -0
  33. {arize_phoenix-2.0.0.dist-info → arize_phoenix-2.2.0rc0.dist-info}/licenses/IP_NOTICE +0 -0
  34. {arize_phoenix-2.0.0.dist-info → arize_phoenix-2.2.0rc0.dist-info}/licenses/LICENSE +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: arize-phoenix
3
- Version: 2.0.0
3
+ Version: 2.2.0rc0
4
4
  Summary: ML Observability in your notebook
5
5
  Project-URL: Documentation, https://docs.arize.com/phoenix/
6
6
  Project-URL: Issues, https://github.com/Arize-ai/phoenix/issues
@@ -20,6 +20,8 @@ Requires-Dist: ddsketch
20
20
  Requires-Dist: hdbscan<1.0.0,>=0.8.33
21
21
  Requires-Dist: jinja2
22
22
  Requires-Dist: numpy
23
+ Requires-Dist: opentelemetry-proto
24
+ Requires-Dist: opentelemetry-sdk
23
25
  Requires-Dist: pandas
24
26
  Requires-Dist: protobuf<5.0,>=3.20
25
27
  Requires-Dist: psutil
@@ -36,8 +38,10 @@ Requires-Dist: umap-learn
36
38
  Requires-Dist: uvicorn
37
39
  Requires-Dist: wrapt
38
40
  Provides-Extra: dev
41
+ Requires-Dist: anthropic; extra == 'dev'
39
42
  Requires-Dist: arize[autoembeddings,llm-evaluation]; extra == 'dev'
40
43
  Requires-Dist: gcsfs; extra == 'dev'
44
+ Requires-Dist: google-cloud-aiplatform>=1.3; extra == 'dev'
41
45
  Requires-Dist: hatch; extra == 'dev'
42
46
  Requires-Dist: jupyter; extra == 'dev'
43
47
  Requires-Dist: langchain>=0.0.334; extra == 'dev'
@@ -1,16 +1,17 @@
1
- phoenix/__init__.py,sha256=PMI2WOSvZVHGPpuhM_CPM29ejrA1b-XOHI8jJXHWHeE,1373
1
+ phoenix/__init__.py,sha256=EEh0vZGRQS8686h34GQ64OjQoZ7neKYO_iO5j6Oa9Jw,1402
2
2
  phoenix/config.py,sha256=ErvGg22SSiuqPJtIX1WZE5KcM2lt6XOGZ__HwRg3JqA,2390
3
3
  phoenix/datetime_utils.py,sha256=D955QLrkgrrSdUM6NyqbCeAu2SMsjhR5rHVQEsVUdng,2773
4
4
  phoenix/exceptions.py,sha256=igIWGAg3m8jm5YwQDeCY1p8ml_60A7zaGVXJ1yZhY9s,44
5
5
  phoenix/py.typed,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
6
6
  phoenix/services.py,sha256=slL4Uu___QQSKEssgD738-WAld-kzVQnpW92uKLxV4E,4886
7
+ phoenix/version.py,sha256=pG4VqwySwU54SQ_mHFbajVD0oK3-38mb_fLPwWYLdoc,25
7
8
  phoenix/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
9
  phoenix/core/embedding_dimension.py,sha256=zKGbcvwOXgLf-yrJBpQyKtd-LEOPRKHnUToyAU8Owis,87
9
- phoenix/core/evals.py,sha256=tBHVgEEQW6zsNAAQCYIN-BbVHy5Q-hgF5UpQy1SmkwE,6538
10
+ phoenix/core/evals.py,sha256=OrHeYlh804rpcZIXTA6kan2mzSZMfgpphNNQdPMpNoM,7597
10
11
  phoenix/core/model.py,sha256=vQ6RxpUPlncezJvur5u6xBN0Lkrk2gW0cTyb-qqaSqA,4713
11
12
  phoenix/core/model_schema.py,sha256=rR9VdhL_oXxbprDTPQJBXs5hw5sMPQmzx__m6Kwsxug,50394
12
13
  phoenix/core/model_schema_adapter.py,sha256=3GkyzqUST4fYi-Bgs8qAam5hwMCdQRZTDLjZ9Bnzdm4,8268
13
- phoenix/core/traces.py,sha256=uNhtCpgXP9L0ahOoP9ZOBmLnubyUTkICiDB4XB-h5GY,14312
14
+ phoenix/core/traces.py,sha256=O01L6qwQfHxHUHNZemKBBsAgqDo1tAIO5-1fK2g0NwE,14618
14
15
  phoenix/datasets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
16
  phoenix/datasets/dataset.py,sha256=scKVZ7zc6Dpc_ntt-pWhzY-KWqOJEwKePuyNnKSVTGE,30515
16
17
  phoenix/datasets/errors.py,sha256=cGp9vxnw4SewFoWBV3ZGMkhE0Kh73lPIv3Ppz_H_RoA,8261
@@ -18,25 +19,27 @@ phoenix/datasets/fixtures.py,sha256=0_PacL3dw49zulKpFpPdhvxJxeGmHTguqIyf2VXkBkk,
18
19
  phoenix/datasets/schema.py,sha256=bF1d2Md6NyqQZuC4Ym5A52f2_IcazkyxGFZ11HPqSg0,6668
19
20
  phoenix/datasets/validation.py,sha256=dZ9lCFUV0EY7HCkQkQBrs-GLAEIZdpOqUxwD5l4dp88,8294
20
21
  phoenix/experimental/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
- phoenix/experimental/evals/__init__.py,sha256=90k7hxxghhqDCftoAWsdOiUsJqYwNuJBXjhbpb3Na4I,1499
22
- phoenix/experimental/evals/evaluators.py,sha256=JEEow9CM3u9GkVey8KEora8e7cbmhJgazd5wh35_LPE,10311
22
+ phoenix/experimental/evals/__init__.py,sha256=I-e_QhT3ezMwc0WeqZuTNbuHkdaLj9WvnFCv6aNAmYM,1595
23
+ phoenix/experimental/evals/evaluators.py,sha256=rLvvXBK2H_cjJyRMBQStTlMYntTJI3RtukwJopeA1jU,13065
23
24
  phoenix/experimental/evals/retrievals.py,sha256=o3fqrsYbYZjyGj_jWkN_9VQVyXjLkDKDw5Ws7l8bwdI,3828
24
25
  phoenix/experimental/evals/functions/__init__.py,sha256=3FMGrjmgxegXAwgDV_RpaN-73cFVyBiO8YwZvml5P9c,156
25
- phoenix/experimental/evals/functions/classify.py,sha256=Q0FMOpU6WFr4m3dtBpJlNyrj2ExTYMB-XjR1EreeeXg,18731
26
- phoenix/experimental/evals/functions/executor.py,sha256=TSw2lVhkl6-VBYcXSlUl3E0U4OuJWnhwhed7NmFgbF8,13376
26
+ phoenix/experimental/evals/functions/classify.py,sha256=uCTZR_ctQorzS0Abcwxzsza0g-4q_91DHiObjJISIXE,18177
27
+ phoenix/experimental/evals/functions/executor.py,sha256=bM7PI2rcPukQQzZ2rWqN_-Kfo_a935YJj0bh1Red8Ps,13406
27
28
  phoenix/experimental/evals/functions/generate.py,sha256=sdr6TeXn5JLEKM0NqYtvq01Lq48Q7uatb0fsq5zQgVY,5310
28
29
  phoenix/experimental/evals/functions/processing.py,sha256=F4xtLsulLV4a8CkuLldRddsCim75dSTIShEJUYN6I6w,1823
29
30
  phoenix/experimental/evals/models/__init__.py,sha256=j1N7DhiOPbcaemtVBONcQ0miNnGQwEXz4u3P3Vwe6-4,320
31
+ phoenix/experimental/evals/models/anthropic.py,sha256=Tcv8R-vTyY8sLAv1wIHeZdMCBtqhyayqMPJXRDc7blI,6267
30
32
  phoenix/experimental/evals/models/base.py,sha256=aSE3Al3MsLvzNKuN2e-z6O-RB5mgpisH4UQqwNQcqp0,7734
31
33
  phoenix/experimental/evals/models/bedrock.py,sha256=CRPmBuSLc_nRnKKWLHhGMxdWEISIKUJM1tzIlOQ_qWM,7927
32
34
  phoenix/experimental/evals/models/litellm.py,sha256=jrRlph22xWxMXMUabUWjIO2e-sHxQzlQwSM-SnAACFQ,4714
33
35
  phoenix/experimental/evals/models/openai.py,sha256=Kl2uES3HRcZGFqblfBQZ6D1BpDffuLZDAqVTjhrSXXQ,17101
34
36
  phoenix/experimental/evals/models/rate_limiters.py,sha256=5GVN0RQKt36Przg3-9jLgocRmyg-tbeO-cdbuLIx89w,10160
37
+ phoenix/experimental/evals/models/vertex.py,sha256=nwTIjVn4gGFfoKfGqUGwPD9GLJaBM4HLXDnMNs9hSrw,5407
35
38
  phoenix/experimental/evals/models/vertexai.py,sha256=NfBpQq0l7XzP-wDEDsK27IRiQBzA1GXEdfwlAf8leX4,5609
36
- phoenix/experimental/evals/templates/__init__.py,sha256=-KFIVh1xQLPcJP8Mv_tieIndxE02mg_c2QaibAuHJuE,1432
37
- phoenix/experimental/evals/templates/default_templates.py,sha256=8BetD8Xufc2f62CPZ9mbysyvDofnbFPalwB0u-KckuE,20614
39
+ phoenix/experimental/evals/templates/__init__.py,sha256=GSJSoWJ4jwyoUANniidmWMUtXQhNQYbTJbfFqCvuYuo,1470
40
+ phoenix/experimental/evals/templates/default_templates.py,sha256=_VVxuhPsY8fkasA9XMNNM_fvftltkIfVCfElSdFbsQY,21056
38
41
  phoenix/experimental/evals/templates/template.py,sha256=VAX_ZeV3vNWCODipMy7EtaYdQ0c7WA6H2Mx0i1axXf0,6005
39
- phoenix/experimental/evals/utils/__init__.py,sha256=PnCsNppI9KRFrQpsKWbLN58FNXsnUA3qqjLwNhoe_6Q,3715
42
+ phoenix/experimental/evals/utils/__init__.py,sha256=608EX7sG0f5oDG__II16J8xnFJiNpY9dI9AC8vXwR00,5601
40
43
  phoenix/experimental/evals/utils/threads.py,sha256=ksI-egarPnlxit0qKKjtjZ2L82qGLxqxZ6s92O0eBA4,1005
41
44
  phoenix/metrics/README.md,sha256=5gekqTU-5gGdMwvcfNp2Wlu8p1ul9kGY_jq0XXQusoI,1964
42
45
  phoenix/metrics/__init__.py,sha256=sLp7td1GIt_0Z8dPUyP4L0-_4x9c871yAaGX30oMsvg,2433
@@ -52,16 +55,17 @@ phoenix/pointcloud/pointcloud.py,sha256=ms-h1FLC0xXb3sk256zpSuZQDE2hdOAJzRNBklP0
52
55
  phoenix/pointcloud/projectors.py,sha256=zO_RrtDYSv2rqVOfIP2_9Cv11Dc8EmcZR94xhFcBYPU,1057
53
56
  phoenix/pointcloud/umap_parameters.py,sha256=lJsEOrbSuSiqI7g4Yt6xj7kgYxEqoep4ZHWLr6VWBqw,1760
54
57
  phoenix/server/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
55
- phoenix/server/app.py,sha256=SEKUBgiXCH6tCXelrzbuwuY_EbDFC8CD7J5W7BkZSzM,7125
58
+ phoenix/server/app.py,sha256=ptm47TRYPj36fNiko8Ja2R40J8HQFlfspSRUIQ1by88,7239
56
59
  phoenix/server/evaluation_handler.py,sha256=HzaoD8Cv9HbEdd0nYSTZoakKsE8Ic5lVjeuBh0vnhoA,1554
57
- phoenix/server/main.py,sha256=cBJ_S_6TQBlV0Uj6N6ps3xq86VIv6nYKR49OYDcborg,6775
58
- phoenix/server/span_handler.py,sha256=TCwzbvtKfAc3CaI2Ao7Q5cfORWtQ56cU7j-43wgbOBc,1263
60
+ phoenix/server/main.py,sha256=1puvebfgsD3GBHiMn5Dx-dURnby7iMGXK5Uce_KaQG4,6804
61
+ phoenix/server/span_handler.py,sha256=reYUDaN5bavSFjEiSfvYyAG_mpJs6S3iB-RNCkZrSUU,1295
59
62
  phoenix/server/thread_server.py,sha256=a9Vnzc69ZLqJbI_FUSOY3eeuYCiCq6aprPj2gS_RB-M,2097
63
+ phoenix/server/trace_handler.py,sha256=pXanrp9L21Mh7MnyJbj202NJ-Rn4bCjG0oL4DtdKcls,2074
60
64
  phoenix/server/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
61
65
  phoenix/server/api/context.py,sha256=02vRgyLFpDCmh97QwsjWD5cdNZkoCUtDPPs1YItbdbI,583
62
66
  phoenix/server/api/helpers.py,sha256=_V1eVkchZmTkhOfRC4QqR1sUB2xtIxdsMJkDouZq_IE,251
63
67
  phoenix/server/api/interceptor.py,sha256=do_J4HjPPQ_C7bMmqe1YpTmt_hoxcwC2I8P3n5sZBo4,1302
64
- phoenix/server/api/schema.py,sha256=3yUzUU9C3r-lH7ouxxZOO-8kiEVoLWn_dG-DUjKu78w,14413
68
+ phoenix/server/api/schema.py,sha256=b_GiRJKkfnqR_Fy51N4NWN2nh7clao2V6C8G94nTYo4,15303
65
69
  phoenix/server/api/input_types/ClusterInput.py,sha256=EL4ftvZxQ8mVdruUPcdhMhByORmSmM8S-X6RPqU6GX0,179
66
70
  phoenix/server/api/input_types/Coordinates.py,sha256=meTwbIjwTfqx5DGD2DBlH9wQzdQVNM5a8x9dp1FfIgA,173
67
71
  phoenix/server/api/input_types/DataQualityMetricInput.py,sha256=LazvmQCCM5m9SDZTpyxQXO1rYF4cmsc3lsR2S9S65X4,1292
@@ -121,19 +125,20 @@ phoenix/server/static/apple-touch-icon-76x76.png,sha256=CT_xT12I0u2i0WU8JzBZBuOQ
121
125
  phoenix/server/static/apple-touch-icon.png,sha256=fOfpjqGpWYbJ0eAurKsyoZP1EAs6ZVooBJ_SGk2ZkDs,3801
122
126
  phoenix/server/static/favicon.ico,sha256=bY0vvCKRftemZfPShwZtE93DiiQdaYaozkPGwNFr6H8,34494
123
127
  phoenix/server/static/index.css,sha256=KKGpx4iwF91VGRm0YN-4cn8oC-oIqC6HecoPf0x3ZM8,1885
124
- phoenix/server/static/index.js,sha256=hxV2PRT6IFyBLfCFykM1Xi537pefpFiNVeJTcU4YZyI,3216221
128
+ phoenix/server/static/index.js,sha256=gP89MKs13uK-k9A_hQFQM6E03GPltzNoEFgaAHaAgBs,3257264
125
129
  phoenix/server/static/modernizr.js,sha256=mvK-XtkNqjOral-QvzoqsyOMECXIMu5BQwSVN_wcU9c,2564
126
130
  phoenix/server/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
127
- phoenix/server/templates/index.html,sha256=UKAw1N5ysyOYiFgP5Hfd4oaSqc_Y7quEtC9FGvtsIBA,1425
131
+ phoenix/server/templates/index.html,sha256=_ZVGz2JYDgJjCL2kxSbVjN1qY7drKYerVIXNfmcW30k,1765
128
132
  phoenix/session/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
129
133
  phoenix/session/evaluation.py,sha256=88wSWlUi71RDHZksRE3hG91GHq8rMRYXirkyA3IbM8Y,4681
130
- phoenix/session/session.py,sha256=35Hf6pmSD0HbXwC7i7eBTnSUfgMIVAJRgi3YwyZ7uXY,17769
134
+ phoenix/session/session.py,sha256=WL0lUGnBp9ZJHOwkLPkf32QvmHOThC5VIERa4SP0o_E,17815
131
135
  phoenix/trace/__init__.py,sha256=lnuxATMemAqjURYqOfIo_HyCo5oIWIVTy98XAsiS1d8,215
132
136
  phoenix/trace/evaluation_conventions.py,sha256=t8jydM3U0-T5YpiQKRJ3tWdWGlHtzKyttYdw-ddvPOk,1048
133
- phoenix/trace/exporter.py,sha256=jPZxjCMsil6mfuzFybmZfdCO49Odr8r916zcYUht-Qg,4293
137
+ phoenix/trace/exporter.py,sha256=z3xrGJhIRh7XMy4Q1FkR3KmFZym-GX0XxLTZ6eSnN0Q,4347
134
138
  phoenix/trace/fixtures.py,sha256=lFuhPe-di54BmCT-RxS95m3e2-z1YBOo8CxsqYSgDD8,6341
139
+ phoenix/trace/otel.py,sha256=4cJ85O_y_S6C_kkVvYh8d1d1mzKpGk_eQKjg688PI0k,13899
135
140
  phoenix/trace/schemas.py,sha256=m1wVlYFT6qL3FovD3TtTYsEgN6OHvv52gNdJkoPCmuY,5400
136
- phoenix/trace/semantic_conventions.py,sha256=E51V06dT4ER0ZD3efinNDbu1aOHfIotve7fri5gl5bg,4599
141
+ phoenix/trace/semantic_conventions.py,sha256=u6NG85ZhbreriZr8cqJaddldM_jUcew7JilszY7JUk8,4652
137
142
  phoenix/trace/span_evaluations.py,sha256=9RTJ8BFhXDJNtqErWRlMj65FG7wJiI41YTgB7vYLqcY,8429
138
143
  phoenix/trace/span_json_decoder.py,sha256=Xv-0uCsHgwzQb0dqTa7CuuDeXAPaXjQICyCFK3ZQaSs,3089
139
144
  phoenix/trace/span_json_encoder.py,sha256=C5y7rkyOcV08oJC5t8TZqVxsKCZMJKad7bBQzAgLoDs,1763
@@ -147,24 +152,21 @@ phoenix/trace/dsl/missing.py,sha256=BWPOHr2_tBkPDgVeq8GVXXVbNbJiBelu4NtwHBg6mTE,
147
152
  phoenix/trace/dsl/query.py,sha256=BAdL5rcliatBtxpcuZ86am5mmSUkhzCMF3PRSH8v3m8,9890
148
153
  phoenix/trace/langchain/__init__.py,sha256=vAjrmrreetV7L5IL8VH_9efG9VJunJTgT0iKyWqjFbc,148
149
154
  phoenix/trace/langchain/instrumentor.py,sha256=HkNKbFNclTYjRXBM8qU4qvZHdyw06J9bhwgE7JnqbNI,1323
150
- phoenix/trace/langchain/tracer.py,sha256=W0wssIwqtEHjDQPgobz9Kd9wsr2kpuHl9lXuX1HQ9zI,16388
155
+ phoenix/trace/langchain/tracer.py,sha256=1Oz3orSDpZX1pZKwtZbeM_f9tiAhQb7Of8ARjRlKVQY,16827
151
156
  phoenix/trace/llama_index/__init__.py,sha256=wCcQgD9CG5TA8i-1XsSed4ZzwHTUmqZwegQAV_FqEng,178
152
157
  phoenix/trace/llama_index/callback.py,sha256=YW3qqzWZUEs9aiDx-2628Eae_rct_Yb-DDzT9dV_xiI,27061
153
158
  phoenix/trace/llama_index/debug_callback.py,sha256=SKToD9q_QADSGTJ5lhilqRVKaUnUSRXUvURCzN4by2U,1367
154
159
  phoenix/trace/llama_index/streaming.py,sha256=5cTtr8evvcEAB88Xb4ih3WEw0xAF4x5W9PehUX9l5_0,3258
155
160
  phoenix/trace/openai/__init__.py,sha256=J3G0uqCxGdksUpaQVHds_Egv2drvh8UEqoLjiQAOveg,79
156
161
  phoenix/trace/openai/instrumentor.py,sha256=H1T2_1uqeH2lKCKeMmirEUl6PRtHQlQTXfsLR_hwDFM,24948
157
- phoenix/trace/v1/__init__.py,sha256=gzPW6vBuE_Z1bymL935cuiFBty1Tl9v2RCgAKY6vfPM,200
162
+ phoenix/trace/v1/__init__.py,sha256=-IbAD0ruESMjvQLvGAg9CTfjBUATFDx1OXseDPis6-0,88
158
163
  phoenix/trace/v1/evaluation_pb2.py,sha256=8sXvv2BW_vqD30MOMbmkeE2zpmm7ncik21kl3e-HzeQ,2254
159
164
  phoenix/trace/v1/evaluation_pb2.pyi,sha256=cCbbx06gwQmaH14s3J1X25TtaARh-k1abbxQdQCXGm8,4500
160
- phoenix/trace/v1/trace_pb2.py,sha256=IfvVb4PkUS6W72uJvcZTj7yj8hFvaaRac0RiOYae7Ik,5724
161
- phoenix/trace/v1/trace_pb2.pyi,sha256=4OErYEvVemBUoCiD2ABG9NSpGDEEzJkHr6x9ALYvE5Y,16497
162
- phoenix/trace/v1/utils.py,sha256=j7gunL9CuSi7Xif56oWYGx0sc7KjfJhXzWcJia4ZM-8,17815
163
165
  phoenix/utilities/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
164
166
  phoenix/utilities/error_handling.py,sha256=7b5rpGFj9EWZ8yrZK1IHvxB89suWk3lggDayUQcvZds,1946
165
167
  phoenix/utilities/logging.py,sha256=lDXd6EGaamBNcQxL4vP1au9-i_SXe0OraUDiJOcszSw,222
166
- arize_phoenix-2.0.0.dist-info/METADATA,sha256=aPHvi6tNxDcZhbOnRkeFus1Zw5dvniTbkET_ythER2c,26310
167
- arize_phoenix-2.0.0.dist-info/WHEEL,sha256=mRYSEL3Ih6g5a_CVMIcwiF__0Ae4_gLYh01YFNwiq1k,87
168
- arize_phoenix-2.0.0.dist-info/licenses/IP_NOTICE,sha256=JBqyyCYYxGDfzQ0TtsQgjts41IJoa-hiwDrBjCb9gHM,469
169
- arize_phoenix-2.0.0.dist-info/licenses/LICENSE,sha256=HFkW9REuMOkvKRACuwLPT0hRydHb3zNg-fdFt94td18,3794
170
- arize_phoenix-2.0.0.dist-info/RECORD,,
168
+ arize_phoenix-2.2.0rc0.dist-info/METADATA,sha256=cV0tw8Sq1yms7yncqdyAkIoUOMVBIfDQkS_X9wlmgKY,26482
169
+ arize_phoenix-2.2.0rc0.dist-info/WHEEL,sha256=mRYSEL3Ih6g5a_CVMIcwiF__0Ae4_gLYh01YFNwiq1k,87
170
+ arize_phoenix-2.2.0rc0.dist-info/licenses/IP_NOTICE,sha256=JBqyyCYYxGDfzQ0TtsQgjts41IJoa-hiwDrBjCb9gHM,469
171
+ arize_phoenix-2.2.0rc0.dist-info/licenses/LICENSE,sha256=HFkW9REuMOkvKRACuwLPT0hRydHb3zNg-fdFt94td18,3794
172
+ arize_phoenix-2.2.0rc0.dist-info/RECORD,,
phoenix/__init__.py CHANGED
@@ -5,8 +5,7 @@ from .session.evaluation import log_evaluations
5
5
  from .session.session import NotebookEnvironment, Session, active_session, close_app, launch_app
6
6
  from .trace.fixtures import load_example_traces
7
7
  from .trace.trace_dataset import TraceDataset
8
-
9
- __version__ = "2.0.0"
8
+ from .version import __version__
10
9
 
11
10
  # module level doc-string
12
11
  __doc__ = """
@@ -25,6 +24,7 @@ Here are just a few of the things that phoenix does well:
25
24
  """
26
25
 
27
26
  __all__ = [
27
+ "__version__",
28
28
  "Dataset",
29
29
  "EmbeddingColumnNames",
30
30
  "RetrievalEmbeddingColumnNames",
phoenix/core/evals.py CHANGED
@@ -1,6 +1,7 @@
1
1
  import logging
2
2
  import weakref
3
3
  from collections import defaultdict
4
+ from datetime import datetime, timezone
4
5
  from queue import SimpleQueue
5
6
  from threading import RLock, Thread
6
7
  from types import MethodType
@@ -46,6 +47,7 @@ class Evals:
46
47
  self._document_evaluations_by_name: DefaultDict[
47
48
  EvaluationName, DefaultDict[SpanID, Dict[DocumentPosition, pb.Evaluation]]
48
49
  ] = defaultdict(lambda: defaultdict(dict))
50
+ self._last_updated_at: Optional[datetime] = None
49
51
  self._start_consumer()
50
52
 
51
53
  def put(self, evaluation: pb.Evaluation) -> None:
@@ -92,10 +94,16 @@ class Evals:
92
94
  )
93
95
  else:
94
96
  assert_never(subject_id_kind)
97
+ self._last_updated_at = datetime.now(timezone.utc)
98
+
99
+ @property
100
+ def last_updated_at(self) -> Optional[datetime]:
101
+ return self._last_updated_at
95
102
 
96
103
  def get_span_evaluation(self, span_id: SpanID, name: str) -> Optional[pb.Evaluation]:
97
104
  with self._lock:
98
- return self._evaluations_by_span_id[span_id].get(name)
105
+ span_evaluations = self._evaluations_by_span_id.get(span_id)
106
+ return span_evaluations.get(name) if span_evaluations else None
99
107
 
100
108
  def get_span_evaluation_names(self) -> List[EvaluationName]:
101
109
  with self._lock:
@@ -108,28 +116,36 @@ class Evals:
108
116
  with self._lock:
109
117
  if span_id is None:
110
118
  return list(self._document_evaluations_by_name)
111
- return list(self._document_evaluations_by_span_id[span_id])
119
+ document_evaluations = self._document_evaluations_by_span_id.get(span_id)
120
+ return list(document_evaluations) if document_evaluations else []
112
121
 
113
122
  def get_span_evaluation_labels(self, name: EvaluationName) -> Tuple[str, ...]:
114
123
  with self._lock:
115
- return tuple(self._span_evaluation_labels[name])
124
+ labels = self._span_evaluation_labels.get(name)
125
+ return tuple(labels) if labels else ()
116
126
 
117
127
  def get_span_evaluation_span_ids(self, name: EvaluationName) -> Tuple[SpanID, ...]:
118
128
  with self._lock:
119
- return tuple(self._span_evaluations_by_name[name].keys())
129
+ span_evaluations = self._span_evaluations_by_name.get(name)
130
+ return tuple(span_evaluations.keys()) if span_evaluations else ()
120
131
 
121
132
  def get_evaluations_by_span_id(self, span_id: SpanID) -> List[pb.Evaluation]:
122
133
  with self._lock:
123
- return list(self._evaluations_by_span_id[span_id].values())
134
+ evaluations = self._evaluations_by_span_id.get(span_id)
135
+ return list(evaluations.values()) if evaluations else []
124
136
 
125
137
  def get_document_evaluation_span_ids(self, name: EvaluationName) -> Tuple[SpanID, ...]:
126
138
  with self._lock:
127
- return tuple(self._document_evaluations_by_name[name].keys())
139
+ document_evaluations = self._document_evaluations_by_name.get(name)
140
+ return tuple(document_evaluations.keys()) if document_evaluations else ()
128
141
 
129
142
  def get_document_evaluations_by_span_id(self, span_id: SpanID) -> List[pb.Evaluation]:
130
143
  all_evaluations: List[pb.Evaluation] = []
131
144
  with self._lock:
132
- for evaluations in self._document_evaluations_by_span_id[span_id].values():
145
+ document_evaluations = self._document_evaluations_by_span_id.get(span_id)
146
+ if not document_evaluations:
147
+ return all_evaluations
148
+ for evaluations in document_evaluations.values():
133
149
  all_evaluations.extend(evaluations.values())
134
150
  return all_evaluations
135
151
 
@@ -144,7 +160,12 @@ class Evals:
144
160
  # of one trillion, we would not want to create a result that large.
145
161
  scores: List[float] = [np.nan] * num_documents
146
162
  with self._lock:
147
- evaluations = self._document_evaluations_by_span_id[span_id][evaluation_name]
163
+ document_evaluations = self._document_evaluations_by_span_id.get(span_id)
164
+ if not document_evaluations:
165
+ return scores
166
+ evaluations = document_evaluations.get(evaluation_name)
167
+ if not evaluations:
168
+ return scores
148
169
  for document_position, evaluation in evaluations.items():
149
170
  result = evaluation.result
150
171
  if result.HasField("score") and document_position < num_documents:
phoenix/core/traces.py CHANGED
@@ -13,20 +13,21 @@ from typing import (
13
13
  Iterator,
14
14
  List,
15
15
  Optional,
16
+ Set,
16
17
  SupportsFloat,
17
18
  Tuple,
18
- Union,
19
19
  cast,
20
20
  )
21
21
 
22
+ import opentelemetry.proto.trace.v1.trace_pb2 as otlp
22
23
  from ddsketch import DDSketch
23
24
  from sortedcontainers import SortedKeyList
24
25
  from typing_extensions import TypeAlias
25
26
  from wrapt import ObjectProxy
26
27
 
27
- import phoenix.trace.v1 as pb
28
28
  from phoenix.datetime_utils import right_open_time_range
29
29
  from phoenix.trace import semantic_conventions
30
+ from phoenix.trace.otel import decode
30
31
  from phoenix.trace.schemas import (
31
32
  ATTRIBUTE_PREFIX,
32
33
  COMPUTED_PREFIX,
@@ -34,9 +35,10 @@ from phoenix.trace.schemas import (
34
35
  Span,
35
36
  SpanAttributes,
36
37
  SpanID,
38
+ SpanStatusCode,
37
39
  TraceID,
38
40
  )
39
- from phoenix.trace.v1.utils import decode, encode
41
+ from phoenix.trace.semantic_conventions import RETRIEVAL_DOCUMENTS
40
42
 
41
43
  END_OF_QUEUE = None # sentinel value for queue termination
42
44
 
@@ -74,15 +76,15 @@ class ReadableSpan(ObjectProxy): # type: ignore
74
76
  are ingested, and would need to be re-computed on the fly.
75
77
  """
76
78
 
77
- __wrapped__: pb.Span
78
-
79
- def __init__(self, span: pb.Span) -> None:
79
+ def __init__(self, otlp_span: otlp.Span) -> None:
80
+ span = decode(otlp_span)
80
81
  super().__init__(span)
82
+ self._self_otlp_span = otlp_span
81
83
  self._self_computed_values: Dict[str, SupportsFloat] = {}
82
84
 
83
85
  @property
84
86
  def span(self) -> Span:
85
- span = decode(self.__wrapped__)
87
+ span = decode(self._self_otlp_span)
86
88
  span.attributes.update(cast(SpanAttributes, self._self_computed_values))
87
89
  # TODO: compute latency rank percent (which can change depending on how
88
90
  # many spans already ingested).
@@ -96,9 +98,7 @@ class ReadableSpan(ObjectProxy): # type: ignore
96
98
  return getattr(self.__wrapped__.context, suffix_key, None)
97
99
  if key.startswith(ATTRIBUTE_PREFIX):
98
100
  suffix_key = key[len(ATTRIBUTE_PREFIX) :]
99
- if suffix_key not in self.__wrapped__.attributes:
100
- return None
101
- return self.__wrapped__.attributes[suffix_key]
101
+ return self.__wrapped__.attributes.get(suffix_key)
102
102
  return getattr(self.__wrapped__, key, None)
103
103
 
104
104
  def __setitem__(self, key: str, value: Any) -> None:
@@ -113,21 +113,21 @@ ChildSpanID: TypeAlias = SpanID
113
113
 
114
114
  class Traces:
115
115
  def __init__(self) -> None:
116
- self._queue: "SimpleQueue[Optional[pb.Span]]" = SimpleQueue()
116
+ self._queue: "SimpleQueue[Optional[otlp.Span]]" = SimpleQueue()
117
117
  # Putting `None` as the sentinel value for queue termination.
118
118
  weakref.finalize(self, self._queue.put, END_OF_QUEUE)
119
119
  self._lock = RLock()
120
120
  self._spans: Dict[SpanID, ReadableSpan] = {}
121
121
  self._parent_span_ids: Dict[SpanID, ParentSpanID] = {}
122
- self._traces: Dict[TraceID, List[SpanID]] = defaultdict(list)
123
- self._child_span_ids: DefaultDict[SpanID, List[ChildSpanID]] = defaultdict(list)
124
- self._orphan_spans: DefaultDict[ParentSpanID, List[pb.Span]] = defaultdict(list)
122
+ self._traces: DefaultDict[TraceID, List[SpanID]] = defaultdict(list)
123
+ self._child_span_ids: DefaultDict[SpanID, Set[ChildSpanID]] = defaultdict(set)
124
+ self._orphan_spans: DefaultDict[ParentSpanID, List[otlp.Span]] = defaultdict(list)
125
125
  self._num_documents: DefaultDict[SpanID, int] = defaultdict(int)
126
126
  self._start_time_sorted_span_ids: SortedKeyList[SpanID] = SortedKeyList(
127
- key=lambda span_id: self._spans[span_id].start_time.ToDatetime(timezone.utc),
127
+ key=lambda span_id: self._spans[span_id].start_time,
128
128
  )
129
129
  self._start_time_sorted_root_span_ids: SortedKeyList[SpanID] = SortedKeyList(
130
- key=lambda span_id: self._spans[span_id].start_time.ToDatetime(timezone.utc),
130
+ key=lambda span_id: self._spans[span_id].start_time,
131
131
  )
132
132
  self._latency_sorted_root_span_ids: SortedKeyList[SpanID] = SortedKeyList(
133
133
  key=lambda span_id: self._spans[span_id][ComputedAttributes.LATENCY_MS.value],
@@ -136,15 +136,18 @@ class Traces:
136
136
  self._min_start_time: Optional[datetime] = None
137
137
  self._max_start_time: Optional[datetime] = None
138
138
  self._token_count_total: int = 0
139
+ self._last_updated_at: Optional[datetime] = None
139
140
  self._start_consumer()
140
141
 
141
- def put(self, span: Optional[Union[Span, pb.Span]] = None) -> None:
142
- self._queue.put(encode(span) if isinstance(span, Span) else span)
142
+ def put(self, span: Optional[otlp.Span] = None) -> None:
143
+ self._queue.put(span)
143
144
 
144
145
  def get_trace(self, trace_id: TraceID) -> Iterator[Span]:
145
146
  with self._lock:
146
147
  # make a copy because source data can mutate during iteration
147
- span_ids = tuple(self._traces[trace_id])
148
+ if not (trace := self._traces.get(trace_id)):
149
+ return
150
+ span_ids = tuple(trace)
148
151
  for span_id in span_ids:
149
152
  if span := self[span_id]:
150
153
  yield span
@@ -194,7 +197,7 @@ class Traces:
194
197
 
195
198
  def get_num_documents(self, span_id: SpanID) -> int:
196
199
  with self._lock:
197
- return self._num_documents[span_id]
200
+ return self._num_documents.get(span_id) or 0
198
201
 
199
202
  def latency_rank_percent(self, latency_ms: float) -> Optional[float]:
200
203
  """
@@ -221,11 +224,17 @@ class Traces:
221
224
  def get_descendant_span_ids(self, span_id: SpanID) -> Iterator[SpanID]:
222
225
  with self._lock:
223
226
  # make a copy because source data can mutate during iteration
224
- span_ids = tuple(self._child_span_ids[span_id])
227
+ if not (child_span_ids := self._child_span_ids.get(span_id)):
228
+ return
229
+ span_ids = tuple(child_span_ids)
225
230
  for child_span_id in span_ids:
226
231
  yield child_span_id
227
232
  yield from self.get_descendant_span_ids(child_span_id)
228
233
 
234
+ @property
235
+ def last_updated_at(self) -> Optional[datetime]:
236
+ return self._last_updated_at
237
+
229
238
  @property
230
239
  def span_count(self) -> int:
231
240
  """Total number of spans (excluding orphan spans if any)"""
@@ -259,24 +268,24 @@ class Traces:
259
268
  with self._lock:
260
269
  self._process_span(item)
261
270
 
262
- def _process_span(self, span: pb.Span) -> None:
263
- span_id = SpanID(span.context.span_id)
271
+ def _process_span(self, span: otlp.Span) -> None:
272
+ new_span = ReadableSpan(span)
273
+ span_id = new_span.context.span_id
264
274
  existing_span = self._spans.get(span_id)
265
- if existing_span and existing_span.HasField("end_time"):
275
+ if existing_span and existing_span.end_time:
266
276
  # Reject updates if span has ended.
267
277
  return
268
- is_root_span = not span.HasField("parent_span_id")
278
+ is_root_span = not new_span.parent_id
269
279
  if not is_root_span:
270
- parent_span_id = SpanID(span.parent_span_id.value)
280
+ parent_span_id = new_span.parent_id
271
281
  if parent_span_id not in self._spans:
272
282
  # Span can't be processed before its parent.
273
283
  self._orphan_spans[parent_span_id].append(span)
274
284
  return
275
- self._child_span_ids[parent_span_id].append(span_id)
285
+ self._child_span_ids[parent_span_id].add(span_id)
276
286
  self._parent_span_ids[span_id] = parent_span_id
277
- new_span = ReadableSpan(span)
278
- start_time = span.start_time.ToDatetime(timezone.utc)
279
- end_time = span.end_time.ToDatetime(timezone.utc) if span.HasField("end_time") else None
287
+ start_time = new_span.start_time
288
+ end_time = new_span.end_time
280
289
  if end_time:
281
290
  new_span[ComputedAttributes.LATENCY_MS.value] = latency = (
282
291
  end_time - start_time
@@ -287,7 +296,7 @@ class Traces:
287
296
  if is_root_span and end_time:
288
297
  self._latency_sorted_root_span_ids.add(span_id)
289
298
  if not existing_span:
290
- trace_id = TraceID(span.context.trace_id)
299
+ trace_id = new_span.context.trace_id
291
300
  self._traces[trace_id].append(span_id)
292
301
  if is_root_span:
293
302
  self._start_time_sorted_root_span_ids.add(span_id)
@@ -303,7 +312,7 @@ class Traces:
303
312
  else max(self._max_start_time, start_time)
304
313
  )
305
314
  new_span[ComputedAttributes.ERROR_COUNT.value] = int(
306
- span.status.code is pb.Span.Status.Code.ERROR
315
+ new_span.status_code is SpanStatusCode.ERROR
307
316
  )
308
317
  # Update cumulative values for span's ancestors.
309
318
  for attribute_name, cumulative_attribute_name in (
@@ -336,14 +345,16 @@ class Traces:
336
345
  self._token_count_total -= existing_span[LLM_TOKEN_COUNT_TOTAL] or 0
337
346
  self._token_count_total += new_span[LLM_TOKEN_COUNT_TOTAL] or 0
338
347
  # Update number of documents
339
- num_documents_update = len(span.retrieval.documents)
348
+ num_documents_update = len(new_span.attributes.get(RETRIEVAL_DOCUMENTS) or ())
340
349
  if existing_span:
341
- num_documents_update -= len(existing_span.retrieval.documents)
350
+ num_documents_update -= len(existing_span.attributes.get(RETRIEVAL_DOCUMENTS) or ())
342
351
  if num_documents_update:
343
352
  self._num_documents[span_id] += num_documents_update
344
353
  # Process previously orphaned spans, if any.
345
354
  for orphan_span in self._orphan_spans.pop(span_id, ()):
346
355
  self._process_span(orphan_span)
356
+ # Update last updated timestamp
357
+ self._last_updated_at = datetime.now(timezone.utc)
347
358
 
348
359
  def _add_value_to_span_ancestors(
349
360
  self,
@@ -1,4 +1,4 @@
1
- from .evaluators import LLMEvaluator
1
+ from .evaluators import InvalidEvalCriteriaError, LLMEvaluator
2
2
  from .functions import llm_classify, llm_generate, run_relevance_eval
3
3
  from .models import BedrockModel, LiteLLMModel, OpenAIModel, VertexAIModel
4
4
  from .retrievals import compute_precisions_at_k
@@ -16,11 +16,13 @@ from .templates import (
16
16
  TOXICITY_PROMPT_RAILS_MAP,
17
17
  TOXICITY_PROMPT_TEMPLATE,
18
18
  ClassificationTemplate,
19
+ EvalCriteria,
19
20
  PromptTemplate,
20
21
  )
21
22
  from .utils import NOT_PARSABLE, download_benchmark_dataset
22
23
 
23
24
  __all__ = [
25
+ "EvalCriteria",
24
26
  "compute_precisions_at_k",
25
27
  "download_benchmark_dataset",
26
28
  "llm_classify",
@@ -46,4 +48,5 @@ __all__ = [
46
48
  "QA_PROMPT_TEMPLATE",
47
49
  "NOT_PARSABLE",
48
50
  "run_relevance_eval",
51
+ "InvalidEvalCriteriaError",
49
52
  ]