@krtclcdy/tersio 2.7.0 → 2.9.0
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.
- package/README.md +2 -2
- package/cli/common.js +4 -4
- package/cli/dashboard.html +560 -184
- package/cli/dashboard.js +4 -4
- package/cli/doctor.js +3 -1
- package/cli/install.js +11 -11
- package/cli/update.js +9 -6
- package/cli/usage.js +17 -3
- package/extensions/shared/usage-ledger.js +35 -1
- package/extensions/tersio-commands/index.js +2 -2
- package/package.json +1 -1
- package/tersio.js +6 -6
package/cli/dashboard.html
CHANGED
|
@@ -8,26 +8,24 @@
|
|
|
8
8
|
<link rel="icon" type="image/png" href="brand.webp">
|
|
9
9
|
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
|
|
10
10
|
<script src="https://unpkg.com/lucide@latest"></script>
|
|
11
|
+
<script src="https://cdn.jsdelivr.net/npm/gsap@3.12.5/dist/gsap.min.js"></script>
|
|
12
|
+
<script src="https://cdn.jsdelivr.net/npm/gsap@3.12.5/dist/ScrollTrigger.min.js"></script>
|
|
13
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource/outfit@5/index.css">
|
|
11
14
|
<style>
|
|
12
15
|
:root {
|
|
13
16
|
--bg: #f4f4f5; --panel: #ffffff; --ink: #18181b; --dim: #52525b;
|
|
14
17
|
--line: rgba(24, 24, 27, .12); --accent: #047857; --accent-soft: rgba(4, 120, 87, .12);
|
|
15
18
|
--track: rgba(24, 24, 27, .08); --grid: rgba(4, 120, 87, .07);
|
|
16
|
-
--cell-0: rgba(24, 24, 27, .06);
|
|
17
|
-
--cell-1: rgba(4, 120, 87, .25); --cell-2: rgba(4, 120, 87, .5);
|
|
18
|
-
--cell-3: rgba(4, 120, 87, .75); --cell-4: #047857;
|
|
19
19
|
}
|
|
20
20
|
@media (prefers-color-scheme: dark) {
|
|
21
21
|
:root {
|
|
22
22
|
--bg: #09090b; --panel: #101014; --ink: #f4f4f5; --dim: #a1a1aa;
|
|
23
23
|
--line: rgba(255, 255, 255, .09); --accent: #34d399; --accent-soft: rgba(52, 211, 153, .1);
|
|
24
24
|
--track: rgba(255, 255, 255, .07); --grid: rgba(52, 211, 153, .05);
|
|
25
|
-
--cell-0: rgba(255, 255, 255, .06);
|
|
26
|
-
--cell-1: rgba(52, 211, 153, .25); --cell-2: rgba(52, 211, 153, .5);
|
|
27
|
-
--cell-3: rgba(52, 211, 153, .75); --cell-4: #34d399;
|
|
28
25
|
}
|
|
29
26
|
}
|
|
30
27
|
body { background: var(--bg); color: var(--ink); }
|
|
28
|
+
.display { font-family: "Outfit", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
|
|
31
29
|
.bg-blueprint {
|
|
32
30
|
background-image: linear-gradient(var(--grid) 1px, transparent 1px),
|
|
33
31
|
linear-gradient(90deg, var(--grid) 1px, transparent 1px);
|
|
@@ -36,27 +34,37 @@
|
|
|
36
34
|
}
|
|
37
35
|
.mono { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-variant-numeric: tabular-nums; }
|
|
38
36
|
.rowline { border-bottom: 1px solid var(--line); }
|
|
37
|
+
.pill { display: inline-flex; align-items: center; gap: 4px; border-radius: 999px; padding: 3px 10px; font-size: 11px; white-space: nowrap; }
|
|
38
|
+
.pill.good { background: var(--accent-soft); color: var(--accent); }
|
|
39
|
+
.pill.bad { background: rgba(248, 113, 113, .12); color: #f87171; }
|
|
40
|
+
.pill.flat { background: var(--track); color: var(--dim); }
|
|
39
41
|
.bar-fill { background: var(--accent); border-radius: 999px; transform-origin: left; }
|
|
40
42
|
.bar-track { background: var(--track); border-radius: 999px; }
|
|
41
|
-
.bar-dim { background: var(--dim); opacity: .55; border-radius: 999px; transform-origin: bottom; }
|
|
42
43
|
.live-dot { background: var(--accent); box-shadow: 0 0 0 0 var(--accent-soft); animation: ping 2s cubic-bezier(0, 0, .2, 1) infinite; }
|
|
43
44
|
@keyframes ping { 75%, 100% { box-shadow: 0 0 0 9px transparent; } }
|
|
44
45
|
.rise { opacity: 0; transform: translateY(26px); }
|
|
45
46
|
.rise.in { opacity: 1; transform: none; transition: opacity .7s cubic-bezier(.16, 1, .3, 1), transform .7s cubic-bezier(.16, 1, .3, 1); }
|
|
46
|
-
.grow { transform: scaleX(0); transition: transform 1.1s cubic-bezier(.16, 1, .3, 1); }
|
|
47
|
-
.grow.in { transform: scaleX(1); }
|
|
48
|
-
.growY { transform: scaleY(0); transition: transform .9s cubic-bezier(.16, 1, .3, 1); }
|
|
49
|
-
.growY.in { transform: scaleY(1); }
|
|
50
47
|
.tilt { transition: transform .25s cubic-bezier(.16, 1, .3, 1), background .25s; }
|
|
51
48
|
.tilt:hover { transform: translateX(6px); background: var(--accent-soft); }
|
|
49
|
+
.stripcell { transition: background .25s; }
|
|
50
|
+
.stripcell:hover { background: var(--accent-soft); }
|
|
51
|
+
button, .seg button, .tilt, .modelcard, .mbar, .cell, .stripcell { cursor: pointer; }
|
|
52
52
|
.btn-push { transition: transform .12s, background .2s; }
|
|
53
53
|
.btn-push:hover { background: var(--accent-soft); }
|
|
54
54
|
.btn-push:active { transform: scale(.96); }
|
|
55
55
|
a.social { color: var(--ink); }
|
|
56
56
|
a.social:hover { color: var(--accent); }
|
|
57
|
-
.
|
|
58
|
-
.
|
|
59
|
-
.
|
|
57
|
+
.seg button { color: var(--dim); border-radius: 8px; transition: background .2s, color .2s; }
|
|
58
|
+
.seg button.on { background: var(--accent-soft); color: var(--ink); }
|
|
59
|
+
.seg button:not(.on):hover { color: var(--ink); }
|
|
60
|
+
.mbar { display: flex; flex-direction: column-reverse; border-radius: 6px 6px 2px 2px; overflow: hidden; min-height: 3px; background: var(--track); }
|
|
61
|
+
.mbar > span { display: block; width: 100%; }
|
|
62
|
+
.monogram { width: 34px; height: 34px; border-radius: 10px; display: grid; place-items: center; font-weight: 700; font-size: 13px; color: #fff; flex-shrink: 0; }
|
|
63
|
+
.monogram svg { width: 18px; height: 18px; fill: #fff; }
|
|
64
|
+
.monogram.sm svg { width: 14px; height: 14px; }
|
|
65
|
+
.modelcard { transition: transform .25s cubic-bezier(.16, 1, .3, 1), border-color .25s; }
|
|
66
|
+
.modelcard:hover { transform: translateY(-4px); border-color: var(--accent); }
|
|
67
|
+
.heatmonth { font-size: 10px; }
|
|
60
68
|
.dock {
|
|
61
69
|
position: sticky; top: 12px; z-index: 50;
|
|
62
70
|
background: color-mix(in srgb, var(--panel) 84%, transparent);
|
|
@@ -64,25 +72,29 @@
|
|
|
64
72
|
border: 1px solid var(--line); border-radius: 20px;
|
|
65
73
|
box-shadow: 0 12px 40px rgba(0, 0, 0, .25);
|
|
66
74
|
}
|
|
67
|
-
.dock a.docklink { transition: transform .22s cubic-bezier(.34, 1.56, .64, 1), background .2s; border-radius: 12px; }
|
|
68
|
-
.dock a.docklink:hover { transform: scale(1.28) translateY(-3px); background: var(--accent-soft); }
|
|
69
|
-
.dock a.docklink:active { transform: scale(1.05); }
|
|
70
75
|
.dock img.brand { border-radius: 10px; }
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
76
|
+
.dock {
|
|
77
|
+
background:
|
|
78
|
+
linear-gradient(var(--panel), var(--panel)) padding-box,
|
|
79
|
+
linear-gradient(120deg, var(--accent-soft), var(--line) 30%, var(--line) 70%, var(--accent-soft)) border-box;
|
|
80
|
+
border: 1px solid transparent;
|
|
74
81
|
}
|
|
82
|
+
.dock .brand { box-shadow: 0 0 12px var(--accent-soft); }
|
|
83
|
+
#reload:hover { box-shadow: 0 0 14px var(--accent-soft); border-color: var(--accent); }
|
|
84
|
+
.spark { display: flex; align-items: flex-end; gap: 3px; }
|
|
85
|
+
.spark > span { flex: 1; min-width: 3px; border-radius: 2px 2px 0 0; background: var(--accent); opacity: .45; }
|
|
86
|
+
.spark > span.top { opacity: 1; box-shadow: 0 0 8px var(--accent-soft); }
|
|
75
87
|
@media (prefers-reduced-motion: reduce) {
|
|
76
88
|
.rise { opacity: 1; transform: none; }
|
|
77
|
-
.grow, .growY { transform: none; transition: none; }
|
|
78
89
|
.live-dot { animation: none; }
|
|
79
|
-
.tilt, .btn-push { transition: none; }
|
|
90
|
+
.tilt, .btn-push, .seg button { transition: none; }
|
|
80
91
|
}
|
|
81
92
|
</style>
|
|
82
93
|
</head>
|
|
83
94
|
<body class="min-h-[100dvh] antialiased">
|
|
84
95
|
<div class="bg-blueprint pointer-events-none fixed inset-0" aria-hidden="true"></div>
|
|
85
96
|
|
|
97
|
+
<main class="overflow-x-hidden w-full max-w-full">
|
|
86
98
|
<div class="relative mx-auto max-w-7xl px-4 sm:px-6 pb-16">
|
|
87
99
|
|
|
88
100
|
<!-- Floating dock navbar -->
|
|
@@ -91,42 +103,82 @@
|
|
|
91
103
|
<img src="brand.webp" alt="Tersio" width="32" height="32" class="brand size-8 rounded-full">
|
|
92
104
|
<span class="leading-tight text-left">
|
|
93
105
|
<span class="block font-bold tracking-tight text-sm">TERSIO GAIN</span>
|
|
94
|
-
<span class="mono block text-[11px]" style="color: var(--dim)"
|
|
106
|
+
<span class="mono block text-[11px]" style="color: var(--dim)">live ledger</span>
|
|
95
107
|
</span>
|
|
96
108
|
</a>
|
|
97
109
|
<span class="mono hidden shrink-0 sm:flex items-center gap-2 text-xs px-2 ml-auto" style="color: var(--dim)">
|
|
98
110
|
<span class="live-dot inline-block size-2 rounded-full"></span>
|
|
99
111
|
<span id="clock">--:--</span>
|
|
100
112
|
</span>
|
|
101
|
-
<
|
|
113
|
+
<span class="hidden sm:block w-px h-5 shrink-0" style="background: var(--line)" aria-hidden="true"></span>
|
|
114
|
+
<button id="reload" class="btn-push mono flex shrink-0 items-center gap-2 text-xs pl-2.5 pr-3 py-2 rounded-xl" style="border: 1px solid var(--line); color: var(--ink)" aria-label="Reload data">
|
|
102
115
|
<i data-lucide="refresh-cw" class="size-3.5"></i><span class="hidden md:inline">Reload</span>
|
|
103
116
|
</button>
|
|
104
117
|
</header>
|
|
105
118
|
|
|
106
|
-
<!-- Hero:
|
|
107
|
-
<section class="
|
|
108
|
-
<
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
119
|
+
<!-- Hero: centered total -->
|
|
120
|
+
<section class="mx-auto max-w-6xl text-center pt-14 pb-10">
|
|
121
|
+
<p class="hero-in mono text-[11px] uppercase tracking-[0.22em] mb-4" style="color: var(--accent)">Live token feed</p>
|
|
122
|
+
<p class="hero-in mono font-bold tracking-tighter leading-none text-6xl md:text-7xl" id="total">0</p>
|
|
123
|
+
<p class="hero-in mono mt-4 text-sm max-w-[62ch] mx-auto" style="color: var(--dim)" id="herosub">session tokens parsed from OMP transcripts. Input, output, cache read, cache write, USD cost, CO2.</p>
|
|
124
|
+
</section>
|
|
125
|
+
|
|
126
|
+
<!-- Savings bento: big USD card + nested right rail -->
|
|
127
|
+
<section class="grid grid-cols-12 grid-flow-dense gap-3" aria-label="Savings">
|
|
128
|
+
<div class="rise col-span-12 lg:col-span-7 lg:row-span-2 rounded-xl p-6 flex flex-col justify-between" style="border: 1px solid var(--line); background: var(--panel)">
|
|
129
|
+
<div>
|
|
130
|
+
<div class="flex items-center justify-between gap-2">
|
|
131
|
+
<p class="mono text-[11px] uppercase tracking-[0.14em]" style="color: var(--dim)">usd cost</p>
|
|
132
|
+
<span class="pill good mono" id="usdDelta">—</span>
|
|
133
|
+
</div>
|
|
134
|
+
<p class="mono font-bold tracking-tighter leading-none mt-2 text-6xl lg:text-7xl" id="usd">-</p>
|
|
135
|
+
</div>
|
|
136
|
+
<div class="mt-4">
|
|
137
|
+
<div class="spark h-16" id="usdSpark"></div>
|
|
138
|
+
<div class="flex gap-4 mt-3 mono text-xs" style="color: var(--dim)">
|
|
139
|
+
<span>~ <span id="usdPerDay" style="color: var(--ink)">-</span>/day</span>
|
|
140
|
+
<span>top <span id="usdTopDay" style="color: var(--ink)">-</span></span>
|
|
141
|
+
<span>x<span id="usdLeverage" style="color: var(--accent)">-</span> cache leverage</span>
|
|
142
|
+
</div>
|
|
143
|
+
</div>
|
|
144
|
+
<p class="mono text-[11px] mt-3" style="color: var(--dim)" id="usdNote">per-model price table</p>
|
|
112
145
|
</div>
|
|
113
|
-
<div class="lg:col-span-5
|
|
114
|
-
<
|
|
115
|
-
<div class="flex justify-between gap-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
146
|
+
<div class="col-span-12 lg:col-span-5 grid grid-cols-2 grid-flow-dense gap-3">
|
|
147
|
+
<div class="rise col-span-2 rounded-xl p-5" style="border: 1px solid var(--line); background: var(--panel)">
|
|
148
|
+
<div class="flex items-center justify-between gap-2">
|
|
149
|
+
<div><p class="mono text-[11px] uppercase tracking-[0.14em]" style="color: var(--dim)">saved by cache</p>
|
|
150
|
+
<p class="mono font-bold text-3xl mt-1" style="color: var(--accent)" id="saved">-</p></div>
|
|
151
|
+
<span class="pill good mono" id="savedDelta">—</span>
|
|
152
|
+
</div>
|
|
153
|
+
<p class="mono text-[11px] mt-2" style="color: var(--dim)">est. vs full input price</p>
|
|
154
|
+
</div>
|
|
155
|
+
<div class="rise col-span-1 rounded-xl p-5" style="border: 1px solid var(--line); background: var(--panel)">
|
|
156
|
+
<div class="flex items-center justify-between gap-2">
|
|
157
|
+
<div><p class="mono text-[11px] uppercase tracking-[0.14em]" style="color: var(--dim)">co2</p>
|
|
158
|
+
<p class="mono font-bold text-3xl mt-1" id="co2">-</p>
|
|
159
|
+
<p class="mt-2"><span class="pill good mono" id="co2Delta">—</span></p></div>
|
|
160
|
+
</div>
|
|
161
|
+
<p class="mono text-[11px] mt-2" style="color: var(--dim)">est. from output</p>
|
|
162
|
+
</div>
|
|
163
|
+
<div class="rise col-span-1 rounded-xl p-5" style="border: 1px solid var(--line); background: var(--panel)">
|
|
164
|
+
<div class="flex items-center justify-between gap-2">
|
|
165
|
+
<div><p class="mono text-[11px] uppercase tracking-[0.14em]" style="color: var(--dim)">cache share</p>
|
|
166
|
+
<p class="mono font-bold text-3xl mt-1" id="cacheShare">-</p>
|
|
167
|
+
<p class="mt-2"><span class="pill good mono" id="cacheDelta">—</span></p></div>
|
|
168
|
+
</div>
|
|
169
|
+
<p class="mono text-[11px] mt-2" style="color: var(--dim)">of tokens cached</p>
|
|
170
|
+
</div>
|
|
119
171
|
</div>
|
|
120
172
|
</section>
|
|
121
173
|
|
|
122
|
-
<!-- Token strip:
|
|
123
|
-
<section class="rise
|
|
174
|
+
<!-- Token strip: nonzero buckets only -->
|
|
175
|
+
<section class="rise mt-3 flex rounded-xl overflow-hidden" style="border: 1px solid var(--line); background: var(--panel)" id="tokens" aria-label="Tokens by bucket"></section>
|
|
124
176
|
|
|
125
|
-
<!--
|
|
177
|
+
<!-- Activity: contribution heatmap, GitHub style -->
|
|
126
178
|
<section id="activity" class="rise mt-8 rounded-xl p-5 overflow-hidden" style="border: 1px solid var(--line); background: var(--panel); scroll-margin-top: 90px" aria-label="Activity graph">
|
|
127
179
|
<div class="flex items-center gap-2 mb-1">
|
|
128
180
|
<i data-lucide="calendar-days" class="size-4" style="color: var(--accent)"></i>
|
|
129
|
-
<h2 class="font-bold tracking-tight text-xl">Activity</h2>
|
|
181
|
+
<h2 class="display font-bold tracking-tight text-xl">Activity</h2>
|
|
130
182
|
<span class="mono text-xs ml-auto" style="color: var(--dim)" id="graphRange"></span>
|
|
131
183
|
</div>
|
|
132
184
|
<p class="mono text-xs mb-4" style="color: var(--dim)">daily session tokens / last 26 weeks / darker means more</p>
|
|
@@ -138,86 +190,110 @@
|
|
|
138
190
|
<span class="cell"></span><span class="cell l1"></span><span class="cell l2"></span><span class="cell l3"></span><span class="cell l4"></span>
|
|
139
191
|
<span>more</span>
|
|
140
192
|
</div>
|
|
193
|
+
<div class="heatmonth mono mt-2 flex" style="color: var(--dim)" id="graphMonths"></div>
|
|
141
194
|
</section>
|
|
142
195
|
|
|
143
|
-
<!--
|
|
144
|
-
<
|
|
196
|
+
<!-- Top models: 3 cards -->
|
|
197
|
+
<section class="mt-8" aria-label="Top models">
|
|
198
|
+
<div class="flex items-center gap-2 mb-1">
|
|
199
|
+
<i data-lucide="cpu" class="size-4" style="color: var(--accent)"></i>
|
|
200
|
+
<h2 class="display font-bold tracking-tight text-xl">Top models</h2>
|
|
201
|
+
<span class="mono text-xs ml-auto" style="color: var(--dim)">usage across sessions</span>
|
|
202
|
+
</div>
|
|
203
|
+
<p class="mono text-xs mb-4" style="color: var(--dim)">week-over-week vs prior 7 days</p>
|
|
204
|
+
<div class="grid grid-cols-1 md:grid-cols-12 grid-flow-dense gap-3" id="modelCards"></div>
|
|
205
|
+
</section>
|
|
145
206
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
<div class="flex gap-2 mt-2 mono text-[10px]" style="color: var(--dim)" id="chartDays"></div>
|
|
156
|
-
</div>
|
|
157
|
-
</section>
|
|
207
|
+
<!-- Models list: full width -->
|
|
208
|
+
<section class="rise mt-8" aria-label="All models">
|
|
209
|
+
<div class="flex items-center gap-2 mb-1">
|
|
210
|
+
<i data-lucide="layers" class="size-4" style="color: var(--accent)"></i>
|
|
211
|
+
<h2 class="display font-bold tracking-tight text-xl">Models</h2>
|
|
212
|
+
</div>
|
|
213
|
+
<p class="mono text-xs mb-4" style="color: var(--dim)">ranked by tokens / top 8</p>
|
|
214
|
+
<ol id="models" class="rounded-xl overflow-hidden" style="border: 1px solid var(--line); background: var(--panel)"></ol>
|
|
215
|
+
</section>
|
|
158
216
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
<ol id="top" class="rounded-xl overflow-hidden" style="border: 1px solid var(--line); background: var(--panel)"></ol>
|
|
166
|
-
<p id="emptyTop" class="mono text-sm py-8 text-center hidden" style="color: var(--dim)">No ledger rows yet. Run tersio commands to record activity.</p>
|
|
167
|
-
</section>
|
|
217
|
+
<!-- Top tools: full-width impact table -->
|
|
218
|
+
<section id="tools" class="rise mt-8 rounded-xl p-5 overflow-hidden" style="border: 1px solid var(--line); background: var(--panel); scroll-margin-top: 90px" aria-label="Top tools">
|
|
219
|
+
<div class="flex items-center gap-2 mb-1">
|
|
220
|
+
<i data-lucide="terminal" class="size-4" style="color: var(--accent)"></i>
|
|
221
|
+
<h2 class="display font-bold tracking-tight text-xl">Top tools</h2>
|
|
222
|
+
<span class="mono text-xs ml-auto" style="color: var(--dim)">tool calls in sessions</span>
|
|
168
223
|
</div>
|
|
224
|
+
<div class="overflow-x-auto">
|
|
225
|
+
<table class="w-full mono text-[13px]" id="topTable">
|
|
226
|
+
<thead>
|
|
227
|
+
<tr class="text-left text-[11px] uppercase tracking-[0.14em]" style="color: var(--dim)">
|
|
228
|
+
<th class="font-normal text-right pr-3 py-2 w-10">#</th>
|
|
229
|
+
<th class="font-normal py-2 pr-3">Tool</th>
|
|
230
|
+
<th class="font-normal text-right py-2 pr-3">Calls</th>
|
|
231
|
+
<th class="font-normal text-right py-2 pr-3">Share</th>
|
|
232
|
+
<th class="font-normal py-2 min-w-32">Impact</th>
|
|
233
|
+
</tr>
|
|
234
|
+
</thead>
|
|
235
|
+
<tbody id="top"></tbody>
|
|
236
|
+
</table>
|
|
237
|
+
</div>
|
|
238
|
+
<p id="emptyTop" class="mono text-sm py-6 text-center hidden" style="color: var(--dim)">No tool calls yet.</p>
|
|
239
|
+
</section>
|
|
169
240
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
<
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
</ul>
|
|
181
|
-
</section>
|
|
182
|
-
|
|
183
|
-
<section class="rise rounded-xl p-5" style="border: 1px solid var(--line); background: var(--panel); transition-delay: .18s" aria-label="Models">
|
|
184
|
-
<div class="flex items-center gap-2 mb-3">
|
|
185
|
-
<i data-lucide="cpu" class="size-4" style="color: var(--accent)"></i>
|
|
186
|
-
<h2 class="font-bold tracking-tight text-xl">Models</h2>
|
|
187
|
-
</div>
|
|
188
|
-
<ol id="models" class="mono text-[13px] space-y-2" style="scroll-margin-top: 90px"></ol>
|
|
189
|
-
</section>
|
|
241
|
+
<!-- Token activity: stacked per-model bars -->
|
|
242
|
+
<section id="modelactivity" class="rise mt-8 rounded-xl p-5" style="border: 1px solid var(--line); background: var(--panel); scroll-margin-top: 90px" aria-label="Token activity">
|
|
243
|
+
<div class="flex flex-wrap items-center gap-3 mb-1">
|
|
244
|
+
<i data-lucide="chart-column" class="size-4" style="color: var(--accent)"></i>
|
|
245
|
+
<h2 class="display font-bold tracking-tight text-xl">Token activity</h2>
|
|
246
|
+
<div class="seg mono text-xs flex items-center gap-1 ml-auto p-1 rounded-[10px]" style="border: 1px solid var(--line)" role="tablist" aria-label="Range">
|
|
247
|
+
<button data-range="daily" class="on px-3 py-1.5" role="tab">Daily</button>
|
|
248
|
+
<button data-range="weekly" class="px-3 py-1.5" role="tab">Weekly</button>
|
|
249
|
+
<button data-range="cumulative" class="px-3 py-1.5" role="tab">Cumulative</button>
|
|
250
|
+
</div>
|
|
190
251
|
</div>
|
|
191
|
-
|
|
252
|
+
<p class="mono text-xs mb-4" style="color: var(--dim)" id="rangeNote">stacked by model / last 60 days</p>
|
|
253
|
+
<div class="flex items-end gap-[3px] h-56" id="bars"></div>
|
|
254
|
+
<div class="flex gap-[3px] mt-2 mono text-[10px]" style="color: var(--dim)" id="barDays"></div>
|
|
255
|
+
<div class="flex flex-wrap gap-x-4 gap-y-1.5 mt-4 mono text-[11px]" style="color: var(--dim)" id="legend"></div>
|
|
256
|
+
</section>
|
|
192
257
|
|
|
193
|
-
<footer class="mono text-xs mt-12 pt-4
|
|
194
|
-
<
|
|
258
|
+
<footer class="mono text-xs mt-12 pt-4" style="color: var(--dim); border-top: 1px solid var(--line)">
|
|
259
|
+
<div class="flex items-center gap-3">
|
|
260
|
+
<span>tersio gain dashboard / single file</span>
|
|
261
|
+
<span class="pill flat" id="verChip">tersio</span>
|
|
262
|
+
</div>
|
|
263
|
+
<div class="flex items-center gap-4 mt-3">
|
|
264
|
+
<span>session tokens stay local — parsed on this machine, never uploaded</span>
|
|
195
265
|
<span class="ml-auto flex items-center gap-1" style="color: var(--ink)">
|
|
196
266
|
<a href="https://github.com/KurutoDenzeru" target="_blank" rel="noopener" aria-label="GitHub" class="btn-push social grid size-8 place-items-center rounded-lg"><svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></a>
|
|
197
267
|
<a href="https://linkedin.com/in/kurtcalacday/" target="_blank" rel="noopener" aria-label="LinkedIn" class="btn-push social grid size-8 place-items-center rounded-lg"><svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"/></svg></a>
|
|
198
268
|
<a href="https://instagram.com/krtclcdy/" target="_blank" rel="noopener" aria-label="Instagram" class="btn-push social grid size-8 place-items-center rounded-lg"><svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M7.0301.084c-1.2768.0602-2.1487.264-2.911.5634-.7888.3075-1.4575.72-2.1228 1.3877-.6652.6677-1.075 1.3368-1.3802 2.127-.2954.7638-.4956 1.6365-.552 2.914-.0564 1.2775-.0689 1.6882-.0626 4.947.0062 3.2586.0206 3.6671.0825 4.9473.061 1.2765.264 2.1482.5635 2.9107.308.7889.72 1.4573 1.388 2.1228.6679.6655 1.3365 1.0743 2.1285 1.38.7632.295 1.6361.4961 2.9134.552 1.2773.056 1.6884.069 4.9462.0627 3.2578-.0062 3.668-.0207 4.9478-.0814 1.28-.0607 2.147-.2652 2.9098-.5633.7889-.3086 1.4578-.72 2.1228-1.3881.665-.6682 1.0745-1.3378 1.3795-2.1284.2957-.7632.4966-1.636.552-2.9124.056-1.2809.0692-1.6898.063-4.948-.0063-3.2583-.021-3.6668-.0817-4.9465-.0607-1.2797-.264-2.1487-.5633-2.9117-.3084-.7889-.72-1.4568-1.3876-2.1228C21.2982 1.33 20.628.9208 19.8378.6165 19.074.321 18.2017.1197 16.9244.0645 15.6471.0093 15.236-.005 11.977.0014 8.718.0076 8.31.0215 7.0301.0839m.1402 21.6932c-1.17-.0509-1.8053-.2453-2.2287-.408-.5606-.216-.96-.4771-1.3819-.895-.422-.4178-.6811-.8186-.9-1.378-.1644-.4234-.3624-1.058-.4171-2.228-.0595-1.2645-.072-1.6442-.079-4.848-.007-3.2037.0053-3.583.0607-4.848.05-1.169.2456-1.805.408-2.2282.216-.5613.4762-.96.895-1.3816.4188-.4217.8184-.6814 1.3783-.9003.423-.1651 1.0575-.3614 2.227-.4171 1.2655-.06 1.6447-.072 4.848-.079 3.2033-.007 3.5835.005 4.8495.0608 1.169.0508 1.8053.2445 2.228.408.5608.216.96.4754 1.3816.895.4217.4194.6816.8176.9005 1.3787.1653.4217.3617 1.056.4169 2.2263.0602 1.2655.0739 1.645.0796 4.848.0058 3.203-.0055 3.5834-.061 4.848-.051 1.17-.245 1.8055-.408 2.2294-.216.5604-.4763.96-.8954 1.3814-.419.4215-.8181.6811-1.3783.9-.4224.1649-1.0577.3617-2.2262.4174-1.2656.0595-1.6448.072-4.8493.079-3.2045.007-3.5825-.006-4.848-.0608M16.953 5.5864A1.44 1.44 0 1 0 18.39 4.144a1.44 1.44 0 0 0-1.437 1.4424M5.8385 12.012c.0067 3.4032 2.7706 6.1557 6.173 6.1493 3.4026-.0065 6.157-2.7701 6.1506-6.1733-.0065-3.4032-2.771-6.1565-6.174-6.1498-3.403.0067-6.156 2.771-6.1496 6.1738M8 12.0077a4 4 0 1 1 4.008 3.9921A3.9996 3.9996 0 0 1 8 12.0077"/></svg></a>
|
|
199
269
|
</span>
|
|
200
|
-
|
|
270
|
+
<a id="rawlink" href="data.json" class="underline underline-offset-2">raw data.json</a>
|
|
271
|
+
</div>
|
|
201
272
|
</footer>
|
|
202
273
|
</div>
|
|
274
|
+
</main>
|
|
203
275
|
|
|
204
276
|
<script>
|
|
205
277
|
(function () {
|
|
206
278
|
var reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
279
|
+
var hasGsap = !reduce && typeof window.gsap !== 'undefined';
|
|
280
|
+
var hasST = hasGsap && typeof window.ScrollTrigger !== 'undefined';
|
|
281
|
+
if (hasST) gsap.registerPlugin(ScrollTrigger);
|
|
207
282
|
|
|
208
283
|
function fmt(n) { return Number(n).toLocaleString('en-US'); }
|
|
284
|
+
function fmtShort(n) {
|
|
285
|
+
if (n >= 1e12) return (n / 1e12).toFixed(1) + 'T';
|
|
286
|
+
if (n >= 1e9) return (n / 1e9).toFixed(1) + 'B';
|
|
287
|
+
if (n >= 1e6) return (n / 1e6).toFixed(1) + 'M';
|
|
288
|
+
if (n >= 1e3) return (n / 1e3).toFixed(1) + 'K';
|
|
289
|
+
return String(Math.round(n));
|
|
290
|
+
}
|
|
209
291
|
|
|
210
292
|
function countUp(el, target, money) {
|
|
211
293
|
function text(v) { return money ? '$' + v.toFixed(2) : fmt(Math.round(v)); }
|
|
212
|
-
if (
|
|
213
|
-
var
|
|
214
|
-
function
|
|
215
|
-
if (!t0) t0 = t;
|
|
216
|
-
var p = Math.min((t - t0) / dur, 1), e = 1 - Math.pow(1 - p, 3);
|
|
217
|
-
el.textContent = text(target * e);
|
|
218
|
-
if (p < 1) requestAnimationFrame(step);
|
|
219
|
-
}
|
|
220
|
-
requestAnimationFrame(step);
|
|
294
|
+
if (!hasGsap || target <= 0) { el.textContent = text(target); return; }
|
|
295
|
+
var o = { v: 0 };
|
|
296
|
+
gsap.to(o, { v: target, duration: 1.1, ease: 'power3.out', onUpdate: function () { el.textContent = text(o.v); } });
|
|
221
297
|
}
|
|
222
298
|
|
|
223
299
|
function tick() {
|
|
@@ -226,86 +302,315 @@
|
|
|
226
302
|
}
|
|
227
303
|
tick(); setInterval(tick, 1000);
|
|
228
304
|
|
|
305
|
+
var VENDORS = [
|
|
306
|
+
[/glm|z-ai|zhipu/i, 'Zhipu', 'Z', '#3b82f6', ''],
|
|
307
|
+
[/muse/i, 'Meta', 'M', '#0082fb', 'M6.915 4.03c-1.968 0-3.683 1.28-4.871 3.113C.704 9.208 0 11.883 0 14.449c0 .706.07 1.369.21 1.973a6.624 6.624 0 0 0 .265.86 5.297 5.297 0 0 0 .371.761c.696 1.159 1.818 1.927 3.593 1.927 1.497 0 2.633-.671 3.965-2.444.76-1.012 1.144-1.626 2.663-4.32l.756-1.339.186-.325c.061.1.121.196.183.3l2.152 3.595c.724 1.21 1.665 2.556 2.47 3.314 1.046.987 1.992 1.22 3.06 1.22 1.075 0 1.876-.355 2.455-.843a3.743 3.743 0 0 0 .81-.973c.542-.939.861-2.127.861-3.745 0-2.72-.681-5.357-2.084-7.45-1.282-1.912-2.957-2.93-4.716-2.93-1.047 0-2.088.467-3.053 1.308-.652.57-1.257 1.29-1.82 2.05-.69-.875-1.335-1.547-1.958-2.056-1.182-.966-2.315-1.303-3.454-1.303zm10.16 2.053c1.147 0 2.188.758 2.992 1.999 1.132 1.748 1.647 4.195 1.647 6.4 0 1.548-.368 2.9-1.839 2.9-.58 0-1.027-.23-1.664-1.004-.496-.601-1.343-1.878-2.832-4.358l-.617-1.028a44.908 44.908 0 0 0-1.255-1.98c.07-.109.141-.224.211-.327 1.12-1.667 2.118-2.602 3.358-2.602zm-10.201.553c1.265 0 2.058.791 2.675 1.446.307.327.737.871 1.234 1.579l-1.02 1.566c-.757 1.163-1.882 3.017-2.837 4.338-1.191 1.649-1.81 1.817-2.486 1.817-.524 0-1.038-.237-1.383-.794-.263-.426-.464-1.13-.464-2.046 0-2.221.63-4.535 1.66-6.088.454-.687.964-1.226 1.533-1.533a2.264 2.264 0 0 1 1.088-.285z'],
|
|
308
|
+
[/qwen|qwq/i, 'Alibaba', 'Q', '#7c3aed', 'M23.919 14.545 20.817 9.17l1.47-2.544a.56.56 0 0 0 0-.566l-1.633-2.83a.57.57 0 0 0-.49-.283h-6.207L12.487.402a.57.57 0 0 0-.49-.284H8.732a.56.56 0 0 0-.49.284L5.139 5.775h-2.94a.56.56 0 0 0-.49.284L.077 8.887a.56.56 0 0 0 0 .567L3.18 14.83l-1.47 2.545a.56.56 0 0 0 0 .566l1.634 2.83a.57.57 0 0 0 .49.283h6.205l1.47 2.545a.57.57 0 0 0 .49.284h3.266a.57.57 0 0 0 .49-.284l3.104-5.375h2.94a.57.57 0 0 0 .49-.283l1.634-2.828a.55.55 0 0 0-.004-.568M8.733.686l1.634 2.828-1.634 2.828H21.8L20.164 9.17H7.425L5.63 6.06Zm1.306 19.801-6.205-.002 1.634-2.83h3.265L2.201 6.344h3.267q3.182 5.517 6.367 11.032zm10.124-5.66L18.53 12l-6.532 11.315-1.634-2.83c2.129-3.673 4.25-7.351 6.373-11.028h3.592l3.102 5.374z'],
|
|
309
|
+
[/deepseek/i, 'DeepSeek', 'D', '#4d6bfe', 'M23.748 4.651c-.254-.124-.364.113-.512.233-.051.04-.094.09-.137.137-.372.397-.806.657-1.373.626-.829-.046-1.537.214-2.163.848-.133-.782-.575-1.248-1.247-1.548-.352-.155-.708-.311-.955-.65-.172-.24-.219-.509-.305-.774-.055-.16-.11-.323-.293-.35-.2-.031-.278.136-.356.276-.313.572-.434 1.202-.422 1.84.027 1.436.633 2.58 1.838 3.393.137.094.172.187.129.323-.082.28-.18.553-.266.833-.055.179-.137.218-.328.14a5.5 5.5 0 0 1-1.737-1.179c-.857-.828-1.631-1.743-2.597-2.46a12 12 0 0 0-.689-.47c-.985-.957.13-1.743.387-1.836.27-.098.094-.433-.778-.428-.872.003-1.67.295-2.687.685a3 3 0 0 1-.465.136 9.6 9.6 0 0 0-2.883-.101c-1.885.21-3.39 1.1-4.497 2.622C.082 8.776-.231 10.854.152 13.02c.403 2.284 1.568 4.175 3.36 5.653 1.857 1.533 3.997 2.284 6.438 2.14 1.482-.085 3.132-.284 4.994-1.86.47.234.962.328 1.78.398.629.058 1.235-.031 1.705-.129.735-.155.684-.836.418-.961-2.155-1.004-1.682-.595-2.112-.926 1.095-1.295 2.768-3.598 3.284-6.733.05-.346.115-.834.108-1.114-.004-.171.035-.238.23-.257a4.2 4.2 0 0 0 1.545-.475c1.397-.763 1.96-2.016 2.093-3.517.02-.23-.004-.467-.247-.588M11.58 18.168c-2.088-1.642-3.101-2.183-3.52-2.16-.39.024-.32.472-.234.763.09.288.207.487.371.74.114.167.192.416-.113.603-.673.416-1.842-.14-1.897-.168-1.361-.801-2.5-1.86-3.301-3.306-.775-1.393-1.225-2.888-1.299-4.482-.02-.385.094-.522.477-.592a4.7 4.7 0 0 1 1.53-.038c2.131.311 3.946 1.264 5.467 2.774.868.86 1.525 1.887 2.202 2.89.72 1.066 1.494 2.082 2.48 2.915.348.291.626.513.892.677-.802.09-2.14.109-3.055-.615zm1.001-6.44a.306.306 0 0 1 .415-.287.3.3 0 0 1 .113.074.3.3 0 0 1 .086.214c0 .17-.136.307-.308.307a.303.303 0 0 1-.306-.307m3.11 1.596c-.2.081-.4.151-.591.16a1.25 1.25 0 0 1-.798-.254c-.274-.23-.47-.358-.551-.758a1.7 1.7 0 0 1 .015-.588c.07-.327-.007-.537-.238-.727-.188-.156-.426-.199-.689-.199a.6.6 0 0 1-.254-.078.253.253 0 0 1-.114-.358 1 1 0 0 1 .192-.21c.356-.202.767-.136 1.146.016.352.144.618.408 1.001.782.392.451.462.576.685.915.176.264.336.536.446.848.066.194-.02.353-.25.45'],
|
|
310
|
+
[/mimo/i, 'Xiaomi', 'Mi', '#ff6900', 'M12 0C8.016 0 4.756.255 2.493 2.516.23 4.776 0 8.033 0 12.012c0 3.98.23 7.235 2.494 9.497C4.757 23.77 8.017 24 12 24c3.983 0 7.243-.23 9.506-2.491C23.77 19.247 24 15.99 24 12.012c0-3.984-.233-7.243-2.502-9.504C19.234.252 15.978 0 12 0zM4.906 7.405h5.624c1.47 0 3.007.068 3.764.827.746.746.827 2.233.83 3.676v4.54a.15.15 0 0 1-.152.147h-1.947a.15.15 0 0 1-.152-.148V11.83c-.002-.806-.048-1.634-.464-2.051-.358-.36-1.026-.441-1.72-.458H7.158a.15.15 0 0 0-.151.147v6.98a.15.15 0 0 1-.152.148H4.906a.15.15 0 0 1-.15-.148V7.554a.15.15 0 0 1 .15-.149zm12.131 0h1.949a.15.15 0 0 1 .15.15v8.892a.15.15 0 0 1-.15.148h-1.949a.15.15 0 0 1-.151-.148V7.554a.15.15 0 0 1 .151-.149zM8.92 10.948h2.046c.083 0 .15.066.15.147v5.352a.15.15 0 0 1-.15.148H8.92a.15.15 0 0 1-.152-.148v-5.352a.15.15 0 0 1 .152-.147Z'],
|
|
311
|
+
[/kimi|moonshot/i, 'Moonshot', 'K', '#a855f7', ''],
|
|
312
|
+
[/minimax/i, 'MiniMax', 'M', '#e11d48', 'M11.43 3.92a.86.86 0 1 0-1.718 0v14.236a1.999 1.999 0 0 1-3.997 0V9.022a.86.86 0 1 0-1.718 0v3.87a1.999 1.999 0 0 1-3.997 0V11.49a.57.57 0 0 1 1.139 0v1.404a.86.86 0 0 0 1.719 0V9.022a1.999 1.999 0 0 1 3.997 0v9.134a.86.86 0 0 0 1.719 0V3.92a1.998 1.998 0 1 1 3.996 0v11.788a.57.57 0 1 1-1.139 0zm10.572 3.105a2 2 0 0 0-1.999 1.997v7.63a.86.86 0 0 1-1.718 0V3.923a1.999 1.999 0 0 0-3.997 0v16.16a.86.86 0 0 1-1.719 0V18.08a.57.57 0 1 0-1.138 0v2a1.998 1.998 0 0 0 3.996 0V3.92a.86.86 0 0 1 1.719 0v12.73a1.999 1.999 0 0 0 3.996 0V9.023a.86.86 0 1 1 1.72 0v6.686a.57.57 0 0 0 1.138 0V9.022a2 2 0 0 0-1.998-1.997'],
|
|
313
|
+
[/nemotron|nvidia/i, 'NVIDIA', 'N', '#76b900', 'M8.948 8.798v-1.43a6.7 6.7 0 0 1 .424-.018c3.922-.124 6.493 3.374 6.493 3.374s-2.774 3.851-5.75 3.851c-.398 0-.787-.062-1.158-.185v-4.346c1.528.185 1.837.857 2.747 2.385l2.04-1.714s-1.492-1.952-4-1.952a6.016 6.016 0 0 0-.796.035m0-4.735v2.138l.424-.027c5.45-.185 9.01 4.47 9.01 4.47s-4.08 4.964-8.33 4.964c-.37 0-.733-.035-1.095-.097v1.325c.3.035.61.062.91.062 3.957 0 6.82-2.023 9.593-4.408.459.371 2.34 1.263 2.73 1.652-2.633 2.208-8.772 3.984-12.253 3.984-.335 0-.653-.018-.971-.053v1.864H24V4.063zm0 10.326v1.131c-3.657-.654-4.673-4.46-4.673-4.46s1.758-1.944 4.673-2.262v1.237H8.94c-1.528-.186-2.73 1.245-2.73 1.245s.68 2.412 2.739 3.11M2.456 10.9s2.164-3.197 6.5-3.533V6.201C4.153 6.59 0 10.653 0 10.653s2.35 6.802 8.948 7.42v-1.237c-4.84-.6-6.492-5.936-6.492-5.936z'],
|
|
314
|
+
[/gpt|openai|codex/i, 'OpenAI', 'O', '#10a37f', 'M22.2819 9.8211a5.9847 5.9847 0 0 0-.5157-4.9108 6.0462 6.0462 0 0 0-6.5098-2.9A6.0651 6.0651 0 0 0 4.9807 4.1818a5.9847 5.9847 0 0 0-3.9977 2.9 6.0462 6.0462 0 0 0 .7427 7.0966 5.98 5.98 0 0 0 .511 4.9107 6.051 6.051 0 0 0 6.5146 2.9001A5.9847 5.9847 0 0 0 13.2599 24a6.0557 6.0557 0 0 0 5.7718-4.2058 5.9894 5.9894 0 0 0 3.9977-2.9001 6.0557 6.0557 0 0 0-.7475-7.0729zm-9.022 12.6081a4.4755 4.4755 0 0 1-2.8764-1.0408l.1419-.0804 4.7783-2.7582a.7948.7948 0 0 0 .3927-.6813v-6.7369l2.02 1.1686a.071.071 0 0 1 .038.052v5.5826a4.504 4.504 0 0 1-4.4945 4.4944zm-9.6607-4.1254a4.4708 4.4708 0 0 1-.5346-3.0137l.142.0852 4.783 2.7582a.7712.7712 0 0 0 .7806 0l5.8428-3.3685v2.3324a.0804.0804 0 0 1-.0332.0615L9.74 19.9502a4.4992 4.4992 0 0 1-6.1408-1.6464zM2.3408 7.8956a4.485 4.485 0 0 1 2.3655-1.9728V11.6a.7664.7664 0 0 0 .3879.6765l5.8144 3.3543-2.0201 1.1685a.0757.0757 0 0 1-.071 0l-4.8303-2.7865A4.504 4.504 0 0 1 2.3408 7.872zm16.5963 3.8558L13.1038 8.364 15.1192 7.2a.0757.0757 0 0 1 .071 0l4.8303 2.7913a4.4944 4.4944 0 0 1-.6765 8.1042v-5.6772a.79.79 0 0 0-.407-.667zm2.0107-3.0231l-.142-.0852-4.7735-2.7818a.7759.7759 0 0 0-.7854 0L9.409 9.2297V6.8974a.0662.0662 0 0 1 .0284-.0615l4.8303-2.7866a4.4992 4.4992 0 0 1 6.6802 4.66zM8.3065 12.863l-2.02-1.1638a.0804.0804 0 0 1-.038-.0567V6.0742a4.4992 4.4992 0 0 1 7.3757-3.4537l-.142.0805L8.704 5.459a.7948.7948 0 0 0-.3927.6813zm1.0976-2.3654l2.602-1.4998 2.6069 1.4998v2.9994l-2.5974 1.4997-2.6067-1.4997Z'],
|
|
315
|
+
[/claude|anthropic/i, 'Anthropic', 'A', '#d97757', 'M17.3041 3.541h-3.6718l6.696 16.918H24Zm-10.6082 0L0 20.459h3.7442l1.3693-3.5527h7.0052l1.3693 3.5528h3.7442L10.5363 3.5409Zm-.3712 10.2232 2.2914-5.9456 2.2914 5.9456Z'],
|
|
316
|
+
[/gemini/i, 'Google', 'G', '#4285f4', 'M11.04 19.32Q12 21.51 12 24q0-2.49.93-4.68.96-2.19 2.58-3.81t3.81-2.55Q21.51 12 24 12q-2.49 0-4.68-.93a12.3 12.3 0 0 1-3.81-2.58 12.3 12.3 0 0 1-2.58-3.81Q12 2.49 12 0q0 2.49-.96 4.68-.93 2.19-2.55 3.81a12.3 12.3 0 0 1-3.81 2.58Q2.49 12 0 12q2.49 0 4.68.96 2.19.93 3.81 2.55t2.55 3.81'],
|
|
317
|
+
[/google/i, 'Google', 'G', '#4285f4', 'M12.48 10.92v3.28h7.84c-.24 1.84-.853 3.187-1.787 4.133-1.147 1.147-2.933 2.4-6.053 2.4-4.827 0-8.6-3.893-8.6-8.72s3.773-8.72 8.6-8.72c2.6 0 4.507 1.027 5.907 2.347l2.307-2.307C18.747 1.44 16.133 0 12.48 0 5.867 0 .307 5.387.307 12s5.56 12 12.173 12c3.573 0 6.267-1.173 8.373-3.36 2.16-2.16 2.84-5.213 2.84-7.667 0-.76-.053-1.467-.173-2.053H12.48z'],
|
|
318
|
+
[/grok|xai/i, 'xAI', 'X', '#71717a', 'M14.234 10.162 22.977 0h-2.072l-7.591 8.824L7.251 0H.258l9.168 13.343L.258 24H2.33l8.016-9.318L16.749 24h6.993zm-2.837 3.299-.929-1.329L3.076 1.56h3.182l5.965 8.532.929 1.329 7.754 11.09h-3.182z'],
|
|
319
|
+
];
|
|
320
|
+
function vendorOf(model) {
|
|
321
|
+
for (var i = 0; i < VENDORS.length; i++) {
|
|
322
|
+
if (VENDORS[i][0].test(model)) return { name: VENDORS[i][1], mark: VENDORS[i][2], color: VENDORS[i][3], icon: VENDORS[i][4] };
|
|
323
|
+
}
|
|
324
|
+
return { name: 'Other', mark: (model || '?').charAt(0).toUpperCase(), color: '#71717a', icon: '' };
|
|
325
|
+
}
|
|
326
|
+
function badgeHTML(v, small) {
|
|
327
|
+
var inner = v.icon
|
|
328
|
+
? '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="' + v.icon + '"/></svg>'
|
|
329
|
+
: '<span>' + v.mark + '</span>';
|
|
330
|
+
return '<span class="monogram' + (small ? ' sm' : '') + '" style="background:' + v.color + '" title="' + v.name + '">' + inner + '</span>';
|
|
331
|
+
}
|
|
332
|
+
var PALETTE = ['#34d399', '#818cf8', '#22d3ee', '#fbbf24', '#f472b6', '#a78bfa', '#fb923c', '#2dd4bf'];
|
|
333
|
+
|
|
229
334
|
function dayKey(d) {
|
|
230
335
|
return d.getFullYear() + '-' + String(d.getMonth() + 1).padStart(2, '0') + '-' + String(d.getDate()).padStart(2, '0');
|
|
231
336
|
}
|
|
337
|
+
function modelTotal(byModel, m) {
|
|
338
|
+
var b = byModel[m] || { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
|
|
339
|
+
return b.input + b.output + b.cacheRead + b.cacheWrite;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
var DATA = null, RANGE = 'daily', cardsShown = false;
|
|
343
|
+
|
|
344
|
+
function topModels(byModel, n) {
|
|
345
|
+
return Object.keys(byModel).sort(function (a, b) { return modelTotal(byModel, b) - modelTotal(byModel, a); }).slice(0, n);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
function allDays() {
|
|
349
|
+
var set = {};
|
|
350
|
+
Object.keys(DATA.byDay || {}).forEach(function (d) { set[d] = 1; });
|
|
351
|
+
Object.keys(DATA.byDayModel || {}).forEach(function (d) { set[d] = 1; });
|
|
352
|
+
return Object.keys(set).sort();
|
|
353
|
+
}
|
|
232
354
|
|
|
233
355
|
function renderGraph(byDay) {
|
|
234
356
|
var g = document.getElementById('graph');
|
|
235
357
|
g.innerHTML = '';
|
|
236
358
|
var today = new Date(); today.setHours(0, 0, 0, 0);
|
|
237
|
-
var start = new Date(today); start.setDate(start.getDate() - (
|
|
359
|
+
var start = new Date(today); start.setDate(start.getDate() - (25 * 7) - today.getDay());
|
|
238
360
|
var max = 1, sums = {};
|
|
239
361
|
Object.keys(byDay).forEach(function (day) {
|
|
240
362
|
var b = byDay[day];
|
|
241
363
|
sums[day] = b.input + b.output + b.cacheRead + b.cacheWrite;
|
|
242
364
|
if (sums[day] > max) max = sums[day];
|
|
243
365
|
});
|
|
244
|
-
var
|
|
366
|
+
var months = document.getElementById('graphMonths');
|
|
367
|
+
months.innerHTML = '';
|
|
368
|
+
var lastMonth = '';
|
|
245
369
|
for (var w = 0; w < 26; w++) {
|
|
246
370
|
var col = document.createElement('div');
|
|
247
|
-
col.
|
|
371
|
+
col.style.cssText = 'display:flex;flex-direction:column;gap:3px;';
|
|
372
|
+
var ml = document.createElement('span');
|
|
373
|
+
ml.className = 'heatmonth w-full truncate';
|
|
248
374
|
for (var i = 0; i < 7; i++) {
|
|
249
|
-
var dt = new Date(start); dt.setDate(dt.getDate() +
|
|
375
|
+
var dt = new Date(start); dt.setDate(dt.getDate() + w * 7 + i);
|
|
250
376
|
var key = dayKey(dt), v = sums[key] || 0, lvl = 0;
|
|
251
377
|
if (v > 0) lvl = Math.min(4, 1 + Math.floor((v / max) * 3.99));
|
|
252
378
|
var cell = document.createElement('span');
|
|
253
379
|
cell.className = 'cell' + (lvl ? ' l' + lvl : '');
|
|
254
380
|
cell.title = key + ': ' + fmt(v) + ' tokens';
|
|
255
381
|
col.appendChild(cell);
|
|
382
|
+
if (i === 0) {
|
|
383
|
+
var mm = dt.toLocaleString('en-US', { month: 'short' });
|
|
384
|
+
ml.textContent = mm !== lastMonth ? mm : '';
|
|
385
|
+
lastMonth = mm;
|
|
386
|
+
}
|
|
256
387
|
}
|
|
257
|
-
weeks++;
|
|
258
388
|
g.appendChild(col);
|
|
389
|
+
months.appendChild(ml);
|
|
259
390
|
}
|
|
391
|
+
// Month labels share the column grid.
|
|
392
|
+
months.className = 'heatmonth mono mt-2 flex';
|
|
393
|
+
months.style.cssText = 'display:flex;gap:3px;';
|
|
394
|
+
Array.prototype.forEach.call(months.children, function (m) { m.className += ' flex-1'; });
|
|
260
395
|
document.getElementById('graphRange').textContent =
|
|
261
396
|
dayKey(start) + ' to ' + dayKey(today);
|
|
262
397
|
}
|
|
263
398
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
399
|
+
// Buckets: [{ key, label, total, segs: [[model, v]] }]
|
|
400
|
+
function buckets() {
|
|
401
|
+
var days = allDays(), tops = topModels(DATA.byModel || {}, 8), out = [];
|
|
402
|
+
if (RANGE === 'daily') {
|
|
403
|
+
var last = days.slice(-60);
|
|
404
|
+
last.forEach(function (d) {
|
|
405
|
+
var per = (DATA.byDayModel || {})[d] || {}, segs = [], total = 0, other = 0;
|
|
406
|
+
tops.forEach(function (m) { var v = per[m] || 0; if (v) { segs.push([m, v]); total += v; } });
|
|
407
|
+
Object.keys(per).forEach(function (m) { if (tops.indexOf(m) < 0) other += per[m]; });
|
|
408
|
+
if (other) { segs.push(['other', other]); total += other; }
|
|
409
|
+
var dt = new Date(d + 'T12:00:00');
|
|
410
|
+
out.push({ key: d, label: isNaN(dt) ? '' : String(dt.getDate()), total: total, segs: segs });
|
|
411
|
+
});
|
|
412
|
+
document.getElementById('rangeNote').textContent = 'stacked by model / last 60 days';
|
|
413
|
+
} else if (RANGE === 'weekly') {
|
|
414
|
+
var weeks = {}, order = [];
|
|
415
|
+
days.forEach(function (d) {
|
|
416
|
+
var dt = new Date(d + 'T12:00:00'); if (isNaN(dt)) return;
|
|
417
|
+
var monday = new Date(dt); monday.setDate(dt.getDate() - ((dt.getDay() + 6) % 7));
|
|
418
|
+
var k = dayKey(monday);
|
|
419
|
+
if (!weeks[k]) { weeks[k] = {}; order.push(k); }
|
|
420
|
+
var per = (DATA.byDayModel || {})[d] || {};
|
|
421
|
+
Object.keys(per).forEach(function (m) { weeks[k][m] = (weeks[k][m] || 0) + per[m]; });
|
|
422
|
+
});
|
|
423
|
+
order.slice(-26).forEach(function (k) {
|
|
424
|
+
var per = weeks[k], segs = [], total = 0, other = 0;
|
|
425
|
+
tops.forEach(function (m) { var v = per[m] || 0; if (v) { segs.push([m, v]); total += v; } });
|
|
426
|
+
Object.keys(per).forEach(function (m) { if (tops.indexOf(m) < 0) other += per[m]; });
|
|
427
|
+
if (other) { segs.push(['other', other]); total += other; }
|
|
428
|
+
var dt = new Date(k + 'T12:00:00');
|
|
429
|
+
out.push({ key: k, label: isNaN(dt) ? '' : (dt.toLocaleString('en-US', { month: 'short' }) + ' ' + dt.getDate()), total: total, segs: segs });
|
|
430
|
+
});
|
|
431
|
+
document.getElementById('rangeNote').textContent = 'stacked by model / last 26 weeks';
|
|
432
|
+
} else {
|
|
433
|
+
var run = {}, cum = 0;
|
|
434
|
+
days.forEach(function (d) {
|
|
435
|
+
var per = (DATA.byDayModel || {})[d] || {}, segs = [], other = 0;
|
|
436
|
+
tops.forEach(function (m) {
|
|
437
|
+
var v = per[m] || 0;
|
|
438
|
+
run[m] = (run[m] || 0) + v;
|
|
439
|
+
if (run[m]) segs.push([m, run[m]]);
|
|
440
|
+
});
|
|
441
|
+
Object.keys(per).forEach(function (m) { if (tops.indexOf(m) < 0) { run[m] = (run[m] || 0) + per[m]; } });
|
|
442
|
+
other = Object.keys(run).reduce(function (a, m) { return tops.indexOf(m) < 0 ? a + run[m] : a; }, 0);
|
|
443
|
+
var tot = segs.reduce(function (a, s) { return a + s[1]; }, 0) + other;
|
|
444
|
+
if (other) segs.push(['other', other]);
|
|
445
|
+
cum = tot;
|
|
446
|
+
var dt = new Date(d + 'T12:00:00');
|
|
447
|
+
out.push({ key: d, label: isNaN(dt) ? '' : String(dt.getDate()), total: tot, segs: segs });
|
|
448
|
+
});
|
|
449
|
+
out = out.slice(-60);
|
|
450
|
+
document.getElementById('rangeNote').textContent = 'running total by model / all time';
|
|
271
451
|
}
|
|
452
|
+
return { list: out, tops: tops };
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
function renderBars() {
|
|
456
|
+
var b = buckets(), wrap = document.getElementById('bars'), axis = document.getElementById('barDays');
|
|
457
|
+
wrap.innerHTML = ''; axis.innerHTML = '';
|
|
272
458
|
var max = 1;
|
|
273
|
-
list.forEach(function (
|
|
274
|
-
list.forEach(function (
|
|
275
|
-
var
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
var
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
459
|
+
b.list.forEach(function (r) { max = Math.max(max, r.total); });
|
|
460
|
+
b.list.forEach(function (r) {
|
|
461
|
+
var col = document.createElement('div');
|
|
462
|
+
col.className = 'flex-1 flex items-end h-full';
|
|
463
|
+
col.title = r.key + ': ' + fmt(r.total) + ' tokens' +
|
|
464
|
+
(r.segs.length ? '\n' + r.segs.map(function (s) { return s[0] + ' ' + fmt(s[1]); }).join('\n') : '');
|
|
465
|
+
var bar = document.createElement('div');
|
|
466
|
+
bar.className = 'mbar w-full';
|
|
467
|
+
bar.style.height = Math.max(2, Math.round(r.total / max * 100)) + '%';
|
|
468
|
+
var order = r.segs.slice().sort(function (x, y) { return y[1] - x[1]; });
|
|
469
|
+
order.forEach(function (s) {
|
|
470
|
+
var seg = document.createElement('span');
|
|
471
|
+
var ci = s[0] === 'other' ? -1 : b.tops.indexOf(s[0]);
|
|
472
|
+
seg.style.background = ci < 0 ? 'var(--dim)' : PALETTE[ci % PALETTE.length];
|
|
473
|
+
seg.style.height = Math.max(1, Math.round(s[1] / r.total * 100)) + '%';
|
|
474
|
+
bar.appendChild(seg);
|
|
475
|
+
});
|
|
476
|
+
col.appendChild(bar); wrap.appendChild(col);
|
|
287
477
|
var lb = document.createElement('span');
|
|
288
|
-
lb.className = 'flex-1 text-center'; lb.textContent =
|
|
289
|
-
|
|
478
|
+
lb.className = 'flex-1 text-center truncate'; lb.textContent = r.label;
|
|
479
|
+
axis.appendChild(lb);
|
|
290
480
|
});
|
|
481
|
+
var legend = document.getElementById('legend');
|
|
482
|
+
legend.innerHTML = '';
|
|
483
|
+
b.tops.slice(0, 8).forEach(function (m, i) {
|
|
484
|
+
var s = document.createElement('span');
|
|
485
|
+
s.className = 'flex items-center gap-1.5';
|
|
486
|
+
var dot = document.createElement('span');
|
|
487
|
+
dot.style.cssText = 'width:9px;height:9px;border-radius:3px;background:' + PALETTE[i % PALETTE.length] + ';display:inline-block';
|
|
488
|
+
s.appendChild(dot);
|
|
489
|
+
s.appendChild(document.createTextNode(m));
|
|
490
|
+
legend.appendChild(s);
|
|
491
|
+
});
|
|
492
|
+
if (hasGsap) {
|
|
493
|
+
gsap.from('#bars > div', { scaleY: 0.2, opacity: 0.2, transformOrigin: 'bottom', duration: 0.5, ease: 'power2.out', stagger: 0.008, overwrite: true });
|
|
494
|
+
if (hasST && !cardsShown) {
|
|
495
|
+
cardsShown = true;
|
|
496
|
+
gsap.from('#modelCards > div', {
|
|
497
|
+
scale: 0.92, opacity: 0.2, duration: 0.6, ease: 'power2.out', stagger: 0.08, overwrite: true,
|
|
498
|
+
scrollTrigger: { trigger: '#modelCards', start: 'top 88%' }
|
|
499
|
+
});
|
|
500
|
+
}
|
|
501
|
+
}
|
|
291
502
|
}
|
|
292
503
|
|
|
293
|
-
function
|
|
294
|
-
var
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
504
|
+
function wow(model) {
|
|
505
|
+
var days = allDays().slice(-14), cur = 0, prev = 0;
|
|
506
|
+
days.forEach(function (d, i) {
|
|
507
|
+
var v = ((DATA.byDayModel || {})[d] || {})[model] || 0;
|
|
508
|
+
if (i < days.length - 7) prev += v; else cur += v;
|
|
509
|
+
});
|
|
510
|
+
if (!prev) return cur ? 'new' : '—';
|
|
511
|
+
var p = Math.round((cur - prev) / prev * 100);
|
|
512
|
+
return (p >= 0 ? '+' : '') + p + '%';
|
|
513
|
+
}
|
|
302
514
|
|
|
303
|
-
|
|
515
|
+
function renderModels() {
|
|
516
|
+
var byModel = DATA.byModel || {}, tops = topModels(byModel, 8);
|
|
517
|
+
var cards = document.getElementById('modelCards');
|
|
518
|
+
cards.innerHTML = '';
|
|
519
|
+
tops.slice(0, 3).forEach(function (m, i) {
|
|
520
|
+
var v = vendorOf(m), d = wow(m);
|
|
521
|
+
var card = document.createElement('div');
|
|
522
|
+
card.className = 'modelcard md:col-span-4 rounded-xl p-5 overflow-hidden relative';
|
|
523
|
+
card.style.cssText = 'border: 1px solid var(--line); background: var(--panel)';
|
|
524
|
+
var ghost = document.createElement('span');
|
|
525
|
+
ghost.className = 'display pointer-events-none select-none absolute -right-2 -bottom-7 font-bold';
|
|
526
|
+
ghost.style.cssText = 'font-size: 120px; line-height: 1; opacity: .07';
|
|
527
|
+
ghost.textContent = v.mark;
|
|
528
|
+
var head = document.createElement('p');
|
|
529
|
+
head.className = 'mono text-xs mb-3'; head.style.color = 'var(--dim)';
|
|
530
|
+
head.textContent = '0' + (i + 1);
|
|
531
|
+
var row = document.createElement('div');
|
|
532
|
+
row.className = 'flex items-center gap-3';
|
|
533
|
+
var badgeWrap = document.createElement('span');
|
|
534
|
+
badgeWrap.innerHTML = badgeHTML(v, false);
|
|
535
|
+
var badge = badgeWrap.firstChild;
|
|
536
|
+
var mid = document.createElement('div'); mid.className = 'min-w-0 flex-1';
|
|
537
|
+
var nm = document.createElement('p'); nm.className = 'mono text-sm font-bold truncate'; nm.textContent = m;
|
|
538
|
+
var vn = document.createElement('p'); vn.className = 'mono text-xs truncate'; vn.style.color = 'var(--dim)'; vn.textContent = v.name;
|
|
539
|
+
mid.appendChild(nm); mid.appendChild(vn);
|
|
540
|
+
var tot = document.createElement('p'); tot.className = 'mono font-bold text-lg shrink-0'; tot.textContent = fmtShort(modelTotal(byModel, m));
|
|
541
|
+
row.appendChild(badge); row.appendChild(mid); row.appendChild(tot);
|
|
542
|
+
var delta = document.createElement('p');
|
|
543
|
+
delta.className = 'mono text-xs mt-3';
|
|
544
|
+
delta.style.color = d.charAt(0) === '-' ? '#f87171' : 'var(--accent)';
|
|
545
|
+
delta.textContent = d;
|
|
546
|
+
card.appendChild(ghost); card.appendChild(head); card.appendChild(row); card.appendChild(delta);
|
|
547
|
+
cards.appendChild(card);
|
|
548
|
+
});
|
|
549
|
+
var ol = document.getElementById('models');
|
|
550
|
+
ol.innerHTML = '';
|
|
551
|
+
var max = 1;
|
|
552
|
+
tops.forEach(function (m) { max = Math.max(max, modelTotal(byModel, m)); });
|
|
553
|
+
tops.forEach(function (m, i) {
|
|
554
|
+
var v = vendorOf(m);
|
|
555
|
+
var li = document.createElement('li');
|
|
556
|
+
li.className = 'tilt flex items-center gap-3 px-4 py-3' + (i < tops.length - 1 ? ' rowline' : '');
|
|
557
|
+
var badgeWrap = document.createElement('span');
|
|
558
|
+
badgeWrap.innerHTML = badgeHTML(v, true);
|
|
559
|
+
var badge = badgeWrap.firstChild;
|
|
560
|
+
badge.style.cssText += 'width:28px;height:28px;font-size:11px;border-radius:8px;';
|
|
561
|
+
var mid = document.createElement('div'); mid.className = 'min-w-0 flex-1';
|
|
562
|
+
var nm = document.createElement('p'); nm.className = 'mono text-sm truncate'; nm.textContent = m;
|
|
563
|
+
var track = document.createElement('div'); track.className = 'bar-track mt-1.5 h-1.5 overflow-hidden';
|
|
564
|
+
var fill = document.createElement('div'); fill.className = 'bar-fill h-full';
|
|
565
|
+
fill.style.width = Math.max(2, Math.round(modelTotal(byModel, m) / max * 100)) + '%';
|
|
566
|
+
track.appendChild(fill); mid.appendChild(nm); mid.appendChild(track);
|
|
567
|
+
var n = document.createElement('span'); n.className = 'mono font-bold shrink-0'; n.textContent = fmt(modelTotal(byModel, m));
|
|
568
|
+
li.appendChild(badge); li.appendChild(mid); li.appendChild(n);
|
|
569
|
+
ol.appendChild(li);
|
|
570
|
+
});
|
|
571
|
+
if (!tops.length) ol.innerHTML = '<li class="mono text-sm px-4 py-6" style="color: var(--dim)">no session tokens yet</li>';
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
function renderTools() {
|
|
575
|
+
var body = document.getElementById('top');
|
|
576
|
+
body.innerHTML = '';
|
|
577
|
+
var tools = DATA.byTool || [], max = 1, sum = 0;
|
|
578
|
+
tools.forEach(function (r) { max = Math.max(max, r[1]); sum += r[1]; });
|
|
579
|
+
tools.forEach(function (r, i) {
|
|
580
|
+
var tr = document.createElement('tr');
|
|
581
|
+
tr.className = 'tilt' + (i < tools.length - 1 ? ' rowline' : '');
|
|
582
|
+
var share = sum ? Math.round(r[1] / sum * 100) : 0;
|
|
583
|
+
tr.innerHTML = '<td class="text-right pr-3 py-2.5 mono text-xs w-10" style="color: var(--dim)"></td>' +
|
|
584
|
+
'<td class="py-2.5 pr-3 truncate" style="max-width: 280px"></td>' +
|
|
585
|
+
'<td class="text-right py-2.5 pr-3 font-bold"></td>' +
|
|
586
|
+
'<td class="text-right py-2.5 pr-3" style="color: var(--dim)"></td>' +
|
|
587
|
+
'<td class="py-2.5 min-w-32"><div class="bar-track h-1.5 overflow-hidden"><div class="bar-fill h-full"></div></div></td>';
|
|
588
|
+
var tds = tr.children;
|
|
589
|
+
tds[0].textContent = String(i + 1).padStart(2, '0');
|
|
590
|
+
tds[1].textContent = r[0];
|
|
591
|
+
tds[1].title = r[0];
|
|
592
|
+
tds[2].textContent = fmt(r[1]);
|
|
593
|
+
tds[3].textContent = share + '%';
|
|
594
|
+
tds[4].firstChild.firstChild.style.width = Math.max(2, Math.round(r[1] / max * 100)) + '%';
|
|
595
|
+
body.appendChild(tr);
|
|
596
|
+
});
|
|
597
|
+
document.getElementById('topTable').style.display = tools.length ? '' : 'none';
|
|
598
|
+
document.getElementById('emptyTop').classList.toggle('hidden', tools.length > 0);
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
function renderStrip(t) {
|
|
602
|
+
var defs = [
|
|
603
|
+
['input', t.input, 'arrow-down-to-line'],
|
|
604
|
+
['output', t.output, 'arrow-up-from-line'],
|
|
605
|
+
['cache read', t.cacheRead, 'hard-drive-download'],
|
|
606
|
+
['cache write', t.cacheWrite, 'hard-drive-upload']
|
|
607
|
+
].filter(function (b) { return b[1] > 0; });
|
|
608
|
+
if (!defs.length) defs = [['input', 0, 'arrow-down-to-line'], ['output', 0, 'arrow-up-from-line']];
|
|
304
609
|
var strip = document.getElementById('tokens');
|
|
305
610
|
strip.innerHTML = '';
|
|
306
|
-
|
|
611
|
+
defs.forEach(function (b, i) {
|
|
307
612
|
var cell = document.createElement('div');
|
|
308
|
-
cell.className = '
|
|
613
|
+
cell.className = 'stripcell flex-1 px-4 py-4' + (i > 0 ? ' sm:border-l' : '');
|
|
309
614
|
cell.style.borderColor = 'var(--line)';
|
|
310
615
|
cell.innerHTML = '<div class="flex items-center gap-2 mono text-[11px] uppercase tracking-[0.14em]" style="color: var(--dim)">' +
|
|
311
616
|
'<i data-lucide="' + b[2] + '" class="size-3.5"></i><span></span></div>' +
|
|
@@ -314,63 +619,126 @@
|
|
|
314
619
|
cell.querySelector('p').textContent = fmt(b[1]);
|
|
315
620
|
strip.appendChild(cell);
|
|
316
621
|
});
|
|
622
|
+
}
|
|
317
623
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
document.getElementById('
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
}).slice(0, 5).forEach(function (row) {
|
|
334
|
-
var li = document.createElement('li');
|
|
335
|
-
li.className = 'flex justify-between gap-2';
|
|
336
|
-
var name = document.createElement('span'); name.className = 'truncate'; name.textContent = row[0];
|
|
337
|
-
var n = document.createElement('span'); n.textContent = fmt(row[1].input + row[1].output);
|
|
338
|
-
li.appendChild(name); li.appendChild(n); models.appendChild(li);
|
|
624
|
+
function money(v) { return '$' + v.toFixed(2); }
|
|
625
|
+
|
|
626
|
+
// 14-day volume sparkline + blended-rate daily stats for the USD card.
|
|
627
|
+
// Daily cost is a blended estimate (total USD / total tokens x day
|
|
628
|
+
// tokens), always rendered with ~ and never mixed with measured totals.
|
|
629
|
+
function renderSpark(byDay, usd, savedUsd, total) {
|
|
630
|
+
var el = document.getElementById('usdSpark');
|
|
631
|
+
el.innerHTML = '';
|
|
632
|
+
var keys = Object.keys(byDay).sort().slice(-14);
|
|
633
|
+
var rate = total ? usd / total : 0;
|
|
634
|
+
var max = 1, vols = [];
|
|
635
|
+
keys.forEach(function (k) {
|
|
636
|
+
var v = dayTotal(byDay[k] || {});
|
|
637
|
+
vols.push({ k: k, v: v });
|
|
638
|
+
max = Math.max(max, v);
|
|
339
639
|
});
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
640
|
+
var top = vols.slice().sort(function (a, b) { return b.v - a.v; })[0] || { k: '', v: 0 };
|
|
641
|
+
vols.forEach(function (r) {
|
|
642
|
+
var s = document.createElement('span');
|
|
643
|
+
if (r.k === top.k && r.v > 0) s.className = 'top';
|
|
644
|
+
s.style.height = Math.max(4, Math.round(r.v / max * 100)) + '%';
|
|
645
|
+
s.title = r.k + ': ' + fmt(r.v) + ' tokens (~$' + (rate * r.v).toFixed(2) + ')';
|
|
646
|
+
el.appendChild(s);
|
|
647
|
+
});
|
|
648
|
+
var days = keys.length || 1;
|
|
649
|
+
document.getElementById('usdPerDay').textContent = '$' + (usd / days).toFixed(2);
|
|
650
|
+
document.getElementById('usdTopDay').textContent = top.k ? top.k.slice(5) + ' ~$' + (rate * top.v).toFixed(2) : '-';
|
|
651
|
+
document.getElementById('usdLeverage').textContent = usd ? (savedUsd / usd).toFixed(1) : '-';
|
|
652
|
+
}
|
|
343
653
|
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
var
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
var
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
654
|
+
// Week-over-week sums from byDay: { cur, prev } for a token selector.
|
|
655
|
+
function weekSplit(days, pick) {
|
|
656
|
+
var keys = Object.keys(days).sort(), cur = 0, prev = 0;
|
|
657
|
+
var last = keys.slice(-14);
|
|
658
|
+
last.forEach(function (k, i) {
|
|
659
|
+
var v = pick(days[k] || {});
|
|
660
|
+
if (i < last.length - 7) prev += v; else cur += v;
|
|
661
|
+
});
|
|
662
|
+
return { cur: cur, prev: prev };
|
|
663
|
+
}
|
|
664
|
+
function pillHTML(cur, prev, goodWhenUp) {
|
|
665
|
+
if (!prev) return { text: cur ? 'new' : '—', cls: 'flat' };
|
|
666
|
+
var p = (cur - prev) / prev * 100, a = Math.abs(p);
|
|
667
|
+
var cls = a < 0.5 ? 'flat' : ((p > 0) === goodWhenUp ? 'good' : 'bad');
|
|
668
|
+
return { text: (p >= 0 ? '▲ +' : '▼ ') + a.toFixed(1) + '% vs prior 7d', cls: cls };
|
|
669
|
+
}
|
|
670
|
+
function setPill(id, cur, prev, goodWhenUp) {
|
|
671
|
+
var el = document.getElementById(id), r = pillHTML(cur, prev, goodWhenUp);
|
|
672
|
+
el.textContent = r.text;
|
|
673
|
+
el.className = 'pill mono ' + r.cls;
|
|
674
|
+
}
|
|
675
|
+
function dayTotal(b) { return (b.input || 0) + (b.output || 0) + (b.cacheRead || 0) + (b.cacheWrite || 0); }
|
|
676
|
+
|
|
677
|
+
function render(d) {
|
|
678
|
+
DATA = d;
|
|
679
|
+
var t = d.tokens || { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
|
|
680
|
+
var total = t.input + t.output + t.cacheRead + t.cacheWrite;
|
|
681
|
+
var sub = document.getElementById('herosub');
|
|
682
|
+
sub.innerHTML = '';
|
|
683
|
+
('input ' + fmt(t.input) + ' · output ' + fmt(t.output) + ' · cache read ' + fmt(t.cacheRead) +
|
|
684
|
+
(t.cacheWrite ? ' · cache write ' + fmt(t.cacheWrite) : '') + ' · ' + money(d.usd || 0)).split(' ').forEach(function (w) {
|
|
685
|
+
var s = document.createElement('span'); s.textContent = w + ' ';
|
|
686
|
+
sub.appendChild(s);
|
|
363
687
|
});
|
|
364
|
-
document.getElementById('
|
|
365
|
-
|
|
688
|
+
var totalEl = document.getElementById('total');
|
|
689
|
+
if (hasGsap) {
|
|
690
|
+
var o = { v: 0 };
|
|
691
|
+
gsap.to(o, { v: total, duration: 1.2, ease: 'power3.out', onUpdate: function () { totalEl.textContent = fmt(o.v); } });
|
|
692
|
+
} else {
|
|
693
|
+
totalEl.textContent = fmt(total);
|
|
694
|
+
}
|
|
695
|
+
countUp(document.getElementById('usd'), d.usd || 0, true);
|
|
696
|
+
document.getElementById('usdNote').textContent = d.priced ? 'per-model price table' : 'incl. default pricing';
|
|
697
|
+
var byDay = d.byDay || {};
|
|
698
|
+
renderSpark(byDay, d.usd || 0, d.savedUsd || 0, total);
|
|
699
|
+
document.getElementById('verChip').textContent = 'tersio v' + (d.version || '?');
|
|
700
|
+
var wAll = weekSplit(byDay, dayTotal);
|
|
701
|
+
setPill('usdDelta', wAll.cur, wAll.prev, false);
|
|
702
|
+
countUp(document.getElementById('saved'), d.savedUsd || 0, true);
|
|
703
|
+
var wCache = weekSplit(byDay, function (b) { return b.cacheRead || 0; });
|
|
704
|
+
setPill('savedDelta', wCache.cur, wCache.prev, true);
|
|
705
|
+
document.getElementById('co2').textContent = '~' + (d.co2g || 0).toFixed(1) + 'g';
|
|
706
|
+
var wOut = weekSplit(byDay, function (b) { return b.output || 0; });
|
|
707
|
+
setPill('co2Delta', wOut.cur, wOut.prev, false);
|
|
708
|
+
var share = total ? Math.round((t.cacheRead + t.cacheWrite) / total * 100) : 0;
|
|
709
|
+
document.getElementById('cacheShare').textContent = share + '%';
|
|
710
|
+
var shareOf = function (b) { var s = dayTotal(b); return s ? ((b.cacheRead || 0) + (b.cacheWrite || 0)) / s * 100 : 0; };
|
|
711
|
+
var keys = Object.keys(byDay).sort(), cPct = 0, pPct = 0, cn = 0, pn = 0;
|
|
712
|
+
keys.slice(-7).forEach(function (k) { cPct += shareOf(byDay[k]); cn++; });
|
|
713
|
+
keys.slice(-14, -7).forEach(function (k) { pPct += shareOf(byDay[k]); pn++; });
|
|
714
|
+
var pp = (cn ? cPct / cn : 0) - (pn ? pPct / pn : 0);
|
|
715
|
+
var cd = document.getElementById('cacheDelta');
|
|
716
|
+
cd.textContent = (pp >= 0 ? '▲ +' : '▼ ') + Math.abs(pp).toFixed(1) + 'pp vs prior 7d';
|
|
717
|
+
cd.className = 'pill mono ' + (Math.abs(pp) < 0.05 ? 'flat' : (pp > 0 ? 'good' : 'bad'));
|
|
718
|
+
|
|
719
|
+
renderStrip(t);
|
|
720
|
+
renderGraph(d.byDay || {});
|
|
721
|
+
renderBars();
|
|
722
|
+
renderModels();
|
|
723
|
+
renderTools();
|
|
366
724
|
|
|
367
725
|
if (window.lucide) lucide.createIcons();
|
|
726
|
+
if (hasGsap) {
|
|
727
|
+
gsap.from('.hero-in', { y: 26, opacity: 0, duration: 0.8, ease: 'power3.out', stagger: 0.08 });
|
|
728
|
+
// Scrub: hero sub words fade in sequence on scroll.
|
|
729
|
+
if (hasST) {
|
|
730
|
+
gsap.fromTo('#herosub span', { opacity: 0.15 }, {
|
|
731
|
+
opacity: 1, ease: 'none', stagger: 0.05,
|
|
732
|
+
scrollTrigger: { trigger: '#herosub', start: 'top 92%', end: 'top 55%', scrub: true }
|
|
733
|
+
});
|
|
734
|
+
}
|
|
735
|
+
}
|
|
368
736
|
observe();
|
|
369
737
|
}
|
|
370
738
|
|
|
371
739
|
var seen = new WeakSet();
|
|
372
740
|
function observe() {
|
|
373
|
-
var els = document.querySelectorAll('.rise
|
|
741
|
+
var els = document.querySelectorAll('.rise');
|
|
374
742
|
if (!('IntersectionObserver' in window) || reduce) {
|
|
375
743
|
els.forEach(function (el) { el.classList.add('in'); });
|
|
376
744
|
return;
|
|
@@ -385,11 +753,19 @@
|
|
|
385
753
|
els.forEach(function (el) { if (!seen.has(el)) io.observe(el); });
|
|
386
754
|
}
|
|
387
755
|
|
|
756
|
+
document.querySelectorAll('.seg button').forEach(function (btn) {
|
|
757
|
+
btn.addEventListener('click', function () {
|
|
758
|
+
document.querySelectorAll('.seg button').forEach(function (b) { b.classList.remove('on'); });
|
|
759
|
+
btn.classList.add('on');
|
|
760
|
+
RANGE = btn.getAttribute('data-range');
|
|
761
|
+
if (DATA) renderBars();
|
|
762
|
+
});
|
|
763
|
+
});
|
|
764
|
+
|
|
388
765
|
function load() {
|
|
389
|
-
document.getElementById('meta').textContent = 'connecting to ledger';
|
|
390
766
|
fetch('data.json').then(function (r) { return r.json(); }).then(render).catch(function () {
|
|
391
|
-
document.getElementById('meta').textContent = 'No live data. Serve with: tersio dashboard';
|
|
392
767
|
document.getElementById('rawlink').style.display = 'none';
|
|
768
|
+
document.getElementById('topTable').style.display = 'none';
|
|
393
769
|
document.getElementById('emptyTop').classList.remove('hidden');
|
|
394
770
|
if (window.lucide) lucide.createIcons();
|
|
395
771
|
observe();
|