llms-py 3.0.0b1__py3-none-any.whl → 3.0.0b3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. llms/__pycache__/__init__.cpython-312.pyc +0 -0
  2. llms/__pycache__/__init__.cpython-313.pyc +0 -0
  3. llms/__pycache__/__init__.cpython-314.pyc +0 -0
  4. llms/__pycache__/__main__.cpython-312.pyc +0 -0
  5. llms/__pycache__/__main__.cpython-314.pyc +0 -0
  6. llms/__pycache__/llms.cpython-312.pyc +0 -0
  7. llms/__pycache__/main.cpython-312.pyc +0 -0
  8. llms/__pycache__/main.cpython-313.pyc +0 -0
  9. llms/__pycache__/main.cpython-314.pyc +0 -0
  10. llms/__pycache__/plugins.cpython-314.pyc +0 -0
  11. llms/index.html +27 -57
  12. llms/llms.json +48 -15
  13. llms/main.py +923 -624
  14. llms/providers/__pycache__/anthropic.cpython-314.pyc +0 -0
  15. llms/providers/__pycache__/chutes.cpython-314.pyc +0 -0
  16. llms/providers/__pycache__/google.cpython-314.pyc +0 -0
  17. llms/providers/__pycache__/nvidia.cpython-314.pyc +0 -0
  18. llms/providers/__pycache__/openai.cpython-314.pyc +0 -0
  19. llms/providers/__pycache__/openrouter.cpython-314.pyc +0 -0
  20. llms/providers/anthropic.py +189 -0
  21. llms/providers/chutes.py +152 -0
  22. llms/providers/google.py +306 -0
  23. llms/providers/nvidia.py +107 -0
  24. llms/providers/openai.py +159 -0
  25. llms/providers/openrouter.py +70 -0
  26. llms/providers-extra.json +356 -0
  27. llms/providers.json +1 -1
  28. llms/ui/App.mjs +150 -57
  29. llms/ui/ai.mjs +84 -50
  30. llms/ui/app.css +1 -4963
  31. llms/ui/ctx.mjs +196 -0
  32. llms/ui/index.mjs +117 -0
  33. llms/ui/lib/charts.mjs +9 -13
  34. llms/ui/markdown.mjs +6 -0
  35. llms/ui/{Analytics.mjs → modules/analytics.mjs} +76 -64
  36. llms/ui/{Main.mjs → modules/chat/ChatBody.mjs} +91 -179
  37. llms/ui/{SettingsDialog.mjs → modules/chat/SettingsDialog.mjs} +8 -8
  38. llms/ui/{ChatPrompt.mjs → modules/chat/index.mjs} +281 -96
  39. llms/ui/modules/layout.mjs +267 -0
  40. llms/ui/modules/model-selector.mjs +851 -0
  41. llms/ui/{Recents.mjs → modules/threads/Recents.mjs} +10 -11
  42. llms/ui/{Sidebar.mjs → modules/threads/index.mjs} +48 -45
  43. llms/ui/{threadStore.mjs → modules/threads/threadStore.mjs} +21 -7
  44. llms/ui/tailwind.input.css +441 -79
  45. llms/ui/utils.mjs +83 -123
  46. {llms_py-3.0.0b1.dist-info → llms_py-3.0.0b3.dist-info}/METADATA +1 -1
  47. llms_py-3.0.0b3.dist-info/RECORD +65 -0
  48. llms/ui/Avatar.mjs +0 -85
  49. llms/ui/Brand.mjs +0 -52
  50. llms/ui/ModelSelector.mjs +0 -693
  51. llms/ui/OAuthSignIn.mjs +0 -92
  52. llms/ui/ProviderIcon.mjs +0 -36
  53. llms/ui/ProviderStatus.mjs +0 -105
  54. llms/ui/SignIn.mjs +0 -64
  55. llms/ui/SystemPromptEditor.mjs +0 -31
  56. llms/ui/SystemPromptSelector.mjs +0 -56
  57. llms/ui/Welcome.mjs +0 -8
  58. llms/ui.json +0 -1069
  59. llms_py-3.0.0b1.dist-info/RECORD +0 -49
  60. {llms_py-3.0.0b1.dist-info → llms_py-3.0.0b3.dist-info}/WHEEL +0 -0
  61. {llms_py-3.0.0b1.dist-info → llms_py-3.0.0b3.dist-info}/entry_points.txt +0 -0
  62. {llms_py-3.0.0b1.dist-info → llms_py-3.0.0b3.dist-info}/licenses/LICENSE +0 -0
  63. {llms_py-3.0.0b1.dist-info → llms_py-3.0.0b3.dist-info}/top_level.txt +0 -0
llms/ui/utils.mjs CHANGED
@@ -1,37 +1,4 @@
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
- }
1
+ import { rightPart } from "@servicestack/client"
35
2
 
36
3
  export function toJsonArray(json) {
37
4
  try {
@@ -83,19 +50,6 @@ export function fileToDataUri(file) {
83
50
  })
84
51
  }
85
52
 
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
-
99
53
  export function serializedClone(obj) {
100
54
  try {
101
55
  return JSON.parse(JSON.stringify(obj))
@@ -105,6 +59,7 @@ export function serializedClone(obj) {
105
59
  }
106
60
  }
107
61
 
62
+
108
63
  export function deepClone(o) {
109
64
  if (o === null || typeof o !== 'object') return o
110
65
 
@@ -118,6 +73,7 @@ export function deepClone(o) {
118
73
  return structuredClone(o)
119
74
  } catch (e) {
120
75
  console.warn('structuredClone failed, falling back to JSON:', e)
76
+ console.log(JSON.stringify(o, undefined, 2))
121
77
  }
122
78
  }
123
79
 
@@ -125,94 +81,82 @@ export function deepClone(o) {
125
81
  return serializedClone(o)
126
82
  }
127
83
 
128
- export function toModelInfo(model) {
129
- if (!model) return undefined
130
- const { id, name, provider, cost, modalities } = model
131
- return deepClone({ id, name, provider, cost, modalities })
132
- }
84
+ const currFmt2 = new Intl.NumberFormat(undefined, { style: 'currency', currency: 'USD', maximumFractionDigits: 2 })
85
+ const currFmt6 = new Intl.NumberFormat(undefined, { style: 'currency', currency: 'USD', maximumFractionDigits: 6 })
133
86
 
134
- const numFmt = new Intl.NumberFormat(undefined, { style: 'currency', currency: 'USD', maximumFractionDigits: 6 })
135
- export function tokenCost(price) {
87
+ export function tokenCost(price, tokens = 1) {
136
88
  if (!price) return ''
137
- var ret = numFmt.format(parseFloat(price))
89
+ var ret = currFmt2.format(parseFloat(price) * tokens)
138
90
  return ret.endsWith('.00') ? ret.slice(0, -3) : ret
139
91
  }
92
+ export function tokenCostLong(price, tokens = 1) {
93
+ if (!price) return ''
94
+ const ret = currFmt6.format(parseFloat(price) * tokens)
95
+ return ret.endsWith('.000000') ? ret.slice(0, -7) : ret
96
+ }
140
97
  export function formatCost(cost) {
141
98
  if (!cost) return ''
142
- return numFmt.format(parseFloat(cost))
99
+ return currFmt2.format(parseFloat(cost))
143
100
  }
144
- export function statsTitle(stats) {
145
- let title = []
146
- // Each stat on its own line
147
- if (stats.cost) {
148
- title.push(`Total Cost: ${formatCost(stats.cost)}`)
149
- }
150
- if (stats.inputTokens) {
151
- title.push(`Input Tokens: ${stats.inputTokens}`)
152
- }
153
- if (stats.outputTokens) {
154
- title.push(`Output Tokens: ${stats.outputTokens}`)
101
+
102
+ // Accessible in views via $fmt
103
+ export function utilsFormatters() {
104
+ function relativeTime(timestamp) {
105
+ const now = new Date()
106
+ const date = new Date(timestamp)
107
+ const diffInSeconds = Math.floor((now - date) / 1000)
108
+
109
+ if (diffInSeconds < 60) return 'Just now'
110
+ if (diffInSeconds < 3600) return `${Math.floor(diffInSeconds / 60)}m ago`
111
+ if (diffInSeconds < 86400) return `${Math.floor(diffInSeconds / 3600)}h ago`
112
+ if (diffInSeconds < 604800) return `${Math.floor(diffInSeconds / 86400)}d ago`
113
+
114
+ return date.toLocaleDateString()
155
115
  }
156
- if (stats.requests) {
157
- title.push(`Requests: ${stats.requests}`)
116
+ function costLong(cost) {
117
+ if (!cost) return ''
118
+ const ret = currFmt6.format(parseFloat(cost))
119
+ return ret.endsWith('.000000') ? ret.slice(0, -7) : ret
158
120
  }
159
- if (stats.duration) {
160
- title.push(`Duration: ${stats.duration}ms`)
121
+ function statsTitle(stats) {
122
+ let title = []
123
+ // Each stat on its own line
124
+ if (stats.cost) {
125
+ title.push(`Total Cost: ${costLong(stats.cost)}`)
126
+ }
127
+ if (stats.inputTokens) {
128
+ title.push(`Input Tokens: ${stats.inputTokens}`)
129
+ }
130
+ if (stats.outputTokens) {
131
+ title.push(`Output Tokens: ${stats.outputTokens}`)
132
+ }
133
+ if (stats.requests) {
134
+ title.push(`Requests: ${stats.requests}`)
135
+ }
136
+ if (stats.duration) {
137
+ title.push(`Duration: ${stats.duration}ms`)
138
+ }
139
+ return title.join('\n')
161
140
  }
162
- return title.join('\n')
163
- }
164
-
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
141
 
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
- }
142
+ function time(timestamp) {
143
+ return new Date(timestamp).toLocaleTimeString([], {
144
+ hour: '2-digit',
145
+ minute: '2-digit'
206
146
  })
207
- btn.innerHTML = svg.clipboard
208
- div.appendChild(label)
209
- div.appendChild(btn)
210
- pre.insertBefore(div, code)
211
- })
212
- }
147
+ }
148
+
213
149
 
214
- export function addCopyButtons() {
215
- addCopyButtonToCodeBlocks('.prose pre>code')
150
+ return {
151
+ currFmt: currFmt2,
152
+ tokenCost,
153
+ tokenCostLong,
154
+ cost: formatCost,
155
+ costLong,
156
+ statsTitle,
157
+ relativeTime,
158
+ time,
159
+ }
216
160
  }
217
161
 
218
162
  /**
@@ -225,4 +169,20 @@ export const nextId = (() => {
225
169
  last = (now > last) ? now : last + 1
226
170
  return last
227
171
  }
228
- })();
172
+ })();
173
+
174
+ export function utilsFunctions() {
175
+ return {
176
+ nextId,
177
+ deepClone,
178
+ toJsonArray,
179
+ toJsonObject,
180
+ storageArray,
181
+ storageObject,
182
+ fileToBase64,
183
+ fileToDataUri,
184
+ serializedClone,
185
+ deepClone,
186
+ }
187
+ }
188
+
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: llms-py
3
- Version: 3.0.0b1
3
+ Version: 3.0.0b3
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
@@ -0,0 +1,65 @@
1
+ llms/__init__.py,sha256=DKwTZDsyYL_wHe7yvLw49Nf8PSgPSyWaeVdotUqSvrQ,84
2
+ llms/__main__.py,sha256=hrBulHIt3lmPm1BCyAEVtB6DQ0Hvc3gnIddhHCmJasg,151
3
+ llms/index.html,sha256=gABCGg8ALHyB8OSH745HXx7U0SrXuNtJry9buUbVDik,2117
4
+ llms/llms.json,sha256=j7CmFdMpzNeo0nCPHHR4djYfzH_AFKKYIAH3cL3TKT8,10641
5
+ llms/main.py,sha256=7Ih99-KuA6fBmrytED6099YFORUVDARWXav2p4bLDOk,124887
6
+ llms/providers-extra.json,sha256=w7_5gB0YUPK0PJNeViM7vRDfNGChXUKMHfGHenVxEkM,10165
7
+ llms/providers.json,sha256=x9Y_17h0aqeFMn3pnbjcZ5SW-RJyxHXH8ZjsUQ3L8aA,253843
8
+ llms/__pycache__/__init__.cpython-312.pyc,sha256=lg2oFc0aKgj536NOJxcIpbCpEWi47ptF8NufPphgUUk,204
9
+ llms/__pycache__/__init__.cpython-313.pyc,sha256=DvmykIYAjV4Xjv5NeC70BA0JIX8qtwEWP2dfzmOBrps,173
10
+ llms/__pycache__/__init__.cpython-314.pyc,sha256=9CxeBz41D_-ezno6pIOsnoMAFzdRX2uZjKkBLUm25RQ,206
11
+ llms/__pycache__/__main__.cpython-312.pyc,sha256=fcu9LVl5nfdSzg9HqoKyDGoDvENeIXKkjygN7FENEGE,321
12
+ llms/__pycache__/__main__.cpython-314.pyc,sha256=IFxtGVpJq_3whKuM5Ln7YMweKFNbHVp8M7VSrLK5h2A,324
13
+ llms/__pycache__/llms.cpython-312.pyc,sha256=S5dFI79JdUe2dQW4ogdB-CCNhudQeFaFGcfKxgJGBms,72080
14
+ llms/__pycache__/main.cpython-312.pyc,sha256=HrqApYAiiBmYN73HIx_Hl2-Xm1Gy7I_0zuR5j86qoRM,104940
15
+ llms/__pycache__/main.cpython-313.pyc,sha256=6NQ__SJ2rC9ItFLKLHL5ewb5RqxLzZabwgczA9wZd-w,74814
16
+ llms/__pycache__/main.cpython-314.pyc,sha256=MYiVCsD1BdoR2lyKK-jmGtT0Y9O_3E7rfPaqJp04CnI,161849
17
+ llms/__pycache__/plugins.cpython-314.pyc,sha256=fer8nTkidG_vQSx80tL2bAvMS0opDom93bewjseFcyg,3560
18
+ llms/providers/anthropic.py,sha256=KBwIPkGFkNCJxlLAY5MzFpEj7AB4d0WwpaOfZfvCrk0,8091
19
+ llms/providers/chutes.py,sha256=TTDfWviHOoNfk2cXnY5UJK_fciRJ2drfz48u67TDmCM,6171
20
+ llms/providers/google.py,sha256=aK9t7iPLmziUx7q6blF_G2MQUHFA1h8t461euxWWtVc,15104
21
+ llms/providers/nvidia.py,sha256=HRcI1-fgMGq5_9s6br9YHVVOIaXRtOGCgUPSCHXB-_0,4355
22
+ llms/providers/openai.py,sha256=zQqxXyF9v7CplmzebFIXd-Xfj7AcP_bIK6G8fPZh2p8,6355
23
+ llms/providers/openrouter.py,sha256=unXvR2KMsosWJe8_7k-JhDM8V_XtVUtnNO2psgtkTNk,3055
24
+ llms/providers/__pycache__/anthropic.cpython-314.pyc,sha256=tRLB3xJoPi0dLXY85JgXcD_DHIwhBcScx08NiHTiwdw,9158
25
+ llms/providers/__pycache__/chutes.cpython-314.pyc,sha256=TFAoyWV3rwvmcVi17ACgdqPY0Vh_kITFJ-IOGAtZp8w,7404
26
+ llms/providers/__pycache__/google.cpython-314.pyc,sha256=mprVq3i-Ma9La9EgUcUh7AXUaPWTBn6STM-w2LZN2Tc,13858
27
+ llms/providers/__pycache__/nvidia.cpython-314.pyc,sha256=pE2P5sz0EjRp3DYy-MiEAf_kq3Ns03Q0f-DQGa8UOXQ,6155
28
+ llms/providers/__pycache__/openai.cpython-314.pyc,sha256=-OnbDtGalUx3NtRU_sAwRL_TvrnKOworTliwS164IUY,8705
29
+ llms/providers/__pycache__/openrouter.cpython-314.pyc,sha256=5zAegKxy40P1uX87T9KhaE5s54UXSq9fjsG0i2n84tc,5078
30
+ llms/ui/App.mjs,sha256=W_rDLlK26t-GbKxSxh5X8727FDaOt7_rPTWnaVw7Cq0,7174
31
+ llms/ui/ai.mjs,sha256=sOzBWe2wpNC7jNI4qZJUp7PsyoT0Wj2awJ2L0nfVvDA,5315
32
+ llms/ui/app.css,sha256=11ENCAUhHgC6wuzHccryCaQseZEOjpdh-c_kLDdIAIo,84747
33
+ llms/ui/ctx.mjs,sha256=p-GEB9rBlU5Vag84dDN0b-4YUJ0jBxqJQPEVGVarj9E,6134
34
+ llms/ui/fav.svg,sha256=_R6MFeXl6wBFT0lqcUxYQIDWgm246YH_3hSTW0oO8qw,734
35
+ llms/ui/index.mjs,sha256=J5g0JXuKeMwS65xr6mMivqUeEtojcQV2hsp5QCqcI4U,3820
36
+ llms/ui/markdown.mjs,sha256=WcYnT7xZFOc-TXbghVGSBjQJdLGTXq9vZ1LEIaYdcao,6611
37
+ llms/ui/tailwind.input.css,sha256=5PiDdc5nyPE9Fheg_PgLnz3RR3C0o5x6M3M-KWVFo-4,14403
38
+ llms/ui/typography.css,sha256=6o7pbMIamRVlm2GfzSStpcOG4T5eFCK_WcQ3RIHKAsU,19587
39
+ llms/ui/utils.mjs,sha256=RN7vYsN-rlaVUzIY91yly9seCeA9V9dtXmEtKzcb9Bs,5276
40
+ llms/ui/lib/chart.js,sha256=dx8FdDX0Rv6OZtZjr9FQh5h-twFsKjfnb-FvFlQ--cU,196176
41
+ llms/ui/lib/charts.mjs,sha256=OPFAifcA4MPRv8pw6I7glVh7Xccv8guio0k35zPBDIY,926
42
+ llms/ui/lib/color.js,sha256=DDG7Pr-qzJHTPISZNSqP_qJR8UflKHEc_56n6xrBugQ,8273
43
+ llms/ui/lib/highlight.min.mjs,sha256=sG7wq8bF-IKkfie7S4QSyh5DdHBRf0NqQxMOEH8-MT0,127458
44
+ llms/ui/lib/idb.min.mjs,sha256=CeTXyV4I_pB5vnibvJuyXdMs0iVF2ZL0Z7cdm3w_QaI,3853
45
+ llms/ui/lib/marked.min.mjs,sha256=QRHb_VZugcBJRD2EP6gYlVFEsJw5C2fQ8ImMf_pA2_s,39488
46
+ llms/ui/lib/servicestack-client.mjs,sha256=UVafVbzhJ_0N2lzv7rlzIbzwnWpoqXxGk3N3FSKgOOc,54534
47
+ llms/ui/lib/servicestack-vue.mjs,sha256=unTA8lM0tKy2PwZiJ8UEvrTuGmei8jNZnmmuQ5MKyV4,216753
48
+ llms/ui/lib/vue-router.min.mjs,sha256=fR30GHoXI1u81zyZ26YEU105pZgbbAKSXbpnzFKIxls,30418
49
+ llms/ui/lib/vue.min.mjs,sha256=iXh97m5hotl0eFllb3aoasQTImvp7mQoRJ_0HoxmZkw,163811
50
+ llms/ui/lib/vue.mjs,sha256=dS8LKOG01t9CvZ04i0tbFXHqFXOO_Ha4NmM3BytjQAs,537071
51
+ llms/ui/modules/analytics.mjs,sha256=ZV5ybl4jnzRtHMV04V3OIX-HgiHd2aby3IHzEemkucs,73909
52
+ llms/ui/modules/layout.mjs,sha256=WTy85_8rSyBQooo2f5baw98RzNhpecw4pDpfhEgKv4s,12105
53
+ llms/ui/modules/model-selector.mjs,sha256=dekgCdaqoWX_9fnpI8mhd6lU25JV7vxBoVQVVuF2p-I,67474
54
+ llms/ui/modules/chat/ChatBody.mjs,sha256=GzHimS-haJPF7oqcqViTlOLWgardbetfNGMarTXBWxI,43368
55
+ llms/ui/modules/chat/SettingsDialog.mjs,sha256=N_Xnd9eXkXuw8cVaKR77k16TgOitB9btInW8Qp-WK7U,19929
56
+ llms/ui/modules/chat/index.mjs,sha256=wQWTo54kGRcA68wCjSY-VOPheQTGlxmAOn-LGR76Qnk,33765
57
+ llms/ui/modules/threads/Recents.mjs,sha256=xiN5K9SYc0oJug60m6g_lPVw-75lNkp1ATuVUYgIgX8,8826
58
+ llms/ui/modules/threads/index.mjs,sha256=0ZwVb6W2BT3mwK5bwKgtlJEGJ9IAnQr7qk3XNG1LnFU,11397
59
+ llms/ui/modules/threads/threadStore.mjs,sha256=cGm6g4dn5q0u_K6Bu5xuoAmBuURquubK7R4ahSKNC_E,16886
60
+ llms_py-3.0.0b3.dist-info/licenses/LICENSE,sha256=bus9cuAOWeYqBk2OuhSABVV1P4z7hgrEFISpyda_H5w,1532
61
+ llms_py-3.0.0b3.dist-info/METADATA,sha256=1iKo8N7Owhqbsr3nemrVRlcmZl07jLlkQtT-Q2vTzFw,2193
62
+ llms_py-3.0.0b3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
63
+ llms_py-3.0.0b3.dist-info/entry_points.txt,sha256=WswyE7PfnkZMIxboC-MS6flBD6wm-CYU7JSUnMhqMfM,40
64
+ llms_py-3.0.0b3.dist-info/top_level.txt,sha256=gC7hk9BKSeog8gyg-EM_g2gxm1mKHwFRfK-10BxOsa4,5
65
+ llms_py-3.0.0b3.dist-info/RECORD,,
llms/ui/Avatar.mjs DELETED
@@ -1,85 +0,0 @@
1
- import { computed, inject, ref, onMounted, onUnmounted } from "vue"
2
-
3
- export default {
4
- template:`
5
- <div v-if="$ai.auth?.profileUrl" class="relative" ref="avatarContainer">
6
- <img
7
- @click.stop="toggleMenu"
8
- :src="$ai.auth.profileUrl"
9
- :title="authTitle"
10
- class="size-8 rounded-full cursor-pointer hover:ring-2 hover:ring-gray-300"
11
- />
12
- <div
13
- v-if="showMenu"
14
- @click.stop
15
- class="absolute right-0 mt-2 w-48 bg-white dark:bg-gray-800 rounded-md shadow-lg py-1 z-50 border border-gray-200 dark:border-gray-700"
16
- >
17
- <div class="px-4 py-2 text-sm text-gray-700 dark:text-gray-300 border-b border-gray-200 dark:border-gray-700">
18
- <div class="font-medium whitespace-nowrap overflow-hidden text-ellipsis">{{ $ai.auth.displayName || $ai.auth.userName }}</div>
19
- <div class="text-xs text-gray-500 dark:text-gray-400 whitespace-nowrap overflow-hidden text-ellipsis">{{ $ai.auth.email }}</div>
20
- </div>
21
- <button type="button"
22
- @click="handleLogout"
23
- class="w-full text-left px-4 py-2 text-sm text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 flex items-center whitespace-nowrap"
24
- >
25
- <svg class="w-4 h-4 mr-2 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
26
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1"></path>
27
- </svg>
28
- Sign Out
29
- </button>
30
- </div>
31
- </div>
32
- `,
33
- setup() {
34
- const ai = inject('ai')
35
- const showMenu = ref(false)
36
- const avatarContainer = ref(null)
37
-
38
- const authTitle = computed(() => {
39
- if (!ai.auth) return ''
40
- const { userId, userName, displayName, bearerToken, roles } = ai.auth
41
- const name = userName || displayName
42
- const prefix = roles && roles.includes('Admin') ? 'Admin' : 'Name'
43
- const sb = [
44
- name ? `${prefix}: ${name}` : '',
45
- `API Key: ${bearerToken}`,
46
- `${userId}`,
47
- ]
48
- return sb.filter(x => x).join('\n')
49
- })
50
-
51
- function toggleMenu() {
52
- showMenu.value = !showMenu.value
53
- }
54
-
55
- async function handleLogout() {
56
- showMenu.value = false
57
- await ai.signOut()
58
- // Reload the page to show sign-in screen
59
- window.location.reload()
60
- }
61
-
62
- // Close menu when clicking outside
63
- const handleClickOutside = (event) => {
64
- if (showMenu.value && avatarContainer.value && !avatarContainer.value.contains(event.target)) {
65
- showMenu.value = false
66
- }
67
- }
68
-
69
- onMounted(() => {
70
- document.addEventListener('click', handleClickOutside)
71
- })
72
-
73
- onUnmounted(() => {
74
- document.removeEventListener('click', handleClickOutside)
75
- })
76
-
77
- return {
78
- authTitle,
79
- handleLogout,
80
- showMenu,
81
- toggleMenu,
82
- avatarContainer,
83
- }
84
- }
85
- }
llms/ui/Brand.mjs DELETED
@@ -1,52 +0,0 @@
1
- export default {
2
- template:`
3
- <div class="flex-shrink-0 pl-2 pr-4 py-4 border-b border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800 min-h-16 select-none">
4
- <div class="flex items-center justify-between">
5
- <div class="flex items-center space-x-2">
6
- <button type="button"
7
- @click="$emit('toggle-sidebar')"
8
- class="group relative text-gray-500 dark:text-gray-400 hover:text-blue-600 dark:hover:text-blue-400 focus:outline-none transition-colors"
9
- title="Collapse sidebar"
10
- >
11
- <div class="relative size-5">
12
- <!-- Default sidebar icon -->
13
- <svg class="absolute inset-0 group-hover:hidden" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
14
- <rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect>
15
- <line x1="9" y1="3" x2="9" y2="21"></line>
16
- </svg>
17
- <!-- Hover state: |← icon -->
18
- <svg class="absolute inset-0 hidden group-hover:block" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="currentColor" d="m10.071 4.929l1.414 1.414L6.828 11H16v2H6.828l4.657 4.657l-1.414 1.414L3 12zM18.001 19V5h2v14z"/></svg>
19
- </div>
20
- </button>
21
-
22
- <button type="button"
23
- @click="$emit('home')"
24
- class="text-lg font-semibold text-gray-900 dark:text-gray-200 hover:text-blue-600 dark:hover:text-blue-400 focus:outline-none transition-colors"
25
- title="Go back to initial state"
26
- >
27
- History
28
- </button>
29
- </div>
30
-
31
- <div class="flex items-center space-x-2">
32
- <button type="button"
33
- @click="$emit('analytics')"
34
- class="text-gray-900 dark:text-gray-200 hover:text-blue-600 dark:hover:text-blue-400 focus:outline-none transition-colors"
35
- title="Analytics"
36
- >
37
- <svg class="size-6" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="currentColor" d="M5 22a1 1 0 0 1-1-1v-8a1 1 0 0 1 2 0v8a1 1 0 0 1-1 1m5 0a1 1 0 0 1-1-1V3a1 1 0 0 1 2 0v18a1 1 0 0 1-1 1m5 0a1 1 0 0 1-1-1V9a1 1 0 0 1 2 0v12a1 1 0 0 1-1 1m5 0a1 1 0 0 1-1-1v-4a1 1 0 0 1 2 0v4a1 1 0 0 1-1 1"/></svg>
38
- </button>
39
-
40
- <button type="button"
41
- @click="$emit('new')"
42
- class="text-gray-900 dark:text-gray-200 hover:text-blue-600 dark:hover:text-blue-400 focus:outline-none transition-colors"
43
- title="New Chat"
44
- >
45
- <svg class="size-6" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"><path d="M12 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/><path d="M18.375 2.625a1 1 0 0 1 3 3l-9.013 9.014a2 2 0 0 1-.853.505l-2.873.84a.5.5 0 0 1-.62-.62l.84-2.873a2 2 0 0 1 .506-.852z"/></g></svg>
46
- </button>
47
- </div>
48
- </div>
49
- </div>
50
- `,
51
- emits:['home','new','analytics','toggle-sidebar'],
52
- }