llms-py 3.0.0b2__py3-none-any.whl → 3.0.0b3__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/index.html +2 -1
- llms/llms.json +50 -17
- llms/main.py +484 -544
- llms/providers/__pycache__/anthropic.cpython-314.pyc +0 -0
- llms/providers/__pycache__/chutes.cpython-314.pyc +0 -0
- llms/providers/__pycache__/google.cpython-314.pyc +0 -0
- llms/providers/__pycache__/nvidia.cpython-314.pyc +0 -0
- llms/providers/__pycache__/openai.cpython-314.pyc +0 -0
- llms/providers/__pycache__/openrouter.cpython-314.pyc +0 -0
- llms/providers/anthropic.py +189 -0
- llms/providers/chutes.py +152 -0
- llms/providers/google.py +306 -0
- llms/providers/nvidia.py +107 -0
- llms/providers/openai.py +159 -0
- llms/providers/openrouter.py +70 -0
- llms/providers-extra.json +356 -0
- llms/providers.json +1 -1
- llms/ui/App.mjs +132 -60
- llms/ui/ai.mjs +76 -10
- llms/ui/app.css +1 -4962
- llms/ui/ctx.mjs +196 -0
- llms/ui/index.mjs +75 -171
- llms/ui/lib/charts.mjs +9 -13
- llms/ui/markdown.mjs +6 -0
- llms/ui/{Analytics.mjs → modules/analytics.mjs} +76 -64
- llms/ui/{Main.mjs → modules/chat/ChatBody.mjs} +56 -133
- llms/ui/{SettingsDialog.mjs → modules/chat/SettingsDialog.mjs} +8 -8
- llms/ui/{ChatPrompt.mjs → modules/chat/index.mjs} +239 -45
- llms/ui/modules/layout.mjs +267 -0
- llms/ui/modules/model-selector.mjs +851 -0
- llms/ui/{Recents.mjs → modules/threads/Recents.mjs} +0 -2
- llms/ui/{Sidebar.mjs → modules/threads/index.mjs} +46 -44
- llms/ui/{threadStore.mjs → modules/threads/threadStore.mjs} +10 -7
- llms/ui/utils.mjs +82 -123
- {llms_py-3.0.0b2.dist-info → llms_py-3.0.0b3.dist-info}/METADATA +1 -1
- llms_py-3.0.0b3.dist-info/RECORD +65 -0
- llms/ui/Avatar.mjs +0 -86
- llms/ui/Brand.mjs +0 -52
- llms/ui/OAuthSignIn.mjs +0 -61
- llms/ui/ProviderIcon.mjs +0 -36
- llms/ui/ProviderStatus.mjs +0 -104
- llms/ui/SignIn.mjs +0 -65
- llms/ui/Welcome.mjs +0 -8
- llms/ui/model-selector.mjs +0 -686
- llms/ui.json +0 -1069
- llms_py-3.0.0b2.dist-info/RECORD +0 -58
- {llms_py-3.0.0b2.dist-info → llms_py-3.0.0b3.dist-info}/WHEEL +0 -0
- {llms_py-3.0.0b2.dist-info → llms_py-3.0.0b3.dist-info}/entry_points.txt +0 -0
- {llms_py-3.0.0b2.dist-info → llms_py-3.0.0b3.dist-info}/licenses/LICENSE +0 -0
- {llms_py-3.0.0b2.dist-info → llms_py-3.0.0b3.dist-info}/top_level.txt +0 -0
|
@@ -1,29 +1,24 @@
|
|
|
1
|
-
import { ref, onMounted, watch, nextTick, computed } from 'vue'
|
|
1
|
+
import { ref, onMounted, watch, nextTick, computed, inject } from 'vue'
|
|
2
2
|
import { useRouter, useRoute } from 'vue-router'
|
|
3
|
-
import { useFormatters } from "@servicestack/vue"
|
|
4
3
|
import { leftPart } from '@servicestack/client'
|
|
5
4
|
import { Chart, registerables } from "chart.js"
|
|
6
|
-
import { useThreadStore } from './threadStore.mjs'
|
|
7
|
-
import { formatCost } from './utils.mjs'
|
|
8
5
|
Chart.register(...registerables)
|
|
9
6
|
|
|
10
|
-
const { humanifyNumber, humanifyMs } = useFormatters()
|
|
11
|
-
|
|
12
7
|
export const colors = [
|
|
13
|
-
{ background: 'rgba(54, 162, 235, 0.2)',
|
|
14
|
-
{ background: 'rgba(255, 99, 132, 0.2)',
|
|
8
|
+
{ background: 'rgba(54, 162, 235, 0.2)', border: 'rgb(54, 162, 235)' }, //blue
|
|
9
|
+
{ background: 'rgba(255, 99, 132, 0.2)', border: 'rgb(255, 99, 132)' },
|
|
15
10
|
{ background: 'rgba(153, 102, 255, 0.2)', border: 'rgb(153, 102, 255)' },
|
|
16
|
-
{ background: 'rgba(54, 162, 235, 0.2)',
|
|
17
|
-
{ background: 'rgba(255, 159, 64, 0.2)',
|
|
18
|
-
{ background: 'rgba(67, 56, 202, 0.2)',
|
|
19
|
-
{ background: 'rgba(255, 99, 132, 0.2)',
|
|
20
|
-
{ background: 'rgba(14, 116, 144, 0.2)',
|
|
21
|
-
{ background: 'rgba(162, 28, 175, 0.2)',
|
|
11
|
+
{ background: 'rgba(54, 162, 235, 0.2)', border: 'rgb(54, 162, 235)' },
|
|
12
|
+
{ background: 'rgba(255, 159, 64, 0.2)', border: 'rgb(255, 159, 64)' },
|
|
13
|
+
{ background: 'rgba(67, 56, 202, 0.2)', border: 'rgb(67, 56, 202)' },
|
|
14
|
+
{ background: 'rgba(255, 99, 132, 0.2)', border: 'rgb(255, 99, 132)' },
|
|
15
|
+
{ background: 'rgba(14, 116, 144, 0.2)', border: 'rgb(14, 116, 144)' },
|
|
16
|
+
{ background: 'rgba(162, 28, 175, 0.2)', border: 'rgb(162, 28, 175)' },
|
|
22
17
|
{ background: 'rgba(201, 203, 207, 0.2)', border: 'rgb(201, 203, 207)' },
|
|
23
18
|
]
|
|
24
19
|
|
|
25
20
|
const MonthSelector = {
|
|
26
|
-
template
|
|
21
|
+
template: `
|
|
27
22
|
<div class="flex flex-col sm:flex-row gap-2 sm:gap-4 items-stretch sm:items-center w-full sm:w-auto">
|
|
28
23
|
<!-- Months Row -->
|
|
29
24
|
<div class="flex gap-1 sm:gap-2 flex-wrap justify-center overflow-x-auto">
|
|
@@ -109,10 +104,7 @@ const MonthSelector = {
|
|
|
109
104
|
}
|
|
110
105
|
}
|
|
111
106
|
|
|
112
|
-
export
|
|
113
|
-
components: {
|
|
114
|
-
MonthSelector,
|
|
115
|
-
},
|
|
107
|
+
export const Analytics = {
|
|
116
108
|
template: `
|
|
117
109
|
<div class="flex flex-col h-full w-full">
|
|
118
110
|
<!-- Header -->
|
|
@@ -165,7 +157,7 @@ export default {
|
|
|
165
157
|
<div v-if="activeTab !== 'activity'" class="grid grid-cols-1 md:grid-cols-4 gap-4 mb-6">
|
|
166
158
|
<div class="bg-white dark:bg-gray-800 rounded-lg shadow p-4">
|
|
167
159
|
<div class="text-sm font-medium text-gray-600 dark:text-gray-400">Total Cost</div>
|
|
168
|
-
<div class="text-2xl font-bold text-gray-900 dark:text-gray-100 mt-1">{{
|
|
160
|
+
<div class="text-2xl font-bold text-gray-900 dark:text-gray-100 mt-1">{{ $fmt.cost(totalCost) }}</div>
|
|
169
161
|
</div>
|
|
170
162
|
<div class="bg-white dark:bg-gray-800 rounded-lg shadow p-4">
|
|
171
163
|
<div class="text-sm font-medium text-gray-600 dark:text-gray-400">Total Requests</div>
|
|
@@ -173,11 +165,11 @@ export default {
|
|
|
173
165
|
</div>
|
|
174
166
|
<div class="bg-white dark:bg-gray-800 rounded-lg shadow p-4">
|
|
175
167
|
<div class="text-sm font-medium text-gray-600 dark:text-gray-400">Total Input Tokens</div>
|
|
176
|
-
<div class="text-2xl font-bold text-gray-900 dark:text-gray-100 mt-1">{{ humanifyNumber(totalInputTokens) }}</div>
|
|
168
|
+
<div class="text-2xl font-bold text-gray-900 dark:text-gray-100 mt-1">{{ $fmt.humanifyNumber(totalInputTokens) }}</div>
|
|
177
169
|
</div>
|
|
178
170
|
<div class="bg-white dark:bg-gray-800 rounded-lg shadow p-4">
|
|
179
171
|
<div class="text-sm font-medium text-gray-600 dark:text-gray-400">Total Output Tokens</div>
|
|
180
|
-
<div class="text-2xl font-bold text-gray-900 dark:text-gray-100 mt-1">{{ humanifyNumber(totalOutputTokens) }}</div>
|
|
172
|
+
<div class="text-2xl font-bold text-gray-900 dark:text-gray-100 mt-1">{{ $fmt.humanifyNumber(totalOutputTokens) }}</div>
|
|
181
173
|
</div>
|
|
182
174
|
</div>
|
|
183
175
|
|
|
@@ -224,11 +216,11 @@ export default {
|
|
|
224
216
|
{{ new Date(selectedDay).toLocaleDateString(undefined, { year: 'numeric', month: 'long', day: 'numeric' }) }}
|
|
225
217
|
</div>
|
|
226
218
|
<div class="flex flex-wrap gap-x-2 gap-y-1">
|
|
227
|
-
<span>{{
|
|
219
|
+
<span>{{ $fmt.cost(allDailyData[selectedDay]?.cost || 0) }}</span>
|
|
228
220
|
<span>·</span>
|
|
229
221
|
<span>{{ allDailyData[selectedDay]?.requests || 0 }} Requests</span>
|
|
230
222
|
<span>·</span>
|
|
231
|
-
<span>{{ humanifyNumber(allDailyData[selectedDay]?.inputTokens || 0) }} -> {{ humanifyNumber(allDailyData[selectedDay]?.outputTokens || 0) }} Tokens</span>
|
|
223
|
+
<span>{{ $fmt.humanifyNumber(allDailyData[selectedDay]?.inputTokens || 0) }} -> {{ $fmt.humanifyNumber(allDailyData[selectedDay]?.outputTokens || 0) }} Tokens</span>
|
|
232
224
|
</div>
|
|
233
225
|
</div>
|
|
234
226
|
|
|
@@ -363,18 +355,18 @@ export default {
|
|
|
363
355
|
<div class="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-5 gap-3 sm:gap-4">
|
|
364
356
|
<div :title="request.cost">
|
|
365
357
|
<div class="text-xs text-gray-500 dark:text-gray-400 font-medium">Cost</div>
|
|
366
|
-
<div class="text-sm font-semibold text-gray-900 dark:text-gray-100">{{
|
|
358
|
+
<div class="text-sm font-semibold text-gray-900 dark:text-gray-100">{{ $fmt.costLong(request.cost) }}</div>
|
|
367
359
|
</div>
|
|
368
360
|
<div class="col-span-2 sm:col-span-1">
|
|
369
361
|
<div class="text-xs text-gray-500 dark:text-gray-400 font-medium">Tokens</div>
|
|
370
362
|
<div class="text-sm font-semibold text-gray-900 dark:text-gray-100">
|
|
371
|
-
{{ humanifyNumber(request.inputTokens) }} -> {{ humanifyNumber(request.outputTokens) }}
|
|
372
|
-
<span v-if="request.inputCachedTokens" class="ml-1 text-xs text-gray-500 dark:text-gray-400">({{ humanifyNumber(request.inputCachedTokens) }} cached)</span>
|
|
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>
|
|
373
365
|
</div>
|
|
374
366
|
</div>
|
|
375
367
|
<div>
|
|
376
368
|
<div class="text-xs text-gray-500 dark:text-gray-400 font-medium">Duration</div>
|
|
377
|
-
<div class="text-sm font-semibold text-gray-900 dark:text-gray-100">{{ request.duration ? humanifyMs(request.duration) : '—' }}</div>
|
|
369
|
+
<div class="text-sm font-semibold text-gray-900 dark:text-gray-100">{{ request.duration ? $fmt.humanifyMs(request.duration) : '—' }}</div>
|
|
378
370
|
</div>
|
|
379
371
|
<div>
|
|
380
372
|
<div class="text-xs text-gray-500 dark:text-gray-400 font-medium">Speed</div>
|
|
@@ -408,9 +400,10 @@ export default {
|
|
|
408
400
|
</div>
|
|
409
401
|
`,
|
|
410
402
|
setup() {
|
|
403
|
+
const ctx = inject('ctx')
|
|
404
|
+
const threads = ctx.threads
|
|
411
405
|
const router = useRouter()
|
|
412
406
|
const route = useRoute()
|
|
413
|
-
const threads = useThreadStore()
|
|
414
407
|
const { initDB } = threads
|
|
415
408
|
|
|
416
409
|
// Initialize activeTab from URL query parameter, default to 'cost'
|
|
@@ -802,7 +795,7 @@ export default {
|
|
|
802
795
|
costChartInstance.destroy()
|
|
803
796
|
}
|
|
804
797
|
|
|
805
|
-
const
|
|
798
|
+
const ctx2d = costChartCanvas.value.getContext('2d')
|
|
806
799
|
const chartTypeValue = costChartType.value
|
|
807
800
|
|
|
808
801
|
// Find the index of the selected day
|
|
@@ -833,7 +826,7 @@ export default {
|
|
|
833
826
|
}]
|
|
834
827
|
}
|
|
835
828
|
|
|
836
|
-
costChartInstance = new Chart(
|
|
829
|
+
costChartInstance = new Chart(ctx2d, {
|
|
837
830
|
type: chartTypeValue,
|
|
838
831
|
data: chartDataWithColors,
|
|
839
832
|
options: {
|
|
@@ -859,14 +852,14 @@ export default {
|
|
|
859
852
|
},
|
|
860
853
|
tooltip: {
|
|
861
854
|
callbacks: {
|
|
862
|
-
title: function(context) {
|
|
855
|
+
title: function (context) {
|
|
863
856
|
const index = context[0].dataIndex
|
|
864
857
|
const dateKey = chartData.value.dateKeys[index]
|
|
865
858
|
const date = new Date(dateKey + 'T00:00:00Z')
|
|
866
859
|
return date.toLocaleDateString(undefined, { year: 'numeric', month: 'long', day: 'numeric' })
|
|
867
860
|
},
|
|
868
|
-
label: function(context) {
|
|
869
|
-
return `Cost: ${
|
|
861
|
+
label: function (context) {
|
|
862
|
+
return `Cost: ${ctx.fmt.cost(context.parsed.y)}`
|
|
870
863
|
}
|
|
871
864
|
}
|
|
872
865
|
}
|
|
@@ -875,7 +868,7 @@ export default {
|
|
|
875
868
|
y: {
|
|
876
869
|
beginAtZero: true,
|
|
877
870
|
ticks: {
|
|
878
|
-
callback: function(value) {
|
|
871
|
+
callback: function (value) {
|
|
879
872
|
return '$' + value.toFixed(4)
|
|
880
873
|
}
|
|
881
874
|
}
|
|
@@ -893,7 +886,7 @@ export default {
|
|
|
893
886
|
tokenChartInstance.destroy()
|
|
894
887
|
}
|
|
895
888
|
|
|
896
|
-
const
|
|
889
|
+
const ctx2d = tokenChartCanvas.value.getContext('2d')
|
|
897
890
|
|
|
898
891
|
// Find the index of the selected day
|
|
899
892
|
const selectedDayIndex = tokenChartData.value.dateKeys.indexOf(selectedDay.value)
|
|
@@ -944,7 +937,7 @@ export default {
|
|
|
944
937
|
]
|
|
945
938
|
}
|
|
946
939
|
|
|
947
|
-
tokenChartInstance = new Chart(
|
|
940
|
+
tokenChartInstance = new Chart(ctx2d, {
|
|
948
941
|
type: 'bar',
|
|
949
942
|
data: chartDataWithColors,
|
|
950
943
|
options: {
|
|
@@ -972,8 +965,8 @@ export default {
|
|
|
972
965
|
stacked: true,
|
|
973
966
|
beginAtZero: true,
|
|
974
967
|
ticks: {
|
|
975
|
-
callback: function(value) {
|
|
976
|
-
return humanifyNumber(value)
|
|
968
|
+
callback: function (value) {
|
|
969
|
+
return ctx.fmt.humanifyNumber(value)
|
|
977
970
|
}
|
|
978
971
|
}
|
|
979
972
|
}
|
|
@@ -985,14 +978,14 @@ export default {
|
|
|
985
978
|
},
|
|
986
979
|
tooltip: {
|
|
987
980
|
callbacks: {
|
|
988
|
-
title: function(context) {
|
|
981
|
+
title: function (context) {
|
|
989
982
|
const index = context[0].dataIndex
|
|
990
983
|
const dateKey = tokenChartData.value.dateKeys[index]
|
|
991
984
|
const date = new Date(dateKey + 'T00:00:00Z')
|
|
992
985
|
return date.toLocaleDateString(undefined, { year: 'numeric', month: 'long', day: 'numeric' })
|
|
993
986
|
},
|
|
994
|
-
label: function(context) {
|
|
995
|
-
return `${context.dataset.label}: ${humanifyNumber(context.parsed.y)}`
|
|
987
|
+
label: function (context) {
|
|
988
|
+
return `${context.dataset.label}: ${ctx.fmt.humanifyNumber(context.parsed.y)}`
|
|
996
989
|
}
|
|
997
990
|
}
|
|
998
991
|
}
|
|
@@ -1009,7 +1002,7 @@ export default {
|
|
|
1009
1002
|
modelPieChartInstance.destroy()
|
|
1010
1003
|
}
|
|
1011
1004
|
|
|
1012
|
-
const
|
|
1005
|
+
const ctx2d = modelPieCanvas.value.getContext('2d')
|
|
1013
1006
|
|
|
1014
1007
|
// Custom plugin to draw percentage labels on pie slices
|
|
1015
1008
|
const percentagePlugin = {
|
|
@@ -1036,7 +1029,7 @@ export default {
|
|
|
1036
1029
|
}
|
|
1037
1030
|
}
|
|
1038
1031
|
|
|
1039
|
-
modelPieChartInstance = new Chart(
|
|
1032
|
+
modelPieChartInstance = new Chart(ctx2d, {
|
|
1040
1033
|
type: 'pie',
|
|
1041
1034
|
data: modelPieData.value,
|
|
1042
1035
|
options: {
|
|
@@ -1049,8 +1042,8 @@ export default {
|
|
|
1049
1042
|
},
|
|
1050
1043
|
tooltip: {
|
|
1051
1044
|
callbacks: {
|
|
1052
|
-
label: function(context) {
|
|
1053
|
-
return `${context.label}: ${
|
|
1045
|
+
label: function (context) {
|
|
1046
|
+
return `${context.label}: ${ctx.fmt.cost(context.parsed)}`
|
|
1054
1047
|
}
|
|
1055
1048
|
}
|
|
1056
1049
|
}
|
|
@@ -1068,7 +1061,7 @@ export default {
|
|
|
1068
1061
|
providerPieChartInstance.destroy()
|
|
1069
1062
|
}
|
|
1070
1063
|
|
|
1071
|
-
const
|
|
1064
|
+
const ctx2d = providerPieCanvas.value.getContext('2d')
|
|
1072
1065
|
|
|
1073
1066
|
// Custom plugin to draw percentage labels on pie slices
|
|
1074
1067
|
const percentagePlugin = {
|
|
@@ -1095,7 +1088,7 @@ export default {
|
|
|
1095
1088
|
}
|
|
1096
1089
|
}
|
|
1097
1090
|
|
|
1098
|
-
providerPieChartInstance = new Chart(
|
|
1091
|
+
providerPieChartInstance = new Chart(ctx2d, {
|
|
1099
1092
|
type: 'pie',
|
|
1100
1093
|
data: providerPieData.value,
|
|
1101
1094
|
options: {
|
|
@@ -1108,8 +1101,8 @@ export default {
|
|
|
1108
1101
|
},
|
|
1109
1102
|
tooltip: {
|
|
1110
1103
|
callbacks: {
|
|
1111
|
-
label: function(context) {
|
|
1112
|
-
return `${context.label}: ${
|
|
1104
|
+
label: function (context) {
|
|
1105
|
+
return `${context.label}: ${ctx.fmt.cost(context.parsed)}`
|
|
1113
1106
|
}
|
|
1114
1107
|
}
|
|
1115
1108
|
}
|
|
@@ -1127,7 +1120,7 @@ export default {
|
|
|
1127
1120
|
tokenModelPieChartInstance.destroy()
|
|
1128
1121
|
}
|
|
1129
1122
|
|
|
1130
|
-
const
|
|
1123
|
+
const ctx2d = tokenModelPieCanvas.value.getContext('2d')
|
|
1131
1124
|
|
|
1132
1125
|
// Custom plugin to draw percentage labels on pie slices
|
|
1133
1126
|
const percentagePlugin = {
|
|
@@ -1154,7 +1147,7 @@ export default {
|
|
|
1154
1147
|
}
|
|
1155
1148
|
}
|
|
1156
1149
|
|
|
1157
|
-
tokenModelPieChartInstance = new Chart(
|
|
1150
|
+
tokenModelPieChartInstance = new Chart(ctx2d, {
|
|
1158
1151
|
type: 'pie',
|
|
1159
1152
|
data: tokenModelPieData.value,
|
|
1160
1153
|
options: {
|
|
@@ -1167,8 +1160,8 @@ export default {
|
|
|
1167
1160
|
},
|
|
1168
1161
|
tooltip: {
|
|
1169
1162
|
callbacks: {
|
|
1170
|
-
label: function(context) {
|
|
1171
|
-
return `${context.label}: ${humanifyNumber(context.parsed)}`
|
|
1163
|
+
label: function (context) {
|
|
1164
|
+
return `${context.label}: ${ctx.fmt.humanifyNumber(context.parsed)}`
|
|
1172
1165
|
}
|
|
1173
1166
|
}
|
|
1174
1167
|
}
|
|
@@ -1186,7 +1179,7 @@ export default {
|
|
|
1186
1179
|
tokenProviderPieChartInstance.destroy()
|
|
1187
1180
|
}
|
|
1188
1181
|
|
|
1189
|
-
const
|
|
1182
|
+
const ctx2d = tokenProviderPieCanvas.value.getContext('2d')
|
|
1190
1183
|
|
|
1191
1184
|
// Custom plugin to draw percentage labels on pie slices
|
|
1192
1185
|
const percentagePlugin = {
|
|
@@ -1213,7 +1206,7 @@ export default {
|
|
|
1213
1206
|
}
|
|
1214
1207
|
}
|
|
1215
1208
|
|
|
1216
|
-
tokenProviderPieChartInstance = new Chart(
|
|
1209
|
+
tokenProviderPieChartInstance = new Chart(ctx2d, {
|
|
1217
1210
|
type: 'pie',
|
|
1218
1211
|
data: tokenProviderPieData.value,
|
|
1219
1212
|
options: {
|
|
@@ -1226,8 +1219,8 @@ export default {
|
|
|
1226
1219
|
},
|
|
1227
1220
|
tooltip: {
|
|
1228
1221
|
callbacks: {
|
|
1229
|
-
label: function(context) {
|
|
1230
|
-
return `${context.label}: ${humanifyNumber(context.parsed)}`
|
|
1222
|
+
label: function (context) {
|
|
1223
|
+
return `${context.label}: ${ctx.fmt.humanifyNumber(context.parsed)}`
|
|
1231
1224
|
}
|
|
1232
1225
|
}
|
|
1233
1226
|
}
|
|
@@ -1339,9 +1332,9 @@ export default {
|
|
|
1339
1332
|
|
|
1340
1333
|
const formatActivityDate = (timestamp) => {
|
|
1341
1334
|
const date = new Date(timestamp * 1000)
|
|
1342
|
-
return date.toLocaleTimeString(undefined, { hour12: false }) + ' '
|
|
1343
|
-
+ date.toLocaleDateString(undefined, { year: 'numeric', month: 'long', day: 'numeric' })
|
|
1344
|
-
|
|
1335
|
+
return date.toLocaleTimeString(undefined, { hour12: false }) + ' '
|
|
1336
|
+
+ date.toLocaleDateString(undefined, { year: 'numeric', month: 'long', day: 'numeric' })
|
|
1337
|
+
|
|
1345
1338
|
}
|
|
1346
1339
|
|
|
1347
1340
|
const openThread = (threadId) => {
|
|
@@ -1497,9 +1490,6 @@ export default {
|
|
|
1497
1490
|
totalRequests,
|
|
1498
1491
|
totalInputTokens,
|
|
1499
1492
|
totalOutputTokens,
|
|
1500
|
-
formatCost,
|
|
1501
|
-
humanifyNumber,
|
|
1502
|
-
humanifyMs,
|
|
1503
1493
|
// Month/Year selection
|
|
1504
1494
|
selectedMonth,
|
|
1505
1495
|
selectedYear,
|
|
@@ -1526,3 +1516,25 @@ export default {
|
|
|
1526
1516
|
}
|
|
1527
1517
|
}
|
|
1528
1518
|
}
|
|
1519
|
+
|
|
1520
|
+
export default {
|
|
1521
|
+
install(ctx) {
|
|
1522
|
+
ctx.components({
|
|
1523
|
+
MonthSelector,
|
|
1524
|
+
Analytics,
|
|
1525
|
+
})
|
|
1526
|
+
|
|
1527
|
+
ctx.setLeftIcons({
|
|
1528
|
+
analytics: {
|
|
1529
|
+
component: {
|
|
1530
|
+
template: `<svg @click="$ctx.togglePath('/analytics')" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="currentColor" d="M5 22a1 1 0 0 1-1-1v-8a1 1 0 0 1 2 0v8a1 1 0 0 1-1 1m5 0a1 1 0 0 1-1-1V3a1 1 0 0 1 2 0v18a1 1 0 0 1-1 1m5 0a1 1 0 0 1-1-1V9a1 1 0 0 1 2 0v12a1 1 0 0 1-1 1m5 0a1 1 0 0 1-1-1v-4a1 1 0 0 1 2 0v4a1 1 0 0 1-1 1"/></svg>`
|
|
1531
|
+
},
|
|
1532
|
+
isActive({ path }) {
|
|
1533
|
+
return path === '/analytics'
|
|
1534
|
+
}
|
|
1535
|
+
}
|
|
1536
|
+
})
|
|
1537
|
+
|
|
1538
|
+
ctx.routes.push({ path: '/analytics', component: Analytics, meta: { title: 'Analytics' } })
|
|
1539
|
+
}
|
|
1540
|
+
}
|