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
llms/ui/utils.mjs
CHANGED
|
@@ -1,5 +1,37 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
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
|
+
}
|
|
3
35
|
|
|
4
36
|
export function toJsonArray(json) {
|
|
5
37
|
try {
|
|
@@ -51,6 +83,19 @@ export function fileToDataUri(file) {
|
|
|
51
83
|
})
|
|
52
84
|
}
|
|
53
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}`)
|
|
95
|
+
}
|
|
96
|
+
return response.json()
|
|
97
|
+
}
|
|
98
|
+
|
|
54
99
|
export function serializedClone(obj) {
|
|
55
100
|
try {
|
|
56
101
|
return JSON.parse(JSON.stringify(obj))
|
|
@@ -73,8 +118,6 @@ export function deepClone(o) {
|
|
|
73
118
|
return structuredClone(o)
|
|
74
119
|
} catch (e) {
|
|
75
120
|
console.warn('structuredClone failed, falling back to JSON:', e)
|
|
76
|
-
console.log(o)
|
|
77
|
-
// console.log(JSON.stringify(o, undefined, 2))
|
|
78
121
|
}
|
|
79
122
|
}
|
|
80
123
|
|
|
@@ -84,114 +127,92 @@ export function deepClone(o) {
|
|
|
84
127
|
|
|
85
128
|
export function toModelInfo(model) {
|
|
86
129
|
if (!model) return undefined
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
props.forEach(k => to[k] = toRaw(model[k]))
|
|
90
|
-
return deepClone(to)
|
|
130
|
+
const { id, name, provider, cost, modalities } = model
|
|
131
|
+
return deepClone({ id, name, provider, cost, modalities })
|
|
91
132
|
}
|
|
92
133
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
const currFmt2 = new Intl.NumberFormat(undefined, { style: 'currency', currency: 'USD', maximumFractionDigits: 2 })
|
|
98
|
-
const currFmt6 = new Intl.NumberFormat(undefined, { style: 'currency', currency: 'USD', maximumFractionDigits: 6 })
|
|
99
|
-
|
|
100
|
-
export function tokenCost(price, tokens = 1) {
|
|
134
|
+
const numFmt = new Intl.NumberFormat(undefined, { style: 'currency', currency: 'USD', maximumFractionDigits: 6 })
|
|
135
|
+
export function tokenCost(price) {
|
|
101
136
|
if (!price) return ''
|
|
102
|
-
var ret =
|
|
137
|
+
var ret = numFmt.format(parseFloat(price))
|
|
103
138
|
return ret.endsWith('.00') ? ret.slice(0, -3) : ret
|
|
104
139
|
}
|
|
105
|
-
export function tokenCostLong(price, tokens = 1) {
|
|
106
|
-
if (!price) return ''
|
|
107
|
-
const ret = currFmt6.format(parseFloat(price) * tokens)
|
|
108
|
-
return ret.endsWith('.000000') ? ret.slice(0, -7) : ret
|
|
109
|
-
}
|
|
110
140
|
export function formatCost(cost) {
|
|
111
141
|
if (!cost) return ''
|
|
112
|
-
return
|
|
142
|
+
return numFmt.format(parseFloat(cost))
|
|
113
143
|
}
|
|
114
|
-
export function
|
|
144
|
+
export function statsTitle(stats) {
|
|
115
145
|
let title = []
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
: `${usage.tokens} tokens`
|
|
120
|
-
const duration = usage.duration ? ` in ${usage.duration}ms` : ''
|
|
121
|
-
title.push(msg + duration)
|
|
146
|
+
// Each stat on its own line
|
|
147
|
+
if (stats.cost) {
|
|
148
|
+
title.push(`Total Cost: ${formatCost(stats.cost)}`)
|
|
122
149
|
}
|
|
123
|
-
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// Accessible in views via $fmt
|
|
127
|
-
export function utilsFormatters() {
|
|
128
|
-
function relativeTime(timestamp) {
|
|
129
|
-
const now = new Date()
|
|
130
|
-
const date = new Date(timestamp)
|
|
131
|
-
const diffInSeconds = Math.floor((now - date) / 1000)
|
|
132
|
-
|
|
133
|
-
if (diffInSeconds < 60) return 'Just now'
|
|
134
|
-
if (diffInSeconds < 3600) return `${Math.floor(diffInSeconds / 60)}m ago`
|
|
135
|
-
if (diffInSeconds < 86400) return `${Math.floor(diffInSeconds / 3600)}h ago`
|
|
136
|
-
if (diffInSeconds < 604800) return `${Math.floor(diffInSeconds / 86400)}d ago`
|
|
137
|
-
|
|
138
|
-
return date.toLocaleDateString()
|
|
150
|
+
if (stats.inputTokens) {
|
|
151
|
+
title.push(`Input Tokens: ${stats.inputTokens}`)
|
|
139
152
|
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
const ret = currFmt6.format(parseFloat(cost))
|
|
143
|
-
return ret.endsWith('.000000') ? ret.slice(0, -7) : ret
|
|
153
|
+
if (stats.outputTokens) {
|
|
154
|
+
title.push(`Output Tokens: ${stats.outputTokens}`)
|
|
144
155
|
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
// Each stat on its own line
|
|
148
|
-
if (stats.cost) {
|
|
149
|
-
title.push(`Total Cost: ${costLong(stats.cost)}`)
|
|
150
|
-
}
|
|
151
|
-
if (stats.inputTokens) {
|
|
152
|
-
title.push(`Input Tokens: ${stats.inputTokens}`)
|
|
153
|
-
}
|
|
154
|
-
if (stats.outputTokens) {
|
|
155
|
-
title.push(`Output Tokens: ${stats.outputTokens}`)
|
|
156
|
-
}
|
|
157
|
-
if (stats.requests) {
|
|
158
|
-
title.push(`Requests: ${stats.requests}`)
|
|
159
|
-
}
|
|
160
|
-
if (stats.duration) {
|
|
161
|
-
title.push(`Duration: ${stats.duration}ms`)
|
|
162
|
-
}
|
|
163
|
-
return title.join('\n')
|
|
156
|
+
if (stats.requests) {
|
|
157
|
+
title.push(`Requests: ${stats.requests}`)
|
|
164
158
|
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
return new Date(timestamp).toLocaleTimeString([], {
|
|
168
|
-
hour: '2-digit',
|
|
169
|
-
minute: '2-digit'
|
|
170
|
-
})
|
|
159
|
+
if (stats.duration) {
|
|
160
|
+
title.push(`Duration: ${stats.duration}ms`)
|
|
171
161
|
}
|
|
162
|
+
return title.join('\n')
|
|
163
|
+
}
|
|
172
164
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
165
|
+
const svg = {
|
|
166
|
+
clipboard: `<svg class="w-6 h-6" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g fill="none"><path d="M8 5H6a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2v-1M8 5a2 2 0 0 0 2 2h2a2 2 0 0 0 2-2M8 5a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2m0 0h2a2 2 0 0 1 2 2v3m2 4H10m0 0l3-3m-3 3l3 3" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path></g></svg>`,
|
|
167
|
+
check: `<svg class="w-6 h-6 text-green-500" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg>`,
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function copyBlock(btn) {
|
|
171
|
+
// console.log('copyBlock',btn)
|
|
172
|
+
const label = btn.previousElementSibling
|
|
173
|
+
const code = btn.parentElement.nextElementSibling
|
|
174
|
+
label.classList.remove('hidden')
|
|
175
|
+
label.innerHTML = 'copied'
|
|
176
|
+
btn.classList.add('border-gray-600', 'bg-gray-700')
|
|
177
|
+
btn.classList.remove('border-gray-700')
|
|
178
|
+
btn.innerHTML = svg.check
|
|
179
|
+
navigator.clipboard.writeText(code.innerText)
|
|
180
|
+
setTimeout(() => {
|
|
181
|
+
label.classList.add('hidden')
|
|
182
|
+
label.innerHTML = ''
|
|
183
|
+
btn.innerHTML = svg.clipboard
|
|
184
|
+
btn.classList.remove('border-gray-600', 'bg-gray-700')
|
|
185
|
+
btn.classList.add('border-gray-700')
|
|
186
|
+
}, 2000)
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export function addCopyButtonToCodeBlocks(sel) {
|
|
190
|
+
globalThis.copyBlock ??= copyBlock
|
|
191
|
+
//console.log('addCopyButtonToCodeBlocks', sel, [...$$(sel)].length)
|
|
192
|
+
|
|
193
|
+
$$(sel).forEach(code => {
|
|
194
|
+
let pre = code.parentElement;
|
|
195
|
+
if (pre.classList.contains('group')) return
|
|
196
|
+
pre.classList.add('relative', 'group')
|
|
197
|
+
|
|
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' } })
|
|
200
|
+
const btn = createElement('button', {
|
|
201
|
+
attrs: {
|
|
202
|
+
type: 'button',
|
|
203
|
+
className: 'p-1 rounded-md border block text-gray-500 hover:text-gray-400 border-gray-700 hover:border-gray-600',
|
|
204
|
+
onclick: 'copyBlock(this)'
|
|
205
|
+
}
|
|
178
206
|
})
|
|
179
|
-
|
|
180
|
-
|
|
207
|
+
btn.innerHTML = svg.clipboard
|
|
208
|
+
div.appendChild(label)
|
|
209
|
+
div.appendChild(btn)
|
|
210
|
+
pre.insertBefore(div, code)
|
|
211
|
+
})
|
|
212
|
+
}
|
|
181
213
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
tokenCost,
|
|
185
|
-
tokenCostLong,
|
|
186
|
-
tokensTitle,
|
|
187
|
-
cost: formatCost,
|
|
188
|
-
costLong,
|
|
189
|
-
statsTitle,
|
|
190
|
-
relativeTime,
|
|
191
|
-
time,
|
|
192
|
-
pluralize,
|
|
193
|
-
shortDate,
|
|
194
|
-
}
|
|
214
|
+
export function addCopyButtons() {
|
|
215
|
+
addCopyButtonToCodeBlocks('.prose pre>code')
|
|
195
216
|
}
|
|
196
217
|
|
|
197
218
|
/**
|
|
@@ -204,21 +225,4 @@ export const nextId = (() => {
|
|
|
204
225
|
last = (now > last) ? now : last + 1
|
|
205
226
|
return last
|
|
206
227
|
}
|
|
207
|
-
})();
|
|
208
|
-
|
|
209
|
-
export function utilsFunctions() {
|
|
210
|
-
return {
|
|
211
|
-
nextId,
|
|
212
|
-
toJsonArray,
|
|
213
|
-
toJsonObject,
|
|
214
|
-
storageArray,
|
|
215
|
-
storageObject,
|
|
216
|
-
fileToBase64,
|
|
217
|
-
fileToDataUri,
|
|
218
|
-
serializedClone,
|
|
219
|
-
deepClone,
|
|
220
|
-
toModelInfo,
|
|
221
|
-
pluralize,
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
|
|
228
|
+
})();
|