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
@@ -1,10 +1,9 @@
1
1
  import { ref, onMounted, watch, inject } from 'vue'
2
2
  import { useRouter, useRoute } from 'vue-router'
3
3
  import { useThreadStore } from './threadStore.mjs'
4
- import { renderMarkdown } from './markdown.mjs'
5
4
 
6
5
  const RecentResults = {
7
- template:`
6
+ template: `
8
7
  <div class="flex-1 overflow-y-auto" @scroll="onScroll">
9
8
  <div class="mx-auto max-w-6xl px-4 py-4">
10
9
  <div class="text-sm text-gray-600 dark:text-gray-400 mb-3" v-if="threads.length">
@@ -46,9 +45,10 @@ const RecentResults = {
46
45
  q: String
47
46
  },
48
47
  setup(props) {
49
- const ai = inject('ai')
48
+ const ctx = inject('ctx')
49
+ const ai = ctx.ai
50
+ const config = ctx.state.config
50
51
  const router = useRouter()
51
- const config = inject('config')
52
52
  const { threads, loadThreads } = useThreadStore()
53
53
  let defaultVisibleCount = 25
54
54
  const visibleCount = ref(defaultVisibleCount)
@@ -106,19 +106,19 @@ const RecentResults = {
106
106
  const snippet = (t) => {
107
107
  const highlight = (s) => clean(s).replace(new RegExp(`(${query.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')})`, 'gi'), `<mark>$1</mark>`)
108
108
  const query = normalized(props.q)
109
- if (!query) return (t.messages && t.messages.length) ? highlight(t.messages[t.messages.length-1].content) : ''
109
+ if (!query) return (t.messages && t.messages.length) ? highlight(t.messages[t.messages.length - 1].content) : ''
110
110
  if (normalized(t.title).includes(query)) return highlight(t.title)
111
- if (Array.isArray(t.messages)){
112
- for (const m of t.messages){
111
+ if (Array.isArray(t.messages)) {
112
+ for (const m of t.messages) {
113
113
  const c = normalized(m?.content)
114
- if (c.includes(query)){
114
+ if (c.includes(query)) {
115
115
  // return small excerpt around first match
116
116
  const idx = c.indexOf(query)
117
117
  const orig = (m?.content || '')
118
118
  const start = Math.max(0, idx - 40)
119
119
  const end = Math.min(orig.length, idx + query.length + 60)
120
- const prefix = start>0 ? '…' : ''
121
- const suffix = end<orig.length ? '…' : ''
120
+ const prefix = start > 0 ? '…' : ''
121
+ const suffix = end < orig.length ? '…' : ''
122
122
  const snippet = prefix + orig.slice(start, end) + suffix
123
123
  // return snippet
124
124
  return highlight(snippet)
@@ -139,7 +139,6 @@ const RecentResults = {
139
139
  snippet,
140
140
  open,
141
141
  formatDate,
142
- renderMarkdown,
143
142
  onScroll,
144
143
  }
145
144
  }
@@ -1,11 +1,7 @@
1
1
  import { onMounted, inject } from 'vue'
2
2
  import { useRouter } from 'vue-router'
3
- import { useFormatters } from '@servicestack/vue'
4
- import { useThreadStore } from './threadStore.mjs'
5
- import Brand from './Brand.mjs'
6
- import { statsTitle, formatCost } from './utils.mjs'
7
-
8
- const { humanifyNumber, humanifyMs } = useFormatters()
3
+ import ThreadStore from './threadStore.mjs'
4
+ import Recents from './Recents.mjs'
9
5
 
10
6
  // Thread Item Component
11
7
  const ThreadItem = {
@@ -21,10 +17,10 @@ const ThreadItem = {
21
17
  {{ thread.title }}
22
18
  </div>
23
19
  <div class="text-xs text-gray-500 dark:text-gray-400 truncate">
24
- <span>{{ formatRelativeTime(thread.updatedAt) }} • {{ thread.messages.length }} msgs</span>
25
- <span v-if="thread.stats?.inputTokens" :title="statsTitle(thread.stats)">
26
- &#8226; {{ humanifyNumber(thread.stats.inputTokens + thread.stats.outputTokens) }} toks
27
- {{ thread.stats.cost ? ' ' + formatCost(thread.stats.cost) : '' }}
20
+ <span>{{ $fmt.relativeTime(thread.updatedAt) }} • {{ thread.messages.length }} msgs</span>
21
+ <span v-if="thread.stats?.inputTokens" :title="$fmt.statsTitle(thread.stats)">
22
+ &#8226; {{ $fmt.humanifyNumber(thread.stats.inputTokens + thread.stats.outputTokens) }} toks
23
+ {{ thread.stats.cost ? ' ' + $fmt.cost(thread.stats.cost) : '' }}
28
24
  </span>
29
25
  </div>
30
26
  <div v-if="thread.model" class="text-xs text-blue-600 dark:text-blue-400 truncate">
@@ -60,32 +56,12 @@ const ThreadItem = {
60
56
  emits: ['select', 'delete'],
61
57
 
62
58
  setup() {
63
- const formatRelativeTime = (timestamp) => {
64
- const now = new Date()
65
- const date = new Date(timestamp)
66
- const diffInSeconds = Math.floor((now - date) / 1000)
67
-
68
- if (diffInSeconds < 60) return 'Just now'
69
- if (diffInSeconds < 3600) return `${Math.floor(diffInSeconds / 60)}m ago`
70
- if (diffInSeconds < 86400) return `${Math.floor(diffInSeconds / 3600)}h ago`
71
- if (diffInSeconds < 604800) return `${Math.floor(diffInSeconds / 86400)}d ago`
72
-
73
- return date.toLocaleDateString()
74
- }
75
-
76
59
  return {
77
- formatRelativeTime,
78
- humanifyNumber,
79
- statsTitle,
80
- formatCost,
81
60
  }
82
61
  }
83
62
  }
84
63
 
85
64
  const GroupedThreads = {
86
- components: {
87
- ThreadItem,
88
- },
89
65
  template: `
90
66
  <!-- Today -->
91
67
  <div v-if="groupedThreads.today.length > 0" class="mb-4">
@@ -156,15 +132,10 @@ const GroupedThreads = {
156
132
  emits: ['select', 'delete'],
157
133
  }
158
134
 
159
- const Sidebar = {
160
- components: {
161
- Brand,
162
- GroupedThreads,
163
- ThreadItem,
164
- },
135
+ const ThreadsSidebar = {
165
136
  template: `
166
- <div class="flex flex-col h-full bg-gray-50 dark:bg-gray-800 border-r border-gray-200 dark:border-gray-700">
167
- <Brand @home="goToInitialState" @new="createNewThread" @analytics="goToAnalytics" @toggle-sidebar="$emit('toggle-sidebar')" />
137
+ <div class="flex flex-col h-full">
138
+ <Brand @home="goToInitialState" @toggle-sidebar="$emit('toggle-sidebar')" />
168
139
  <!-- Thread List -->
169
140
  <div class="flex-1 overflow-y-auto">
170
141
  <div v-if="isLoading" class="p-4 text-center text-gray-500 dark:text-gray-400">
@@ -180,8 +151,19 @@ const Sidebar = {
180
151
  <p class="text-xs text-gray-400 dark:text-gray-500 mt-1">Start a new chat to begin</p>
181
152
  </div>
182
153
 
183
- <div v-else class="py-2">
184
- <GroupedThreads :currentThread="currentThread" :groupedThreads="threadStore.getGroupedThreads(18)"
154
+ <div v-else class="relative py-2">
155
+
156
+ <div class="flex items-center space-x-2 absolute top-2 right-2">
157
+ <button type="button"
158
+ @click="createNewThread"
159
+ class="text-gray-900 dark:text-gray-200 hover:text-blue-600 dark:hover:text-blue-400 focus:outline-none transition-colors"
160
+ title="New Chat"
161
+ >
162
+ <svg class="size-5" 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>
163
+ </button>
164
+ </div>
165
+
166
+ <GroupedThreads :currentThread="currentThread" :groupedThreads="$threads.getGroupedThreads(50)"
185
167
  @select="selectThread" @delete="deleteThread" />
186
168
  </div>
187
169
  </div>
@@ -189,9 +171,9 @@ const Sidebar = {
189
171
  `,
190
172
  emits: ['thread-selected', 'toggle-sidebar'],
191
173
  setup(props, { emit }) {
192
- const ai = inject('ai')
174
+ const ctx = inject('ctx')
175
+ const ai = ctx.ai
193
176
  const router = useRouter()
194
- const threadStore = useThreadStore()
195
177
  const {
196
178
  threads,
197
179
  currentThread,
@@ -201,7 +183,7 @@ const Sidebar = {
201
183
  createThread,
202
184
  deleteThread: deleteThreadFromStore,
203
185
  clearCurrentThread
204
- } = threadStore
186
+ } = ctx.threads
205
187
 
206
188
  onMounted(async () => {
207
189
  await loadThreads()
@@ -240,7 +222,6 @@ const Sidebar = {
240
222
  }
241
223
 
242
224
  return {
243
- threadStore,
244
225
  threads,
245
226
  currentThread,
246
227
  isLoading,
@@ -254,4 +235,26 @@ const Sidebar = {
254
235
  }
255
236
  }
256
237
 
257
- export default Sidebar
238
+ export default {
239
+ install(ctx) {
240
+ ctx.components({
241
+ ThreadsSidebar,
242
+ ThreadItem,
243
+ GroupedThreads,
244
+ Recents,
245
+ })
246
+ ctx.routes.push(...[
247
+ { path: '/recents', component: Recents },
248
+ ])
249
+ ThreadStore.install(ctx)
250
+
251
+ ctx.setLayout({
252
+ left: 'ThreadsSidebar',
253
+ })
254
+ },
255
+
256
+ async load(ctx) {
257
+ const { initDB } = ctx.threads
258
+ await initDB()
259
+ }
260
+ }
@@ -1,6 +1,6 @@
1
1
  import { ref, computed, unref } from 'vue'
2
2
  import { openDB } from 'idb'
3
- import { nextId, toModelInfo } from './utils.mjs'
3
+ import { nextId } from '../../utils.mjs'
4
4
 
5
5
  // Thread store for managing chat threads with IndexedDB
6
6
  const threads = ref([])
@@ -8,6 +8,7 @@ const currentThread = ref(null)
8
8
  const isLoading = ref(false)
9
9
 
10
10
  let db = null
11
+ let ctx = null
11
12
 
12
13
  // Initialize IndexedDB
13
14
  async function initDB() {
@@ -103,20 +104,22 @@ async function logRequest(threadId, model, request, response) {
103
104
  }
104
105
 
105
106
  // Create a new thread
106
- async function createThread(title = 'New Chat', model = null, systemPrompt = '') {
107
+ async function createThread(args = {}) {
107
108
  await initDB()
108
109
 
109
110
  const thread = {
110
111
  id: generateThreadId(),
111
- title: title,
112
- model: model?.id ?? '',
113
- info: toModelInfo(model),
114
- systemPrompt: systemPrompt,
115
112
  messages: [],
116
113
  createdAt: new Date().toISOString(),
117
- updatedAt: new Date().toISOString()
114
+ updatedAt: new Date().toISOString(),
115
+ ...args
116
+ }
117
+ if (!thread.title) {
118
+ thread.title = 'New Chat'
118
119
  }
119
120
 
121
+ ctx.createThreadFilters.forEach(f => f(thread))
122
+
120
123
  try {
121
124
  const tx = db.transaction(['threads'], 'readwrite')
122
125
  await tx.objectStore('threads').add(thread)
@@ -148,6 +151,8 @@ async function updateThread(threadId, updates) {
148
151
  updatedAt: new Date().toISOString()
149
152
  }
150
153
 
154
+ ctx.updateThreadFilters.forEach(f => f(updatedThread))
155
+
151
156
  await store.put(updatedThread)
152
157
  await tx.complete
153
158
 
@@ -570,3 +575,12 @@ export function useThreadStore() {
570
575
  getAllThreadIds,
571
576
  }
572
577
  }
578
+
579
+ export default {
580
+ install(context) {
581
+ ctx = context
582
+ ctx.setGlobals({
583
+ threads: useThreadStore()
584
+ })
585
+ }
586
+ }