@qvac/sdk 0.1.0-dev.1760648187.328e967
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/LICENSE +202 -0
- package/README.md +301 -0
- package/dist/client/api/cancel.d.ts +25 -0
- package/dist/client/api/cancel.js +37 -0
- package/dist/client/api/completion-stream.d.ts +50 -0
- package/dist/client/api/completion-stream.js +103 -0
- package/dist/client/api/download-asset.d.ts +39 -0
- package/dist/client/api/download-asset.js +72 -0
- package/dist/client/api/embed.d.ts +11 -0
- package/dist/client/api/embed.js +24 -0
- package/dist/client/api/index.d.ts +13 -0
- package/dist/client/api/index.js +12 -0
- package/dist/client/api/load-model.d.ts +98 -0
- package/dist/client/api/load-model.js +154 -0
- package/dist/client/api/logging-stream.d.ts +21 -0
- package/dist/client/api/logging-stream.js +32 -0
- package/dist/client/api/ping.d.ts +11 -0
- package/dist/client/api/ping.js +18 -0
- package/dist/client/api/provide.d.ts +18 -0
- package/dist/client/api/provide.js +27 -0
- package/dist/client/api/rag.d.ts +42 -0
- package/dist/client/api/rag.js +97 -0
- package/dist/client/api/transcribe.d.ts +24 -0
- package/dist/client/api/transcribe.js +52 -0
- package/dist/client/api/translate.d.ts +47 -0
- package/dist/client/api/translate.js +114 -0
- package/dist/client/api/unload-model.d.ts +11 -0
- package/dist/client/api/unload-model.js +26 -0
- package/dist/client/index.d.ts +2 -0
- package/dist/client/index.js +1 -0
- package/dist/client/logging-stream-registry.d.ts +5 -0
- package/dist/client/logging-stream-registry.js +60 -0
- package/dist/client/rpc/bare-client.d.ts +112 -0
- package/dist/client/rpc/bare-client.js +82 -0
- package/dist/client/rpc/bare-rpc-client.d.ts +4 -0
- package/dist/client/rpc/bare-rpc-client.js +87 -0
- package/dist/client/rpc/expo-rpc-client.d.ts +3 -0
- package/dist/client/rpc/expo-rpc-client.js +57 -0
- package/dist/client/rpc/node-rpc-client.d.ts +9 -0
- package/dist/client/rpc/node-rpc-client.js +99 -0
- package/dist/client/rpc/rpc-client.d.ts +5 -0
- package/dist/client/rpc/rpc-client.js +91 -0
- package/dist/client/rpc/rpc-error.d.ts +19 -0
- package/dist/client/rpc/rpc-error.js +39 -0
- package/dist/constants/audio.d.ts +3 -0
- package/dist/constants/audio.js +17 -0
- package/dist/constants/index.d.ts +2 -0
- package/dist/constants/index.js +1 -0
- package/dist/examples/delegated-inference/consumer.d.ts +2 -0
- package/dist/examples/delegated-inference/consumer.js +56 -0
- package/dist/examples/delegated-inference/provider.d.ts +2 -0
- package/dist/examples/delegated-inference/provider.js +57 -0
- package/dist/examples/download-with-cancel.d.ts +2 -0
- package/dist/examples/download-with-cancel.js +46 -0
- package/dist/examples/embed-hyperdrive.d.ts +2 -0
- package/dist/examples/embed-hyperdrive.js +19 -0
- package/dist/examples/kv-cache-example.d.ts +2 -0
- package/dist/examples/kv-cache-example.js +74 -0
- package/dist/examples/llamacpp-file-logging.d.ts +2 -0
- package/dist/examples/llamacpp-file-logging.js +62 -0
- package/dist/examples/llamacpp-filesystem.d.ts +2 -0
- package/dist/examples/llamacpp-filesystem.js +40 -0
- package/dist/examples/llamacpp-http.d.ts +2 -0
- package/dist/examples/llamacpp-http.js +41 -0
- package/dist/examples/llamacpp-hyperdrive.d.ts +2 -0
- package/dist/examples/llamacpp-hyperdrive.js +39 -0
- package/dist/examples/llamacpp-multimodal.d.ts +2 -0
- package/dist/examples/llamacpp-multimodal.js +62 -0
- package/dist/examples/llamacpp-native-tools.d.ts +2 -0
- package/dist/examples/llamacpp-native-tools.js +64 -0
- package/dist/examples/llamacpp-tools-routing.d.ts +2 -0
- package/dist/examples/llamacpp-tools-routing.js +364 -0
- package/dist/examples/llamacpp-tools.d.ts +2 -0
- package/dist/examples/llamacpp-tools.js +81 -0
- package/dist/examples/multi-model-demo.d.ts +2 -0
- package/dist/examples/multi-model-demo.js +75 -0
- package/dist/examples/parallel-download.d.ts +2 -0
- package/dist/examples/parallel-download.js +21 -0
- package/dist/examples/rag/rag-chromadb.d.ts +2 -0
- package/dist/examples/rag/rag-chromadb.js +130 -0
- package/dist/examples/rag/rag-hyperdb-workspaces.d.ts +2 -0
- package/dist/examples/rag/rag-hyperdb-workspaces.js +106 -0
- package/dist/examples/rag/rag-hyperdb.d.ts +2 -0
- package/dist/examples/rag/rag-hyperdb.js +50 -0
- package/dist/examples/rag/rag-lancedb.d.ts +2 -0
- package/dist/examples/rag/rag-lancedb.js +95 -0
- package/dist/examples/rag/rag-sqlite.d.ts +2 -0
- package/dist/examples/rag/rag-sqlite.js +107 -0
- package/dist/examples/seed-hyperdrive.d.ts +2 -0
- package/dist/examples/seed-hyperdrive.js +21 -0
- package/dist/examples/translation/translation-indic.d.ts +2 -0
- package/dist/examples/translation/translation-indic.js +30 -0
- package/dist/examples/translation/translation-llm-context.d.ts +2 -0
- package/dist/examples/translation/translation-llm-context.js +30 -0
- package/dist/examples/translation/translation-llm.d.ts +2 -0
- package/dist/examples/translation/translation-llm.js +38 -0
- package/dist/examples/translation/translation-opus.d.ts +2 -0
- package/dist/examples/translation/translation-opus.js +30 -0
- package/dist/examples/translation/translation-stream.d.ts +2 -0
- package/dist/examples/translation/translation-stream.js +35 -0
- package/dist/examples/whispercpp-filesystem.d.ts +2 -0
- package/dist/examples/whispercpp-filesystem.js +43 -0
- package/dist/examples/whispercpp-microphone-record.d.ts +2 -0
- package/dist/examples/whispercpp-microphone-record.js +311 -0
- package/dist/expo/plugins/index.d.ts +5 -0
- package/dist/expo/plugins/index.js +5 -0
- package/dist/expo/plugins/withMobileBundle.d.ts +8 -0
- package/dist/expo/plugins/withMobileBundle.js +60 -0
- package/dist/expo/plugins/withOpenCL.d.ts +9 -0
- package/dist/expo/plugins/withOpenCL.js +118 -0
- package/dist/expo/plugins/withQvacSDK.d.ts +9 -0
- package/dist/expo/plugins/withQvacSDK.js +13 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +8 -0
- package/dist/logging/base-logger.d.ts +7 -0
- package/dist/logging/base-logger.js +55 -0
- package/dist/logging/index.d.ts +4 -0
- package/dist/logging/index.js +2 -0
- package/dist/logging/logger.d.ts +5 -0
- package/dist/logging/logger.js +28 -0
- package/dist/logging/stream-logger.d.ts +3 -0
- package/dist/logging/stream-logger.js +9 -0
- package/dist/logging/transport.d.ts +3 -0
- package/dist/logging/transport.js +15 -0
- package/dist/logging/types.d.ts +18 -0
- package/dist/logging/types.js +1 -0
- package/dist/logging/utils.d.ts +4 -0
- package/dist/logging/utils.js +47 -0
- package/dist/models/hyperdrive/index.d.ts +2 -0
- package/dist/models/hyperdrive/index.js +2 -0
- package/dist/models/hyperdrive/models.d.ts +475 -0
- package/dist/models/hyperdrive/models.js +534 -0
- package/dist/schemas/cancel.d.ts +33 -0
- package/dist/schemas/cancel.js +25 -0
- package/dist/schemas/common.d.ts +626 -0
- package/dist/schemas/common.js +47 -0
- package/dist/schemas/completion-stream.d.ts +125 -0
- package/dist/schemas/completion-stream.js +53 -0
- package/dist/schemas/delegate.d.ts +9 -0
- package/dist/schemas/delegate.js +9 -0
- package/dist/schemas/download-asset.d.ts +75 -0
- package/dist/schemas/download-asset.js +43 -0
- package/dist/schemas/embed.d.ts +20 -0
- package/dist/schemas/embed.js +14 -0
- package/dist/schemas/error.d.ts +13 -0
- package/dist/schemas/error.js +35 -0
- package/dist/schemas/index.d.ts +19 -0
- package/dist/schemas/index.js +19 -0
- package/dist/schemas/llamacpp-config.d.ts +30 -0
- package/dist/schemas/llamacpp-config.js +39 -0
- package/dist/schemas/load-model.d.ts +1259 -0
- package/dist/schemas/load-model.js +108 -0
- package/dist/schemas/logging-stream.d.ts +27 -0
- package/dist/schemas/logging-stream.js +16 -0
- package/dist/schemas/ping.d.ts +11 -0
- package/dist/schemas/ping.js +8 -0
- package/dist/schemas/provide.d.ts +43 -0
- package/dist/schemas/provide.js +25 -0
- package/dist/schemas/rag.d.ts +159 -0
- package/dist/schemas/rag.js +78 -0
- package/dist/schemas/transcription.d.ts +24 -0
- package/dist/schemas/transcription.js +15 -0
- package/dist/schemas/translate.d.ts +82 -0
- package/dist/schemas/translate.js +42 -0
- package/dist/schemas/translation-config.d.ts +83 -0
- package/dist/schemas/translation-config.js +46 -0
- package/dist/schemas/unload-model.d.ts +19 -0
- package/dist/schemas/unload-model.js +13 -0
- package/dist/schemas/whispercpp-config.d.ts +25 -0
- package/dist/schemas/whispercpp-config.js +18 -0
- package/dist/server/bare/addons/cancel.d.ts +3 -0
- package/dist/server/bare/addons/cancel.js +12 -0
- package/dist/server/bare/addons/index.d.ts +4 -0
- package/dist/server/bare/addons/index.js +3 -0
- package/dist/server/bare/addons/llamacpp/create-model.d.ts +5 -0
- package/dist/server/bare/addons/llamacpp/create-model.js +57 -0
- package/dist/server/bare/addons/llamacpp/handlers/completion-stream.d.ts +3 -0
- package/dist/server/bare/addons/llamacpp/handlers/completion-stream.js +65 -0
- package/dist/server/bare/addons/llamacpp/handlers/embed.d.ts +4 -0
- package/dist/server/bare/addons/llamacpp/handlers/embed.js +40 -0
- package/dist/server/bare/addons/llamacpp/index.d.ts +4 -0
- package/dist/server/bare/addons/llamacpp/index.js +3 -0
- package/dist/server/bare/addons/llamacpp/kv-cache-utils.d.ts +19 -0
- package/dist/server/bare/addons/llamacpp/kv-cache-utils.js +46 -0
- package/dist/server/bare/addons/load-model.d.ts +3 -0
- package/dist/server/bare/addons/load-model.js +55 -0
- package/dist/server/bare/addons/translation/create-model.d.ts +4 -0
- package/dist/server/bare/addons/translation/create-model.js +45 -0
- package/dist/server/bare/addons/translation/handlers/translate.d.ts +3 -0
- package/dist/server/bare/addons/translation/handlers/translate.js +86 -0
- package/dist/server/bare/addons/translation/index.d.ts +3 -0
- package/dist/server/bare/addons/translation/index.js +2 -0
- package/dist/server/bare/addons/unload-model.d.ts +3 -0
- package/dist/server/bare/addons/unload-model.js +20 -0
- package/dist/server/bare/addons/whispercpp/create-model.d.ts +6 -0
- package/dist/server/bare/addons/whispercpp/create-model.js +55 -0
- package/dist/server/bare/addons/whispercpp/handlers/transcribe-stream.d.ts +3 -0
- package/dist/server/bare/addons/whispercpp/handlers/transcribe-stream.js +42 -0
- package/dist/server/bare/addons/whispercpp/index.d.ts +3 -0
- package/dist/server/bare/addons/whispercpp/index.js +2 -0
- package/dist/server/bare/delegate-rpc-client.d.ts +4 -0
- package/dist/server/bare/delegate-rpc-client.js +70 -0
- package/dist/server/bare/hyperswarm.d.ts +7 -0
- package/dist/server/bare/hyperswarm.js +62 -0
- package/dist/server/bare/rag-hyperdb/handlers/delete-embeddings.d.ts +3 -0
- package/dist/server/bare/rag-hyperdb/handlers/delete-embeddings.js +12 -0
- package/dist/server/bare/rag-hyperdb/handlers/save-embeddings.d.ts +6 -0
- package/dist/server/bare/rag-hyperdb/handlers/save-embeddings.js +16 -0
- package/dist/server/bare/rag-hyperdb/handlers/search.d.ts +3 -0
- package/dist/server/bare/rag-hyperdb/handlers/search.js +15 -0
- package/dist/server/bare/rag-hyperdb/index.d.ts +5 -0
- package/dist/server/bare/rag-hyperdb/index.js +4 -0
- package/dist/server/bare/rag-hyperdb/rag-manager.d.ts +5 -0
- package/dist/server/bare/rag-hyperdb/rag-manager.js +61 -0
- package/dist/server/bare/registry/logging-stream-registry.d.ts +12 -0
- package/dist/server/bare/registry/logging-stream-registry.js +46 -0
- package/dist/server/bare/registry/model-registry.d.ts +64 -0
- package/dist/server/bare/registry/model-registry.js +95 -0
- package/dist/server/error-handlers.d.ts +4 -0
- package/dist/server/error-handlers.js +27 -0
- package/dist/server/http-server.d.ts +2 -0
- package/dist/server/http-server.js +189 -0
- package/dist/server/rpc/create-server.d.ts +4 -0
- package/dist/server/rpc/create-server.js +19 -0
- package/dist/server/rpc/handle-request.d.ts +12 -0
- package/dist/server/rpc/handle-request.js +220 -0
- package/dist/server/rpc/handlers/cancelHandler.d.ts +3 -0
- package/dist/server/rpc/handlers/cancelHandler.js +27 -0
- package/dist/server/rpc/handlers/completion-stream-delegated.d.ts +3 -0
- package/dist/server/rpc/handlers/completion-stream-delegated.js +30 -0
- package/dist/server/rpc/handlers/completion-stream.d.ts +3 -0
- package/dist/server/rpc/handlers/completion-stream.js +52 -0
- package/dist/server/rpc/handlers/download-asset.d.ts +3 -0
- package/dist/server/rpc/handlers/download-asset.js +21 -0
- package/dist/server/rpc/handlers/embed.d.ts +3 -0
- package/dist/server/rpc/handlers/embed.js +21 -0
- package/dist/server/rpc/handlers/index.d.ts +23 -0
- package/dist/server/rpc/handlers/index.js +22 -0
- package/dist/server/rpc/handlers/load-model/download-manager.d.ts +31 -0
- package/dist/server/rpc/handlers/load-model/download-manager.js +88 -0
- package/dist/server/rpc/handlers/load-model/http.d.ts +3 -0
- package/dist/server/rpc/handlers/load-model/http.js +337 -0
- package/dist/server/rpc/handlers/load-model/hyperdrive.d.ts +4 -0
- package/dist/server/rpc/handlers/load-model/hyperdrive.js +332 -0
- package/dist/server/rpc/handlers/load-model/index.d.ts +4 -0
- package/dist/server/rpc/handlers/load-model/index.js +3 -0
- package/dist/server/rpc/handlers/load-model/resolve.d.ts +3 -0
- package/dist/server/rpc/handlers/load-model/resolve.js +121 -0
- package/dist/server/rpc/handlers/load-model-delegated.d.ts +3 -0
- package/dist/server/rpc/handlers/load-model-delegated.js +93 -0
- package/dist/server/rpc/handlers/load-model.d.ts +3 -0
- package/dist/server/rpc/handlers/load-model.js +41 -0
- package/dist/server/rpc/handlers/logging-stream.d.ts +3 -0
- package/dist/server/rpc/handlers/logging-stream.js +37 -0
- package/dist/server/rpc/handlers/provideHandler/connection.d.ts +3 -0
- package/dist/server/rpc/handlers/provideHandler/connection.js +25 -0
- package/dist/server/rpc/handlers/provideHandler/handler.d.ts +3 -0
- package/dist/server/rpc/handlers/provideHandler/handler.js +50 -0
- package/dist/server/rpc/handlers/provideHandler/proxy.d.ts +3 -0
- package/dist/server/rpc/handlers/provideHandler/proxy.js +22 -0
- package/dist/server/rpc/handlers/provideHandler.d.ts +2 -0
- package/dist/server/rpc/handlers/provideHandler.js +2 -0
- package/dist/server/rpc/handlers/rag.d.ts +3 -0
- package/dist/server/rpc/handlers/rag.js +67 -0
- package/dist/server/rpc/handlers/transcribe-stream.d.ts +3 -0
- package/dist/server/rpc/handlers/transcribe-stream.js +26 -0
- package/dist/server/rpc/handlers/translate.d.ts +3 -0
- package/dist/server/rpc/handlers/translate.js +51 -0
- package/dist/server/rpc/handlers/unload-model.d.ts +3 -0
- package/dist/server/rpc/handlers/unload-model.js +20 -0
- package/dist/server/rpc/index.d.ts +3 -0
- package/dist/server/rpc/index.js +2 -0
- package/dist/server/utils/audio/decoder.d.ts +4 -0
- package/dist/server/utils/audio/decoder.js +41 -0
- package/dist/server/utils/cache.d.ts +15 -0
- package/dist/server/utils/cache.js +32 -0
- package/dist/server/utils/hash.d.ts +5 -0
- package/dist/server/utils/hash.js +11 -0
- package/dist/server/utils/index.d.ts +5 -0
- package/dist/server/utils/index.js +4 -0
- package/dist/server/utils/model-path.d.ts +5 -0
- package/dist/server/utils/model-path.js +7 -0
- package/dist/server/worker.d.ts +6 -0
- package/dist/server/worker.js +77 -0
- package/dist/utils/withTimeout.d.ts +11 -0
- package/dist/utils/withTimeout.js +37 -0
- package/package.json +129 -0
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
import fs, { promises as fsPromises } from "bare-fs";
|
|
2
|
+
import path from "bare-path";
|
|
3
|
+
import crypto from "bare-crypto";
|
|
4
|
+
import Corestore from "corestore";
|
|
5
|
+
import Hyperswarm, {} from "hyperswarm";
|
|
6
|
+
import Hyperdrive from "hyperdrive";
|
|
7
|
+
import {} from "bare-stream";
|
|
8
|
+
import { AbortController } from "bare-abort-controller";
|
|
9
|
+
import { getEnv } from "../../../worker.js";
|
|
10
|
+
import { getModelsCacheDir, generateShortHash } from "../../../utils/index.js";
|
|
11
|
+
import { getModelBySrc } from "../../../../models/hyperdrive/index.js";
|
|
12
|
+
import { getActiveDownload, registerDownload, unregisterDownload, createHyperdriveDownloadKey, shouldClearCache, clearClearCacheFlag, } from "./download-manager.js";
|
|
13
|
+
async function setupHyperdrive(hyperdriveKey, corestoreDir) {
|
|
14
|
+
const corestore = new Corestore(corestoreDir);
|
|
15
|
+
await corestore.ready();
|
|
16
|
+
const drive = new Hyperdrive(corestore, Buffer.from(hyperdriveKey, "hex"));
|
|
17
|
+
await drive.ready();
|
|
18
|
+
const swarm = new Hyperswarm();
|
|
19
|
+
swarm.join(drive.discoveryKey, { server: false, client: true });
|
|
20
|
+
swarm.on("connection", (connection) => {
|
|
21
|
+
console.log(`🤝 Connected to peer for hyperdrive download`);
|
|
22
|
+
drive.replicate(connection);
|
|
23
|
+
});
|
|
24
|
+
const doneFindingPeers = drive.findingPeers();
|
|
25
|
+
await swarm.flush();
|
|
26
|
+
doneFindingPeers();
|
|
27
|
+
return { corestore, drive, swarm, corestoreDir };
|
|
28
|
+
}
|
|
29
|
+
async function cleanupHyperdrive(setup) {
|
|
30
|
+
console.log("🧹 Cleaning up hyperdrive setup");
|
|
31
|
+
await setup.swarm.destroy();
|
|
32
|
+
await setup.drive.close();
|
|
33
|
+
await setup.corestore.close();
|
|
34
|
+
}
|
|
35
|
+
export async function deleteCorestoreDirectory(corestoreDir) {
|
|
36
|
+
console.log(`🗑️ DELETING corestore directory... ${corestoreDir}`);
|
|
37
|
+
try {
|
|
38
|
+
await fsPromises.rm(corestoreDir, { recursive: true, force: true });
|
|
39
|
+
}
|
|
40
|
+
catch (e) {
|
|
41
|
+
console.error(`Error deleting corestore directory: ${e instanceof Error ? e.message : String(e)}`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
async function findFileInHyperdrive(drive, modelFileName) {
|
|
45
|
+
const paths = [modelFileName, `/${modelFileName}`, `./${modelFileName}`];
|
|
46
|
+
let entry = null;
|
|
47
|
+
let targetPath = modelFileName;
|
|
48
|
+
for (const pathVariation of paths) {
|
|
49
|
+
try {
|
|
50
|
+
entry = await drive.entry(pathVariation);
|
|
51
|
+
if (entry) {
|
|
52
|
+
targetPath = pathVariation;
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
// Continue trying other paths
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
if (!entry) {
|
|
61
|
+
// Try listing available files to help debug
|
|
62
|
+
try {
|
|
63
|
+
const rootFiles = drive.list("/", false);
|
|
64
|
+
const availableFiles = [];
|
|
65
|
+
for await (const file of rootFiles) {
|
|
66
|
+
availableFiles.push(file.key);
|
|
67
|
+
}
|
|
68
|
+
if (availableFiles.length === 0) {
|
|
69
|
+
// Try without leading slash
|
|
70
|
+
const noSlashFiles = drive.list("", false);
|
|
71
|
+
for await (const file of noSlashFiles) {
|
|
72
|
+
availableFiles.push(file.key);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
throw new Error(`File ${modelFileName} not found in hyperdrive. Available files: ${availableFiles.join(", ")}`);
|
|
76
|
+
}
|
|
77
|
+
catch (listError) {
|
|
78
|
+
throw new Error(`File ${modelFileName} not found in hyperdrive. Could not list available files: ${listError instanceof Error ? listError.message : String(listError)}`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return { entry, targetPath };
|
|
82
|
+
}
|
|
83
|
+
async function validateFileChecksum(filePath, expectedChecksum) {
|
|
84
|
+
console.log(`🔍 Validating SHA256 checksum...`);
|
|
85
|
+
return new Promise((resolve) => {
|
|
86
|
+
try {
|
|
87
|
+
const hash = crypto.createHash("sha256");
|
|
88
|
+
const stream = fs.createReadStream(filePath);
|
|
89
|
+
stream.on("data", (chunk) => {
|
|
90
|
+
hash.update(chunk);
|
|
91
|
+
});
|
|
92
|
+
stream.on("end", () => {
|
|
93
|
+
const actualChecksum = hash.digest("hex");
|
|
94
|
+
console.log(`Expected: ${String(expectedChecksum)}`);
|
|
95
|
+
console.log(`Actual: ${String(actualChecksum)}`);
|
|
96
|
+
const isValid = actualChecksum === expectedChecksum;
|
|
97
|
+
if (isValid) {
|
|
98
|
+
console.log(`✅ Checksum validation passed!`);
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
console.log(`❌ Checksum validation FAILED! File may be corrupted.`);
|
|
102
|
+
}
|
|
103
|
+
resolve(isValid);
|
|
104
|
+
});
|
|
105
|
+
stream.on("error", (error) => {
|
|
106
|
+
console.error(`❌ Error validating checksum: ${error.message}`);
|
|
107
|
+
resolve(false);
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
console.error(`❌ Error validating checksum: ${error instanceof Error ? error.message : String(error)}`);
|
|
112
|
+
resolve(false);
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
async function validateCachedFile(modelPath, modelFileName, expectedSize, expectedChecksum) {
|
|
117
|
+
try {
|
|
118
|
+
await fsPromises.access(modelPath);
|
|
119
|
+
const localStats = await fsPromises.stat(modelPath);
|
|
120
|
+
const localSize = localStats.size;
|
|
121
|
+
// For hyperdrive: only validate if file is complete
|
|
122
|
+
// Partial files are ignored - corestore state is the source of truth for resume
|
|
123
|
+
if (localSize === expectedSize) {
|
|
124
|
+
console.log(`✅ Model cached with correct size: ${modelPath}`);
|
|
125
|
+
// Always validate checksum if provided, even when size matches
|
|
126
|
+
if (expectedChecksum && expectedChecksum.length === 64) {
|
|
127
|
+
const isValid = await validateFileChecksum(modelPath, expectedChecksum);
|
|
128
|
+
if (isValid) {
|
|
129
|
+
return modelPath;
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
throw new Error(`File ${modelFileName} is fully downloaded but checksum validation failed. Expected: ${expectedChecksum}. File may be corrupted.`);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
console.log(`✅ Model already cached and size validated: ${modelPath}`);
|
|
137
|
+
return modelPath;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
// File exists but incomplete - will be overwritten during download
|
|
141
|
+
// Resume state will be determined by corestore blocks, not file size
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
// Model doesn't exist, need to download
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
async function performHyperdriveDownload(modelPath, modelFileName, hyperdriveKey, corestoreDir, downloadKey, progressCallback, seed, signal) {
|
|
150
|
+
// Check if already aborted
|
|
151
|
+
if (signal?.aborted) {
|
|
152
|
+
throw new Error("Download cancelled");
|
|
153
|
+
}
|
|
154
|
+
console.log(`Downloading model from hyperdrive ${hyperdriveKey} to ${modelPath}`);
|
|
155
|
+
const setup = await setupHyperdrive(hyperdriveKey, corestoreDir);
|
|
156
|
+
let downloadedBytes = 0;
|
|
157
|
+
let totalBytes = 0;
|
|
158
|
+
// Set up abort handler
|
|
159
|
+
let readStream;
|
|
160
|
+
let writeStream;
|
|
161
|
+
const cleanup = () => {
|
|
162
|
+
console.log("🛑 Aborting hyperdrive download...");
|
|
163
|
+
// Destroy streams if they exist
|
|
164
|
+
if (readStream) {
|
|
165
|
+
readStream.destroy();
|
|
166
|
+
}
|
|
167
|
+
if (writeStream) {
|
|
168
|
+
writeStream.destroy();
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
signal?.addEventListener("abort", cleanup);
|
|
172
|
+
try {
|
|
173
|
+
const result = await findFileInHyperdrive(setup.drive, modelFileName);
|
|
174
|
+
const { entry, targetPath } = result;
|
|
175
|
+
totalBytes = entry?.value?.blob?.byteLength || 0;
|
|
176
|
+
console.log(`📏 Model size: ${totalBytes} bytes (${(totalBytes / 1024 / 1024).toFixed(2)} MB)`);
|
|
177
|
+
// Get blobs and file blob range
|
|
178
|
+
const blobs = await setup.drive.getBlobs();
|
|
179
|
+
const blob = entry?.value?.blob;
|
|
180
|
+
if (!blob) {
|
|
181
|
+
throw new Error(`No blob found for ${modelFileName}`);
|
|
182
|
+
}
|
|
183
|
+
// Check what blocks are already downloaded in corestore for this specific file
|
|
184
|
+
let alreadyDownloaded = 0;
|
|
185
|
+
for (let i = blob.blockOffset; i < blob.blockOffset + blob.blockLength; i++) {
|
|
186
|
+
const hasBlock = await blobs.core.has(i);
|
|
187
|
+
if (hasBlock) {
|
|
188
|
+
alreadyDownloaded++;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
downloadedBytes = 0;
|
|
192
|
+
if (alreadyDownloaded > 0) {
|
|
193
|
+
console.log(`📥 Resuming download (${alreadyDownloaded}/${blob.blockLength} blocks already in corestore)`);
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
console.log(`📥 Starting fresh download`);
|
|
197
|
+
}
|
|
198
|
+
// Track only downloads for blocks within our file's blob range
|
|
199
|
+
blobs.core.on("download", (index, bytes) => {
|
|
200
|
+
if (index >= blob.blockOffset &&
|
|
201
|
+
index < blob.blockOffset + blob.blockLength) {
|
|
202
|
+
downloadedBytes += bytes;
|
|
203
|
+
if (progressCallback) {
|
|
204
|
+
progressCallback({
|
|
205
|
+
type: "modelProgress",
|
|
206
|
+
downloaded: downloadedBytes,
|
|
207
|
+
total: totalBytes,
|
|
208
|
+
percentage: totalBytes > 0 ? (downloadedBytes / totalBytes) * 100 : 0,
|
|
209
|
+
downloadKey,
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
// Check if aborted before starting streams
|
|
215
|
+
if (signal?.aborted) {
|
|
216
|
+
throw new Error("Download cancelled");
|
|
217
|
+
}
|
|
218
|
+
// Trigger download for this file (hyperdrive will only download missing blocks)
|
|
219
|
+
setup.drive.download(targetPath);
|
|
220
|
+
readStream = setup.drive.createReadStream(targetPath);
|
|
221
|
+
writeStream = fs.createWriteStream(modelPath);
|
|
222
|
+
// Pipe the streams
|
|
223
|
+
readStream.pipe(writeStream);
|
|
224
|
+
// Wait for download to complete
|
|
225
|
+
await new Promise((resolve, reject) => {
|
|
226
|
+
writeStream.on("finish", () => resolve(undefined));
|
|
227
|
+
writeStream.on("error", reject);
|
|
228
|
+
readStream.on("error", reject);
|
|
229
|
+
// Also reject on abort
|
|
230
|
+
if (signal) {
|
|
231
|
+
signal.addEventListener("abort", () => {
|
|
232
|
+
reject(new Error("Download cancelled"));
|
|
233
|
+
}, { once: true });
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
console.log(`✅ Model downloaded successfully to ${modelPath}`);
|
|
237
|
+
// Delete corestore directory after successful download (only when not seeding, to save space)
|
|
238
|
+
if (!seed) {
|
|
239
|
+
await deleteCorestoreDirectory(setup.corestoreDir);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
catch (error) {
|
|
243
|
+
console.error("❌ Error during hyperdrive download:", error instanceof Error ? error.message : String(error));
|
|
244
|
+
// Preserve cancellation errors
|
|
245
|
+
if (error instanceof Error && error.message === "Download cancelled") {
|
|
246
|
+
throw error;
|
|
247
|
+
}
|
|
248
|
+
throw new Error(`Download failed for ${modelFileName} from hyperdrive: ${hyperdriveKey}`);
|
|
249
|
+
}
|
|
250
|
+
finally {
|
|
251
|
+
signal?.removeEventListener("abort", cleanup);
|
|
252
|
+
if (!seed) {
|
|
253
|
+
await cleanupHyperdrive(setup);
|
|
254
|
+
}
|
|
255
|
+
// Only delete corestore and partial file if user explicitly requested clearCache
|
|
256
|
+
if (signal?.aborted) {
|
|
257
|
+
if (shouldClearCache(downloadKey)) {
|
|
258
|
+
try {
|
|
259
|
+
await fsPromises.unlink(modelPath);
|
|
260
|
+
}
|
|
261
|
+
catch {
|
|
262
|
+
// no-op
|
|
263
|
+
}
|
|
264
|
+
await deleteCorestoreDirectory(corestoreDir);
|
|
265
|
+
}
|
|
266
|
+
clearClearCacheFlag(downloadKey);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
export async function downloadModelFromHyperdrive(hyperdriveKey, modelFileName, seed, progressCallback, expectedChecksum) {
|
|
271
|
+
const downloadKey = createHyperdriveDownloadKey(hyperdriveKey, modelFileName);
|
|
272
|
+
// Check if already downloading
|
|
273
|
+
const existing = getActiveDownload(downloadKey);
|
|
274
|
+
if (existing) {
|
|
275
|
+
return existing.promise;
|
|
276
|
+
}
|
|
277
|
+
const corestoreDir = path.join(getEnv().HOME_DIR, ".qvac", "corestore", hyperdriveKey);
|
|
278
|
+
const cacheDir = getModelsCacheDir();
|
|
279
|
+
const sourceHash = generateShortHash(`${hyperdriveKey}/${modelFileName}`);
|
|
280
|
+
const modelPath = path.join(cacheDir, `${sourceHash}_${modelFileName}`);
|
|
281
|
+
// Get model definition to get expected size (if it's a known model)
|
|
282
|
+
const model = getModelBySrc(modelFileName, hyperdriveKey);
|
|
283
|
+
// First, check if we already have a valid cached file (only if we have model metadata)
|
|
284
|
+
if (model) {
|
|
285
|
+
const cachedPath = await validateCachedFile(modelPath, modelFileName, model.expectedSize, expectedChecksum || model.sha256Checksum);
|
|
286
|
+
if (cachedPath) {
|
|
287
|
+
// Delete any leftover corestore directory from previous runs (only when not seeding)
|
|
288
|
+
if (!seed) {
|
|
289
|
+
await deleteCorestoreDirectory(corestoreDir);
|
|
290
|
+
}
|
|
291
|
+
return cachedPath;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
// Create managed download with AbortController
|
|
295
|
+
const abortController = new AbortController();
|
|
296
|
+
const downloadPromise = (async () => {
|
|
297
|
+
try {
|
|
298
|
+
// Download the file from hyperdrive
|
|
299
|
+
await performHyperdriveDownload(modelPath, modelFileName, hyperdriveKey, corestoreDir, downloadKey, progressCallback, seed, abortController.signal);
|
|
300
|
+
// Validate checksum using provided checksum or model's checksum (if available)
|
|
301
|
+
const checksumToValidate = expectedChecksum || model?.sha256Checksum;
|
|
302
|
+
if (checksumToValidate && checksumToValidate.length === 64) {
|
|
303
|
+
const isValid = await validateFileChecksum(modelPath, checksumToValidate);
|
|
304
|
+
if (!isValid) {
|
|
305
|
+
await fsPromises.unlink(modelPath);
|
|
306
|
+
throw new Error(`Checksum validation failed for ${modelFileName}`);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
else {
|
|
310
|
+
console.log(`⚠️ No valid checksum available for validation`);
|
|
311
|
+
}
|
|
312
|
+
return modelPath;
|
|
313
|
+
}
|
|
314
|
+
finally {
|
|
315
|
+
// Cleanup from download manager
|
|
316
|
+
unregisterDownload(downloadKey);
|
|
317
|
+
}
|
|
318
|
+
})();
|
|
319
|
+
// Register download
|
|
320
|
+
const downloadEntry = {
|
|
321
|
+
key: downloadKey,
|
|
322
|
+
promise: downloadPromise,
|
|
323
|
+
abortController,
|
|
324
|
+
startTime: Date.now(),
|
|
325
|
+
type: "hyperdrive",
|
|
326
|
+
hyperdriveKey,
|
|
327
|
+
modelFileName,
|
|
328
|
+
...(progressCallback && { onProgress: progressCallback }),
|
|
329
|
+
};
|
|
330
|
+
registerDownload(downloadKey, downloadEntry);
|
|
331
|
+
return downloadPromise;
|
|
332
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { getModelBySrc, models } from "../../../../models/hyperdrive/models.js";
|
|
2
|
+
import { hyperdriveUrlSchema } from "../../../../schemas/index.js";
|
|
3
|
+
import { getModelsCacheDir } from "../../../utils/index.js";
|
|
4
|
+
import { promises as fsPromises } from "bare-fs";
|
|
5
|
+
import path from "bare-path";
|
|
6
|
+
import { downloadModelFromHttp } from "./http.js";
|
|
7
|
+
import { downloadModelFromHyperdrive } from "./hyperdrive.js";
|
|
8
|
+
/**
|
|
9
|
+
* Attempts to resolve a model from cache (without validation)
|
|
10
|
+
* Validation will be handled by the hyperdrive download logic
|
|
11
|
+
*/
|
|
12
|
+
async function tryResolveCachedModel(modelId) {
|
|
13
|
+
const cacheDir = getModelsCacheDir();
|
|
14
|
+
const cachedPath = path.join(cacheDir, modelId);
|
|
15
|
+
try {
|
|
16
|
+
await fsPromises.access(cachedPath);
|
|
17
|
+
// File exists - return null to let hyperdrive validation handle size/checksum
|
|
18
|
+
// This ensures partial downloads are properly resumed instead of being
|
|
19
|
+
// incorrectly validated and deleted
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
// File doesn't exist
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Resolves a known model by ID from hyperdrive, checking cache first
|
|
29
|
+
*/
|
|
30
|
+
async function resolveKnownModel(model, modelIdOrPath, progressCallback, seed) {
|
|
31
|
+
if (!model) {
|
|
32
|
+
throw new Error("Model is null");
|
|
33
|
+
}
|
|
34
|
+
console.log(`Loading model ID '${modelIdOrPath}' from hyperdrive`);
|
|
35
|
+
// Try to resolve from cache first
|
|
36
|
+
const cachedPath = await tryResolveCachedModel(model.modelId);
|
|
37
|
+
if (cachedPath) {
|
|
38
|
+
return cachedPath;
|
|
39
|
+
}
|
|
40
|
+
// Not cached or invalid, download from hyperdrive
|
|
41
|
+
const downloadedPath = await downloadModelFromHyperdrive(model.hyperdriveKey, model.modelId, seed, progressCallback, model.sha256Checksum);
|
|
42
|
+
return downloadedPath;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Resolves a local file path or cached file
|
|
46
|
+
*/
|
|
47
|
+
async function resolveLocalOrCachedFile(modelIdOrPath) {
|
|
48
|
+
// Check if it's a hex string (arbitrary hyperdrive key)
|
|
49
|
+
const isHexString = /^[0-9a-fA-F]{64}$/.test(modelIdOrPath);
|
|
50
|
+
if (isHexString) {
|
|
51
|
+
throw new Error(`Direct hyperdrive keys not supported. Use hyperdriveKey parameter instead. Example: loadModel("model.gguf", "${modelIdOrPath}")`);
|
|
52
|
+
}
|
|
53
|
+
// Check if it's a cached file or local file
|
|
54
|
+
const cacheDir = getModelsCacheDir();
|
|
55
|
+
const cachedPath = path.join(cacheDir, modelIdOrPath);
|
|
56
|
+
try {
|
|
57
|
+
await fsPromises.access(cachedPath);
|
|
58
|
+
console.log(`Loading cached model: ${cachedPath}`);
|
|
59
|
+
return cachedPath;
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
// Try as local file in current directory
|
|
63
|
+
try {
|
|
64
|
+
await fsPromises.access(modelIdOrPath);
|
|
65
|
+
console.log(`Loading local file: ${modelIdOrPath}`);
|
|
66
|
+
return modelIdOrPath;
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
// Invalid model ID - provide helpful error
|
|
70
|
+
const availableModels = models.map((m) => m.modelId);
|
|
71
|
+
throw new Error(`Invalid model ID: "${modelIdOrPath}". Available models: ${availableModels.join(", ")}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
export async function resolveModelPath(modelSrc, progressCallback, seed) {
|
|
76
|
+
// Parse hyperdrive URLs if present
|
|
77
|
+
let hyperdriveKey;
|
|
78
|
+
let actualModelSrc = modelSrc;
|
|
79
|
+
if (modelSrc.startsWith("pear://")) {
|
|
80
|
+
const { key, path } = hyperdriveUrlSchema.parse(modelSrc);
|
|
81
|
+
hyperdriveKey = key;
|
|
82
|
+
actualModelSrc = path;
|
|
83
|
+
}
|
|
84
|
+
let actualPath;
|
|
85
|
+
// Validate seeding is only used with hyperdrive models
|
|
86
|
+
if (seed && !hyperdriveKey) {
|
|
87
|
+
const model = getModelBySrc(actualModelSrc);
|
|
88
|
+
if (!model) {
|
|
89
|
+
throw new Error("Seeding is only supported for hyperdrive models");
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
// Check if it's an HTTP/HTTPS URL
|
|
93
|
+
if (actualModelSrc.startsWith("http://") ||
|
|
94
|
+
actualModelSrc.startsWith("https://")) {
|
|
95
|
+
console.log(`Loading from HTTP URL: ${actualModelSrc}`);
|
|
96
|
+
actualPath = await downloadModelFromHttp(actualModelSrc, progressCallback);
|
|
97
|
+
console.log(`Loaded Model to ${actualPath}`);
|
|
98
|
+
}
|
|
99
|
+
else if (hyperdriveKey) {
|
|
100
|
+
// Direct hyperdrive loading
|
|
101
|
+
console.log(`Loading from hyperdrive: ${hyperdriveKey}`);
|
|
102
|
+
actualPath = await downloadModelFromHyperdrive(hyperdriveKey, actualModelSrc, seed, progressCallback);
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
// Try to resolve as a known model ID
|
|
106
|
+
const model = getModelBySrc(actualModelSrc);
|
|
107
|
+
if (model) {
|
|
108
|
+
actualPath = await resolveKnownModel(model, actualModelSrc, progressCallback, seed);
|
|
109
|
+
}
|
|
110
|
+
else if (actualModelSrc.includes("/") || actualModelSrc.includes("\\")) {
|
|
111
|
+
// Handle file paths (absolute or relative with slashes)
|
|
112
|
+
console.log(`Loading from file: ${actualModelSrc}`);
|
|
113
|
+
actualPath = actualModelSrc;
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
// Handle local files and cached files
|
|
117
|
+
actualPath = await resolveLocalOrCachedFile(actualModelSrc);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return actualPath;
|
|
121
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { LoadModelRequest, LoadModelResponse, ModelProgressUpdate } from "../../../schemas/index";
|
|
2
|
+
export declare function handleLoadModelDelegated(request: LoadModelRequest, progressCallback?: (update: ModelProgressUpdate) => void): Promise<LoadModelResponse>;
|
|
3
|
+
//# sourceMappingURL=load-model-delegated.d.ts.map
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { registerModel } from "../../bare/registry/model-registry.js";
|
|
2
|
+
import { getRPC } from "../../bare/delegate-rpc-client.js";
|
|
3
|
+
import { send, stream } from "../../../client/rpc/rpc-client.js";
|
|
4
|
+
import { handleLoadModel } from "./load-model/index.js";
|
|
5
|
+
export async function handleLoadModelDelegated(request, progressCallback) {
|
|
6
|
+
if (!request.delegate) {
|
|
7
|
+
throw new Error("Delegate information is required for delegated load model");
|
|
8
|
+
}
|
|
9
|
+
const { delegate } = request;
|
|
10
|
+
const { topic, providerPublicKey, timeout, fallbackToLocal } = delegate;
|
|
11
|
+
try {
|
|
12
|
+
console.log(`📤 Sending delegated loadModel request to provider: ${providerPublicKey}${timeout ? `, timeout: ${timeout}ms` : ""}`);
|
|
13
|
+
// Create RPC instance for this HyperSwarm peer
|
|
14
|
+
const rpc = await getRPC(topic, providerPublicKey, { timeout });
|
|
15
|
+
// Strip out the delegate field to avoid infinite delegation
|
|
16
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
17
|
+
const { delegate: _, ...providerRequest } = request;
|
|
18
|
+
let finalResponse;
|
|
19
|
+
if (request.withProgress) {
|
|
20
|
+
// Use streaming for progress updates
|
|
21
|
+
console.log("📊 Using streaming mode for loadModel with progress");
|
|
22
|
+
const responseStream = stream(providerRequest, rpc, timeout ? { timeout } : {});
|
|
23
|
+
for await (const response of responseStream) {
|
|
24
|
+
if (response.type === "modelProgress") {
|
|
25
|
+
// Forward progress updates to the client
|
|
26
|
+
if (progressCallback) {
|
|
27
|
+
progressCallback(response);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
else if (response.type === "loadModel") {
|
|
31
|
+
finalResponse = response;
|
|
32
|
+
break;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
if (!finalResponse) {
|
|
36
|
+
throw new Error("No final response received from provider");
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
// Use simple send for non-progress requests
|
|
41
|
+
console.log("📤 Using simple send mode for loadModel");
|
|
42
|
+
finalResponse = (await send(providerRequest, rpc, timeout ? { timeout } : {}));
|
|
43
|
+
}
|
|
44
|
+
if (!finalResponse || !finalResponse.success) {
|
|
45
|
+
console.error("Provider failed to load model:", finalResponse?.error);
|
|
46
|
+
return {
|
|
47
|
+
type: "loadModel",
|
|
48
|
+
success: false,
|
|
49
|
+
error: `Provider failed to load model: ${finalResponse?.error || "Unknown error"}`,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
// Register the delegated model with provider info
|
|
53
|
+
const modelId = finalResponse.modelId || request.modelSrc || `delegated-${Date.now()}`;
|
|
54
|
+
const delegateOptions = {
|
|
55
|
+
topic,
|
|
56
|
+
providerPublicKey,
|
|
57
|
+
};
|
|
58
|
+
if (timeout !== undefined) {
|
|
59
|
+
delegateOptions.timeout = timeout;
|
|
60
|
+
}
|
|
61
|
+
registerModel(modelId, delegateOptions);
|
|
62
|
+
console.log(`✅ Delegated model registered: ${modelId} -> provider: ${providerPublicKey}`);
|
|
63
|
+
return {
|
|
64
|
+
type: "loadModel",
|
|
65
|
+
success: true,
|
|
66
|
+
modelId,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
console.error("Error in delegated load model:", error);
|
|
71
|
+
if (fallbackToLocal) {
|
|
72
|
+
console.log("🔄 Fallback to local model loading enabled, attempting local load...");
|
|
73
|
+
try {
|
|
74
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
75
|
+
const { delegate: _, ...localRequest } = request;
|
|
76
|
+
return await handleLoadModel(localRequest, progressCallback);
|
|
77
|
+
}
|
|
78
|
+
catch (localError) {
|
|
79
|
+
console.error("❌ Local fallback also failed:", localError);
|
|
80
|
+
return {
|
|
81
|
+
type: "loadModel",
|
|
82
|
+
success: false,
|
|
83
|
+
error: `Both delegated and local loading failed. Delegated error: ${error instanceof Error ? error.message : String(error)}. Local error: ${localError instanceof Error ? localError.message : String(localError)}`,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return {
|
|
88
|
+
type: "loadModel",
|
|
89
|
+
success: false,
|
|
90
|
+
error: error instanceof Error ? error.message : "Unknown error",
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { LoadModelRequest, LoadModelResponse, ModelProgressUpdate } from "../../../schemas/index";
|
|
2
|
+
export declare function handleLoadModel(request: LoadModelRequest, progressCallback?: (update: ModelProgressUpdate) => void): Promise<LoadModelResponse>;
|
|
3
|
+
//# sourceMappingURL=load-model.d.ts.map
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { loadModel } from "../../bare/addons/index.js";
|
|
2
|
+
import { resolveModelPath } from "./load-model/resolve.js";
|
|
3
|
+
import { generateShortHash } from "../../utils/index.js";
|
|
4
|
+
export async function handleLoadModel(request, progressCallback) {
|
|
5
|
+
const { modelSrc, seed, projectionModelSrc, vadModelSrc } = request;
|
|
6
|
+
try {
|
|
7
|
+
const modelPath = await resolveModelPath(modelSrc, progressCallback, seed);
|
|
8
|
+
let projectionModelPath;
|
|
9
|
+
if (projectionModelSrc) {
|
|
10
|
+
projectionModelPath = await resolveModelPath(projectionModelSrc, progressCallback, seed);
|
|
11
|
+
}
|
|
12
|
+
let vadModelPath;
|
|
13
|
+
if (vadModelSrc) {
|
|
14
|
+
vadModelPath = await resolveModelPath(vadModelSrc, progressCallback, seed);
|
|
15
|
+
}
|
|
16
|
+
// Generate hash-based modelId
|
|
17
|
+
const configStr = JSON.stringify(request.modelConfig, Object.keys(request.modelConfig).sort());
|
|
18
|
+
const modelHashInput = `${request.modelType}:${modelSrc}:${configStr}`;
|
|
19
|
+
const modelId = generateShortHash(modelHashInput);
|
|
20
|
+
await loadModel({
|
|
21
|
+
modelId,
|
|
22
|
+
modelPath,
|
|
23
|
+
options: request,
|
|
24
|
+
projectionModelPath,
|
|
25
|
+
vadModelPath,
|
|
26
|
+
});
|
|
27
|
+
return {
|
|
28
|
+
type: "loadModel",
|
|
29
|
+
success: true,
|
|
30
|
+
modelId,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
console.error("Error loading model:", error);
|
|
35
|
+
return {
|
|
36
|
+
type: "loadModel",
|
|
37
|
+
success: false,
|
|
38
|
+
error: error instanceof Error ? error.message : "Unknown error",
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { registerLoggingStream, unregisterLoggingStream, } from "../../bare/registry/logging-stream-registry.js";
|
|
2
|
+
export async function* handleLoggingStream(request) {
|
|
3
|
+
const { modelId } = request;
|
|
4
|
+
const logQueue = [];
|
|
5
|
+
let pendingResolve = null;
|
|
6
|
+
const streamHandler = (level, namespace, message) => {
|
|
7
|
+
const logResponse = {
|
|
8
|
+
type: "loggingStream",
|
|
9
|
+
modelId,
|
|
10
|
+
level: level,
|
|
11
|
+
namespace,
|
|
12
|
+
message,
|
|
13
|
+
timestamp: Date.now(),
|
|
14
|
+
};
|
|
15
|
+
logQueue.push(logResponse);
|
|
16
|
+
if (pendingResolve) {
|
|
17
|
+
const resolve = pendingResolve;
|
|
18
|
+
pendingResolve = null;
|
|
19
|
+
resolve();
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
registerLoggingStream(modelId, streamHandler);
|
|
23
|
+
try {
|
|
24
|
+
while (true) {
|
|
25
|
+
while (logQueue.length > 0) {
|
|
26
|
+
yield logQueue.shift();
|
|
27
|
+
}
|
|
28
|
+
// Wait for new logs - stream will terminate when client disconnects
|
|
29
|
+
await new Promise((resolve) => {
|
|
30
|
+
pendingResolve = resolve;
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
finally {
|
|
35
|
+
unregisterLoggingStream(modelId, streamHandler);
|
|
36
|
+
}
|
|
37
|
+
}
|