edgeflowjs 0.1.0 → 0.3.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.
Files changed (152) hide show
  1. package/README.md +200 -66
  2. package/dist/backends/index.d.ts +9 -2
  3. package/dist/backends/index.d.ts.map +1 -1
  4. package/dist/backends/index.js +13 -13
  5. package/dist/backends/index.js.map +1 -1
  6. package/dist/backends/onnx.d.ts +49 -4
  7. package/dist/backends/onnx.d.ts.map +1 -1
  8. package/dist/backends/onnx.js +165 -76
  9. package/dist/backends/onnx.js.map +1 -1
  10. package/dist/backends/transformers-adapter.d.ts +99 -0
  11. package/dist/backends/transformers-adapter.d.ts.map +1 -0
  12. package/dist/backends/transformers-adapter.js +171 -0
  13. package/dist/backends/transformers-adapter.js.map +1 -0
  14. package/dist/backends/webgpu.d.ts +7 -5
  15. package/dist/backends/webgpu.d.ts.map +1 -1
  16. package/dist/backends/webgpu.js +7 -5
  17. package/dist/backends/webgpu.js.map +1 -1
  18. package/dist/backends/webnn.d.ts +6 -5
  19. package/dist/backends/webnn.d.ts.map +1 -1
  20. package/dist/backends/webnn.js +6 -5
  21. package/dist/backends/webnn.js.map +1 -1
  22. package/dist/core/composer.d.ts +118 -0
  23. package/dist/core/composer.d.ts.map +1 -0
  24. package/dist/core/composer.js +163 -0
  25. package/dist/core/composer.js.map +1 -0
  26. package/dist/core/device-profiler.d.ts +75 -0
  27. package/dist/core/device-profiler.d.ts.map +1 -0
  28. package/dist/core/device-profiler.js +131 -0
  29. package/dist/core/device-profiler.js.map +1 -0
  30. package/dist/core/index.d.ts +4 -0
  31. package/dist/core/index.d.ts.map +1 -1
  32. package/dist/core/index.js +8 -0
  33. package/dist/core/index.js.map +1 -1
  34. package/dist/core/memory.d.ts +22 -2
  35. package/dist/core/memory.d.ts.map +1 -1
  36. package/dist/core/memory.js +49 -13
  37. package/dist/core/memory.js.map +1 -1
  38. package/dist/core/plugin.d.ts +100 -0
  39. package/dist/core/plugin.d.ts.map +1 -0
  40. package/dist/core/plugin.js +106 -0
  41. package/dist/core/plugin.js.map +1 -0
  42. package/dist/core/runtime.d.ts +4 -0
  43. package/dist/core/runtime.d.ts.map +1 -1
  44. package/dist/core/runtime.js +18 -0
  45. package/dist/core/runtime.js.map +1 -1
  46. package/dist/core/scheduler.d.ts +17 -0
  47. package/dist/core/scheduler.d.ts.map +1 -1
  48. package/dist/core/scheduler.js +101 -3
  49. package/dist/core/scheduler.js.map +1 -1
  50. package/dist/core/types.d.ts +14 -0
  51. package/dist/core/types.d.ts.map +1 -1
  52. package/dist/core/types.js.map +1 -1
  53. package/dist/core/worker.d.ts +202 -0
  54. package/dist/core/worker.d.ts.map +1 -0
  55. package/dist/core/worker.js +477 -0
  56. package/dist/core/worker.js.map +1 -0
  57. package/dist/edgeflow.browser.js +9789 -4379
  58. package/dist/edgeflow.browser.js.map +4 -4
  59. package/dist/edgeflow.browser.min.js +435 -5
  60. package/dist/edgeflow.browser.min.js.map +4 -4
  61. package/dist/index.d.ts +9 -6
  62. package/dist/index.d.ts.map +1 -1
  63. package/dist/index.js +32 -12
  64. package/dist/index.js.map +1 -1
  65. package/dist/pipelines/automatic-speech-recognition.d.ts +63 -0
  66. package/dist/pipelines/automatic-speech-recognition.d.ts.map +1 -0
  67. package/dist/pipelines/automatic-speech-recognition.js +269 -0
  68. package/dist/pipelines/automatic-speech-recognition.js.map +1 -0
  69. package/dist/pipelines/base.d.ts +6 -1
  70. package/dist/pipelines/base.d.ts.map +1 -1
  71. package/dist/pipelines/base.js +12 -2
  72. package/dist/pipelines/base.js.map +1 -1
  73. package/dist/pipelines/feature-extraction.d.ts +5 -40
  74. package/dist/pipelines/feature-extraction.d.ts.map +1 -1
  75. package/dist/pipelines/feature-extraction.js +44 -63
  76. package/dist/pipelines/feature-extraction.js.map +1 -1
  77. package/dist/pipelines/image-classification.d.ts +4 -36
  78. package/dist/pipelines/image-classification.d.ts.map +1 -1
  79. package/dist/pipelines/image-classification.js +22 -60
  80. package/dist/pipelines/image-classification.js.map +1 -1
  81. package/dist/pipelines/image-segmentation.d.ts +221 -0
  82. package/dist/pipelines/image-segmentation.d.ts.map +1 -0
  83. package/dist/pipelines/image-segmentation.js +535 -0
  84. package/dist/pipelines/image-segmentation.js.map +1 -0
  85. package/dist/pipelines/index.d.ts +18 -0
  86. package/dist/pipelines/index.d.ts.map +1 -1
  87. package/dist/pipelines/index.js +51 -2
  88. package/dist/pipelines/index.js.map +1 -1
  89. package/dist/pipelines/object-detection.d.ts +44 -0
  90. package/dist/pipelines/object-detection.d.ts.map +1 -0
  91. package/dist/pipelines/object-detection.js +218 -0
  92. package/dist/pipelines/object-detection.js.map +1 -0
  93. package/dist/pipelines/question-answering.d.ts +41 -0
  94. package/dist/pipelines/question-answering.d.ts.map +1 -0
  95. package/dist/pipelines/question-answering.js +164 -0
  96. package/dist/pipelines/question-answering.js.map +1 -0
  97. package/dist/pipelines/text-classification.d.ts +3 -39
  98. package/dist/pipelines/text-classification.d.ts.map +1 -1
  99. package/dist/pipelines/text-classification.js +29 -67
  100. package/dist/pipelines/text-classification.js.map +1 -1
  101. package/dist/pipelines/text-generation.d.ts +281 -0
  102. package/dist/pipelines/text-generation.d.ts.map +1 -0
  103. package/dist/pipelines/text-generation.js +766 -0
  104. package/dist/pipelines/text-generation.js.map +1 -0
  105. package/dist/pipelines/zero-shot-classification.d.ts +45 -0
  106. package/dist/pipelines/zero-shot-classification.d.ts.map +1 -0
  107. package/dist/pipelines/zero-shot-classification.js +140 -0
  108. package/dist/pipelines/zero-shot-classification.js.map +1 -0
  109. package/dist/tools/benchmark.d.ts +92 -0
  110. package/dist/tools/benchmark.d.ts.map +1 -0
  111. package/dist/tools/benchmark.js +213 -0
  112. package/dist/tools/benchmark.js.map +1 -0
  113. package/dist/tools/debugger.d.ts +258 -0
  114. package/dist/tools/debugger.d.ts.map +1 -0
  115. package/dist/tools/debugger.js +624 -0
  116. package/dist/tools/debugger.js.map +1 -0
  117. package/dist/tools/index.d.ts +8 -0
  118. package/dist/tools/index.d.ts.map +1 -1
  119. package/dist/tools/index.js +16 -0
  120. package/dist/tools/index.js.map +1 -1
  121. package/dist/tools/monitor.d.ts +284 -0
  122. package/dist/tools/monitor.d.ts.map +1 -0
  123. package/dist/tools/monitor.js +921 -0
  124. package/dist/tools/monitor.js.map +1 -0
  125. package/dist/tools/quantization.d.ts +235 -0
  126. package/dist/tools/quantization.d.ts.map +1 -0
  127. package/dist/tools/quantization.js +830 -0
  128. package/dist/tools/quantization.js.map +1 -0
  129. package/dist/utils/hub.d.ts +162 -0
  130. package/dist/utils/hub.d.ts.map +1 -0
  131. package/dist/utils/hub.js +311 -0
  132. package/dist/utils/hub.js.map +1 -0
  133. package/dist/utils/index.d.ts +3 -1
  134. package/dist/utils/index.d.ts.map +1 -1
  135. package/dist/utils/index.js +5 -1
  136. package/dist/utils/index.js.map +1 -1
  137. package/dist/utils/model-loader.d.ts.map +1 -1
  138. package/dist/utils/model-loader.js +106 -30
  139. package/dist/utils/model-loader.js.map +1 -1
  140. package/dist/utils/offline.d.ts +147 -0
  141. package/dist/utils/offline.d.ts.map +1 -0
  142. package/dist/utils/offline.js +405 -0
  143. package/dist/utils/offline.js.map +1 -0
  144. package/dist/utils/preprocessor.d.ts +82 -6
  145. package/dist/utils/preprocessor.d.ts.map +1 -1
  146. package/dist/utils/preprocessor.js +278 -21
  147. package/dist/utils/preprocessor.js.map +1 -1
  148. package/dist/utils/tokenizer.d.ts +197 -72
  149. package/dist/utils/tokenizer.d.ts.map +1 -1
  150. package/dist/utils/tokenizer.js +558 -274
  151. package/dist/utils/tokenizer.js.map +1 -1
  152. package/package.json +26 -11
@@ -0,0 +1,921 @@
1
+ /**
2
+ * edgeFlow.js - Performance Monitoring Dashboard
3
+ *
4
+ * Real-time performance monitoring and metrics visualization.
5
+ */
6
+ // ============================================================================
7
+ // Performance Monitor
8
+ // ============================================================================
9
+ /**
10
+ * Performance monitor for edgeFlow.js
11
+ */
12
+ export class PerformanceMonitor {
13
+ config;
14
+ samples = [];
15
+ isRunning = false;
16
+ intervalId = null;
17
+ alerts = [];
18
+ alertListeners = [];
19
+ sampleListeners = [];
20
+ // Inference tracking
21
+ inferenceCount = 0;
22
+ inferenceTimes = [];
23
+ queueLength = 0;
24
+ activeCount = 0;
25
+ // FPS tracking
26
+ frameCount = 0;
27
+ lastFrameTime = 0;
28
+ fps = 0;
29
+ rafId = null;
30
+ // Memory tracking
31
+ tensorMemory = 0;
32
+ cacheMemory = 0;
33
+ constructor(config = {}) {
34
+ this.config = {
35
+ enabled: config.enabled ?? true,
36
+ sampleInterval: config.sampleInterval ?? 1000,
37
+ historySize: config.historySize ?? 60,
38
+ monitorMemory: config.monitorMemory ?? true,
39
+ monitorFPS: config.monitorFPS ?? true,
40
+ collectors: config.collectors ?? [],
41
+ };
42
+ }
43
+ /**
44
+ * Start monitoring
45
+ */
46
+ start() {
47
+ if (this.isRunning)
48
+ return;
49
+ this.isRunning = true;
50
+ // Start sampling
51
+ this.intervalId = setInterval(() => {
52
+ this.collectSample();
53
+ }, this.config.sampleInterval);
54
+ // Start FPS monitoring
55
+ if (this.config.monitorFPS && typeof requestAnimationFrame !== 'undefined') {
56
+ this.lastFrameTime = performance.now();
57
+ this.frameCount = 0;
58
+ this.monitorFPS();
59
+ }
60
+ }
61
+ /**
62
+ * Stop monitoring
63
+ */
64
+ stop() {
65
+ this.isRunning = false;
66
+ if (this.intervalId) {
67
+ clearInterval(this.intervalId);
68
+ this.intervalId = null;
69
+ }
70
+ if (this.rafId) {
71
+ cancelAnimationFrame(this.rafId);
72
+ this.rafId = null;
73
+ }
74
+ }
75
+ /**
76
+ * Monitor FPS
77
+ */
78
+ monitorFPS() {
79
+ if (!this.isRunning)
80
+ return;
81
+ this.frameCount++;
82
+ const now = performance.now();
83
+ const elapsed = now - this.lastFrameTime;
84
+ if (elapsed >= 1000) {
85
+ this.fps = Math.round((this.frameCount * 1000) / elapsed);
86
+ this.frameCount = 0;
87
+ this.lastFrameTime = now;
88
+ }
89
+ this.rafId = requestAnimationFrame(() => this.monitorFPS());
90
+ }
91
+ /**
92
+ * Collect a performance sample
93
+ */
94
+ collectSample() {
95
+ const now = Date.now();
96
+ // Calculate inference metrics
97
+ const avgTime = this.inferenceTimes.length > 0
98
+ ? this.inferenceTimes.reduce((a, b) => a + b, 0) / this.inferenceTimes.length
99
+ : 0;
100
+ const minTime = this.inferenceTimes.length > 0
101
+ ? Math.min(...this.inferenceTimes)
102
+ : 0;
103
+ const maxTime = this.inferenceTimes.length > 0
104
+ ? Math.max(...this.inferenceTimes)
105
+ : 0;
106
+ const throughput = this.inferenceCount / (this.config.sampleInterval / 1000);
107
+ const inference = {
108
+ count: this.inferenceCount,
109
+ avgTime,
110
+ minTime,
111
+ maxTime,
112
+ throughput,
113
+ queueLength: this.queueLength,
114
+ activeCount: this.activeCount,
115
+ };
116
+ // Collect memory metrics
117
+ const memory = this.collectMemoryMetrics();
118
+ // Collect system metrics
119
+ const system = this.collectSystemMetrics();
120
+ // Collect custom metrics
121
+ const custom = {};
122
+ for (const collector of this.config.collectors) {
123
+ try {
124
+ Object.assign(custom, collector());
125
+ }
126
+ catch {
127
+ // Ignore collector errors
128
+ }
129
+ }
130
+ const sample = {
131
+ timestamp: now,
132
+ inference,
133
+ memory,
134
+ system,
135
+ custom,
136
+ };
137
+ // Add to history
138
+ this.samples.push(sample);
139
+ if (this.samples.length > this.config.historySize) {
140
+ this.samples.shift();
141
+ }
142
+ // Check alerts
143
+ this.checkAlerts(sample);
144
+ // Notify listeners
145
+ for (const listener of this.sampleListeners) {
146
+ listener(sample);
147
+ }
148
+ // Reset counters
149
+ this.inferenceCount = 0;
150
+ this.inferenceTimes = [];
151
+ }
152
+ /**
153
+ * Collect memory metrics
154
+ */
155
+ collectMemoryMetrics() {
156
+ let usedHeap = 0;
157
+ let totalHeap = 0;
158
+ let heapLimit = 0;
159
+ if (typeof performance !== 'undefined' && 'memory' in performance) {
160
+ const memory = performance.memory;
161
+ usedHeap = memory.usedJSHeapSize;
162
+ totalHeap = memory.totalJSHeapSize;
163
+ heapLimit = memory.jsHeapSizeLimit;
164
+ }
165
+ return {
166
+ usedHeap,
167
+ totalHeap,
168
+ heapLimit,
169
+ heapUsage: heapLimit > 0 ? usedHeap / heapLimit : 0,
170
+ tensorMemory: this.tensorMemory,
171
+ cacheMemory: this.cacheMemory,
172
+ };
173
+ }
174
+ /**
175
+ * Collect system metrics
176
+ */
177
+ collectSystemMetrics() {
178
+ const lastSample = this.samples[this.samples.length - 1];
179
+ const deltaTime = lastSample
180
+ ? Date.now() - lastSample.timestamp
181
+ : this.config.sampleInterval;
182
+ // Check WebGPU availability
183
+ let webgpuAvailable = false;
184
+ if (typeof navigator !== 'undefined' && 'gpu' in navigator) {
185
+ webgpuAvailable = true;
186
+ }
187
+ // Check WebNN availability
188
+ let webnnAvailable = false;
189
+ if (typeof navigator !== 'undefined' && 'ml' in navigator) {
190
+ webnnAvailable = true;
191
+ }
192
+ return {
193
+ fps: this.fps,
194
+ cpuUsage: this.estimateCPUUsage(),
195
+ deltaTime,
196
+ userAgent: typeof navigator !== 'undefined' ? navigator.userAgent : 'unknown',
197
+ webgpuAvailable,
198
+ webnnAvailable,
199
+ };
200
+ }
201
+ /**
202
+ * Estimate CPU usage based on inference times
203
+ */
204
+ estimateCPUUsage() {
205
+ if (this.inferenceTimes.length === 0)
206
+ return 0;
207
+ const totalTime = this.inferenceTimes.reduce((a, b) => a + b, 0);
208
+ return Math.min(1, totalTime / this.config.sampleInterval);
209
+ }
210
+ /**
211
+ * Check alerts
212
+ */
213
+ checkAlerts(sample) {
214
+ for (const alert of this.alerts) {
215
+ const value = this.getMetricValue(sample, alert.metric);
216
+ if (value === undefined)
217
+ continue;
218
+ let triggered = false;
219
+ switch (alert.operator) {
220
+ case '>':
221
+ triggered = value > alert.threshold;
222
+ break;
223
+ case '<':
224
+ triggered = value < alert.threshold;
225
+ break;
226
+ case '>=':
227
+ triggered = value >= alert.threshold;
228
+ break;
229
+ case '<=':
230
+ triggered = value <= alert.threshold;
231
+ break;
232
+ case '==':
233
+ triggered = value === alert.threshold;
234
+ break;
235
+ case '!=':
236
+ triggered = value !== alert.threshold;
237
+ break;
238
+ }
239
+ if (triggered) {
240
+ const event = {
241
+ config: alert,
242
+ value,
243
+ timestamp: sample.timestamp,
244
+ };
245
+ for (const listener of this.alertListeners) {
246
+ listener(event);
247
+ }
248
+ }
249
+ }
250
+ }
251
+ /**
252
+ * Get metric value from sample
253
+ */
254
+ getMetricValue(sample, metric) {
255
+ const parts = metric.split('.');
256
+ let value = sample;
257
+ for (const part of parts) {
258
+ if (value && typeof value === 'object' && part in value) {
259
+ value = value[part];
260
+ }
261
+ else {
262
+ return undefined;
263
+ }
264
+ }
265
+ return typeof value === 'number' ? value : undefined;
266
+ }
267
+ /**
268
+ * Record an inference
269
+ */
270
+ recordInference(duration) {
271
+ this.inferenceCount++;
272
+ this.inferenceTimes.push(duration);
273
+ }
274
+ /**
275
+ * Update queue length
276
+ */
277
+ updateQueueLength(length) {
278
+ this.queueLength = length;
279
+ }
280
+ /**
281
+ * Update active count
282
+ */
283
+ updateActiveCount(count) {
284
+ this.activeCount = count;
285
+ }
286
+ /**
287
+ * Update tensor memory
288
+ */
289
+ updateTensorMemory(bytes) {
290
+ this.tensorMemory = bytes;
291
+ }
292
+ /**
293
+ * Update cache memory
294
+ */
295
+ updateCacheMemory(bytes) {
296
+ this.cacheMemory = bytes;
297
+ }
298
+ /**
299
+ * Add an alert
300
+ */
301
+ addAlert(config) {
302
+ this.alerts.push(config);
303
+ }
304
+ /**
305
+ * Remove an alert
306
+ */
307
+ removeAlert(metric) {
308
+ this.alerts = this.alerts.filter(a => a.metric !== metric);
309
+ }
310
+ /**
311
+ * Subscribe to alerts
312
+ */
313
+ onAlert(callback) {
314
+ this.alertListeners.push(callback);
315
+ return () => {
316
+ const idx = this.alertListeners.indexOf(callback);
317
+ if (idx !== -1)
318
+ this.alertListeners.splice(idx, 1);
319
+ };
320
+ }
321
+ /**
322
+ * Subscribe to samples
323
+ */
324
+ onSample(callback) {
325
+ this.sampleListeners.push(callback);
326
+ return () => {
327
+ const idx = this.sampleListeners.indexOf(callback);
328
+ if (idx !== -1)
329
+ this.sampleListeners.splice(idx, 1);
330
+ };
331
+ }
332
+ /**
333
+ * Get current sample
334
+ */
335
+ getCurrentSample() {
336
+ return this.samples[this.samples.length - 1];
337
+ }
338
+ /**
339
+ * Get all samples
340
+ */
341
+ getSamples() {
342
+ return [...this.samples];
343
+ }
344
+ /**
345
+ * Get samples in time range
346
+ */
347
+ getSamplesInRange(startTime, endTime) {
348
+ return this.samples.filter(s => s.timestamp >= startTime && s.timestamp <= endTime);
349
+ }
350
+ /**
351
+ * Get summary statistics
352
+ */
353
+ getSummary() {
354
+ if (this.samples.length === 0) {
355
+ return {
356
+ avgInferenceTime: 0,
357
+ avgThroughput: 0,
358
+ avgMemoryUsage: 0,
359
+ avgFPS: 0,
360
+ totalInferences: 0,
361
+ uptime: 0,
362
+ };
363
+ }
364
+ const avgInferenceTime = this.samples.reduce((sum, s) => sum + s.inference.avgTime, 0) / this.samples.length;
365
+ const avgThroughput = this.samples.reduce((sum, s) => sum + s.inference.throughput, 0) / this.samples.length;
366
+ const avgMemoryUsage = this.samples.reduce((sum, s) => sum + s.memory.heapUsage, 0) / this.samples.length;
367
+ const avgFPS = this.samples.reduce((sum, s) => sum + s.system.fps, 0) / this.samples.length;
368
+ const totalInferences = this.samples.reduce((sum, s) => sum + s.inference.count, 0);
369
+ const firstSample = this.samples[0];
370
+ const lastSample = this.samples[this.samples.length - 1];
371
+ const uptime = lastSample.timestamp - firstSample.timestamp;
372
+ return {
373
+ avgInferenceTime,
374
+ avgThroughput,
375
+ avgMemoryUsage,
376
+ avgFPS,
377
+ totalInferences,
378
+ uptime,
379
+ };
380
+ }
381
+ /**
382
+ * Clear all data
383
+ */
384
+ clear() {
385
+ this.samples = [];
386
+ this.inferenceCount = 0;
387
+ this.inferenceTimes = [];
388
+ this.queueLength = 0;
389
+ this.activeCount = 0;
390
+ this.tensorMemory = 0;
391
+ this.cacheMemory = 0;
392
+ }
393
+ /**
394
+ * Export data
395
+ */
396
+ export() {
397
+ return {
398
+ samples: this.getSamples(),
399
+ summary: this.getSummary(),
400
+ config: this.config,
401
+ timestamp: Date.now(),
402
+ };
403
+ }
404
+ }
405
+ // ============================================================================
406
+ // Dashboard Generator
407
+ // ============================================================================
408
+ /**
409
+ * Generate HTML dashboard
410
+ */
411
+ export function generateDashboardHTML(monitor) {
412
+ const summary = monitor.getSummary();
413
+ const samples = monitor.getSamples();
414
+ const lastSample = samples[samples.length - 1];
415
+ const formatBytes = (bytes) => {
416
+ if (bytes < 1024)
417
+ return `${bytes} B`;
418
+ if (bytes < 1024 * 1024)
419
+ return `${(bytes / 1024).toFixed(1)} KB`;
420
+ if (bytes < 1024 * 1024 * 1024)
421
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
422
+ return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)} GB`;
423
+ };
424
+ const formatDuration = (ms) => {
425
+ if (ms < 1000)
426
+ return `${ms.toFixed(0)}ms`;
427
+ if (ms < 60000)
428
+ return `${(ms / 1000).toFixed(1)}s`;
429
+ return `${(ms / 60000).toFixed(1)}m`;
430
+ };
431
+ return `
432
+ <!DOCTYPE html>
433
+ <html lang="en">
434
+ <head>
435
+ <meta charset="UTF-8">
436
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
437
+ <title>edgeFlow.js Performance Dashboard</title>
438
+ <style>
439
+ :root {
440
+ --bg-primary: #0d1117;
441
+ --bg-secondary: #161b22;
442
+ --bg-tertiary: #21262d;
443
+ --text-primary: #f0f6fc;
444
+ --text-secondary: #8b949e;
445
+ --accent: #58a6ff;
446
+ --success: #3fb950;
447
+ --warning: #d29922;
448
+ --error: #f85149;
449
+ }
450
+
451
+ * {
452
+ margin: 0;
453
+ padding: 0;
454
+ box-sizing: border-box;
455
+ }
456
+
457
+ body {
458
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
459
+ background: var(--bg-primary);
460
+ color: var(--text-primary);
461
+ line-height: 1.6;
462
+ }
463
+
464
+ .dashboard {
465
+ max-width: 1400px;
466
+ margin: 0 auto;
467
+ padding: 24px;
468
+ }
469
+
470
+ header {
471
+ display: flex;
472
+ justify-content: space-between;
473
+ align-items: center;
474
+ margin-bottom: 32px;
475
+ padding-bottom: 16px;
476
+ border-bottom: 1px solid var(--bg-tertiary);
477
+ }
478
+
479
+ h1 {
480
+ font-size: 24px;
481
+ font-weight: 600;
482
+ display: flex;
483
+ align-items: center;
484
+ gap: 12px;
485
+ }
486
+
487
+ .status {
488
+ display: flex;
489
+ align-items: center;
490
+ gap: 8px;
491
+ font-size: 14px;
492
+ color: var(--text-secondary);
493
+ }
494
+
495
+ .status-dot {
496
+ width: 8px;
497
+ height: 8px;
498
+ border-radius: 50%;
499
+ background: var(--success);
500
+ }
501
+
502
+ .grid {
503
+ display: grid;
504
+ grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
505
+ gap: 20px;
506
+ margin-bottom: 32px;
507
+ }
508
+
509
+ .card {
510
+ background: var(--bg-secondary);
511
+ border: 1px solid var(--bg-tertiary);
512
+ border-radius: 12px;
513
+ padding: 20px;
514
+ }
515
+
516
+ .card-header {
517
+ display: flex;
518
+ justify-content: space-between;
519
+ align-items: center;
520
+ margin-bottom: 16px;
521
+ }
522
+
523
+ .card-title {
524
+ font-size: 14px;
525
+ font-weight: 500;
526
+ color: var(--text-secondary);
527
+ text-transform: uppercase;
528
+ letter-spacing: 0.5px;
529
+ }
530
+
531
+ .card-value {
532
+ font-size: 36px;
533
+ font-weight: 700;
534
+ font-variant-numeric: tabular-nums;
535
+ }
536
+
537
+ .card-value.small {
538
+ font-size: 24px;
539
+ }
540
+
541
+ .card-unit {
542
+ font-size: 14px;
543
+ color: var(--text-secondary);
544
+ margin-left: 4px;
545
+ }
546
+
547
+ .card-change {
548
+ font-size: 12px;
549
+ padding: 4px 8px;
550
+ border-radius: 4px;
551
+ }
552
+
553
+ .card-change.up {
554
+ background: rgba(63, 185, 80, 0.2);
555
+ color: var(--success);
556
+ }
557
+
558
+ .card-change.down {
559
+ background: rgba(248, 81, 73, 0.2);
560
+ color: var(--error);
561
+ }
562
+
563
+ .progress-bar {
564
+ height: 8px;
565
+ background: var(--bg-tertiary);
566
+ border-radius: 4px;
567
+ overflow: hidden;
568
+ margin-top: 12px;
569
+ }
570
+
571
+ .progress-fill {
572
+ height: 100%;
573
+ border-radius: 4px;
574
+ transition: width 0.3s ease;
575
+ }
576
+
577
+ .progress-fill.blue { background: var(--accent); }
578
+ .progress-fill.green { background: var(--success); }
579
+ .progress-fill.yellow { background: var(--warning); }
580
+ .progress-fill.red { background: var(--error); }
581
+
582
+ .chart-container {
583
+ background: var(--bg-secondary);
584
+ border: 1px solid var(--bg-tertiary);
585
+ border-radius: 12px;
586
+ padding: 20px;
587
+ margin-bottom: 20px;
588
+ }
589
+
590
+ .chart-header {
591
+ display: flex;
592
+ justify-content: space-between;
593
+ align-items: center;
594
+ margin-bottom: 16px;
595
+ }
596
+
597
+ .chart-title {
598
+ font-size: 16px;
599
+ font-weight: 600;
600
+ }
601
+
602
+ .chart {
603
+ height: 200px;
604
+ position: relative;
605
+ }
606
+
607
+ .chart-line {
608
+ stroke: var(--accent);
609
+ stroke-width: 2;
610
+ fill: none;
611
+ }
612
+
613
+ .chart-area {
614
+ fill: url(#chartGradient);
615
+ opacity: 0.3;
616
+ }
617
+
618
+ .chart-grid {
619
+ stroke: var(--bg-tertiary);
620
+ stroke-width: 1;
621
+ }
622
+
623
+ .table {
624
+ width: 100%;
625
+ border-collapse: collapse;
626
+ }
627
+
628
+ .table th,
629
+ .table td {
630
+ padding: 12px 16px;
631
+ text-align: left;
632
+ border-bottom: 1px solid var(--bg-tertiary);
633
+ }
634
+
635
+ .table th {
636
+ font-size: 12px;
637
+ font-weight: 500;
638
+ color: var(--text-secondary);
639
+ text-transform: uppercase;
640
+ letter-spacing: 0.5px;
641
+ }
642
+
643
+ .table td {
644
+ font-variant-numeric: tabular-nums;
645
+ }
646
+
647
+ footer {
648
+ text-align: center;
649
+ padding: 24px;
650
+ color: var(--text-secondary);
651
+ font-size: 14px;
652
+ }
653
+ </style>
654
+ </head>
655
+ <body>
656
+ <div class="dashboard">
657
+ <header>
658
+ <h1>
659
+ <svg width="32" height="32" viewBox="0 0 32 32" fill="none">
660
+ <rect width="32" height="32" rx="8" fill="var(--accent)"/>
661
+ <path d="M8 16L14 10L20 16L26 10" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
662
+ <path d="M8 22L14 16L20 22L26 16" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" opacity="0.5"/>
663
+ </svg>
664
+ edgeFlow.js Performance Dashboard
665
+ </h1>
666
+ <div class="status">
667
+ <div class="status-dot"></div>
668
+ Running for ${formatDuration(summary.uptime)}
669
+ </div>
670
+ </header>
671
+
672
+ <div class="grid">
673
+ <div class="card">
674
+ <div class="card-header">
675
+ <span class="card-title">Total Inferences</span>
676
+ </div>
677
+ <div class="card-value">${summary.totalInferences.toLocaleString()}</div>
678
+ </div>
679
+
680
+ <div class="card">
681
+ <div class="card-header">
682
+ <span class="card-title">Avg Inference Time</span>
683
+ </div>
684
+ <div class="card-value">${summary.avgInferenceTime.toFixed(1)}<span class="card-unit">ms</span></div>
685
+ </div>
686
+
687
+ <div class="card">
688
+ <div class="card-header">
689
+ <span class="card-title">Throughput</span>
690
+ </div>
691
+ <div class="card-value">${summary.avgThroughput.toFixed(1)}<span class="card-unit">ops/s</span></div>
692
+ </div>
693
+
694
+ <div class="card">
695
+ <div class="card-header">
696
+ <span class="card-title">Avg FPS</span>
697
+ </div>
698
+ <div class="card-value">${Math.round(summary.avgFPS)}</div>
699
+ </div>
700
+ </div>
701
+
702
+ <div class="grid">
703
+ <div class="card">
704
+ <div class="card-header">
705
+ <span class="card-title">Memory Usage</span>
706
+ </div>
707
+ <div class="card-value small">${formatBytes(lastSample?.memory.usedHeap ?? 0)}</div>
708
+ <div class="progress-bar">
709
+ <div class="progress-fill ${summary.avgMemoryUsage > 0.8 ? 'red' : summary.avgMemoryUsage > 0.6 ? 'yellow' : 'green'}"
710
+ style="width: ${(summary.avgMemoryUsage * 100).toFixed(0)}%"></div>
711
+ </div>
712
+ </div>
713
+
714
+ <div class="card">
715
+ <div class="card-header">
716
+ <span class="card-title">Tensor Memory</span>
717
+ </div>
718
+ <div class="card-value small">${formatBytes(lastSample?.memory.tensorMemory ?? 0)}</div>
719
+ </div>
720
+
721
+ <div class="card">
722
+ <div class="card-header">
723
+ <span class="card-title">Cache Memory</span>
724
+ </div>
725
+ <div class="card-value small">${formatBytes(lastSample?.memory.cacheMemory ?? 0)}</div>
726
+ </div>
727
+
728
+ <div class="card">
729
+ <div class="card-header">
730
+ <span class="card-title">Queue Length</span>
731
+ </div>
732
+ <div class="card-value small">${lastSample?.inference.queueLength ?? 0}</div>
733
+ </div>
734
+ </div>
735
+
736
+ <div class="chart-container">
737
+ <div class="chart-header">
738
+ <span class="chart-title">Inference Time History</span>
739
+ </div>
740
+ <div class="chart">
741
+ <svg width="100%" height="100%" viewBox="0 0 600 200" preserveAspectRatio="none">
742
+ <defs>
743
+ <linearGradient id="chartGradient" x1="0" y1="0" x2="0" y2="1">
744
+ <stop offset="0%" stop-color="var(--accent)" stop-opacity="0.5"/>
745
+ <stop offset="100%" stop-color="var(--accent)" stop-opacity="0"/>
746
+ </linearGradient>
747
+ </defs>
748
+ ${generateChartPath(samples)}
749
+ </svg>
750
+ </div>
751
+ </div>
752
+
753
+ <div class="chart-container">
754
+ <div class="chart-header">
755
+ <span class="chart-title">Recent Samples</span>
756
+ </div>
757
+ <table class="table">
758
+ <thead>
759
+ <tr>
760
+ <th>Time</th>
761
+ <th>Inferences</th>
762
+ <th>Avg Time</th>
763
+ <th>Throughput</th>
764
+ <th>Memory</th>
765
+ <th>FPS</th>
766
+ </tr>
767
+ </thead>
768
+ <tbody>
769
+ ${samples.slice(-10).reverse().map(s => `
770
+ <tr>
771
+ <td>${new Date(s.timestamp).toLocaleTimeString()}</td>
772
+ <td>${s.inference.count}</td>
773
+ <td>${s.inference.avgTime.toFixed(2)}ms</td>
774
+ <td>${s.inference.throughput.toFixed(1)}/s</td>
775
+ <td>${formatBytes(s.memory.usedHeap)}</td>
776
+ <td>${s.system.fps}</td>
777
+ </tr>
778
+ `).join('')}
779
+ </tbody>
780
+ </table>
781
+ </div>
782
+
783
+ <footer>
784
+ Generated at ${new Date().toLocaleString()} | edgeFlow.js Performance Monitor
785
+ </footer>
786
+ </div>
787
+ </body>
788
+ </html>
789
+ `.trim();
790
+ }
791
+ /**
792
+ * Generate SVG chart path
793
+ */
794
+ function generateChartPath(samples) {
795
+ if (samples.length < 2)
796
+ return '';
797
+ const width = 600;
798
+ const height = 180;
799
+ const padding = 10;
800
+ const times = samples.map(s => s.inference.avgTime);
801
+ const maxTime = Math.max(...times, 1);
802
+ const points = samples.map((s, i) => {
803
+ const x = padding + (i / (samples.length - 1)) * (width - 2 * padding);
804
+ const y = height - padding - (s.inference.avgTime / maxTime) * (height - 2 * padding);
805
+ return `${x},${y}`;
806
+ });
807
+ const linePath = `M ${points.join(' L ')}`;
808
+ const areaPath = `M ${padding},${height - padding} L ${points.join(' L ')} L ${width - padding},${height - padding} Z`;
809
+ // Grid lines
810
+ const gridLines = [];
811
+ for (let i = 0; i <= 4; i++) {
812
+ const y = padding + (i / 4) * (height - 2 * padding);
813
+ gridLines.push(`<line class="chart-grid" x1="${padding}" y1="${y}" x2="${width - padding}" y2="${y}"/>`);
814
+ }
815
+ return `
816
+ ${gridLines.join('\n')}
817
+ <path class="chart-area" d="${areaPath}"/>
818
+ <path class="chart-line" d="${linePath}"/>
819
+ `;
820
+ }
821
+ /**
822
+ * Generate ASCII dashboard
823
+ */
824
+ export function generateAsciiDashboard(monitor) {
825
+ const summary = monitor.getSummary();
826
+ const samples = monitor.getSamples();
827
+ const lastSample = samples[samples.length - 1];
828
+ const formatBytes = (bytes) => {
829
+ if (bytes < 1024)
830
+ return `${bytes} B`;
831
+ if (bytes < 1024 * 1024)
832
+ return `${(bytes / 1024).toFixed(1)} KB`;
833
+ if (bytes < 1024 * 1024 * 1024)
834
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
835
+ return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)} GB`;
836
+ };
837
+ const bar = (value, max, width = 20) => {
838
+ const filled = Math.round((value / max) * width);
839
+ return '█'.repeat(filled) + '░'.repeat(width - filled);
840
+ };
841
+ const lines = [
842
+ '╔══════════════════════════════════════════════════════════════════════════╗',
843
+ '║ edgeFlow.js Performance Monitor Dashboard ║',
844
+ '╠══════════════════════════════════════════════════════════════════════════╣',
845
+ '║ ║',
846
+ `║ Total Inferences: ${summary.totalInferences.toString().padStart(10)} ║`,
847
+ `║ Avg Inference: ${summary.avgInferenceTime.toFixed(2).padStart(10)}ms ║`,
848
+ `║ Throughput: ${summary.avgThroughput.toFixed(2).padStart(10)} ops/s ║`,
849
+ `║ Avg FPS: ${Math.round(summary.avgFPS).toString().padStart(10)} ║`,
850
+ '║ ║',
851
+ '╟──────────────────────────────────────────────────────────────────────────╢',
852
+ '║ Memory Usage ║',
853
+ `║ Heap: ${bar(summary.avgMemoryUsage, 1)} ${(summary.avgMemoryUsage * 100).toFixed(0).padStart(3)}% ║`,
854
+ `║ Used: ${formatBytes(lastSample?.memory.usedHeap ?? 0).padStart(10)} ║`,
855
+ `║ Tensor: ${formatBytes(lastSample?.memory.tensorMemory ?? 0).padStart(10)} ║`,
856
+ `║ Cache: ${formatBytes(lastSample?.memory.cacheMemory ?? 0).padStart(10)} ║`,
857
+ '║ ║',
858
+ '╟──────────────────────────────────────────────────────────────────────────╢',
859
+ '║ Inference Time History (last 30 samples) ║',
860
+ '║ ║',
861
+ ];
862
+ // Add mini chart
863
+ const recentSamples = samples.slice(-30);
864
+ if (recentSamples.length > 0) {
865
+ const times = recentSamples.map(s => s.inference.avgTime);
866
+ const maxTime = Math.max(...times, 1);
867
+ const chartHeight = 5;
868
+ for (let row = chartHeight; row > 0; row--) {
869
+ let line = '║ ';
870
+ for (const time of times) {
871
+ const height = Math.ceil((time / maxTime) * chartHeight);
872
+ line += height >= row ? '▓' : ' ';
873
+ }
874
+ lines.push(line.padEnd(76) + '║');
875
+ }
876
+ lines.push('║ ' + '─'.repeat(30) + ' ║');
877
+ }
878
+ lines.push('║ ║');
879
+ lines.push(`║ Last updated: ${new Date().toLocaleString().padEnd(40)} ║`);
880
+ lines.push('╚══════════════════════════════════════════════════════════════════════════╝');
881
+ return lines.join('\n');
882
+ }
883
+ // ============================================================================
884
+ // Global Instance
885
+ // ============================================================================
886
+ let globalMonitor = null;
887
+ /**
888
+ * Get or create global monitor
889
+ */
890
+ export function getMonitor(config) {
891
+ if (!globalMonitor || config) {
892
+ globalMonitor = new PerformanceMonitor(config);
893
+ }
894
+ return globalMonitor;
895
+ }
896
+ /**
897
+ * Start monitoring
898
+ */
899
+ export function startMonitoring(config) {
900
+ const monitor = getMonitor(config);
901
+ monitor.start();
902
+ return monitor;
903
+ }
904
+ /**
905
+ * Stop monitoring
906
+ */
907
+ export function stopMonitoring() {
908
+ globalMonitor?.stop();
909
+ }
910
+ // ============================================================================
911
+ // Exports
912
+ // ============================================================================
913
+ export default {
914
+ PerformanceMonitor,
915
+ getMonitor,
916
+ startMonitoring,
917
+ stopMonitoring,
918
+ generateDashboardHTML,
919
+ generateAsciiDashboard,
920
+ };
921
+ //# sourceMappingURL=monitor.js.map