llms-py 2.0.35__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/llms.json +306 -1184
- llms/main.py +885 -181
- llms/providers.json +1 -0
- llms/ui/ChatPrompt.mjs +138 -122
- llms/ui/Main.mjs +162 -112
- llms/ui/ModelSelector.mjs +662 -47
- llms/ui/ProviderIcon.mjs +20 -14
- llms/ui/ProviderStatus.mjs +2 -2
- llms/ui/ai.mjs +10 -10
- llms/ui/app.css +369 -83
- llms/ui/markdown.mjs +8 -5
- llms/ui/threadStore.mjs +54 -45
- llms/ui/utils.mjs +100 -28
- {llms_py-2.0.35.dist-info → llms_py-3.0.0b1.dist-info}/METADATA +1 -1
- {llms_py-2.0.35.dist-info → llms_py-3.0.0b1.dist-info}/RECORD +19 -18
- {llms_py-2.0.35.dist-info → llms_py-3.0.0b1.dist-info}/WHEEL +0 -0
- {llms_py-2.0.35.dist-info → llms_py-3.0.0b1.dist-info}/entry_points.txt +0 -0
- {llms_py-2.0.35.dist-info → llms_py-3.0.0b1.dist-info}/licenses/LICENSE +0 -0
- {llms_py-2.0.35.dist-info → llms_py-3.0.0b1.dist-info}/top_level.txt +0 -0
llms/ui/markdown.mjs
CHANGED
|
@@ -5,7 +5,7 @@ export const marked = (() => {
|
|
|
5
5
|
const aliases = {
|
|
6
6
|
vue: 'html',
|
|
7
7
|
}
|
|
8
|
-
|
|
8
|
+
|
|
9
9
|
const ret = new Marked(
|
|
10
10
|
markedHighlight({
|
|
11
11
|
langPrefix: 'hljs language-',
|
|
@@ -18,18 +18,21 @@ export const marked = (() => {
|
|
|
18
18
|
}
|
|
19
19
|
})
|
|
20
20
|
)
|
|
21
|
-
ret.use({ extensions:[thinkTag()] })
|
|
21
|
+
ret.use({ extensions: [thinkTag()] })
|
|
22
22
|
//ret.use({ extensions: [divExtension()] })
|
|
23
23
|
return ret
|
|
24
24
|
})();
|
|
25
25
|
|
|
26
26
|
export function renderMarkdown(content) {
|
|
27
|
+
if (Array.isArray(content)) {
|
|
28
|
+
content = content.filter(c => c.type === 'text').map(c => c.text).join('\n')
|
|
29
|
+
}
|
|
27
30
|
if (content) {
|
|
28
31
|
content = content
|
|
29
|
-
.replaceAll(`\\[ \\boxed{`,'\n<span class="inline-block text-xl text-blue-500 bg-blue-50 dark:text-blue-400 dark:bg-blue-950 px-3 py-1 rounded">')
|
|
30
|
-
.replaceAll('} \\]','</span>\n')
|
|
32
|
+
.replaceAll(`\\[ \\boxed{`, '\n<span class="inline-block text-xl text-blue-500 bg-blue-50 dark:text-blue-400 dark:bg-blue-950 px-3 py-1 rounded">')
|
|
33
|
+
.replaceAll('} \\]', '</span>\n')
|
|
31
34
|
}
|
|
32
|
-
return marked.parse(content)
|
|
35
|
+
return marked.parse(content || '')
|
|
33
36
|
}
|
|
34
37
|
|
|
35
38
|
// export async function renderMarkdown(body) {
|
llms/ui/threadStore.mjs
CHANGED
|
@@ -12,7 +12,7 @@ let db = null
|
|
|
12
12
|
// Initialize IndexedDB
|
|
13
13
|
async function initDB() {
|
|
14
14
|
if (db) return db
|
|
15
|
-
|
|
15
|
+
|
|
16
16
|
db = await openDB('LlmsThreads', 3, {
|
|
17
17
|
upgrade(db, _oldVersion, _newVersion, transaction) {
|
|
18
18
|
if (!db.objectStoreNames.contains('threads')) {
|
|
@@ -44,7 +44,7 @@ async function initDB() {
|
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
46
|
})
|
|
47
|
-
|
|
47
|
+
|
|
48
48
|
return db
|
|
49
49
|
}
|
|
50
50
|
|
|
@@ -59,8 +59,8 @@ async function logRequest(threadId, model, request, response) {
|
|
|
59
59
|
const usage = response.usage || {}
|
|
60
60
|
const [inputPrice, outputPrice] = metadata.pricing ? metadata.pricing.split('/') : [0, 0]
|
|
61
61
|
const lastUserContent = request.messages?.slice().reverse().find(m => m.role === 'user')?.content
|
|
62
|
-
const content = Array.isArray(lastUserContent)
|
|
63
|
-
? lastUserContent.filter(c => c?.text).map(c => c.text).join(' ')
|
|
62
|
+
const content = Array.isArray(lastUserContent)
|
|
63
|
+
? lastUserContent.filter(c => c?.text).map(c => c.text).join(' ')
|
|
64
64
|
: lastUserContent
|
|
65
65
|
const title = content.slice(0, 100) + (content.length > 100 ? '...' : '')
|
|
66
66
|
const inputTokens = usage?.prompt_tokens ?? 0
|
|
@@ -87,7 +87,7 @@ async function logRequest(threadId, model, request, response) {
|
|
|
87
87
|
totalTokens: usage.total_tokens ?? (inputTokens + outputTokens),
|
|
88
88
|
inputPrice,
|
|
89
89
|
outputPrice,
|
|
90
|
-
cost: (parseFloat(inputPrice) * inputTokens) + (parseFloat(outputPrice) * outputTokens),
|
|
90
|
+
cost: (parseFloat(inputPrice) * inputTokens / 1_000_000) + (parseFloat(outputPrice) * outputTokens / 1_000_000),
|
|
91
91
|
duration: parseInt(metadata.duration) || 0,
|
|
92
92
|
created: response.created ?? Math.floor(Date.now() / 1000),
|
|
93
93
|
finishReason,
|
|
@@ -116,13 +116,18 @@ async function createThread(title = 'New Chat', model = null, systemPrompt = '')
|
|
|
116
116
|
createdAt: new Date().toISOString(),
|
|
117
117
|
updatedAt: new Date().toISOString()
|
|
118
118
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
119
|
+
|
|
120
|
+
try {
|
|
121
|
+
const tx = db.transaction(['threads'], 'readwrite')
|
|
122
|
+
await tx.objectStore('threads').add(thread)
|
|
123
|
+
await tx.complete
|
|
124
|
+
|
|
125
|
+
threads.value.unshift(thread)
|
|
126
|
+
// Note: currentThread will be set by router navigation
|
|
127
|
+
|
|
128
|
+
} catch (e) {
|
|
129
|
+
console.error('Error creating thread', e, thread)
|
|
130
|
+
}
|
|
126
131
|
|
|
127
132
|
return thread
|
|
128
133
|
}
|
|
@@ -130,56 +135,56 @@ async function createThread(title = 'New Chat', model = null, systemPrompt = '')
|
|
|
130
135
|
// Update thread
|
|
131
136
|
async function updateThread(threadId, updates) {
|
|
132
137
|
await initDB()
|
|
133
|
-
|
|
138
|
+
|
|
134
139
|
const tx = db.transaction(['threads'], 'readwrite')
|
|
135
140
|
const store = tx.objectStore('threads')
|
|
136
|
-
|
|
141
|
+
|
|
137
142
|
const thread = await store.get(threadId)
|
|
138
143
|
if (!thread) throw new Error('Thread not found')
|
|
139
|
-
|
|
144
|
+
|
|
140
145
|
const updatedThread = {
|
|
141
146
|
...thread,
|
|
142
147
|
...updates,
|
|
143
148
|
updatedAt: new Date().toISOString()
|
|
144
149
|
}
|
|
145
|
-
|
|
150
|
+
|
|
146
151
|
await store.put(updatedThread)
|
|
147
152
|
await tx.complete
|
|
148
|
-
|
|
153
|
+
|
|
149
154
|
// Update in memory
|
|
150
155
|
const index = threads.value.findIndex(t => t.id === threadId)
|
|
151
156
|
if (index !== -1) {
|
|
152
157
|
threads.value[index] = updatedThread
|
|
153
158
|
}
|
|
154
|
-
|
|
159
|
+
|
|
155
160
|
if (currentThread.value?.id === threadId) {
|
|
156
161
|
currentThread.value = updatedThread
|
|
157
162
|
}
|
|
158
|
-
|
|
163
|
+
|
|
159
164
|
return updatedThread
|
|
160
165
|
}
|
|
161
166
|
|
|
162
167
|
async function calculateThreadStats(threadId) {
|
|
163
168
|
await initDB()
|
|
164
|
-
|
|
169
|
+
|
|
165
170
|
const tx = db.transaction(['requests'], 'readonly')
|
|
166
171
|
const store = tx.objectStore('requests')
|
|
167
172
|
const index = store.index('threadId')
|
|
168
|
-
|
|
173
|
+
|
|
169
174
|
const requests = await index.getAll(threadId)
|
|
170
|
-
|
|
175
|
+
|
|
171
176
|
let inputTokens = 0
|
|
172
177
|
let outputTokens = 0
|
|
173
178
|
let cost = 0.0
|
|
174
179
|
let duration = 0
|
|
175
|
-
|
|
180
|
+
|
|
176
181
|
requests.forEach(req => {
|
|
177
182
|
inputTokens += req.inputTokens || 0
|
|
178
183
|
outputTokens += req.outputTokens || 0
|
|
179
184
|
cost += req.cost || 0.0
|
|
180
185
|
duration += req.duration || 0
|
|
181
186
|
})
|
|
182
|
-
|
|
187
|
+
|
|
183
188
|
return {
|
|
184
189
|
inputTokens,
|
|
185
190
|
outputTokens,
|
|
@@ -193,13 +198,13 @@ async function calculateThreadStats(threadId) {
|
|
|
193
198
|
async function addMessageToThread(threadId, message, usage) {
|
|
194
199
|
const thread = await getThread(threadId)
|
|
195
200
|
if (!thread) throw new Error('Thread not found')
|
|
196
|
-
|
|
201
|
+
|
|
197
202
|
const newMessage = {
|
|
198
203
|
id: nextId(),
|
|
199
204
|
timestamp: new Date().toISOString(),
|
|
200
205
|
...message
|
|
201
206
|
}
|
|
202
|
-
|
|
207
|
+
|
|
203
208
|
// Add input and output token usage to previous 'input' message
|
|
204
209
|
if (usage?.prompt_tokens != null) {
|
|
205
210
|
const lastMessage = thread.messages[thread.messages.length - 1]
|
|
@@ -219,21 +224,25 @@ async function addMessageToThread(threadId, message, usage) {
|
|
|
219
224
|
}
|
|
220
225
|
|
|
221
226
|
const updatedMessages = [...thread.messages, newMessage]
|
|
222
|
-
|
|
227
|
+
|
|
223
228
|
// Auto-generate title from first user message if still "New Chat"
|
|
224
229
|
let title = thread.title
|
|
225
230
|
if (title === 'New Chat' && message.role === 'user' && updatedMessages.length <= 2) {
|
|
226
|
-
|
|
231
|
+
let contentText = message.content
|
|
232
|
+
if (Array.isArray(contentText)) {
|
|
233
|
+
contentText = contentText.filter(c => c.type === 'text').map(c => c.text).join(' ')
|
|
234
|
+
}
|
|
235
|
+
title = contentText.slice(0, 200) + (contentText.length > 200 ? '...' : '')
|
|
227
236
|
}
|
|
228
237
|
|
|
229
238
|
const stats = await calculateThreadStats(threadId)
|
|
230
|
-
|
|
239
|
+
|
|
231
240
|
await updateThread(threadId, {
|
|
232
241
|
messages: updatedMessages,
|
|
233
242
|
title: title,
|
|
234
243
|
stats,
|
|
235
244
|
})
|
|
236
|
-
|
|
245
|
+
|
|
237
246
|
return newMessage
|
|
238
247
|
}
|
|
239
248
|
|
|
@@ -279,15 +288,15 @@ async function redoMessageFromThread(threadId, messageId) {
|
|
|
279
288
|
async function loadThreads() {
|
|
280
289
|
await initDB()
|
|
281
290
|
isLoading.value = true
|
|
282
|
-
|
|
291
|
+
|
|
283
292
|
try {
|
|
284
293
|
const tx = db.transaction(['threads'], 'readonly')
|
|
285
294
|
const store = tx.objectStore('threads')
|
|
286
295
|
const index = store.index('updatedAt')
|
|
287
|
-
|
|
296
|
+
|
|
288
297
|
const allThreads = await index.getAll()
|
|
289
298
|
threads.value = allThreads.reverse() // Most recent first
|
|
290
|
-
|
|
299
|
+
|
|
291
300
|
return threads.value
|
|
292
301
|
} finally {
|
|
293
302
|
isLoading.value = false
|
|
@@ -297,23 +306,23 @@ async function loadThreads() {
|
|
|
297
306
|
// Get single thread
|
|
298
307
|
async function getThread(threadId) {
|
|
299
308
|
await initDB()
|
|
300
|
-
|
|
309
|
+
|
|
301
310
|
const tx = db.transaction(['threads'], 'readonly')
|
|
302
311
|
const thread = await tx.objectStore('threads').get(threadId)
|
|
303
|
-
|
|
312
|
+
|
|
304
313
|
return thread
|
|
305
314
|
}
|
|
306
315
|
|
|
307
316
|
// Delete thread
|
|
308
317
|
async function deleteThread(threadId) {
|
|
309
318
|
await initDB()
|
|
310
|
-
|
|
319
|
+
|
|
311
320
|
const tx = db.transaction(['threads'], 'readwrite')
|
|
312
321
|
await tx.objectStore('threads').delete(threadId)
|
|
313
322
|
await tx.complete
|
|
314
|
-
|
|
323
|
+
|
|
315
324
|
threads.value = threads.value.filter(t => t.id !== threadId)
|
|
316
|
-
|
|
325
|
+
|
|
317
326
|
if (currentThread.value?.id === threadId) {
|
|
318
327
|
currentThread.value = null
|
|
319
328
|
}
|
|
@@ -359,19 +368,19 @@ function getGroupedThreads(total) {
|
|
|
359
368
|
const today = new Date(now.getFullYear(), now.getMonth(), now.getDate())
|
|
360
369
|
const lastWeek = new Date(today.getTime() - 7 * 24 * 60 * 60 * 1000)
|
|
361
370
|
const lastMonth = new Date(today.getTime() - 30 * 24 * 60 * 60 * 1000)
|
|
362
|
-
|
|
371
|
+
|
|
363
372
|
const groups = {
|
|
364
373
|
today: [],
|
|
365
374
|
lastWeek: [],
|
|
366
375
|
lastMonth: [],
|
|
367
376
|
older: {}
|
|
368
377
|
}
|
|
369
|
-
|
|
378
|
+
|
|
370
379
|
const takeThreads = threads.value.slice(0, total)
|
|
371
380
|
|
|
372
381
|
takeThreads.forEach(thread => {
|
|
373
382
|
const threadDate = new Date(thread.updatedAt)
|
|
374
|
-
|
|
383
|
+
|
|
375
384
|
if (threadDate >= today) {
|
|
376
385
|
groups.today.push(thread)
|
|
377
386
|
} else if (threadDate >= lastWeek) {
|
|
@@ -382,14 +391,14 @@ function getGroupedThreads(total) {
|
|
|
382
391
|
const year = threadDate.getFullYear()
|
|
383
392
|
const month = threadDate.toLocaleString('default', { month: 'long' })
|
|
384
393
|
const key = `${month} ${year}`
|
|
385
|
-
|
|
394
|
+
|
|
386
395
|
if (!groups.older[key]) {
|
|
387
396
|
groups.older[key] = []
|
|
388
397
|
}
|
|
389
398
|
groups.older[key].push(thread)
|
|
390
399
|
}
|
|
391
400
|
})
|
|
392
|
-
|
|
401
|
+
|
|
393
402
|
return groups
|
|
394
403
|
}
|
|
395
404
|
|
|
@@ -416,7 +425,7 @@ async function getRequest(requestId) {
|
|
|
416
425
|
|
|
417
426
|
async function getAllRequestIds() {
|
|
418
427
|
await initDB()
|
|
419
|
-
|
|
428
|
+
|
|
420
429
|
const tx = db.transaction(['requests'], 'readonly')
|
|
421
430
|
const store = tx.objectStore('requests')
|
|
422
431
|
const ids = await store.getAllKeys()
|
|
@@ -428,7 +437,7 @@ async function getAllThreadIds() {
|
|
|
428
437
|
const tx = db.transaction(['threads'], 'readonly')
|
|
429
438
|
const store = tx.objectStore('threads')
|
|
430
439
|
const ids = await store.getAllKeys()
|
|
431
|
-
return ids
|
|
440
|
+
return ids
|
|
432
441
|
}
|
|
433
442
|
|
|
434
443
|
// Query requests with pagination and filtering
|
llms/ui/utils.mjs
CHANGED
|
@@ -1,4 +1,37 @@
|
|
|
1
|
-
import { $$, createElement, rightPart } from "@servicestack/client"
|
|
1
|
+
import { $$, createElement, rightPart, pick } from "@servicestack/client"
|
|
2
|
+
|
|
3
|
+
const cacheUrlInfo = {}
|
|
4
|
+
|
|
5
|
+
export function getCacheInfo(url) {
|
|
6
|
+
return cacheUrlInfo[url]
|
|
7
|
+
}
|
|
8
|
+
export async function fetchCacheInfos(urls) {
|
|
9
|
+
const infos = {}
|
|
10
|
+
const fetchInfos = []
|
|
11
|
+
for (const url of urls) {
|
|
12
|
+
const info = getCacheInfo(url)
|
|
13
|
+
if (info) {
|
|
14
|
+
infos[url] = info
|
|
15
|
+
} else {
|
|
16
|
+
fetchInfos.push(fetch(url + "?info"))
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
const responses = await Promise.all(fetchInfos)
|
|
20
|
+
for (let i = 0; i < urls.length; i++) {
|
|
21
|
+
try {
|
|
22
|
+
const info = await responses[i].json()
|
|
23
|
+
setCacheInfo(urls[i], info)
|
|
24
|
+
infos[urls[i]] = info
|
|
25
|
+
} catch (e) {
|
|
26
|
+
console.error('Failed to fetch info for', urls[i], e)
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return infos
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function setCacheInfo(url, info) {
|
|
33
|
+
cacheUrlInfo[url] = info
|
|
34
|
+
}
|
|
2
35
|
|
|
3
36
|
export function toJsonArray(json) {
|
|
4
37
|
try {
|
|
@@ -30,36 +63,75 @@ export function storageObject(key, save) {
|
|
|
30
63
|
return toJsonObject(localStorage.getItem(key)) ?? {}
|
|
31
64
|
}
|
|
32
65
|
|
|
33
|
-
export function
|
|
34
|
-
return
|
|
66
|
+
export function fileToBase64(file) {
|
|
67
|
+
return new Promise((resolve, reject) => {
|
|
68
|
+
const reader = new FileReader()
|
|
69
|
+
reader.readAsDataURL(file) //= "data:…;base64,…"
|
|
70
|
+
reader.onload = () => {
|
|
71
|
+
resolve(rightPart(reader.result, ',')) // strip prefix
|
|
72
|
+
}
|
|
73
|
+
reader.onerror = err => reject(err)
|
|
74
|
+
})
|
|
35
75
|
}
|
|
36
76
|
|
|
37
|
-
export function
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
77
|
+
export function fileToDataUri(file) {
|
|
78
|
+
return new Promise((resolve, reject) => {
|
|
79
|
+
const reader = new FileReader()
|
|
80
|
+
reader.readAsDataURL(file) //= "data:…;base64,…"
|
|
81
|
+
reader.onload = () => resolve(reader.result)
|
|
82
|
+
reader.onerror = err => reject(err)
|
|
83
|
+
})
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export async function uploadFile(file) {
|
|
87
|
+
const formData = new FormData()
|
|
88
|
+
formData.append('file', file)
|
|
89
|
+
const response = await fetch('/upload', {
|
|
90
|
+
method: 'POST',
|
|
91
|
+
body: formData
|
|
92
|
+
})
|
|
93
|
+
if (!response.ok) {
|
|
94
|
+
throw new Error(`Upload failed: ${response.statusText}`)
|
|
43
95
|
}
|
|
44
|
-
|
|
45
|
-
})
|
|
96
|
+
return response.json()
|
|
46
97
|
}
|
|
47
98
|
|
|
48
|
-
export function
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
99
|
+
export function serializedClone(obj) {
|
|
100
|
+
try {
|
|
101
|
+
return JSON.parse(JSON.stringify(obj))
|
|
102
|
+
} catch (e) {
|
|
103
|
+
console.warn('Deep cloning failed, returning original value:', e)
|
|
104
|
+
return obj
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export function deepClone(o) {
|
|
109
|
+
if (o === null || typeof o !== 'object') return o
|
|
110
|
+
|
|
111
|
+
// Handle Array objects
|
|
112
|
+
if (Array.isArray(o)) {
|
|
113
|
+
return o.map(x => deepClone(x))
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (typeof structuredClone === 'function') { // available (modern browsers, Node.js 17+)
|
|
117
|
+
try {
|
|
118
|
+
return structuredClone(o)
|
|
119
|
+
} catch (e) {
|
|
120
|
+
console.warn('structuredClone failed, falling back to JSON:', e)
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Fallback to JSON stringify/parse for older environments
|
|
125
|
+
return serializedClone(o)
|
|
55
126
|
}
|
|
56
127
|
|
|
57
128
|
export function toModelInfo(model) {
|
|
58
129
|
if (!model) return undefined
|
|
59
|
-
|
|
130
|
+
const { id, name, provider, cost, modalities } = model
|
|
131
|
+
return deepClone({ id, name, provider, cost, modalities })
|
|
60
132
|
}
|
|
61
133
|
|
|
62
|
-
const numFmt = new Intl.NumberFormat(undefined,{style:'currency',currency:'USD', maximumFractionDigits:6})
|
|
134
|
+
const numFmt = new Intl.NumberFormat(undefined, { style: 'currency', currency: 'USD', maximumFractionDigits: 6 })
|
|
63
135
|
export function tokenCost(price) {
|
|
64
136
|
if (!price) return ''
|
|
65
137
|
var ret = numFmt.format(parseFloat(price))
|
|
@@ -123,8 +195,8 @@ export function addCopyButtonToCodeBlocks(sel) {
|
|
|
123
195
|
if (pre.classList.contains('group')) return
|
|
124
196
|
pre.classList.add('relative', 'group')
|
|
125
197
|
|
|
126
|
-
const div = createElement('div', {attrs: {className: 'opacity-0 group-hover:opacity-100 transition-opacity duration-100 flex absolute right-2 -mt-1 select-none'}})
|
|
127
|
-
const label = createElement('div', {attrs: {className: 'hidden font-sans p-1 px-2 mr-1 rounded-md border border-gray-600 bg-gray-700 text-gray-400'}})
|
|
198
|
+
const div = createElement('div', { attrs: { className: 'opacity-0 group-hover:opacity-100 transition-opacity duration-100 flex absolute right-2 -mt-1 select-none' } })
|
|
199
|
+
const label = createElement('div', { attrs: { className: 'hidden font-sans p-1 px-2 mr-1 rounded-md border border-gray-600 bg-gray-700 text-gray-400' } })
|
|
128
200
|
const btn = createElement('button', {
|
|
129
201
|
attrs: {
|
|
130
202
|
type: 'button',
|
|
@@ -147,10 +219,10 @@ export function addCopyButtons() {
|
|
|
147
219
|
* Returns an ever-increasing unique integer id.
|
|
148
220
|
*/
|
|
149
221
|
export const nextId = (() => {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
222
|
+
let last = 0 // cache of the last id that was handed out
|
|
223
|
+
return () => {
|
|
224
|
+
const now = Date.now() // current millisecond timestamp
|
|
225
|
+
last = (now > last) ? now : last + 1
|
|
226
|
+
return last
|
|
227
|
+
}
|
|
156
228
|
})();
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: llms-py
|
|
3
|
-
Version:
|
|
3
|
+
Version: 3.0.0b1
|
|
4
4
|
Summary: A lightweight CLI tool and OpenAI-compatible server for querying multiple Large Language Model (LLM) providers
|
|
5
5
|
Home-page: https://github.com/ServiceStack/llms
|
|
6
6
|
Author: ServiceStack
|
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
llms/__init__.py,sha256=DKwTZDsyYL_wHe7yvLw49Nf8PSgPSyWaeVdotUqSvrQ,84
|
|
2
2
|
llms/__main__.py,sha256=hrBulHIt3lmPm1BCyAEVtB6DQ0Hvc3gnIddhHCmJasg,151
|
|
3
3
|
llms/index.html,sha256=_pkjdzCX95HTf19LgE4gMh6tLittcnf7M_jL2hSEbbM,3250
|
|
4
|
-
llms/llms.json,sha256=
|
|
5
|
-
llms/main.py,sha256=
|
|
4
|
+
llms/llms.json,sha256=Y_J3Usw0tt96fc7Dp_fY41wjHrIRKbx0gS0-gk2Uoqk,9697
|
|
5
|
+
llms/main.py,sha256=knAHWd0WZO_nSLrAqDVTziPa0CjQfS8Ahsk9vuw510M,117476
|
|
6
|
+
llms/providers.json,sha256=meE6G2vyzfKYmwdml9-O8Pm_uGc520bj891SUjQmsLY,215127
|
|
6
7
|
llms/ui.json,sha256=iBOmpNeD5-o8AgUa51ymS-KemovJ7bm9J1fnL0nf8jk,134025
|
|
7
8
|
llms/ui/Analytics.mjs,sha256=LfWbUlpb__0EEYtHu6e4r8AeyhsNQeAxrg44RuNSR0M,73261
|
|
8
9
|
llms/ui/App.mjs,sha256=L8Zn7b7YVqR5jgVQKvo_txijSd1T7jq6QOQEt7Q0eB0,3811
|
|
9
10
|
llms/ui/Avatar.mjs,sha256=TgouwV9bN-Ou1Tf2zCDtVaRiUB21TXZZPFCTlFL-xxQ,3387
|
|
10
11
|
llms/ui/Brand.mjs,sha256=JLN_lPirNXqS332g0B_WVOlFRVg3lNe1Q56TRnpj0zQ,3411
|
|
11
|
-
llms/ui/ChatPrompt.mjs,sha256=
|
|
12
|
-
llms/ui/Main.mjs,sha256=
|
|
13
|
-
llms/ui/ModelSelector.mjs,sha256=
|
|
12
|
+
llms/ui/ChatPrompt.mjs,sha256=vu05EC_mHdiEBYRHUNMJrmyupfhHVo-MZh4QgvNhrsM,26892
|
|
13
|
+
llms/ui/Main.mjs,sha256=Z5RQfFF7AaXZ-SSMHBnWeiKnXbZP6po1HY28mBGH9Ro,45867
|
|
14
|
+
llms/ui/ModelSelector.mjs,sha256=8WoPrlWXr_kSJN6TFJfGjk6M_GzoEm-trswvprDCwK0,37507
|
|
14
15
|
llms/ui/OAuthSignIn.mjs,sha256=IdA9Tbswlh74a_-9e9YulOpqLfRpodRLGfCZ9sTZ5jU,4879
|
|
15
|
-
llms/ui/ProviderIcon.mjs,sha256=
|
|
16
|
-
llms/ui/ProviderStatus.mjs,sha256=
|
|
16
|
+
llms/ui/ProviderIcon.mjs,sha256=XdEJRm90Zaeu7AlcxfLTXqh_jj2F5JvFkug0XexZeQc,22900
|
|
17
|
+
llms/ui/ProviderStatus.mjs,sha256=Dsr_kzjdYuXNLNIwpcQe3URB4nmBdEEFeU8DgOfWu20,6144
|
|
17
18
|
llms/ui/Recents.mjs,sha256=sRoesSktUvBZ7UjfFJwp0btCQj5eQvnTDjSUDzN8ySU,8864
|
|
18
19
|
llms/ui/SettingsDialog.mjs,sha256=vyqLOrACBICwT8qQ10oJAMOYeA1phrAyz93mZygn-9Y,19956
|
|
19
20
|
llms/ui/Sidebar.mjs,sha256=93wCzrbY4F9VBFGiWujNIj5ynxP_9bmv5pJQOGdybIc,11183
|
|
@@ -21,14 +22,14 @@ llms/ui/SignIn.mjs,sha256=df3b-7L3ZIneDGbJWUk93K9RGo40gVeuR5StzT1ZH9g,2324
|
|
|
21
22
|
llms/ui/SystemPromptEditor.mjs,sha256=PffkNPV6hGbm1QZBKPI7yvWPZSBL7qla0d-JEJ4mxYo,1466
|
|
22
23
|
llms/ui/SystemPromptSelector.mjs,sha256=UgoeuscFes0B1oFkx74dFwC0JgRib37VM4Gy3-kCVDQ,3769
|
|
23
24
|
llms/ui/Welcome.mjs,sha256=r9j7unF9CF3k7gEQBMRMVsa2oSjgHGNn46Oa5l5BwlY,950
|
|
24
|
-
llms/ui/ai.mjs,sha256=
|
|
25
|
-
llms/ui/app.css,sha256=
|
|
25
|
+
llms/ui/ai.mjs,sha256=GpYD7np2mFb4FX49dzHZCUUrB9-Aj676zf_1ejVp4tA,4839
|
|
26
|
+
llms/ui/app.css,sha256=WrCjd6lJTS6DWuQKUMGPwmrIYCTfauDS_m-ghkoR2qA,119287
|
|
26
27
|
llms/ui/fav.svg,sha256=_R6MFeXl6wBFT0lqcUxYQIDWgm246YH_3hSTW0oO8qw,734
|
|
27
|
-
llms/ui/markdown.mjs,sha256=
|
|
28
|
+
llms/ui/markdown.mjs,sha256=0LUF2Tyvpv88ic-MjdUjAAdd1Rt8LYA_d7VRA-kBFuM,6518
|
|
28
29
|
llms/ui/tailwind.input.css,sha256=QInTVDpCR89OTzRo9AePdAa-MX3i66RkhNOfa4_7UAg,12086
|
|
29
|
-
llms/ui/threadStore.mjs,sha256=
|
|
30
|
+
llms/ui/threadStore.mjs,sha256=CL-dTxnMJsk9ORDiN80FSgdsdDQEmKsZDKI5fAGCr-o,16706
|
|
30
31
|
llms/ui/typography.css,sha256=6o7pbMIamRVlm2GfzSStpcOG4T5eFCK_WcQ3RIHKAsU,19587
|
|
31
|
-
llms/ui/utils.mjs,sha256=
|
|
32
|
+
llms/ui/utils.mjs,sha256=dzBBhltx8bUPasFAM3VRsobbDOesBd2M3mjuYdwAExA,7283
|
|
32
33
|
llms/ui/lib/chart.js,sha256=dx8FdDX0Rv6OZtZjr9FQh5h-twFsKjfnb-FvFlQ--cU,196176
|
|
33
34
|
llms/ui/lib/charts.mjs,sha256=MNym9qE_2eoH6M7_8Gj9i6e6-Y3b7zw9UQWCUHRF6x0,1088
|
|
34
35
|
llms/ui/lib/color.js,sha256=DDG7Pr-qzJHTPISZNSqP_qJR8UflKHEc_56n6xrBugQ,8273
|
|
@@ -40,9 +41,9 @@ llms/ui/lib/servicestack-vue.mjs,sha256=unTA8lM0tKy2PwZiJ8UEvrTuGmei8jNZnmmuQ5MK
|
|
|
40
41
|
llms/ui/lib/vue-router.min.mjs,sha256=fR30GHoXI1u81zyZ26YEU105pZgbbAKSXbpnzFKIxls,30418
|
|
41
42
|
llms/ui/lib/vue.min.mjs,sha256=iXh97m5hotl0eFllb3aoasQTImvp7mQoRJ_0HoxmZkw,163811
|
|
42
43
|
llms/ui/lib/vue.mjs,sha256=dS8LKOG01t9CvZ04i0tbFXHqFXOO_Ha4NmM3BytjQAs,537071
|
|
43
|
-
llms_py-
|
|
44
|
-
llms_py-
|
|
45
|
-
llms_py-
|
|
46
|
-
llms_py-
|
|
47
|
-
llms_py-
|
|
48
|
-
llms_py-
|
|
44
|
+
llms_py-3.0.0b1.dist-info/licenses/LICENSE,sha256=bus9cuAOWeYqBk2OuhSABVV1P4z7hgrEFISpyda_H5w,1532
|
|
45
|
+
llms_py-3.0.0b1.dist-info/METADATA,sha256=jS7M9B8ThKrqFC_Uzuk_fYmbzo3eNNDqiAj6aJY7cZw,2193
|
|
46
|
+
llms_py-3.0.0b1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
47
|
+
llms_py-3.0.0b1.dist-info/entry_points.txt,sha256=WswyE7PfnkZMIxboC-MS6flBD6wm-CYU7JSUnMhqMfM,40
|
|
48
|
+
llms_py-3.0.0b1.dist-info/top_level.txt,sha256=gC7hk9BKSeog8gyg-EM_g2gxm1mKHwFRfK-10BxOsa4,5
|
|
49
|
+
llms_py-3.0.0b1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|