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,88 +1,9 @@
|
|
|
1
|
-
import { ref, computed, nextTick, watch, onMounted,
|
|
1
|
+
import { ref, computed, nextTick, watch, onMounted, onUnmounted, inject } from 'vue'
|
|
2
2
|
import { useRouter, useRoute } from 'vue-router'
|
|
3
|
-
import { useFormatters } from '@servicestack/vue'
|
|
4
|
-
import { useThreadStore } from './threadStore.mjs'
|
|
5
|
-
import { addCopyButtons, formatCost, statsTitle, fetchCacheInfos } from './utils.mjs'
|
|
6
|
-
import { renderMarkdown } from './markdown.mjs'
|
|
7
|
-
import ChatPrompt, { useChatPrompt } from './ChatPrompt.mjs'
|
|
8
|
-
import SignIn from './SignIn.mjs'
|
|
9
|
-
import OAuthSignIn from './OAuthSignIn.mjs'
|
|
10
|
-
import Avatar from './Avatar.mjs'
|
|
11
|
-
import { useSettings } from "./SettingsDialog.mjs"
|
|
12
|
-
import Welcome from './Welcome.mjs'
|
|
13
|
-
|
|
14
|
-
const { humanifyMs, humanifyNumber } = useFormatters()
|
|
15
|
-
|
|
16
|
-
const TopBar = {
|
|
17
|
-
template: `
|
|
18
|
-
<div class="flex space-x-2">
|
|
19
|
-
<div v-for="(ext, index) in extensions" :key="ext.id" class="relative flex items-center justify-center">
|
|
20
|
-
<component :is="ext.topBarIcon"
|
|
21
|
-
class="size-7 p-1 cursor-pointer text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300 block"
|
|
22
|
-
:class="{ 'bg-gray-100 dark:bg-gray-800 border border-gray-300 dark:border-gray-600 rounded' : ext.isActive($layout.top) }"
|
|
23
|
-
@mouseenter="tooltip = ext.name"
|
|
24
|
-
@mouseleave="tooltip = ''"
|
|
25
|
-
/>
|
|
26
|
-
<div v-if="tooltip === ext.name"
|
|
27
|
-
class="absolute top-full mt-2 px-2 py-1 text-xs text-white bg-gray-900 dark:bg-gray-800 rounded shadow-md z-50 whitespace-nowrap pointer-events-none"
|
|
28
|
-
:class="index <= extensions.length - 1 ? 'right-0' : 'left-1/2 -translate-x-1/2'">
|
|
29
|
-
{{ext.name}}
|
|
30
|
-
</div>
|
|
31
|
-
</div>
|
|
32
|
-
</div>
|
|
33
|
-
`,
|
|
34
|
-
setup() {
|
|
35
|
-
const ctx = inject('ctx')
|
|
36
|
-
const tooltip = ref('')
|
|
37
|
-
const extensions = computed(() => ctx.extensions.filter(x => x.topBarIcon))
|
|
38
|
-
return {
|
|
39
|
-
extensions,
|
|
40
|
-
tooltip,
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
const TopPanel = {
|
|
46
|
-
template: `
|
|
47
|
-
<component v-if="component" :is="component" />
|
|
48
|
-
`,
|
|
49
|
-
setup() {
|
|
50
|
-
const ctx = inject('ctx')
|
|
51
|
-
const component = computed(() => ctx.component(ctx.layout.top))
|
|
52
|
-
return {
|
|
53
|
-
component,
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
3
|
|
|
58
4
|
export default {
|
|
59
|
-
components: {
|
|
60
|
-
TopBar,
|
|
61
|
-
TopPanel,
|
|
62
|
-
ChatPrompt,
|
|
63
|
-
SignIn,
|
|
64
|
-
OAuthSignIn,
|
|
65
|
-
Avatar,
|
|
66
|
-
Welcome,
|
|
67
|
-
},
|
|
68
5
|
template: `
|
|
69
|
-
<div class="flex flex-col h-full
|
|
70
|
-
<!-- Header with model selectors -->
|
|
71
|
-
<div v-if="$ai.hasAccess"
|
|
72
|
-
:class="!$ai.isSidebarOpen ? 'pl-6' : ''"
|
|
73
|
-
class="flex items-center border-b border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800 px-2 w-full min-h-16">
|
|
74
|
-
<div class="flex flex-wrap items-center justify-between w-full">
|
|
75
|
-
<ModelSelector :models="models" v-model="selectedModel" @updated="configUpdated" />
|
|
76
|
-
|
|
77
|
-
<div class="flex items-center space-x-2 pl-4">
|
|
78
|
-
<TopBar />
|
|
79
|
-
<Avatar />
|
|
80
|
-
</div>
|
|
81
|
-
</div>
|
|
82
|
-
</div>
|
|
83
|
-
|
|
84
|
-
<TopPanel />
|
|
85
|
-
|
|
6
|
+
<div class="flex flex-col h-full">
|
|
86
7
|
<!-- Messages Area -->
|
|
87
8
|
<div class="flex-1 overflow-y-auto" ref="messagesContainer">
|
|
88
9
|
<div class="mx-auto max-w-6xl px-4 py-6">
|
|
@@ -149,6 +70,13 @@ export default {
|
|
|
149
70
|
|
|
150
71
|
<!-- Messages -->
|
|
151
72
|
<div v-else class="space-y-6">
|
|
73
|
+
<div v-if="currentThread.messages.length && currentThread.model" class="absolute -mt-2">
|
|
74
|
+
<span @click="$chat.setSelectedModel({ name: currentThread.model})"
|
|
75
|
+
class="flex items-center cursor-pointer px-1.5 py-0.5 text-xs rounded text-gray-600 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800 hover:text-gray-900 dark:hover:text-gray-100 transition-colors border hover:border-gray-300 dark:hover:border-gray-700">
|
|
76
|
+
<ProviderIcon class="size-4 mr-1" :provider="$chat.getProviderForModel(currentThread.model)" />
|
|
77
|
+
{{currentThread.model}}
|
|
78
|
+
</span>
|
|
79
|
+
</div>
|
|
152
80
|
<div
|
|
153
81
|
v-for="message in currentThread.messages"
|
|
154
82
|
:key="message.id"
|
|
@@ -199,7 +127,7 @@ export default {
|
|
|
199
127
|
|
|
200
128
|
<div
|
|
201
129
|
v-if="message.role === 'assistant'"
|
|
202
|
-
v-html="
|
|
130
|
+
v-html="$fmt.markdown(message.content)"
|
|
203
131
|
class="prose prose-sm max-w-none dark:prose-invert"
|
|
204
132
|
></div>
|
|
205
133
|
|
|
@@ -210,14 +138,23 @@ export default {
|
|
|
210
138
|
<span>{{ isReasoningExpanded(message.id) ? 'Hide reasoning' : 'Show reasoning' }}</span>
|
|
211
139
|
</button>
|
|
212
140
|
<div v-if="isReasoningExpanded(message.id)" class="mt-2 rounded border border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-900 p-2">
|
|
213
|
-
<div v-if="typeof message.reasoning === 'string'" v-html="
|
|
141
|
+
<div v-if="typeof message.reasoning === 'string'" v-html="$fmt.markdown(message.reasoning)" class="prose prose-xs max-w-none dark:prose-invert"></div>
|
|
214
142
|
<pre v-else class="text-xs whitespace-pre-wrap overflow-x-auto text-gray-900 dark:text-gray-100">{{ formatReasoning(message.reasoning) }}</pre>
|
|
215
143
|
</div>
|
|
216
144
|
</div>
|
|
217
145
|
|
|
146
|
+
<!-- Assistant Images -->
|
|
147
|
+
<div v-if="message.images && message.images.length > 0" class="mt-2 flex flex-wrap gap-2">
|
|
148
|
+
<template v-for="(img, i) in message.images" :key="i">
|
|
149
|
+
<div v-if="img.type === 'image_url'" class="group relative cursor-pointer" @click="openLightbox(resolveUrl(img.image_url.url))">
|
|
150
|
+
<img :src="resolveUrl(img.image_url.url)" class="max-w-[400px] max-h-96 rounded-lg border border-gray-200 dark:border-gray-700 object-contain bg-gray-50 dark:bg-gray-900 shadow-sm transition-transform hover:scale-[1.02]" />
|
|
151
|
+
</div>
|
|
152
|
+
</template>
|
|
153
|
+
</div>
|
|
154
|
+
|
|
218
155
|
<!-- User Message with separate attachments -->
|
|
219
156
|
<div v-if="message.role !== 'assistant'">
|
|
220
|
-
<div v-html="
|
|
157
|
+
<div v-html="$fmt.markdown(message.content)" class="prose prose-sm max-w-none dark:prose-invert break-words"></div>
|
|
221
158
|
|
|
222
159
|
<!-- Attachments Grid -->
|
|
223
160
|
<div v-if="hasAttachments(message)" class="mt-2 flex flex-wrap gap-2">
|
|
@@ -242,12 +179,12 @@ export default {
|
|
|
242
179
|
</div>
|
|
243
180
|
|
|
244
181
|
<div class="mt-2 text-xs opacity-70">
|
|
245
|
-
<span>{{
|
|
182
|
+
<span>{{ $fmt.time(message.timestamp) }}</span>
|
|
246
183
|
<span v-if="message.usage" :title="tokensTitle(message.usage)">
|
|
247
184
|
•
|
|
248
|
-
{{ humanifyNumber(message.usage.tokens) }} tokens
|
|
185
|
+
{{ $fmt.humanifyNumber(message.usage.tokens) }} tokens
|
|
249
186
|
<span v-if="message.usage.cost">· {{ message.usage.cost }}</span>
|
|
250
|
-
<span v-if="message.usage.duration"> in {{ humanifyMs(message.usage.duration) }}</span>
|
|
187
|
+
<span v-if="message.usage.duration"> in {{ $fmt.humanifyMs(message.usage.duration) }}</span>
|
|
251
188
|
</span>
|
|
252
189
|
</div>
|
|
253
190
|
</div>
|
|
@@ -274,8 +211,8 @@ export default {
|
|
|
274
211
|
</div>
|
|
275
212
|
|
|
276
213
|
<div v-if="currentThread.stats && currentThread.stats.outputTokens" class="text-center text-gray-500 dark:text-gray-400 text-sm">
|
|
277
|
-
<span :title="statsTitle(currentThread.stats)">
|
|
278
|
-
{{ currentThread.stats.cost ?
|
|
214
|
+
<span :title="$fmt.statsTitle(currentThread.stats)">
|
|
215
|
+
{{ currentThread.stats.cost ? $fmt.costLong(currentThread.stats.cost) + ' for ' : '' }} {{ $fmt.humanifyNumber(currentThread.stats.inputTokens) }} → {{ $fmt.humanifyNumber(currentThread.stats.outputTokens) }} tokens over {{ currentThread.stats.requests }} request{{currentThread.stats.requests===1?'':'s'}} in {{ $fmt.humanifyMs(currentThread.stats.duration) }}
|
|
279
216
|
</span>
|
|
280
217
|
</div>
|
|
281
218
|
|
|
@@ -342,20 +279,21 @@ export default {
|
|
|
342
279
|
|
|
343
280
|
<!-- Input Area -->
|
|
344
281
|
<div v-if="$ai.hasAccess" class="flex-shrink-0 border-t border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800 px-6 py-4">
|
|
345
|
-
<ChatPrompt :model="
|
|
282
|
+
<ChatPrompt :model="$chat.getSelectedModel()" />
|
|
346
283
|
</div>
|
|
347
284
|
|
|
348
285
|
<!-- Lightbox -->
|
|
349
|
-
<div v-if="lightboxUrl" class="fixed inset-0 z-[100] bg-black/90 flex items-center justify-center p-4 cursor-pointer"
|
|
286
|
+
<div v-if="lightboxUrl" class="fixed inset-0 z-[100] bg-black/90 flex items-center justify-center p-4 cursor-pointer"
|
|
287
|
+
@click="closeLightbox">
|
|
288
|
+
<button type="button" @click="closeLightbox"
|
|
289
|
+
class="absolute top-4 right-4 text-white/70 hover:text-white p-2 rounded-full hover:bg-white/10 transition-colors z-[101]"
|
|
290
|
+
title="Close">
|
|
291
|
+
<svg class="size-8" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
292
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
|
293
|
+
</svg>
|
|
294
|
+
</button>
|
|
350
295
|
<div class="relative max-w-full max-h-full">
|
|
351
296
|
<img :src="lightboxUrl" class="max-w-full max-h-[90vh] object-contain rounded-sm shadow-2xl" @click.stop />
|
|
352
|
-
<button type="button" @click="closeLightbox"
|
|
353
|
-
class="absolute -top-12 right-0 text-white/70 hover:text-white p-2 rounded-full bg-white/10 hover:bg-white/20 transition-colors"
|
|
354
|
-
title="Close">
|
|
355
|
-
<svg class="size-8" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
356
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
|
357
|
-
</svg>
|
|
358
|
-
</button>
|
|
359
297
|
</div>
|
|
360
298
|
</div>
|
|
361
299
|
</div>
|
|
@@ -364,19 +302,13 @@ export default {
|
|
|
364
302
|
const ctx = inject('ctx')
|
|
365
303
|
const models = ctx.state.models
|
|
366
304
|
const config = ctx.state.config
|
|
305
|
+
const threads = ctx.threads
|
|
306
|
+
const chatPrompt = ctx.chat
|
|
307
|
+
const { currentThread } = threads
|
|
308
|
+
const { errorStatus, isGenerating } = ctx.chat
|
|
309
|
+
|
|
367
310
|
const router = useRouter()
|
|
368
311
|
const route = useRoute()
|
|
369
|
-
const threads = useThreadStore()
|
|
370
|
-
const { currentThread } = threads
|
|
371
|
-
const chatPrompt = useChatPrompt()
|
|
372
|
-
const chatSettings = useSettings()
|
|
373
|
-
const {
|
|
374
|
-
errorStatus,
|
|
375
|
-
isGenerating,
|
|
376
|
-
} = chatPrompt
|
|
377
|
-
provide('threads', threads)
|
|
378
|
-
provide('chatPrompt', chatPrompt)
|
|
379
|
-
provide('chatSettings', chatSettings)
|
|
380
312
|
|
|
381
313
|
const prefs = ctx.getPrefs()
|
|
382
314
|
|
|
@@ -399,6 +331,13 @@ export default {
|
|
|
399
331
|
lightboxUrl.value = null
|
|
400
332
|
}
|
|
401
333
|
|
|
334
|
+
const resolveUrl = (url) => {
|
|
335
|
+
if (url && url.startsWith('~')) {
|
|
336
|
+
return '/' + url
|
|
337
|
+
}
|
|
338
|
+
return ctx.ai.resolveUrl(url)
|
|
339
|
+
}
|
|
340
|
+
|
|
402
341
|
// Auto-scroll to bottom when new messages arrive
|
|
403
342
|
const scrollToBottom = async () => {
|
|
404
343
|
await nextTick()
|
|
@@ -422,7 +361,7 @@ export default {
|
|
|
422
361
|
if (!newId) {
|
|
423
362
|
chatPrompt.reset()
|
|
424
363
|
}
|
|
425
|
-
nextTick(addCopyButtons)
|
|
364
|
+
nextTick(ctx.chat.addCopyButtons)
|
|
426
365
|
}, { immediate: true })
|
|
427
366
|
|
|
428
367
|
watch(() => [selectedModel.value], () => {
|
|
@@ -622,14 +561,6 @@ export default {
|
|
|
622
561
|
}
|
|
623
562
|
}
|
|
624
563
|
|
|
625
|
-
// Format timestamp
|
|
626
|
-
const formatTime = (timestamp) => {
|
|
627
|
-
return new Date(timestamp).toLocaleTimeString([], {
|
|
628
|
-
hour: '2-digit',
|
|
629
|
-
minute: '2-digit'
|
|
630
|
-
})
|
|
631
|
-
}
|
|
632
|
-
|
|
633
564
|
// Reasoning collapse state and helpers
|
|
634
565
|
const expandedReasoning = ref(new Set())
|
|
635
566
|
const isReasoningExpanded = (id) => expandedReasoning.value.has(id)
|
|
@@ -721,7 +652,7 @@ export default {
|
|
|
721
652
|
text = message.content
|
|
722
653
|
}
|
|
723
654
|
|
|
724
|
-
const infos = await fetchCacheInfos(getCacheInfos)
|
|
655
|
+
const infos = await ctx.ai.fetchCacheInfos(getCacheInfos)
|
|
725
656
|
// replace name with info.name
|
|
726
657
|
for (let i = 0; i < files.length; i++) {
|
|
727
658
|
const url = files[i]?.url
|
|
@@ -801,22 +732,20 @@ export default {
|
|
|
801
732
|
let title = []
|
|
802
733
|
if (usage.tokens && usage.price) {
|
|
803
734
|
const msg = parseFloat(usage.price) > 0
|
|
804
|
-
? `${usage.tokens} tokens @ ${usage.price} = ${
|
|
735
|
+
? `${usage.tokens} tokens @ ${usage.price} = ${ctx.fmt.tokenCostLong(usage.price, usage.tokens)}`
|
|
805
736
|
: `${usage.tokens} tokens`
|
|
806
737
|
const duration = usage.duration ? ` in ${usage.duration}ms` : ''
|
|
807
738
|
title.push(msg + duration)
|
|
808
739
|
}
|
|
809
740
|
return title.join('\n')
|
|
810
741
|
}
|
|
811
|
-
const numFmt = new Intl.NumberFormat(undefined, { style: 'currency', currency: 'USD', minimumFractionDigits: 6 })
|
|
812
|
-
function tokenCost(price, tokens) {
|
|
813
|
-
if (!price || !tokens) return ''
|
|
814
|
-
return numFmt.format(parseFloat(price) * tokens)
|
|
815
|
-
}
|
|
816
742
|
|
|
743
|
+
let sub
|
|
817
744
|
onMounted(() => {
|
|
818
|
-
|
|
745
|
+
sub = ctx.events.subscribe(`keydown:Escape`, closeLightbox)
|
|
746
|
+
setTimeout(ctx.chat.addCopyButtons, 1)
|
|
819
747
|
})
|
|
748
|
+
onUnmounted(() => sub?.unsubscribe())
|
|
820
749
|
|
|
821
750
|
return {
|
|
822
751
|
config,
|
|
@@ -829,8 +758,6 @@ export default {
|
|
|
829
758
|
messagesContainer,
|
|
830
759
|
errorStatus,
|
|
831
760
|
copying,
|
|
832
|
-
formatTime,
|
|
833
|
-
renderMarkdown,
|
|
834
761
|
isReasoningExpanded,
|
|
835
762
|
toggleReasoning,
|
|
836
763
|
formatReasoning,
|
|
@@ -847,16 +774,12 @@ export default {
|
|
|
847
774
|
isImporting,
|
|
848
775
|
fileInput,
|
|
849
776
|
tokensTitle,
|
|
850
|
-
humanifyMs,
|
|
851
|
-
humanifyNumber,
|
|
852
|
-
formatCost,
|
|
853
|
-
formatCost,
|
|
854
|
-
statsTitle,
|
|
855
777
|
getAttachments,
|
|
856
778
|
hasAttachments,
|
|
857
779
|
lightboxUrl,
|
|
858
780
|
openLightbox,
|
|
859
781
|
closeLightbox,
|
|
782
|
+
resolveUrl,
|
|
860
783
|
}
|
|
861
784
|
}
|
|
862
785
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ref, computed, watch, inject } from 'vue'
|
|
2
|
-
import { storageObject } from '
|
|
2
|
+
import { storageObject } from '../../utils.mjs'
|
|
3
3
|
|
|
4
4
|
const settingsKey = 'llms.settings'
|
|
5
5
|
|
|
@@ -40,7 +40,7 @@ export function useSettings() {
|
|
|
40
40
|
]
|
|
41
41
|
|
|
42
42
|
let settings = ref(storageObject(settingsKey))
|
|
43
|
-
|
|
43
|
+
|
|
44
44
|
function validSettings(localSettings) {
|
|
45
45
|
const to = {}
|
|
46
46
|
intFields.forEach(f => {
|
|
@@ -65,9 +65,9 @@ export function useSettings() {
|
|
|
65
65
|
})
|
|
66
66
|
listFields.forEach(f => {
|
|
67
67
|
if (localSettings[f] != null && localSettings[f] !== '') {
|
|
68
|
-
to[f] = Array.isArray(localSettings[f])
|
|
68
|
+
to[f] = Array.isArray(localSettings[f])
|
|
69
69
|
? localSettings[f]
|
|
70
|
-
: typeof localSettings[f] == 'string'
|
|
70
|
+
: typeof localSettings[f] == 'string'
|
|
71
71
|
? localSettings[f].split(',').map(x => x.trim())
|
|
72
72
|
: []
|
|
73
73
|
}
|
|
@@ -88,7 +88,7 @@ export function useSettings() {
|
|
|
88
88
|
function resetSettings() {
|
|
89
89
|
return saveSettings({})
|
|
90
90
|
}
|
|
91
|
-
|
|
91
|
+
|
|
92
92
|
function saveSettings(localSettings) {
|
|
93
93
|
// console.log('saveSettings', JSON.stringify(localSettings, undefined, 2))
|
|
94
94
|
settings.value = validSettings(localSettings)
|
|
@@ -337,9 +337,9 @@ export default {
|
|
|
337
337
|
},
|
|
338
338
|
emits: ['close'],
|
|
339
339
|
setup(props, { emit }) {
|
|
340
|
-
const
|
|
341
|
-
const { settings, saveSettings, resetSettings } =
|
|
342
|
-
|
|
340
|
+
const ctx = inject('ctx')
|
|
341
|
+
const { settings, saveSettings, resetSettings } = ctx.chat.settings
|
|
342
|
+
|
|
343
343
|
// Local copy for editing
|
|
344
344
|
const localSettings = ref(Object.assign({}, settings.value))
|
|
345
345
|
|