arize-phoenix 6.2.0__py3-none-any.whl → 7.0.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 (46) hide show
  1. {arize_phoenix-6.2.0.dist-info → arize_phoenix-7.0.0.dist-info}/METADATA +4 -4
  2. {arize_phoenix-6.2.0.dist-info → arize_phoenix-7.0.0.dist-info}/RECORD +44 -31
  3. phoenix/db/insertion/span.py +65 -30
  4. phoenix/db/migrations/data_migration_scripts/__init__.py +0 -0
  5. phoenix/db/migrations/data_migration_scripts/populate_project_sessions.py +199 -0
  6. phoenix/db/migrations/versions/4ded9e43755f_create_project_sessions_table.py +66 -0
  7. phoenix/db/models.py +27 -0
  8. phoenix/server/api/context.py +15 -2
  9. phoenix/server/api/dataloaders/__init__.py +14 -2
  10. phoenix/server/api/dataloaders/session_io.py +75 -0
  11. phoenix/server/api/dataloaders/session_num_traces.py +30 -0
  12. phoenix/server/api/dataloaders/session_num_traces_with_error.py +32 -0
  13. phoenix/server/api/dataloaders/session_token_usages.py +41 -0
  14. phoenix/server/api/dataloaders/session_trace_latency_ms_quantile.py +55 -0
  15. phoenix/server/api/dataloaders/trace_by_trace_ids.py +25 -0
  16. phoenix/server/api/dataloaders/trace_root_spans.py +32 -0
  17. phoenix/server/api/input_types/ProjectSessionSort.py +29 -0
  18. phoenix/server/api/mutations/project_mutations.py +12 -2
  19. phoenix/server/api/queries.py +14 -9
  20. phoenix/server/api/types/ExperimentRun.py +3 -4
  21. phoenix/server/api/types/ExperimentRunAnnotation.py +3 -4
  22. phoenix/server/api/types/Project.py +150 -12
  23. phoenix/server/api/types/ProjectSession.py +139 -0
  24. phoenix/server/api/types/Span.py +6 -19
  25. phoenix/server/api/types/SpanIOValue.py +15 -0
  26. phoenix/server/api/types/TokenUsage.py +11 -0
  27. phoenix/server/api/types/Trace.py +59 -2
  28. phoenix/server/app.py +15 -2
  29. phoenix/server/static/.vite/manifest.json +36 -36
  30. phoenix/server/static/assets/{components-DrwPLMB6.js → components-DKH6AzJw.js} +276 -276
  31. phoenix/server/static/assets/index-DLV87qiO.js +93 -0
  32. phoenix/server/static/assets/{pages-Cmqh2i4E.js → pages-CVY3Nv4Z.js} +611 -290
  33. phoenix/server/static/assets/{vendor-Cdrqqth8.js → vendor-Cb3zlNNd.js} +45 -45
  34. phoenix/server/static/assets/{vendor-arizeai-BSCL03yQ.js → vendor-arizeai-Buo4e1A6.js} +2 -2
  35. phoenix/server/static/assets/{vendor-codemirror-Utqu7Snw.js → vendor-codemirror-BuAQiUVf.js} +1 -1
  36. phoenix/server/static/assets/{vendor-recharts-CNNUvc5T.js → vendor-recharts-Cl9dK5tC.js} +1 -1
  37. phoenix/server/static/assets/{vendor-shiki-B6bHerDK.js → vendor-shiki-CazYUixL.js} +1 -1
  38. phoenix/trace/fixtures.py +8 -0
  39. phoenix/trace/schemas.py +16 -0
  40. phoenix/version.py +1 -1
  41. phoenix/server/api/dataloaders/trace_row_ids.py +0 -33
  42. phoenix/server/static/assets/index-CTN-OfBU.js +0 -93
  43. {arize_phoenix-6.2.0.dist-info → arize_phoenix-7.0.0.dist-info}/WHEEL +0 -0
  44. {arize_phoenix-6.2.0.dist-info → arize_phoenix-7.0.0.dist-info}/entry_points.txt +0 -0
  45. {arize_phoenix-6.2.0.dist-info → arize_phoenix-7.0.0.dist-info}/licenses/IP_NOTICE +0 -0
  46. {arize_phoenix-6.2.0.dist-info → arize_phoenix-7.0.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: arize-phoenix
3
- Version: 6.2.0
3
+ Version: 7.0.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
@@ -44,7 +44,7 @@ Requires-Dist: scipy
44
44
  Requires-Dist: sqlalchemy[asyncio]<3,>=2.0.4
45
45
  Requires-Dist: sqlean-py>=3.45.1
46
46
  Requires-Dist: starlette
47
- Requires-Dist: strawberry-graphql==0.243.1
47
+ Requires-Dist: strawberry-graphql==0.247.0
48
48
  Requires-Dist: tqdm
49
49
  Requires-Dist: typing-extensions>=4.6
50
50
  Requires-Dist: uvicorn
@@ -66,7 +66,7 @@ Requires-Dist: opentelemetry-sdk; extra == 'container'
66
66
  Requires-Dist: opentelemetry-semantic-conventions; extra == 'container'
67
67
  Requires-Dist: prometheus-client; extra == 'container'
68
68
  Requires-Dist: py-grpc-prometheus; extra == 'container'
69
- Requires-Dist: strawberry-graphql[opentelemetry]==0.243.1; extra == 'container'
69
+ Requires-Dist: strawberry-graphql[opentelemetry]==0.247.0; extra == 'container'
70
70
  Requires-Dist: umap-learn; extra == 'container'
71
71
  Requires-Dist: uvloop; (platform_system != 'Windows') and extra == 'container'
72
72
  Provides-Extra: dev
@@ -97,7 +97,7 @@ Requires-Dist: pytest-postgresql; extra == 'dev'
97
97
  Requires-Dist: pytest-xdist; extra == 'dev'
98
98
  Requires-Dist: pytest==8.3.3; extra == 'dev'
99
99
  Requires-Dist: ruff==0.6.9; extra == 'dev'
100
- Requires-Dist: strawberry-graphql[debug-server,opentelemetry]==0.243.1; extra == 'dev'
100
+ Requires-Dist: strawberry-graphql[debug-server,opentelemetry]==0.247.0; extra == 'dev'
101
101
  Requires-Dist: tabulate; extra == 'dev'
102
102
  Requires-Dist: tox-uv==1.11.3; extra == 'dev'
103
103
  Requires-Dist: tox==4.18.1; extra == 'dev'
@@ -6,7 +6,7 @@ phoenix/exceptions.py,sha256=n2L2KKuecrdflB9MsCdAYCiSEvGJptIsfRkXMoJle7A,169
6
6
  phoenix/py.typed,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
7
7
  phoenix/services.py,sha256=kpW1WL0kiB8XJsO6XycvZVJ-lBkNoenhQ7atCvBoSe8,5365
8
8
  phoenix/settings.py,sha256=ht-0oN-sMV6SPXrk7Tu1EZlngpAYkGNLYPhO8DyrdQI,661
9
- phoenix/version.py,sha256=5H_IrrHNTfYkLbC3nRLonK3TwkV0TTf0xGbx1a13Scw,22
9
+ phoenix/version.py,sha256=VgMOOqsYbyb60I1RmlZpqwqQ0C0IyT3R0c8_xX4pRGM,22
10
10
  phoenix/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
11
  phoenix/core/embedding_dimension.py,sha256=zKGbcvwOXgLf-yrJBpQyKtd-LEOPRKHnUToyAU8Owis,87
12
12
  phoenix/core/model.py,sha256=qBFraOtmwCCnWJltKNP18DDG0mULXigytlFsa6YOz6k,4837
@@ -21,22 +21,25 @@ phoenix/db/enums.py,sha256=tt7iovXLhVTLZ3_LbHNGgcI44SnNjXfkKtLAZG57T54,428
21
21
  phoenix/db/facilitator.py,sha256=sAYqzBXYSVBKPTQVYrd7ZmtqMAr1zP9dVJwjfNGW7hc,4207
22
22
  phoenix/db/helpers.py,sha256=daKbpY2QhTPo9a_T1xNHKI4WzWHkMmmrGIws7Hw-RZ4,4884
23
23
  phoenix/db/migrate.py,sha256=oUrXH8yEbcpL4eh09aSCuUiSrhFli0eT5D_j4ZmYChY,2797
24
- phoenix/db/models.py,sha256=wx2XQgf6qhUO2ZQ4oUENoAguf440qaR0Ea_q1XB1bBU,26484
24
+ phoenix/db/models.py,sha256=56_I2oV-OOKfQUIqUlNKWc3GIPag3nuHmoKqrtIis68,27459
25
25
  phoenix/db/insertion/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
26
26
  phoenix/db/insertion/constants.py,sha256=8wifm7X-1XvroZ__R2Gc96NsgLhTDn0zXl4lehlXtcA,70
27
27
  phoenix/db/insertion/dataset.py,sha256=I9OC1ouVx7m6BH_c8hvcxW1dWGRAtpvXee29yBTuFkg,7136
28
28
  phoenix/db/insertion/document_annotation.py,sha256=vnszF9L0qHjUY-eWgBVRG5OTpz-ECs1BoCfy66ynzjo,5997
29
29
  phoenix/db/insertion/evaluation.py,sha256=SoI85N3MYUSeNgjKa5WzFw14OfNjNTjExv-2m3sxaR8,6371
30
30
  phoenix/db/insertion/helpers.py,sha256=-DyRcxzJnjSJFhscPoqiNiQn8fBvGqI8IcNJEu-79Vw,3455
31
- phoenix/db/insertion/span.py,sha256=-CXn2LlEv2u7xbz7m8X5jALQ-BUNNzTxPJEzSmjhTpA,5958
31
+ phoenix/db/insertion/span.py,sha256=QHjWTc6cEdq1raxHDcQ9x9tBAdUfePJYjRE_wGdgXFk,7811
32
32
  phoenix/db/insertion/span_annotation.py,sha256=EtzcjS8GR2rDM_cxIQloGc2SZqfdrACyAPwvyFBa2Ac,5273
33
33
  phoenix/db/insertion/trace_annotation.py,sha256=6yzWuU0Fh-mC-rJJ96rH0IYTJg1EQFnj-GZhUwolUKI,5338
34
34
  phoenix/db/insertion/types.py,sha256=cWeBceyZZ3efLHKPjnPpVahrpX7-P8Bm_sdudWXkOek,8106
35
35
  phoenix/db/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
36
36
  phoenix/db/migrations/env.py,sha256=tFO3ceuCx9Es5_2w_BXclaQMmNQKNX21b1UEV5mYdeo,3387
37
37
  phoenix/db/migrations/script.py.mako,sha256=MEqL-2qATlST9TAOeYgscMn1uy6HUS9NFvDgl93dMj8,635
38
+ phoenix/db/migrations/data_migration_scripts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
39
+ phoenix/db/migrations/data_migration_scripts/populate_project_sessions.py,sha256=NJPoEX2-OhYxQXl0jRcX5eoq1azgLi8RLArZZw2pTY4,6046
38
40
  phoenix/db/migrations/versions/10460e46d750_datasets.py,sha256=3wftHgat1sEeKBl0EcQ24r_oOK_T-Tcmd2Loo73RVCs,8679
39
41
  phoenix/db/migrations/versions/3be8647b87d8_add_token_columns_to_spans_table.py,sha256=GxuKD501WSx083uIv21GhJS0l4Xk3exovfycaGAxY30,3638
42
+ phoenix/db/migrations/versions/4ded9e43755f_create_project_sessions_table.py,sha256=HDP3X5yxm5PwxMkODd-wrSwspQpFotTEz40jXRgq320,1787
40
43
  phoenix/db/migrations/versions/cd164e83824f_users_and_tokens.py,sha256=fkpmh5PgMZJiZpvLbZIaqlI2cucVpVbbNYpQ-Tznil8,5180
41
44
  phoenix/db/migrations/versions/cf03bd6bae1d_init.py,sha256=lorqWUcujC0fsYIOriGZlZw2LKjS3nF34KHxi1fp_Z8,8646
42
45
  phoenix/experiments/__init__.py,sha256=6JGwgUd7xCbGpuHqYZlsmErmYvVgv7N_j43bn3dUqsk,123
@@ -73,7 +76,7 @@ phoenix/pointcloud/pointcloud.py,sha256=SN_1wXZcwKrtSnHGZLDZGx71orqE1WyVF7E-D58d
73
76
  phoenix/pointcloud/projectors.py,sha256=TQgwc9cJDjJkin1WZyZzgl3HsYrLLiyWD7Czy4jNW3U,1088
74
77
  phoenix/pointcloud/umap_parameters.py,sha256=db_WEPoamuWtopZx7tQfAXPnoE0MS8FkAV0_ThjEx_Q,1735
75
78
  phoenix/server/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
76
- phoenix/server/app.py,sha256=O-oawPGpm02KT6_09E66qdEpZqJT1pMUt9LODeI5m5U,37934
79
+ phoenix/server/app.py,sha256=6ahHhsZeiYaWIRAVOGUk66c5BDQnB6EZQhgvtnqS6-M,38691
77
80
  phoenix/server/bearer_auth.py,sha256=0UudvkAS_dxna5JEJJhGUYwB6Ny-e22ssX5Mm79QwCk,5907
78
81
  phoenix/server/dml_event.py,sha256=MjJmVEKytq75chBOSyvYDusUnEbg1pHpIjR3pZkUaJA,2838
79
82
  phoenix/server/dml_event_handler.py,sha256=EZLXmCvx4pJrCkz29gxwKwmvmUkTtPCHw6klR-XM8qE,8258
@@ -89,14 +92,14 @@ phoenix/server/types.py,sha256=Ur73LKRB3VlvBDN95gKJoDIdmauuR-r1rpO1rNHm9kA,7209
89
92
  phoenix/server/api/README.md,sha256=Pyq1PLPgTzXAswrfIhGXrjI3Skq8it2jTVnanT6Ba4Q,1162
90
93
  phoenix/server/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
91
94
  phoenix/server/api/auth.py,sha256=OhWmv_Hl-K-yhJeUWXKRYYiUOIPo-rYSQXdm4fjeTJ8,901
92
- phoenix/server/api/context.py,sha256=g5tAYInMifMOdnGTlyfHdB7rDNlC9F2E5bU6IA_3Y0c,5337
95
+ phoenix/server/api/context.py,sha256=oTSBervsrFYeKsln37Mc_fgBD5y5TktYdNVPZSzTJlU,5952
93
96
  phoenix/server/api/exceptions.py,sha256=TA0JuY2YRnj35qGuMSQ8d0ToHum9gWm9W--3fSKHrX0,1171
94
97
  phoenix/server/api/interceptor.py,sha256=ykDnoC_apUd-llVli3m1CW18kNSIgjz2qZ6m5JmPDu8,1294
95
- phoenix/server/api/queries.py,sha256=4KJz8TUz3VUTup9MDjr_GoKX0SttWSvHBq2ncWZGxf8,27343
98
+ phoenix/server/api/queries.py,sha256=zRngYE72hxaeAg_1vsnSLwmqs_FSHrRNjQwi632_D-Y,27670
96
99
  phoenix/server/api/schema.py,sha256=tHyw2jTbue_-gu0fe9Sw7LUYtzJUCwp9SvccDgOkNPw,1696
97
100
  phoenix/server/api/subscriptions.py,sha256=NJXCWrbBERyTwmi3H_9jNpml4klIxs_kpynwXRoH9pc,23572
98
101
  phoenix/server/api/utils.py,sha256=quCBRcusc6PUq9tJq7M8PgwFZp7nXgVAxtbw8feribY,833
99
- phoenix/server/api/dataloaders/__init__.py,sha256=jNYvfXjnZzgA2HWTG7AZdqWGla3ZysBUDUei8Zkz6N8,3290
102
+ phoenix/server/api/dataloaders/__init__.py,sha256=nt5Lbs34q05GSvNCT2IGrkRW0kg65L8h3bZelzgpkYg,3909
100
103
  phoenix/server/api/dataloaders/annotation_summaries.py,sha256=2sHmIDX7n8tuPeBTs9bMKtlMKWn_Ph9awTZqmwn2Owc,5505
101
104
  phoenix/server/api/dataloaders/average_experiment_run_latency.py,sha256=GLFoFAbztOH-0FVzzZ77mATIO63UcjB50j3qXiNi-tE,1811
102
105
  phoenix/server/api/dataloaders/dataset_example_revisions.py,sha256=YG2VSWOkM7q_-RO8OwE8bHYX8d3_OH34SeaD4pvEt0w,5115
@@ -113,12 +116,18 @@ phoenix/server/api/dataloaders/latency_ms_quantile.py,sha256=CHWV9nvEEM3xqpXWuby
113
116
  phoenix/server/api/dataloaders/min_start_or_max_end_times.py,sha256=1jYglTXv4S8k7OWSGdgeJ2OxVCmZtX8a6sjJp9GPZ04,2783
114
117
  phoenix/server/api/dataloaders/project_by_name.py,sha256=O24Rjs0ZQaYtSnPfA6YBQfbHfUgNsHKUcc_gIKyK9vo,1086
115
118
  phoenix/server/api/dataloaders/record_counts.py,sha256=NLlMEaJ-HxiJavqbSkMbzOrIRzqzYxO8-t2mfp1vXqM,4160
119
+ phoenix/server/api/dataloaders/session_io.py,sha256=r-Zvn19qOo_JWATHtt5zwuwhHjiATLAGHRjoi4czd6U,3038
120
+ phoenix/server/api/dataloaders/session_num_traces.py,sha256=lu5EMdQWQzEr_4wCiu7FycnIShjGf0yQXpwBG_DDzGs,1050
121
+ phoenix/server/api/dataloaders/session_num_traces_with_error.py,sha256=Y5xmr4Nme2ZMfvJljW9yhBfuCNdGlxTRka0h9VdXdqA,1149
122
+ phoenix/server/api/dataloaders/session_token_usages.py,sha256=9RXZUyzDmzp5WDp_BpmvvDhk5gIIaV97x0xxUM1H9bA,1586
123
+ phoenix/server/api/dataloaders/session_trace_latency_ms_quantile.py,sha256=s_Ce_BSad1Wvabq9hajdq-i-9rLbZ0esU2gwg9h7Vwg,2157
116
124
  phoenix/server/api/dataloaders/span_annotations.py,sha256=y5TvxnljS2P3hm_NiQd24qy313AG76lyjcZFNWGls1A,1028
117
125
  phoenix/server/api/dataloaders/span_dataset_examples.py,sha256=rpBStVP7ZMIH11Cpq4-zCJ4amNC5ZzX72NYv4vAQTdc,1255
118
126
  phoenix/server/api/dataloaders/span_descendants.py,sha256=1NhD59micO9ozKTF85bFKVCqqsrfDzrK0e0nlg6QyvI,2051
119
127
  phoenix/server/api/dataloaders/span_projects.py,sha256=JTfuKn2BBn72QdAP53ZGP2OUCgZJ7AzlzQAx8WivBog,1234
120
128
  phoenix/server/api/dataloaders/token_counts.py,sha256=9BjumOJ8uCaQ8ZieJVoIP_zEnI38VxyBoB_ks8YrUYU,4629
121
- phoenix/server/api/dataloaders/trace_row_ids.py,sha256=yFv752LmBmOnMYVaauU4v0Y660AnSGJCtD7O-UgKk9Q,1070
129
+ phoenix/server/api/dataloaders/trace_by_trace_ids.py,sha256=xqYJOjCgXlTzour4vY72kO-2gJFgWMjD3759o78cq44,874
130
+ phoenix/server/api/dataloaders/trace_root_spans.py,sha256=IpSsoBRF0NHtbFhQasA_mux6v-m6b0yFRINygjCBOtM,1106
122
131
  phoenix/server/api/dataloaders/user_roles.py,sha256=TvPWve38TlGFvaFkMeFvnnHBn1OMHUJTErRLeYrXR8I,1029
123
132
  phoenix/server/api/dataloaders/users.py,sha256=Uh86Kny_xpqDdEvEklcTBUA_MELgu4Z0jgh45ZqTzXs,1075
124
133
  phoenix/server/api/dataloaders/cache/__init__.py,sha256=SYoOM9n8FJaMdQarma5d1blu-jIg2GB8Shqg5ezSzZ8,106
@@ -155,6 +164,7 @@ phoenix/server/api/input_types/PatchAnnotationInput.py,sha256=NWhkcbcGNPwfOYsN3w
155
164
  phoenix/server/api/input_types/PatchDatasetExamplesInput.py,sha256=_uMqkAInhLDvzUSASl6HgLNulTsekMcYzyd5J6LF90I,884
156
165
  phoenix/server/api/input_types/PatchDatasetInput.py,sha256=OURtTVY8Z_oFEDtKwT1LCMaOK5D4QYo5TVQ6mDrex-g,328
157
166
  phoenix/server/api/input_types/PerformanceMetricInput.py,sha256=fElsLTSEYYgGFGMYTEGcYid39tXUKFdV_JkdHavMcbA,591
167
+ phoenix/server/api/input_types/ProjectSessionSort.py,sha256=qFgLmKYeyFpx7An9ZNdDNkkt7tghrG6XXruQbFLiFt8,919
158
168
  phoenix/server/api/input_types/SpanAnnotationSort.py,sha256=T5pAGzmh4MiJp9JMAzNDByFVTczfw02FH4WFWwFezyI,361
159
169
  phoenix/server/api/input_types/SpanSort.py,sha256=Dhvl8BIoV52yHoqntfOax_gUc15uH8ITI_00Ha7PvYc,5959
160
170
  phoenix/server/api/input_types/TemplateOptions.py,sha256=BrKozr604QwthBdKhlsHbxJc5oZ7eHnwviVubW2i0jA,220
@@ -168,7 +178,7 @@ phoenix/server/api/mutations/chat_mutations.py,sha256=X8Rq0_gBYX_Ey2U9EIuWuOt2Je
168
178
  phoenix/server/api/mutations/dataset_mutations.py,sha256=OkVek-GtDf_1eloI7Sdz6W6l5FFmwU_41LJM8-fw3q4,26088
169
179
  phoenix/server/api/mutations/experiment_mutations.py,sha256=p3CoLAa8nFPa3D759Y2A7De_PVJNGOL98mA3HoZBrRQ,3188
170
180
  phoenix/server/api/mutations/export_events_mutations.py,sha256=xoDnVWC7eA_8wNQP0-oyiHojyUZ0EhVVSrsAnztetC0,3993
171
- phoenix/server/api/mutations/project_mutations.py,sha256=KdcA3c6tgLZ8QhpIv37qJESTBPxs56SbfeYdDKzU7-8,2263
181
+ phoenix/server/api/mutations/project_mutations.py,sha256=u7kLvJbBFR418F9lMamiisZerF18E8h5wGKV4sDTF-g,2674
172
182
  phoenix/server/api/mutations/span_annotations_mutations.py,sha256=kvIOUjHRA6wNMh-bLe5B6bRszMw77HyFp3bxHTOL3yU,5940
173
183
  phoenix/server/api/mutations/trace_annotations_mutations.py,sha256=qwTnYt6A5BwXC7sn_TT0f2A2PO7M26C22aYMnA3MpYk,5915
174
184
  phoenix/server/api/mutations/user_mutations.py,sha256=YWgg1t5P0XVdxOMrhWpRqsCWi8NQR2zxerzuITC-UrY,13311
@@ -222,8 +232,8 @@ phoenix/server/api/types/ExampleRevisionInterface.py,sha256=gV3Gt9-3Oi5wjaVtepC6
222
232
  phoenix/server/api/types/Experiment.py,sha256=hqqIwgeWoylOeBAMmQyzefn_p_COwxW0VqEGOqdcTpE,5470
223
233
  phoenix/server/api/types/ExperimentAnnotationSummary.py,sha256=Uk3JtxIrsMoZT5tqc4nJdUOM3XegVzjUyoV3pkjNotE,256
224
234
  phoenix/server/api/types/ExperimentComparison.py,sha256=cFQZy5rj_klzTV-3jnxIlkrCHXkW8gYnp5uSR1UWCzg,416
225
- phoenix/server/api/types/ExperimentRun.py,sha256=18VDl9ciENRp-yn1_gyCDnTI4TYchG985GuM6hssN7g,4253
226
- phoenix/server/api/types/ExperimentRunAnnotation.py,sha256=iBxDaD9DgiF-Qymp5QyxWfJRGYXM1_CeWA_qzsZBqkI,1812
235
+ phoenix/server/api/types/ExperimentRun.py,sha256=5PjvIx-VLx-W9Xw8JURbbfOYYIL-FAaZs1kyJB0icp4,4169
236
+ phoenix/server/api/types/ExperimentRunAnnotation.py,sha256=HEbPygBwbWg10fwY3VZyM10OL1TKlnQk_x5MZIjZKPs,1724
227
237
  phoenix/server/api/types/ExportedFile.py,sha256=e3GTn7B5LgsTbqiwjhMCQH7VsiqXitrBO4aCMS1lHsg,163
228
238
  phoenix/server/api/types/Functionality.py,sha256=tzV9xdhB8zqfsjWxP66NDC7EZsplYkYO7jRbLWJIeeg,382
229
239
  phoenix/server/api/types/GenerativeModel.py,sha256=P7eBUMXbeqaLwSSGBKdZy3a5gOLd9I0fuP8o1st6H08,193
@@ -235,18 +245,21 @@ phoenix/server/api/types/MimeType.py,sha256=Zpi6zCalkSFgsvhzvOs-O1gYA04usAi9H__Q
235
245
  phoenix/server/api/types/Model.py,sha256=dirXGnOqLFNaOlXUwqyAjiJjcOrWpryO_5N6V0pAxtk,8045
236
246
  phoenix/server/api/types/NumericRange.py,sha256=afEjgF97Go_OvmjMggbPBt-zGM8IONewAyEiKEHRds0,192
237
247
  phoenix/server/api/types/PerformanceMetric.py,sha256=W92B7OghEOgzFvmY0LCqpgavHaQggTGshdgfD0yqHX4,350
238
- phoenix/server/api/types/Project.py,sha256=tNTiDgbjUTVm45XxmMhHYSjqBI8WjHim9NZ69SfMA8w,13107
248
+ phoenix/server/api/types/Project.py,sha256=xbV15SOHcPQeE1TMSWFpXk7ZQkfxCD4ZjFS4C83K4tU,18852
249
+ phoenix/server/api/types/ProjectSession.py,sha256=j3RJrTG9umruav7d81AqnQVz-Zpi60nXmnsr2Wplpac,4646
239
250
  phoenix/server/api/types/PromptResponse.py,sha256=Q8HKtpp8GpUOcxPCzZpkkokidDd6u0aZOv_SuPZZd5Q,630
240
251
  phoenix/server/api/types/Retrieval.py,sha256=OhMK2ncjoyp5h1yjKhjlKpoTbQrMHuxmgSFw-AO1rWw,285
241
252
  phoenix/server/api/types/ScalarDriftMetricEnum.py,sha256=IUAcRPpgL41WdoIgK6cNk2Te38SspXGyEs-S1fY23_A,232
242
253
  phoenix/server/api/types/Segments.py,sha256=vT2v0efoa5cuBKxLtxTnsUP5YJJCZfTloM71Spu0tMI,2915
243
254
  phoenix/server/api/types/SortDir.py,sha256=OUpXhlCzCxPoXSDkJJygEs9Rw9pMymfaZUG5zPTrw4Y,152
244
- phoenix/server/api/types/Span.py,sha256=wJGvenSL6d1oDmpJt4hsLjIVTxmemJBRCBKHy4rYztc,15355
255
+ phoenix/server/api/types/Span.py,sha256=3vMWnCH0w7-lytq9fVpD0oWIfC-4huS5U6lOaoTSPrA,15113
245
256
  phoenix/server/api/types/SpanAnnotation.py,sha256=6b5G-b_OoRvDL2ayWk7MkbqarLK-F-pQMx21CpUuNGY,1168
257
+ phoenix/server/api/types/SpanIOValue.py,sha256=u_g9QrX-E3fwneoucire73KY5gf3fE4V9IBN3qx2cvU,445
246
258
  phoenix/server/api/types/SystemApiKey.py,sha256=2ym8EgsTBIvxx1l9xZ-2YMovz58ZwYb_MaHBTJ9NH2E,166
247
259
  phoenix/server/api/types/TemplateLanguage.py,sha256=6j_0uwO_GZIeCpR7sTOnxySXudT7qBSC6LFsjzbvW1o,160
248
260
  phoenix/server/api/types/TimeSeries.py,sha256=IIeGVRFdSMozYXxPg736DW_mKvj4-3WjYSYEnn4UEJc,5241
249
- phoenix/server/api/types/Trace.py,sha256=1RrdEedlPpNmWkQwosOZ81fabc9-B6PDHTYpr-hZj-Y,3240
261
+ phoenix/server/api/types/TokenUsage.py,sha256=g-PjAGVigpchQgkXAuC5sc53fn2YwAgfeXkGmFPi_TE,201
262
+ phoenix/server/api/types/Trace.py,sha256=PG07x8h1VjYNkE40EK2SJHMW1TRWBoguJS6vPjmJOy8,5217
250
263
  phoenix/server/api/types/TraceAnnotation.py,sha256=OW6A2zr1gomOuG0XQe55dk15XXX2DSM0DzatRbHWH5A,1256
251
264
  phoenix/server/api/types/UMAPPoints.py,sha256=49sWnxjcAJKRzqUY71Fa0tOPti5XjIIFT5cSg6oNu_U,1650
252
265
  phoenix/server/api/types/User.py,sha256=iTVUrI8U6-asOhBt1bOZNtoRAaRNC4WHgR1Uv2rHnWQ,1975
@@ -273,16 +286,16 @@ phoenix/server/static/apple-touch-icon-76x76.png,sha256=CT_xT12I0u2i0WU8JzBZBuOQ
273
286
  phoenix/server/static/apple-touch-icon.png,sha256=fOfpjqGpWYbJ0eAurKsyoZP1EAs6ZVooBJ_SGk2ZkDs,3801
274
287
  phoenix/server/static/favicon.ico,sha256=bY0vvCKRftemZfPShwZtE93DiiQdaYaozkPGwNFr6H8,34494
275
288
  phoenix/server/static/modernizr.js,sha256=mvK-XtkNqjOral-QvzoqsyOMECXIMu5BQwSVN_wcU9c,2564
276
- phoenix/server/static/.vite/manifest.json,sha256=OHnaSfFCgMjSBfa90MdnYJDMisFjQ0KsBhgAJqRxCXo,2163
277
- phoenix/server/static/assets/components-DrwPLMB6.js,sha256=8Z11dkkE4K_rxpp63EcjuRXrq7HhCiRWPnqP9k10kMo,316774
278
- phoenix/server/static/assets/index-CTN-OfBU.js,sha256=F5Q2Ru7h1CGEA_nJCVjXpzNhbH5DxudUB6NnCwHFZt0,7954
279
- phoenix/server/static/assets/pages-Cmqh2i4E.js,sha256=GI_-PAJ9vx1c3_tZxgmmtXke31-baxkeI3pbk6Suv3s,632754
280
- phoenix/server/static/assets/vendor-Cdrqqth8.js,sha256=XSrmzfFJlLftuuErU4XHtyYlKYyjh0QWF57SHxkF40c,2061915
289
+ phoenix/server/static/.vite/manifest.json,sha256=H-INZnWsmbWImSRNUMxk97n_Gp3Q7kUXeNZme12yLPM,2163
290
+ phoenix/server/static/assets/components-DKH6AzJw.js,sha256=RWkQPJgVGgZqEzBaCuKcxc19e24pfbjaEjwWdxbrkSY,316783
291
+ phoenix/server/static/assets/index-DLV87qiO.js,sha256=F-cdG02QreiLbNUM0Vcp1PTBfjyaHH2XXzHamQ6syQY,8033
292
+ phoenix/server/static/assets/pages-CVY3Nv4Z.js,sha256=QzdU8hUVKqys5cST3gmMy0bNjShoKGbL6btLMoT3cnc,669246
293
+ phoenix/server/static/assets/vendor-Cb3zlNNd.js,sha256=4yHqkg-jnECjHY3bA_-aYIK8paH4j0vY5Vx0qkaW_OU,2061939
281
294
  phoenix/server/static/assets/vendor-DxkFTwjz.css,sha256=nZrkr0u6NNElFGvpWHk9GTHeGoibCXCli1bE7mXZGZg,1816
282
- phoenix/server/static/assets/vendor-arizeai-BSCL03yQ.js,sha256=Dc98gjSV20cL0_jum75PB6YzkxVrjjmWBIWUjZOW4CE,308489
283
- phoenix/server/static/assets/vendor-codemirror-Utqu7Snw.js,sha256=yakF-gdRQqJHvaxwXGwCq57p6ETOTqvbTFQf4kx7pt8,392748
284
- phoenix/server/static/assets/vendor-recharts-CNNUvc5T.js,sha256=RwJTuhF_tFrGfEKZEIbnWxXP6_IoWKuFtALElwXyzUc,282859
285
- phoenix/server/static/assets/vendor-shiki-B6bHerDK.js,sha256=X1XflS-vSyEn9DOgrz0CyvVlkm0BAxvfDW8b_1852UI,8980328
295
+ phoenix/server/static/assets/vendor-arizeai-Buo4e1A6.js,sha256=gDkYYjDuuj7Qt18ZzrQriCjh3pLiqQjyzdYPcrRnmLs,308489
296
+ phoenix/server/static/assets/vendor-codemirror-BuAQiUVf.js,sha256=BwKGD-l2CFA_RJ6J908ykmJkbYR4STxh9Cq3VnIoitg,392748
297
+ phoenix/server/static/assets/vendor-recharts-Cl9dK5tC.js,sha256=02BDRWrMBNjAqY68qazFHrrSIxR_0r1rSlcJChH-ZrU,282859
298
+ phoenix/server/static/assets/vendor-shiki-CazYUixL.js,sha256=yo1zcws-X4sfuIlakSqCUAqp-ohj0OfjXdZC9nzu9oE,8980328
286
299
  phoenix/server/static/assets/vendor-three-DwGkEfCM.js,sha256=0D12ZgKzfKCTSdSTKJBFR2RZO_xxeMXrqDp0AszZqHY,620972
287
300
  phoenix/server/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
288
301
  phoenix/server/templates/index.html,sha256=ram6sfy2obf_F053ay35V30v-mnRWZ86rK-PstXLy1c,4457
@@ -296,10 +309,10 @@ phoenix/trace/attributes.py,sha256=mHpOtdjGIs-VGSev_dwvxTeZTc9GILovi1Rdnj56HO0,1
296
309
  phoenix/trace/errors.py,sha256=wB1z8qdPckngdfU-TORToekvg3344oNFAA83_hC2yFY,180
297
310
  phoenix/trace/evaluation_conventions.py,sha256=t8jydM3U0-T5YpiQKRJ3tWdWGlHtzKyttYdw-ddvPOk,1048
298
311
  phoenix/trace/exporter.py,sha256=bUXh8fjJIbHurrnt4bAm-cCWqUN5FqNsIc8DZzzklkQ,4695
299
- phoenix/trace/fixtures.py,sha256=bwDD0rgIRdAi_9zwLLipke50oYuKJvZLvhiGsuvnGbs,19169
312
+ phoenix/trace/fixtures.py,sha256=k5gduf21C5NbZx95O_WB7mqGnrRiig0ti2VVYQiB9vo,19537
300
313
  phoenix/trace/otel.py,sha256=FZGzo0NPJqFBLkL_VmQeBne2z-LdHNPTz3oIZOuPPzQ,9997
301
314
  phoenix/trace/projects.py,sha256=9dKv1aiKL4IYMFsg2xnC6EOIRO0YHtkR5o9ALHbMK9g,2178
302
- phoenix/trace/schemas.py,sha256=0tghsJDaLKvSuxDDQGpUEQ0HkMsKmFWPO3lwJrJ9t84,5972
315
+ phoenix/trace/schemas.py,sha256=Su6e567Bei9oo6PsWO2srTcPAj9C2bMgbGtx64Sgqeg,6332
303
316
  phoenix/trace/span_evaluations.py,sha256=x3nye9r2SQk1mrR3N05YbuWsgUKpMWwTRBtJTDBSj3Y,13156
304
317
  phoenix/trace/span_json_decoder.py,sha256=J1_oDViuUoC4vxPg61U4EOZC1uEMcCzoj-kVjOFEE8k,3224
305
318
  phoenix/trace/span_json_encoder.py,sha256=Wa7RvQTZSsFG4pdKSSFSO_4q4DjAOQuG8wLNJvYzsfM,2004
@@ -323,9 +336,9 @@ phoenix/utilities/project.py,sha256=auVpARXkDb-JgeX5f2aStyFIkeKvGwN9l7qrFeJMVxI,
323
336
  phoenix/utilities/re.py,sha256=x8Xbk-Wa6qDMAtUd_7JtZvKtrYEuMY-bchB0n163_5c,2006
324
337
  phoenix/utilities/span_store.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
325
338
  phoenix/utilities/template_formatters.py,sha256=gh9PJD6WEGw7TEYXfSst1UR4pWWwmjxMLrDVQ_CkpkQ,2779
326
- arize_phoenix-6.2.0.dist-info/METADATA,sha256=7PdpBWXytNhusx8KpjVhN3BtROpDGm6qF2SvpM1Cy4g,23173
327
- arize_phoenix-6.2.0.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
328
- arize_phoenix-6.2.0.dist-info/entry_points.txt,sha256=Pgpn8Upxx9P8z8joPXZWl2LlnAlGc3gcQoVchb06X1Q,94
329
- arize_phoenix-6.2.0.dist-info/licenses/IP_NOTICE,sha256=JBqyyCYYxGDfzQ0TtsQgjts41IJoa-hiwDrBjCb9gHM,469
330
- arize_phoenix-6.2.0.dist-info/licenses/LICENSE,sha256=HFkW9REuMOkvKRACuwLPT0hRydHb3zNg-fdFt94td18,3794
331
- arize_phoenix-6.2.0.dist-info/RECORD,,
339
+ arize_phoenix-7.0.0.dist-info/METADATA,sha256=JewxawzwVoqTyW-sdqRFKimVnbpgX7UtZfUV3c878SY,23173
340
+ arize_phoenix-7.0.0.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
341
+ arize_phoenix-7.0.0.dist-info/entry_points.txt,sha256=Pgpn8Upxx9P8z8joPXZWl2LlnAlGc3gcQoVchb06X1Q,94
342
+ arize_phoenix-7.0.0.dist-info/licenses/IP_NOTICE,sha256=JBqyyCYYxGDfzQ0TtsQgjts41IJoa-hiwDrBjCb9gHM,469
343
+ arize_phoenix-7.0.0.dist-info/licenses/LICENSE,sha256=HFkW9REuMOkvKRACuwLPT0hRydHb3zNg-fdFt94td18,3794
344
+ arize_phoenix-7.0.0.dist-info/RECORD,,
@@ -28,42 +28,77 @@ async def insert_span(
28
28
  dialect = SupportedSQLDialect(session.bind.dialect.name)
29
29
  if (
30
30
  project_rowid := await session.scalar(
31
- select(models.Project.id).where(models.Project.name == project_name)
31
+ select(models.Project.id).filter_by(name=project_name)
32
32
  )
33
33
  ) is None:
34
34
  project_rowid = await session.scalar(
35
- insert(models.Project).values(dict(name=project_name)).returning(models.Project.id)
35
+ insert(models.Project).values(name=project_name).returning(models.Project.id)
36
36
  )
37
37
  assert project_rowid is not None
38
- if trace := await session.scalar(
39
- select(models.Trace).where(models.Trace.trace_id == span.context.trace_id)
40
- ):
41
- trace_rowid = trace.id
42
- if span.start_time < trace.start_time or trace.end_time < span.end_time:
43
- trace_start_time = min(trace.start_time, span.start_time)
44
- trace_end_time = max(trace.end_time, span.end_time)
45
- await session.execute(
46
- update(models.Trace)
47
- .where(models.Trace.id == trace_rowid)
48
- .values(
49
- start_time=trace_start_time,
50
- end_time=trace_end_time,
51
- )
52
- )
38
+
39
+ trace_id = span.context.trace_id
40
+ trace: models.Trace = await session.scalar(
41
+ select(models.Trace).filter_by(trace_id=trace_id)
42
+ ) or models.Trace(trace_id=trace_id)
43
+
44
+ if trace.id is not None:
45
+ # Trace record may need to be updated.
46
+ if trace.end_time < span.end_time:
47
+ trace.end_time = span.end_time
48
+ trace.project_rowid = project_rowid
49
+ if span.start_time < trace.start_time:
50
+ trace.start_time = span.start_time
53
51
  else:
54
- trace_rowid = cast(
55
- int,
56
- await session.scalar(
57
- insert(models.Trace)
58
- .values(
59
- project_rowid=project_rowid,
60
- trace_id=span.context.trace_id,
61
- start_time=span.start_time,
62
- end_time=span.end_time,
63
- )
64
- .returning(models.Trace.id)
65
- ),
52
+ # Trace record needs to be persisted for the first time.
53
+ trace.start_time = span.start_time
54
+ trace.end_time = span.end_time
55
+ trace.project_rowid = project_rowid
56
+ session.add(trace)
57
+
58
+ session_id = get_attribute_value(span.attributes, SpanAttributes.SESSION_ID)
59
+ session_id = str(session_id).strip() if session_id is not None else ""
60
+ assert isinstance(session_id, str)
61
+
62
+ project_session: Optional[models.ProjectSession] = None
63
+ if trace.project_session_rowid is not None:
64
+ # ProjectSession record already exists in database for this Trace record, so we fetch
65
+ # it because it may need to be updated. However, the session_id on the span, if exists,
66
+ # will be ignored at this point. Otherwise, if session_id is different, we will need
67
+ # to create a new ProjectSession record, as well as to determine whether the old record
68
+ # needs to be deleted if this is the last Trace associated with it.
69
+ project_session = await session.scalar(
70
+ select(models.ProjectSession).filter_by(id=trace.project_session_rowid)
66
71
  )
72
+ elif session_id:
73
+ project_session = await session.scalar(
74
+ select(models.ProjectSession).filter_by(session_id=session_id)
75
+ ) or models.ProjectSession(session_id=session_id)
76
+
77
+ if project_session is not None:
78
+ if project_session.id is None:
79
+ # ProjectSession record needs to be persisted for the first time.
80
+ project_session.start_time = trace.start_time
81
+ project_session.end_time = trace.end_time
82
+ project_session.project_id = project_rowid
83
+ session.add(project_session)
84
+ await session.flush()
85
+ assert project_session.id is not None
86
+ trace.project_session_rowid = project_session.id
87
+ else:
88
+ # ProjectSession record may need to be updated.
89
+ if trace.project_session_rowid is None:
90
+ trace.project_session_rowid = project_session.id
91
+ if trace.start_time < project_session.start_time:
92
+ project_session.start_time = trace.start_time
93
+ if project_session.end_time < trace.end_time:
94
+ project_session.end_time = trace.end_time
95
+
96
+ await session.flush()
97
+ assert trace.id is not None
98
+ assert project_session is None or (
99
+ project_session.id is not None and project_session.id == trace.project_session_rowid
100
+ )
101
+
67
102
  cumulative_error_count = int(span.status_code is SpanStatusCode.ERROR)
68
103
  cumulative_llm_token_count_prompt = cast(
69
104
  int, get_attribute_value(span.attributes, SpanAttributes.LLM_TOKEN_COUNT_PROMPT) or 0
@@ -94,7 +129,7 @@ async def insert_span(
94
129
  insert_on_conflict(
95
130
  dict(
96
131
  span_id=span.context.span_id,
97
- trace_rowid=trace_rowid,
132
+ trace_rowid=trace.id,
98
133
  parent_id=span.parent_id,
99
134
  span_kind=span.span_kind.value,
100
135
  name=span.name,
@@ -0,0 +1,199 @@
1
+ # /// script
2
+ # dependencies = [
3
+ # "arize-phoenix[pg]",
4
+ # ]
5
+ # ///
6
+ """
7
+ Populate the `project_sessions` table with data from the traces and spans tables.
8
+
9
+ Environment variables.
10
+
11
+ - `PHOENIX_SQL_DATABASE_URL` must be set to the database connection string.
12
+ - (optional) Postgresql schema can be set via `PHOENIX_SQL_DATABASE_SCHEMA`.
13
+ """
14
+
15
+ import os
16
+ from datetime import datetime
17
+ from time import perf_counter
18
+ from typing import Any, Optional, Union
19
+
20
+ import sqlean
21
+ from openinference.semconv.trace import SpanAttributes
22
+ from sqlalchemy import (
23
+ JSON,
24
+ Engine,
25
+ NullPool,
26
+ create_engine,
27
+ event,
28
+ func,
29
+ insert,
30
+ make_url,
31
+ select,
32
+ update,
33
+ )
34
+ from sqlalchemy.dialects import postgresql
35
+ from sqlalchemy.ext.compiler import compiles
36
+ from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, sessionmaker
37
+
38
+ from phoenix.config import ENV_PHOENIX_SQL_DATABASE_SCHEMA, get_env_database_connection_str
39
+ from phoenix.db.engines import set_postgresql_search_path
40
+
41
+
42
+ class JSONB(JSON):
43
+ # See https://docs.sqlalchemy.org/en/20/core/custom_types.html
44
+ __visit_name__ = "JSONB"
45
+
46
+
47
+ @compiles(JSONB, "sqlite")
48
+ def _(*args: Any, **kwargs: Any) -> str:
49
+ # See https://docs.sqlalchemy.org/en/20/core/custom_types.html
50
+ return "JSONB"
51
+
52
+
53
+ JSON_ = (
54
+ JSON()
55
+ .with_variant(
56
+ postgresql.JSONB(), # type: ignore
57
+ "postgresql",
58
+ )
59
+ .with_variant(
60
+ JSONB(),
61
+ "sqlite",
62
+ )
63
+ )
64
+
65
+
66
+ class Base(DeclarativeBase): ...
67
+
68
+
69
+ class ProjectSession(Base):
70
+ __tablename__ = "project_sessions"
71
+ id: Mapped[int] = mapped_column(primary_key=True)
72
+ session_id: Mapped[str]
73
+ project_id: Mapped[int]
74
+ start_time: Mapped[datetime]
75
+ end_time: Mapped[datetime]
76
+
77
+
78
+ class Trace(Base):
79
+ __tablename__ = "traces"
80
+ id: Mapped[int] = mapped_column(primary_key=True)
81
+ project_session_rowid: Mapped[Union[int, None]]
82
+ project_rowid: Mapped[int]
83
+ start_time: Mapped[datetime]
84
+ end_time: Mapped[datetime]
85
+
86
+
87
+ class Span(Base):
88
+ __tablename__ = "spans"
89
+ id: Mapped[int] = mapped_column(primary_key=True)
90
+ trace_rowid: Mapped[int]
91
+ parent_id: Mapped[Optional[str]]
92
+ attributes: Mapped[dict[str, Any]] = mapped_column(JSON_, nullable=False)
93
+
94
+
95
+ SESSION_ID = SpanAttributes.SESSION_ID.split(".")
96
+ USER_ID = SpanAttributes.USER_ID.split(".")
97
+
98
+
99
+ def populate_project_sessions(
100
+ engine: Engine,
101
+ ) -> None:
102
+ sessions_from_span = (
103
+ select(
104
+ Span.attributes[SESSION_ID].as_string().label("session_id"),
105
+ Trace.project_rowid.label("project_id"),
106
+ Trace.start_time.label("start_time"),
107
+ func.row_number()
108
+ .over(
109
+ partition_by=Span.attributes[SESSION_ID],
110
+ order_by=[Trace.start_time, Trace.id, Span.id],
111
+ )
112
+ .label("rank"),
113
+ func.max(Trace.end_time)
114
+ .over(partition_by=Span.attributes[SESSION_ID])
115
+ .label("end_time"),
116
+ )
117
+ .join_from(Span, Trace, Span.trace_rowid == Trace.id)
118
+ .where(Span.parent_id.is_(None))
119
+ .where(Span.attributes[SESSION_ID].as_string() != "")
120
+ .subquery()
121
+ )
122
+ sessions_for_trace_id = (
123
+ select(
124
+ Span.trace_rowid,
125
+ ProjectSession.id.label("project_session_rowid"),
126
+ )
127
+ .join_from(
128
+ Span,
129
+ ProjectSession,
130
+ Span.attributes[SESSION_ID].as_string() == ProjectSession.session_id,
131
+ )
132
+ .where(Span.parent_id.is_(None))
133
+ .where(Span.attributes[SESSION_ID].as_string() != "")
134
+ .subquery()
135
+ )
136
+ start_time = perf_counter()
137
+ with sessionmaker(engine).begin() as session:
138
+ session.execute(
139
+ insert(ProjectSession).from_select(
140
+ [
141
+ "session_id",
142
+ "project_id",
143
+ "start_time",
144
+ "end_time",
145
+ ],
146
+ select(
147
+ sessions_from_span.c.session_id,
148
+ sessions_from_span.c.project_id,
149
+ sessions_from_span.c.start_time,
150
+ sessions_from_span.c.end_time,
151
+ ).where(sessions_from_span.c.rank == 1),
152
+ )
153
+ )
154
+ session.execute(
155
+ (
156
+ update(Trace)
157
+ .values(project_session_rowid=sessions_for_trace_id.c.project_session_rowid)
158
+ .where(Trace.id == sessions_for_trace_id.c.trace_rowid)
159
+ )
160
+ )
161
+ elapsed_time = perf_counter() - start_time
162
+ print(f"✅ Populated project_sessions in {elapsed_time:.3f} seconds.")
163
+
164
+
165
+ if __name__ == "__main__":
166
+ sql_database_url = make_url(get_env_database_connection_str())
167
+ print(f"Using database URL: {sql_database_url}")
168
+ ans = input("Is that correct? [y]/n: ")
169
+ if ans.lower().startswith("n"):
170
+ url = input("Please enter the correct database URL: ")
171
+ sql_database_url = make_url(url)
172
+ backend = sql_database_url.get_backend_name()
173
+ if backend == "sqlite":
174
+ file = sql_database_url.database
175
+ engine = create_engine(
176
+ url=sql_database_url.set(drivername="sqlite"),
177
+ creator=lambda: sqlean.connect(f"file:///{file}", uri=True),
178
+ poolclass=NullPool,
179
+ echo=True,
180
+ )
181
+ elif backend == "postgresql":
182
+ schema = os.getenv(ENV_PHOENIX_SQL_DATABASE_SCHEMA)
183
+ if schema:
184
+ print(f"Using schema: {schema}")
185
+ else:
186
+ print("No PostgreSQL schema set. (This is the default.)")
187
+ ans = input("Is that correct? [y]/n: ")
188
+ if ans.lower().startswith("n"):
189
+ schema = input("Please enter the correct schema: ")
190
+ engine = create_engine(
191
+ url=sql_database_url.set(drivername="postgresql+psycopg"),
192
+ poolclass=NullPool,
193
+ echo=True,
194
+ )
195
+ if schema:
196
+ event.listen(engine, "connect", set_postgresql_search_path(schema))
197
+ else:
198
+ raise ValueError(f"Unknown database backend: {backend}")
199
+ populate_project_sessions(engine)
@@ -0,0 +1,66 @@
1
+ """create project_session table
2
+
3
+ Revision ID: 4ded9e43755f
4
+ Revises: cd164e83824f
5
+ Create Date: 2024-10-08 22:53:24.539786
6
+
7
+ """
8
+
9
+ from typing import Sequence, Union
10
+
11
+ import sqlalchemy as sa
12
+ from alembic import op
13
+
14
+ # revision identifiers, used by Alembic.
15
+ revision: str = "4ded9e43755f"
16
+ down_revision: Union[str, None] = "cd164e83824f"
17
+ branch_labels: Union[str, Sequence[str], None] = None
18
+ depends_on: Union[str, Sequence[str], None] = None
19
+
20
+
21
+ def upgrade() -> None:
22
+ op.create_table(
23
+ "project_sessions",
24
+ sa.Column("id", sa.Integer, primary_key=True),
25
+ sa.Column("session_id", sa.String, unique=True, nullable=False),
26
+ sa.Column(
27
+ "project_id",
28
+ sa.Integer,
29
+ sa.ForeignKey("projects.id", ondelete="CASCADE"),
30
+ nullable=False,
31
+ index=True,
32
+ ),
33
+ sa.Column(
34
+ "start_time",
35
+ sa.TIMESTAMP(timezone=True),
36
+ index=True,
37
+ nullable=False,
38
+ ),
39
+ sa.Column(
40
+ "end_time",
41
+ sa.TIMESTAMP(timezone=True),
42
+ index=True,
43
+ nullable=False,
44
+ ),
45
+ )
46
+ with op.batch_alter_table("traces") as batch_op:
47
+ batch_op.add_column(
48
+ sa.Column(
49
+ "project_session_rowid",
50
+ sa.Integer,
51
+ sa.ForeignKey("project_sessions.id", ondelete="CASCADE"),
52
+ nullable=True,
53
+ ),
54
+ )
55
+ op.create_index(
56
+ "ix_traces_project_session_rowid",
57
+ "traces",
58
+ ["project_session_rowid"],
59
+ )
60
+
61
+
62
+ def downgrade() -> None:
63
+ op.drop_index("ix_traces_project_session_rowid")
64
+ with op.batch_alter_table("traces") as batch_op:
65
+ batch_op.drop_column("project_session_rowid")
66
+ op.drop_table("project_sessions")