llmflow 0.3.1
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 +142 -0
- package/bin/llmflow.js +91 -0
- package/db.js +857 -0
- package/logger.js +122 -0
- package/otlp-export.js +564 -0
- package/otlp-logs.js +238 -0
- package/otlp-metrics.js +300 -0
- package/otlp.js +398 -0
- package/package.json +62 -0
- package/pricing.fallback.json +58 -0
- package/pricing.js +154 -0
- package/providers/anthropic.js +195 -0
- package/providers/azure.js +159 -0
- package/providers/base.js +145 -0
- package/providers/cohere.js +225 -0
- package/providers/gemini.js +278 -0
- package/providers/index.js +130 -0
- package/providers/ollama.js +36 -0
- package/providers/openai-compatible.js +77 -0
- package/providers/openai.js +217 -0
- package/providers/passthrough.js +573 -0
- package/public/app.js +1484 -0
- package/public/index.html +367 -0
- package/public/style.css +1152 -0
- package/server.js +1222 -0
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>LLMFlow</title>
|
|
7
|
+
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>🔍</text></svg>">
|
|
8
|
+
<link rel="stylesheet" href="style.css" />
|
|
9
|
+
<script defer src="app.js"></script>
|
|
10
|
+
</head>
|
|
11
|
+
<body>
|
|
12
|
+
<div class="container">
|
|
13
|
+
<header>
|
|
14
|
+
<div class="header-row">
|
|
15
|
+
<div class="header-left">
|
|
16
|
+
<h1 class="logo">
|
|
17
|
+
<svg class="logo-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
18
|
+
<path d="M12 2L2 7l10 5 10-5-10-5z"/>
|
|
19
|
+
<path d="M2 17l10 5 10-5"/>
|
|
20
|
+
<path d="M2 12l10 5 10-5"/>
|
|
21
|
+
</svg>
|
|
22
|
+
LLMFlow
|
|
23
|
+
<span id="connectionStatus" class="status-dot" title="Connecting..."></span>
|
|
24
|
+
</h1>
|
|
25
|
+
<button class="theme-toggle" onclick="toggleTheme()" title="Toggle dark mode">
|
|
26
|
+
<svg class="icon-moon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
27
|
+
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/>
|
|
28
|
+
</svg>
|
|
29
|
+
<svg class="icon-sun" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
30
|
+
<circle cx="12" cy="12" r="5"/>
|
|
31
|
+
<line x1="12" y1="1" x2="12" y2="3"/>
|
|
32
|
+
<line x1="12" y1="21" x2="12" y2="23"/>
|
|
33
|
+
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/>
|
|
34
|
+
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/>
|
|
35
|
+
<line x1="1" y1="12" x2="3" y2="12"/>
|
|
36
|
+
<line x1="21" y1="12" x2="23" y2="12"/>
|
|
37
|
+
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/>
|
|
38
|
+
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/>
|
|
39
|
+
</svg>
|
|
40
|
+
</button>
|
|
41
|
+
</div>
|
|
42
|
+
<div class="stats-bar">
|
|
43
|
+
<div class="stat">
|
|
44
|
+
<span class="stat-value" id="totalRequests">-</span>
|
|
45
|
+
<span class="stat-label">Traces</span>
|
|
46
|
+
</div>
|
|
47
|
+
<div class="stat">
|
|
48
|
+
<span class="stat-value" id="totalTokens">-</span>
|
|
49
|
+
<span class="stat-label">Tokens</span>
|
|
50
|
+
</div>
|
|
51
|
+
<div class="stat">
|
|
52
|
+
<span class="stat-value" id="totalCost">-</span>
|
|
53
|
+
<span class="stat-label">Cost</span>
|
|
54
|
+
</div>
|
|
55
|
+
<div class="stat">
|
|
56
|
+
<span class="stat-value" id="avgLatency">-</span>
|
|
57
|
+
<span class="stat-label">Avg Latency</span>
|
|
58
|
+
</div>
|
|
59
|
+
</div>
|
|
60
|
+
</div>
|
|
61
|
+
</header>
|
|
62
|
+
|
|
63
|
+
<main>
|
|
64
|
+
<div class="tabs">
|
|
65
|
+
<button class="tab active" onclick="showTab('timeline')">Timeline</button>
|
|
66
|
+
<button class="tab" onclick="showTab('traces')">Traces</button>
|
|
67
|
+
<button class="tab" onclick="showTab('logs')">Logs</button>
|
|
68
|
+
<button class="tab" onclick="showTab('metrics')">Metrics</button>
|
|
69
|
+
<button class="tab" onclick="showTab('models')">Models</button>
|
|
70
|
+
<button class="tab" onclick="showTab('analytics')">Analytics</button>
|
|
71
|
+
</div>
|
|
72
|
+
|
|
73
|
+
<div id="timelineTab" class="tab-content active">
|
|
74
|
+
<div class="filter-bar">
|
|
75
|
+
<input type="text" id="timelineSearchInput" placeholder="Search timeline... (press /)" />
|
|
76
|
+
<select id="toolFilter">
|
|
77
|
+
<option value="">All Tools</option>
|
|
78
|
+
<option value="claude-code">Claude Code</option>
|
|
79
|
+
<option value="codex-cli">Codex CLI</option>
|
|
80
|
+
<option value="gemini-cli">Gemini CLI</option>
|
|
81
|
+
<option value="aider">Aider</option>
|
|
82
|
+
<option value="proxy">Proxy</option>
|
|
83
|
+
</select>
|
|
84
|
+
<select id="timelineTypeFilter">
|
|
85
|
+
<option value="">All Types</option>
|
|
86
|
+
<option value="trace">Traces</option>
|
|
87
|
+
<option value="log">Logs</option>
|
|
88
|
+
<option value="metric">Metrics</option>
|
|
89
|
+
</select>
|
|
90
|
+
<select id="timelineDateFilter">
|
|
91
|
+
<option value="">All Time</option>
|
|
92
|
+
<option value="1h">Last Hour</option>
|
|
93
|
+
<option value="24h">Last 24h</option>
|
|
94
|
+
<option value="7d">Last 7d</option>
|
|
95
|
+
</select>
|
|
96
|
+
<button id="clearTimelineFilters" class="btn-secondary">Clear</button>
|
|
97
|
+
</div>
|
|
98
|
+
|
|
99
|
+
<div class="split-layout">
|
|
100
|
+
<div class="panel-left">
|
|
101
|
+
<div id="timelineList" class="timeline-list">
|
|
102
|
+
<div class="empty-state">Loading timeline...</div>
|
|
103
|
+
</div>
|
|
104
|
+
</div>
|
|
105
|
+
|
|
106
|
+
<div class="panel-right" id="timelineDetailPanel">
|
|
107
|
+
<div class="detail-header">
|
|
108
|
+
<h2 id="timelineDetailTitle">Select an item</h2>
|
|
109
|
+
<span id="timelineDetailMeta" class="detail-meta"></span>
|
|
110
|
+
</div>
|
|
111
|
+
<div class="detail-body">
|
|
112
|
+
<div class="detail-section" id="timelineDetailContent">
|
|
113
|
+
<pre id="timelineDetailData">{}</pre>
|
|
114
|
+
</div>
|
|
115
|
+
<div class="detail-section" id="relatedLogsSection" style="display: none;">
|
|
116
|
+
<h3>Related Logs</h3>
|
|
117
|
+
<div id="relatedLogs"></div>
|
|
118
|
+
</div>
|
|
119
|
+
</div>
|
|
120
|
+
</div>
|
|
121
|
+
</div>
|
|
122
|
+
</div>
|
|
123
|
+
|
|
124
|
+
<div id="tracesTab" class="tab-content">
|
|
125
|
+
<div class="filter-bar">
|
|
126
|
+
<input type="text" id="searchInput" placeholder="Search... (press /)" />
|
|
127
|
+
<select id="modelFilter">
|
|
128
|
+
<option value="">All Models</option>
|
|
129
|
+
</select>
|
|
130
|
+
<select id="statusFilter">
|
|
131
|
+
<option value="">All Status</option>
|
|
132
|
+
<option value="success">Success</option>
|
|
133
|
+
<option value="error">Error</option>
|
|
134
|
+
</select>
|
|
135
|
+
<select id="dateFilter">
|
|
136
|
+
<option value="">All Time</option>
|
|
137
|
+
<option value="1h">Last Hour</option>
|
|
138
|
+
<option value="24h">Last 24h</option>
|
|
139
|
+
<option value="7d">Last 7d</option>
|
|
140
|
+
</select>
|
|
141
|
+
<button id="clearFilters" class="btn-secondary">Clear</button>
|
|
142
|
+
</div>
|
|
143
|
+
|
|
144
|
+
<div class="split-layout">
|
|
145
|
+
<div class="panel-left">
|
|
146
|
+
<table id="tracesTable">
|
|
147
|
+
<thead>
|
|
148
|
+
<tr>
|
|
149
|
+
<th>Time</th>
|
|
150
|
+
<th>Type</th>
|
|
151
|
+
<th>Name</th>
|
|
152
|
+
<th>Model</th>
|
|
153
|
+
<th>Tokens</th>
|
|
154
|
+
<th>Cost</th>
|
|
155
|
+
<th>Latency</th>
|
|
156
|
+
<th>Status</th>
|
|
157
|
+
</tr>
|
|
158
|
+
</thead>
|
|
159
|
+
<tbody id="tracesBody">
|
|
160
|
+
<tr>
|
|
161
|
+
<td colspan="8" class="empty-state">Loading...</td>
|
|
162
|
+
</tr>
|
|
163
|
+
</tbody>
|
|
164
|
+
</table>
|
|
165
|
+
</div>
|
|
166
|
+
|
|
167
|
+
<div class="panel-right" id="detailPanel">
|
|
168
|
+
<div class="detail-header">
|
|
169
|
+
<h2 id="detailTitle">Select a trace</h2>
|
|
170
|
+
<span id="detailMeta" class="detail-meta"></span>
|
|
171
|
+
</div>
|
|
172
|
+
<div class="detail-body">
|
|
173
|
+
<div class="detail-section">
|
|
174
|
+
<h3>Info</h3>
|
|
175
|
+
<pre id="traceInfo">{}</pre>
|
|
176
|
+
</div>
|
|
177
|
+
<div class="detail-section">
|
|
178
|
+
<h3>Spans</h3>
|
|
179
|
+
<div id="spanTree" class="span-tree">
|
|
180
|
+
<span class="empty-state">Click a trace to view spans</span>
|
|
181
|
+
</div>
|
|
182
|
+
</div>
|
|
183
|
+
<div class="detail-section">
|
|
184
|
+
<h3>Input / Output</h3>
|
|
185
|
+
<pre id="traceIO">{}</pre>
|
|
186
|
+
</div>
|
|
187
|
+
</div>
|
|
188
|
+
</div>
|
|
189
|
+
</div>
|
|
190
|
+
</div>
|
|
191
|
+
|
|
192
|
+
<div id="logsTab" class="tab-content">
|
|
193
|
+
<div class="filter-bar">
|
|
194
|
+
<input type="text" id="logSearchInput" placeholder="Search logs... (press /)" />
|
|
195
|
+
<select id="logServiceFilter">
|
|
196
|
+
<option value="">All Services</option>
|
|
197
|
+
</select>
|
|
198
|
+
<select id="logEventFilter">
|
|
199
|
+
<option value="">All Events</option>
|
|
200
|
+
</select>
|
|
201
|
+
<select id="logSeverityFilter">
|
|
202
|
+
<option value="">All Severity</option>
|
|
203
|
+
<option value="17">Error+</option>
|
|
204
|
+
<option value="13">Warn+</option>
|
|
205
|
+
<option value="9">Info+</option>
|
|
206
|
+
<option value="5">Debug+</option>
|
|
207
|
+
</select>
|
|
208
|
+
<button id="clearLogFilters" class="btn-secondary">Clear</button>
|
|
209
|
+
</div>
|
|
210
|
+
|
|
211
|
+
<div class="split-layout">
|
|
212
|
+
<div class="panel-left">
|
|
213
|
+
<table id="logsTable">
|
|
214
|
+
<thead>
|
|
215
|
+
<tr>
|
|
216
|
+
<th>Time</th>
|
|
217
|
+
<th>Severity</th>
|
|
218
|
+
<th>Service</th>
|
|
219
|
+
<th>Event</th>
|
|
220
|
+
<th>Body</th>
|
|
221
|
+
</tr>
|
|
222
|
+
</thead>
|
|
223
|
+
<tbody id="logsBody">
|
|
224
|
+
<tr>
|
|
225
|
+
<td colspan="5" class="empty-state">Loading...</td>
|
|
226
|
+
</tr>
|
|
227
|
+
</tbody>
|
|
228
|
+
</table>
|
|
229
|
+
</div>
|
|
230
|
+
|
|
231
|
+
<div class="panel-right" id="logDetailPanel">
|
|
232
|
+
<div class="detail-header">
|
|
233
|
+
<h2 id="logDetailTitle">Select a log</h2>
|
|
234
|
+
<span id="logDetailMeta" class="detail-meta"></span>
|
|
235
|
+
</div>
|
|
236
|
+
<div class="detail-body">
|
|
237
|
+
<div class="detail-section">
|
|
238
|
+
<h3>Body</h3>
|
|
239
|
+
<pre id="logBody">-</pre>
|
|
240
|
+
</div>
|
|
241
|
+
<div class="detail-section">
|
|
242
|
+
<h3>Attributes</h3>
|
|
243
|
+
<pre id="logAttributes">{}</pre>
|
|
244
|
+
</div>
|
|
245
|
+
<div class="detail-section">
|
|
246
|
+
<h3>Resource</h3>
|
|
247
|
+
<pre id="logResource">{}</pre>
|
|
248
|
+
</div>
|
|
249
|
+
</div>
|
|
250
|
+
</div>
|
|
251
|
+
</div>
|
|
252
|
+
</div>
|
|
253
|
+
|
|
254
|
+
<div id="metricsTab" class="tab-content">
|
|
255
|
+
<div class="filter-bar">
|
|
256
|
+
<select id="metricNameFilter">
|
|
257
|
+
<option value="">All Metrics</option>
|
|
258
|
+
</select>
|
|
259
|
+
<select id="metricServiceFilter">
|
|
260
|
+
<option value="">All Services</option>
|
|
261
|
+
</select>
|
|
262
|
+
<select id="metricTypeFilter">
|
|
263
|
+
<option value="">All Types</option>
|
|
264
|
+
<option value="sum">Sum (Counter)</option>
|
|
265
|
+
<option value="gauge">Gauge</option>
|
|
266
|
+
<option value="histogram">Histogram</option>
|
|
267
|
+
</select>
|
|
268
|
+
<button id="clearMetricFilters" class="btn-secondary">Clear</button>
|
|
269
|
+
</div>
|
|
270
|
+
|
|
271
|
+
<div class="metrics-layout">
|
|
272
|
+
<div class="metrics-summary" id="metricsSummary">
|
|
273
|
+
<p class="empty-state">Loading metrics summary...</p>
|
|
274
|
+
</div>
|
|
275
|
+
|
|
276
|
+
<div class="metrics-table-container">
|
|
277
|
+
<table id="metricsTable">
|
|
278
|
+
<thead>
|
|
279
|
+
<tr>
|
|
280
|
+
<th>Time</th>
|
|
281
|
+
<th>Type</th>
|
|
282
|
+
<th>Name</th>
|
|
283
|
+
<th>Value</th>
|
|
284
|
+
<th>Service</th>
|
|
285
|
+
</tr>
|
|
286
|
+
</thead>
|
|
287
|
+
<tbody id="metricsBody">
|
|
288
|
+
<tr>
|
|
289
|
+
<td colspan="5" class="empty-state">Loading...</td>
|
|
290
|
+
</tr>
|
|
291
|
+
</tbody>
|
|
292
|
+
</table>
|
|
293
|
+
</div>
|
|
294
|
+
</div>
|
|
295
|
+
</div>
|
|
296
|
+
|
|
297
|
+
<div id="modelsTab" class="tab-content">
|
|
298
|
+
<div id="modelStats" class="model-grid">
|
|
299
|
+
<p class="empty-state">Loading...</p>
|
|
300
|
+
</div>
|
|
301
|
+
</div>
|
|
302
|
+
|
|
303
|
+
<div id="analyticsTab" class="tab-content">
|
|
304
|
+
<div class="analytics-controls">
|
|
305
|
+
<select id="analyticsDaysFilter">
|
|
306
|
+
<option value="7">Last 7 days</option>
|
|
307
|
+
<option value="14">Last 14 days</option>
|
|
308
|
+
<option value="30" selected>Last 30 days</option>
|
|
309
|
+
<option value="90">Last 90 days</option>
|
|
310
|
+
</select>
|
|
311
|
+
<button id="refreshAnalytics" class="btn-secondary">Refresh</button>
|
|
312
|
+
</div>
|
|
313
|
+
|
|
314
|
+
<div class="analytics-grid">
|
|
315
|
+
<div class="analytics-card analytics-card-wide">
|
|
316
|
+
<div class="analytics-card-header">
|
|
317
|
+
<h3>Token Usage Trends</h3>
|
|
318
|
+
<span class="analytics-subtitle">Daily token consumption</span>
|
|
319
|
+
</div>
|
|
320
|
+
<div class="analytics-card-body">
|
|
321
|
+
<div id="tokenTrendsChart" class="chart-container">
|
|
322
|
+
<p class="empty-state">Loading chart...</p>
|
|
323
|
+
</div>
|
|
324
|
+
</div>
|
|
325
|
+
</div>
|
|
326
|
+
|
|
327
|
+
<div class="analytics-card">
|
|
328
|
+
<div class="analytics-card-header">
|
|
329
|
+
<h3>Cost by Tool</h3>
|
|
330
|
+
<span class="analytics-subtitle">Total spend per AI tool</span>
|
|
331
|
+
</div>
|
|
332
|
+
<div class="analytics-card-body">
|
|
333
|
+
<div id="costByToolChart" class="chart-container">
|
|
334
|
+
<p class="empty-state">Loading chart...</p>
|
|
335
|
+
</div>
|
|
336
|
+
</div>
|
|
337
|
+
</div>
|
|
338
|
+
|
|
339
|
+
<div class="analytics-card">
|
|
340
|
+
<div class="analytics-card-header">
|
|
341
|
+
<h3>Cost by Model</h3>
|
|
342
|
+
<span class="analytics-subtitle">Total spend per model</span>
|
|
343
|
+
</div>
|
|
344
|
+
<div class="analytics-card-body">
|
|
345
|
+
<div id="costByModelChart" class="chart-container">
|
|
346
|
+
<p class="empty-state">Loading chart...</p>
|
|
347
|
+
</div>
|
|
348
|
+
</div>
|
|
349
|
+
</div>
|
|
350
|
+
|
|
351
|
+
<div class="analytics-card analytics-card-wide">
|
|
352
|
+
<div class="analytics-card-header">
|
|
353
|
+
<h3>Daily Summary</h3>
|
|
354
|
+
<span class="analytics-subtitle">Requests, tokens, and costs per day</span>
|
|
355
|
+
</div>
|
|
356
|
+
<div class="analytics-card-body">
|
|
357
|
+
<div id="dailySummaryTable" class="daily-summary-table">
|
|
358
|
+
<p class="empty-state">Loading data...</p>
|
|
359
|
+
</div>
|
|
360
|
+
</div>
|
|
361
|
+
</div>
|
|
362
|
+
</div>
|
|
363
|
+
</div>
|
|
364
|
+
</main>
|
|
365
|
+
</div>
|
|
366
|
+
</body>
|
|
367
|
+
</html>
|