arize-phoenix 5.10.0__py3-none-any.whl → 5.11.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.
- {arize_phoenix-5.10.0.dist-info → arize_phoenix-5.11.0.dist-info}/METADATA +2 -1
- {arize_phoenix-5.10.0.dist-info → arize_phoenix-5.11.0.dist-info}/RECORD +23 -23
- phoenix/config.py +13 -0
- phoenix/db/facilitator.py +3 -2
- phoenix/server/api/helpers/playground_clients.py +29 -13
- phoenix/server/api/helpers/playground_spans.py +6 -0
- phoenix/server/api/mutations/chat_mutations.py +75 -34
- phoenix/server/api/subscriptions.py +108 -49
- phoenix/server/static/.vite/manifest.json +31 -31
- phoenix/server/static/assets/{components-BXIz9ZO8.js → components-C_HASv83.js} +90 -90
- phoenix/server/static/assets/{index-DTut7g1y.js → index-D7UiCRtr.js} +2 -2
- phoenix/server/static/assets/{pages-B8FpJuXu.js → pages-DYHcAdjT.js} +313 -264
- phoenix/server/static/assets/{vendor-BX8_Znqy.js → vendor-BCxsh5i3.js} +150 -150
- phoenix/server/static/assets/{vendor-arizeai-CtHir-Ua.js → vendor-arizeai-C2CDZgMz.js} +28 -28
- phoenix/server/static/assets/{vendor-codemirror-DLlGiguX.js → vendor-codemirror-DYbtnCTn.js} +1 -1
- phoenix/server/static/assets/{vendor-recharts-CJRple0d.js → vendor-recharts-P6W8G0Mb.js} +1 -1
- phoenix/trace/span_evaluations.py +4 -3
- phoenix/utilities/json.py +7 -1
- phoenix/version.py +1 -1
- {arize_phoenix-5.10.0.dist-info → arize_phoenix-5.11.0.dist-info}/WHEEL +0 -0
- {arize_phoenix-5.10.0.dist-info → arize_phoenix-5.11.0.dist-info}/entry_points.txt +0 -0
- {arize_phoenix-5.10.0.dist-info → arize_phoenix-5.11.0.dist-info}/licenses/IP_NOTICE +0 -0
- {arize_phoenix-5.10.0.dist-info → arize_phoenix-5.11.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: arize-phoenix
|
|
3
|
-
Version: 5.
|
|
3
|
+
Version: 5.11.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
|
|
@@ -53,6 +53,7 @@ Requires-Dist: wrapt
|
|
|
53
53
|
Provides-Extra: container
|
|
54
54
|
Requires-Dist: anthropic; extra == 'container'
|
|
55
55
|
Requires-Dist: fast-hdbscan>=0.2.0; extra == 'container'
|
|
56
|
+
Requires-Dist: google-generativeai; extra == 'container'
|
|
56
57
|
Requires-Dist: numba>=0.60.0; extra == 'container'
|
|
57
58
|
Requires-Dist: openai>=1.0.0; extra == 'container'
|
|
58
59
|
Requires-Dist: opentelemetry-exporter-otlp; extra == 'container'
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
phoenix/__init__.py,sha256=X3eUEwd2rG8KKWWYVNNDJoqo08ihfjgHhlP29dcdNJE,5481
|
|
2
2
|
phoenix/auth.py,sha256=JpkwJbis2INlIXWcQ-M_Nk5Ln9LBgHMdWNnaAQp0D2w,10940
|
|
3
|
-
phoenix/config.py,sha256=
|
|
3
|
+
phoenix/config.py,sha256=QLaKuc7N3qZsaAzJnsUVyFuWaROYTVlZsVXTr0Re6d8,26191
|
|
4
4
|
phoenix/datetime_utils.py,sha256=iJzNG6YJ6V7_u8B2iA7P2Z26FyxYbOPtx0dhJ7kNDHA,3398
|
|
5
5
|
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=
|
|
9
|
+
phoenix/version.py,sha256=6_DlfgAX4MBZnyPuaEthIkiqPKB1Zz3_f4Z2L40k-Ws,23
|
|
10
10
|
phoenix/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
11
11
|
phoenix/core/embedding_dimension.py,sha256=zKGbcvwOXgLf-yrJBpQyKtd-LEOPRKHnUToyAU8Owis,87
|
|
12
12
|
phoenix/core/model.py,sha256=qBFraOtmwCCnWJltKNP18DDG0mULXigytlFsa6YOz6k,4837
|
|
@@ -18,7 +18,7 @@ phoenix/db/alembic.ini,sha256=GIS6HpHaKaJbbuahZg1Rc1D2_QqyCkV9r58wdARGf6w,3262
|
|
|
18
18
|
phoenix/db/bulk_inserter.py,sha256=faNjuwLqqsw4ky8sa4D0h9u5TvEDTOjrccUW89L008E,12725
|
|
19
19
|
phoenix/db/engines.py,sha256=BYFiHFGABtNuCo7OB8fLc46gMxur4rePK_sJxrMrMjA,6508
|
|
20
20
|
phoenix/db/enums.py,sha256=tt7iovXLhVTLZ3_LbHNGgcI44SnNjXfkKtLAZG57T54,428
|
|
21
|
-
phoenix/db/facilitator.py,sha256=
|
|
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=lf6FFGzdyNjwtQ4TFi3mmHNGnnazMtG30PPB2qRF1Xc,2648
|
|
24
24
|
phoenix/db/models.py,sha256=wx2XQgf6qhUO2ZQ4oUENoAguf440qaR0Ea_q1XB1bBU,26484
|
|
@@ -94,7 +94,7 @@ phoenix/server/api/exceptions.py,sha256=TA0JuY2YRnj35qGuMSQ8d0ToHum9gWm9W--3fSKH
|
|
|
94
94
|
phoenix/server/api/interceptor.py,sha256=ykDnoC_apUd-llVli3m1CW18kNSIgjz2qZ6m5JmPDu8,1294
|
|
95
95
|
phoenix/server/api/queries.py,sha256=4KJz8TUz3VUTup9MDjr_GoKX0SttWSvHBq2ncWZGxf8,27343
|
|
96
96
|
phoenix/server/api/schema.py,sha256=tHyw2jTbue_-gu0fe9Sw7LUYtzJUCwp9SvccDgOkNPw,1696
|
|
97
|
-
phoenix/server/api/subscriptions.py,sha256=
|
|
97
|
+
phoenix/server/api/subscriptions.py,sha256=HPb5agJPMPBM_v_sHjiwe7hwMAHsBsrKZZMLq5bxhcw,22062
|
|
98
98
|
phoenix/server/api/utils.py,sha256=quCBRcusc6PUq9tJq7M8PgwFZp7nXgVAxtbw8feribY,833
|
|
99
99
|
phoenix/server/api/dataloaders/__init__.py,sha256=jNYvfXjnZzgA2HWTG7AZdqWGla3ZysBUDUei8Zkz6N8,3290
|
|
100
100
|
phoenix/server/api/dataloaders/annotation_summaries.py,sha256=2sHmIDX7n8tuPeBTs9bMKtlMKWn_Ph9awTZqmwn2Owc,5505
|
|
@@ -125,9 +125,9 @@ phoenix/server/api/dataloaders/cache/__init__.py,sha256=SYoOM9n8FJaMdQarma5d1blu
|
|
|
125
125
|
phoenix/server/api/dataloaders/cache/two_tier_cache.py,sha256=cmo8FUT3E91R139IEzh4yCga-6nTamc5KPXAfMrzNDM,2315
|
|
126
126
|
phoenix/server/api/helpers/__init__.py,sha256=m2-xaSPqUiSs91k62JaRDjFNfl-1byxBfY-m_Vxw16U,272
|
|
127
127
|
phoenix/server/api/helpers/dataset_helpers.py,sha256=14mldZp9to3rr9BdvvoFqEwZHHV_k2e7jPm8q9z2OdQ,6896
|
|
128
|
-
phoenix/server/api/helpers/playground_clients.py,sha256=
|
|
128
|
+
phoenix/server/api/helpers/playground_clients.py,sha256=fTWY883qVNCK_IkiYm1yxFx3GaXMWhalMeV0zYzIyUM,37407
|
|
129
129
|
phoenix/server/api/helpers/playground_registry.py,sha256=CPLMziFB2wmr-dfbx7VbzO2f8YIG_k5RftzvGXYGQ1w,2570
|
|
130
|
-
phoenix/server/api/helpers/playground_spans.py,sha256=
|
|
130
|
+
phoenix/server/api/helpers/playground_spans.py,sha256=LJjndkVxr6DsfVFerrtMZWlRd5YL5AIbcM2CvFe8ajc,16489
|
|
131
131
|
phoenix/server/api/input_types/AddExamplesToDatasetInput.py,sha256=mIQz0S_z8YdrktKIY6RCvtNJ2yZF9pYvTGgasUsI-54,430
|
|
132
132
|
phoenix/server/api/input_types/AddSpansToDatasetInput.py,sha256=-StSstyMAVrba3tG1U30b-srkKCtu_svflQuSM19iJA,362
|
|
133
133
|
phoenix/server/api/input_types/ChatCompletionInput.py,sha256=g_5ARuwylt-uCVAsGyZPEVtidEQiOhbKakvDQsZumzw,1451
|
|
@@ -164,7 +164,7 @@ phoenix/server/api/input_types/UserRoleInput.py,sha256=xxhFe0ITZOgRVEJbVem_W6F1I
|
|
|
164
164
|
phoenix/server/api/input_types/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
165
165
|
phoenix/server/api/mutations/__init__.py,sha256=1wClieLNA3_Tin4Ah67rkrQvwSSZAdPU0EPsRiUxyAA,1103
|
|
166
166
|
phoenix/server/api/mutations/api_key_mutations.py,sha256=OmPipsmlQIb6DKvAgO58mZUwkYJihlJB2N4lTyeUlAA,6164
|
|
167
|
-
phoenix/server/api/mutations/chat_mutations.py,sha256=
|
|
167
|
+
phoenix/server/api/mutations/chat_mutations.py,sha256=Rky_PwILAhDBjW6K2cxfaIVsT5iOP5pjuViYUpoVHWY,22540
|
|
168
168
|
phoenix/server/api/mutations/dataset_mutations.py,sha256=siwsSmozKRIK8ZhPrfWl-GxKCL4lAmRPms862tG2KXY,27064
|
|
169
169
|
phoenix/server/api/mutations/experiment_mutations.py,sha256=p3CoLAa8nFPa3D759Y2A7De_PVJNGOL98mA3HoZBrRQ,3188
|
|
170
170
|
phoenix/server/api/mutations/export_events_mutations.py,sha256=xoDnVWC7eA_8wNQP0-oyiHojyUZ0EhVVSrsAnztetC0,3993
|
|
@@ -273,15 +273,15 @@ phoenix/server/static/apple-touch-icon-76x76.png,sha256=CT_xT12I0u2i0WU8JzBZBuOQ
|
|
|
273
273
|
phoenix/server/static/apple-touch-icon.png,sha256=fOfpjqGpWYbJ0eAurKsyoZP1EAs6ZVooBJ_SGk2ZkDs,3801
|
|
274
274
|
phoenix/server/static/favicon.ico,sha256=bY0vvCKRftemZfPShwZtE93DiiQdaYaozkPGwNFr6H8,34494
|
|
275
275
|
phoenix/server/static/modernizr.js,sha256=mvK-XtkNqjOral-QvzoqsyOMECXIMu5BQwSVN_wcU9c,2564
|
|
276
|
-
phoenix/server/static/.vite/manifest.json,sha256=
|
|
277
|
-
phoenix/server/static/assets/components-
|
|
278
|
-
phoenix/server/static/assets/index-
|
|
279
|
-
phoenix/server/static/assets/pages-
|
|
280
|
-
phoenix/server/static/assets/vendor-
|
|
276
|
+
phoenix/server/static/.vite/manifest.json,sha256=QVqqb_JM1hcyubZgGH4qh08LUHWKE_FR43j_YdVWk0M,1929
|
|
277
|
+
phoenix/server/static/assets/components-C_HASv83.js,sha256=7xZ3sMiHZkpbHJjpzujdMII4znFs-h5DkFCvY8oX1Aw,306769
|
|
278
|
+
phoenix/server/static/assets/index-D7UiCRtr.js,sha256=i6WbtADGyqEQix4x9_4yIbl1U7dc0NpIRoI5ckFGUZ8,7290
|
|
279
|
+
phoenix/server/static/assets/pages-DYHcAdjT.js,sha256=aUloiI7AopSeUGfKhYmalMk1luUrQpMJYHnjZwLV9vs,632400
|
|
280
|
+
phoenix/server/static/assets/vendor-BCxsh5i3.js,sha256=fPeA9hYHGj1n2Bg8JOlpsddXw7Vkulbvra3z4RCy0Ss,10899238
|
|
281
281
|
phoenix/server/static/assets/vendor-DxkFTwjz.css,sha256=nZrkr0u6NNElFGvpWHk9GTHeGoibCXCli1bE7mXZGZg,1816
|
|
282
|
-
phoenix/server/static/assets/vendor-arizeai-
|
|
283
|
-
phoenix/server/static/assets/vendor-codemirror-
|
|
284
|
-
phoenix/server/static/assets/vendor-recharts-
|
|
282
|
+
phoenix/server/static/assets/vendor-arizeai-C2CDZgMz.js,sha256=Isrlf-QaErzG0UZGd2VeCf1l-d6eghpvLr4v4K5A2Xk,308483
|
|
283
|
+
phoenix/server/static/assets/vendor-codemirror-DYbtnCTn.js,sha256=-xGEPOe20e89kdfMNfTrthj084muiJ3gMKPdUtzdjmA,392709
|
|
284
|
+
phoenix/server/static/assets/vendor-recharts-P6W8G0Mb.js,sha256=0B8yyQbqMwwsPvLkd-tZzntAKMNZpZGJ8OlMfXKvbu4,282859
|
|
285
285
|
phoenix/server/static/assets/vendor-three-DwGkEfCM.js,sha256=0D12ZgKzfKCTSdSTKJBFR2RZO_xxeMXrqDp0AszZqHY,620972
|
|
286
286
|
phoenix/server/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
287
287
|
phoenix/server/templates/index.html,sha256=ram6sfy2obf_F053ay35V30v-mnRWZ86rK-PstXLy1c,4457
|
|
@@ -299,7 +299,7 @@ phoenix/trace/fixtures.py,sha256=bwDD0rgIRdAi_9zwLLipke50oYuKJvZLvhiGsuvnGbs,191
|
|
|
299
299
|
phoenix/trace/otel.py,sha256=FZGzo0NPJqFBLkL_VmQeBne2z-LdHNPTz3oIZOuPPzQ,9997
|
|
300
300
|
phoenix/trace/projects.py,sha256=9dKv1aiKL4IYMFsg2xnC6EOIRO0YHtkR5o9ALHbMK9g,2178
|
|
301
301
|
phoenix/trace/schemas.py,sha256=0tghsJDaLKvSuxDDQGpUEQ0HkMsKmFWPO3lwJrJ9t84,5972
|
|
302
|
-
phoenix/trace/span_evaluations.py,sha256=
|
|
302
|
+
phoenix/trace/span_evaluations.py,sha256=x3nye9r2SQk1mrR3N05YbuWsgUKpMWwTRBtJTDBSj3Y,13156
|
|
303
303
|
phoenix/trace/span_json_decoder.py,sha256=J1_oDViuUoC4vxPg61U4EOZC1uEMcCzoj-kVjOFEE8k,3224
|
|
304
304
|
phoenix/trace/span_json_encoder.py,sha256=Wa7RvQTZSsFG4pdKSSFSO_4q4DjAOQuG8wLNJvYzsfM,2004
|
|
305
305
|
phoenix/trace/trace_dataset.py,sha256=7XyCe_7WemBmAiHw0kigmwkC1gPSLeVBqtrRe9FpM6s,14490
|
|
@@ -316,15 +316,15 @@ phoenix/utilities/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU
|
|
|
316
316
|
phoenix/utilities/client.py,sha256=kr95EgpTJtCbb7CLoxC-KiyB2Wco03DZGIlcEmozHFs,5605
|
|
317
317
|
phoenix/utilities/deprecation.py,sha256=LL1LWfVqnYulceMQw2CggoIv8Uogrj7fAD_85devnoo,1067
|
|
318
318
|
phoenix/utilities/error_handling.py,sha256=5_ggfwmd0xZPoI3qi1fwm0x1F0i7g5j-gr0ny1TFzPU,1967
|
|
319
|
-
phoenix/utilities/json.py,sha256=
|
|
319
|
+
phoenix/utilities/json.py,sha256=UE8WHZU060NY_8ZKJ97gmtEC2mp60d8tJFXyRqIz51Y,3743
|
|
320
320
|
phoenix/utilities/logging.py,sha256=NKvX43jWITgSTtHGCi6l5xp8jTjtQ8FQ_irEi9ybOxg,502
|
|
321
321
|
phoenix/utilities/project.py,sha256=auVpARXkDb-JgeX5f2aStyFIkeKvGwN9l7qrFeJMVxI,445
|
|
322
322
|
phoenix/utilities/re.py,sha256=x8Xbk-Wa6qDMAtUd_7JtZvKtrYEuMY-bchB0n163_5c,2006
|
|
323
323
|
phoenix/utilities/span_store.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
324
324
|
phoenix/utilities/template_formatters.py,sha256=JuOyvukMPLDHa1uVNw0kCFBUnIxy02dwAWNZimdIZU4,2423
|
|
325
|
-
arize_phoenix-5.
|
|
326
|
-
arize_phoenix-5.
|
|
327
|
-
arize_phoenix-5.
|
|
328
|
-
arize_phoenix-5.
|
|
329
|
-
arize_phoenix-5.
|
|
330
|
-
arize_phoenix-5.
|
|
325
|
+
arize_phoenix-5.11.0.dist-info/METADATA,sha256=6ALW-ZaTA2y2Temcz899qgQfCOjqJVGx9A2jgWPkkOI,22671
|
|
326
|
+
arize_phoenix-5.11.0.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
|
|
327
|
+
arize_phoenix-5.11.0.dist-info/entry_points.txt,sha256=Pgpn8Upxx9P8z8joPXZWl2LlnAlGc3gcQoVchb06X1Q,94
|
|
328
|
+
arize_phoenix-5.11.0.dist-info/licenses/IP_NOTICE,sha256=JBqyyCYYxGDfzQ0TtsQgjts41IJoa-hiwDrBjCb9gHM,469
|
|
329
|
+
arize_phoenix-5.11.0.dist-info/licenses/LICENSE,sha256=HFkW9REuMOkvKRACuwLPT0hRydHb3zNg-fdFt94td18,3794
|
|
330
|
+
arize_phoenix-5.11.0.dist-info/RECORD,,
|
phoenix/config.py
CHANGED
|
@@ -97,6 +97,13 @@ ENV_PHOENIX_SERVER_INSTRUMENTATION_OTLP_TRACE_COLLECTOR_GRPC_ENDPOINT = (
|
|
|
97
97
|
ENV_PHOENIX_ENABLE_AUTH = "PHOENIX_ENABLE_AUTH"
|
|
98
98
|
ENV_PHOENIX_DISABLE_RATE_LIMIT = "PHOENIX_DISABLE_RATE_LIMIT"
|
|
99
99
|
ENV_PHOENIX_SECRET = "PHOENIX_SECRET"
|
|
100
|
+
ENV_PHOENIX_DEFAULT_ADMIN_INITIAL_PASSWORD = "PHOENIX_DEFAULT_ADMIN_INITIAL_PASSWORD"
|
|
101
|
+
"""
|
|
102
|
+
The initial password for the default admin account, which defaults to ‘admin’ if not
|
|
103
|
+
explicitly set. Note that changing this value will have no effect if the default admin
|
|
104
|
+
record already exists in the database. In such cases, the default admin password must
|
|
105
|
+
be updated manually in the application.
|
|
106
|
+
"""
|
|
100
107
|
ENV_PHOENIX_API_KEY = "PHOENIX_API_KEY"
|
|
101
108
|
ENV_PHOENIX_USE_SECURE_COOKIES = "PHOENIX_USE_SECURE_COOKIES"
|
|
102
109
|
ENV_PHOENIX_ACCESS_TOKEN_EXPIRY_MINUTES = "PHOENIX_ACCESS_TOKEN_EXPIRY_MINUTES"
|
|
@@ -274,6 +281,12 @@ def get_env_phoenix_secret() -> Optional[str]:
|
|
|
274
281
|
return phoenix_secret
|
|
275
282
|
|
|
276
283
|
|
|
284
|
+
def get_env_default_admin_initial_password() -> str:
|
|
285
|
+
from phoenix.auth import DEFAULT_ADMIN_PASSWORD
|
|
286
|
+
|
|
287
|
+
return os.environ.get(ENV_PHOENIX_DEFAULT_ADMIN_INITIAL_PASSWORD) or DEFAULT_ADMIN_PASSWORD
|
|
288
|
+
|
|
289
|
+
|
|
277
290
|
def get_env_phoenix_use_secure_cookies() -> bool:
|
|
278
291
|
return _bool_val(ENV_PHOENIX_USE_SECURE_COOKIES, False)
|
|
279
292
|
|
phoenix/db/facilitator.py
CHANGED
|
@@ -13,13 +13,13 @@ from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
13
13
|
|
|
14
14
|
from phoenix.auth import (
|
|
15
15
|
DEFAULT_ADMIN_EMAIL,
|
|
16
|
-
DEFAULT_ADMIN_PASSWORD,
|
|
17
16
|
DEFAULT_ADMIN_USERNAME,
|
|
18
17
|
DEFAULT_SECRET_LENGTH,
|
|
19
18
|
DEFAULT_SYSTEM_EMAIL,
|
|
20
19
|
DEFAULT_SYSTEM_USERNAME,
|
|
21
20
|
compute_password_hash,
|
|
22
21
|
)
|
|
22
|
+
from phoenix.config import get_env_default_admin_initial_password
|
|
23
23
|
from phoenix.db import models
|
|
24
24
|
from phoenix.db.enums import COLUMN_ENUMS, UserRole
|
|
25
25
|
from phoenix.server.types import DbSessionFactory
|
|
@@ -97,7 +97,8 @@ async def _ensure_user_roles(session: AsyncSession) -> None:
|
|
|
97
97
|
admin_role_id := role_ids.get(admin_role)
|
|
98
98
|
) is not None:
|
|
99
99
|
salt = secrets.token_bytes(DEFAULT_SECRET_LENGTH)
|
|
100
|
-
|
|
100
|
+
password = get_env_default_admin_initial_password()
|
|
101
|
+
compute = partial(compute_password_hash, password=password, salt=salt)
|
|
101
102
|
loop = asyncio.get_running_loop()
|
|
102
103
|
hash_ = await loop.run_in_executor(None, compute)
|
|
103
104
|
admin_user = models.User(
|
|
@@ -2,6 +2,7 @@ import asyncio
|
|
|
2
2
|
import importlib.util
|
|
3
3
|
import inspect
|
|
4
4
|
import json
|
|
5
|
+
import os
|
|
5
6
|
import time
|
|
6
7
|
from abc import ABC, abstractmethod
|
|
7
8
|
from collections.abc import AsyncIterator, Callable, Iterator
|
|
@@ -25,6 +26,7 @@ from phoenix.evals.models.rate_limiters import (
|
|
|
25
26
|
RateLimiter,
|
|
26
27
|
RateLimitError,
|
|
27
28
|
)
|
|
29
|
+
from phoenix.server.api.exceptions import BadRequest
|
|
28
30
|
from phoenix.server.api.helpers.playground_registry import PROVIDER_DEFAULT, register_llm_client
|
|
29
31
|
from phoenix.server.api.input_types.GenerativeModelInput import GenerativeModelInput
|
|
30
32
|
from phoenix.server.api.input_types.InvocationParameters import (
|
|
@@ -99,9 +101,9 @@ class PlaygroundRateLimiter(RateLimiter, KeyedSingleton):
|
|
|
99
101
|
super().__init__(
|
|
100
102
|
rate_limit_error=rate_limit_error,
|
|
101
103
|
max_rate_limit_retries=3,
|
|
102
|
-
initial_per_second_request_rate=
|
|
103
|
-
maximum_per_second_request_rate=
|
|
104
|
-
enforcement_window_minutes=
|
|
104
|
+
initial_per_second_request_rate=1.0,
|
|
105
|
+
maximum_per_second_request_rate=3.0,
|
|
106
|
+
enforcement_window_minutes=0.05,
|
|
105
107
|
rate_reduction_factor=0.5,
|
|
106
108
|
rate_increase_factor=0.01,
|
|
107
109
|
cooldown_seconds=5,
|
|
@@ -128,10 +130,11 @@ class PlaygroundRateLimiter(RateLimiter, KeyedSingleton):
|
|
|
128
130
|
self._rate_limit_handling.set() # Set the event as a failsafe
|
|
129
131
|
await self._throttler.async_wait_until_ready()
|
|
130
132
|
request_start_time = time.time()
|
|
131
|
-
|
|
132
|
-
|
|
133
|
+
maybe_coroutine = fn(*args, **kwargs)
|
|
134
|
+
if inspect.iscoroutine(maybe_coroutine):
|
|
135
|
+
return await maybe_coroutine # type: ignore
|
|
133
136
|
else:
|
|
134
|
-
return
|
|
137
|
+
return maybe_coroutine
|
|
135
138
|
except self._rate_limit_error:
|
|
136
139
|
async with self._rate_limit_handling_lock:
|
|
137
140
|
self._rate_limit_handling.clear() # prevent new requests from starting
|
|
@@ -258,6 +261,10 @@ class OpenAIStreamingClient(PlaygroundStreamingClient):
|
|
|
258
261
|
from openai import AsyncOpenAI
|
|
259
262
|
from openai import RateLimitError as OpenAIRateLimitError
|
|
260
263
|
|
|
264
|
+
# todo: check if custom base url is set before raising error to allow
|
|
265
|
+
# for custom endpoints that don't require an API key
|
|
266
|
+
if not (api_key := api_key or os.environ.get("OPENAI_API_KEY")):
|
|
267
|
+
raise BadRequest("An API key is required for OpenAI models")
|
|
261
268
|
super().__init__(model=model, api_key=api_key)
|
|
262
269
|
self._attributes[LLM_PROVIDER] = OpenInferenceLLMProviderValues.OPENAI.value
|
|
263
270
|
self._attributes[LLM_SYSTEM] = OpenInferenceLLMSystemValues.OPENAI.value
|
|
@@ -341,7 +348,7 @@ class OpenAIStreamingClient(PlaygroundStreamingClient):
|
|
|
341
348
|
openai_messages = [self.to_openai_chat_completion_param(*message) for message in messages]
|
|
342
349
|
tool_call_ids: dict[int, str] = {}
|
|
343
350
|
token_usage: Optional["CompletionUsage"] = None
|
|
344
|
-
throttled_create = self.rate_limiter.
|
|
351
|
+
throttled_create = self.rate_limiter._alimit(self.client.chat.completions.create)
|
|
345
352
|
async for chunk in await throttled_create(
|
|
346
353
|
messages=openai_messages,
|
|
347
354
|
model=self.model_name,
|
|
@@ -510,7 +517,7 @@ class OpenAIO1StreamingClient(OpenAIStreamingClient):
|
|
|
510
517
|
|
|
511
518
|
tool_call_ids: dict[int, str] = {}
|
|
512
519
|
|
|
513
|
-
throttled_create = self.rate_limiter.
|
|
520
|
+
throttled_create = self.rate_limiter._alimit(self.client.chat.completions.create)
|
|
514
521
|
response = await throttled_create(
|
|
515
522
|
messages=openai_messages,
|
|
516
523
|
model=self.model_name,
|
|
@@ -618,12 +625,14 @@ class AzureOpenAIStreamingClient(OpenAIStreamingClient):
|
|
|
618
625
|
super().__init__(model=model, api_key=api_key)
|
|
619
626
|
self._attributes[LLM_PROVIDER] = OpenInferenceLLMProviderValues.AZURE.value
|
|
620
627
|
self._attributes[LLM_SYSTEM] = OpenInferenceLLMSystemValues.OPENAI.value
|
|
621
|
-
if model.endpoint
|
|
622
|
-
raise
|
|
628
|
+
if not (endpoint := model.endpoint or os.environ.get("AZURE_OPENAI_ENDPOINT")):
|
|
629
|
+
raise BadRequest("An Azure endpoint is required for Azure OpenAI models")
|
|
630
|
+
if not (api_version := model.api_version or os.environ.get("OPENAI_API_VERSION")):
|
|
631
|
+
raise BadRequest("An OpenAI API version is required for Azure OpenAI models")
|
|
623
632
|
self.client = AsyncAzureOpenAI(
|
|
624
633
|
api_key=api_key,
|
|
625
|
-
azure_endpoint=
|
|
626
|
-
api_version=
|
|
634
|
+
azure_endpoint=endpoint,
|
|
635
|
+
api_version=api_version,
|
|
627
636
|
)
|
|
628
637
|
|
|
629
638
|
|
|
@@ -648,6 +657,8 @@ class AnthropicStreamingClient(PlaygroundStreamingClient):
|
|
|
648
657
|
super().__init__(model=model, api_key=api_key)
|
|
649
658
|
self._attributes[LLM_PROVIDER] = OpenInferenceLLMProviderValues.ANTHROPIC.value
|
|
650
659
|
self._attributes[LLM_SYSTEM] = OpenInferenceLLMSystemValues.ANTHROPIC.value
|
|
660
|
+
if not (api_key := api_key or os.environ.get("ANTHROPIC_API_KEY")):
|
|
661
|
+
raise BadRequest("An API key is required for Anthropic models")
|
|
651
662
|
self.client = anthropic.AsyncAnthropic(api_key=api_key)
|
|
652
663
|
self.model_name = model.name
|
|
653
664
|
self.rate_limiter = PlaygroundRateLimiter(model.provider_key, anthropic.RateLimitError)
|
|
@@ -707,7 +718,6 @@ class AnthropicStreamingClient(PlaygroundStreamingClient):
|
|
|
707
718
|
"messages": anthropic_messages,
|
|
708
719
|
"model": self.model_name,
|
|
709
720
|
"system": system_prompt,
|
|
710
|
-
"max_tokens": 1024,
|
|
711
721
|
"tools": tools,
|
|
712
722
|
**invocation_parameters,
|
|
713
723
|
}
|
|
@@ -820,6 +830,12 @@ class GeminiStreamingClient(PlaygroundStreamingClient):
|
|
|
820
830
|
super().__init__(model=model, api_key=api_key)
|
|
821
831
|
self._attributes[LLM_PROVIDER] = OpenInferenceLLMProviderValues.GOOGLE.value
|
|
822
832
|
self._attributes[LLM_SYSTEM] = OpenInferenceLLMSystemValues.VERTEXAI.value
|
|
833
|
+
if not (
|
|
834
|
+
api_key := api_key
|
|
835
|
+
or os.environ.get("GEMINI_API_KEY")
|
|
836
|
+
or os.environ.get("GOOGLE_API_KEY")
|
|
837
|
+
):
|
|
838
|
+
raise BadRequest("An API key is required for Gemini models")
|
|
823
839
|
google_genai.configure(api_key=api_key)
|
|
824
840
|
self.model_name = model.name
|
|
825
841
|
|
|
@@ -379,6 +379,11 @@ def _llm_output_messages(
|
|
|
379
379
|
if content := "".join(chunk.content for chunk in text_chunks):
|
|
380
380
|
yield f"{LLM_OUTPUT_MESSAGES}.0.{MESSAGE_CONTENT}", content
|
|
381
381
|
for tool_call_index, (_tool_call_id, tool_call_chunks_) in enumerate(tool_call_chunks.items()):
|
|
382
|
+
if _tool_call_id:
|
|
383
|
+
yield (
|
|
384
|
+
f"{LLM_OUTPUT_MESSAGES}.0.{MESSAGE_TOOL_CALLS}.{tool_call_index}.{TOOL_CALL_ID}",
|
|
385
|
+
_tool_call_id,
|
|
386
|
+
)
|
|
382
387
|
if tool_call_chunks_ and (name := tool_call_chunks_[0].function.name):
|
|
383
388
|
yield (
|
|
384
389
|
f"{LLM_OUTPUT_MESSAGES}.0.{MESSAGE_TOOL_CALLS}.{tool_call_index}.{TOOL_CALL_FUNCTION_NAME}",
|
|
@@ -441,6 +446,7 @@ MESSAGE_CONTENT = MessageAttributes.MESSAGE_CONTENT
|
|
|
441
446
|
MESSAGE_ROLE = MessageAttributes.MESSAGE_ROLE
|
|
442
447
|
MESSAGE_TOOL_CALLS = MessageAttributes.MESSAGE_TOOL_CALLS
|
|
443
448
|
|
|
449
|
+
TOOL_CALL_ID = ToolCallAttributes.TOOL_CALL_ID
|
|
444
450
|
TOOL_CALL_FUNCTION_NAME = ToolCallAttributes.TOOL_CALL_FUNCTION_NAME
|
|
445
451
|
TOOL_CALL_FUNCTION_ARGUMENTS_JSON = ToolCallAttributes.TOOL_CALL_FUNCTION_ARGUMENTS_JSON
|
|
446
452
|
TOOL_CALL_ID = ToolCallAttributes.TOOL_CALL_ID
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
from dataclasses import asdict, field
|
|
3
3
|
from datetime import datetime, timezone
|
|
4
|
-
from itertools import chain
|
|
4
|
+
from itertools import chain, islice
|
|
5
5
|
from traceback import format_exc
|
|
6
|
-
from typing import Any, Iterable, Iterator, List, Optional, Union
|
|
6
|
+
from typing import Any, Iterable, Iterator, List, Optional, TypeVar, Union
|
|
7
7
|
|
|
8
8
|
import strawberry
|
|
9
9
|
from openinference.instrumentation import safe_json_dumps
|
|
@@ -26,7 +26,7 @@ from phoenix.datetime_utils import local_now, normalize_datetime
|
|
|
26
26
|
from phoenix.db import models
|
|
27
27
|
from phoenix.db.helpers import get_dataset_example_revisions
|
|
28
28
|
from phoenix.server.api.context import Context
|
|
29
|
-
from phoenix.server.api.exceptions import BadRequest, NotFound
|
|
29
|
+
from phoenix.server.api.exceptions import BadRequest, CustomGraphQLError, NotFound
|
|
30
30
|
from phoenix.server.api.helpers.playground_clients import (
|
|
31
31
|
PlaygroundStreamingClient,
|
|
32
32
|
initialize_playground_clients,
|
|
@@ -127,11 +127,19 @@ class ChatCompletionMutationMixin:
|
|
|
127
127
|
provider_key = input.model.provider_key
|
|
128
128
|
llm_client_class = PLAYGROUND_CLIENT_REGISTRY.get_client(provider_key, input.model.name)
|
|
129
129
|
if llm_client_class is None:
|
|
130
|
-
raise BadRequest(f"
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
130
|
+
raise BadRequest(f"Unknown LLM provider: '{provider_key.value}'")
|
|
131
|
+
try:
|
|
132
|
+
llm_client = llm_client_class(
|
|
133
|
+
model=input.model,
|
|
134
|
+
api_key=input.api_key,
|
|
135
|
+
)
|
|
136
|
+
except CustomGraphQLError:
|
|
137
|
+
raise
|
|
138
|
+
except Exception as error:
|
|
139
|
+
raise BadRequest(
|
|
140
|
+
f"Failed to connect to LLM API for {provider_key.value} {input.model.name}: "
|
|
141
|
+
f"{str(error)}"
|
|
142
|
+
)
|
|
135
143
|
dataset_id = from_global_id_with_expected_type(input.dataset_id, Dataset.__name__)
|
|
136
144
|
dataset_version_id = (
|
|
137
145
|
from_global_id_with_expected_type(
|
|
@@ -158,7 +166,9 @@ class ChatCompletionMutationMixin:
|
|
|
158
166
|
revisions = [
|
|
159
167
|
revision
|
|
160
168
|
async for revision in await session.stream_scalars(
|
|
161
|
-
get_dataset_example_revisions(resolved_version_id)
|
|
169
|
+
get_dataset_example_revisions(resolved_version_id).order_by(
|
|
170
|
+
models.DatasetExampleRevision.id
|
|
171
|
+
)
|
|
162
172
|
)
|
|
163
173
|
]
|
|
164
174
|
if not revisions:
|
|
@@ -181,28 +191,32 @@ class ChatCompletionMutationMixin:
|
|
|
181
191
|
session.add(experiment)
|
|
182
192
|
await session.flush()
|
|
183
193
|
|
|
194
|
+
results = []
|
|
195
|
+
batch_size = 3
|
|
184
196
|
start_time = datetime.now(timezone.utc)
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
197
|
+
for batch in _get_batches(revisions, batch_size):
|
|
198
|
+
batch_results = await asyncio.gather(
|
|
199
|
+
*(
|
|
200
|
+
cls._chat_completion(
|
|
201
|
+
info,
|
|
202
|
+
llm_client,
|
|
203
|
+
ChatCompletionInput(
|
|
204
|
+
model=input.model,
|
|
205
|
+
api_key=input.api_key,
|
|
206
|
+
messages=input.messages,
|
|
207
|
+
tools=input.tools,
|
|
208
|
+
invocation_parameters=input.invocation_parameters,
|
|
209
|
+
template=TemplateOptions(
|
|
210
|
+
language=input.template_language,
|
|
211
|
+
variables=revision.input,
|
|
212
|
+
),
|
|
199
213
|
),
|
|
200
|
-
)
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
214
|
+
)
|
|
215
|
+
for revision in batch
|
|
216
|
+
),
|
|
217
|
+
return_exceptions=True,
|
|
218
|
+
)
|
|
219
|
+
results.extend(batch_results)
|
|
206
220
|
|
|
207
221
|
payload = ChatCompletionOverDatasetMutationPayload(
|
|
208
222
|
dataset_id=GlobalID(models.Dataset.__name__, str(dataset.id)),
|
|
@@ -266,11 +280,19 @@ class ChatCompletionMutationMixin:
|
|
|
266
280
|
provider_key = input.model.provider_key
|
|
267
281
|
llm_client_class = PLAYGROUND_CLIENT_REGISTRY.get_client(provider_key, input.model.name)
|
|
268
282
|
if llm_client_class is None:
|
|
269
|
-
raise BadRequest(f"
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
283
|
+
raise BadRequest(f"Unknown LLM provider: '{provider_key.value}'")
|
|
284
|
+
try:
|
|
285
|
+
llm_client = llm_client_class(
|
|
286
|
+
model=input.model,
|
|
287
|
+
api_key=input.api_key,
|
|
288
|
+
)
|
|
289
|
+
except CustomGraphQLError:
|
|
290
|
+
raise
|
|
291
|
+
except Exception as error:
|
|
292
|
+
raise BadRequest(
|
|
293
|
+
f"Failed to connect to LLM API for {provider_key.value} {input.model.name}: "
|
|
294
|
+
f"{str(error)}"
|
|
295
|
+
)
|
|
274
296
|
return await cls._chat_completion(info, llm_client, input)
|
|
275
297
|
|
|
276
298
|
@classmethod
|
|
@@ -486,6 +508,11 @@ def _llm_output_messages(
|
|
|
486
508
|
if text_content:
|
|
487
509
|
yield f"{LLM_OUTPUT_MESSAGES}.0.{MESSAGE_CONTENT}", text_content
|
|
488
510
|
for tool_call_index, tool_call in enumerate(tool_calls.values()):
|
|
511
|
+
if tool_call_id := tool_call.id:
|
|
512
|
+
yield (
|
|
513
|
+
f"{LLM_OUTPUT_MESSAGES}.0.{MESSAGE_TOOL_CALLS}.{tool_call_index}.{TOOL_CALL_ID}",
|
|
514
|
+
tool_call_id,
|
|
515
|
+
)
|
|
489
516
|
yield (
|
|
490
517
|
f"{LLM_OUTPUT_MESSAGES}.0.{MESSAGE_TOOL_CALLS}.{tool_call_index}.{TOOL_CALL_FUNCTION_NAME}",
|
|
491
518
|
tool_call.function.name,
|
|
@@ -513,6 +540,19 @@ def _serialize_event(event: SpanException) -> dict[str, Any]:
|
|
|
513
540
|
return {k: (v.isoformat() if isinstance(v, datetime) else v) for k, v in asdict(event).items()}
|
|
514
541
|
|
|
515
542
|
|
|
543
|
+
_AnyT = TypeVar("_AnyT")
|
|
544
|
+
|
|
545
|
+
|
|
546
|
+
def _get_batches(
|
|
547
|
+
iterable: Iterable[_AnyT],
|
|
548
|
+
batch_size: int,
|
|
549
|
+
) -> Iterator[list[_AnyT]]:
|
|
550
|
+
"""Splits an iterable into batches not exceeding a specified size."""
|
|
551
|
+
iterator = iter(iterable)
|
|
552
|
+
while batch := list(islice(iterator, batch_size)):
|
|
553
|
+
yield batch
|
|
554
|
+
|
|
555
|
+
|
|
516
556
|
JSON = OpenInferenceMimeTypeValues.JSON.value
|
|
517
557
|
TEXT = OpenInferenceMimeTypeValues.TEXT.value
|
|
518
558
|
LLM = OpenInferenceSpanKindValues.LLM.value
|
|
@@ -534,6 +574,7 @@ MESSAGE_CONTENT = MessageAttributes.MESSAGE_CONTENT
|
|
|
534
574
|
MESSAGE_ROLE = MessageAttributes.MESSAGE_ROLE
|
|
535
575
|
MESSAGE_TOOL_CALLS = MessageAttributes.MESSAGE_TOOL_CALLS
|
|
536
576
|
|
|
577
|
+
TOOL_CALL_ID = ToolCallAttributes.TOOL_CALL_ID
|
|
537
578
|
TOOL_CALL_FUNCTION_NAME = ToolCallAttributes.TOOL_CALL_FUNCTION_NAME
|
|
538
579
|
TOOL_CALL_FUNCTION_ARGUMENTS_JSON = ToolCallAttributes.TOOL_CALL_FUNCTION_ARGUMENTS_JSON
|
|
539
580
|
|