llms-py 3.0.0__py3-none-any.whl → 3.0.0b1__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/index.html +77 -35
- llms/llms.json +23 -72
- llms/main.py +732 -1786
- llms/providers.json +1 -1
- llms/{extensions/analytics/ui/index.mjs → ui/Analytics.mjs} +238 -154
- llms/ui/App.mjs +60 -151
- llms/ui/Avatar.mjs +85 -0
- llms/ui/Brand.mjs +52 -0
- llms/ui/ChatPrompt.mjs +606 -0
- llms/ui/Main.mjs +873 -0
- llms/ui/ModelSelector.mjs +693 -0
- llms/ui/OAuthSignIn.mjs +92 -0
- llms/ui/ProviderIcon.mjs +36 -0
- llms/ui/ProviderStatus.mjs +105 -0
- llms/{extensions/app/ui → ui}/Recents.mjs +65 -91
- llms/ui/{modules/chat/SettingsDialog.mjs → SettingsDialog.mjs} +9 -9
- llms/{extensions/app/ui/index.mjs → ui/Sidebar.mjs} +58 -124
- llms/ui/SignIn.mjs +64 -0
- llms/ui/SystemPromptEditor.mjs +31 -0
- llms/ui/SystemPromptSelector.mjs +56 -0
- llms/ui/Welcome.mjs +8 -0
- llms/ui/ai.mjs +53 -125
- llms/ui/app.css +111 -1837
- llms/ui/lib/charts.mjs +13 -9
- llms/ui/lib/servicestack-vue.mjs +3 -3
- llms/ui/lib/vue.min.mjs +9 -10
- llms/ui/lib/vue.mjs +1602 -1763
- llms/ui/markdown.mjs +2 -10
- llms/ui/tailwind.input.css +80 -496
- llms/ui/threadStore.mjs +572 -0
- llms/ui/utils.mjs +117 -113
- llms/ui.json +1069 -0
- {llms_py-3.0.0.dist-info → llms_py-3.0.0b1.dist-info}/METADATA +1 -1
- llms_py-3.0.0b1.dist-info/RECORD +49 -0
- llms/__pycache__/__init__.cpython-312.pyc +0 -0
- llms/__pycache__/__init__.cpython-313.pyc +0 -0
- llms/__pycache__/__init__.cpython-314.pyc +0 -0
- llms/__pycache__/__main__.cpython-312.pyc +0 -0
- llms/__pycache__/__main__.cpython-314.pyc +0 -0
- llms/__pycache__/llms.cpython-312.pyc +0 -0
- llms/__pycache__/main.cpython-312.pyc +0 -0
- llms/__pycache__/main.cpython-313.pyc +0 -0
- llms/__pycache__/main.cpython-314.pyc +0 -0
- llms/__pycache__/plugins.cpython-314.pyc +0 -0
- llms/extensions/app/README.md +0 -20
- llms/extensions/app/__init__.py +0 -530
- 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 +0 -644
- llms/extensions/app/db_manager.py +0 -195
- llms/extensions/app/requests.json +0 -9073
- llms/extensions/app/threads.json +0 -15290
- llms/extensions/app/ui/threadStore.mjs +0 -411
- llms/extensions/core_tools/CALCULATOR.md +0 -32
- llms/extensions/core_tools/__init__.py +0 -598
- llms/extensions/core_tools/__pycache__/__init__.cpython-314.pyc +0 -0
- llms/extensions/core_tools/ui/codemirror/addon/edit/closebrackets.js +0 -201
- llms/extensions/core_tools/ui/codemirror/addon/edit/closetag.js +0 -185
- llms/extensions/core_tools/ui/codemirror/addon/edit/continuelist.js +0 -101
- llms/extensions/core_tools/ui/codemirror/addon/edit/matchbrackets.js +0 -160
- llms/extensions/core_tools/ui/codemirror/addon/edit/matchtags.js +0 -66
- llms/extensions/core_tools/ui/codemirror/addon/edit/trailingspace.js +0 -27
- llms/extensions/core_tools/ui/codemirror/addon/selection/active-line.js +0 -72
- llms/extensions/core_tools/ui/codemirror/addon/selection/mark-selection.js +0 -119
- llms/extensions/core_tools/ui/codemirror/addon/selection/selection-pointer.js +0 -98
- llms/extensions/core_tools/ui/codemirror/doc/docs.css +0 -225
- llms/extensions/core_tools/ui/codemirror/doc/source_sans.woff +0 -0
- llms/extensions/core_tools/ui/codemirror/lib/codemirror.css +0 -344
- llms/extensions/core_tools/ui/codemirror/lib/codemirror.js +0 -9884
- llms/extensions/core_tools/ui/codemirror/mode/clike/clike.js +0 -942
- llms/extensions/core_tools/ui/codemirror/mode/javascript/index.html +0 -118
- llms/extensions/core_tools/ui/codemirror/mode/javascript/javascript.js +0 -962
- llms/extensions/core_tools/ui/codemirror/mode/javascript/typescript.html +0 -62
- llms/extensions/core_tools/ui/codemirror/mode/python/python.js +0 -402
- llms/extensions/core_tools/ui/codemirror/theme/dracula.css +0 -40
- llms/extensions/core_tools/ui/codemirror/theme/mocha.css +0 -135
- llms/extensions/core_tools/ui/index.mjs +0 -650
- llms/extensions/gallery/README.md +0 -61
- llms/extensions/gallery/__init__.py +0 -61
- llms/extensions/gallery/__pycache__/__init__.cpython-314.pyc +0 -0
- llms/extensions/gallery/__pycache__/db.cpython-314.pyc +0 -0
- llms/extensions/gallery/db.py +0 -298
- llms/extensions/gallery/ui/index.mjs +0 -482
- llms/extensions/katex/README.md +0 -39
- llms/extensions/katex/__init__.py +0 -6
- llms/extensions/katex/__pycache__/__init__.cpython-314.pyc +0 -0
- llms/extensions/katex/ui/README.md +0 -125
- llms/extensions/katex/ui/contrib/auto-render.js +0 -338
- llms/extensions/katex/ui/contrib/auto-render.min.js +0 -1
- llms/extensions/katex/ui/contrib/auto-render.mjs +0 -244
- llms/extensions/katex/ui/contrib/copy-tex.js +0 -127
- llms/extensions/katex/ui/contrib/copy-tex.min.js +0 -1
- llms/extensions/katex/ui/contrib/copy-tex.mjs +0 -105
- llms/extensions/katex/ui/contrib/mathtex-script-type.js +0 -109
- llms/extensions/katex/ui/contrib/mathtex-script-type.min.js +0 -1
- llms/extensions/katex/ui/contrib/mathtex-script-type.mjs +0 -24
- llms/extensions/katex/ui/contrib/mhchem.js +0 -3213
- llms/extensions/katex/ui/contrib/mhchem.min.js +0 -1
- llms/extensions/katex/ui/contrib/mhchem.mjs +0 -3109
- llms/extensions/katex/ui/contrib/render-a11y-string.js +0 -887
- llms/extensions/katex/ui/contrib/render-a11y-string.min.js +0 -1
- llms/extensions/katex/ui/contrib/render-a11y-string.mjs +0 -800
- 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 +0 -92
- llms/extensions/katex/ui/katex-swap.css +0 -1230
- llms/extensions/katex/ui/katex-swap.min.css +0 -1
- llms/extensions/katex/ui/katex.css +0 -1230
- llms/extensions/katex/ui/katex.js +0 -19080
- llms/extensions/katex/ui/katex.min.css +0 -1
- llms/extensions/katex/ui/katex.min.js +0 -1
- llms/extensions/katex/ui/katex.min.mjs +0 -1
- llms/extensions/katex/ui/katex.mjs +0 -18547
- llms/extensions/providers/__init__.py +0 -18
- llms/extensions/providers/__pycache__/__init__.cpython-314.pyc +0 -0
- llms/extensions/providers/__pycache__/anthropic.cpython-314.pyc +0 -0
- llms/extensions/providers/__pycache__/chutes.cpython-314.pyc +0 -0
- llms/extensions/providers/__pycache__/google.cpython-314.pyc +0 -0
- llms/extensions/providers/__pycache__/nvidia.cpython-314.pyc +0 -0
- llms/extensions/providers/__pycache__/openai.cpython-314.pyc +0 -0
- llms/extensions/providers/__pycache__/openrouter.cpython-314.pyc +0 -0
- llms/extensions/providers/anthropic.py +0 -229
- llms/extensions/providers/chutes.py +0 -155
- llms/extensions/providers/google.py +0 -378
- llms/extensions/providers/nvidia.py +0 -105
- llms/extensions/providers/openai.py +0 -156
- llms/extensions/providers/openrouter.py +0 -72
- llms/extensions/system_prompts/README.md +0 -22
- llms/extensions/system_prompts/__init__.py +0 -45
- llms/extensions/system_prompts/__pycache__/__init__.cpython-314.pyc +0 -0
- llms/extensions/system_prompts/ui/index.mjs +0 -280
- llms/extensions/system_prompts/ui/prompts.json +0 -1067
- llms/extensions/tools/__init__.py +0 -5
- llms/extensions/tools/__pycache__/__init__.cpython-314.pyc +0 -0
- llms/extensions/tools/ui/index.mjs +0 -204
- llms/providers-extra.json +0 -356
- llms/ui/ctx.mjs +0 -365
- llms/ui/index.mjs +0 -129
- llms/ui/modules/chat/ChatBody.mjs +0 -691
- llms/ui/modules/chat/index.mjs +0 -828
- llms/ui/modules/layout.mjs +0 -243
- llms/ui/modules/model-selector.mjs +0 -851
- llms_py-3.0.0.dist-info/RECORD +0 -202
- {llms_py-3.0.0.dist-info → llms_py-3.0.0b1.dist-info}/WHEEL +0 -0
- {llms_py-3.0.0.dist-info → llms_py-3.0.0b1.dist-info}/entry_points.txt +0 -0
- {llms_py-3.0.0.dist-info → llms_py-3.0.0b1.dist-info}/licenses/LICENSE +0 -0
- {llms_py-3.0.0.dist-info → llms_py-3.0.0b1.dist-info}/top_level.txt +0 -0
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { onMounted, inject } from 'vue'
|
|
2
2
|
import { useRouter } from 'vue-router'
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
5
|
-
import
|
|
3
|
+
import { useFormatters } from '@servicestack/vue'
|
|
4
|
+
import { useThreadStore } from './threadStore.mjs'
|
|
5
|
+
import Brand from './Brand.mjs'
|
|
6
|
+
import { statsTitle, formatCost } from './utils.mjs'
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
const { humanifyNumber, humanifyMs } = useFormatters()
|
|
8
9
|
|
|
9
10
|
// Thread Item Component
|
|
10
11
|
const ThreadItem = {
|
|
@@ -20,10 +21,10 @@ const ThreadItem = {
|
|
|
20
21
|
{{ thread.title }}
|
|
21
22
|
</div>
|
|
22
23
|
<div class="text-xs text-gray-500 dark:text-gray-400 truncate">
|
|
23
|
-
<span>{{
|
|
24
|
-
<span v-if="thread.stats?.inputTokens" :title="
|
|
25
|
-
• {{
|
|
26
|
-
{{ thread.stats.cost ? ' ' +
|
|
24
|
+
<span>{{ formatRelativeTime(thread.updatedAt) }} • {{ thread.messages.length }} msgs</span>
|
|
25
|
+
<span v-if="thread.stats?.inputTokens" :title="statsTitle(thread.stats)">
|
|
26
|
+
• {{ humanifyNumber(thread.stats.inputTokens + thread.stats.outputTokens) }} toks
|
|
27
|
+
{{ thread.stats.cost ? ' ' + formatCost(thread.stats.cost) : '' }}
|
|
27
28
|
</span>
|
|
28
29
|
</div>
|
|
29
30
|
<div v-if="thread.model" class="text-xs text-blue-600 dark:text-blue-400 truncate">
|
|
@@ -59,12 +60,32 @@ const ThreadItem = {
|
|
|
59
60
|
emits: ['select', 'delete'],
|
|
60
61
|
|
|
61
62
|
setup() {
|
|
63
|
+
const formatRelativeTime = (timestamp) => {
|
|
64
|
+
const now = new Date()
|
|
65
|
+
const date = new Date(timestamp)
|
|
66
|
+
const diffInSeconds = Math.floor((now - date) / 1000)
|
|
67
|
+
|
|
68
|
+
if (diffInSeconds < 60) return 'Just now'
|
|
69
|
+
if (diffInSeconds < 3600) return `${Math.floor(diffInSeconds / 60)}m ago`
|
|
70
|
+
if (diffInSeconds < 86400) return `${Math.floor(diffInSeconds / 3600)}h ago`
|
|
71
|
+
if (diffInSeconds < 604800) return `${Math.floor(diffInSeconds / 86400)}d ago`
|
|
72
|
+
|
|
73
|
+
return date.toLocaleDateString()
|
|
74
|
+
}
|
|
75
|
+
|
|
62
76
|
return {
|
|
77
|
+
formatRelativeTime,
|
|
78
|
+
humanifyNumber,
|
|
79
|
+
statsTitle,
|
|
80
|
+
formatCost,
|
|
63
81
|
}
|
|
64
82
|
}
|
|
65
83
|
}
|
|
66
84
|
|
|
67
85
|
const GroupedThreads = {
|
|
86
|
+
components: {
|
|
87
|
+
ThreadItem,
|
|
88
|
+
},
|
|
68
89
|
template: `
|
|
69
90
|
<!-- Today -->
|
|
70
91
|
<div v-if="groupedThreads.today.length > 0" class="mb-4">
|
|
@@ -73,20 +94,7 @@ const GroupedThreads = {
|
|
|
73
94
|
v-for="thread in groupedThreads.today"
|
|
74
95
|
:key="thread.id"
|
|
75
96
|
:thread="thread"
|
|
76
|
-
:is-active="currentThread?.id
|
|
77
|
-
@select="$emit('select', $event)"
|
|
78
|
-
@delete="$emit('delete', $event)"
|
|
79
|
-
/>
|
|
80
|
-
</div>
|
|
81
|
-
|
|
82
|
-
<!-- Yesterday -->
|
|
83
|
-
<div v-if="groupedThreads.yesterday.length > 0" class="mb-4">
|
|
84
|
-
<h3 class="px-4 py-2 text-xs font-semibold text-gray-500 dark:text-gray-400 uppercase tracking-wider select-none">Yesterday</h3>
|
|
85
|
-
<ThreadItem
|
|
86
|
-
v-for="thread in groupedThreads.yesterday"
|
|
87
|
-
:key="thread.id"
|
|
88
|
-
:thread="thread"
|
|
89
|
-
:is-active="currentThread?.id == thread.id"
|
|
97
|
+
:is-active="currentThread?.id === thread.id"
|
|
90
98
|
@select="$emit('select', $event)"
|
|
91
99
|
@delete="$emit('delete', $event)"
|
|
92
100
|
/>
|
|
@@ -99,7 +107,7 @@ const GroupedThreads = {
|
|
|
99
107
|
v-for="thread in groupedThreads.lastWeek"
|
|
100
108
|
:key="thread.id"
|
|
101
109
|
:thread="thread"
|
|
102
|
-
:is-active="currentThread?.id
|
|
110
|
+
:is-active="currentThread?.id === thread.id"
|
|
103
111
|
@select="$emit('select', $event)"
|
|
104
112
|
@delete="$emit('delete', $event)"
|
|
105
113
|
/>
|
|
@@ -112,7 +120,7 @@ const GroupedThreads = {
|
|
|
112
120
|
v-for="thread in groupedThreads.lastMonth"
|
|
113
121
|
:key="thread.id"
|
|
114
122
|
:thread="thread"
|
|
115
|
-
:is-active="currentThread?.id
|
|
123
|
+
:is-active="currentThread?.id === thread.id"
|
|
116
124
|
@select="$emit('select', $event)"
|
|
117
125
|
@delete="$emit('delete', $event)"
|
|
118
126
|
/>
|
|
@@ -125,7 +133,7 @@ const GroupedThreads = {
|
|
|
125
133
|
v-for="thread in monthThreads"
|
|
126
134
|
:key="thread.id"
|
|
127
135
|
:thread="thread"
|
|
128
|
-
:is-active="currentThread?.id
|
|
136
|
+
:is-active="currentThread?.id === thread.id"
|
|
129
137
|
@select="$emit('select', $event)"
|
|
130
138
|
@delete="$emit('delete', $event)"
|
|
131
139
|
/>
|
|
@@ -148,10 +156,15 @@ const GroupedThreads = {
|
|
|
148
156
|
emits: ['select', 'delete'],
|
|
149
157
|
}
|
|
150
158
|
|
|
151
|
-
const
|
|
159
|
+
const Sidebar = {
|
|
160
|
+
components: {
|
|
161
|
+
Brand,
|
|
162
|
+
GroupedThreads,
|
|
163
|
+
ThreadItem,
|
|
164
|
+
},
|
|
152
165
|
template: `
|
|
153
|
-
<div class="flex flex-col h-full">
|
|
154
|
-
<Brand />
|
|
166
|
+
<div class="flex flex-col h-full bg-gray-50 dark:bg-gray-800 border-r border-gray-200 dark:border-gray-700">
|
|
167
|
+
<Brand @home="goToInitialState" @new="createNewThread" @analytics="goToAnalytics" @toggle-sidebar="$emit('toggle-sidebar')" />
|
|
155
168
|
<!-- Thread List -->
|
|
156
169
|
<div class="flex-1 overflow-y-auto">
|
|
157
170
|
<div v-if="isLoading" class="p-4 text-center text-gray-500 dark:text-gray-400">
|
|
@@ -167,28 +180,18 @@ const ThreadsSidebar = {
|
|
|
167
180
|
<p class="text-xs text-gray-400 dark:text-gray-500 mt-1">Start a new chat to begin</p>
|
|
168
181
|
</div>
|
|
169
182
|
|
|
170
|
-
<div v-else class="
|
|
171
|
-
|
|
172
|
-
<div class="flex items-center space-x-2 absolute top-2 right-2">
|
|
173
|
-
<button type="button"
|
|
174
|
-
@click="createNewThread"
|
|
175
|
-
class="text-gray-900 dark:text-gray-200 hover:text-blue-600 dark:hover:text-blue-400 focus:outline-none transition-colors"
|
|
176
|
-
title="New Chat"
|
|
177
|
-
>
|
|
178
|
-
<svg class="size-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"><path d="M12 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/><path d="M18.375 2.625a1 1 0 0 1 3 3l-9.013 9.014a2 2 0 0 1-.853.505l-2.873.84a.5.5 0 0 1-.62-.62l.84-2.873a2 2 0 0 1 .506-.852z"/></g></svg>
|
|
179
|
-
</button>
|
|
180
|
-
</div>
|
|
181
|
-
|
|
182
|
-
<GroupedThreads :currentThread="currentThread" :groupedThreads="$threads.getGroupedThreads(50)"
|
|
183
|
+
<div v-else class="py-2">
|
|
184
|
+
<GroupedThreads :currentThread="currentThread" :groupedThreads="threadStore.getGroupedThreads(18)"
|
|
183
185
|
@select="selectThread" @delete="deleteThread" />
|
|
184
186
|
</div>
|
|
185
187
|
</div>
|
|
186
188
|
</div>
|
|
187
189
|
`,
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
const ai =
|
|
190
|
+
emits: ['thread-selected', 'toggle-sidebar'],
|
|
191
|
+
setup(props, { emit }) {
|
|
192
|
+
const ai = inject('ai')
|
|
191
193
|
const router = useRouter()
|
|
194
|
+
const threadStore = useThreadStore()
|
|
192
195
|
const {
|
|
193
196
|
threads,
|
|
194
197
|
currentThread,
|
|
@@ -198,7 +201,7 @@ const ThreadsSidebar = {
|
|
|
198
201
|
createThread,
|
|
199
202
|
deleteThread: deleteThreadFromStore,
|
|
200
203
|
clearCurrentThread
|
|
201
|
-
} =
|
|
204
|
+
} = threadStore
|
|
202
205
|
|
|
203
206
|
onMounted(async () => {
|
|
204
207
|
await loadThreads()
|
|
@@ -206,6 +209,7 @@ const ThreadsSidebar = {
|
|
|
206
209
|
|
|
207
210
|
const selectThread = async (threadId) => {
|
|
208
211
|
router.push(`${ai.base}/c/${threadId}`)
|
|
212
|
+
emit('thread-selected')
|
|
209
213
|
}
|
|
210
214
|
|
|
211
215
|
const deleteThread = async (threadId) => {
|
|
@@ -219,19 +223,24 @@ const ThreadsSidebar = {
|
|
|
219
223
|
}
|
|
220
224
|
|
|
221
225
|
const createNewThread = async () => {
|
|
222
|
-
|
|
226
|
+
const newThread = await createThread()
|
|
227
|
+
router.push(`${ai.base}/c/${newThread.id}`)
|
|
228
|
+
emit('thread-selected')
|
|
223
229
|
}
|
|
224
230
|
|
|
225
231
|
const goToInitialState = () => {
|
|
226
232
|
clearCurrentThread()
|
|
227
|
-
|
|
233
|
+
router.push(`${ai.base}/`)
|
|
234
|
+
emit('thread-selected')
|
|
228
235
|
}
|
|
229
236
|
|
|
230
237
|
const goToAnalytics = () => {
|
|
231
|
-
|
|
238
|
+
router.push(`${ai.base}/analytics`)
|
|
239
|
+
emit('thread-selected')
|
|
232
240
|
}
|
|
233
241
|
|
|
234
242
|
return {
|
|
243
|
+
threadStore,
|
|
235
244
|
threads,
|
|
236
245
|
currentThread,
|
|
237
246
|
isLoading,
|
|
@@ -245,79 +254,4 @@ const ThreadsSidebar = {
|
|
|
245
254
|
}
|
|
246
255
|
}
|
|
247
256
|
|
|
248
|
-
|
|
249
|
-
async function query(query) {
|
|
250
|
-
return (await ext.getJson(appendQueryString(`/requests`, query))).response || []
|
|
251
|
-
}
|
|
252
|
-
async function deleteById(requestId) {
|
|
253
|
-
if (!requestId) {
|
|
254
|
-
throw new Error('Request ID is required')
|
|
255
|
-
}
|
|
256
|
-
return await ext.deleteJson(`/requests/${requestId}`)
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
async function getThreadIds(query) {
|
|
260
|
-
return (await ext.getJson(appendQueryString(`/requests?fields=threadId¬_null=threadId&as=column&take=10000`, query))).response || []
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
async function getSummary() {
|
|
264
|
-
return (await ext.getJson(`/requests/summary`)).response
|
|
265
|
-
}
|
|
266
|
-
async function getDailySummary(day) {
|
|
267
|
-
return (await ext.getJson(`/requests/summary/${day}`)).response
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
// Get unique values for filter options
|
|
271
|
-
async function getFilterOptions() {
|
|
272
|
-
const results = await query({
|
|
273
|
-
select: 'distinct',
|
|
274
|
-
fields: 'model,provider',
|
|
275
|
-
not_null: 'model,provider',
|
|
276
|
-
})
|
|
277
|
-
|
|
278
|
-
if (results) {
|
|
279
|
-
const models = [...new Set(results.map(r => r.model).filter(m => m))].sort()
|
|
280
|
-
const providers = [...new Set(results.map(r => r.provider).filter(p => p))].sort()
|
|
281
|
-
console.log('getFilterOptions', models, providers)
|
|
282
|
-
return {
|
|
283
|
-
models,
|
|
284
|
-
providers
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
return {
|
|
290
|
-
query,
|
|
291
|
-
deleteById,
|
|
292
|
-
getThreadIds,
|
|
293
|
-
getSummary,
|
|
294
|
-
getDailySummary,
|
|
295
|
-
getFilterOptions,
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
export default {
|
|
300
|
-
order: -100,
|
|
301
|
-
|
|
302
|
-
install(ctx) {
|
|
303
|
-
ext = ctx.scope('app')
|
|
304
|
-
ctx.components({
|
|
305
|
-
ThreadsSidebar,
|
|
306
|
-
ThreadItem,
|
|
307
|
-
GroupedThreads,
|
|
308
|
-
Recents,
|
|
309
|
-
})
|
|
310
|
-
ctx.routes.push(...[
|
|
311
|
-
{ path: '/recents', component: Recents },
|
|
312
|
-
])
|
|
313
|
-
ThreadStore.install(ctx)
|
|
314
|
-
|
|
315
|
-
ctx.setGlobals({
|
|
316
|
-
requests: useRequests(ext)
|
|
317
|
-
})
|
|
318
|
-
|
|
319
|
-
ctx.setLayout({
|
|
320
|
-
left: 'ThreadsSidebar',
|
|
321
|
-
})
|
|
322
|
-
}
|
|
323
|
-
}
|
|
257
|
+
export default Sidebar
|
llms/ui/SignIn.mjs
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { inject, ref } from "vue"
|
|
2
|
+
import { toJsonObject } from "./utils.mjs"
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
template: `
|
|
6
|
+
<div class="min-h-full -mt-12 flex flex-col justify-center py-12 sm:px-6 lg:px-8">
|
|
7
|
+
<div class="sm:mx-auto sm:w-full sm:max-w-md">
|
|
8
|
+
<h2 class="mt-6 text-center text-3xl font-extrabold text-gray-900 dark:text-gray-50">
|
|
9
|
+
Sign In
|
|
10
|
+
</h2>
|
|
11
|
+
</div>
|
|
12
|
+
<div class="mt-8 sm:mx-auto sm:w-full sm:max-w-md">
|
|
13
|
+
<ErrorSummary v-if="errorSummary" class="mb-3" :status="errorSummary" />
|
|
14
|
+
<div class="bg-white dark:bg-black py-8 px-4 shadow sm:rounded-lg sm:px-10">
|
|
15
|
+
<form @submit.prevent="submit">
|
|
16
|
+
<div class="flex flex-1 flex-col justify-between">
|
|
17
|
+
<div class="space-y-6">
|
|
18
|
+
<fieldset class="grid grid-cols-12 gap-6">
|
|
19
|
+
<div class="w-full col-span-12">
|
|
20
|
+
<TextInput id="apiKey" name="apiKey" label="API Key" v-model="apiKey" />
|
|
21
|
+
</div>
|
|
22
|
+
</fieldset>
|
|
23
|
+
</div>
|
|
24
|
+
</div>
|
|
25
|
+
<div class="mt-8">
|
|
26
|
+
<PrimaryButton class="w-full">Sign In</PrimaryButton>
|
|
27
|
+
</div>
|
|
28
|
+
</form>
|
|
29
|
+
</div>
|
|
30
|
+
</div>
|
|
31
|
+
</div>
|
|
32
|
+
`,
|
|
33
|
+
emits: ['done'],
|
|
34
|
+
setup(props, { emit }) {
|
|
35
|
+
const ai = inject('ai')
|
|
36
|
+
const apiKey = ref('')
|
|
37
|
+
const errorSummary = ref()
|
|
38
|
+
async function submit() {
|
|
39
|
+
const r = await ai.get('/auth', {
|
|
40
|
+
headers: {
|
|
41
|
+
'Authorization': `Bearer ${apiKey.value}`
|
|
42
|
+
},
|
|
43
|
+
})
|
|
44
|
+
const txt = await r.text()
|
|
45
|
+
const json = toJsonObject(txt)
|
|
46
|
+
// console.log('json', json)
|
|
47
|
+
if (r.ok) {
|
|
48
|
+
json.apiKey = apiKey.value
|
|
49
|
+
emit('done', json)
|
|
50
|
+
} else {
|
|
51
|
+
errorSummary.value = json.responseStatus || {
|
|
52
|
+
errorCode: "Unauthorized",
|
|
53
|
+
message: 'Invalid API Key'
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return {
|
|
59
|
+
apiKey,
|
|
60
|
+
submit,
|
|
61
|
+
errorSummary,
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
template:`
|
|
3
|
+
<div class="border-b border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-800 px-6 py-4">
|
|
4
|
+
<div class="max-w-6xl mx-auto">
|
|
5
|
+
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
|
6
|
+
System Prompt
|
|
7
|
+
<span v-if="selected" class="text-gray-500 dark:text-gray-400 font-normal">
|
|
8
|
+
({{ prompts.find(p => p.id === selected.id)?.name || 'Custom' }})
|
|
9
|
+
</span>
|
|
10
|
+
</label>
|
|
11
|
+
<textarea
|
|
12
|
+
:value="modelValue" @input="$emit('update:modelValue', $event.target.value)"
|
|
13
|
+
placeholder="Enter a system prompt to guide AI's behavior..."
|
|
14
|
+
rows="6"
|
|
15
|
+
class="block w-full resize-vertical rounded-md border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100 px-3 py-2 text-sm placeholder-gray-500 dark:placeholder-gray-400 focus:border-blue-500 focus:outline-none focus:ring-1 focus:ring-blue-500"
|
|
16
|
+
></textarea>
|
|
17
|
+
<div class="mt-2 text-xs text-gray-500 dark:text-gray-400">
|
|
18
|
+
You can modify this system prompt before sending messages. Changes will only apply to new conversations.
|
|
19
|
+
</div>
|
|
20
|
+
</div>
|
|
21
|
+
</div>
|
|
22
|
+
`,
|
|
23
|
+
emits: ['update:modelValue'],
|
|
24
|
+
props: {
|
|
25
|
+
prompts: Array,
|
|
26
|
+
selected: Object,
|
|
27
|
+
modelValue: String,
|
|
28
|
+
},
|
|
29
|
+
setup() {
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { ref, onMounted, onUnmounted } from "vue"
|
|
2
|
+
export default {
|
|
3
|
+
template:`
|
|
4
|
+
<button v-if="modelValue" type="button" title="Clear System Prompt" @click="$emit('update:modelValue', null)">
|
|
5
|
+
<svg class="size-4 text-gray-500 dark:text-gray-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="currentColor" d="M19 6.41L17.59 5L12 10.59L6.41 5L5 6.41L10.59 12L5 17.59L6.41 19L12 13.41L17.59 19L19 17.59L13.41 12z"/></svg>
|
|
6
|
+
</button>
|
|
7
|
+
|
|
8
|
+
<Autocomplete ref="refSelector" id="prompt" :options="prompts" label=""
|
|
9
|
+
:modelValue="modelValue" @update:modelValue="$emit('update:modelValue', $event)"
|
|
10
|
+
class="w-68 xl:w-84"
|
|
11
|
+
:match="(x, value) => x.name.toLowerCase().includes(value.toLowerCase())"
|
|
12
|
+
placeholder="Select a System Prompt...">
|
|
13
|
+
<template #item="{ value }">
|
|
14
|
+
<div class="truncate max-w-72" :title="value">{{value}}</div>
|
|
15
|
+
</template>
|
|
16
|
+
</Autocomplete>
|
|
17
|
+
|
|
18
|
+
<!-- Toggle System Prompt Visibility -->
|
|
19
|
+
<button type="button"
|
|
20
|
+
@click="$emit('toggle')"
|
|
21
|
+
:class="show ? 'text-blue-700 dark:text-blue-400' : 'text-gray-600 dark:text-gray-400'"
|
|
22
|
+
class="p-1 rounded-md hover:bg-blue-100 dark:hover:bg-blue-900/30 hover:text-blue-700 dark:hover:text-blue-400 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2"
|
|
23
|
+
:title="show ? 'Hide system prompt' : 'Show system prompt'"
|
|
24
|
+
>
|
|
25
|
+
<svg v-if="!show" class="size-6" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36"><path fill="currentColor" d="M33.62 17.53c-3.37-6.23-9.28-10-15.82-10S5.34 11.3 2 17.53l-.28.47l.26.48c3.37 6.23 9.28 10 15.82 10s12.46-3.72 15.82-10l.26-.48Zm-15.82 8.9C12.17 26.43 7 23.29 4 18c3-5.29 8.17-8.43 13.8-8.43S28.54 12.72 31.59 18c-3.05 5.29-8.17 8.43-13.79 8.43"/><path fill="currentColor" d="M18.09 11.17A6.86 6.86 0 1 0 25 18a6.86 6.86 0 0 0-6.91-6.83m0 11.72A4.86 4.86 0 1 1 23 18a4.87 4.87 0 0 1-4.91 4.89"/><path fill="none" d="M0 0h36v36H0z"/></svg>
|
|
26
|
+
<svg v-else class="size-6" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36"><path fill="currentColor" d="M25.19 20.4a6.8 6.8 0 0 0 .43-2.4a6.86 6.86 0 0 0-6.86-6.86a6.8 6.8 0 0 0-2.37.43L18 13.23a5 5 0 0 1 .74-.06A4.87 4.87 0 0 1 23.62 18a5 5 0 0 1-.06.74Z" class="clr-i-outline clr-i-outline-path-1"/><path fill="currentColor" d="M34.29 17.53c-3.37-6.23-9.28-10-15.82-10a16.8 16.8 0 0 0-5.24.85L14.84 10a14.8 14.8 0 0 1 3.63-.47c5.63 0 10.75 3.14 13.8 8.43a17.8 17.8 0 0 1-4.37 5.1l1.42 1.42a19.9 19.9 0 0 0 5-6l.26-.48Z"/><path fill="currentColor" d="m4.87 5.78l4.46 4.46a19.5 19.5 0 0 0-6.69 7.29l-.26.47l.26.48c3.37 6.23 9.28 10 15.82 10a16.9 16.9 0 0 0 7.37-1.69l5 5l1.75-1.5l-26-26Zm9.75 9.75l6.65 6.65a4.8 4.8 0 0 1-2.5.72A4.87 4.87 0 0 1 13.9 18a4.8 4.8 0 0 1 .72-2.47m-1.45-1.45a6.85 6.85 0 0 0 9.55 9.55l1.6 1.6a14.9 14.9 0 0 1-5.86 1.2c-5.63 0-10.75-3.14-13.8-8.43a17.3 17.3 0 0 1 6.12-6.3Z"/><path fill="none" d="M0 0h36v36H0z"/></svg>
|
|
27
|
+
</button>
|
|
28
|
+
`,
|
|
29
|
+
emits: ['updated', 'update:modelValue', 'toggle'],
|
|
30
|
+
props: {
|
|
31
|
+
prompts: Array,
|
|
32
|
+
modelValue: Object,
|
|
33
|
+
show: Boolean,
|
|
34
|
+
},
|
|
35
|
+
setup() {
|
|
36
|
+
const refSelector = ref()
|
|
37
|
+
|
|
38
|
+
function collapse(e) {
|
|
39
|
+
// call toggle when clicking outside of the Autocomplete component
|
|
40
|
+
if (refSelector.value && !refSelector.value.$el.contains(e.target)) {
|
|
41
|
+
refSelector.value.toggle(false)
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
onMounted(() => {
|
|
46
|
+
document.addEventListener('click', collapse)
|
|
47
|
+
})
|
|
48
|
+
onUnmounted(() => {
|
|
49
|
+
document.removeEventListener('click', collapse)
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
refSelector,
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
llms/ui/Welcome.mjs
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
template: `
|
|
3
|
+
<div class="mb-2 flex justify-center">
|
|
4
|
+
<svg class="size-20 text-gray-700 dark:text-gray-300" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill="currentColor" d="M8 2.19c3.13 0 5.68 2.25 5.68 5s-2.55 5-5.68 5a5.7 5.7 0 0 1-1.89-.29l-.75-.26l-.56.56a14 14 0 0 1-2 1.55a.13.13 0 0 1-.07 0v-.06a6.58 6.58 0 0 0 .15-4.29a5.25 5.25 0 0 1-.55-2.16c0-2.77 2.55-5 5.68-5M8 .94c-3.83 0-6.93 2.81-6.93 6.27a6.4 6.4 0 0 0 .64 2.64a5.53 5.53 0 0 1-.18 3.48a1.32 1.32 0 0 0 2 1.5a15 15 0 0 0 2.16-1.71a6.8 6.8 0 0 0 2.31.36c3.83 0 6.93-2.81 6.93-6.27S11.83.94 8 .94"/><ellipse cx="5.2" cy="7.7" fill="currentColor" rx=".8" ry=".75"/><ellipse cx="8" cy="7.7" fill="currentColor" rx=".8" ry=".75"/><ellipse cx="10.8" cy="7.7" fill="currentColor" rx=".8" ry=".75"/></svg>
|
|
5
|
+
</div>
|
|
6
|
+
<h2 class="text-2xl font-semibold text-gray-900 dark:text-gray-100 mb-2">{{ $ai.welcome }}</h2>
|
|
7
|
+
`
|
|
8
|
+
}
|