llms-py 3.0.0__py3-none-any.whl → 3.0.0b2__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 +37 -26
- llms/llms.json +21 -70
- llms/main.py +731 -1426
- llms/providers.json +1 -1
- llms/{extensions/analytics/ui/index.mjs → ui/Analytics.mjs} +238 -154
- llms/ui/App.mjs +63 -133
- llms/ui/Avatar.mjs +86 -0
- llms/ui/Brand.mjs +52 -0
- llms/ui/ChatPrompt.mjs +597 -0
- llms/ui/Main.mjs +862 -0
- llms/ui/OAuthSignIn.mjs +61 -0
- llms/ui/ProviderIcon.mjs +36 -0
- llms/ui/ProviderStatus.mjs +104 -0
- llms/{extensions/app/ui → ui}/Recents.mjs +57 -82
- llms/ui/{modules/chat/SettingsDialog.mjs → SettingsDialog.mjs} +9 -9
- llms/{extensions/app/ui/index.mjs → ui/Sidebar.mjs} +57 -122
- llms/ui/SignIn.mjs +65 -0
- llms/ui/Welcome.mjs +8 -0
- llms/ui/ai.mjs +13 -117
- llms/ui/app.css +49 -1776
- llms/ui/index.mjs +171 -87
- 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/model-selector.mjs +686 -0
- llms/ui/tailwind.input.css +1 -55
- llms/ui/threadStore.mjs +583 -0
- llms/ui/utils.mjs +118 -113
- llms/ui.json +1069 -0
- {llms_py-3.0.0.dist-info → llms_py-3.0.0b2.dist-info}/METADATA +1 -1
- llms_py-3.0.0b2.dist-info/RECORD +58 -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/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.0b2.dist-info}/WHEEL +0 -0
- {llms_py-3.0.0.dist-info → llms_py-3.0.0b2.dist-info}/entry_points.txt +0 -0
- {llms_py-3.0.0.dist-info → llms_py-3.0.0b2.dist-info}/licenses/LICENSE +0 -0
- {llms_py-3.0.0.dist-info → llms_py-3.0.0b2.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,7 @@ 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))
|
|
121
|
+
console.log(JSON.stringify(o, undefined, 2))
|
|
78
122
|
}
|
|
79
123
|
}
|
|
80
124
|
|
|
@@ -84,114 +128,92 @@ export function deepClone(o) {
|
|
|
84
128
|
|
|
85
129
|
export function toModelInfo(model) {
|
|
86
130
|
if (!model) return undefined
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
props.forEach(k => to[k] = toRaw(model[k]))
|
|
90
|
-
return deepClone(to)
|
|
131
|
+
const { id, name, provider, cost, modalities } = model
|
|
132
|
+
return deepClone({ id, name, provider, cost, modalities })
|
|
91
133
|
}
|
|
92
134
|
|
|
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) {
|
|
135
|
+
const numFmt = new Intl.NumberFormat(undefined, { style: 'currency', currency: 'USD', maximumFractionDigits: 6 })
|
|
136
|
+
export function tokenCost(price) {
|
|
101
137
|
if (!price) return ''
|
|
102
|
-
var ret =
|
|
138
|
+
var ret = numFmt.format(parseFloat(price))
|
|
103
139
|
return ret.endsWith('.00') ? ret.slice(0, -3) : ret
|
|
104
140
|
}
|
|
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
141
|
export function formatCost(cost) {
|
|
111
142
|
if (!cost) return ''
|
|
112
|
-
return
|
|
143
|
+
return numFmt.format(parseFloat(cost))
|
|
113
144
|
}
|
|
114
|
-
export function
|
|
145
|
+
export function statsTitle(stats) {
|
|
115
146
|
let title = []
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
: `${usage.tokens} tokens`
|
|
120
|
-
const duration = usage.duration ? ` in ${usage.duration}ms` : ''
|
|
121
|
-
title.push(msg + duration)
|
|
147
|
+
// Each stat on its own line
|
|
148
|
+
if (stats.cost) {
|
|
149
|
+
title.push(`Total Cost: ${formatCost(stats.cost)}`)
|
|
122
150
|
}
|
|
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()
|
|
151
|
+
if (stats.inputTokens) {
|
|
152
|
+
title.push(`Input Tokens: ${stats.inputTokens}`)
|
|
139
153
|
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
const ret = currFmt6.format(parseFloat(cost))
|
|
143
|
-
return ret.endsWith('.000000') ? ret.slice(0, -7) : ret
|
|
154
|
+
if (stats.outputTokens) {
|
|
155
|
+
title.push(`Output Tokens: ${stats.outputTokens}`)
|
|
144
156
|
}
|
|
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')
|
|
157
|
+
if (stats.requests) {
|
|
158
|
+
title.push(`Requests: ${stats.requests}`)
|
|
164
159
|
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
return new Date(timestamp).toLocaleTimeString([], {
|
|
168
|
-
hour: '2-digit',
|
|
169
|
-
minute: '2-digit'
|
|
170
|
-
})
|
|
160
|
+
if (stats.duration) {
|
|
161
|
+
title.push(`Duration: ${stats.duration}ms`)
|
|
171
162
|
}
|
|
163
|
+
return title.join('\n')
|
|
164
|
+
}
|
|
172
165
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
166
|
+
const svg = {
|
|
167
|
+
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>`,
|
|
168
|
+
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>`,
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function copyBlock(btn) {
|
|
172
|
+
// console.log('copyBlock',btn)
|
|
173
|
+
const label = btn.previousElementSibling
|
|
174
|
+
const code = btn.parentElement.nextElementSibling
|
|
175
|
+
label.classList.remove('hidden')
|
|
176
|
+
label.innerHTML = 'copied'
|
|
177
|
+
btn.classList.add('border-gray-600', 'bg-gray-700')
|
|
178
|
+
btn.classList.remove('border-gray-700')
|
|
179
|
+
btn.innerHTML = svg.check
|
|
180
|
+
navigator.clipboard.writeText(code.innerText)
|
|
181
|
+
setTimeout(() => {
|
|
182
|
+
label.classList.add('hidden')
|
|
183
|
+
label.innerHTML = ''
|
|
184
|
+
btn.innerHTML = svg.clipboard
|
|
185
|
+
btn.classList.remove('border-gray-600', 'bg-gray-700')
|
|
186
|
+
btn.classList.add('border-gray-700')
|
|
187
|
+
}, 2000)
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export function addCopyButtonToCodeBlocks(sel) {
|
|
191
|
+
globalThis.copyBlock ??= copyBlock
|
|
192
|
+
//console.log('addCopyButtonToCodeBlocks', sel, [...$$(sel)].length)
|
|
193
|
+
|
|
194
|
+
$$(sel).forEach(code => {
|
|
195
|
+
let pre = code.parentElement;
|
|
196
|
+
if (pre.classList.contains('group')) return
|
|
197
|
+
pre.classList.add('relative', 'group')
|
|
198
|
+
|
|
199
|
+
const div = createElement('div', { attrs: { className: 'opacity-0 group-hover:opacity-100 transition-opacity duration-100 flex absolute right-2 -mt-1 select-none' } })
|
|
200
|
+
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' } })
|
|
201
|
+
const btn = createElement('button', {
|
|
202
|
+
attrs: {
|
|
203
|
+
type: 'button',
|
|
204
|
+
className: 'p-1 rounded-md border block text-gray-500 hover:text-gray-400 border-gray-700 hover:border-gray-600',
|
|
205
|
+
onclick: 'copyBlock(this)'
|
|
206
|
+
}
|
|
178
207
|
})
|
|
179
|
-
|
|
180
|
-
|
|
208
|
+
btn.innerHTML = svg.clipboard
|
|
209
|
+
div.appendChild(label)
|
|
210
|
+
div.appendChild(btn)
|
|
211
|
+
pre.insertBefore(div, code)
|
|
212
|
+
})
|
|
213
|
+
}
|
|
181
214
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
tokenCost,
|
|
185
|
-
tokenCostLong,
|
|
186
|
-
tokensTitle,
|
|
187
|
-
cost: formatCost,
|
|
188
|
-
costLong,
|
|
189
|
-
statsTitle,
|
|
190
|
-
relativeTime,
|
|
191
|
-
time,
|
|
192
|
-
pluralize,
|
|
193
|
-
shortDate,
|
|
194
|
-
}
|
|
215
|
+
export function addCopyButtons() {
|
|
216
|
+
addCopyButtonToCodeBlocks('.prose pre>code')
|
|
195
217
|
}
|
|
196
218
|
|
|
197
219
|
/**
|
|
@@ -204,21 +226,4 @@ export const nextId = (() => {
|
|
|
204
226
|
last = (now > last) ? now : last + 1
|
|
205
227
|
return last
|
|
206
228
|
}
|
|
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
|
-
|
|
229
|
+
})();
|