llms-py 3.0.0b7__py3-none-any.whl → 3.0.0b9__py3-none-any.whl
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.
- llms/__pycache__/main.cpython-314.pyc +0 -0
- llms/extensions/analytics/ui/index.mjs +51 -162
- llms/extensions/app/__init__.py +519 -0
- llms/extensions/app/__pycache__/__init__.cpython-314.pyc +0 -0
- llms/extensions/app/__pycache__/db.cpython-314.pyc +0 -0
- llms/extensions/app/__pycache__/db_manager.cpython-314.pyc +0 -0
- llms/extensions/app/db.py +643 -0
- llms/extensions/app/db_manager.py +195 -0
- llms/extensions/app/requests.json +9073 -0
- llms/extensions/app/threads.json +15290 -0
- llms/{ui/modules/threads → extensions/app/ui}/Recents.mjs +82 -55
- llms/{ui/modules/threads → extensions/app/ui}/index.mjs +78 -9
- llms/extensions/app/ui/threadStore.mjs +407 -0
- llms/extensions/core_tools/__init__.py +272 -32
- llms/extensions/core_tools/__pycache__/__init__.cpython-314.pyc +0 -0
- llms/extensions/core_tools/ui/codemirror/addon/edit/closebrackets.js +201 -0
- llms/extensions/core_tools/ui/codemirror/addon/edit/closetag.js +185 -0
- llms/extensions/core_tools/ui/codemirror/addon/edit/continuelist.js +101 -0
- llms/extensions/core_tools/ui/codemirror/addon/edit/matchbrackets.js +160 -0
- llms/extensions/core_tools/ui/codemirror/addon/edit/matchtags.js +66 -0
- llms/extensions/core_tools/ui/codemirror/addon/edit/trailingspace.js +27 -0
- llms/extensions/core_tools/ui/codemirror/addon/selection/active-line.js +72 -0
- llms/extensions/core_tools/ui/codemirror/addon/selection/mark-selection.js +119 -0
- llms/extensions/core_tools/ui/codemirror/addon/selection/selection-pointer.js +98 -0
- llms/extensions/core_tools/ui/codemirror/doc/docs.css +225 -0
- llms/extensions/core_tools/ui/codemirror/doc/source_sans.woff +0 -0
- llms/extensions/core_tools/ui/codemirror/lib/codemirror.css +344 -0
- llms/extensions/core_tools/ui/codemirror/lib/codemirror.js +9884 -0
- llms/extensions/core_tools/ui/codemirror/mode/clike/clike.js +942 -0
- llms/extensions/core_tools/ui/codemirror/mode/javascript/index.html +118 -0
- llms/extensions/core_tools/ui/codemirror/mode/javascript/javascript.js +962 -0
- llms/extensions/core_tools/ui/codemirror/mode/javascript/typescript.html +62 -0
- llms/extensions/core_tools/ui/codemirror/mode/python/python.js +402 -0
- llms/extensions/core_tools/ui/codemirror/theme/dracula.css +40 -0
- llms/extensions/core_tools/ui/codemirror/theme/mocha.css +135 -0
- llms/extensions/core_tools/ui/index.mjs +650 -0
- llms/extensions/gallery/__pycache__/db.cpython-314.pyc +0 -0
- llms/extensions/gallery/db.py +4 -4
- llms/extensions/gallery/ui/index.mjs +2 -1
- llms/extensions/katex/__init__.py +6 -0
- llms/extensions/katex/__pycache__/__init__.cpython-314.pyc +0 -0
- llms/extensions/katex/ui/README.md +125 -0
- llms/extensions/katex/ui/contrib/auto-render.js +338 -0
- llms/extensions/katex/ui/contrib/auto-render.min.js +1 -0
- llms/extensions/katex/ui/contrib/auto-render.mjs +244 -0
- llms/extensions/katex/ui/contrib/copy-tex.js +127 -0
- llms/extensions/katex/ui/contrib/copy-tex.min.js +1 -0
- llms/extensions/katex/ui/contrib/copy-tex.mjs +105 -0
- llms/extensions/katex/ui/contrib/mathtex-script-type.js +109 -0
- llms/extensions/katex/ui/contrib/mathtex-script-type.min.js +1 -0
- llms/extensions/katex/ui/contrib/mathtex-script-type.mjs +24 -0
- llms/extensions/katex/ui/contrib/mhchem.js +3213 -0
- llms/extensions/katex/ui/contrib/mhchem.min.js +1 -0
- llms/extensions/katex/ui/contrib/mhchem.mjs +3109 -0
- llms/extensions/katex/ui/contrib/render-a11y-string.js +887 -0
- llms/extensions/katex/ui/contrib/render-a11y-string.min.js +1 -0
- llms/extensions/katex/ui/contrib/render-a11y-string.mjs +800 -0
- llms/extensions/katex/ui/fonts/KaTeX_AMS-Regular.ttf +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_AMS-Regular.woff +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_AMS-Regular.woff2 +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Caligraphic-Bold.ttf +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Caligraphic-Bold.woff +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Caligraphic-Regular.ttf +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Caligraphic-Regular.woff +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Fraktur-Bold.ttf +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Fraktur-Bold.woff +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Fraktur-Regular.ttf +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Fraktur-Regular.woff +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Main-Bold.ttf +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Main-Bold.woff +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Main-Bold.woff2 +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Main-BoldItalic.ttf +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Main-BoldItalic.woff +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Main-Italic.ttf +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Main-Italic.woff +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Main-Italic.woff2 +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Main-Regular.ttf +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Main-Regular.woff +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Main-Regular.woff2 +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Math-BoldItalic.ttf +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Math-BoldItalic.woff +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Math-Italic.ttf +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Math-Italic.woff +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Math-Italic.woff2 +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_SansSerif-Bold.ttf +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_SansSerif-Bold.woff +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_SansSerif-Italic.ttf +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_SansSerif-Italic.woff +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_SansSerif-Regular.ttf +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_SansSerif-Regular.woff +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Script-Regular.ttf +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Script-Regular.woff +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Script-Regular.woff2 +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Size1-Regular.ttf +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Size1-Regular.woff +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Size1-Regular.woff2 +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Size2-Regular.ttf +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Size2-Regular.woff +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Size2-Regular.woff2 +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Size3-Regular.ttf +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Size3-Regular.woff +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Size3-Regular.woff2 +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Size4-Regular.ttf +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Size4-Regular.woff +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Size4-Regular.woff2 +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Typewriter-Regular.ttf +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Typewriter-Regular.woff +0 -0
- llms/extensions/katex/ui/fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
- llms/extensions/katex/ui/index.mjs +92 -0
- llms/extensions/katex/ui/katex-swap.css +1230 -0
- llms/extensions/katex/ui/katex-swap.min.css +1 -0
- llms/extensions/katex/ui/katex.css +1230 -0
- llms/extensions/katex/ui/katex.js +19080 -0
- llms/extensions/katex/ui/katex.min.css +1 -0
- llms/extensions/katex/ui/katex.min.js +1 -0
- llms/extensions/katex/ui/katex.min.mjs +1 -0
- llms/extensions/katex/ui/katex.mjs +18547 -0
- llms/extensions/providers/__pycache__/anthropic.cpython-314.pyc +0 -0
- llms/extensions/providers/anthropic.py +44 -1
- llms/extensions/system_prompts/ui/index.mjs +2 -1
- llms/extensions/tools/__init__.py +5 -0
- llms/extensions/tools/__pycache__/__init__.cpython-314.pyc +0 -0
- llms/extensions/tools/ui/index.mjs +8 -8
- llms/index.html +26 -38
- llms/llms.json +4 -1
- llms/main.py +492 -103
- llms/ui/App.mjs +2 -3
- llms/ui/ai.mjs +29 -13
- llms/ui/app.css +255 -289
- llms/ui/ctx.mjs +84 -6
- llms/ui/index.mjs +4 -6
- llms/ui/lib/vue.min.mjs +10 -9
- llms/ui/lib/vue.mjs +1796 -1635
- llms/ui/markdown.mjs +4 -2
- llms/ui/modules/chat/ChatBody.mjs +90 -86
- llms/ui/modules/chat/HomeTools.mjs +0 -242
- llms/ui/modules/chat/index.mjs +103 -170
- llms/ui/modules/model-selector.mjs +2 -2
- llms/ui/tailwind.input.css +35 -1
- llms/ui/utils.mjs +12 -0
- {llms_py-3.0.0b7.dist-info → llms_py-3.0.0b9.dist-info}/METADATA +1 -1
- llms_py-3.0.0b9.dist-info/RECORD +198 -0
- llms/ui/modules/threads/threadStore.mjs +0 -640
- llms_py-3.0.0b7.dist-info/RECORD +0 -80
- {llms_py-3.0.0b7.dist-info → llms_py-3.0.0b9.dist-info}/WHEEL +0 -0
- {llms_py-3.0.0b7.dist-info → llms_py-3.0.0b9.dist-info}/entry_points.txt +0 -0
- {llms_py-3.0.0b7.dist-info → llms_py-3.0.0b9.dist-info}/licenses/LICENSE +0 -0
- {llms_py-3.0.0b7.dist-info → llms_py-3.0.0b9.dist-info}/top_level.txt +0 -0
|
Binary file
|
|
@@ -46,7 +46,7 @@ const MonthSelector = {
|
|
|
46
46
|
</div>
|
|
47
47
|
`,
|
|
48
48
|
props: {
|
|
49
|
-
dailyData:
|
|
49
|
+
dailyData: Object,
|
|
50
50
|
},
|
|
51
51
|
setup(props) {
|
|
52
52
|
const router = useRouter()
|
|
@@ -307,7 +307,7 @@ export const Analytics = {
|
|
|
307
307
|
|
|
308
308
|
<div class="flex flex-col flex-1 min-w-[140px] sm:flex-initial">
|
|
309
309
|
<select v-model="sortBy" class="px-3 py-2 border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100 rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 w-full">
|
|
310
|
-
<option value="
|
|
310
|
+
<option value="createdAt">Date (Newest)</option>
|
|
311
311
|
<option value="cost">Cost (Highest)</option>
|
|
312
312
|
<option value="duration">Duration (Longest)</option>
|
|
313
313
|
<option value="totalTokens">Tokens (Most)</option>
|
|
@@ -322,14 +322,14 @@ export const Analytics = {
|
|
|
322
322
|
|
|
323
323
|
<!-- Requests List with Infinite Scroll -->
|
|
324
324
|
<div class="flex-1">
|
|
325
|
-
<div v-if="isActivityLoading && activityRequests.length === 0" class="flex items-center justify-center h-full">
|
|
325
|
+
<div v-if="isActivityLoading && activityRequests.length === 0" class="mt-8 flex items-center justify-center h-full">
|
|
326
326
|
<div class="text-center">
|
|
327
327
|
<div class="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600 mx-auto"></div>
|
|
328
328
|
<p class="mt-4 text-gray-600 dark:text-gray-400">Loading requests...</p>
|
|
329
329
|
</div>
|
|
330
330
|
</div>
|
|
331
331
|
|
|
332
|
-
<div v-else-if="activityRequests.length === 0" class="flex items-center justify-center h-full">
|
|
332
|
+
<div v-else-if="activityRequests.length === 0" class="mt-4 flex items-center justify-center h-full">
|
|
333
333
|
<p class="text-gray-500 dark:text-gray-400">No requests found</p>
|
|
334
334
|
</div>
|
|
335
335
|
|
|
@@ -345,32 +345,36 @@ export const Analytics = {
|
|
|
345
345
|
<span v-if="request.finishReason" class="text-xs px-2 py-1 bg-gray-100 dark:bg-gray-700 text-gray-800 dark:text-gray-300 rounded font-medium">{{ request.finishReason }}</span>
|
|
346
346
|
</div>
|
|
347
347
|
<div class="text-xs text-gray-500 dark:text-gray-400 whitespace-nowrap">
|
|
348
|
-
{{ formatActivityDate(request.
|
|
348
|
+
{{ formatActivityDate(request.createdAt) }}
|
|
349
349
|
</div>
|
|
350
350
|
</div>
|
|
351
351
|
<div class="text-sm font-semibold text-gray-900 dark:text-gray-100 truncate mb-3">
|
|
352
352
|
{{ request.title }}
|
|
353
353
|
</div>
|
|
354
354
|
|
|
355
|
-
<div class="
|
|
355
|
+
<div v-if="request.error" class="rounded-lg px-2 py-1 bg-red-50 dark:bg-red-900/30 border border-red-200 dark:border-red-800 text-red-800 dark:text-red-200 text-sm"
|
|
356
|
+
:title="request.error + '\\n' + (request.stacktrace || '')">
|
|
357
|
+
{{ request.error }}
|
|
358
|
+
</div>
|
|
359
|
+
<div v-else class="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-5 gap-3 sm:gap-4">
|
|
356
360
|
<div :title="request.cost">
|
|
357
361
|
<div class="text-xs text-gray-500 dark:text-gray-400 font-medium">Cost</div>
|
|
358
362
|
<div class="text-sm font-semibold text-gray-900 dark:text-gray-100">{{ $fmt.costLong(request.cost) }}</div>
|
|
359
363
|
</div>
|
|
360
364
|
<div class="col-span-2 sm:col-span-1">
|
|
361
365
|
<div class="text-xs text-gray-500 dark:text-gray-400 font-medium">Tokens</div>
|
|
362
|
-
<div class="text-sm font-semibold text-gray-900 dark:text-gray-100">
|
|
363
|
-
{{ $fmt.humanifyNumber(request.inputTokens) }} -> {{ $fmt.humanifyNumber(request.outputTokens) }}
|
|
364
|
-
<span v-if="request.inputCachedTokens" class="ml-1 text-xs text-gray-500 dark:text-gray-400">({{ $fmt.humanifyNumber(request.inputCachedTokens) }} cached)</span>
|
|
366
|
+
<div v-if="request.inputTokens || request.outputTokens" class="text-sm font-semibold text-gray-900 dark:text-gray-100">
|
|
367
|
+
{{ $fmt.humanifyNumber(request.inputTokens || 0) }} -> {{ $fmt.humanifyNumber(request.outputTokens || 0) }}
|
|
368
|
+
<span v-if="request.inputCachedTokens" class="ml-1 text-xs text-gray-500 dark:text-gray-400">({{ $fmt.humanifyNumber(request.inputCachedTokens || 0) }} cached)</span>
|
|
365
369
|
</div>
|
|
366
370
|
</div>
|
|
367
371
|
<div>
|
|
368
372
|
<div class="text-xs text-gray-500 dark:text-gray-400 font-medium">Duration</div>
|
|
369
|
-
<div class="text-sm font-semibold text-gray-900 dark:text-gray-100">{{
|
|
373
|
+
<div v-if="request.duration" class="text-sm font-semibold text-gray-900 dark:text-gray-100">{{ $fmt.humanifyMs(request.duration) }}</div>
|
|
370
374
|
</div>
|
|
371
375
|
<div>
|
|
372
376
|
<div class="text-xs text-gray-500 dark:text-gray-400 font-medium">Speed</div>
|
|
373
|
-
<div class="text-sm font-semibold text-gray-900 dark:text-gray-100">{{
|
|
377
|
+
<div v-if="request.duration && request.outputTokens" class="text-sm font-semibold text-gray-900 dark:text-gray-100">{{ (request.outputTokens / (request.duration / 1000)).toFixed(1) + ' tok/s' }}</div>
|
|
374
378
|
</div>
|
|
375
379
|
</div>
|
|
376
380
|
</div>
|
|
@@ -402,10 +406,9 @@ export const Analytics = {
|
|
|
402
406
|
`,
|
|
403
407
|
setup() {
|
|
404
408
|
const ctx = inject('ctx')
|
|
405
|
-
const threads = ctx.threads
|
|
406
409
|
const router = useRouter()
|
|
407
410
|
const route = useRoute()
|
|
408
|
-
const
|
|
411
|
+
const analyticsData = ref()
|
|
409
412
|
|
|
410
413
|
// Initialize activeTab from URL query parameter, default to 'cost'
|
|
411
414
|
const activeTab = ref(route.query.tab || 'cost')
|
|
@@ -431,6 +434,9 @@ export const Analytics = {
|
|
|
431
434
|
const selectedYear = computed(() => {
|
|
432
435
|
return route.query.year !== undefined ? parseInt(route.query.year) : currentDate.getFullYear()
|
|
433
436
|
})
|
|
437
|
+
const selectedYearMonth = computed(() => {
|
|
438
|
+
return `${selectedYear.value}-${selectedMonth.value < 10 ? '0' + selectedMonth.value : selectedMonth.value}`
|
|
439
|
+
})
|
|
434
440
|
const allDailyData = ref({}) // Store all data for filtering
|
|
435
441
|
|
|
436
442
|
// Selected day - read from URL, default to today
|
|
@@ -526,7 +532,7 @@ export const Analytics = {
|
|
|
526
532
|
|
|
527
533
|
const selectedModel = ref('')
|
|
528
534
|
const selectedProvider = ref('')
|
|
529
|
-
const sortBy = ref('
|
|
535
|
+
const sortBy = ref('createdAt')
|
|
530
536
|
const filterOptions = ref({ models: [], providers: [] })
|
|
531
537
|
const scrollSentinel = ref(null)
|
|
532
538
|
let observer = null
|
|
@@ -535,44 +541,9 @@ export const Analytics = {
|
|
|
535
541
|
|
|
536
542
|
async function loadAnalyticsData() {
|
|
537
543
|
try {
|
|
538
|
-
const db = await initDB()
|
|
539
|
-
const tx = db.transaction(['requests'], 'readonly')
|
|
540
|
-
const store = tx.objectStore('requests')
|
|
541
|
-
const allRequests = await store.getAll()
|
|
542
|
-
|
|
543
544
|
// Group requests by date
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
let totalInputSum = 0
|
|
547
|
-
let totalOutputSum = 0
|
|
548
|
-
const yearsSet = new Set()
|
|
549
|
-
|
|
550
|
-
allRequests.forEach(req => {
|
|
551
|
-
const date = new Date(req.created * 1000)
|
|
552
|
-
const dateKey = date.toISOString().split('T')[0] // YYYY-MM-DD
|
|
553
|
-
yearsSet.add(date.getFullYear())
|
|
554
|
-
|
|
555
|
-
if (!dailyData[dateKey]) {
|
|
556
|
-
dailyData[dateKey] = {
|
|
557
|
-
cost: 0,
|
|
558
|
-
requests: 0,
|
|
559
|
-
inputTokens: 0,
|
|
560
|
-
outputTokens: 0
|
|
561
|
-
}
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
dailyData[dateKey].cost += req.cost || 0
|
|
565
|
-
dailyData[dateKey].requests += 1
|
|
566
|
-
dailyData[dateKey].inputTokens += req.inputTokens || 0
|
|
567
|
-
dailyData[dateKey].outputTokens += req.outputTokens || 0
|
|
568
|
-
|
|
569
|
-
totalCostSum += req.cost || 0
|
|
570
|
-
totalInputSum += req.inputTokens || 0
|
|
571
|
-
totalOutputSum += req.outputTokens || 0
|
|
572
|
-
})
|
|
573
|
-
|
|
574
|
-
// Store all daily data for filtering
|
|
575
|
-
allDailyData.value = dailyData
|
|
545
|
+
analyticsData.value = await ctx.requests.getSummary()
|
|
546
|
+
allDailyData.value = analyticsData.value.dailyData
|
|
576
547
|
|
|
577
548
|
// Update chart data based on selected month/year
|
|
578
549
|
updateChartData()
|
|
@@ -649,36 +620,8 @@ export const Analytics = {
|
|
|
649
620
|
}
|
|
650
621
|
|
|
651
622
|
try {
|
|
652
|
-
const
|
|
653
|
-
const
|
|
654
|
-
const store = tx.objectStore('requests')
|
|
655
|
-
const allRequests = await store.getAll()
|
|
656
|
-
|
|
657
|
-
// Filter requests for the selected day
|
|
658
|
-
const dayStart = Math.floor(new Date(dateKey + 'T00:00:00Z').getTime() / 1000)
|
|
659
|
-
const dayEnd = Math.floor(new Date(dateKey + 'T23:59:59Z').getTime() / 1000)
|
|
660
|
-
|
|
661
|
-
const dayRequests = allRequests.filter(req => req.created >= dayStart && req.created <= dayEnd)
|
|
662
|
-
|
|
663
|
-
// Aggregate by model
|
|
664
|
-
const modelData = {}
|
|
665
|
-
const providerData = {}
|
|
666
|
-
|
|
667
|
-
dayRequests.forEach(req => {
|
|
668
|
-
// Model aggregation
|
|
669
|
-
if (!modelData[req.model]) {
|
|
670
|
-
modelData[req.model] = { cost: 0, count: 0 }
|
|
671
|
-
}
|
|
672
|
-
modelData[req.model].cost += req.cost || 0
|
|
673
|
-
modelData[req.model].count += 1
|
|
674
|
-
|
|
675
|
-
// Provider aggregation
|
|
676
|
-
if (!providerData[req.provider]) {
|
|
677
|
-
providerData[req.provider] = { cost: 0, count: 0 }
|
|
678
|
-
}
|
|
679
|
-
providerData[req.provider].cost += req.cost || 0
|
|
680
|
-
providerData[req.provider].count += 1
|
|
681
|
-
})
|
|
623
|
+
const dailySummary = await ctx.requests.getDailySummary(dateKey)
|
|
624
|
+
const { modelData, providerData } = dailySummary
|
|
682
625
|
|
|
683
626
|
// Prepare model pie chart data
|
|
684
627
|
const modelLabels = Object.keys(modelData).sort()
|
|
@@ -722,38 +665,8 @@ export const Analytics = {
|
|
|
722
665
|
}
|
|
723
666
|
|
|
724
667
|
try {
|
|
725
|
-
const
|
|
726
|
-
const
|
|
727
|
-
const store = tx.objectStore('requests')
|
|
728
|
-
const allRequests = await store.getAll()
|
|
729
|
-
|
|
730
|
-
// Filter requests for the selected day
|
|
731
|
-
const dayStart = Math.floor(new Date(dateKey + 'T00:00:00Z').getTime() / 1000)
|
|
732
|
-
const dayEnd = Math.floor(new Date(dateKey + 'T23:59:59Z').getTime() / 1000)
|
|
733
|
-
|
|
734
|
-
const dayRequests = allRequests.filter(req => req.created >= dayStart && req.created <= dayEnd)
|
|
735
|
-
|
|
736
|
-
// Aggregate by model and provider (using tokens)
|
|
737
|
-
const modelData = {}
|
|
738
|
-
const providerData = {}
|
|
739
|
-
|
|
740
|
-
dayRequests.forEach(req => {
|
|
741
|
-
const totalTokens = (req.inputTokens || 0) + (req.outputTokens || 0)
|
|
742
|
-
|
|
743
|
-
// Model aggregation
|
|
744
|
-
if (!modelData[req.model]) {
|
|
745
|
-
modelData[req.model] = { tokens: 0, count: 0 }
|
|
746
|
-
}
|
|
747
|
-
modelData[req.model].tokens += totalTokens
|
|
748
|
-
modelData[req.model].count += 1
|
|
749
|
-
|
|
750
|
-
// Provider aggregation
|
|
751
|
-
if (!providerData[req.provider]) {
|
|
752
|
-
providerData[req.provider] = { tokens: 0, count: 0 }
|
|
753
|
-
}
|
|
754
|
-
providerData[req.provider].tokens += totalTokens
|
|
755
|
-
providerData[req.provider].count += 1
|
|
756
|
-
})
|
|
668
|
+
const dailySummary = await ctx.requests.getDailySummary(dateKey)
|
|
669
|
+
const { modelData, providerData } = dailySummary
|
|
757
670
|
|
|
758
671
|
// Prepare model pie chart data
|
|
759
672
|
const modelLabels = Object.keys(modelData).sort()
|
|
@@ -1235,7 +1148,7 @@ export const Analytics = {
|
|
|
1235
1148
|
// Activity tab functions
|
|
1236
1149
|
const loadActivityFilterOptions = async () => {
|
|
1237
1150
|
try {
|
|
1238
|
-
filterOptions.value = await
|
|
1151
|
+
filterOptions.value = await ctx.requests.getFilterOptions()
|
|
1239
1152
|
} catch (error) {
|
|
1240
1153
|
console.error('Failed to load filter options:', error)
|
|
1241
1154
|
}
|
|
@@ -1243,24 +1156,9 @@ export const Analytics = {
|
|
|
1243
1156
|
|
|
1244
1157
|
const loadExistingThreadIds = async () => {
|
|
1245
1158
|
try {
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
// Convert to timestamp strings (threadId format)
|
|
1251
|
-
const startThreadId = startDate.getTime().toString()
|
|
1252
|
-
const endThreadId = endDate.getTime().toString()
|
|
1253
|
-
|
|
1254
|
-
const db = await initDB()
|
|
1255
|
-
const tx = db.transaction(['threads'], 'readonly')
|
|
1256
|
-
const store = tx.objectStore('threads')
|
|
1257
|
-
|
|
1258
|
-
// Use IDBKeyRange to only load threads within the month's timestamp range
|
|
1259
|
-
const range = IDBKeyRange.bound(startThreadId, endThreadId)
|
|
1260
|
-
const monthThreads = await store.getAll(range)
|
|
1261
|
-
|
|
1262
|
-
// Create a Set of existing thread IDs for the month
|
|
1263
|
-
existingThreadIds.value = new Set(monthThreads.map(thread => thread.id))
|
|
1159
|
+
existingThreadIds.value = new Set(await ctx.requests.getThreadIds({
|
|
1160
|
+
month: selectedYearMonth.value,
|
|
1161
|
+
}))
|
|
1264
1162
|
} catch (error) {
|
|
1265
1163
|
console.error('Failed to load existing thread IDs:', error)
|
|
1266
1164
|
existingThreadIds.value = new Set()
|
|
@@ -1283,28 +1181,24 @@ export const Analytics = {
|
|
|
1283
1181
|
}
|
|
1284
1182
|
|
|
1285
1183
|
try {
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
sortOrder: 'desc',
|
|
1295
|
-
startDate: Math.floor(startDate.getTime() / 1000),
|
|
1296
|
-
endDate: Math.floor(endDate.getTime() / 1000)
|
|
1297
|
-
}
|
|
1184
|
+
const requests = await ctx.requests.query({
|
|
1185
|
+
model: selectedModel.value || undefined,
|
|
1186
|
+
provider: selectedProvider.value || undefined,
|
|
1187
|
+
sort: `-${sortBy.value}`,
|
|
1188
|
+
take: activityPageSize,
|
|
1189
|
+
skip: activityOffset.value,
|
|
1190
|
+
month: selectedYearMonth.value,
|
|
1191
|
+
})
|
|
1298
1192
|
|
|
1299
|
-
const
|
|
1193
|
+
const hasMore = requests.length >= activityPageSize
|
|
1300
1194
|
|
|
1301
1195
|
if (reset) {
|
|
1302
|
-
activityRequests.value =
|
|
1196
|
+
activityRequests.value = requests
|
|
1303
1197
|
} else {
|
|
1304
|
-
activityRequests.value.push(...
|
|
1198
|
+
activityRequests.value.push(...requests)
|
|
1305
1199
|
}
|
|
1306
1200
|
|
|
1307
|
-
activityHasMore.value =
|
|
1201
|
+
activityHasMore.value = hasMore
|
|
1308
1202
|
activityOffset.value += activityPageSize
|
|
1309
1203
|
} catch (error) {
|
|
1310
1204
|
console.error('Failed to load requests:', error)
|
|
@@ -1331,12 +1225,12 @@ export const Analytics = {
|
|
|
1331
1225
|
const clearActivityFilters = async () => {
|
|
1332
1226
|
selectedModel.value = ''
|
|
1333
1227
|
selectedProvider.value = ''
|
|
1334
|
-
sortBy.value = '
|
|
1228
|
+
sortBy.value = 'createdAt'
|
|
1335
1229
|
await loadActivityRequests(true)
|
|
1336
1230
|
}
|
|
1337
1231
|
|
|
1338
|
-
const formatActivityDate = (
|
|
1339
|
-
const date = new Date(
|
|
1232
|
+
const formatActivityDate = (d) => {
|
|
1233
|
+
const date = new Date(d)
|
|
1340
1234
|
return date.toLocaleTimeString(undefined, { hour12: false }) + ' '
|
|
1341
1235
|
+ date.toLocaleDateString(undefined, { year: 'numeric', month: 'long', day: 'numeric' })
|
|
1342
1236
|
|
|
@@ -1347,17 +1241,12 @@ export const Analytics = {
|
|
|
1347
1241
|
}
|
|
1348
1242
|
|
|
1349
1243
|
const deleteRequestLog = async (requestId) => {
|
|
1350
|
-
if (confirm(
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
await loadAnalyticsData()
|
|
1357
|
-
} catch (error) {
|
|
1358
|
-
console.error('Failed to delete request:', error)
|
|
1359
|
-
alert('Failed to delete request')
|
|
1360
|
-
}
|
|
1244
|
+
if (confirm(`Are you sure you want to delete this request log ${requestId}?`)) {
|
|
1245
|
+
await ctx.requests.deleteById(requestId)
|
|
1246
|
+
// Remove from the list
|
|
1247
|
+
activityRequests.value = activityRequests.value.filter(r => r.id !== requestId)
|
|
1248
|
+
// Reload analytics data
|
|
1249
|
+
await loadAnalyticsData()
|
|
1361
1250
|
}
|
|
1362
1251
|
}
|
|
1363
1252
|
|