inference-server 1.0.0-beta.19
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.
- package/README.md +216 -0
- package/dist/api/openai/enums.d.ts +4 -0
- package/dist/api/openai/enums.js +17 -0
- package/dist/api/openai/enums.js.map +1 -0
- package/dist/api/openai/handlers/chat.d.ts +3 -0
- package/dist/api/openai/handlers/chat.js +358 -0
- package/dist/api/openai/handlers/chat.js.map +1 -0
- package/dist/api/openai/handlers/completions.d.ts +3 -0
- package/dist/api/openai/handlers/completions.js +169 -0
- package/dist/api/openai/handlers/completions.js.map +1 -0
- package/dist/api/openai/handlers/embeddings.d.ts +3 -0
- package/dist/api/openai/handlers/embeddings.js +74 -0
- package/dist/api/openai/handlers/embeddings.js.map +1 -0
- package/dist/api/openai/handlers/images.d.ts +0 -0
- package/dist/api/openai/handlers/images.js +4 -0
- package/dist/api/openai/handlers/images.js.map +1 -0
- package/dist/api/openai/handlers/models.d.ts +3 -0
- package/dist/api/openai/handlers/models.js +23 -0
- package/dist/api/openai/handlers/models.js.map +1 -0
- package/dist/api/openai/handlers/transcription.d.ts +0 -0
- package/dist/api/openai/handlers/transcription.js +4 -0
- package/dist/api/openai/handlers/transcription.js.map +1 -0
- package/dist/api/openai/index.d.ts +7 -0
- package/dist/api/openai/index.js +14 -0
- package/dist/api/openai/index.js.map +1 -0
- package/dist/api/parseJSONRequestBody.d.ts +2 -0
- package/dist/api/parseJSONRequestBody.js +24 -0
- package/dist/api/parseJSONRequestBody.js.map +1 -0
- package/dist/api/v1/index.d.ts +2 -0
- package/dist/api/v1/index.js +29 -0
- package/dist/api/v1/index.js.map +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +10 -0
- package/dist/cli.js.map +1 -0
- package/dist/engines/gpt4all/engine.d.ts +34 -0
- package/dist/engines/gpt4all/engine.js +357 -0
- package/dist/engines/gpt4all/engine.js.map +1 -0
- package/dist/engines/gpt4all/util.d.ts +3 -0
- package/dist/engines/gpt4all/util.js +29 -0
- package/dist/engines/gpt4all/util.js.map +1 -0
- package/dist/engines/index.d.ts +19 -0
- package/dist/engines/index.js +21 -0
- package/dist/engines/index.js.map +1 -0
- package/dist/engines/node-llama-cpp/engine.d.ts +49 -0
- package/dist/engines/node-llama-cpp/engine.js +666 -0
- package/dist/engines/node-llama-cpp/engine.js.map +1 -0
- package/dist/engines/node-llama-cpp/types.d.ts +13 -0
- package/dist/engines/node-llama-cpp/types.js +2 -0
- package/dist/engines/node-llama-cpp/types.js.map +1 -0
- package/dist/engines/node-llama-cpp/util.d.ts +15 -0
- package/dist/engines/node-llama-cpp/util.js +84 -0
- package/dist/engines/node-llama-cpp/util.js.map +1 -0
- package/dist/engines/node-llama-cpp/validateModelFile.d.ts +8 -0
- package/dist/engines/node-llama-cpp/validateModelFile.js +36 -0
- package/dist/engines/node-llama-cpp/validateModelFile.js.map +1 -0
- package/dist/engines/stable-diffusion-cpp/engine.d.ts +90 -0
- package/dist/engines/stable-diffusion-cpp/engine.js +294 -0
- package/dist/engines/stable-diffusion-cpp/engine.js.map +1 -0
- package/dist/engines/stable-diffusion-cpp/types.d.ts +3 -0
- package/dist/engines/stable-diffusion-cpp/types.js +2 -0
- package/dist/engines/stable-diffusion-cpp/types.js.map +1 -0
- package/dist/engines/stable-diffusion-cpp/util.d.ts +4 -0
- package/dist/engines/stable-diffusion-cpp/util.js +55 -0
- package/dist/engines/stable-diffusion-cpp/util.js.map +1 -0
- package/dist/engines/stable-diffusion-cpp/validateModelFiles.d.ts +19 -0
- package/dist/engines/stable-diffusion-cpp/validateModelFiles.js +91 -0
- package/dist/engines/stable-diffusion-cpp/validateModelFiles.js.map +1 -0
- package/dist/engines/transformers-js/engine.d.ts +37 -0
- package/dist/engines/transformers-js/engine.js +538 -0
- package/dist/engines/transformers-js/engine.js.map +1 -0
- package/dist/engines/transformers-js/types.d.ts +7 -0
- package/dist/engines/transformers-js/types.js +2 -0
- package/dist/engines/transformers-js/types.js.map +1 -0
- package/dist/engines/transformers-js/util.d.ts +7 -0
- package/dist/engines/transformers-js/util.js +36 -0
- package/dist/engines/transformers-js/util.js.map +1 -0
- package/dist/engines/transformers-js/validateModelFiles.d.ts +17 -0
- package/dist/engines/transformers-js/validateModelFiles.js +133 -0
- package/dist/engines/transformers-js/validateModelFiles.js.map +1 -0
- package/dist/experiments/ChatWithVision.d.ts +11 -0
- package/dist/experiments/ChatWithVision.js +91 -0
- package/dist/experiments/ChatWithVision.js.map +1 -0
- package/dist/experiments/StableDiffPromptGenerator.d.ts +0 -0
- package/dist/experiments/StableDiffPromptGenerator.js +4 -0
- package/dist/experiments/StableDiffPromptGenerator.js.map +1 -0
- package/dist/experiments/VoiceFunctionCall.d.ts +18 -0
- package/dist/experiments/VoiceFunctionCall.js +51 -0
- package/dist/experiments/VoiceFunctionCall.js.map +1 -0
- package/dist/http.d.ts +19 -0
- package/dist/http.js +54 -0
- package/dist/http.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/instance.d.ts +88 -0
- package/dist/instance.js +594 -0
- package/dist/instance.js.map +1 -0
- package/dist/lib/acquireFileLock.d.ts +7 -0
- package/dist/lib/acquireFileLock.js +38 -0
- package/dist/lib/acquireFileLock.js.map +1 -0
- package/dist/lib/calculateContextIdentity.d.ts +7 -0
- package/dist/lib/calculateContextIdentity.js +39 -0
- package/dist/lib/calculateContextIdentity.js.map +1 -0
- package/dist/lib/calculateFileChecksum.d.ts +1 -0
- package/dist/lib/calculateFileChecksum.js +16 -0
- package/dist/lib/calculateFileChecksum.js.map +1 -0
- package/dist/lib/copyDirectory.d.ts +6 -0
- package/dist/lib/copyDirectory.js +27 -0
- package/dist/lib/copyDirectory.js.map +1 -0
- package/dist/lib/decodeAudio.d.ts +1 -0
- package/dist/lib/decodeAudio.js +26 -0
- package/dist/lib/decodeAudio.js.map +1 -0
- package/dist/lib/downloadModelFile.d.ts +10 -0
- package/dist/lib/downloadModelFile.js +58 -0
- package/dist/lib/downloadModelFile.js.map +1 -0
- package/dist/lib/flattenMessageTextContent.d.ts +2 -0
- package/dist/lib/flattenMessageTextContent.js +11 -0
- package/dist/lib/flattenMessageTextContent.js.map +1 -0
- package/dist/lib/getCacheDirPath.d.ts +12 -0
- package/dist/lib/getCacheDirPath.js +31 -0
- package/dist/lib/getCacheDirPath.js.map +1 -0
- package/dist/lib/loadImage.d.ts +12 -0
- package/dist/lib/loadImage.js +30 -0
- package/dist/lib/loadImage.js.map +1 -0
- package/dist/lib/logger.d.ts +12 -0
- package/dist/lib/logger.js +98 -0
- package/dist/lib/logger.js.map +1 -0
- package/dist/lib/math.d.ts +7 -0
- package/dist/lib/math.js +30 -0
- package/dist/lib/math.js.map +1 -0
- package/dist/lib/resolveModelFileLocation.d.ts +15 -0
- package/dist/lib/resolveModelFileLocation.js +41 -0
- package/dist/lib/resolveModelFileLocation.js.map +1 -0
- package/dist/lib/util.d.ts +7 -0
- package/dist/lib/util.js +61 -0
- package/dist/lib/util.js.map +1 -0
- package/dist/lib/validateModelFile.d.ts +9 -0
- package/dist/lib/validateModelFile.js +62 -0
- package/dist/lib/validateModelFile.js.map +1 -0
- package/dist/lib/validateModelOptions.d.ts +3 -0
- package/dist/lib/validateModelOptions.js +23 -0
- package/dist/lib/validateModelOptions.js.map +1 -0
- package/dist/pool.d.ts +61 -0
- package/dist/pool.js +512 -0
- package/dist/pool.js.map +1 -0
- package/dist/server.d.ts +59 -0
- package/dist/server.js +221 -0
- package/dist/server.js.map +1 -0
- package/dist/standalone.d.ts +1 -0
- package/dist/standalone.js +306 -0
- package/dist/standalone.js.map +1 -0
- package/dist/store.d.ts +60 -0
- package/dist/store.js +203 -0
- package/dist/store.js.map +1 -0
- package/dist/types/completions.d.ts +57 -0
- package/dist/types/completions.js +2 -0
- package/dist/types/completions.js.map +1 -0
- package/dist/types/index.d.ts +326 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/docs/engines.md +28 -0
- package/docs/gpu.md +72 -0
- package/docs/http-api.md +147 -0
- package/examples/all-options.js +108 -0
- package/examples/chat-cli.js +56 -0
- package/examples/chat-server.js +65 -0
- package/examples/concurrency.js +70 -0
- package/examples/express.js +70 -0
- package/examples/pool.js +91 -0
- package/package.json +113 -0
- package/src/api/openai/enums.ts +20 -0
- package/src/api/openai/handlers/chat.ts +408 -0
- package/src/api/openai/handlers/completions.ts +196 -0
- package/src/api/openai/handlers/embeddings.ts +92 -0
- package/src/api/openai/handlers/images.ts +3 -0
- package/src/api/openai/handlers/models.ts +33 -0
- package/src/api/openai/handlers/transcription.ts +2 -0
- package/src/api/openai/index.ts +16 -0
- package/src/api/parseJSONRequestBody.ts +26 -0
- package/src/api/v1/DRAFT.md +16 -0
- package/src/api/v1/index.ts +37 -0
- package/src/cli.ts +9 -0
- package/src/engines/gpt4all/engine.ts +441 -0
- package/src/engines/gpt4all/util.ts +31 -0
- package/src/engines/index.ts +28 -0
- package/src/engines/node-llama-cpp/engine.ts +811 -0
- package/src/engines/node-llama-cpp/types.ts +17 -0
- package/src/engines/node-llama-cpp/util.ts +126 -0
- package/src/engines/node-llama-cpp/validateModelFile.ts +46 -0
- package/src/engines/stable-diffusion-cpp/engine.ts +369 -0
- package/src/engines/stable-diffusion-cpp/types.ts +54 -0
- package/src/engines/stable-diffusion-cpp/util.ts +58 -0
- package/src/engines/stable-diffusion-cpp/validateModelFiles.ts +119 -0
- package/src/engines/transformers-js/engine.ts +659 -0
- package/src/engines/transformers-js/types.ts +25 -0
- package/src/engines/transformers-js/util.ts +40 -0
- package/src/engines/transformers-js/validateModelFiles.ts +168 -0
- package/src/experiments/ChatWithVision.ts +103 -0
- package/src/experiments/StableDiffPromptGenerator.ts +2 -0
- package/src/experiments/VoiceFunctionCall.ts +71 -0
- package/src/http.ts +72 -0
- package/src/index.ts +7 -0
- package/src/instance.ts +723 -0
- package/src/lib/acquireFileLock.ts +38 -0
- package/src/lib/calculateContextIdentity.ts +53 -0
- package/src/lib/calculateFileChecksum.ts +18 -0
- package/src/lib/copyDirectory.ts +29 -0
- package/src/lib/decodeAudio.ts +39 -0
- package/src/lib/downloadModelFile.ts +70 -0
- package/src/lib/flattenMessageTextContent.ts +19 -0
- package/src/lib/getCacheDirPath.ts +34 -0
- package/src/lib/loadImage.ts +46 -0
- package/src/lib/logger.ts +112 -0
- package/src/lib/math.ts +31 -0
- package/src/lib/resolveModelFileLocation.ts +49 -0
- package/src/lib/util.ts +75 -0
- package/src/lib/validateModelFile.ts +71 -0
- package/src/lib/validateModelOptions.ts +31 -0
- package/src/pool.ts +651 -0
- package/src/server.ts +270 -0
- package/src/standalone.ts +320 -0
- package/src/store.ts +278 -0
- package/src/types/completions.ts +86 -0
- package/src/types/index.ts +488 -0
- package/tsconfig.json +29 -0
- package/tsconfig.release.json +11 -0
- package/vitest.config.ts +18 -0
package/src/store.ts
ADDED
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
import { promises as fs, existsSync } from 'node:fs'
|
|
2
|
+
import PQueue from 'p-queue'
|
|
3
|
+
import prettyMilliseconds from 'pretty-ms'
|
|
4
|
+
import prettyBytes from 'pretty-bytes'
|
|
5
|
+
import {
|
|
6
|
+
FileDownloadProgress,
|
|
7
|
+
ModelConfig,
|
|
8
|
+
ModelEngine,
|
|
9
|
+
} from '#package/types/index.js'
|
|
10
|
+
import {
|
|
11
|
+
Logger,
|
|
12
|
+
LogLevels,
|
|
13
|
+
LogLevel,
|
|
14
|
+
createSublogger,
|
|
15
|
+
} from '#package/lib/logger.js'
|
|
16
|
+
import { formatBytesPerSecond, mergeAbortSignals } from '#package/lib/util.js'
|
|
17
|
+
|
|
18
|
+
interface ModelFile {
|
|
19
|
+
size: number
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface StoredModel extends ModelConfig {
|
|
23
|
+
meta?: unknown
|
|
24
|
+
downloads?: Map<string, DownloadTracker>
|
|
25
|
+
status: 'unloaded' | 'preparing' | 'ready' | 'error'
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface ModelStoreOptions {
|
|
29
|
+
modelsCachePath: string
|
|
30
|
+
models: Record<string, ModelConfig>
|
|
31
|
+
prepareConcurrency?: number
|
|
32
|
+
log?: Logger | LogLevel
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export class ModelStore {
|
|
36
|
+
prepareQueue: PQueue
|
|
37
|
+
models: Record<string, StoredModel> = {}
|
|
38
|
+
engines?: Record<string, ModelEngine>
|
|
39
|
+
private prepareController: AbortController
|
|
40
|
+
private modelsCachePath: string
|
|
41
|
+
private log: Logger
|
|
42
|
+
|
|
43
|
+
constructor(options: ModelStoreOptions) {
|
|
44
|
+
this.prepareController = new AbortController()
|
|
45
|
+
this.log = createSublogger(options.log)
|
|
46
|
+
this.prepareQueue = new PQueue({
|
|
47
|
+
concurrency: options.prepareConcurrency ?? 2,
|
|
48
|
+
})
|
|
49
|
+
this.modelsCachePath = options.modelsCachePath
|
|
50
|
+
this.models = Object.fromEntries(
|
|
51
|
+
Object.entries(options.models).map(([modelId, model]) => [
|
|
52
|
+
modelId,
|
|
53
|
+
{
|
|
54
|
+
...model,
|
|
55
|
+
status: 'unloaded',
|
|
56
|
+
},
|
|
57
|
+
]),
|
|
58
|
+
)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
async init(engines: Record<string, ModelEngine>) {
|
|
62
|
+
this.engines = engines
|
|
63
|
+
if (!existsSync(this.modelsCachePath)) {
|
|
64
|
+
await fs.mkdir(this.modelsCachePath, { recursive: true })
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const blockingPromises = []
|
|
68
|
+
for (const modelId in this.models) {
|
|
69
|
+
const model = this.models[modelId]
|
|
70
|
+
if (model.prepare === 'blocking' || model.minInstances > 0) {
|
|
71
|
+
blockingPromises.push(this.prepareModel(modelId))
|
|
72
|
+
} else if (model.prepare === 'async') {
|
|
73
|
+
this.prepareModel(modelId)
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
await Promise.all(blockingPromises)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
dispose() {
|
|
80
|
+
this.prepareController.abort()
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
private onDownloadProgress(
|
|
84
|
+
modelId: string,
|
|
85
|
+
progress: { file: string; loadedBytes: number; totalBytes: number },
|
|
86
|
+
) {
|
|
87
|
+
const model = this.models[modelId]
|
|
88
|
+
if (!model.downloads) {
|
|
89
|
+
model.downloads = new Map()
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (model.downloads.has(progress.file)) {
|
|
93
|
+
const tracker = model.downloads.get(progress.file)!
|
|
94
|
+
tracker.pushProgress(progress)
|
|
95
|
+
} else {
|
|
96
|
+
const tracker = new DownloadTracker(5000)
|
|
97
|
+
tracker.pushProgress(progress)
|
|
98
|
+
model.downloads.set(progress.file, tracker)
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// makes sure all required files for the model exist and are valid
|
|
103
|
+
// checking model checksums and reading metadata is model + engine specific and can be slow
|
|
104
|
+
async prepareModel(modelId: string, signal?: AbortSignal) {
|
|
105
|
+
const model = this.models[modelId]
|
|
106
|
+
if (!this.engines) {
|
|
107
|
+
throw new Error('No engines available - did you call init()?')
|
|
108
|
+
}
|
|
109
|
+
model.status = 'preparing'
|
|
110
|
+
const engine = this.engines[model.engine]
|
|
111
|
+
this.log(LogLevels.info, 'Preparing model', {
|
|
112
|
+
model: modelId,
|
|
113
|
+
task: model.task,
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
await this.prepareQueue.add(async () => {
|
|
117
|
+
if (!('prepareModel' in engine)) {
|
|
118
|
+
model.status = 'ready'
|
|
119
|
+
return model
|
|
120
|
+
}
|
|
121
|
+
const logProgressInterval = setInterval(() => {
|
|
122
|
+
const progress = Array.from(model.downloads?.values() ?? [])
|
|
123
|
+
.map((tracker) => tracker.getStatus())
|
|
124
|
+
.reduce(
|
|
125
|
+
(acc, status) => {
|
|
126
|
+
acc.loadedBytes += status?.loadedBytes || 0
|
|
127
|
+
acc.totalBytes += status?.totalBytes || 0
|
|
128
|
+
acc.speed += status?.speed || 0
|
|
129
|
+
return acc
|
|
130
|
+
},
|
|
131
|
+
{ loadedBytes: 0, totalBytes: 0, speed: 0 },
|
|
132
|
+
)
|
|
133
|
+
if (progress.totalBytes) {
|
|
134
|
+
const percent = (progress.loadedBytes / progress.totalBytes) * 100
|
|
135
|
+
const formattedTotalBytes = prettyBytes(progress.totalBytes, { space: false })
|
|
136
|
+
const formattedLoadedBytes = prettyBytes(progress.loadedBytes, { space: false })
|
|
137
|
+
this.log(LogLevels.info, `Downloading at ${formatBytesPerSecond(progress.speed)} ${percent.toFixed(1)}% - ${formattedLoadedBytes} of ${formattedTotalBytes}`, {
|
|
138
|
+
model: modelId,
|
|
139
|
+
})
|
|
140
|
+
}
|
|
141
|
+
}, 10000)
|
|
142
|
+
try {
|
|
143
|
+
const modelMeta = await engine.prepareModel(
|
|
144
|
+
{ config: model, log: this.log },
|
|
145
|
+
(progress) => {
|
|
146
|
+
this.onDownloadProgress(model.id, progress)
|
|
147
|
+
},
|
|
148
|
+
mergeAbortSignals([signal, this.prepareController.signal]),
|
|
149
|
+
)
|
|
150
|
+
model.downloads = undefined
|
|
151
|
+
model.meta = modelMeta
|
|
152
|
+
model.status = 'ready'
|
|
153
|
+
this.log(LogLevels.info, 'Model ready', {
|
|
154
|
+
model: modelId,
|
|
155
|
+
task: model.task,
|
|
156
|
+
})
|
|
157
|
+
} catch (error) {
|
|
158
|
+
this.log(LogLevels.error, 'Error preparing model', {
|
|
159
|
+
model: modelId,
|
|
160
|
+
error: error,
|
|
161
|
+
})
|
|
162
|
+
model.status = 'error'
|
|
163
|
+
} finally {
|
|
164
|
+
clearInterval(logProgressInterval)
|
|
165
|
+
}
|
|
166
|
+
return model
|
|
167
|
+
})
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
getStatus() {
|
|
171
|
+
const formatFloat = (num?: number) => parseFloat(num?.toFixed(2) || '0')
|
|
172
|
+
const storeStatusInfo = Object.fromEntries(
|
|
173
|
+
Object.entries(this.models).map(([modelId, model]) => {
|
|
174
|
+
let downloads: any = undefined
|
|
175
|
+
if (model.downloads) {
|
|
176
|
+
downloads = [...model.downloads].reduce<any>(
|
|
177
|
+
(acc, [key, download]) => {
|
|
178
|
+
const status = download.getStatus()
|
|
179
|
+
const latestState =
|
|
180
|
+
download.progressBuffer[download.progressBuffer.length - 1]
|
|
181
|
+
const totalBytes = latestState?.totalBytes ?? 0
|
|
182
|
+
const loadedBytes = latestState?.loadedBytes ?? 0
|
|
183
|
+
const etaSeconds = status?.etaSeconds ?? 0
|
|
184
|
+
const formattedEta = prettyMilliseconds(etaSeconds * 1000)
|
|
185
|
+
const formattedTotalBytes = prettyBytes(totalBytes)
|
|
186
|
+
const formattedLoadedBytes = prettyBytes(loadedBytes)
|
|
187
|
+
acc.push({
|
|
188
|
+
file: key,
|
|
189
|
+
loadedBytes,
|
|
190
|
+
formattedLoadedBytes,
|
|
191
|
+
totalBytes,
|
|
192
|
+
formattedTotalBytes,
|
|
193
|
+
percent: formatFloat(status?.percent),
|
|
194
|
+
speed: formatFloat(status?.speed),
|
|
195
|
+
etaSeconds: formatFloat(etaSeconds),
|
|
196
|
+
formattedEta,
|
|
197
|
+
})
|
|
198
|
+
return acc
|
|
199
|
+
},
|
|
200
|
+
[],
|
|
201
|
+
)
|
|
202
|
+
}
|
|
203
|
+
return [
|
|
204
|
+
modelId,
|
|
205
|
+
{
|
|
206
|
+
engine: model.engine,
|
|
207
|
+
device: model.device,
|
|
208
|
+
minInstances: model.minInstances,
|
|
209
|
+
maxInstances: model.maxInstances,
|
|
210
|
+
status: model.status,
|
|
211
|
+
downloads,
|
|
212
|
+
},
|
|
213
|
+
]
|
|
214
|
+
}),
|
|
215
|
+
)
|
|
216
|
+
return storeStatusInfo
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
type ProgressState = {
|
|
221
|
+
loadedBytes: number
|
|
222
|
+
totalBytes: number
|
|
223
|
+
timestamp: number // in milliseconds
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
type DownloadStatus = {
|
|
227
|
+
percent: number
|
|
228
|
+
speed: number
|
|
229
|
+
etaSeconds: number
|
|
230
|
+
loadedBytes: number
|
|
231
|
+
totalBytes: number
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
class DownloadTracker {
|
|
235
|
+
progressBuffer: ProgressState[] = []
|
|
236
|
+
private timeWindow: number
|
|
237
|
+
|
|
238
|
+
constructor(timeWindow: number = 1000) {
|
|
239
|
+
this.timeWindow = timeWindow
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
pushProgress({ loadedBytes, totalBytes }: FileDownloadProgress): void {
|
|
243
|
+
const timestamp = Date.now()
|
|
244
|
+
this.progressBuffer.push({ loadedBytes, totalBytes, timestamp })
|
|
245
|
+
this.cleanup()
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
private cleanup(): void {
|
|
249
|
+
const cutoffTime = Date.now() - this.timeWindow
|
|
250
|
+
this.progressBuffer = this.progressBuffer.filter(
|
|
251
|
+
(item) => item.timestamp >= cutoffTime,
|
|
252
|
+
)
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
getStatus(): DownloadStatus | null {
|
|
256
|
+
if (this.progressBuffer.length < 2) {
|
|
257
|
+
return null // Not enough data to calculate speed and ETA
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const latestState = this.progressBuffer[this.progressBuffer.length - 1]
|
|
261
|
+
const previousState = this.progressBuffer[0] // oldest state within the time window
|
|
262
|
+
|
|
263
|
+
const bytesLoaded = latestState.loadedBytes - previousState.loadedBytes
|
|
264
|
+
const timeElapsed = latestState.timestamp - previousState.timestamp // in milliseconds
|
|
265
|
+
|
|
266
|
+
const speed = bytesLoaded / (timeElapsed / 1000) // bytes per second
|
|
267
|
+
const remainingBytes = latestState.totalBytes - latestState.loadedBytes
|
|
268
|
+
const eta = speed > 0 ? remainingBytes / speed : 0
|
|
269
|
+
|
|
270
|
+
return {
|
|
271
|
+
speed,
|
|
272
|
+
etaSeconds: eta,
|
|
273
|
+
percent: latestState.loadedBytes / latestState.totalBytes,
|
|
274
|
+
loadedBytes: latestState.loadedBytes,
|
|
275
|
+
totalBytes: latestState.totalBytes,
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import type { SomeJSONSchema } from 'ajv/dist/types/json-schema'
|
|
2
|
+
import { Image } from './index.js'
|
|
3
|
+
|
|
4
|
+
export type CompletionFinishReason =
|
|
5
|
+
| 'maxTokens'
|
|
6
|
+
| 'toolCalls'
|
|
7
|
+
| 'eogToken'
|
|
8
|
+
| 'stopTrigger'
|
|
9
|
+
| 'abort'
|
|
10
|
+
| 'cancel'
|
|
11
|
+
| 'timeout'
|
|
12
|
+
|
|
13
|
+
export interface AssistantToolCall {
|
|
14
|
+
id: string
|
|
15
|
+
name: string
|
|
16
|
+
parameters?: Record<string, any>
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export type ChatMessage =
|
|
20
|
+
| UserMessage
|
|
21
|
+
| SystemMessage
|
|
22
|
+
| AssistantMessage
|
|
23
|
+
| ToolCallResultMessage
|
|
24
|
+
|
|
25
|
+
export interface MessageTextContentPart {
|
|
26
|
+
type: 'text'
|
|
27
|
+
text: string
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface MessageImageContentPart {
|
|
31
|
+
type: 'image'
|
|
32
|
+
image: Image
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export type MessageContentPart =
|
|
36
|
+
| MessageTextContentPart
|
|
37
|
+
| MessageImageContentPart
|
|
38
|
+
|
|
39
|
+
export interface UserMessage {
|
|
40
|
+
role: 'user'
|
|
41
|
+
content: string | MessageContentPart[]
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface SystemMessage {
|
|
45
|
+
role: 'system'
|
|
46
|
+
content: string | MessageContentPart[]
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface AssistantMessage {
|
|
50
|
+
role: 'assistant'
|
|
51
|
+
content: string
|
|
52
|
+
toolCalls?: AssistantToolCall[]
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface ToolCallResultMessage {
|
|
56
|
+
role: 'tool'
|
|
57
|
+
content: string | MessageContentPart[]
|
|
58
|
+
callId: string
|
|
59
|
+
// name: string
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// TODO figure out how to type this better.
|
|
63
|
+
// export type ToolDefinitionParams<TParams = any> = JSONSchemaType<TParams>
|
|
64
|
+
export type ToolDefinitionParams<TParams> = SomeJSONSchema
|
|
65
|
+
|
|
66
|
+
export interface ToolDefinition<TParams extends Record<string, any> = any> {
|
|
67
|
+
description?: string
|
|
68
|
+
parameters?: ToolDefinitionParams<TParams>
|
|
69
|
+
handler?: (params: TParams) => Promise<string>
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface TextCompletionParams {
|
|
73
|
+
temperature?: number
|
|
74
|
+
maxTokens?: number
|
|
75
|
+
seed?: number
|
|
76
|
+
stop?: string[]
|
|
77
|
+
repeatPenalty?: number
|
|
78
|
+
repeatPenaltyNum?: number
|
|
79
|
+
frequencyPenalty?: number
|
|
80
|
+
presencePenalty?: number
|
|
81
|
+
grammar?: string
|
|
82
|
+
topP?: number
|
|
83
|
+
minP?: number
|
|
84
|
+
topK?: number
|
|
85
|
+
tokenBias?: Record<string, number>
|
|
86
|
+
}
|