llms-py 2.0.20__py3-none-any.whl → 3.0.18__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/__init__.py +3 -1
- llms/db.py +359 -0
- llms/{ui/Analytics.mjs → extensions/analytics/ui/index.mjs} +254 -327
- llms/extensions/app/README.md +20 -0
- llms/extensions/app/__init__.py +588 -0
- llms/extensions/app/db.py +540 -0
- llms/{ui → extensions/app/ui}/Recents.mjs +99 -73
- llms/{ui/Sidebar.mjs → extensions/app/ui/index.mjs} +139 -68
- llms/extensions/app/ui/threadStore.mjs +440 -0
- llms/extensions/computer/README.md +96 -0
- llms/extensions/computer/__init__.py +59 -0
- llms/extensions/computer/base.py +80 -0
- llms/extensions/computer/bash.py +185 -0
- llms/extensions/computer/computer.py +523 -0
- llms/extensions/computer/edit.py +299 -0
- llms/extensions/computer/filesystem.py +542 -0
- llms/extensions/computer/platform.py +461 -0
- llms/extensions/computer/run.py +37 -0
- llms/extensions/core_tools/CALCULATOR.md +32 -0
- llms/extensions/core_tools/__init__.py +599 -0
- llms/extensions/core_tools/ui/codemirror/addon/edit/closebrackets.js +201 -0
- llms/extensions/core_tools/ui/codemirror/addon/edit/closetag.js +185 -0
- llms/extensions/core_tools/ui/codemirror/addon/edit/continuelist.js +101 -0
- llms/extensions/core_tools/ui/codemirror/addon/edit/matchbrackets.js +160 -0
- llms/extensions/core_tools/ui/codemirror/addon/edit/matchtags.js +66 -0
- llms/extensions/core_tools/ui/codemirror/addon/edit/trailingspace.js +27 -0
- llms/extensions/core_tools/ui/codemirror/addon/selection/active-line.js +72 -0
- llms/extensions/core_tools/ui/codemirror/addon/selection/mark-selection.js +119 -0
- llms/extensions/core_tools/ui/codemirror/addon/selection/selection-pointer.js +98 -0
- llms/extensions/core_tools/ui/codemirror/codemirror.css +344 -0
- llms/extensions/core_tools/ui/codemirror/codemirror.js +9884 -0
- llms/extensions/core_tools/ui/codemirror/doc/docs.css +225 -0
- llms/extensions/core_tools/ui/codemirror/doc/source_sans.woff +0 -0
- llms/extensions/core_tools/ui/codemirror/mode/clike/clike.js +942 -0
- llms/extensions/core_tools/ui/codemirror/mode/javascript/index.html +118 -0
- llms/extensions/core_tools/ui/codemirror/mode/javascript/javascript.js +962 -0
- llms/extensions/core_tools/ui/codemirror/mode/javascript/typescript.html +62 -0
- llms/extensions/core_tools/ui/codemirror/mode/python/python.js +402 -0
- llms/extensions/core_tools/ui/codemirror/theme/dracula.css +40 -0
- llms/extensions/core_tools/ui/codemirror/theme/mocha.css +135 -0
- llms/extensions/core_tools/ui/index.mjs +650 -0
- llms/extensions/gallery/README.md +61 -0
- llms/extensions/gallery/__init__.py +63 -0
- llms/extensions/gallery/db.py +243 -0
- llms/extensions/gallery/ui/index.mjs +482 -0
- llms/extensions/katex/README.md +39 -0
- llms/extensions/katex/__init__.py +6 -0
- llms/extensions/katex/ui/README.md +125 -0
- llms/extensions/katex/ui/contrib/auto-render.js +338 -0
- llms/extensions/katex/ui/contrib/auto-render.min.js +1 -0
- llms/extensions/katex/ui/contrib/auto-render.mjs +244 -0
- llms/extensions/katex/ui/contrib/copy-tex.js +127 -0
- llms/extensions/katex/ui/contrib/copy-tex.min.js +1 -0
- llms/extensions/katex/ui/contrib/copy-tex.mjs +105 -0
- llms/extensions/katex/ui/contrib/mathtex-script-type.js +109 -0
- llms/extensions/katex/ui/contrib/mathtex-script-type.min.js +1 -0
- llms/extensions/katex/ui/contrib/mathtex-script-type.mjs +24 -0
- llms/extensions/katex/ui/contrib/mhchem.js +3213 -0
- llms/extensions/katex/ui/contrib/mhchem.min.js +1 -0
- llms/extensions/katex/ui/contrib/mhchem.mjs +3109 -0
- llms/extensions/katex/ui/contrib/render-a11y-string.js +887 -0
- llms/extensions/katex/ui/contrib/render-a11y-string.min.js +1 -0
- llms/extensions/katex/ui/contrib/render-a11y-string.mjs +800 -0
- 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 +92 -0
- llms/extensions/katex/ui/katex-swap.css +1230 -0
- llms/extensions/katex/ui/katex-swap.min.css +1 -0
- llms/extensions/katex/ui/katex.css +1230 -0
- llms/extensions/katex/ui/katex.js +19080 -0
- llms/extensions/katex/ui/katex.min.css +1 -0
- llms/extensions/katex/ui/katex.min.js +1 -0
- llms/extensions/katex/ui/katex.min.mjs +1 -0
- llms/extensions/katex/ui/katex.mjs +18547 -0
- llms/extensions/providers/__init__.py +22 -0
- llms/extensions/providers/anthropic.py +260 -0
- llms/extensions/providers/cerebras.py +36 -0
- llms/extensions/providers/chutes.py +153 -0
- llms/extensions/providers/google.py +559 -0
- llms/extensions/providers/nvidia.py +103 -0
- llms/extensions/providers/openai.py +154 -0
- llms/extensions/providers/openrouter.py +74 -0
- llms/extensions/providers/zai.py +182 -0
- llms/extensions/skills/LICENSE +202 -0
- llms/extensions/skills/__init__.py +130 -0
- llms/extensions/skills/errors.py +25 -0
- llms/extensions/skills/models.py +39 -0
- llms/extensions/skills/parser.py +178 -0
- llms/extensions/skills/ui/index.mjs +376 -0
- llms/extensions/skills/ui/skills/create-plan/SKILL.md +74 -0
- llms/extensions/skills/validator.py +177 -0
- llms/extensions/system_prompts/README.md +22 -0
- llms/extensions/system_prompts/__init__.py +45 -0
- llms/extensions/system_prompts/ui/index.mjs +276 -0
- llms/extensions/system_prompts/ui/prompts.json +1067 -0
- llms/extensions/tools/__init__.py +67 -0
- llms/extensions/tools/ui/index.mjs +837 -0
- llms/index.html +36 -62
- llms/llms.json +180 -879
- llms/main.py +4009 -912
- llms/providers-extra.json +394 -0
- llms/providers.json +1 -0
- llms/ui/App.mjs +176 -8
- llms/ui/ai.mjs +156 -20
- llms/ui/app.css +3768 -321
- llms/ui/ctx.mjs +459 -0
- llms/ui/index.mjs +131 -0
- llms/ui/lib/chart.js +14 -0
- llms/ui/lib/charts.mjs +16 -0
- llms/ui/lib/color.js +14 -0
- llms/ui/lib/highlight.min.mjs +1243 -0
- llms/ui/lib/idb.min.mjs +8 -0
- llms/ui/lib/marked.min.mjs +8 -0
- llms/ui/lib/servicestack-client.mjs +1 -0
- llms/ui/lib/servicestack-vue.mjs +37 -0
- llms/ui/lib/vue-router.min.mjs +6 -0
- llms/ui/lib/vue.min.mjs +13 -0
- llms/ui/lib/vue.mjs +18530 -0
- llms/ui/markdown.mjs +25 -14
- llms/ui/modules/chat/ChatBody.mjs +1156 -0
- llms/ui/{SettingsDialog.mjs → modules/chat/SettingsDialog.mjs} +74 -74
- llms/ui/modules/chat/index.mjs +995 -0
- llms/ui/modules/icons.mjs +46 -0
- llms/ui/modules/layout.mjs +271 -0
- llms/ui/modules/model-selector.mjs +811 -0
- llms/ui/tailwind.input.css +560 -78
- llms/ui/typography.css +54 -36
- llms/ui/utils.mjs +221 -92
- llms_py-3.0.18.dist-info/METADATA +49 -0
- llms_py-3.0.18.dist-info/RECORD +194 -0
- {llms_py-2.0.20.dist-info → llms_py-3.0.18.dist-info}/WHEEL +1 -1
- {llms_py-2.0.20.dist-info → llms_py-3.0.18.dist-info}/licenses/LICENSE +1 -2
- llms/ui/Avatar.mjs +0 -28
- llms/ui/Brand.mjs +0 -34
- llms/ui/ChatPrompt.mjs +0 -443
- llms/ui/Main.mjs +0 -740
- llms/ui/ModelSelector.mjs +0 -60
- llms/ui/ProviderIcon.mjs +0 -29
- llms/ui/ProviderStatus.mjs +0 -105
- llms/ui/SignIn.mjs +0 -64
- llms/ui/SystemPromptEditor.mjs +0 -31
- llms/ui/SystemPromptSelector.mjs +0 -36
- llms/ui/Welcome.mjs +0 -8
- llms/ui/threadStore.mjs +0 -524
- llms/ui.json +0 -1069
- llms_py-2.0.20.dist-info/METADATA +0 -931
- llms_py-2.0.20.dist-info/RECORD +0 -36
- {llms_py-2.0.20.dist-info → llms_py-3.0.18.dist-info}/entry_points.txt +0 -0
- {llms_py-2.0.20.dist-info → llms_py-3.0.18.dist-info}/top_level.txt +0 -0
llms/ui/typography.css
CHANGED
|
@@ -94,16 +94,18 @@
|
|
|
94
94
|
border-left-style: solid;
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
-
.dark .prose :
|
|
97
|
+
.dark .prose :where(td):not(:where([class~="not-prose"] *)) {
|
|
98
98
|
color: rgb(209 213 219); /*text-gray-300*/
|
|
99
99
|
}
|
|
100
100
|
.dark .prose :where(h1,h2,h3,h4,h5,h6,th):not(:where([class~="not-prose"] *)) {
|
|
101
101
|
color: rgb(243 244 246); /*text-gray-100*/
|
|
102
102
|
}
|
|
103
|
-
.dark .prose :where(code):not(:where([class~="not-prose"] *))
|
|
103
|
+
.dark .prose :where(code):not(:where([class~="not-prose"] *)),
|
|
104
|
+
.dark .message em {
|
|
104
105
|
background-color: rgb(30 58 138); /*text-blue-900*/
|
|
105
106
|
color: rgb(243 244 246); /*text-gray-100*/
|
|
106
107
|
}
|
|
108
|
+
|
|
107
109
|
.dark .prose :where(pre code):not(:where([class~="not-prose"] *)) {
|
|
108
110
|
background-color: unset;
|
|
109
111
|
}
|
|
@@ -130,10 +132,6 @@
|
|
|
130
132
|
.not-prose { max-width: unset; }
|
|
131
133
|
.prose-table { max-width: 56rem; width: 56rem; padding-left: 1px; overflow-x: auto; }
|
|
132
134
|
.hide-h2+h2 { display:none }
|
|
133
|
-
.hljs, .prose :where(pre):not(:where([class~="not-prose"] *)) .hljs {
|
|
134
|
-
color: var(--tw-prose-pre-code) !important;
|
|
135
|
-
background-color: var(--tw-prose-pre-bg) !important;
|
|
136
|
-
}
|
|
137
135
|
@media (min-width: 1024px) {
|
|
138
136
|
.lg\:prose-xl {
|
|
139
137
|
font-size: 1.25rem;
|
|
@@ -285,6 +283,12 @@
|
|
|
285
283
|
.prose pre::-webkit-scrollbar-thumb, .prose code::-webkit-scrollbar-thumb {
|
|
286
284
|
background-color: rgb(100 116 139);
|
|
287
285
|
}
|
|
286
|
+
.dark .prose pre::-webkit-scrollbar, .dark .prose code::-webkit-scrollbar {
|
|
287
|
+
background: #111827;
|
|
288
|
+
}
|
|
289
|
+
.dark .prose pre::-webkit-scrollbar-thumb, .dark .prose code::-webkit-scrollbar-thumb {
|
|
290
|
+
background-color: rgb(71 85 105);
|
|
291
|
+
}
|
|
288
292
|
|
|
289
293
|
.html-format {
|
|
290
294
|
max-width: unset;
|
|
@@ -390,6 +394,33 @@ h1:hover .header-anchor, h1 .header-anchor:focus, h2:hover .header-anchor, h2 .h
|
|
|
390
394
|
font-weight: 600;
|
|
391
395
|
}
|
|
392
396
|
|
|
397
|
+
pre {
|
|
398
|
+
overflow-x: auto;
|
|
399
|
+
font-weight: 400;
|
|
400
|
+
font-size: .875em;
|
|
401
|
+
line-height: 1.7142857;
|
|
402
|
+
margin-top: 1.7142857em;
|
|
403
|
+
margin-bottom: 1.7142857em;
|
|
404
|
+
border-radius: .375rem;
|
|
405
|
+
padding: .8571429em 1.1428571em;
|
|
406
|
+
max-width: calc(100vw - 1rem);
|
|
407
|
+
min-width: fit-content;
|
|
408
|
+
background-color: #282c34;
|
|
409
|
+
}
|
|
410
|
+
pre code.hljs {
|
|
411
|
+
display: block;
|
|
412
|
+
overflow-x: auto;
|
|
413
|
+
padding: 1em;
|
|
414
|
+
}
|
|
415
|
+
.message pre {
|
|
416
|
+
max-width: 100%;
|
|
417
|
+
min-width: auto;
|
|
418
|
+
}
|
|
419
|
+
.message pre code.hljs {
|
|
420
|
+
overflow-x: unset;
|
|
421
|
+
width: 100%;
|
|
422
|
+
}
|
|
423
|
+
|
|
393
424
|
/* highlight.js - vs.css */
|
|
394
425
|
.hljs {background:white;color:black}
|
|
395
426
|
.hljs-comment,.hljs-quote,.hljs-variable{color:#008000}
|
|
@@ -413,38 +444,25 @@ pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5p
|
|
|
413
444
|
.hljs-built_in,.hljs-class .hljs-title,.hljs-title.class_{color:#e6c07b}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}
|
|
414
445
|
.hljs-link{text-decoration:underline}
|
|
415
446
|
|
|
416
|
-
/*
|
|
417
|
-
.
|
|
418
|
-
color: #
|
|
419
|
-
|
|
447
|
+
/* Dark mode overrides for Chat-specific styles */
|
|
448
|
+
.dark .prose blockquote {
|
|
449
|
+
border-left-color: #374151;
|
|
450
|
+
color: #9ca3af;
|
|
420
451
|
}
|
|
421
|
-
.
|
|
422
|
-
|
|
452
|
+
.dark .prose th,
|
|
453
|
+
.dark .prose td {
|
|
454
|
+
border-color: #374151;
|
|
423
455
|
}
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
overflow-x: auto;
|
|
427
|
-
font-weight: 400;
|
|
428
|
-
font-size: .875em;
|
|
429
|
-
line-height: 1.7142857;
|
|
430
|
-
margin-top: 1.7142857em;
|
|
431
|
-
margin-bottom: 1.7142857em;
|
|
432
|
-
border-radius: .375rem;
|
|
433
|
-
padding: .8571429em 1.1428571em;
|
|
434
|
-
max-width: calc(100vw - 1rem);
|
|
435
|
-
min-width: fit-content;
|
|
436
|
-
background-color: #282c34 !important;
|
|
456
|
+
.dark .prose th {
|
|
457
|
+
background-color: #1f2937;
|
|
437
458
|
}
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
overflow-x: auto;
|
|
441
|
-
padding: 1em;
|
|
459
|
+
.dark .prose td {
|
|
460
|
+
background-color: #111827;
|
|
442
461
|
}
|
|
443
|
-
.
|
|
444
|
-
|
|
445
|
-
|
|
462
|
+
.hljs-comment, .hljs-quote {
|
|
463
|
+
color: rgb(148 163 184); /*text-slate-400*/
|
|
464
|
+
}
|
|
465
|
+
.dark .prose > pre, .dark .prose pre code.hljs {
|
|
466
|
+
background-color: #111827 !important;
|
|
467
|
+
color: #f3f4f6;
|
|
446
468
|
}
|
|
447
|
-
.message pre code.hljs {
|
|
448
|
-
overflow-x: unset;
|
|
449
|
-
width: 100%;
|
|
450
|
-
}
|
llms/ui/utils.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { toRaw } from "vue"
|
|
2
|
+
import { rightPart, toDate } from "@servicestack/client"
|
|
2
3
|
|
|
3
4
|
export function toJsonArray(json) {
|
|
4
5
|
try {
|
|
@@ -30,127 +31,255 @@ export function storageObject(key, save) {
|
|
|
30
31
|
return toJsonObject(localStorage.getItem(key)) ?? {}
|
|
31
32
|
}
|
|
32
33
|
|
|
33
|
-
export function
|
|
34
|
-
return
|
|
34
|
+
export function fileToBase64(file) {
|
|
35
|
+
return new Promise((resolve, reject) => {
|
|
36
|
+
const reader = new FileReader()
|
|
37
|
+
reader.readAsDataURL(file) //= "data:…;base64,…"
|
|
38
|
+
reader.onload = () => {
|
|
39
|
+
resolve(rightPart(reader.result, ',')) // strip prefix
|
|
40
|
+
}
|
|
41
|
+
reader.onerror = err => reject(err)
|
|
42
|
+
})
|
|
35
43
|
}
|
|
36
44
|
|
|
37
|
-
export function
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
45
|
+
export function fileToDataUri(file) {
|
|
46
|
+
return new Promise((resolve, reject) => {
|
|
47
|
+
const reader = new FileReader()
|
|
48
|
+
reader.readAsDataURL(file) //= "data:…;base64,…"
|
|
49
|
+
reader.onload = () => resolve(reader.result)
|
|
50
|
+
reader.onerror = err => reject(err)
|
|
51
|
+
})
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function serializedClone(obj) {
|
|
55
|
+
try {
|
|
56
|
+
return JSON.parse(JSON.stringify(obj))
|
|
57
|
+
} catch (e) {
|
|
58
|
+
console.warn('Deep cloning failed, returning original value:', e)
|
|
59
|
+
return obj
|
|
43
60
|
}
|
|
44
|
-
reader.onerror = err => reject(err)
|
|
45
|
-
})
|
|
46
61
|
}
|
|
47
62
|
|
|
48
|
-
export function
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
63
|
+
export function deepClone(o) {
|
|
64
|
+
if (o === null || typeof o !== 'object') return o
|
|
65
|
+
|
|
66
|
+
// Handle Array objects
|
|
67
|
+
if (Array.isArray(o)) {
|
|
68
|
+
return o.map(x => deepClone(x))
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (typeof structuredClone === 'function') { // available (modern browsers, Node.js 17+)
|
|
72
|
+
try {
|
|
73
|
+
return structuredClone(o)
|
|
74
|
+
} catch (e) {
|
|
75
|
+
console.warn('structuredClone failed, falling back to JSON:', e)
|
|
76
|
+
console.log(o)
|
|
77
|
+
// console.log(JSON.stringify(o, undefined, 2))
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Fallback to JSON stringify/parse for older environments
|
|
82
|
+
return serializedClone(o)
|
|
55
83
|
}
|
|
56
84
|
|
|
57
85
|
export function toModelInfo(model) {
|
|
58
86
|
if (!model) return undefined
|
|
59
|
-
|
|
87
|
+
const props = ['id', 'name', 'provider', 'cost', 'modalities']
|
|
88
|
+
const to = {}
|
|
89
|
+
props.forEach(k => to[k] = toRaw(model[k]))
|
|
90
|
+
return deepClone(to)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function pluralize(word, count) {
|
|
94
|
+
return count === 1 ? word : word + 's'
|
|
60
95
|
}
|
|
61
96
|
|
|
62
|
-
const
|
|
63
|
-
|
|
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 = 1000000) {
|
|
64
101
|
if (!price) return ''
|
|
65
|
-
var ret =
|
|
102
|
+
var ret = currFmt2.format(parseFloat(price) * (tokens / 1000000))
|
|
66
103
|
return ret.endsWith('.00') ? ret.slice(0, -3) : ret
|
|
67
104
|
}
|
|
105
|
+
export function tokenCostLong(price, tokens = 1000000) {
|
|
106
|
+
if (!price) return ''
|
|
107
|
+
const ret = currFmt6.format(parseFloat(price) * (tokens / 1000000))
|
|
108
|
+
return ret.endsWith('.000000') ? ret.slice(0, -7) : ret
|
|
109
|
+
}
|
|
68
110
|
export function formatCost(cost) {
|
|
69
111
|
if (!cost) return ''
|
|
70
|
-
return
|
|
112
|
+
return currFmt2.format(parseFloat(cost))
|
|
71
113
|
}
|
|
72
|
-
export function
|
|
114
|
+
export function tokensTitle(usage) {
|
|
73
115
|
let title = []
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
116
|
+
if (usage.tokens && usage.price) {
|
|
117
|
+
const msg = parseFloat(usage.price) > 0
|
|
118
|
+
? `${usage.tokens} tokens @ ${usage.price} = ${tokenCostLong(usage.price, usage.tokens)}`
|
|
119
|
+
: `${usage.tokens} tokens`
|
|
120
|
+
const duration = usage.duration ? ` in ${usage.duration}ms` : ''
|
|
121
|
+
title.push(msg + duration)
|
|
122
|
+
}
|
|
123
|
+
return title.join('\n')
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
// Accessible in views via $fmt
|
|
128
|
+
export function utilsFormatters() {
|
|
129
|
+
function relativeTime(timestamp) {
|
|
130
|
+
const now = new Date()
|
|
131
|
+
const date = new Date(timestamp)
|
|
132
|
+
const diffInSeconds = Math.floor((now - date) / 1000)
|
|
133
|
+
|
|
134
|
+
if (diffInSeconds < 60) return 'Just now'
|
|
135
|
+
if (diffInSeconds < 3600) return `${Math.floor(diffInSeconds / 60)}m ago`
|
|
136
|
+
if (diffInSeconds < 86400) return `${Math.floor(diffInSeconds / 3600)}h ago`
|
|
137
|
+
if (diffInSeconds < 604800) return `${Math.floor(diffInSeconds / 86400)}d ago`
|
|
138
|
+
|
|
139
|
+
return date.toLocaleDateString()
|
|
77
140
|
}
|
|
78
|
-
|
|
79
|
-
|
|
141
|
+
function costLong(cost) {
|
|
142
|
+
if (!cost) return ''
|
|
143
|
+
const ret = currFmt6.format(parseFloat(cost))
|
|
144
|
+
return ret.endsWith('.000000') ? ret.slice(0, -7) : ret
|
|
80
145
|
}
|
|
81
|
-
|
|
82
|
-
title
|
|
146
|
+
function statsTitle(stats) {
|
|
147
|
+
let title = []
|
|
148
|
+
// Each stat on its own line
|
|
149
|
+
if (stats.cost) {
|
|
150
|
+
title.push(`Total Cost: ${costLong(stats.cost)}`)
|
|
151
|
+
}
|
|
152
|
+
if (stats.inputTokens) {
|
|
153
|
+
title.push(`Input Tokens: ${stats.inputTokens}`)
|
|
154
|
+
}
|
|
155
|
+
if (stats.outputTokens) {
|
|
156
|
+
title.push(`Output Tokens: ${stats.outputTokens}`)
|
|
157
|
+
}
|
|
158
|
+
if (stats.requests) {
|
|
159
|
+
title.push(`Requests: ${stats.requests}`)
|
|
160
|
+
}
|
|
161
|
+
if (stats.duration) {
|
|
162
|
+
title.push(`Duration: ${stats.duration}ms`)
|
|
163
|
+
}
|
|
164
|
+
return title.join('\n')
|
|
83
165
|
}
|
|
84
|
-
|
|
85
|
-
|
|
166
|
+
|
|
167
|
+
function time(timestamp) {
|
|
168
|
+
return new Date(timestamp).toLocaleTimeString([], {
|
|
169
|
+
hour: '2-digit',
|
|
170
|
+
minute: '2-digit'
|
|
171
|
+
})
|
|
86
172
|
}
|
|
87
|
-
|
|
88
|
-
|
|
173
|
+
|
|
174
|
+
function shortDate(ts) {
|
|
175
|
+
if (!ts) return ''
|
|
176
|
+
const date = typeof ts === 'number' ? new Date(ts * 1000) : new Date(ts)
|
|
177
|
+
return date.toLocaleDateString(undefined, {
|
|
178
|
+
month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit'
|
|
179
|
+
})
|
|
89
180
|
}
|
|
90
|
-
return title.join('\n')
|
|
91
|
-
}
|
|
92
181
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
function copyBlock(btn) {
|
|
99
|
-
// console.log('copyBlock',btn)
|
|
100
|
-
const label = btn.previousElementSibling
|
|
101
|
-
const code = btn.parentElement.nextElementSibling
|
|
102
|
-
label.classList.remove('hidden')
|
|
103
|
-
label.innerHTML = 'copied'
|
|
104
|
-
btn.classList.add('border-gray-600', 'bg-gray-700')
|
|
105
|
-
btn.classList.remove('border-gray-700')
|
|
106
|
-
btn.innerHTML = svg.check
|
|
107
|
-
navigator.clipboard.writeText(code.innerText)
|
|
108
|
-
setTimeout(() => {
|
|
109
|
-
label.classList.add('hidden')
|
|
110
|
-
label.innerHTML = ''
|
|
111
|
-
btn.innerHTML = svg.clipboard
|
|
112
|
-
btn.classList.remove('border-gray-600', 'bg-gray-700')
|
|
113
|
-
btn.classList.add('border-gray-700')
|
|
114
|
-
}, 2000)
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
export function addCopyButtonToCodeBlocks(sel) {
|
|
118
|
-
globalThis.copyBlock ??= copyBlock
|
|
119
|
-
//console.log('addCopyButtonToCodeBlocks', sel, [...$$(sel)].length)
|
|
120
|
-
|
|
121
|
-
$$(sel).forEach(code => {
|
|
122
|
-
let pre = code.parentElement;
|
|
123
|
-
if (pre.classList.contains('group')) return
|
|
124
|
-
pre.classList.add('relative', 'group')
|
|
125
|
-
|
|
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'}})
|
|
128
|
-
const btn = createElement('button', {
|
|
129
|
-
attrs: {
|
|
130
|
-
type: 'button',
|
|
131
|
-
className: 'p-1 rounded-md border block text-gray-500 hover:text-gray-400 border-gray-700 hover:border-gray-600',
|
|
132
|
-
onclick: 'copyBlock(this)'
|
|
133
|
-
}
|
|
182
|
+
function date(d) {
|
|
183
|
+
date = toDate(d)
|
|
184
|
+
return date.toLocaleDateString(undefined, {
|
|
185
|
+
month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit'
|
|
134
186
|
})
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
return {
|
|
191
|
+
currFmt: currFmt2,
|
|
192
|
+
tokenCost,
|
|
193
|
+
tokenCostLong,
|
|
194
|
+
tokensTitle,
|
|
195
|
+
cost: formatCost,
|
|
196
|
+
costLong,
|
|
197
|
+
statsTitle,
|
|
198
|
+
relativeTime,
|
|
199
|
+
time,
|
|
200
|
+
pluralize,
|
|
201
|
+
shortDate,
|
|
202
|
+
date,
|
|
203
|
+
}
|
|
140
204
|
}
|
|
141
205
|
|
|
142
|
-
|
|
143
|
-
|
|
206
|
+
const htmlStartTags = ['<!doctype', '<html', '<head', '<body', '<script', '<style', '<link']
|
|
207
|
+
export function isHtml(s) {
|
|
208
|
+
if (!s || typeof s != 'string') return false
|
|
209
|
+
const lower = s.toLowerCase().trim()
|
|
210
|
+
const isHtml = htmlStartTags.some(tag => lower.startsWith(tag))
|
|
211
|
+
return isHtml
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const htmlEntities = {
|
|
215
|
+
'&': '&',
|
|
216
|
+
'<': '<',
|
|
217
|
+
'>': '>',
|
|
218
|
+
'"': '"',
|
|
219
|
+
"'": '''
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
export function encodeHtml(str) {
|
|
223
|
+
if (!str) return ''
|
|
224
|
+
return str.replace(/[&<>"']/g, m => htmlEntities[m]);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* @param {object|array} type
|
|
229
|
+
* @param {'div'|'table'|'thead'|'th'|'tr'|'td'} tag
|
|
230
|
+
* @param {number} depth
|
|
231
|
+
* @param {string} cls
|
|
232
|
+
* @param {number} index
|
|
233
|
+
*/
|
|
234
|
+
function htmlFormatClasses(type, tag, depth, cls, index) {
|
|
235
|
+
cls = cls.replace('shadow ring-1 ring-black/5 md:rounded-lg', '')
|
|
236
|
+
if (tag == 'th') {
|
|
237
|
+
cls += ' lowercase'
|
|
238
|
+
}
|
|
239
|
+
if (tag == 'td') {
|
|
240
|
+
cls += ' whitespace-pre-wrap'
|
|
241
|
+
}
|
|
242
|
+
return cls
|
|
144
243
|
}
|
|
145
244
|
|
|
146
245
|
/**
|
|
147
246
|
* Returns an ever-increasing unique integer id.
|
|
148
247
|
*/
|
|
149
248
|
export const nextId = (() => {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
})();
|
|
249
|
+
let last = 0 // cache of the last id that was handed out
|
|
250
|
+
return () => {
|
|
251
|
+
const now = Date.now() // current millisecond timestamp
|
|
252
|
+
last = (now > last) ? now : last + 1
|
|
253
|
+
return last
|
|
254
|
+
}
|
|
255
|
+
})();
|
|
256
|
+
|
|
257
|
+
export function fnv1a(str) {
|
|
258
|
+
let hash = 0x811c9dc5
|
|
259
|
+
for (let i = 0; i < str.length; i++) {
|
|
260
|
+
hash ^= str.charCodeAt(i)
|
|
261
|
+
hash = Math.imul(hash, 0x01000193)
|
|
262
|
+
}
|
|
263
|
+
return hash >>> 0
|
|
264
|
+
}
|
|
265
|
+
export const hashString = fnv1a
|
|
266
|
+
|
|
267
|
+
export function utilsFunctions() {
|
|
268
|
+
return {
|
|
269
|
+
nextId,
|
|
270
|
+
toJsonArray,
|
|
271
|
+
toJsonObject,
|
|
272
|
+
storageArray,
|
|
273
|
+
storageObject,
|
|
274
|
+
fileToBase64,
|
|
275
|
+
fileToDataUri,
|
|
276
|
+
serializedClone,
|
|
277
|
+
deepClone,
|
|
278
|
+
toModelInfo,
|
|
279
|
+
pluralize,
|
|
280
|
+
isHtml,
|
|
281
|
+
htmlFormatClasses,
|
|
282
|
+
encodeHtml,
|
|
283
|
+
hashString,
|
|
284
|
+
}
|
|
285
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: llms-py
|
|
3
|
+
Version: 3.0.18
|
|
4
|
+
Summary: A lightweight CLI tool and OpenAI-compatible server for querying multiple Large Language Model (LLM) providers
|
|
5
|
+
Home-page: https://github.com/ServiceStack/llms
|
|
6
|
+
Author: ServiceStack
|
|
7
|
+
Author-email: ServiceStack <team@servicestack.net>
|
|
8
|
+
Maintainer-email: ServiceStack <team@servicestack.net>
|
|
9
|
+
License-Expression: BSD-3-Clause
|
|
10
|
+
Project-URL: Homepage, https://github.com/ServiceStack/llms
|
|
11
|
+
Project-URL: Documentation, https://github.com/ServiceStack/llms#readme
|
|
12
|
+
Project-URL: Repository, https://github.com/ServiceStack/llms
|
|
13
|
+
Project-URL: Bug Reports, https://github.com/ServiceStack/llms/issues
|
|
14
|
+
Keywords: llm,ai,openai,anthropic,google,gemini,groq,mistral,ollama,cli,server,chat,completion
|
|
15
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
16
|
+
Classifier: Intended Audience :: Developers
|
|
17
|
+
Classifier: Intended Audience :: System Administrators
|
|
18
|
+
Classifier: Operating System :: OS Independent
|
|
19
|
+
Classifier: Programming Language :: Python :: 3
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
26
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
27
|
+
Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers
|
|
28
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
29
|
+
Classifier: Topic :: System :: Systems Administration
|
|
30
|
+
Classifier: Topic :: Utilities
|
|
31
|
+
Classifier: Environment :: Console
|
|
32
|
+
Requires-Python: >=3.7
|
|
33
|
+
Description-Content-Type: text/markdown
|
|
34
|
+
License-File: LICENSE
|
|
35
|
+
Requires-Dist: aiohttp
|
|
36
|
+
Dynamic: author
|
|
37
|
+
Dynamic: home-page
|
|
38
|
+
Dynamic: license-file
|
|
39
|
+
Dynamic: requires-python
|
|
40
|
+
|
|
41
|
+
# llms.py
|
|
42
|
+
|
|
43
|
+
Lightweight CLI, API and ChatGPT-like alternative to Open WebUI for accessing multiple LLMs, entirely offline, with all data kept private in browser storage.
|
|
44
|
+
|
|
45
|
+
[llmspy.org](https://llmspy.org)
|
|
46
|
+
|
|
47
|
+
[](https://llmspy.org)
|
|
48
|
+
|
|
49
|
+
GitHub: [llmspy.org](https://github.com/ServiceStack/llmspy.org)
|