@tokcalc/mcp-server 0.1.2 → 0.1.4

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.
Files changed (192) hide show
  1. package/README.md +86 -406
  2. package/dist/index.js +21285 -0
  3. package/package.json +34 -91
  4. package/.zscripts/build.sh +0 -175
  5. package/.zscripts/database-runtime-build.sh +0 -33
  6. package/.zscripts/dev.pid +0 -1
  7. package/.zscripts/dev.sh +0 -154
  8. package/.zscripts/mini-services-build.sh +0 -78
  9. package/.zscripts/mini-services-install.sh +0 -65
  10. package/.zscripts/mini-services-start.sh +0 -123
  11. package/.zscripts/python-runtime-build.sh +0 -120
  12. package/.zscripts/start.sh +0 -145
  13. package/CAPACITY_STUDY.md +0 -283
  14. package/CODE_OF_CONDUCT.md +0 -55
  15. package/CONTRIBUTING.md +0 -177
  16. package/Caddyfile +0 -23
  17. package/LICENSE +0 -204
  18. package/bun.lock +0 -1965
  19. package/components.json +0 -21
  20. package/db/custom.db +0 -0
  21. package/download/README.md +0 -1
  22. package/download/tokcalc-dark-calculator.png +0 -0
  23. package/download/tokcalc-dark-default.png +0 -0
  24. package/download/tokcalc-demo.webm +0 -0
  25. package/download/tokcalc-github-link.png +0 -0
  26. package/download/tokcalc-hydration-fixed.png +0 -0
  27. package/download/tokcalc-issue-resolved.png +0 -0
  28. package/download/tokcalc-light-mode.png +0 -0
  29. package/download/tokcalc-light-reference.png +0 -0
  30. package/download/tokcalc-long-context-qwen.png +0 -0
  31. package/download/tokcalc-long-context.png +0 -0
  32. package/download/tokcalc-og-image-preview.png +0 -0
  33. package/download/tokcalc-phase2-3.png +0 -0
  34. package/download/tokcalc-plain-english.png +0 -0
  35. package/download/tokcalc-preview.png +0 -0
  36. package/download/tokcalc-share-bvb.png +0 -0
  37. package/download/tokcalc-share-feature.png +0 -0
  38. package/download/tokcalc-tab-build-vs-buy.png +0 -0
  39. package/download/tokcalc-tab-calculator.png +0 -0
  40. package/download/tokcalc-tab-reference.png +0 -0
  41. package/eslint.config.mjs +0 -50
  42. package/examples/websocket/frontend.tsx +0 -196
  43. package/examples/websocket/server.ts +0 -138
  44. package/mini-services/.gitkeep +0 -0
  45. package/mini-services/mcp-server/README.md +0 -86
  46. package/mini-services/mcp-server/bun.lock +0 -202
  47. package/mini-services/mcp-server/index.ts +0 -504
  48. package/mini-services/mcp-server/package.json +0 -40
  49. package/next.config.ts +0 -12
  50. package/postcss.config.mjs +0 -5
  51. package/prisma/schema.prisma +0 -32
  52. package/public/google6f58ca6be85fa903.html +0 -1
  53. package/public/logo.svg +0 -29
  54. package/public/manifest.json +0 -51
  55. package/public/og-icon-256.png +0 -0
  56. package/public/og.png +0 -0
  57. package/public/robots.txt +0 -25
  58. package/public/sitemap.xml +0 -23
  59. package/public/tokcalc-demo.gif +0 -0
  60. package/scripts/og-template.html +0 -120
  61. package/scripts/render-og.mjs +0 -43
  62. package/server.json +0 -21
  63. package/src/app/api/pricing/aws/route.ts +0 -186
  64. package/src/app/api/pricing/azure/route.ts +0 -168
  65. package/src/app/api/pricing/gcp/route.ts +0 -230
  66. package/src/app/api/pricing/vast-ai/route.ts +0 -164
  67. package/src/app/api/route.ts +0 -5
  68. package/src/app/compare/h100-vs-h200/layout.tsx +0 -30
  69. package/src/app/compare/h100-vs-h200/page.tsx +0 -328
  70. package/src/app/globals.css +0 -122
  71. package/src/app/layout.tsx +0 -276
  72. package/src/app/page.tsx +0 -2670
  73. package/src/components/azure-live-pricing.tsx +0 -185
  74. package/src/components/benchmark-import.tsx +0 -340
  75. package/src/components/confidence-badge.tsx +0 -116
  76. package/src/components/live-pricing-comparison.tsx +0 -241
  77. package/src/components/theme-provider.tsx +0 -11
  78. package/src/components/theme-toggle.tsx +0 -55
  79. package/src/components/ui/accordion.tsx +0 -66
  80. package/src/components/ui/alert-dialog.tsx +0 -157
  81. package/src/components/ui/alert.tsx +0 -66
  82. package/src/components/ui/aspect-ratio.tsx +0 -11
  83. package/src/components/ui/avatar.tsx +0 -53
  84. package/src/components/ui/badge.tsx +0 -46
  85. package/src/components/ui/breadcrumb.tsx +0 -109
  86. package/src/components/ui/button.tsx +0 -59
  87. package/src/components/ui/calendar.tsx +0 -213
  88. package/src/components/ui/card.tsx +0 -92
  89. package/src/components/ui/carousel.tsx +0 -241
  90. package/src/components/ui/chart.tsx +0 -353
  91. package/src/components/ui/checkbox.tsx +0 -32
  92. package/src/components/ui/collapsible.tsx +0 -33
  93. package/src/components/ui/command.tsx +0 -184
  94. package/src/components/ui/context-menu.tsx +0 -252
  95. package/src/components/ui/dialog.tsx +0 -143
  96. package/src/components/ui/drawer.tsx +0 -135
  97. package/src/components/ui/dropdown-menu.tsx +0 -257
  98. package/src/components/ui/form.tsx +0 -167
  99. package/src/components/ui/hover-card.tsx +0 -44
  100. package/src/components/ui/input-otp.tsx +0 -77
  101. package/src/components/ui/input.tsx +0 -21
  102. package/src/components/ui/label.tsx +0 -24
  103. package/src/components/ui/menubar.tsx +0 -276
  104. package/src/components/ui/navigation-menu.tsx +0 -168
  105. package/src/components/ui/pagination.tsx +0 -127
  106. package/src/components/ui/popover.tsx +0 -48
  107. package/src/components/ui/progress.tsx +0 -31
  108. package/src/components/ui/radio-group.tsx +0 -45
  109. package/src/components/ui/resizable.tsx +0 -56
  110. package/src/components/ui/scroll-area.tsx +0 -58
  111. package/src/components/ui/select.tsx +0 -185
  112. package/src/components/ui/separator.tsx +0 -28
  113. package/src/components/ui/sheet.tsx +0 -139
  114. package/src/components/ui/sidebar.tsx +0 -726
  115. package/src/components/ui/skeleton.tsx +0 -13
  116. package/src/components/ui/slider.tsx +0 -63
  117. package/src/components/ui/sonner.tsx +0 -25
  118. package/src/components/ui/switch.tsx +0 -31
  119. package/src/components/ui/table.tsx +0 -116
  120. package/src/components/ui/tabs.tsx +0 -66
  121. package/src/components/ui/textarea.tsx +0 -18
  122. package/src/components/ui/toast.tsx +0 -129
  123. package/src/components/ui/toaster.tsx +0 -35
  124. package/src/components/ui/toggle-group.tsx +0 -73
  125. package/src/components/ui/toggle.tsx +0 -47
  126. package/src/components/ui/tooltip.tsx +0 -61
  127. package/src/components/vast-ai-live-pricing.tsx +0 -176
  128. package/src/hooks/use-mobile.ts +0 -19
  129. package/src/hooks/use-toast.ts +0 -194
  130. package/src/lib/benchmark-parser-sglang.ts +0 -150
  131. package/src/lib/benchmark-parser-tokcalc.ts +0 -247
  132. package/src/lib/benchmark-parser-trtllm.ts +0 -152
  133. package/src/lib/benchmark-parser-vllm.ts +0 -198
  134. package/src/lib/benchmark-schema.ts +0 -263
  135. package/src/lib/db.ts +0 -13
  136. package/src/lib/engine-presets.ts +0 -183
  137. package/src/lib/price-schema.ts +0 -141
  138. package/src/lib/token-calc.ts +0 -808
  139. package/src/lib/track.ts +0 -31
  140. package/src/lib/url-state.ts +0 -256
  141. package/src/lib/utils.ts +0 -6
  142. package/tailwind.config.ts +0 -64
  143. package/tests/database-runtime-build.sh +0 -75
  144. package/tests/python-runtime-build.sh +0 -64
  145. package/tests/python-runtime-container.sh +0 -31
  146. package/tool-results/bash_1789888171144_2c5381860539.txt +0 -161
  147. package/tool-results/bash_1789888175925_49c53ba3c61b.txt +0 -191
  148. package/tool-results/bash_1789888181202_49c53ba3c61b.txt +0 -191
  149. package/tool-results/bash_1789888195219_4a86a5c91411.txt +0 -200
  150. package/tool-results/bash_1789888203128_6cca13c71b47.txt +0 -199
  151. package/tool-results/bash_1789929256963_2a52aff0d0a8.txt +0 -160
  152. package/tool-results/read_1789888151021_69f58eec6a5b.txt +0 -653
  153. package/tool-results/read_1789888153837_1d3a8bfc2a94.txt +0 -653
  154. package/tool-results/read_1789888163087_ccc406d47505.txt +0 -122
  155. package/tool-results/read_1789888167347_67d1d7c9830a.txt +0 -122
  156. package/tool-results/read_1789929252529_d90e8f383a25.txt +0 -285
  157. package/tsconfig.json +0 -42
  158. package/upload/Pasted Content_1789887800864.txt +0 -652
  159. package/upload/Pasted Content_1789887909561.txt +0 -652
  160. package/upload/Pasted Content_1789887918428.txt +0 -652
  161. package/upload/Pasted Content_1789887959420.txt +0 -652
  162. package/upload/Pasted Content_1789888020485.txt +0 -652
  163. package/upload/Pasted Content_1789888058079.txt +0 -652
  164. package/upload/Pasted Content_1789888885033.txt +0 -686
  165. package/upload/Pasted Content_1789928912741.txt +0 -285
  166. package/upload/Pasted Content_1789928938402.txt +0 -285
  167. package/upload/Pasted Content_1789929160389.txt +0 -285
  168. package/upload/Pasted Content_1789929176660.txt +0 -285
  169. package/upload/issue_vision.json +0 -28
  170. package/upload/pasted_image_1789883175209.png +0 -0
  171. package/upload/pasted_image_1789899056690.png +0 -0
  172. package/upload/pasted_image_1789900371483.png +0 -0
  173. package/upload/pasted_image_1789900472823.png +0 -0
  174. package/upload/pasted_image_1789900490374.png +0 -0
  175. package/upload/pasted_image_1789900585552.png +0 -0
  176. package/upload/pasted_image_1789900606519.png +0 -0
  177. package/upload/pasted_image_1789901598705.png +0 -0
  178. package/upload/pasted_image_1789901613545.png +0 -0
  179. package/upload/pasted_image_1789978382674.png +0 -0
  180. package/upload/pasted_image_1789978392749.png +0 -0
  181. package/upload/pasted_image_1789978474879.png +0 -0
  182. package/upload/pasted_image_1789978523652.png +0 -0
  183. package/upload/pasted_image_1789984219089.png +0 -0
  184. package/upload/pasted_image_1789984491896.png +0 -0
  185. package/upload/pasted_image_1789985017950.png +0 -0
  186. package/upload/pasted_image_1789985036765.png +0 -0
  187. package/upload/pasted_image_1789985049848.png +0 -0
  188. package/upload/pasted_image_1790002427833.png +0 -0
  189. package/upload/pasted_image_1790002659944.png +0 -0
  190. package/upload/pasted_image_1790037038476.png +0 -0
  191. package/upload/screenshot_analysis.json +0 -28
  192. package/upload/vision_output.json +0 -28
@@ -1,176 +0,0 @@
1
- "use client";
2
-
3
- import { useEffect, useState } from "react";
4
- import {
5
- Card,
6
- CardContent,
7
- CardDescription,
8
- CardHeader,
9
- CardTitle,
10
- } from "@/components/ui/card";
11
- import { Button } from "@/components/ui/button";
12
- import { Badge } from "@/components/ui/badge";
13
- import { RefreshCw, Zap, AlertTriangle, TrendingDown } from "lucide-react";
14
- import { track } from "@/lib/track";
15
-
16
- interface VastAiOffer {
17
- gpu: string;
18
- gpuCount: number;
19
- vramGb: number;
20
- pricePerGpuHour: number;
21
- totalPriceHour: number;
22
- reliability: number;
23
- region: string;
24
- bundleId: number;
25
- }
26
-
27
- interface VastAiApiResponse {
28
- source: string;
29
- cached: boolean;
30
- retrievedAt?: string;
31
- count?: number;
32
- offers?: VastAiOffer[];
33
- note?: string;
34
- error?: string;
35
- }
36
-
37
- export function VastAiLivePricing() {
38
- const [data, setData] = useState<VastAiApiResponse | null>(null);
39
- const [loading, setLoading] = useState(false);
40
- const [error, setError] = useState<string | null>(null);
41
-
42
- const fetchPrices = async () => {
43
- setLoading(true);
44
- setError(null);
45
- try {
46
- const res = await fetch("/api/pricing/vast-ai");
47
- if (!res.ok) {
48
- const errData = await res.json().catch(() => ({}));
49
- throw new Error(errData.error || `HTTP ${res.status}`);
50
- }
51
- const json = (await res.json()) as VastAiApiResponse;
52
- setData(json);
53
- track("fetched_live_pricing", { provider: "vast_ai", count: json.count });
54
- } catch (e) {
55
- setError(e instanceof Error ? e.message : "Failed to fetch Vast.ai pricing");
56
- } finally {
57
- setLoading(false);
58
- }
59
- };
60
-
61
- useEffect(() => {
62
- fetchPrices();
63
- }, []);
64
-
65
- const asOfLabel = (() => {
66
- if (!data?.retrievedAt) return null;
67
- const ageMs = Date.now() - new Date(data.retrievedAt).getTime();
68
- if (ageMs < 60000) return "just now";
69
- if (ageMs < 3600000) return `${Math.floor(ageMs / 60000)}m ago`;
70
- return `${Math.floor(ageMs / 3600000)}h ago`;
71
- })();
72
-
73
- const offers = data?.offers || [];
74
-
75
- return (
76
- <Card className="border-amber-500/30 shadow-sm">
77
- <CardHeader className="pb-3">
78
- <div className="flex items-center justify-between">
79
- <div>
80
- <CardTitle className="text-sm flex items-center gap-2">
81
- <TrendingDown className="size-4 text-amber-500" />
82
- Vast.ai marketplace — spot prices
83
- <Badge variant="outline" className="text-[9px] gap-1 ml-1">
84
- <span className="size-1.5 rounded-full bg-amber-500 animate-pulse" />
85
- LIVE
86
- </Badge>
87
- </CardTitle>
88
- <CardDescription className="text-xs mt-1">
89
- Cheapest available GPU offers on Vast.ai marketplace right now.
90
- {asOfLabel && ` Last updated ${asOfLabel}.`}
91
- {" "}Spot prices change rapidly — individual offers may be gone by the time you rent.
92
- </CardDescription>
93
- </div>
94
- <Button
95
- variant="ghost"
96
- size="sm"
97
- onClick={fetchPrices}
98
- disabled={loading}
99
- className="gap-1.5 h-8"
100
- >
101
- <RefreshCw className={`size-3.5 ${loading ? "animate-spin" : ""}`} />
102
- <span className="text-xs">Refresh</span>
103
- </Button>
104
- </div>
105
- </CardHeader>
106
- <CardContent>
107
- {loading && !data && (
108
- <div className="flex items-center justify-center py-8 text-xs text-muted-foreground">
109
- <RefreshCw className="size-4 animate-spin mr-2" />
110
- Fetching Vast.ai marketplace offers...
111
- </div>
112
- )}
113
-
114
- {error && (
115
- <div className="flex items-start gap-2 p-3 rounded-md border border-amber-500/30 bg-amber-500/5 text-xs">
116
- <AlertTriangle className="size-3.5 text-amber-500 shrink-0 mt-0.5" />
117
- <div>
118
- <p className="font-medium text-amber-600 dark:text-amber-400">
119
- Couldn&apos;t fetch marketplace prices
120
- </p>
121
- <p className="text-muted-foreground mt-0.5">{error}</p>
122
- </div>
123
- </div>
124
- )}
125
-
126
- {offers.length > 0 && (
127
- <div className="overflow-x-auto">
128
- <table className="w-full text-xs">
129
- <thead className="bg-muted/40 text-[10px] uppercase">
130
- <tr>
131
- <th className="text-left px-3 py-1.5">GPU</th>
132
- <th className="text-right px-3 py-1.5">$/GPU-hr</th>
133
- <th className="text-right px-3 py-1.5">GPU count</th>
134
- <th className="text-right px-3 py-1.5">Total $/hr</th>
135
- <th className="text-right px-3 py-1.5">VRAM</th>
136
- <th className="text-right px-3 py-1.5">Reliability</th>
137
- <th className="text-left px-3 py-1.5">Region</th>
138
- </tr>
139
- </thead>
140
- <tbody>
141
- {offers.slice(0, 15).map((o, i) => (
142
- <tr key={i} className="border-t border-border/40 hover:bg-muted/20">
143
- <td className="px-3 py-1.5 font-medium">{o.gpu}</td>
144
- <td className="px-3 py-1.5 text-right font-mono text-amber-500 font-semibold">
145
- ${o.pricePerGpuHour}/hr
146
- </td>
147
- <td className="px-3 py-1.5 text-right font-mono">{o.gpuCount}×</td>
148
- <td className="px-3 py-1.5 text-right font-mono text-muted-foreground">${o.totalPriceHour}</td>
149
- <td className="px-3 py-1.5 text-right font-mono text-muted-foreground">{o.vramGb}GB</td>
150
- <td className="px-3 py-1.5 text-right font-mono">
151
- <span className={o.reliability > 0.9 ? "text-emerald-500" : o.reliability > 0.7 ? "text-amber-500" : "text-red-500"}>
152
- {(o.reliability * 100).toFixed(0)}%
153
- </span>
154
- </td>
155
- <td className="px-3 py-1.5 text-muted-foreground text-[10px]">{o.region || "—"}</td>
156
- </tr>
157
- ))}
158
- </tbody>
159
- </table>
160
- <p className="text-[10px] text-muted-foreground mt-2 leading-relaxed">
161
- Spot-market prices from Vast.ai marketplace.
162
- Reliability score (0-100%) indicates host trustworthiness.
163
- Total $/hr is the full bundle price (all GPUs + CPU + RAM).
164
- Source: <a
165
- href="https://vast.ai/pricing"
166
- target="_blank"
167
- rel="noopener noreferrer"
168
- className="text-amber-500 hover:underline"
169
- >Vast.ai marketplace API ↗</a>
170
- </p>
171
- </div>
172
- )}
173
- </CardContent>
174
- </Card>
175
- );
176
- }
@@ -1,19 +0,0 @@
1
- import * as React from "react"
2
-
3
- const MOBILE_BREAKPOINT = 768
4
-
5
- export function useIsMobile() {
6
- const [isMobile, setIsMobile] = React.useState<boolean | undefined>(undefined)
7
-
8
- React.useEffect(() => {
9
- const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`)
10
- const onChange = () => {
11
- setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
12
- }
13
- mql.addEventListener("change", onChange)
14
- setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
15
- return () => mql.removeEventListener("change", onChange)
16
- }, [])
17
-
18
- return !!isMobile
19
- }
@@ -1,194 +0,0 @@
1
- "use client"
2
-
3
- // Inspired by react-hot-toast library
4
- import * as React from "react"
5
-
6
- import type {
7
- ToastActionElement,
8
- ToastProps,
9
- } from "@/components/ui/toast"
10
-
11
- const TOAST_LIMIT = 1
12
- const TOAST_REMOVE_DELAY = 1000000
13
-
14
- type ToasterToast = ToastProps & {
15
- id: string
16
- title?: React.ReactNode
17
- description?: React.ReactNode
18
- action?: ToastActionElement
19
- }
20
-
21
- const actionTypes = {
22
- ADD_TOAST: "ADD_TOAST",
23
- UPDATE_TOAST: "UPDATE_TOAST",
24
- DISMISS_TOAST: "DISMISS_TOAST",
25
- REMOVE_TOAST: "REMOVE_TOAST",
26
- } as const
27
-
28
- let count = 0
29
-
30
- function genId() {
31
- count = (count + 1) % Number.MAX_SAFE_INTEGER
32
- return count.toString()
33
- }
34
-
35
- type ActionType = typeof actionTypes
36
-
37
- type Action =
38
- | {
39
- type: ActionType["ADD_TOAST"]
40
- toast: ToasterToast
41
- }
42
- | {
43
- type: ActionType["UPDATE_TOAST"]
44
- toast: Partial<ToasterToast>
45
- }
46
- | {
47
- type: ActionType["DISMISS_TOAST"]
48
- toastId?: ToasterToast["id"]
49
- }
50
- | {
51
- type: ActionType["REMOVE_TOAST"]
52
- toastId?: ToasterToast["id"]
53
- }
54
-
55
- interface State {
56
- toasts: ToasterToast[]
57
- }
58
-
59
- const toastTimeouts = new Map<string, ReturnType<typeof setTimeout>>()
60
-
61
- const addToRemoveQueue = (toastId: string) => {
62
- if (toastTimeouts.has(toastId)) {
63
- return
64
- }
65
-
66
- const timeout = setTimeout(() => {
67
- toastTimeouts.delete(toastId)
68
- dispatch({
69
- type: "REMOVE_TOAST",
70
- toastId: toastId,
71
- })
72
- }, TOAST_REMOVE_DELAY)
73
-
74
- toastTimeouts.set(toastId, timeout)
75
- }
76
-
77
- export const reducer = (state: State, action: Action): State => {
78
- switch (action.type) {
79
- case "ADD_TOAST":
80
- return {
81
- ...state,
82
- toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT),
83
- }
84
-
85
- case "UPDATE_TOAST":
86
- return {
87
- ...state,
88
- toasts: state.toasts.map((t) =>
89
- t.id === action.toast.id ? { ...t, ...action.toast } : t
90
- ),
91
- }
92
-
93
- case "DISMISS_TOAST": {
94
- const { toastId } = action
95
-
96
- // ! Side effects ! - This could be extracted into a dismissToast() action,
97
- // but I'll keep it here for simplicity
98
- if (toastId) {
99
- addToRemoveQueue(toastId)
100
- } else {
101
- state.toasts.forEach((toast) => {
102
- addToRemoveQueue(toast.id)
103
- })
104
- }
105
-
106
- return {
107
- ...state,
108
- toasts: state.toasts.map((t) =>
109
- t.id === toastId || toastId === undefined
110
- ? {
111
- ...t,
112
- open: false,
113
- }
114
- : t
115
- ),
116
- }
117
- }
118
- case "REMOVE_TOAST":
119
- if (action.toastId === undefined) {
120
- return {
121
- ...state,
122
- toasts: [],
123
- }
124
- }
125
- return {
126
- ...state,
127
- toasts: state.toasts.filter((t) => t.id !== action.toastId),
128
- }
129
- }
130
- }
131
-
132
- const listeners: Array<(state: State) => void> = []
133
-
134
- let memoryState: State = { toasts: [] }
135
-
136
- function dispatch(action: Action) {
137
- memoryState = reducer(memoryState, action)
138
- listeners.forEach((listener) => {
139
- listener(memoryState)
140
- })
141
- }
142
-
143
- type Toast = Omit<ToasterToast, "id">
144
-
145
- function toast({ ...props }: Toast) {
146
- const id = genId()
147
-
148
- const update = (props: ToasterToast) =>
149
- dispatch({
150
- type: "UPDATE_TOAST",
151
- toast: { ...props, id },
152
- })
153
- const dismiss = () => dispatch({ type: "DISMISS_TOAST", toastId: id })
154
-
155
- dispatch({
156
- type: "ADD_TOAST",
157
- toast: {
158
- ...props,
159
- id,
160
- open: true,
161
- onOpenChange: (open) => {
162
- if (!open) dismiss()
163
- },
164
- },
165
- })
166
-
167
- return {
168
- id: id,
169
- dismiss,
170
- update,
171
- }
172
- }
173
-
174
- function useToast() {
175
- const [state, setState] = React.useState<State>(memoryState)
176
-
177
- React.useEffect(() => {
178
- listeners.push(setState)
179
- return () => {
180
- const index = listeners.indexOf(setState)
181
- if (index > -1) {
182
- listeners.splice(index, 1)
183
- }
184
- }
185
- }, [state])
186
-
187
- return {
188
- ...state,
189
- toast,
190
- dismiss: (toastId?: string) => dispatch({ type: "DISMISS_TOAST", toastId }),
191
- }
192
- }
193
-
194
- export { useToast, toast }
@@ -1,150 +0,0 @@
1
- /**
2
- * SGLang benchmark parser.
3
- *
4
- * SGLang's benchmark scripts produce JSON/log output with fields like:
5
- * - total_throughput or output_throughput (tokens/s)
6
- * - mean_ttft or ttft_avg (ms)
7
- * - mean_itl or itl_avg (ms)
8
- * - total_input_tokens, total_output_tokens
9
- * - num_requests
10
- * - concurrency
11
- * - model_id
12
- *
13
- * SGLang output format varies by benchmark script version. This parser
14
- * handles common aliases across SGLang v0.3.x → v0.5.x.
15
- */
16
-
17
- import type {
18
- BenchmarkParser,
19
- BenchmarkRecord,
20
- ConfidenceTier,
21
- } from "./benchmark-schema";
22
- import { generateBenchmarkId } from "./benchmark-schema";
23
-
24
- export const sglangParser: BenchmarkParser = {
25
- name: "sglang-json",
26
- version: "v1",
27
- formatLabel: "SGLang benchmark JSON",
28
-
29
- detect(rawText: string): boolean {
30
- try {
31
- const data = JSON.parse(rawText);
32
- return !!(
33
- data &&
34
- (data.total_throughput ||
35
- data.output_throughput ||
36
- data.mean_ttft ||
37
- data.ttft_avg ||
38
- data.mean_itl ||
39
- data.itl_avg ||
40
- data.num_requests ||
41
- data.total_input_tokens)
42
- );
43
- } catch {
44
- // Also check for SGLang log format (not JSON)
45
- return rawText.includes("sglang") && rawText.includes("throughput");
46
- }
47
- },
48
-
49
- parse(rawText: string): BenchmarkRecord | null {
50
- try {
51
- // Try JSON first
52
- const data = JSON.parse(rawText);
53
- if (!data) return null;
54
-
55
- const modelId = data.model_id || data.model || "unknown";
56
- const modelDisplayName = modelId.split("/").pop() || modelId;
57
-
58
- const outputThroughput =
59
- data.output_throughput ?? data.total_throughput ?? data.throughput ?? 0;
60
- const meanTtft = data.mean_ttft ?? data.ttft_avg ?? data.ttft_mean;
61
- const p99Ttft = data.p99_ttft ?? data.ttft_p99;
62
- const meanItl = data.mean_itl ?? data.itl_avg ?? data.itl_mean;
63
- const p99Itl = data.p99_itl ?? data.itl_p99;
64
-
65
- const numRequests = data.num_requests ?? data.completed ?? 0;
66
- const inputLen = Number(data.input_len ?? data.mean_input_len ?? 0);
67
- const outputLen = Number(data.output_len ?? data.mean_output_len ?? 0);
68
- const concurrency = data.concurrency ?? data.num_procs ?? 1;
69
-
70
- const confidenceTier: ConfidenceTier =
71
- modelId !== "unknown" && outputThroughput > 0 && numRequests > 0
72
- ? "community_reproducible"
73
- : "community_unverified";
74
-
75
- return {
76
- benchmark_id: generateBenchmarkId(),
77
- source_name: "sglang",
78
- source_url: data.source_url || "https://github.com/sgl-project/sglang",
79
- source_license: "Apache-2.0",
80
- ingestion_method: "uploaded_raw_artifact",
81
- retrieved_at: new Date().toISOString(),
82
- parser_name: "sglang-json",
83
- parser_version: "v1",
84
- confidence_tier: confidenceTier,
85
- verification_status: "schema_valid",
86
-
87
- model_id: modelId,
88
- model_display_name: modelDisplayName,
89
- model_revision: data.model_revision || "unspecified",
90
- architecture: data.architecture,
91
- parameter_count_b: data.parameter_count_b,
92
- context_window_tokens: data.max_model_len,
93
- quantization_format: data.quantization || data.dtype || "unspecified",
94
- weight_dtype: data.dtype,
95
- kv_cache_dtype: data.kv_cache_dtype || "float16",
96
-
97
- accelerator_vendor: "NVIDIA",
98
- accelerator_model: data.gpu_model || "unspecified",
99
- gpu_count: data.tensor_parallel_size || data.gpu_count || 1,
100
- memory_per_gpu_gb: data.gpu_memory || 0,
101
- driver_version: data.driver_version,
102
- cuda_rocm_metal_version: data.cuda_version,
103
-
104
- serving_engine: "SGLang",
105
- engine_version: data.sglang_version || "unspecified",
106
- engine_command: data.command,
107
- engine_config: {
108
- tensor_parallel_size: data.tensor_parallel_size,
109
- max_model_len: data.max_model_len,
110
- max_num_seqs: data.max_num_seqs,
111
- prefix_cache_enabled: data.enable_prefix_caching ?? data.radix_cache,
112
- chunked_prefill_enabled: data.enable_chunked_prefill,
113
- attention_backend: data.attention_backend,
114
- },
115
-
116
- workload_type: data.workload_type || "online_poisson",
117
- dataset_name: data.dataset_name || data.dataset,
118
- request_count: numRequests,
119
- concurrency,
120
- input_tokens_mean: inputLen,
121
- output_tokens_mean: outputLen,
122
- streaming_enabled: data.streaming ?? true,
123
-
124
- successful_requests: numRequests,
125
- failed_requests: data.failed ?? 0,
126
- output_token_throughput_tps: outputThroughput,
127
- total_token_throughput_tps: data.total_token_throughput,
128
- request_throughput_rps: data.request_throughput,
129
- ttft_mean_ms: meanTtft,
130
- ttft_p50_ms: data.p50_ttft ?? data.median_ttft,
131
- ttft_p95_ms: data.p95_ttft,
132
- ttft_p99_ms: p99Ttft,
133
- itl_mean_ms: meanItl,
134
- itl_p50_ms: data.p50_itl ?? data.median_itl,
135
- itl_p95_ms: data.p95_itl,
136
- itl_p99_ms: p99Itl,
137
-
138
- gpu_memory_peak_gb: data.peak_gpu_memory,
139
-
140
- metric_definition_version: "sglang-v1",
141
- citation_text: `SGLang benchmark: ${outputThroughput.toFixed(2)} tok/s, TTFT mean ${meanTtft?.toFixed(1) || "?"} ms, ${numRequests} requests`,
142
- attribution_required: true,
143
- commercial_redistribution_allowed: "yes",
144
- };
145
- } catch {
146
- // Not JSON — try log format (future: parse SGLang text logs)
147
- return null;
148
- }
149
- },
150
- };