arize-phoenix 11.4.0__py3-none-any.whl → 11.6.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-11.4.0.dist-info → arize_phoenix-11.6.0.dist-info}/METADATA +2 -2
- {arize_phoenix-11.4.0.dist-info → arize_phoenix-11.6.0.dist-info}/RECORD +42 -40
- phoenix/config.py +51 -2
- phoenix/server/api/auth.py +1 -1
- phoenix/server/api/queries.py +52 -44
- phoenix/server/api/routers/v1/annotation_configs.py +4 -1
- phoenix/server/api/routers/v1/datasets.py +3 -1
- phoenix/server/api/routers/v1/evaluations.py +3 -1
- phoenix/server/api/routers/v1/experiment_runs.py +3 -1
- phoenix/server/api/routers/v1/experiments.py +3 -1
- phoenix/server/api/routers/v1/projects.py +4 -1
- phoenix/server/api/routers/v1/prompts.py +4 -1
- phoenix/server/api/routers/v1/spans.py +6 -3
- phoenix/server/api/routers/v1/traces.py +4 -1
- phoenix/server/api/routers/v1/users.py +2 -2
- phoenix/server/api/types/Span.py +0 -99
- phoenix/server/app.py +47 -12
- phoenix/server/authorization.py +9 -0
- phoenix/server/bearer_auth.py +18 -15
- phoenix/server/cost_tracking/cost_model_lookup.py +1 -1
- phoenix/server/cost_tracking/model_cost_manifest.json +107 -107
- phoenix/server/daemons/db_disk_usage_monitor.py +215 -0
- phoenix/server/email/sender.py +25 -0
- phoenix/server/email/templates/db_disk_usage_notification.html +16 -0
- phoenix/server/email/types.py +11 -0
- phoenix/server/grpc_server.py +3 -3
- phoenix/server/prometheus.py +22 -0
- phoenix/server/static/.vite/manifest.json +44 -44
- phoenix/server/static/assets/{components-CVcMbu2U.js → components-mOUBHJ12.js} +297 -298
- phoenix/server/static/assets/{index-Dz7I-Hpn.js → index-CQ_A6K_M.js} +2 -2
- phoenix/server/static/assets/{pages-QK2o2V7x.js → pages-CCsLkNZY.js} +517 -498
- phoenix/server/static/assets/{vendor-pg5m6BWE.js → vendor-DRWIRkSJ.js} +1 -1
- phoenix/server/static/assets/{vendor-arizeai-BwMsgSAG.js → vendor-arizeai-DUhQaeau.js} +1 -1
- phoenix/server/static/assets/{vendor-codemirror-BwSDEu2g.js → vendor-codemirror-D_6Q6Auv.js} +1 -1
- phoenix/server/static/assets/{vendor-recharts-SW3HwAtG.js → vendor-recharts-BNBwj7vz.js} +1 -1
- phoenix/server/static/assets/{vendor-shiki-BsdYoDvs.js → vendor-shiki-k1qj_XjP.js} +1 -1
- phoenix/server/types.py +11 -2
- phoenix/version.py +1 -1
- {arize_phoenix-11.4.0.dist-info → arize_phoenix-11.6.0.dist-info}/WHEEL +0 -0
- {arize_phoenix-11.4.0.dist-info → arize_phoenix-11.6.0.dist-info}/entry_points.txt +0 -0
- {arize_phoenix-11.4.0.dist-info → arize_phoenix-11.6.0.dist-info}/licenses/IP_NOTICE +0 -0
- {arize_phoenix-11.4.0.dist-info → arize_phoenix-11.6.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from asyncio import sleep
|
|
5
|
+
from datetime import datetime, timedelta, timezone
|
|
6
|
+
from typing import Optional
|
|
7
|
+
|
|
8
|
+
import sqlalchemy as sa
|
|
9
|
+
from email_validator import EmailNotValidError, validate_email
|
|
10
|
+
from sqlalchemy import text
|
|
11
|
+
from typing_extensions import assert_never
|
|
12
|
+
|
|
13
|
+
from phoenix.config import (
|
|
14
|
+
ENV_PHOENIX_SQL_DATABASE_SCHEMA,
|
|
15
|
+
get_env_database_allocated_storage_capacity_gibibytes,
|
|
16
|
+
get_env_database_usage_email_warning_threshold_percentage,
|
|
17
|
+
get_env_database_usage_insertion_blocking_threshold_percentage,
|
|
18
|
+
getenv,
|
|
19
|
+
)
|
|
20
|
+
from phoenix.db import models
|
|
21
|
+
from phoenix.db.helpers import SupportedSQLDialect
|
|
22
|
+
from phoenix.server.email.types import DbUsageWarningEmailSender
|
|
23
|
+
from phoenix.server.prometheus import (
|
|
24
|
+
DB_DISK_USAGE_BYTES,
|
|
25
|
+
DB_DISK_USAGE_RATIO,
|
|
26
|
+
DB_DISK_USAGE_WARNING_EMAIL_ERRORS,
|
|
27
|
+
DB_DISK_USAGE_WARNING_EMAILS_SENT,
|
|
28
|
+
DB_INSERTIONS_BLOCKED,
|
|
29
|
+
)
|
|
30
|
+
from phoenix.server.types import DaemonTask, DbSessionFactory
|
|
31
|
+
|
|
32
|
+
logger = logging.getLogger(__name__)
|
|
33
|
+
|
|
34
|
+
_SLEEP_SECONDS = 60
|
|
35
|
+
_EMAIL_FREQUENCY_HOURS = 24
|
|
36
|
+
_BYTES_PER_GIBIBYTE = 1024**3
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class DbDiskUsageMonitor(DaemonTask):
|
|
40
|
+
"""
|
|
41
|
+
Monitors database disk space usage and triggers warnings/blocking when thresholds are exceeded.
|
|
42
|
+
|
|
43
|
+
This daemon:
|
|
44
|
+
- Periodically checks current database size
|
|
45
|
+
- Compares usage against configured thresholds
|
|
46
|
+
- Sends warning emails to admins when warning threshold is reached
|
|
47
|
+
- Toggles insertion blocking when blocking threshold is reached
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
def __init__(
|
|
51
|
+
self,
|
|
52
|
+
db: DbSessionFactory,
|
|
53
|
+
email_sender: Optional[DbUsageWarningEmailSender] = None,
|
|
54
|
+
) -> None:
|
|
55
|
+
super().__init__()
|
|
56
|
+
self._db = db
|
|
57
|
+
self._email_sender = email_sender
|
|
58
|
+
# Tracks last email send time per admin email address to prevent spam
|
|
59
|
+
self._last_email_sent: dict[str, datetime] = {}
|
|
60
|
+
|
|
61
|
+
@property
|
|
62
|
+
def _is_disabled(self) -> bool:
|
|
63
|
+
return not bool(
|
|
64
|
+
get_env_database_allocated_storage_capacity_gibibytes()
|
|
65
|
+
and (
|
|
66
|
+
get_env_database_usage_email_warning_threshold_percentage()
|
|
67
|
+
or get_env_database_usage_insertion_blocking_threshold_percentage()
|
|
68
|
+
)
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
async def _run(self) -> None:
|
|
72
|
+
if self._is_disabled:
|
|
73
|
+
return
|
|
74
|
+
|
|
75
|
+
while self._running:
|
|
76
|
+
try:
|
|
77
|
+
current_usage_bytes = await self._check_disk_usage_bytes()
|
|
78
|
+
except Exception:
|
|
79
|
+
logger.exception("Failed to check disk space")
|
|
80
|
+
else:
|
|
81
|
+
DB_DISK_USAGE_BYTES.set(current_usage_bytes)
|
|
82
|
+
current_usage_gibibytes = current_usage_bytes / _BYTES_PER_GIBIBYTE
|
|
83
|
+
try:
|
|
84
|
+
await self._check_thresholds(current_usage_gibibytes)
|
|
85
|
+
except Exception:
|
|
86
|
+
logger.exception("Failed to check database usage thresholds")
|
|
87
|
+
await sleep(_SLEEP_SECONDS)
|
|
88
|
+
|
|
89
|
+
async def _check_disk_usage_bytes(self) -> float:
|
|
90
|
+
if self._db.dialect is SupportedSQLDialect.SQLITE:
|
|
91
|
+
async with self._db() as session:
|
|
92
|
+
page_count = await session.scalar(text("PRAGMA page_count;"))
|
|
93
|
+
freelist_count = await session.scalar(text("PRAGMA freelist_count;"))
|
|
94
|
+
page_size = await session.scalar(text("PRAGMA page_size;"))
|
|
95
|
+
current_usage_bytes = (page_count - freelist_count) * page_size
|
|
96
|
+
elif self._db.dialect is SupportedSQLDialect.POSTGRESQL:
|
|
97
|
+
nspname = getenv(ENV_PHOENIX_SQL_DATABASE_SCHEMA) or "public"
|
|
98
|
+
stmt = text("""\
|
|
99
|
+
SELECT sum(pg_total_relation_size(c.oid))
|
|
100
|
+
FROM pg_class as c
|
|
101
|
+
INNER JOIN pg_namespace as n ON n.oid = c.relnamespace
|
|
102
|
+
WHERE c.relkind = 'r'
|
|
103
|
+
AND n.nspname = :nspname;
|
|
104
|
+
""").bindparams(nspname=nspname)
|
|
105
|
+
async with self._db() as session:
|
|
106
|
+
current_usage_bytes = await session.scalar(stmt)
|
|
107
|
+
else:
|
|
108
|
+
assert_never(self._db.dialect)
|
|
109
|
+
return float(current_usage_bytes)
|
|
110
|
+
|
|
111
|
+
async def _check_thresholds(self, current_usage_gibibytes: float) -> None:
|
|
112
|
+
allocated_capacity_gibibytes = get_env_database_allocated_storage_capacity_gibibytes()
|
|
113
|
+
if not allocated_capacity_gibibytes:
|
|
114
|
+
return
|
|
115
|
+
|
|
116
|
+
used_ratio = current_usage_gibibytes / allocated_capacity_gibibytes
|
|
117
|
+
DB_DISK_USAGE_RATIO.set(used_ratio)
|
|
118
|
+
used_percentage = used_ratio * 100
|
|
119
|
+
|
|
120
|
+
# Check insertion blocking threshold
|
|
121
|
+
if (
|
|
122
|
+
insertion_blocking_threshold_percentage
|
|
123
|
+
:= get_env_database_usage_insertion_blocking_threshold_percentage()
|
|
124
|
+
):
|
|
125
|
+
should_not_insert_or_update = used_percentage > insertion_blocking_threshold_percentage
|
|
126
|
+
self._db.should_not_insert_or_update = should_not_insert_or_update
|
|
127
|
+
DB_INSERTIONS_BLOCKED.set(int(should_not_insert_or_update))
|
|
128
|
+
|
|
129
|
+
# Check warning email threshold
|
|
130
|
+
if (
|
|
131
|
+
notification_threshold_percentage
|
|
132
|
+
:= get_env_database_usage_email_warning_threshold_percentage()
|
|
133
|
+
):
|
|
134
|
+
if used_percentage > notification_threshold_percentage:
|
|
135
|
+
await self._send_warning_emails(
|
|
136
|
+
used_percentage,
|
|
137
|
+
allocated_capacity_gibibytes,
|
|
138
|
+
notification_threshold_percentage,
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
async def _send_warning_emails(
|
|
142
|
+
self,
|
|
143
|
+
used_percentage: float,
|
|
144
|
+
allocated_capacity_gibibytes: float,
|
|
145
|
+
notification_threshold_percentage: float,
|
|
146
|
+
) -> None:
|
|
147
|
+
if not self._email_sender:
|
|
148
|
+
return
|
|
149
|
+
|
|
150
|
+
current_usage_gibibytes = used_percentage / 100 * allocated_capacity_gibibytes
|
|
151
|
+
stmt = (
|
|
152
|
+
sa.select(models.User.email)
|
|
153
|
+
.join(models.UserRole)
|
|
154
|
+
.where(models.UserRole.name == "ADMIN")
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
try:
|
|
158
|
+
async with self._db() as session:
|
|
159
|
+
admin_emails = (await session.scalars(stmt)).all()
|
|
160
|
+
except Exception:
|
|
161
|
+
logger.exception(
|
|
162
|
+
"Failed to fetch admin emails from database, "
|
|
163
|
+
"skipping database usage warning emails"
|
|
164
|
+
)
|
|
165
|
+
return
|
|
166
|
+
|
|
167
|
+
if not admin_emails:
|
|
168
|
+
return
|
|
169
|
+
|
|
170
|
+
# Validate email addresses
|
|
171
|
+
valid_emails: list[str] = []
|
|
172
|
+
|
|
173
|
+
for email in admin_emails:
|
|
174
|
+
try:
|
|
175
|
+
normalized_email = validate_email(email, check_deliverability=False).normalized
|
|
176
|
+
except EmailNotValidError:
|
|
177
|
+
pass
|
|
178
|
+
else:
|
|
179
|
+
valid_emails.append(normalized_email)
|
|
180
|
+
|
|
181
|
+
if not valid_emails:
|
|
182
|
+
return
|
|
183
|
+
|
|
184
|
+
self._last_email_sent = {
|
|
185
|
+
email: timestamp
|
|
186
|
+
for email, timestamp in self._last_email_sent.items()
|
|
187
|
+
if email in valid_emails
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
now = datetime.now(timezone.utc)
|
|
191
|
+
emails_sent = 0
|
|
192
|
+
send_attempts = 0
|
|
193
|
+
|
|
194
|
+
for email in valid_emails:
|
|
195
|
+
if email in self._last_email_sent and now - self._last_email_sent[email] < timedelta(
|
|
196
|
+
hours=_EMAIL_FREQUENCY_HOURS
|
|
197
|
+
):
|
|
198
|
+
continue
|
|
199
|
+
send_attempts += 1
|
|
200
|
+
try:
|
|
201
|
+
await self._email_sender.send_db_usage_warning_email(
|
|
202
|
+
email=email,
|
|
203
|
+
current_usage_gibibytes=current_usage_gibibytes,
|
|
204
|
+
allocated_storage_gibibytes=allocated_capacity_gibibytes,
|
|
205
|
+
notification_threshold_percentage=notification_threshold_percentage,
|
|
206
|
+
)
|
|
207
|
+
except Exception:
|
|
208
|
+
logger.exception(f"Failed to send database usage warning email to {email}")
|
|
209
|
+
# Count email send errors
|
|
210
|
+
DB_DISK_USAGE_WARNING_EMAIL_ERRORS.inc()
|
|
211
|
+
else:
|
|
212
|
+
self._last_email_sent[email] = now
|
|
213
|
+
emails_sent += 1
|
|
214
|
+
# Count successful warning email sends
|
|
215
|
+
DB_DISK_USAGE_WARNING_EMAILS_SENT.inc()
|
phoenix/server/email/sender.py
CHANGED
|
@@ -81,6 +81,31 @@ class SimpleEmailSender:
|
|
|
81
81
|
|
|
82
82
|
await to_thread.run_sync(self._send_email, msg)
|
|
83
83
|
|
|
84
|
+
async def send_db_usage_warning_email(
|
|
85
|
+
self,
|
|
86
|
+
email: str,
|
|
87
|
+
current_usage_gibibytes: float,
|
|
88
|
+
allocated_storage_gibibytes: float,
|
|
89
|
+
notification_threshold_percentage: float,
|
|
90
|
+
) -> None:
|
|
91
|
+
subject = "[Phoenix] Database Usage Threshold Exceeded"
|
|
92
|
+
template_name = "db_disk_usage_notification.html"
|
|
93
|
+
|
|
94
|
+
template = self.env.get_template(template_name)
|
|
95
|
+
html_content = template.render(
|
|
96
|
+
current_usage_gibibytes=current_usage_gibibytes,
|
|
97
|
+
allocated_storage_gibibytes=allocated_storage_gibibytes,
|
|
98
|
+
notification_threshold_percentage=notification_threshold_percentage,
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
msg = EmailMessage()
|
|
102
|
+
msg["Subject"] = subject
|
|
103
|
+
msg["From"] = self.sender_email
|
|
104
|
+
msg["To"] = email
|
|
105
|
+
msg.set_content(html_content, subtype="html")
|
|
106
|
+
|
|
107
|
+
await to_thread.run_sync(self._send_email, msg)
|
|
108
|
+
|
|
84
109
|
def _send_email(self, msg: EmailMessage) -> None:
|
|
85
110
|
context: ssl.SSLContext
|
|
86
111
|
if self.validate_certs:
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<title>Database Usage Notification</title>
|
|
6
|
+
</head>
|
|
7
|
+
<body>
|
|
8
|
+
<h1>Database Usage Notification</h1>
|
|
9
|
+
<p>Your Phoenix database usage has exceeded the notification threshold.</p>
|
|
10
|
+
<p><strong>Current Usage:</strong> {{ current_usage_gibibytes|round(1) }} GiB</p>
|
|
11
|
+
<p><strong>Allocated Storage:</strong> {{ allocated_storage_gibibytes|round(1) }} GiB</p>
|
|
12
|
+
<p><strong>Usage Percentage:</strong> {{ ((current_usage_gibibytes / allocated_storage_gibibytes) * 100)|round(1) }}%</p>
|
|
13
|
+
<p><strong>Notification Threshold:</strong> {{ notification_threshold_percentage }}%</p>
|
|
14
|
+
<p>Please consider removing old data or increasing your storage allocation to prevent interruption.</p>
|
|
15
|
+
</body>
|
|
16
|
+
</html>
|
phoenix/server/email/types.py
CHANGED
|
@@ -19,8 +19,19 @@ class PasswordResetEmailSender(Protocol):
|
|
|
19
19
|
) -> None: ...
|
|
20
20
|
|
|
21
21
|
|
|
22
|
+
class DbUsageWarningEmailSender(Protocol):
|
|
23
|
+
async def send_db_usage_warning_email(
|
|
24
|
+
self,
|
|
25
|
+
email: str,
|
|
26
|
+
current_usage_gibibytes: float,
|
|
27
|
+
allocated_storage_gibibytes: float,
|
|
28
|
+
notification_threshold_percentage: float,
|
|
29
|
+
) -> None: ...
|
|
30
|
+
|
|
31
|
+
|
|
22
32
|
class EmailSender(
|
|
23
33
|
WelcomeEmailSender,
|
|
24
34
|
PasswordResetEmailSender,
|
|
35
|
+
DbUsageWarningEmailSender,
|
|
25
36
|
Protocol,
|
|
26
37
|
): ...
|
phoenix/server/grpc_server.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from collections.abc import Awaitable, Callable
|
|
2
|
-
from typing import TYPE_CHECKING, Any, Optional
|
|
2
|
+
from typing import TYPE_CHECKING, Any, Iterable, Optional
|
|
3
3
|
|
|
4
4
|
import grpc
|
|
5
5
|
from grpc.aio import RpcContext, Server, ServerInterceptor
|
|
@@ -61,7 +61,7 @@ class GrpcServer:
|
|
|
61
61
|
enable_prometheus: bool = False,
|
|
62
62
|
disabled: bool = False,
|
|
63
63
|
token_store: Optional[CanReadToken] = None,
|
|
64
|
-
interceptors:
|
|
64
|
+
interceptors: Iterable[ServerInterceptor] = (),
|
|
65
65
|
) -> None:
|
|
66
66
|
self._callback = callback
|
|
67
67
|
self._server: Optional[Server] = None
|
|
@@ -69,7 +69,7 @@ class GrpcServer:
|
|
|
69
69
|
self._enable_prometheus = enable_prometheus
|
|
70
70
|
self._disabled = disabled
|
|
71
71
|
self._token_store = token_store
|
|
72
|
-
self._interceptors = interceptors
|
|
72
|
+
self._interceptors = list(interceptors)
|
|
73
73
|
|
|
74
74
|
async def __aenter__(self) -> None:
|
|
75
75
|
interceptors = self._interceptors
|
phoenix/server/prometheus.py
CHANGED
|
@@ -73,6 +73,28 @@ JWT_STORE_API_KEYS_ACTIVE = Gauge(
|
|
|
73
73
|
documentation="Current number of API keys in the JWT store",
|
|
74
74
|
)
|
|
75
75
|
|
|
76
|
+
DB_DISK_USAGE_BYTES = Gauge(
|
|
77
|
+
name="database_disk_usage_bytes",
|
|
78
|
+
documentation="Current database disk usage in bytes",
|
|
79
|
+
)
|
|
80
|
+
DB_DISK_USAGE_RATIO = Gauge(
|
|
81
|
+
name="database_disk_usage_ratio",
|
|
82
|
+
documentation="Current database disk usage as ratio of allocated capacity (0-1)",
|
|
83
|
+
)
|
|
84
|
+
DB_INSERTIONS_BLOCKED = Gauge(
|
|
85
|
+
name="database_insertions_blocked",
|
|
86
|
+
documentation="Whether database insertions are currently blocked due to disk usage "
|
|
87
|
+
"(1 = blocked, 0 = not blocked)",
|
|
88
|
+
)
|
|
89
|
+
DB_DISK_USAGE_WARNING_EMAILS_SENT = Counter(
|
|
90
|
+
name="database_disk_usage_warning_emails_sent_total",
|
|
91
|
+
documentation="Total count of database disk usage warning emails sent",
|
|
92
|
+
)
|
|
93
|
+
DB_DISK_USAGE_WARNING_EMAIL_ERRORS = Counter(
|
|
94
|
+
name="database_disk_usage_warning_email_errors_total",
|
|
95
|
+
documentation="Total count of database disk usage warning email send errors",
|
|
96
|
+
)
|
|
97
|
+
|
|
76
98
|
|
|
77
99
|
class PrometheusMiddleware(BaseHTTPMiddleware):
|
|
78
100
|
async def dispatch(self, request: Request, call_next: RequestResponseEndpoint) -> Response:
|
|
@@ -1,67 +1,67 @@
|
|
|
1
1
|
{
|
|
2
|
-
"_components-
|
|
3
|
-
"file": "assets/components-
|
|
2
|
+
"_components-mOUBHJ12.js": {
|
|
3
|
+
"file": "assets/components-mOUBHJ12.js",
|
|
4
4
|
"name": "components",
|
|
5
5
|
"imports": [
|
|
6
|
-
"_vendor-
|
|
7
|
-
"_pages-
|
|
8
|
-
"_vendor-arizeai-
|
|
9
|
-
"_vendor-codemirror-
|
|
6
|
+
"_vendor-DRWIRkSJ.js",
|
|
7
|
+
"_pages-CCsLkNZY.js",
|
|
8
|
+
"_vendor-arizeai-DUhQaeau.js",
|
|
9
|
+
"_vendor-codemirror-D_6Q6Auv.js",
|
|
10
10
|
"_vendor-three-C5WAXd5r.js"
|
|
11
11
|
]
|
|
12
12
|
},
|
|
13
|
-
"_pages-
|
|
14
|
-
"file": "assets/pages-
|
|
13
|
+
"_pages-CCsLkNZY.js": {
|
|
14
|
+
"file": "assets/pages-CCsLkNZY.js",
|
|
15
15
|
"name": "pages",
|
|
16
16
|
"imports": [
|
|
17
|
-
"_vendor-
|
|
18
|
-
"_vendor-arizeai-
|
|
19
|
-
"_components-
|
|
20
|
-
"_vendor-codemirror-
|
|
21
|
-
"_vendor-recharts-
|
|
17
|
+
"_vendor-DRWIRkSJ.js",
|
|
18
|
+
"_vendor-arizeai-DUhQaeau.js",
|
|
19
|
+
"_components-mOUBHJ12.js",
|
|
20
|
+
"_vendor-codemirror-D_6Q6Auv.js",
|
|
21
|
+
"_vendor-recharts-BNBwj7vz.js"
|
|
22
|
+
]
|
|
23
|
+
},
|
|
24
|
+
"_vendor-DRWIRkSJ.js": {
|
|
25
|
+
"file": "assets/vendor-DRWIRkSJ.js",
|
|
26
|
+
"name": "vendor",
|
|
27
|
+
"imports": [
|
|
28
|
+
"_vendor-three-C5WAXd5r.js"
|
|
29
|
+
],
|
|
30
|
+
"css": [
|
|
31
|
+
"assets/vendor-WIZid84E.css"
|
|
22
32
|
]
|
|
23
33
|
},
|
|
24
34
|
"_vendor-WIZid84E.css": {
|
|
25
35
|
"file": "assets/vendor-WIZid84E.css",
|
|
26
36
|
"src": "_vendor-WIZid84E.css"
|
|
27
37
|
},
|
|
28
|
-
"_vendor-arizeai-
|
|
29
|
-
"file": "assets/vendor-arizeai-
|
|
38
|
+
"_vendor-arizeai-DUhQaeau.js": {
|
|
39
|
+
"file": "assets/vendor-arizeai-DUhQaeau.js",
|
|
30
40
|
"name": "vendor-arizeai",
|
|
31
41
|
"imports": [
|
|
32
|
-
"_vendor-
|
|
42
|
+
"_vendor-DRWIRkSJ.js"
|
|
33
43
|
]
|
|
34
44
|
},
|
|
35
|
-
"_vendor-codemirror-
|
|
36
|
-
"file": "assets/vendor-codemirror-
|
|
45
|
+
"_vendor-codemirror-D_6Q6Auv.js": {
|
|
46
|
+
"file": "assets/vendor-codemirror-D_6Q6Auv.js",
|
|
37
47
|
"name": "vendor-codemirror",
|
|
38
48
|
"imports": [
|
|
39
|
-
"_vendor-
|
|
40
|
-
"_vendor-shiki-
|
|
41
|
-
]
|
|
42
|
-
},
|
|
43
|
-
"_vendor-pg5m6BWE.js": {
|
|
44
|
-
"file": "assets/vendor-pg5m6BWE.js",
|
|
45
|
-
"name": "vendor",
|
|
46
|
-
"imports": [
|
|
47
|
-
"_vendor-three-C5WAXd5r.js"
|
|
48
|
-
],
|
|
49
|
-
"css": [
|
|
50
|
-
"assets/vendor-WIZid84E.css"
|
|
49
|
+
"_vendor-DRWIRkSJ.js",
|
|
50
|
+
"_vendor-shiki-k1qj_XjP.js"
|
|
51
51
|
]
|
|
52
52
|
},
|
|
53
|
-
"_vendor-recharts-
|
|
54
|
-
"file": "assets/vendor-recharts-
|
|
53
|
+
"_vendor-recharts-BNBwj7vz.js": {
|
|
54
|
+
"file": "assets/vendor-recharts-BNBwj7vz.js",
|
|
55
55
|
"name": "vendor-recharts",
|
|
56
56
|
"imports": [
|
|
57
|
-
"_vendor-
|
|
57
|
+
"_vendor-DRWIRkSJ.js"
|
|
58
58
|
]
|
|
59
59
|
},
|
|
60
|
-
"_vendor-shiki-
|
|
61
|
-
"file": "assets/vendor-shiki-
|
|
60
|
+
"_vendor-shiki-k1qj_XjP.js": {
|
|
61
|
+
"file": "assets/vendor-shiki-k1qj_XjP.js",
|
|
62
62
|
"name": "vendor-shiki",
|
|
63
63
|
"imports": [
|
|
64
|
-
"_vendor-
|
|
64
|
+
"_vendor-DRWIRkSJ.js"
|
|
65
65
|
]
|
|
66
66
|
},
|
|
67
67
|
"_vendor-three-C5WAXd5r.js": {
|
|
@@ -69,19 +69,19 @@
|
|
|
69
69
|
"name": "vendor-three"
|
|
70
70
|
},
|
|
71
71
|
"index.tsx": {
|
|
72
|
-
"file": "assets/index-
|
|
72
|
+
"file": "assets/index-CQ_A6K_M.js",
|
|
73
73
|
"name": "index",
|
|
74
74
|
"src": "index.tsx",
|
|
75
75
|
"isEntry": true,
|
|
76
76
|
"imports": [
|
|
77
|
-
"_vendor-
|
|
78
|
-
"_vendor-arizeai-
|
|
79
|
-
"_pages-
|
|
80
|
-
"_components-
|
|
77
|
+
"_vendor-DRWIRkSJ.js",
|
|
78
|
+
"_vendor-arizeai-DUhQaeau.js",
|
|
79
|
+
"_pages-CCsLkNZY.js",
|
|
80
|
+
"_components-mOUBHJ12.js",
|
|
81
81
|
"_vendor-three-C5WAXd5r.js",
|
|
82
|
-
"_vendor-codemirror-
|
|
83
|
-
"_vendor-shiki-
|
|
84
|
-
"_vendor-recharts-
|
|
82
|
+
"_vendor-codemirror-D_6Q6Auv.js",
|
|
83
|
+
"_vendor-shiki-k1qj_XjP.js",
|
|
84
|
+
"_vendor-recharts-BNBwj7vz.js"
|
|
85
85
|
]
|
|
86
86
|
}
|
|
87
87
|
}
|