@goldensheepai/toknxr-cli 0.2.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.
package/src/dashboard.tsx DELETED
@@ -1,391 +0,0 @@
1
- // Simple vanilla JavaScript dashboard for browser compatibility
2
- // This creates a pure HTML/CSS/JS dashboard that works without React
3
-
4
- function createDashboard() {
5
- const COLORS = {
6
- primary: '#6B5BED',
7
- secondary: '#9B5BED',
8
- accent: '#ED5B9B',
9
- success: '#10B981',
10
- warning: '#F59E0B',
11
- error: '#EF4444',
12
- background: '#0F172A',
13
- surface: '#1E293B',
14
- text: '#F8FAFC',
15
- textMuted: '#94A3B8'
16
- };
17
-
18
- let stats = null;
19
- let lastUpdated = new Date();
20
-
21
- // Create stat card HTML
22
- function createStatCard(title: string, value: string | number, icon: string, color: string = COLORS.primary) {
23
- return `
24
- <div style="background: ${COLORS.surface}; border-radius: 12px; padding: 24px; border: 1px solid ${color}20; box-shadow: 0 4px 6px -1px ${color}10;">
25
- <div style="display: flex; align-items: center; justify-content: space-between;">
26
- <div>
27
- <p style="color: ${COLORS.textMuted}; font-size: 14px; margin: 0 0 8px 0;">${title}</p>
28
- <p style="font-size: 32px; font-weight: bold; margin: 0; color: ${COLORS.text};">${value}</p>
29
- </div>
30
- <div style="font-size: 24px; color: ${color}; opacity: 0.8;">${icon}</div>
31
- </div>
32
- </div>
33
- `;
34
- }
35
-
36
- // Create provider card HTML
37
- function createProviderChart(name: string, data: any) {
38
- return `
39
- <div style="background: ${COLORS.surface}; border-radius: 8px; padding: 16px; border: 1px solid ${COLORS.primary}20;">
40
- <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px;">
41
- <h3 style="margin: 0; color: ${COLORS.text}; font-size: 16px;">${name}</h3>
42
- <div style="font-size: 12px; color: ${COLORS.textMuted};">${(data.cost || 0).toFixed(2)}</div>
43
- </div>
44
- <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 8px; font-size: 12px;">
45
- <div style="color: ${COLORS.textMuted};">Interactions: <span style="color: ${COLORS.text};">${data.interactions || 0}</span></div>
46
- ${data.avgQuality ? `<div style="color: ${COLORS.textMuted};">Quality: <span style="color: ${COLORS.accent};">${data.avgQuality}/100</span></div>` : ''}
47
- ${data.avgEffectiveness ? `<div style="color: ${COLORS.textMuted};">Effectiveness: <span style="color: ${COLORS.secondary};">${data.avgEffectiveness}/100</span></div>` : ''}
48
- </div>
49
- </div>
50
- `;
51
- }
52
-
53
- // Create recent activity HTML with prompt previews
54
- function createRecentActivity(interactions: any[]) {
55
- const recentHTML = interactions.slice(-10).map((interaction: any, i: number) => {
56
- const qualityColor = !interaction.qualityScore ? COLORS.textMuted :
57
- interaction.qualityScore >= 90 ? COLORS.success :
58
- interaction.qualityScore >= 70 ? COLORS.warning : COLORS.error;
59
-
60
- const effectivenessColor = !interaction.effectivenessScore ? COLORS.textMuted :
61
- interaction.effectivenessScore >= 90 ? COLORS.success :
62
- interaction.effectivenessScore >= 70 ? COLORS.warning : COLORS.error;
63
-
64
- const promptPreview = interaction.userPrompt ?
65
- (interaction.userPrompt.length > 60 ?
66
- interaction.userPrompt.substring(0, 60) + '...' :
67
- interaction.userPrompt) : 'No prompt captured';
68
-
69
- return `
70
- <div style="padding: 16px 0; border-bottom: ${i < interactions.length - 1 ? `1px solid ${COLORS.primary}10` : 'none'}; cursor: pointer; transition: background-color 0.2s;"
71
- onmouseover="this.style.background='${COLORS.primary}08'"
72
- onmouseout="this.style.background='transparent'"
73
- onclick="showPromptDetails('${interaction.provider}', '${interaction.model}', \`${(interaction.userPrompt || 'N/A').replace(/'/g, "\\'")}\`, \`${(interaction.aiResponse || 'N/A').substring(0, 300).replace(/'/g, "\\'")}\`, ${interaction.qualityScore || 0}, ${interaction.effectivenessScore || 0}, '${interaction.taskType || 'unknown'}', ${interaction.cost || 0})">
74
- <div style="display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 8px;">
75
- <div style="flex: 1;">
76
- <div style="color: ${COLORS.text}; font-size: 14px; font-weight: 500; margin-bottom: 4px;">
77
- ${interaction.provider} • ${interaction.model}
78
- </div>
79
- <div style="color: ${COLORS.textMuted}; font-size: 12px; margin-bottom: 6px;">
80
- ${new Date(interaction.timestamp).toLocaleTimeString()}
81
- ${interaction.taskType ? ` • <span style="color: ${COLORS.accent};">${interaction.taskType}</span>` : ''}
82
- </div>
83
- <div style="color: ${COLORS.textMuted}; font-size: 11px; font-style: italic; line-height: 1.3; margin-bottom: 8px;">
84
- 💬 ${promptPreview}
85
- </div>
86
- </div>
87
- <div style="text-align: right; margin-left: 16px;">
88
- <div style="color: ${COLORS.success}; font-size: 14px; font-weight: 500; margin-bottom: 4px;">
89
- ${interaction.cost.toFixed(4)}
90
- </div>
91
- <div style="display: flex; gap: 8px; font-size: 12px;">
92
- ${interaction.qualityScore ? `<span style="color: ${qualityColor};">Q:${interaction.qualityScore}</span>` : ''}
93
- ${interaction.effectivenessScore ? `<span style="color: ${effectivenessColor};">E:${interaction.effectivenessScore}</span>` : ''}
94
- </div>
95
- </div>
96
- </div>
97
- </div>
98
- `;
99
- }).join('');
100
-
101
- return `
102
- <div style="background: ${COLORS.surface}; border-radius: 12px; padding: 24px; border: 1px solid ${COLORS.primary}20;">
103
- <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px;">
104
- <h2 style="margin: 0; color: ${COLORS.text};">Recent Activity</h2>
105
- <div style="display: flex; gap: 8px;">
106
- <input type="text" id="prompt-search" placeholder="Search prompts..." style="background: ${COLORS.background}; border: 1px solid ${COLORS.primary}20; color: ${COLORS.text}; padding: 4px 8px; border-radius: 4px; font-size: 12px;" onkeyup="filterPrompts()">
107
- <select id="provider-filter" style="background: ${COLORS.background}; border: 1px solid ${COLORS.primary}20; color: ${COLORS.text}; padding: 4px 8px; border-radius: 4px; font-size: 12px;" onchange="filterPrompts()">
108
- <option value="">All Providers</option>
109
- <option value="Gemini-Pro">Gemini-Pro</option>
110
- <option value="OpenAI-GPT4">OpenAI-GPT4</option>
111
- <option value="Anthropic-Claude">Anthropic-Claude</option>
112
- <option value="Ollama-Llama3">Ollama-Llama3</option>
113
- </select>
114
- </div>
115
- </div>
116
- <div id="activity-list" style="max-height: 400px; overflow-y: auto;">
117
- ${recentHTML}
118
- </div>
119
- </div>
120
- `;
121
- }
122
-
123
- // Fetch and update stats
124
- async function fetchStats() {
125
- try {
126
- const response = await fetch('/api/stats');
127
- if (!response.ok) throw new Error('Failed to fetch stats');
128
- const data = await response.json();
129
-
130
- // Transform the data for display
131
- const totalCost = data.totals.total || 0;
132
- const totalInteractions = data.totals.requestCount || 0;
133
- const avgCostPerTask = totalInteractions ? (totalCost / totalInteractions) : 0;
134
-
135
- // Update stats cards
136
- document.getElementById('total-cost')!.innerHTML = `${totalCost.toFixed(4)}`;
137
- document.getElementById('total-interactions')!.innerHTML = totalInteractions.toString();
138
- document.getElementById('avg-cost')!.innerHTML = `${avgCostPerTask.toFixed(4)}`;
139
- document.getElementById('waste-rate')!.innerHTML = '0.0%';
140
-
141
- // Update provider cards
142
- const providerContainer = document.getElementById('provider-container');
143
- if (providerContainer && data.totals.byProvider) {
144
- const providerHTML = Object.entries(data.totals.byProvider).map(([name, providerData]) =>
145
- createProviderChart(name, {
146
- cost: (providerData as any).costUSD || 0,
147
- interactions: (providerData as any).requestCount || 0,
148
- avgQuality: (providerData as any).avgQualityScore,
149
- avgEffectiveness: (providerData as any).avgEffectivenessScore
150
- })
151
- ).join('');
152
- providerContainer.innerHTML = providerHTML;
153
- }
154
-
155
- // Update recent activity
156
- const activityContainer = document.getElementById('recent-activity');
157
- if (activityContainer) {
158
- activityContainer.innerHTML = createRecentActivity(data.recentInteractions || []);
159
- }
160
-
161
- // Update timestamp
162
- lastUpdated = new Date();
163
- document.getElementById('last-updated')!.textContent = lastUpdated.toLocaleTimeString();
164
-
165
- } catch (error) {
166
- console.error('Dashboard error:', error);
167
- document.getElementById('error-message')!.textContent = (error as Error).message;
168
- document.getElementById('error-container')!.style.display = 'block';
169
- }
170
- }
171
-
172
- // Create the complete dashboard HTML
173
- const dashboardHTML = `
174
- <div style="background: ${COLORS.background}; min-height: 100vh; color: ${COLORS.text}; font-family: system-ui, -apple-system, sans-serif;">
175
- <!-- Header -->
176
- <header style="background: ${COLORS.surface}; border-bottom: 1px solid ${COLORS.primary}20; padding: 16px 24px;">
177
- <div style="display: flex; justify-content: space-between; align-items: center; max-width: 1200px; margin: 0 auto;">
178
- <div>
179
- <h1 style="margin: 0; font-size: 24px; color: ${COLORS.text};">🚀 TokNXR Dashboard</h1>
180
- <p style="color: ${COLORS.textMuted}; margin: 4px 0 0 0; font-size: 14px;">
181
- Real-time AI Effectiveness & Code Quality Analytics
182
- </p>
183
- </div>
184
- <div style="text-align: right;">
185
- <div id="last-updated" style="color: ${COLORS.textMuted}; font-size: 12px;">
186
- Last updated: ${lastUpdated.toLocaleTimeString()}
187
- </div>
188
- <button
189
- onclick="fetchStats()"
190
- style="background: ${COLORS.primary}; color: white; border: none; padding: 6px 12px; border-radius: 4px; cursor: pointer; font-size: 12px; margin-top: 4px;"
191
- >
192
- Refresh
193
- </button>
194
- </div>
195
- </div>
196
- </header>
197
-
198
- <!-- Error Message -->
199
- <div id="error-container" style="display: none; background: ${COLORS.error}; color: white; padding: 12px 16px; margin: 16px; border-radius: 8px;">
200
- Error: <span id="error-message"></span>
201
- </div>
202
-
203
- <!-- Main Content -->
204
- <main style="padding: 24px; max-width: 1200px; margin: 0 auto;">
205
- <!-- Stats Overview -->
206
- <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 24px; margin-bottom: 32px;">
207
- <div style="background: ${COLORS.surface}; border-radius: 12px; padding: 24px; border: 1px solid ${COLORS.success}20;">
208
- <div style="display: flex; align-items: center; justify-content: space-between;">
209
- <div>
210
- <p style="color: ${COLORS.textMuted}; font-size: 14px; margin: 0 0 8px 0;">Total Cost</p>
211
- <p id="total-cost" style="font-size: 32px; font-weight: bold; margin: 0; color: ${COLORS.text};">$0.0000</p>
212
- </div>
213
- <div style="font-size: 24px; color: ${COLORS.success}; opacity: 0.8;">💰</div>
214
- </div>
215
- </div>
216
-
217
- <div style="background: ${COLORS.surface}; border-radius: 12px; padding: 24px; border: 1px solid ${COLORS.primary}20;">
218
- <div style="display: flex; align-items: center; justify-content: space-between;">
219
- <div>
220
- <p style="color: ${COLORS.textMuted}; font-size: 14px; margin: 0 0 8px 0;">Total Interactions</p>
221
- <p id="total-interactions" style="font-size: 32px; font-weight: bold; margin: 0; color: ${COLORS.text};">0</p>
222
- </div>
223
- <div style="font-size: 24px; color: ${COLORS.primary}; opacity: 0.8;">📊</div>
224
- </div>
225
- </div>
226
-
227
- <div style="background: ${COLORS.surface}; border-radius: 12px; padding: 24px; border: 1px solid ${COLORS.secondary}20;">
228
- <div style="display: flex; align-items: center; justify-content: space-between;">
229
- <div>
230
- <p style="color: ${COLORS.textMuted}; font-size: 14px; margin: 0 0 8px 0;">Avg Cost per Task</p>
231
- <p id="avg-cost" style="font-size: 32px; font-weight: bold; margin: 0; color: ${COLORS.text};">$0.0000</p>
232
- </div>
233
- <div style="font-size: 24px; color: ${COLORS.secondary}; opacity: 0.8;">🎯</div>
234
- </div>
235
- </div>
236
-
237
- <div style="background: ${COLORS.surface}; border-radius: 12px; padding: 24px; border: 1px solid ${COLORS.warning}20;">
238
- <div style="display: flex; align-items: center; justify-content: space-between;">
239
- <div>
240
- <p style="color: ${COLORS.textMuted}; font-size: 14px; margin: 0 0 8px 0;">Waste Rate</p>
241
- <p id="waste-rate" style="font-size: 32px; font-weight: bold; margin: 0; color: ${COLORS.text};">0.0%</p>
242
- </div>
243
- <div style="font-size: 24px; color: ${COLORS.warning}; opacity: 0.8;">⚠️</div>
244
- </div>
245
- </div>
246
- </div>
247
-
248
- <!-- Provider Breakdown -->
249
- <div id="provider-section" style="margin-bottom: 32px;">
250
- <h2 style="color: ${COLORS.text}; margin: 0 0 16px 0;">Provider Breakdown</h2>
251
- <div id="provider-container" style="display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 16px;">
252
- <!-- Provider cards will be inserted here -->
253
- </div>
254
- </div>
255
-
256
- <!-- Recent Activity -->
257
- <div id="recent-activity">
258
- <!-- Recent activity will be inserted here -->
259
- </div>
260
- </main>
261
-
262
- <!-- Footer -->
263
- <footer style="background: ${COLORS.surface}; border-top: 1px solid ${COLORS.primary}20; padding: 16px 24px; text-align: center; color: ${COLORS.textMuted}; font-size: 12px;">
264
- <div style="max-width: 1200px; margin: 0 auto;">
265
- TokNXR Dashboard • Real-time AI Analytics • ${new Date().getFullYear()}
266
- <br>
267
- <span style="color: #FFD700; font-size: 11px; margin-top: 4px; display: block;">
268
- 🐑 Powered by Golden Sheep AI
269
- </span>
270
- </div>
271
- </footer>
272
- </div>
273
- `;
274
-
275
- // Set the dashboard content
276
- const container = document.getElementById('dashboard-root');
277
- if (container) {
278
- container.innerHTML = dashboardHTML;
279
-
280
- // Start fetching stats
281
- fetchStats();
282
-
283
- // Auto-refresh every 5 seconds
284
- setInterval(fetchStats, 5000);
285
- }
286
- }
287
-
288
- // Modal for showing prompt details
289
- function showPromptDetails(provider: string, model: string, userPrompt: string, aiResponse: string, qualityScore: number, effectivenessScore: number, taskType: string, cost: number) {
290
- const modal = document.createElement('div');
291
- modal.id = 'prompt-modal';
292
- modal.style.cssText = `
293
- position: fixed;
294
- top: 0;
295
- left: 0;
296
- width: 100%;
297
- height: 100%;
298
- background: rgba(0, 0, 0, 0.8);
299
- display: flex;
300
- align-items: center;
301
- justify-content: center;
302
- z-index: 1000;
303
- padding: 20px;
304
- box-sizing: border-box;
305
- `;
306
-
307
- const modalContent = document.createElement('div');
308
- modalContent.style.cssText = `
309
- background: #1E293B;
310
- border-radius: 12px;
311
- padding: 24px;
312
- max-width: 800px;
313
- max-height: 80vh;
314
- overflow-y: auto;
315
- color: #F8FAFC;
316
- border: 1px solid #6B5BED20;
317
- `;
318
-
319
- modalContent.innerHTML = `
320
- <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px;">
321
- <h3 style="margin: 0; color: #F8FAFC;">Interaction Details</h3>
322
- <button onclick="closePromptModal()" style="background: #6B5BED; color: white; border: none; padding: 8px 12px; border-radius: 6px; cursor: pointer;">✕ Close</button>
323
- </div>
324
-
325
- <div style="margin-bottom: 16px;">
326
- <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 16px; margin-bottom: 20px;">
327
- <div>
328
- <strong>Provider:</strong> ${provider}<br>
329
- <strong>Model:</strong> ${model}<br>
330
- <strong>Task Type:</strong> ${taskType}<br>
331
- <strong>Cost:</strong> $${cost.toFixed(4)}
332
- </div>
333
- <div>
334
- <strong>Quality Score:</strong> ${qualityScore}/100<br>
335
- <strong>Effectiveness:</strong> ${effectivenessScore}/100<br>
336
- <strong>Status:</strong> ${qualityScore >= 90 ? '🟢 Excellent' : qualityScore >= 70 ? '🟡 Good' : '🔴 Needs Improvement'}
337
- </div>
338
- </div>
339
-
340
- <div style="margin-bottom: 16px;">
341
- <h4 style="margin: 0 0 8px 0; color: #F8FAFC;">📝 User Prompt:</h4>
342
- <div style="background: #0F172A; padding: 12px; border-radius: 6px; border: 1px solid #6B5BED20; font-family: monospace; white-space: pre-wrap;">${userPrompt}</div>
343
- </div>
344
-
345
- <div>
346
- <h4 style="margin: 0 0 8px 0; color: #F8FAFC;">🤖 AI Response:</h4>
347
- <div style="background: #0F172A; padding: 12px; border-radius: 6px; border: 1px solid #6B5BED20; font-family: monospace; white-space: pre-wrap; max-height: 200px; overflow-y: auto;">${aiResponse}${aiResponse.length > 300 ? '...' : ''}</div>
348
- </div>
349
- </div>
350
- `;
351
-
352
- modal.appendChild(modalContent);
353
- document.body.appendChild(modal);
354
-
355
- // Close modal on outside click
356
- modal.addEventListener('click', function(e) {
357
- if (e.target === modal) {
358
- closePromptModal();
359
- }
360
- });
361
- }
362
-
363
- function closePromptModal() {
364
- const modal = document.getElementById('prompt-modal');
365
- if (modal) {
366
- modal.remove();
367
- }
368
- }
369
-
370
- // Filter prompts based on search and provider filter
371
- function filterPrompts() {
372
- const searchTermValue = (document.getElementById('prompt-search') as HTMLInputElement)?.value.toLowerCase() || '';
373
- const providerFilterValue = (document.getElementById('provider-filter') as HTMLSelectElement)?.value || '';
374
- const activityItems = document.querySelectorAll('#activity-list > div');
375
-
376
- activityItems.forEach(item => {
377
- const text = item.textContent?.toLowerCase() || '';
378
- const provider = item.textContent?.split(' • ')[0] || '';
379
-
380
- const shouldShow = text.includes(searchTermValue) &&
381
- (providerFilterValue === '' || text.includes(providerFilterValue.toLowerCase()));
382
- (item as HTMLElement).style.display = shouldShow ? 'block' : 'none';
383
- });
384
- }
385
-
386
- // Initialize dashboard when DOM is loaded
387
- if (document.readyState === 'loading') {
388
- document.addEventListener('DOMContentLoaded', createDashboard);
389
- } else {
390
- createDashboard();
391
- }