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.
Files changed (157) hide show
  1. llms/__pycache__/main.cpython-314.pyc +0 -0
  2. llms/extensions/analytics/ui/index.mjs +51 -162
  3. llms/extensions/app/__init__.py +519 -0
  4. llms/extensions/app/__pycache__/__init__.cpython-314.pyc +0 -0
  5. llms/extensions/app/__pycache__/db.cpython-314.pyc +0 -0
  6. llms/extensions/app/__pycache__/db_manager.cpython-314.pyc +0 -0
  7. llms/extensions/app/db.py +643 -0
  8. llms/extensions/app/db_manager.py +195 -0
  9. llms/extensions/app/requests.json +9073 -0
  10. llms/extensions/app/threads.json +15290 -0
  11. llms/{ui/modules/threads → extensions/app/ui}/Recents.mjs +82 -55
  12. llms/{ui/modules/threads → extensions/app/ui}/index.mjs +78 -9
  13. llms/extensions/app/ui/threadStore.mjs +407 -0
  14. llms/extensions/core_tools/__init__.py +272 -32
  15. llms/extensions/core_tools/__pycache__/__init__.cpython-314.pyc +0 -0
  16. llms/extensions/core_tools/ui/codemirror/addon/edit/closebrackets.js +201 -0
  17. llms/extensions/core_tools/ui/codemirror/addon/edit/closetag.js +185 -0
  18. llms/extensions/core_tools/ui/codemirror/addon/edit/continuelist.js +101 -0
  19. llms/extensions/core_tools/ui/codemirror/addon/edit/matchbrackets.js +160 -0
  20. llms/extensions/core_tools/ui/codemirror/addon/edit/matchtags.js +66 -0
  21. llms/extensions/core_tools/ui/codemirror/addon/edit/trailingspace.js +27 -0
  22. llms/extensions/core_tools/ui/codemirror/addon/selection/active-line.js +72 -0
  23. llms/extensions/core_tools/ui/codemirror/addon/selection/mark-selection.js +119 -0
  24. llms/extensions/core_tools/ui/codemirror/addon/selection/selection-pointer.js +98 -0
  25. llms/extensions/core_tools/ui/codemirror/doc/docs.css +225 -0
  26. llms/extensions/core_tools/ui/codemirror/doc/source_sans.woff +0 -0
  27. llms/extensions/core_tools/ui/codemirror/lib/codemirror.css +344 -0
  28. llms/extensions/core_tools/ui/codemirror/lib/codemirror.js +9884 -0
  29. llms/extensions/core_tools/ui/codemirror/mode/clike/clike.js +942 -0
  30. llms/extensions/core_tools/ui/codemirror/mode/javascript/index.html +118 -0
  31. llms/extensions/core_tools/ui/codemirror/mode/javascript/javascript.js +962 -0
  32. llms/extensions/core_tools/ui/codemirror/mode/javascript/typescript.html +62 -0
  33. llms/extensions/core_tools/ui/codemirror/mode/python/python.js +402 -0
  34. llms/extensions/core_tools/ui/codemirror/theme/dracula.css +40 -0
  35. llms/extensions/core_tools/ui/codemirror/theme/mocha.css +135 -0
  36. llms/extensions/core_tools/ui/index.mjs +650 -0
  37. llms/extensions/gallery/__pycache__/db.cpython-314.pyc +0 -0
  38. llms/extensions/gallery/db.py +4 -4
  39. llms/extensions/gallery/ui/index.mjs +2 -1
  40. llms/extensions/katex/__init__.py +6 -0
  41. llms/extensions/katex/__pycache__/__init__.cpython-314.pyc +0 -0
  42. llms/extensions/katex/ui/README.md +125 -0
  43. llms/extensions/katex/ui/contrib/auto-render.js +338 -0
  44. llms/extensions/katex/ui/contrib/auto-render.min.js +1 -0
  45. llms/extensions/katex/ui/contrib/auto-render.mjs +244 -0
  46. llms/extensions/katex/ui/contrib/copy-tex.js +127 -0
  47. llms/extensions/katex/ui/contrib/copy-tex.min.js +1 -0
  48. llms/extensions/katex/ui/contrib/copy-tex.mjs +105 -0
  49. llms/extensions/katex/ui/contrib/mathtex-script-type.js +109 -0
  50. llms/extensions/katex/ui/contrib/mathtex-script-type.min.js +1 -0
  51. llms/extensions/katex/ui/contrib/mathtex-script-type.mjs +24 -0
  52. llms/extensions/katex/ui/contrib/mhchem.js +3213 -0
  53. llms/extensions/katex/ui/contrib/mhchem.min.js +1 -0
  54. llms/extensions/katex/ui/contrib/mhchem.mjs +3109 -0
  55. llms/extensions/katex/ui/contrib/render-a11y-string.js +887 -0
  56. llms/extensions/katex/ui/contrib/render-a11y-string.min.js +1 -0
  57. llms/extensions/katex/ui/contrib/render-a11y-string.mjs +800 -0
  58. llms/extensions/katex/ui/fonts/KaTeX_AMS-Regular.ttf +0 -0
  59. llms/extensions/katex/ui/fonts/KaTeX_AMS-Regular.woff +0 -0
  60. llms/extensions/katex/ui/fonts/KaTeX_AMS-Regular.woff2 +0 -0
  61. llms/extensions/katex/ui/fonts/KaTeX_Caligraphic-Bold.ttf +0 -0
  62. llms/extensions/katex/ui/fonts/KaTeX_Caligraphic-Bold.woff +0 -0
  63. llms/extensions/katex/ui/fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
  64. llms/extensions/katex/ui/fonts/KaTeX_Caligraphic-Regular.ttf +0 -0
  65. llms/extensions/katex/ui/fonts/KaTeX_Caligraphic-Regular.woff +0 -0
  66. llms/extensions/katex/ui/fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
  67. llms/extensions/katex/ui/fonts/KaTeX_Fraktur-Bold.ttf +0 -0
  68. llms/extensions/katex/ui/fonts/KaTeX_Fraktur-Bold.woff +0 -0
  69. llms/extensions/katex/ui/fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
  70. llms/extensions/katex/ui/fonts/KaTeX_Fraktur-Regular.ttf +0 -0
  71. llms/extensions/katex/ui/fonts/KaTeX_Fraktur-Regular.woff +0 -0
  72. llms/extensions/katex/ui/fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
  73. llms/extensions/katex/ui/fonts/KaTeX_Main-Bold.ttf +0 -0
  74. llms/extensions/katex/ui/fonts/KaTeX_Main-Bold.woff +0 -0
  75. llms/extensions/katex/ui/fonts/KaTeX_Main-Bold.woff2 +0 -0
  76. llms/extensions/katex/ui/fonts/KaTeX_Main-BoldItalic.ttf +0 -0
  77. llms/extensions/katex/ui/fonts/KaTeX_Main-BoldItalic.woff +0 -0
  78. llms/extensions/katex/ui/fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
  79. llms/extensions/katex/ui/fonts/KaTeX_Main-Italic.ttf +0 -0
  80. llms/extensions/katex/ui/fonts/KaTeX_Main-Italic.woff +0 -0
  81. llms/extensions/katex/ui/fonts/KaTeX_Main-Italic.woff2 +0 -0
  82. llms/extensions/katex/ui/fonts/KaTeX_Main-Regular.ttf +0 -0
  83. llms/extensions/katex/ui/fonts/KaTeX_Main-Regular.woff +0 -0
  84. llms/extensions/katex/ui/fonts/KaTeX_Main-Regular.woff2 +0 -0
  85. llms/extensions/katex/ui/fonts/KaTeX_Math-BoldItalic.ttf +0 -0
  86. llms/extensions/katex/ui/fonts/KaTeX_Math-BoldItalic.woff +0 -0
  87. llms/extensions/katex/ui/fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
  88. llms/extensions/katex/ui/fonts/KaTeX_Math-Italic.ttf +0 -0
  89. llms/extensions/katex/ui/fonts/KaTeX_Math-Italic.woff +0 -0
  90. llms/extensions/katex/ui/fonts/KaTeX_Math-Italic.woff2 +0 -0
  91. llms/extensions/katex/ui/fonts/KaTeX_SansSerif-Bold.ttf +0 -0
  92. llms/extensions/katex/ui/fonts/KaTeX_SansSerif-Bold.woff +0 -0
  93. llms/extensions/katex/ui/fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
  94. llms/extensions/katex/ui/fonts/KaTeX_SansSerif-Italic.ttf +0 -0
  95. llms/extensions/katex/ui/fonts/KaTeX_SansSerif-Italic.woff +0 -0
  96. llms/extensions/katex/ui/fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
  97. llms/extensions/katex/ui/fonts/KaTeX_SansSerif-Regular.ttf +0 -0
  98. llms/extensions/katex/ui/fonts/KaTeX_SansSerif-Regular.woff +0 -0
  99. llms/extensions/katex/ui/fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
  100. llms/extensions/katex/ui/fonts/KaTeX_Script-Regular.ttf +0 -0
  101. llms/extensions/katex/ui/fonts/KaTeX_Script-Regular.woff +0 -0
  102. llms/extensions/katex/ui/fonts/KaTeX_Script-Regular.woff2 +0 -0
  103. llms/extensions/katex/ui/fonts/KaTeX_Size1-Regular.ttf +0 -0
  104. llms/extensions/katex/ui/fonts/KaTeX_Size1-Regular.woff +0 -0
  105. llms/extensions/katex/ui/fonts/KaTeX_Size1-Regular.woff2 +0 -0
  106. llms/extensions/katex/ui/fonts/KaTeX_Size2-Regular.ttf +0 -0
  107. llms/extensions/katex/ui/fonts/KaTeX_Size2-Regular.woff +0 -0
  108. llms/extensions/katex/ui/fonts/KaTeX_Size2-Regular.woff2 +0 -0
  109. llms/extensions/katex/ui/fonts/KaTeX_Size3-Regular.ttf +0 -0
  110. llms/extensions/katex/ui/fonts/KaTeX_Size3-Regular.woff +0 -0
  111. llms/extensions/katex/ui/fonts/KaTeX_Size3-Regular.woff2 +0 -0
  112. llms/extensions/katex/ui/fonts/KaTeX_Size4-Regular.ttf +0 -0
  113. llms/extensions/katex/ui/fonts/KaTeX_Size4-Regular.woff +0 -0
  114. llms/extensions/katex/ui/fonts/KaTeX_Size4-Regular.woff2 +0 -0
  115. llms/extensions/katex/ui/fonts/KaTeX_Typewriter-Regular.ttf +0 -0
  116. llms/extensions/katex/ui/fonts/KaTeX_Typewriter-Regular.woff +0 -0
  117. llms/extensions/katex/ui/fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
  118. llms/extensions/katex/ui/index.mjs +92 -0
  119. llms/extensions/katex/ui/katex-swap.css +1230 -0
  120. llms/extensions/katex/ui/katex-swap.min.css +1 -0
  121. llms/extensions/katex/ui/katex.css +1230 -0
  122. llms/extensions/katex/ui/katex.js +19080 -0
  123. llms/extensions/katex/ui/katex.min.css +1 -0
  124. llms/extensions/katex/ui/katex.min.js +1 -0
  125. llms/extensions/katex/ui/katex.min.mjs +1 -0
  126. llms/extensions/katex/ui/katex.mjs +18547 -0
  127. llms/extensions/providers/__pycache__/anthropic.cpython-314.pyc +0 -0
  128. llms/extensions/providers/anthropic.py +44 -1
  129. llms/extensions/system_prompts/ui/index.mjs +2 -1
  130. llms/extensions/tools/__init__.py +5 -0
  131. llms/extensions/tools/__pycache__/__init__.cpython-314.pyc +0 -0
  132. llms/extensions/tools/ui/index.mjs +8 -8
  133. llms/index.html +26 -38
  134. llms/llms.json +4 -1
  135. llms/main.py +492 -103
  136. llms/ui/App.mjs +2 -3
  137. llms/ui/ai.mjs +29 -13
  138. llms/ui/app.css +255 -289
  139. llms/ui/ctx.mjs +84 -6
  140. llms/ui/index.mjs +4 -6
  141. llms/ui/lib/vue.min.mjs +10 -9
  142. llms/ui/lib/vue.mjs +1796 -1635
  143. llms/ui/markdown.mjs +4 -2
  144. llms/ui/modules/chat/ChatBody.mjs +90 -86
  145. llms/ui/modules/chat/HomeTools.mjs +0 -242
  146. llms/ui/modules/chat/index.mjs +103 -170
  147. llms/ui/modules/model-selector.mjs +2 -2
  148. llms/ui/tailwind.input.css +35 -1
  149. llms/ui/utils.mjs +12 -0
  150. {llms_py-3.0.0b7.dist-info → llms_py-3.0.0b9.dist-info}/METADATA +1 -1
  151. llms_py-3.0.0b9.dist-info/RECORD +198 -0
  152. llms/ui/modules/threads/threadStore.mjs +0 -640
  153. llms_py-3.0.0b7.dist-info/RECORD +0 -80
  154. {llms_py-3.0.0b7.dist-info → llms_py-3.0.0b9.dist-info}/WHEEL +0 -0
  155. {llms_py-3.0.0b7.dist-info → llms_py-3.0.0b9.dist-info}/entry_points.txt +0 -0
  156. {llms_py-3.0.0b7.dist-info → llms_py-3.0.0b9.dist-info}/licenses/LICENSE +0 -0
  157. {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: Array,
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="created">Date (Newest)</option>
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.created) }}
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="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-5 gap-3 sm:gap-4">
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">{{ request.duration ? $fmt.humanifyMs(request.duration) : '—' }}</div>
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">{{ request.duration && request.outputTokens ? (request.outputTokens / (request.duration / 1000)).toFixed(1) + ' tok/s' : '—' }}</div>
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 { initDB } = threads
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('created')
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
- const dailyData = {}
545
- let totalCostSum = 0
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 db = await initDB()
653
- const tx = db.transaction(['requests'], 'readonly')
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 db = await initDB()
726
- const tx = db.transaction(['requests'], 'readonly')
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 threads.getFilterOptions()
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
- // Calculate date range for selected month/year
1247
- const startDate = new Date(selectedYear.value, selectedMonth.value - 1, 1)
1248
- const endDate = new Date(selectedYear.value, selectedMonth.value, 0, 23, 59, 59)
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
- // Calculate date range for selected month/year
1287
- const startDate = new Date(selectedYear.value, selectedMonth.value - 1, 1)
1288
- const endDate = new Date(selectedYear.value, selectedMonth.value, 0, 23, 59, 59)
1289
-
1290
- const filters = {
1291
- model: selectedModel.value || null,
1292
- provider: selectedProvider.value || null,
1293
- sortBy: sortBy.value,
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 result = await threads.getRequests(filters, activityPageSize, activityOffset.value)
1193
+ const hasMore = requests.length >= activityPageSize
1300
1194
 
1301
1195
  if (reset) {
1302
- activityRequests.value = result.requests
1196
+ activityRequests.value = requests
1303
1197
  } else {
1304
- activityRequests.value.push(...result.requests)
1198
+ activityRequests.value.push(...requests)
1305
1199
  }
1306
1200
 
1307
- activityHasMore.value = result.hasMore
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 = 'created'
1228
+ sortBy.value = 'createdAt'
1335
1229
  await loadActivityRequests(true)
1336
1230
  }
1337
1231
 
1338
- const formatActivityDate = (timestamp) => {
1339
- const date = new Date(timestamp * 1000)
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('Are you sure you want to delete this request log?')) {
1351
- try {
1352
- await threads.deleteRequest(requestId)
1353
- // Remove from the list
1354
- activityRequests.value = activityRequests.value.filter(r => r.id !== requestId)
1355
- // Reload analytics data
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