arize-phoenix 8.1.0__py3-none-any.whl → 8.2.1__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-8.1.0.dist-info → arize_phoenix-8.2.1.dist-info}/METADATA +1 -1
- {arize_phoenix-8.1.0.dist-info → arize_phoenix-8.2.1.dist-info}/RECORD +36 -34
- phoenix/db/models.py +151 -11
- phoenix/server/api/context.py +4 -0
- phoenix/server/api/dataloaders/__init__.py +4 -0
- phoenix/server/api/dataloaders/span_by_id.py +29 -0
- phoenix/server/api/dataloaders/span_descendants.py +24 -15
- phoenix/server/api/dataloaders/span_fields.py +76 -0
- phoenix/server/api/dataloaders/trace_root_spans.py +9 -10
- phoenix/server/api/mutations/chat_mutations.py +10 -7
- phoenix/server/api/queries.py +2 -2
- phoenix/server/api/subscriptions.py +3 -3
- phoenix/server/api/types/Annotation.py +4 -1
- phoenix/server/api/types/DatasetExample.py +2 -2
- phoenix/server/api/types/Project.py +8 -10
- phoenix/server/api/types/ProjectSession.py +2 -2
- phoenix/server/api/types/Span.py +377 -120
- phoenix/server/api/types/SpanIOValue.py +39 -6
- phoenix/server/api/types/Trace.py +17 -15
- phoenix/server/app.py +4 -0
- phoenix/server/prometheus.py +113 -7
- phoenix/server/static/.vite/manifest.json +36 -36
- phoenix/server/static/assets/{components-B-qgPyHv.js → components-CgcYOKnv.js} +175 -170
- phoenix/server/static/assets/{index-D4KO1IcF.js → index-B_Nkd6Rh.js} +2 -2
- phoenix/server/static/assets/{pages-DdcuL3Rh.js → pages-Cz-JsoAE.js} +327 -327
- phoenix/server/static/assets/{vendor-DQp7CrDA.js → vendor-Cqfydjep.js} +117 -117
- phoenix/server/static/assets/{vendor-arizeai-C1nEIEQq.js → vendor-arizeai-WnerlUPN.js} +1 -1
- phoenix/server/static/assets/{vendor-codemirror-BZXYUIkP.js → vendor-codemirror-D-ZZKLFq.js} +1 -1
- phoenix/server/static/assets/{vendor-recharts-BUFpwCVD.js → vendor-recharts-KY97ZPfK.js} +1 -1
- phoenix/server/static/assets/{vendor-shiki-C8L-c9jT.js → vendor-shiki-D5K9GnFn.js} +1 -1
- phoenix/trace/attributes.py +7 -2
- phoenix/version.py +1 -1
- {arize_phoenix-8.1.0.dist-info → arize_phoenix-8.2.1.dist-info}/WHEEL +0 -0
- {arize_phoenix-8.1.0.dist-info → arize_phoenix-8.2.1.dist-info}/entry_points.txt +0 -0
- {arize_phoenix-8.1.0.dist-info → arize_phoenix-8.2.1.dist-info}/licenses/IP_NOTICE +0 -0
- {arize_phoenix-8.1.0.dist-info → arize_phoenix-8.2.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -6,10 +6,10 @@ from typing import TYPE_CHECKING, Annotated, Optional, Union
|
|
|
6
6
|
import strawberry
|
|
7
7
|
from openinference.semconv.trace import SpanAttributes
|
|
8
8
|
from sqlalchemy import desc, select
|
|
9
|
-
from sqlalchemy.orm import contains_eager
|
|
10
9
|
from strawberry import UNSET, Private, lazy
|
|
11
10
|
from strawberry.relay import Connection, GlobalID, Node, NodeID
|
|
12
11
|
from strawberry.types import Info
|
|
12
|
+
from typing_extensions import TypeAlias
|
|
13
13
|
|
|
14
14
|
from phoenix.db import models
|
|
15
15
|
from phoenix.server.api.context import Context
|
|
@@ -20,17 +20,20 @@ from phoenix.server.api.types.pagination import (
|
|
|
20
20
|
connection_from_list,
|
|
21
21
|
)
|
|
22
22
|
from phoenix.server.api.types.SortDir import SortDir
|
|
23
|
-
from phoenix.server.api.types.Span import Span
|
|
23
|
+
from phoenix.server.api.types.Span import Span
|
|
24
24
|
from phoenix.server.api.types.TraceAnnotation import TraceAnnotation, to_gql_trace_annotation
|
|
25
25
|
|
|
26
26
|
if TYPE_CHECKING:
|
|
27
27
|
from phoenix.server.api.types.ProjectSession import ProjectSession
|
|
28
28
|
|
|
29
|
+
ProjectRowId: TypeAlias = int
|
|
30
|
+
TraceRowId: TypeAlias = int
|
|
31
|
+
|
|
29
32
|
|
|
30
33
|
@strawberry.type
|
|
31
34
|
class Trace(Node):
|
|
32
|
-
|
|
33
|
-
project_rowid: Private[
|
|
35
|
+
trace_rowid: NodeID[TraceRowId]
|
|
36
|
+
project_rowid: Private[ProjectRowId]
|
|
34
37
|
project_session_rowid: Private[Optional[int]]
|
|
35
38
|
trace_id: str
|
|
36
39
|
start_time: datetime
|
|
@@ -45,7 +48,7 @@ class Trace(Node):
|
|
|
45
48
|
latency = await session.scalar(
|
|
46
49
|
select(
|
|
47
50
|
models.Trace.latency_ms,
|
|
48
|
-
).where(models.Trace.id == self.
|
|
51
|
+
).where(models.Trace.id == self.trace_rowid)
|
|
49
52
|
)
|
|
50
53
|
return latency
|
|
51
54
|
|
|
@@ -84,10 +87,10 @@ class Trace(Node):
|
|
|
84
87
|
self,
|
|
85
88
|
info: Info[Context, None],
|
|
86
89
|
) -> Optional[Span]:
|
|
87
|
-
|
|
88
|
-
if
|
|
90
|
+
span_rowid = await info.context.data_loaders.trace_root_spans.load(self.trace_rowid)
|
|
91
|
+
if span_rowid is None:
|
|
89
92
|
return None
|
|
90
|
-
return
|
|
93
|
+
return Span(span_rowid=span_rowid)
|
|
91
94
|
|
|
92
95
|
@strawberry.field
|
|
93
96
|
async def spans(
|
|
@@ -105,18 +108,17 @@ class Trace(Node):
|
|
|
105
108
|
before=before if isinstance(before, CursorString) else None,
|
|
106
109
|
)
|
|
107
110
|
stmt = (
|
|
108
|
-
select(models.Span)
|
|
111
|
+
select(models.Span.id)
|
|
109
112
|
.join(models.Trace)
|
|
110
|
-
.where(models.Trace.id == self.
|
|
111
|
-
.options(contains_eager(models.Span.trace).load_only(models.Trace.trace_id))
|
|
113
|
+
.where(models.Trace.id == self.trace_rowid)
|
|
112
114
|
# Sort descending because the root span tends to show up later
|
|
113
115
|
# in the ingestion process.
|
|
114
116
|
.order_by(desc(models.Span.id))
|
|
115
117
|
.limit(first)
|
|
116
118
|
)
|
|
117
119
|
async with info.context.db() as session:
|
|
118
|
-
|
|
119
|
-
data = [
|
|
120
|
+
span_rowids = await session.stream_scalars(stmt)
|
|
121
|
+
data = [Span(span_rowid=span_rowid) async for span_rowid in span_rowids]
|
|
120
122
|
return connection_from_list(data=data, args=args)
|
|
121
123
|
|
|
122
124
|
@strawberry.field(description="Annotations associated with the trace.") # type: ignore
|
|
@@ -126,7 +128,7 @@ class Trace(Node):
|
|
|
126
128
|
sort: Optional[TraceAnnotationSort] = None,
|
|
127
129
|
) -> list[TraceAnnotation]:
|
|
128
130
|
async with info.context.db() as session:
|
|
129
|
-
stmt = select(models.TraceAnnotation).filter_by(span_rowid=self.
|
|
131
|
+
stmt = select(models.TraceAnnotation).filter_by(span_rowid=self.trace_rowid)
|
|
130
132
|
if sort:
|
|
131
133
|
sort_col = getattr(models.TraceAnnotation, sort.col.value)
|
|
132
134
|
if sort.dir is SortDir.desc:
|
|
@@ -141,7 +143,7 @@ class Trace(Node):
|
|
|
141
143
|
|
|
142
144
|
def to_gql_trace(trace: models.Trace) -> Trace:
|
|
143
145
|
return Trace(
|
|
144
|
-
|
|
146
|
+
trace_rowid=trace.id,
|
|
145
147
|
project_rowid=trace.project_rowid,
|
|
146
148
|
project_session_rowid=trace.project_session_rowid,
|
|
147
149
|
trace_id=trace.trace_id,
|
phoenix/server/app.py
CHANGED
|
@@ -94,8 +94,10 @@ from phoenix.server.api.dataloaders import (
|
|
|
94
94
|
SessionTokenUsagesDataLoader,
|
|
95
95
|
SessionTraceLatencyMsQuantileDataLoader,
|
|
96
96
|
SpanAnnotationsDataLoader,
|
|
97
|
+
SpanByIdDataLoader,
|
|
97
98
|
SpanDatasetExamplesDataLoader,
|
|
98
99
|
SpanDescendantsDataLoader,
|
|
100
|
+
SpanFieldsDataLoader,
|
|
99
101
|
SpanProjectsDataLoader,
|
|
100
102
|
TokenCountDataLoader,
|
|
101
103
|
TraceByTraceIdsDataLoader,
|
|
@@ -624,6 +626,8 @@ def create_graphql_router(
|
|
|
624
626
|
session_token_usages=SessionTokenUsagesDataLoader(db),
|
|
625
627
|
session_trace_latency_ms_quantile=SessionTraceLatencyMsQuantileDataLoader(db),
|
|
626
628
|
span_annotations=SpanAnnotationsDataLoader(db),
|
|
629
|
+
span_fields=SpanFieldsDataLoader(db),
|
|
630
|
+
span_by_id=SpanByIdDataLoader(db),
|
|
627
631
|
span_dataset_examples=SpanDatasetExamplesDataLoader(db),
|
|
628
632
|
span_descendants=SpanDescendantsDataLoader(db),
|
|
629
633
|
span_projects=SpanProjectsDataLoader(db),
|
phoenix/server/prometheus.py
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
1
3
|
import time
|
|
4
|
+
from functools import lru_cache
|
|
2
5
|
from threading import Thread
|
|
6
|
+
from typing import Optional
|
|
3
7
|
|
|
4
8
|
import psutil
|
|
5
9
|
from prometheus_client import (
|
|
@@ -31,7 +35,6 @@ RAM_METRIC = Gauge(
|
|
|
31
35
|
CPU_METRIC = Gauge(
|
|
32
36
|
name="cpu_usage_percent",
|
|
33
37
|
documentation="CPU usage percent",
|
|
34
|
-
labelnames=["core"],
|
|
35
38
|
)
|
|
36
39
|
BULK_LOADER_INSERTION_TIME = Summary(
|
|
37
40
|
name="bulk_loader_insertion_time_seconds_summary",
|
|
@@ -101,11 +104,114 @@ def gather_system_data() -> None:
|
|
|
101
104
|
while True:
|
|
102
105
|
time.sleep(1)
|
|
103
106
|
|
|
104
|
-
|
|
105
|
-
swap
|
|
107
|
+
RAM_METRIC.labels(type="virtual").set(estimate_memory_usage_bytes())
|
|
108
|
+
RAM_METRIC.labels(type="swap").set(estimate_swap_usage_bytes())
|
|
109
|
+
if cpu_metric := estimate_cpu_usage_percent():
|
|
110
|
+
CPU_METRIC.set(cpu_metric)
|
|
106
111
|
|
|
107
|
-
RAM_METRIC.labels(type="virtual").set(ram.used)
|
|
108
|
-
RAM_METRIC.labels(type="swap").set(swap.used)
|
|
109
112
|
|
|
110
|
-
|
|
111
|
-
|
|
113
|
+
def estimate_memory_usage_bytes() -> int:
|
|
114
|
+
# https://docs.docker.com/engine/containers/runmetrics/
|
|
115
|
+
# psutil reports host-level metrics, use cgroups if running on linux
|
|
116
|
+
|
|
117
|
+
if sys.platform == "linux":
|
|
118
|
+
cgroup_v1_file = "/sys/fs/cgroup/memory/memory.usage_in_bytes"
|
|
119
|
+
cgroup_v2_file = "/sys/fs/cgroup/memory.current"
|
|
120
|
+
|
|
121
|
+
if is_cgroup_v2():
|
|
122
|
+
try:
|
|
123
|
+
with open(cgroup_v2_file, "r") as f:
|
|
124
|
+
return int(f.read().strip())
|
|
125
|
+
except Exception:
|
|
126
|
+
pass
|
|
127
|
+
else:
|
|
128
|
+
try:
|
|
129
|
+
with open(cgroup_v1_file, "r") as f:
|
|
130
|
+
return int(f.read().strip())
|
|
131
|
+
except Exception:
|
|
132
|
+
pass
|
|
133
|
+
return psutil.virtual_memory().used
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def estimate_swap_usage_bytes() -> int:
|
|
137
|
+
if sys.platform == "linux":
|
|
138
|
+
# cgroup v2: swap usage file (if swap accounting is enabled).
|
|
139
|
+
cgroup_v2_swap_file = "/sys/fs/cgroup/memory.swap.current"
|
|
140
|
+
cgroup_v1_swap_file = "/sys/fs/cgroup/memory/memory.memsw.usage_in_bytes"
|
|
141
|
+
|
|
142
|
+
if is_cgroup_v2() and os.path.exists(cgroup_v2_swap_file):
|
|
143
|
+
try:
|
|
144
|
+
with open(cgroup_v2_swap_file, "r") as f:
|
|
145
|
+
return int(f.read().strip())
|
|
146
|
+
except Exception:
|
|
147
|
+
pass
|
|
148
|
+
elif os.path.exists(cgroup_v1_swap_file):
|
|
149
|
+
try:
|
|
150
|
+
with open(cgroup_v1_swap_file, "r") as f:
|
|
151
|
+
return int(f.read().strip())
|
|
152
|
+
except Exception:
|
|
153
|
+
pass
|
|
154
|
+
return psutil.swap_memory().used
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
_previous_cpu_sample: dict[str, tuple[float, float]] = {} # cache for previous cpu usage sample
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def estimate_cpu_usage_percent() -> Optional[float]:
|
|
161
|
+
# https://docs.docker.com/engine/containers/runmetrics/
|
|
162
|
+
# psutil reports host-level metrics, use cgroups if running on linux
|
|
163
|
+
|
|
164
|
+
current_time = time.time()
|
|
165
|
+
|
|
166
|
+
if sys.platform.startswith("linux"):
|
|
167
|
+
cgroup_v2_cpu_stat = "/sys/fs/cgroup/cpu.stat"
|
|
168
|
+
cgroup_v1_cpu_usage = "/sys/fs/cgroup/cpuacct/cpuacct.usage"
|
|
169
|
+
if is_cgroup_v2():
|
|
170
|
+
try:
|
|
171
|
+
with open(cgroup_v2_cpu_stat, "r") as f:
|
|
172
|
+
lines = f.readlines()
|
|
173
|
+
stats = {}
|
|
174
|
+
for line in lines:
|
|
175
|
+
parts = line.strip().split()
|
|
176
|
+
if len(parts) == 2:
|
|
177
|
+
stats[parts[0]] = float(parts[1])
|
|
178
|
+
if "usage_usec" in stats:
|
|
179
|
+
usage = stats["usage_usec"]
|
|
180
|
+
key = "cgroup_v2"
|
|
181
|
+
if key in _previous_cpu_sample:
|
|
182
|
+
prev_usage, prev_time = _previous_cpu_sample[key]
|
|
183
|
+
delta_usage = usage - prev_usage # in microseconds
|
|
184
|
+
delta_time = current_time - prev_time
|
|
185
|
+
_previous_cpu_sample[key] = (usage, current_time)
|
|
186
|
+
if delta_time > 0:
|
|
187
|
+
# Convert microseconds to seconds.
|
|
188
|
+
return round((delta_usage / (delta_time * 1e6)) * 100, 2)
|
|
189
|
+
else:
|
|
190
|
+
_previous_cpu_sample[key] = (usage, current_time)
|
|
191
|
+
return None # No previous sample yet.
|
|
192
|
+
except Exception:
|
|
193
|
+
pass
|
|
194
|
+
else:
|
|
195
|
+
try:
|
|
196
|
+
with open(cgroup_v1_cpu_usage, "r") as f:
|
|
197
|
+
usage = int(f.read().strip())
|
|
198
|
+
key = "cgroup_v1"
|
|
199
|
+
if key in _previous_cpu_sample:
|
|
200
|
+
prev_usage, prev_time = _previous_cpu_sample[key]
|
|
201
|
+
delta_usage = usage - prev_usage # in nanoseconds
|
|
202
|
+
delta_time = current_time - prev_time
|
|
203
|
+
_previous_cpu_sample[key] = (usage, current_time)
|
|
204
|
+
if delta_time > 0:
|
|
205
|
+
# Convert nanoseconds to seconds.
|
|
206
|
+
return round((delta_usage / (delta_time * 1e9)) * 100, 2)
|
|
207
|
+
else:
|
|
208
|
+
_previous_cpu_sample[key] = (usage, current_time)
|
|
209
|
+
return None # No previous sample yet.
|
|
210
|
+
except Exception:
|
|
211
|
+
pass
|
|
212
|
+
return psutil.cpu_percent(interval=None)
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
@lru_cache(maxsize=1)
|
|
216
|
+
def is_cgroup_v2() -> bool:
|
|
217
|
+
return os.path.exists("/sys/fs/cgroup/cgroup.controllers")
|
|
@@ -1,32 +1,32 @@
|
|
|
1
1
|
{
|
|
2
|
-
"_components-
|
|
3
|
-
"file": "assets/components-
|
|
2
|
+
"_components-CgcYOKnv.js": {
|
|
3
|
+
"file": "assets/components-CgcYOKnv.js",
|
|
4
4
|
"name": "components",
|
|
5
5
|
"imports": [
|
|
6
|
-
"_vendor-
|
|
7
|
-
"_pages-
|
|
8
|
-
"_vendor-arizeai-
|
|
9
|
-
"_vendor-codemirror-
|
|
6
|
+
"_vendor-Cqfydjep.js",
|
|
7
|
+
"_pages-Cz-JsoAE.js",
|
|
8
|
+
"_vendor-arizeai-WnerlUPN.js",
|
|
9
|
+
"_vendor-codemirror-D-ZZKLFq.js",
|
|
10
10
|
"_vendor-three-C-AGeJYv.js"
|
|
11
11
|
]
|
|
12
12
|
},
|
|
13
|
-
"_pages-
|
|
14
|
-
"file": "assets/pages-
|
|
13
|
+
"_pages-Cz-JsoAE.js": {
|
|
14
|
+
"file": "assets/pages-Cz-JsoAE.js",
|
|
15
15
|
"name": "pages",
|
|
16
16
|
"imports": [
|
|
17
|
-
"_vendor-
|
|
18
|
-
"_vendor-arizeai-
|
|
19
|
-
"_components-
|
|
20
|
-
"_vendor-codemirror-
|
|
21
|
-
"_vendor-recharts-
|
|
17
|
+
"_vendor-Cqfydjep.js",
|
|
18
|
+
"_vendor-arizeai-WnerlUPN.js",
|
|
19
|
+
"_components-CgcYOKnv.js",
|
|
20
|
+
"_vendor-codemirror-D-ZZKLFq.js",
|
|
21
|
+
"_vendor-recharts-KY97ZPfK.js"
|
|
22
22
|
]
|
|
23
23
|
},
|
|
24
24
|
"_vendor-Cg6lcjUC.css": {
|
|
25
25
|
"file": "assets/vendor-Cg6lcjUC.css",
|
|
26
26
|
"src": "_vendor-Cg6lcjUC.css"
|
|
27
27
|
},
|
|
28
|
-
"_vendor-
|
|
29
|
-
"file": "assets/vendor-
|
|
28
|
+
"_vendor-Cqfydjep.js": {
|
|
29
|
+
"file": "assets/vendor-Cqfydjep.js",
|
|
30
30
|
"name": "vendor",
|
|
31
31
|
"imports": [
|
|
32
32
|
"_vendor-three-C-AGeJYv.js"
|
|
@@ -35,33 +35,33 @@
|
|
|
35
35
|
"assets/vendor-Cg6lcjUC.css"
|
|
36
36
|
]
|
|
37
37
|
},
|
|
38
|
-
"_vendor-arizeai-
|
|
39
|
-
"file": "assets/vendor-arizeai-
|
|
38
|
+
"_vendor-arizeai-WnerlUPN.js": {
|
|
39
|
+
"file": "assets/vendor-arizeai-WnerlUPN.js",
|
|
40
40
|
"name": "vendor-arizeai",
|
|
41
41
|
"imports": [
|
|
42
|
-
"_vendor-
|
|
42
|
+
"_vendor-Cqfydjep.js"
|
|
43
43
|
]
|
|
44
44
|
},
|
|
45
|
-
"_vendor-codemirror-
|
|
46
|
-
"file": "assets/vendor-codemirror-
|
|
45
|
+
"_vendor-codemirror-D-ZZKLFq.js": {
|
|
46
|
+
"file": "assets/vendor-codemirror-D-ZZKLFq.js",
|
|
47
47
|
"name": "vendor-codemirror",
|
|
48
48
|
"imports": [
|
|
49
|
-
"_vendor-
|
|
50
|
-
"_vendor-shiki-
|
|
49
|
+
"_vendor-Cqfydjep.js",
|
|
50
|
+
"_vendor-shiki-D5K9GnFn.js"
|
|
51
51
|
]
|
|
52
52
|
},
|
|
53
|
-
"_vendor-recharts-
|
|
54
|
-
"file": "assets/vendor-recharts-
|
|
53
|
+
"_vendor-recharts-KY97ZPfK.js": {
|
|
54
|
+
"file": "assets/vendor-recharts-KY97ZPfK.js",
|
|
55
55
|
"name": "vendor-recharts",
|
|
56
56
|
"imports": [
|
|
57
|
-
"_vendor-
|
|
57
|
+
"_vendor-Cqfydjep.js"
|
|
58
58
|
]
|
|
59
59
|
},
|
|
60
|
-
"_vendor-shiki-
|
|
61
|
-
"file": "assets/vendor-shiki-
|
|
60
|
+
"_vendor-shiki-D5K9GnFn.js": {
|
|
61
|
+
"file": "assets/vendor-shiki-D5K9GnFn.js",
|
|
62
62
|
"name": "vendor-shiki",
|
|
63
63
|
"imports": [
|
|
64
|
-
"_vendor-
|
|
64
|
+
"_vendor-Cqfydjep.js"
|
|
65
65
|
]
|
|
66
66
|
},
|
|
67
67
|
"_vendor-three-C-AGeJYv.js": {
|
|
@@ -69,19 +69,19 @@
|
|
|
69
69
|
"name": "vendor-three"
|
|
70
70
|
},
|
|
71
71
|
"index.tsx": {
|
|
72
|
-
"file": "assets/index-
|
|
72
|
+
"file": "assets/index-B_Nkd6Rh.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-Cqfydjep.js",
|
|
78
|
+
"_vendor-arizeai-WnerlUPN.js",
|
|
79
|
+
"_pages-Cz-JsoAE.js",
|
|
80
|
+
"_components-CgcYOKnv.js",
|
|
81
81
|
"_vendor-three-C-AGeJYv.js",
|
|
82
|
-
"_vendor-codemirror-
|
|
83
|
-
"_vendor-shiki-
|
|
84
|
-
"_vendor-recharts-
|
|
82
|
+
"_vendor-codemirror-D-ZZKLFq.js",
|
|
83
|
+
"_vendor-shiki-D5K9GnFn.js",
|
|
84
|
+
"_vendor-recharts-KY97ZPfK.js"
|
|
85
85
|
]
|
|
86
86
|
}
|
|
87
87
|
}
|