@qvac/sdk 0.7.0 → 0.8.0
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/NOTICE +57 -331
- package/README.md +2 -2
- package/bare-imports.json +9 -0
- package/dist/client/api/completion-stream.d.ts +2 -1
- package/dist/client/api/completion-stream.js +2 -1
- package/dist/client/api/download-asset.d.ts +3 -2
- package/dist/client/api/download-asset.js +4 -3
- package/dist/client/api/embed.d.ts +5 -2
- package/dist/client/api/embed.js +2 -2
- package/dist/client/api/get-model-info.d.ts +1 -1
- package/dist/client/api/invoke-plugin.d.ts +3 -2
- package/dist/client/api/invoke-plugin.js +4 -4
- package/dist/client/api/load-model.d.ts +12 -10
- package/dist/client/api/load-model.js +3 -3
- package/dist/client/api/rag.d.ts +10 -10
- package/dist/client/api/rag.js +21 -21
- package/dist/client/api/text-to-speech.d.ts +2 -2
- package/dist/client/api/text-to-speech.js +3 -3
- package/dist/client/api/transcribe.d.ts +5 -3
- package/dist/client/api/transcribe.js +6 -4
- package/dist/client/api/translate.d.ts +2 -2
- package/dist/client/api/translate.js +3 -3
- package/dist/client/rpc/node-rpc-client.d.ts +2 -7
- package/dist/client/rpc/node-rpc-client.js +2 -39
- package/dist/client/rpc/profiling/index.d.ts +2 -0
- package/dist/client/rpc/profiling/index.js +1 -0
- package/dist/client/rpc/profiling/profiler.d.ts +27 -0
- package/dist/client/rpc/profiling/profiler.js +139 -0
- package/dist/client/rpc/rpc-client.d.ts +2 -2
- package/dist/client/rpc/rpc-client.js +174 -12
- package/dist/examples/delegated-inference/consumer-profiled.d.ts +2 -0
- package/dist/examples/delegated-inference/consumer-profiled.js +67 -0
- package/dist/examples/llamacpp-multimodal.js +1 -1
- package/dist/examples/parallel-download.js +45 -13
- package/dist/examples/profiling/basic.d.ts +2 -0
- package/dist/examples/profiling/basic.js +71 -0
- package/dist/examples/profiling/per-call.d.ts +2 -0
- package/dist/examples/profiling/per-call.js +30 -0
- package/dist/examples/transcription/parakeet-ctc-filesystem.d.ts +2 -0
- package/dist/examples/transcription/parakeet-ctc-filesystem.js +40 -0
- package/dist/examples/transcription/parakeet-microphone-record.d.ts +2 -0
- package/dist/examples/transcription/parakeet-microphone-record.js +95 -0
- package/dist/examples/transcription/parakeet-sortformer.d.ts +2 -0
- package/dist/examples/transcription/parakeet-sortformer.js +115 -0
- package/dist/examples/transcription/parakeet-tdt-filesystem.d.ts +2 -0
- package/dist/examples/transcription/parakeet-tdt-filesystem.js +44 -0
- package/dist/examples/translation/translation-bergamot-pivot.d.ts +2 -0
- package/dist/examples/translation/translation-bergamot-pivot.js +73 -0
- package/dist/examples/translation/translation-llm-afriquegemma.d.ts +2 -0
- package/dist/examples/translation/translation-llm-afriquegemma.js +39 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +2 -0
- package/dist/logging/index.d.ts +1 -1
- package/dist/logging/index.js +1 -1
- package/dist/logging/namespaces.d.ts +3 -9
- package/dist/logging/namespaces.js +2 -8
- package/dist/logging/registry.js +15 -1
- package/dist/models/registry/models.d.ts +1606 -245
- package/dist/models/registry/models.js +2127 -721
- package/dist/models/update-models/codegen.js +2 -2
- package/dist/models/update-models/history.d.ts +11 -0
- package/dist/models/update-models/history.js +24 -5
- package/dist/models/update-models/index.js +17 -16
- package/dist/models/update-models/naming.js +56 -0
- package/dist/profiling/aggregator.d.ts +15 -0
- package/dist/profiling/aggregator.js +100 -0
- package/dist/profiling/clock.d.ts +12 -0
- package/dist/profiling/clock.js +51 -0
- package/dist/profiling/controller.d.ts +33 -0
- package/dist/profiling/controller.js +123 -0
- package/dist/profiling/envelope.d.ts +10 -0
- package/dist/profiling/envelope.js +36 -0
- package/dist/profiling/events.d.ts +20 -0
- package/dist/profiling/events.js +37 -0
- package/dist/profiling/exporters.d.ts +10 -0
- package/dist/profiling/exporters.js +236 -0
- package/dist/profiling/index.d.ts +36 -0
- package/dist/profiling/index.js +31 -0
- package/dist/profiling/ring-buffer.d.ts +19 -0
- package/dist/profiling/ring-buffer.js +83 -0
- package/dist/profiling/types.d.ts +47 -0
- package/dist/profiling/types.js +1 -0
- package/dist/schemas/common.d.ts +1888 -133
- package/dist/schemas/common.js +2 -0
- package/dist/schemas/completion-stream.d.ts +31 -0
- package/dist/schemas/completion-stream.js +13 -0
- package/dist/schemas/download-asset.d.ts +14 -3
- package/dist/schemas/download-asset.js +3 -1
- package/dist/schemas/engine-addon-map.js +9 -6
- package/dist/schemas/get-model-info.d.ts +2 -0
- package/dist/schemas/get-model-info.js +1 -0
- package/dist/schemas/index.d.ts +2 -1
- package/dist/schemas/index.js +2 -1
- package/dist/schemas/llamacpp-config.d.ts +140 -14
- package/dist/schemas/llamacpp-config.js +11 -7
- package/dist/schemas/load-model.d.ts +9649 -2515
- package/dist/schemas/load-model.js +142 -182
- package/dist/schemas/model-src-utils.d.ts +10 -2
- package/dist/schemas/model-types.d.ts +19 -1
- package/dist/schemas/model-types.js +11 -0
- package/dist/schemas/ocr.d.ts +37 -0
- package/dist/schemas/ocr.js +5 -0
- package/dist/schemas/plugin.d.ts +51 -5
- package/dist/schemas/plugin.js +26 -0
- package/dist/schemas/profiling.d.ts +105 -0
- package/dist/schemas/profiling.js +66 -0
- package/dist/schemas/registry.d.ts +18 -0
- package/dist/schemas/registry.js +2 -0
- package/dist/schemas/reload-config.d.ts +126 -6
- package/dist/schemas/reload-config.js +1 -1
- package/dist/schemas/sdk-config.d.ts +2280 -24
- package/dist/schemas/sdk-config.js +6 -1
- package/dist/schemas/sdk-errors-client.d.ts +1 -0
- package/dist/schemas/sdk-errors-client.js +7 -0
- package/dist/schemas/sdk-errors-server.d.ts +3 -0
- package/dist/schemas/sdk-errors-server.js +15 -0
- package/dist/schemas/text-to-speech.d.ts +90 -68
- package/dist/schemas/text-to-speech.js +16 -33
- package/dist/schemas/transcription-config.d.ts +383 -0
- package/dist/schemas/{whispercpp-config.js → transcription-config.js} +29 -1
- package/dist/schemas/translation-config.d.ts +463 -8
- package/dist/schemas/translation-config.js +35 -2
- package/dist/server/bare/delegate-rpc-client.js +11 -1
- package/dist/server/bare/ops/load-model.d.ts +7 -1
- package/dist/server/bare/ops/load-model.js +41 -42
- package/dist/server/bare/ops/transcribe.d.ts +3 -0
- package/dist/server/bare/ops/transcribe.js +75 -0
- package/dist/server/bare/ops/translate.d.ts +2 -0
- package/dist/server/bare/ops/translate.js +12 -4
- package/dist/server/bare/plugins/index.d.ts +1 -0
- package/dist/server/bare/plugins/index.js +1 -0
- package/dist/server/bare/plugins/llamacpp-completion/ops/completion-stream.d.ts +2 -1
- package/dist/server/bare/plugins/llamacpp-completion/ops/completion-stream.js +8 -6
- package/dist/server/bare/plugins/llamacpp-completion/plugin.d.ts +108 -3
- package/dist/server/bare/plugins/llamacpp-completion/plugin.js +19 -6
- package/dist/server/bare/plugins/llamacpp-embedding/plugin.d.ts +32 -2
- package/dist/server/bare/plugins/llamacpp-embedding/plugin.js +31 -17
- package/dist/server/bare/plugins/nmtcpp-translation/plugin.d.ts +325 -3
- package/dist/server/bare/plugins/nmtcpp-translation/plugin.js +117 -10
- package/dist/server/bare/plugins/onnx-ocr/plugin.d.ts +50 -2
- package/dist/server/bare/plugins/onnx-ocr/plugin.js +46 -5
- package/dist/server/bare/plugins/onnx-tts/plugin.d.ts +351 -4
- package/dist/server/bare/plugins/onnx-tts/plugin.js +81 -61
- package/dist/server/bare/plugins/parakeet-transcription/plugin.d.ts +317 -0
- package/dist/server/bare/plugins/parakeet-transcription/plugin.js +154 -0
- package/dist/server/bare/plugins/whispercpp-transcription/plugin.d.ts +209 -3
- package/dist/server/bare/plugins/whispercpp-transcription/plugin.js +21 -9
- package/dist/server/bare/rag-hyperdb/rag-workspace-manager.js +2 -2
- package/dist/server/bare/registry/model-config-utils.js +3 -1
- package/dist/server/bare/utils/audio-input.d.ts +10 -0
- package/dist/server/bare/utils/audio-input.js +33 -0
- package/dist/server/error-handlers.d.ts +3 -2
- package/dist/server/error-handlers.js +11 -8
- package/dist/server/plugins/registry.js +5 -1
- package/dist/server/rpc/delegate-transport.d.ts +11 -3
- package/dist/server/rpc/delegate-transport.js +158 -3
- package/dist/server/rpc/handle-request.js +43 -4
- package/dist/server/rpc/handler-registry.js +7 -1
- package/dist/server/rpc/handler-utils.d.ts +5 -4
- package/dist/server/rpc/handler-utils.js +72 -31
- package/dist/server/rpc/handlers/completion-stream-delegated.d.ts +3 -1
- package/dist/server/rpc/handlers/completion-stream-delegated.js +11 -2
- package/dist/server/rpc/handlers/download-asset.js +55 -3
- package/dist/server/rpc/handlers/load-model/download-stats.d.ts +6 -0
- package/dist/server/rpc/handlers/load-model/download-stats.js +87 -0
- package/dist/server/rpc/handlers/load-model/handler.js +108 -123
- package/dist/server/rpc/handlers/load-model/http.d.ts +2 -1
- package/dist/server/rpc/handlers/load-model/http.js +21 -5
- package/dist/server/rpc/handlers/load-model/hyperdrive.d.ts +2 -1
- package/dist/server/rpc/handlers/load-model/hyperdrive.js +19 -14
- package/dist/server/rpc/handlers/load-model/registry.d.ts +2 -1
- package/dist/server/rpc/handlers/load-model/registry.js +123 -130
- package/dist/server/rpc/handlers/load-model/resolve.d.ts +2 -0
- package/dist/server/rpc/handlers/load-model/resolve.js +55 -22
- package/dist/server/rpc/handlers/load-model/types.d.ts +29 -0
- package/dist/server/rpc/handlers/load-model/types.js +1 -0
- package/dist/server/rpc/handlers/load-model-delegated.d.ts +5 -1
- package/dist/server/rpc/handlers/load-model-delegated.js +35 -7
- package/dist/server/rpc/handlers/plugin-dispatch.js +15 -10
- package/dist/server/rpc/handlers/plugin-invoke.js +56 -51
- package/dist/server/rpc/handlers/rag.js +24 -0
- package/dist/server/rpc/handlers/unload-model-delegated.d.ts +3 -0
- package/dist/server/rpc/handlers/unload-model-delegated.js +32 -0
- package/dist/server/rpc/profiling/context.d.ts +18 -0
- package/dist/server/rpc/profiling/context.js +38 -0
- package/dist/server/rpc/profiling/delegation-profiler.d.ts +32 -0
- package/dist/server/rpc/profiling/delegation-profiler.js +154 -0
- package/dist/server/rpc/profiling/index.d.ts +5 -0
- package/dist/server/rpc/profiling/index.js +4 -0
- package/dist/server/rpc/profiling/operation-metrics.d.ts +25 -0
- package/dist/server/rpc/profiling/operation-metrics.js +199 -0
- package/dist/server/rpc/profiling/operation-wrappers.d.ts +18 -0
- package/dist/server/rpc/profiling/operation-wrappers.js +124 -0
- package/dist/server/rpc/profiling/profiler.d.ts +13 -0
- package/dist/server/rpc/profiling/profiler.js +97 -0
- package/dist/server/utils/cache.d.ts +2 -1
- package/dist/server/utils/cache.js +5 -1
- package/dist/server/utils/checksum.d.ts +2 -0
- package/dist/server/utils/checksum.js +7 -0
- package/dist/server/utils/formatting.d.ts +6 -0
- package/dist/server/utils/formatting.js +35 -0
- package/dist/server/worker.js +2 -1
- package/dist/utils/errors-client.d.ts +3 -0
- package/dist/utils/errors-client.js +6 -0
- package/dist/utils/errors-server.d.ts +9 -0
- package/dist/utils/errors-server.js +15 -0
- package/dist/utils/global-singleton.d.ts +2 -0
- package/dist/utils/global-singleton.js +10 -0
- package/package.json +14 -17
- package/dist/schemas/whispercpp-config.d.ts +0 -70
- package/dist/server/bare/plugins/whispercpp-transcription/ops/transcribe-stream.d.ts +0 -3
- package/dist/server/bare/plugins/whispercpp-transcription/ops/transcribe-stream.js +0 -81
- /package/dist/examples/{whispercpp-filesystem.d.ts → transcription/whispercpp-filesystem.d.ts} +0 -0
- /package/dist/examples/{whispercpp-filesystem.js → transcription/whispercpp-filesystem.js} +0 -0
- /package/dist/examples/{whispercpp-microphone-record.d.ts → transcription/whispercpp-microphone-record.d.ts} +0 -0
- /package/dist/examples/{whispercpp-microphone-record.js → transcription/whispercpp-microphone-record.js} +0 -0
- /package/dist/examples/{whispercpp-prompt.d.ts → transcription/whispercpp-prompt.d.ts} +0 -0
- /package/dist/examples/{whispercpp-prompt.js → transcription/whispercpp-prompt.js} +0 -0
|
@@ -1,112 +1,135 @@
|
|
|
1
|
-
import { normalizeModelType,
|
|
2
|
-
import { hyperdriveUrlSchema } from "../../../../schemas/load-model.js";
|
|
1
|
+
import { normalizeModelType, PROFILING_KEY, OPERATION_EVENT_KEY, } from "../../../../schemas/index.js";
|
|
3
2
|
import { loadModel } from "../../../bare/ops/load-model.js";
|
|
4
|
-
import { resolveModelPath } from "./resolve.js";
|
|
3
|
+
import { resolveModelPath, resolveModelPathWithStats, } from "./resolve.js";
|
|
4
|
+
import { nowMs, generateProfileId } from "../../../../profiling/clock.js";
|
|
5
5
|
import { getModelEntry, updateModelConfig, } from "../../../bare/registry/model-registry.js";
|
|
6
|
-
import { generateShortHash, transformConfigForReload } from "../../../utils/index.js";
|
|
7
|
-
import { ConfigReloadNotSupportedError, ModelTypeMismatchError, ModelIsDelegatedError, ModelNotFoundError, } from "../../../../utils/errors-server.js";
|
|
6
|
+
import { generateShortHash, canonicalConfigString, transformConfigForReload, } from "../../../utils/index.js";
|
|
7
|
+
import { ConfigReloadNotSupportedError, ModelTypeMismatchError, ModelIsDelegatedError, ModelNotFoundError, ModelLoadFailedError, PluginLoadConfigValidationFailedError, PluginNotFoundError, } from "../../../../utils/errors-server.js";
|
|
8
8
|
import { getServerLogger } from "../../../../logging/index.js";
|
|
9
|
-
import { OCR_CRAFT_DETECTOR } from "../../../../models/registry/index.js";
|
|
10
9
|
import { getPlugin } from "../../../plugins/index.js";
|
|
11
10
|
const logger = getServerLogger();
|
|
12
|
-
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
// Handler
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
13
14
|
export async function handleLoadModel(request, progressCallback) {
|
|
14
|
-
// Handle reload config
|
|
15
15
|
if (isReloadConfigRequest(request)) {
|
|
16
16
|
return handleConfigReload(request);
|
|
17
17
|
}
|
|
18
|
-
|
|
19
|
-
const { modelSrc, modelName, seed, projectionModelSrc, vadModelSrc } = request;
|
|
18
|
+
const { modelSrc, modelName, seed } = request;
|
|
20
19
|
const canonicalModelType = normalizeModelType(request.modelType);
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
: undefined;
|
|
24
|
-
const dstVocabSrc = canonicalModelType === ModelType.nmtcppTranslation
|
|
25
|
-
? request.dstVocabSrc
|
|
26
|
-
: undefined;
|
|
27
|
-
const detectorModelSrc = canonicalModelType === ModelType.onnxOcr
|
|
28
|
-
? request.detectorModelSrc
|
|
29
|
-
: undefined;
|
|
20
|
+
const profilingMeta = request[PROFILING_KEY];
|
|
21
|
+
const profilingEnabled = profilingMeta?.enabled !== false && !!profilingMeta;
|
|
30
22
|
try {
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
projectionModelPath = await resolveModelPath(projectionModelSrc, progressCallback, seed);
|
|
23
|
+
const plugin = getPlugin(canonicalModelType);
|
|
24
|
+
if (!plugin) {
|
|
25
|
+
throw new PluginNotFoundError(canonicalModelType);
|
|
35
26
|
}
|
|
36
|
-
let
|
|
37
|
-
|
|
38
|
-
|
|
27
|
+
let resolvedModelConfig = (request.modelConfig ?? {});
|
|
28
|
+
const parseResult = plugin.loadConfigSchema.safeParse(resolvedModelConfig);
|
|
29
|
+
if (!parseResult.success) {
|
|
30
|
+
const details = parseResult.error.issues
|
|
31
|
+
.map((i) => `${String(i.path.join("."))}: ${i.message}`)
|
|
32
|
+
.join(", ");
|
|
33
|
+
throw new PluginLoadConfigValidationFailedError(canonicalModelType, details);
|
|
39
34
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
const { key } = hyperdriveUrlSchema.parse(modelSrc);
|
|
48
|
-
const derivedDetectorSrc = `pear://${key}/${OCR_DETECTOR_FILENAME}`;
|
|
49
|
-
detectorModelPath = await resolveModelPath(derivedDetectorSrc, progressCallback, seed);
|
|
50
|
-
}
|
|
51
|
-
else if (modelSrc.startsWith("registry://")) {
|
|
52
|
-
detectorModelPath = await resolveModelPath(OCR_CRAFT_DETECTOR, progressCallback, seed);
|
|
53
|
-
}
|
|
35
|
+
resolvedModelConfig = parseResult.data;
|
|
36
|
+
const totalLoadStart = profilingEnabled ? nowMs() : 0;
|
|
37
|
+
let resolveResult;
|
|
38
|
+
let resolvedModelPath;
|
|
39
|
+
if (profilingEnabled) {
|
|
40
|
+
resolveResult = await resolveModelPathWithStats(modelSrc, progressCallback, seed);
|
|
41
|
+
resolvedModelPath = resolveResult.path;
|
|
54
42
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
request.modelConfig) {
|
|
58
|
-
const nmtConfig = request.modelConfig;
|
|
59
|
-
if (nmtConfig.engine === "Bergamot") {
|
|
60
|
-
let resolvedSrcVocabSrc = srcVocabSrc;
|
|
61
|
-
let resolvedDstVocabSrc = dstVocabSrc;
|
|
62
|
-
if (!srcVocabSrc || !dstVocabSrc) {
|
|
63
|
-
const derivedVocabSrcs = modelSrc.startsWith("pear://")
|
|
64
|
-
? deriveBergamotVocabSources(modelSrc)
|
|
65
|
-
: modelSrc.startsWith("registry://")
|
|
66
|
-
? deriveBergamotRegistryVocabSources(modelSrc)
|
|
67
|
-
: null;
|
|
68
|
-
if (derivedVocabSrcs) {
|
|
69
|
-
resolvedSrcVocabSrc = srcVocabSrc ?? derivedVocabSrcs.srcVocabSrc;
|
|
70
|
-
resolvedDstVocabSrc = dstVocabSrc ?? derivedVocabSrcs.dstVocabSrc;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
if (resolvedSrcVocabSrc) {
|
|
74
|
-
nmtConfig.srcVocabPath = await resolveModelPath(resolvedSrcVocabSrc, progressCallback, seed);
|
|
75
|
-
}
|
|
76
|
-
if (resolvedDstVocabSrc) {
|
|
77
|
-
nmtConfig.dstVocabPath = await resolveModelPath(resolvedDstVocabSrc, progressCallback, seed);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
43
|
+
else {
|
|
44
|
+
resolvedModelPath = await resolveModelPath(modelSrc, progressCallback, seed);
|
|
80
45
|
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
46
|
+
let pluginArtifacts = {};
|
|
47
|
+
if (plugin.resolveConfig) {
|
|
48
|
+
const ctx = {
|
|
49
|
+
resolveModelPath: (src) => resolveModelPath(src, progressCallback, seed),
|
|
50
|
+
modelSrc,
|
|
51
|
+
modelType: canonicalModelType,
|
|
52
|
+
...(modelName !== undefined && { modelName }),
|
|
53
|
+
};
|
|
54
|
+
const result = await plugin.resolveConfig(resolvedModelConfig, ctx);
|
|
55
|
+
resolvedModelConfig = result.config;
|
|
56
|
+
if (result.artifacts) {
|
|
57
|
+
pluginArtifacts = result.artifacts;
|
|
58
|
+
}
|
|
87
59
|
}
|
|
88
|
-
|
|
89
|
-
const configStr = JSON.stringify(request.modelConfig, Object.keys(request.modelConfig).sort());
|
|
60
|
+
const configStr = canonicalConfigString(request.modelConfig);
|
|
90
61
|
const modelHashInput = `${request.modelType}:${modelSrc}:${configStr}`;
|
|
91
62
|
const modelId = generateShortHash(modelHashInput);
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
63
|
+
if ("modelPath" in pluginArtifacts) {
|
|
64
|
+
logger.warn("Plugin returned 'modelPath' artifact which was overridden by core");
|
|
65
|
+
}
|
|
66
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
67
|
+
const { modelPath: _, ...artifacts } = pluginArtifacts;
|
|
68
|
+
if (!resolvedModelPath) {
|
|
69
|
+
throw new ModelLoadFailedError("modelPath resolution failed");
|
|
70
|
+
}
|
|
71
|
+
const loadResult = await loadModel({
|
|
97
72
|
modelId,
|
|
98
|
-
modelPath,
|
|
99
|
-
options:
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
73
|
+
modelPath: resolvedModelPath,
|
|
74
|
+
options: {
|
|
75
|
+
...request,
|
|
76
|
+
modelType: canonicalModelType,
|
|
77
|
+
modelConfig: resolvedModelConfig,
|
|
78
|
+
},
|
|
79
|
+
artifacts: Object.keys(artifacts).length > 0 ? artifacts : undefined,
|
|
103
80
|
modelName,
|
|
104
|
-
});
|
|
105
|
-
|
|
81
|
+
}, profilingEnabled ? { collectTiming: true } : undefined);
|
|
82
|
+
const response = {
|
|
106
83
|
type: "loadModel",
|
|
107
84
|
success: true,
|
|
108
85
|
modelId,
|
|
109
86
|
};
|
|
87
|
+
if (profilingEnabled) {
|
|
88
|
+
const totalLoadTimeMs = nowMs() - totalLoadStart;
|
|
89
|
+
const profileId = profilingMeta?.id ?? generateProfileId();
|
|
90
|
+
const gauges = {
|
|
91
|
+
totalLoadTime: totalLoadTimeMs,
|
|
92
|
+
};
|
|
93
|
+
if (loadResult.timing?.modelInitializationTimeMs !== undefined) {
|
|
94
|
+
gauges["modelInitializationTime"] =
|
|
95
|
+
loadResult.timing.modelInitializationTimeMs;
|
|
96
|
+
}
|
|
97
|
+
if (resolveResult?.downloadStats) {
|
|
98
|
+
const ds = resolveResult.downloadStats;
|
|
99
|
+
if (ds.downloadTimeMs !== undefined) {
|
|
100
|
+
gauges["downloadTime"] = ds.downloadTimeMs;
|
|
101
|
+
}
|
|
102
|
+
if (ds.totalBytesDownloaded !== undefined) {
|
|
103
|
+
gauges["totalBytesDownloaded"] = ds.totalBytesDownloaded;
|
|
104
|
+
}
|
|
105
|
+
if (ds.downloadSpeedBps !== undefined) {
|
|
106
|
+
gauges["downloadSpeedBps"] = ds.downloadSpeedBps;
|
|
107
|
+
}
|
|
108
|
+
if (ds.checksumValidationTimeMs !== undefined) {
|
|
109
|
+
gauges["checksumValidationTime"] = ds.checksumValidationTimeMs;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
const tags = {};
|
|
113
|
+
if (canonicalModelType) {
|
|
114
|
+
tags["modelType"] = canonicalModelType;
|
|
115
|
+
}
|
|
116
|
+
if (resolveResult?.sourceType) {
|
|
117
|
+
tags["sourceType"] = resolveResult.sourceType;
|
|
118
|
+
}
|
|
119
|
+
if (resolveResult?.downloadStats?.cacheHit !== undefined) {
|
|
120
|
+
tags["cacheHit"] = resolveResult.downloadStats.cacheHit ? "true" : "false";
|
|
121
|
+
}
|
|
122
|
+
const operationEvent = {
|
|
123
|
+
op: "loadModel",
|
|
124
|
+
kind: "handler",
|
|
125
|
+
ms: totalLoadTimeMs,
|
|
126
|
+
profileId,
|
|
127
|
+
gauges: Object.keys(gauges).length > 0 ? gauges : undefined,
|
|
128
|
+
tags: Object.keys(tags).length > 0 ? tags : undefined,
|
|
129
|
+
};
|
|
130
|
+
response[OPERATION_EVENT_KEY] = operationEvent;
|
|
131
|
+
}
|
|
132
|
+
return response;
|
|
110
133
|
}
|
|
111
134
|
catch (error) {
|
|
112
135
|
logger.error("Error loading model:", error);
|
|
@@ -162,41 +185,3 @@ async function handleConfigReload(request) {
|
|
|
162
185
|
function isReloadConfigRequest(request) {
|
|
163
186
|
return "modelId" in request && !("modelSrc" in request);
|
|
164
187
|
}
|
|
165
|
-
const BERGAMOT_CJK_LANG_PAIRS = ["enja", "enko", "enzh"];
|
|
166
|
-
function deriveBergamotVocabSources(modelSrc) {
|
|
167
|
-
const match = modelSrc.match(/^pear:\/\/([a-f0-9]+)\/model\.([a-z]+)\.intgemm\.alphas\.bin$/);
|
|
168
|
-
if (!match || !match[1] || !match[2])
|
|
169
|
-
return null;
|
|
170
|
-
const key = match[1];
|
|
171
|
-
const langPair = match[2];
|
|
172
|
-
if (BERGAMOT_CJK_LANG_PAIRS.includes(langPair)) {
|
|
173
|
-
return {
|
|
174
|
-
srcVocabSrc: `pear://${key}/srcvocab.${langPair}.spm`,
|
|
175
|
-
dstVocabSrc: `pear://${key}/trgvocab.${langPair}.spm`,
|
|
176
|
-
};
|
|
177
|
-
}
|
|
178
|
-
const sharedVocab = `pear://${key}/vocab.${langPair}.spm`;
|
|
179
|
-
return {
|
|
180
|
-
srcVocabSrc: sharedVocab,
|
|
181
|
-
dstVocabSrc: sharedVocab,
|
|
182
|
-
};
|
|
183
|
-
}
|
|
184
|
-
function deriveBergamotRegistryVocabSources(modelSrc) {
|
|
185
|
-
// registry://s3/path/to/model.enfr.intgemm.alphas.bin
|
|
186
|
-
const match = modelSrc.match(/^(registry:\/\/.+\/)model\.([a-z]+)\.intgemm\.alphas\.bin$/);
|
|
187
|
-
if (!match || !match[1] || !match[2])
|
|
188
|
-
return null;
|
|
189
|
-
const basePath = match[1];
|
|
190
|
-
const langPair = match[2];
|
|
191
|
-
if (BERGAMOT_CJK_LANG_PAIRS.includes(langPair)) {
|
|
192
|
-
return {
|
|
193
|
-
srcVocabSrc: `${basePath}srcvocab.${langPair}.spm`,
|
|
194
|
-
dstVocabSrc: `${basePath}trgvocab.${langPair}.spm`,
|
|
195
|
-
};
|
|
196
|
-
}
|
|
197
|
-
const sharedVocab = `${basePath}vocab.${langPair}.spm`;
|
|
198
|
-
return {
|
|
199
|
-
srcVocabSrc: sharedVocab,
|
|
200
|
-
dstVocabSrc: sharedVocab,
|
|
201
|
-
};
|
|
202
|
-
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
import type { ModelProgressUpdate } from "../../../../schemas/index";
|
|
2
|
-
|
|
2
|
+
import type { DownloadMetricsHooks } from "./types";
|
|
3
|
+
export declare function downloadModelFromHttp(url: string, progressCallback?: (progress: ModelProgressUpdate) => void, hooks?: DownloadMetricsHooks): Promise<string>;
|
|
3
4
|
//# sourceMappingURL=http.d.ts.map
|
|
@@ -314,19 +314,20 @@ async function performHttpDownload(url, modelPath, downloadKey, progressCallback
|
|
|
314
314
|
throw error instanceof Error ? error : new Error(String(error));
|
|
315
315
|
}
|
|
316
316
|
}
|
|
317
|
-
export async function downloadModelFromHttp(url, progressCallback) {
|
|
317
|
+
export async function downloadModelFromHttp(url, progressCallback, hooks) {
|
|
318
318
|
const filename = extractFilenameFromUrl(url);
|
|
319
319
|
if (isArchiveUrl(url)) {
|
|
320
|
-
return downloadShardedModelFromArchive(url, progressCallback);
|
|
320
|
+
return downloadShardedModelFromArchive(url, progressCallback, hooks);
|
|
321
321
|
}
|
|
322
322
|
const shardInfo = detectShardedModel(filename);
|
|
323
323
|
if (shardInfo.isSharded && shardInfo.totalShards) {
|
|
324
|
-
return downloadShardedModelFromHttp(url, progressCallback);
|
|
324
|
+
return downloadShardedModelFromHttp(url, progressCallback, hooks);
|
|
325
325
|
}
|
|
326
326
|
const downloadKey = createHttpDownloadKey(url);
|
|
327
327
|
const existing = getActiveDownload(downloadKey);
|
|
328
328
|
if (existing) {
|
|
329
329
|
logger.info(`📥 Reusing existing download for: ${downloadKey}`);
|
|
330
|
+
hooks?.markCacheMiss();
|
|
330
331
|
return existing.promise;
|
|
331
332
|
}
|
|
332
333
|
const cacheDir = getModelsCacheDir();
|
|
@@ -339,6 +340,7 @@ export async function downloadModelFromHttp(url, progressCallback) {
|
|
|
339
340
|
// Check if already cached
|
|
340
341
|
const cachedPath = await validateCachedFile(modelPath, url, abortController.signal);
|
|
341
342
|
if (cachedPath) {
|
|
343
|
+
hooks?.markCacheHit();
|
|
342
344
|
if (progressCallback) {
|
|
343
345
|
try {
|
|
344
346
|
const stats = await fsPromises.stat(cachedPath);
|
|
@@ -360,6 +362,7 @@ export async function downloadModelFromHttp(url, progressCallback) {
|
|
|
360
362
|
return cachedPath;
|
|
361
363
|
}
|
|
362
364
|
// Download the file
|
|
365
|
+
hooks?.markCacheMiss();
|
|
363
366
|
await performHttpDownload(url, modelPath, downloadKey, progressCallback, abortController.signal);
|
|
364
367
|
// Send final 100% progress update
|
|
365
368
|
if (progressCallback) {
|
|
@@ -426,7 +429,7 @@ export async function downloadModelFromHttp(url, progressCallback) {
|
|
|
426
429
|
registerDownload(downloadKey, downloadEntry);
|
|
427
430
|
return downloadPromise;
|
|
428
431
|
}
|
|
429
|
-
async function downloadShardedModelFromHttp(shardUrl, progressCallback) {
|
|
432
|
+
async function downloadShardedModelFromHttp(shardUrl, progressCallback, hooks) {
|
|
430
433
|
const config = getSDKConfig();
|
|
431
434
|
const concurrency = config.httpDownloadConcurrency ?? DEFAULT_CONCURRENCY;
|
|
432
435
|
const { shardUrls: shardInfos, cacheKey } = parsePatternBasedShardUrl(shardUrl);
|
|
@@ -435,6 +438,7 @@ async function downloadShardedModelFromHttp(shardUrl, progressCallback) {
|
|
|
435
438
|
const existing = getActiveDownload(downloadKey);
|
|
436
439
|
if (existing) {
|
|
437
440
|
logger.info(`📥 Reusing existing sharded download for: ${downloadKey}`);
|
|
441
|
+
hooks?.markCacheMiss();
|
|
438
442
|
return existing.promise;
|
|
439
443
|
}
|
|
440
444
|
const abortController = new AbortController();
|
|
@@ -483,6 +487,12 @@ async function downloadShardedModelFromHttp(shardUrl, progressCallback) {
|
|
|
483
487
|
}
|
|
484
488
|
}
|
|
485
489
|
logger.info(`📥 ${shardsToDownload.length} of ${shardInfos.length} shards need downloading`);
|
|
490
|
+
if (shardsToDownload.length === 0) {
|
|
491
|
+
hooks?.markCacheHit();
|
|
492
|
+
}
|
|
493
|
+
else {
|
|
494
|
+
hooks?.markCacheMiss();
|
|
495
|
+
}
|
|
486
496
|
await downloadShardsWithConcurrency(shardsToDownload, shardStates, concurrency, abortController.signal, downloadKey, overallTotal, progressCallback);
|
|
487
497
|
logger.info(`✅ All ${shardInfos.length} shards downloaded successfully`);
|
|
488
498
|
await extractTensorsFromShards(shardDir, shardInfos[0].filename);
|
|
@@ -523,7 +533,7 @@ async function downloadShardedModelFromHttp(shardUrl, progressCallback) {
|
|
|
523
533
|
});
|
|
524
534
|
return downloadPromise;
|
|
525
535
|
}
|
|
526
|
-
async function downloadShardedModelFromArchive(archiveUrl, progressCallback) {
|
|
536
|
+
async function downloadShardedModelFromArchive(archiveUrl, progressCallback, hooks) {
|
|
527
537
|
const filename = extractFilenameFromUrl(archiveUrl);
|
|
528
538
|
const sourceHash = generateShortHash(archiveUrl);
|
|
529
539
|
const downloadKey = `http-archive:${sourceHash}`;
|
|
@@ -531,6 +541,7 @@ async function downloadShardedModelFromArchive(archiveUrl, progressCallback) {
|
|
|
531
541
|
const existing = getActiveDownload(downloadKey);
|
|
532
542
|
if (existing) {
|
|
533
543
|
logger.info(`📥 Reusing existing archive download for: ${downloadKey}`);
|
|
544
|
+
hooks?.markCacheMiss();
|
|
534
545
|
return existing.promise;
|
|
535
546
|
}
|
|
536
547
|
const abortController = new AbortController();
|
|
@@ -542,12 +553,14 @@ async function downloadShardedModelFromArchive(archiveUrl, progressCallback) {
|
|
|
542
553
|
const files = await fsPromises.readdir(extractDir);
|
|
543
554
|
const shardedFile = files.find((f) => detectShardedModel(String(f)).isSharded);
|
|
544
555
|
if (!shardedFile) {
|
|
556
|
+
hooks?.markCacheMiss();
|
|
545
557
|
return downloadAndExtractArchive();
|
|
546
558
|
}
|
|
547
559
|
const shardFilename = String(shardedFile);
|
|
548
560
|
const allShardsExist = await checkAllShardsExist(extractDir, shardFilename);
|
|
549
561
|
if (!allShardsExist) {
|
|
550
562
|
logger.warn(`⚠️ Incomplete shards found, re-downloading archive`);
|
|
563
|
+
hooks?.markCacheMiss();
|
|
551
564
|
return downloadAndExtractArchive();
|
|
552
565
|
}
|
|
553
566
|
const shardFilenames = generateShardFilenames(shardFilename);
|
|
@@ -555,6 +568,7 @@ async function downloadShardedModelFromArchive(archiveUrl, progressCallback) {
|
|
|
555
568
|
const isComplete = await validateShardedModelCache(extractDir, shardFilename);
|
|
556
569
|
if (isComplete) {
|
|
557
570
|
logger.info(`✅ Archive already extracted: ${extractDir}`);
|
|
571
|
+
hooks?.markCacheHit();
|
|
558
572
|
if (progressCallback) {
|
|
559
573
|
progressCallback({
|
|
560
574
|
type: "modelProgress",
|
|
@@ -570,6 +584,7 @@ async function downloadShardedModelFromArchive(archiveUrl, progressCallback) {
|
|
|
570
584
|
try {
|
|
571
585
|
await extractTensorsFromShards(extractDir, shardFilename);
|
|
572
586
|
logger.info(`✅ Tensors extracted successfully`);
|
|
587
|
+
hooks?.markCacheHit();
|
|
573
588
|
if (progressCallback) {
|
|
574
589
|
progressCallback({
|
|
575
590
|
type: "modelProgress",
|
|
@@ -585,6 +600,7 @@ async function downloadShardedModelFromArchive(archiveUrl, progressCallback) {
|
|
|
585
600
|
logger.warn(`Failed to extract tensors, will re-download archive`, {
|
|
586
601
|
error,
|
|
587
602
|
});
|
|
603
|
+
hooks?.markCacheMiss();
|
|
588
604
|
return downloadAndExtractArchive();
|
|
589
605
|
}
|
|
590
606
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ModelProgressUpdate } from "../../../../schemas/index";
|
|
2
|
+
import type { DownloadMetricsHooks } from "./types";
|
|
2
3
|
export declare function deleteCorestoreDirectory(corestoreDir: string): Promise<void>;
|
|
3
|
-
export declare function downloadModelFromHyperdrive(hyperdriveKey: string, modelFileName: string, seed?: boolean, progressCallback?: (progress: ModelProgressUpdate) => void, expectedChecksum?: string): Promise<string>;
|
|
4
|
+
export declare function downloadModelFromHyperdrive(hyperdriveKey: string, modelFileName: string, seed?: boolean, progressCallback?: (progress: ModelProgressUpdate) => void, hooks?: DownloadMetricsHooks, expectedChecksum?: string): Promise<string>;
|
|
4
5
|
//# sourceMappingURL=hyperdrive.d.ts.map
|
|
@@ -6,7 +6,7 @@ import Hyperdrive from "hyperdrive";
|
|
|
6
6
|
import {} from "bare-stream";
|
|
7
7
|
import { AbortController } from "bare-abort-controller";
|
|
8
8
|
import { getEnv } from "../../../env.js";
|
|
9
|
-
import { getModelsCacheDir, generateShortHash, detectShardedModel, getShardedModelCacheDir, getShardPath, checkShardCompleteness,
|
|
9
|
+
import { getModelsCacheDir, generateShortHash, detectShardedModel, getShardedModelCacheDir, getShardPath, checkShardCompleteness, measureChecksum, extractTensorsFromShards, calculatePercentage, } from "../../../utils/index.js";
|
|
10
10
|
import { getModelBySrc } from "../../../../models/registry/index.js";
|
|
11
11
|
import { getActiveDownload, registerDownload, unregisterDownload, createHyperdriveDownloadKey, shouldClearCache, clearClearCacheFlag, } from "./download-manager.js";
|
|
12
12
|
import { getSDKConfig } from "../../../bare/registry/config-registry.js";
|
|
@@ -142,7 +142,7 @@ async function validateFileExistence(drive, file) {
|
|
|
142
142
|
totalBytes,
|
|
143
143
|
};
|
|
144
144
|
}
|
|
145
|
-
async function validateCachedFile(modelPath, modelFileName, expectedSize, expectedChecksum) {
|
|
145
|
+
async function validateCachedFile(modelPath, modelFileName, expectedSize, expectedChecksum, hooks) {
|
|
146
146
|
try {
|
|
147
147
|
await fsPromises.access(modelPath);
|
|
148
148
|
const localStats = await fsPromises.stat(modelPath);
|
|
@@ -153,7 +153,7 @@ async function validateCachedFile(modelPath, modelFileName, expectedSize, expect
|
|
|
153
153
|
logger.info(`✅ Model cached with correct size: ${modelPath}`);
|
|
154
154
|
// Always validate checksum if provided, even when size matches
|
|
155
155
|
if (expectedChecksum && expectedChecksum.length === 64) {
|
|
156
|
-
const checksum = await
|
|
156
|
+
const checksum = await measureChecksum(modelPath, hooks);
|
|
157
157
|
if (checksum !== expectedChecksum) {
|
|
158
158
|
throw new ChecksumValidationFailedError(`${modelFileName}. Expected: ${expectedChecksum}. Actual: ${checksum}. File may be corrupted`);
|
|
159
159
|
}
|
|
@@ -170,7 +170,7 @@ async function validateCachedFile(modelPath, modelFileName, expectedSize, expect
|
|
|
170
170
|
return null;
|
|
171
171
|
}
|
|
172
172
|
}
|
|
173
|
-
async function downloadSingleFileToFilesystem(modelPath, modelFileName, hyperdriveKey, corestoreDir, downloadKey, expectedChecksum, progressCallback, seed, signal) {
|
|
173
|
+
async function downloadSingleFileToFilesystem(modelPath, modelFileName, hyperdriveKey, corestoreDir, downloadKey, expectedChecksum, progressCallback, seed, signal, hooks) {
|
|
174
174
|
// Check if already aborted
|
|
175
175
|
if (signal?.aborted) {
|
|
176
176
|
throw new DownloadCancelledError();
|
|
@@ -194,7 +194,7 @@ async function downloadSingleFileToFilesystem(modelPath, modelFileName, hyperdri
|
|
|
194
194
|
}
|
|
195
195
|
: undefined;
|
|
196
196
|
await downloadAndValidateFile(setup.drive, modelFileName, modelPath, 0, // Size will be determined from drive
|
|
197
|
-
expectedChecksum, progressContext, signal);
|
|
197
|
+
expectedChecksum, progressContext, signal, hooks);
|
|
198
198
|
logger.info(`✅ Model downloaded successfully to ${modelPath}`);
|
|
199
199
|
// Send final 100% progress update
|
|
200
200
|
if (progressCallback) {
|
|
@@ -244,7 +244,7 @@ async function downloadSingleFileToFilesystem(modelPath, modelFileName, hyperdri
|
|
|
244
244
|
clearClearCacheFlag(downloadKey);
|
|
245
245
|
}
|
|
246
246
|
}
|
|
247
|
-
async function downloadAndValidateFile(drive, sourceFileName, targetFilePath, expectedSize, expectedChecksum, progressContext, signal) {
|
|
247
|
+
async function downloadAndValidateFile(drive, sourceFileName, targetFilePath, expectedSize, expectedChecksum, progressContext, signal, hooks) {
|
|
248
248
|
const { entry, blobs, targetPath, blocksDownloaded, totalBlocks, totalBytes, } = await validateFileExistence(drive, sourceFileName);
|
|
249
249
|
const blob = entry?.value?.blob;
|
|
250
250
|
if (!blob) {
|
|
@@ -316,7 +316,7 @@ async function downloadAndValidateFile(drive, sourceFileName, targetFilePath, ex
|
|
|
316
316
|
}
|
|
317
317
|
// Validate checksum
|
|
318
318
|
if (expectedChecksum && expectedChecksum.length === 64) {
|
|
319
|
-
const checksum = await
|
|
319
|
+
const checksum = await measureChecksum(targetFilePath, hooks);
|
|
320
320
|
if (checksum !== expectedChecksum) {
|
|
321
321
|
await fsPromises.unlink(targetFilePath);
|
|
322
322
|
throw new ChecksumValidationFailedError(`${path.basename(targetFilePath)}. Expected: ${expectedChecksum}. Actual: ${checksum}`);
|
|
@@ -361,7 +361,7 @@ function createManagedDownload(downloadKey, hyperdriveKey, modelFileName, downlo
|
|
|
361
361
|
registerDownload(downloadKey, downloadEntry);
|
|
362
362
|
return downloadPromise;
|
|
363
363
|
}
|
|
364
|
-
async function downloadShardedFilesToFilesystem(hyperdriveKey, firstShardFileName, shardMetadata, progressCallback, seed, signal) {
|
|
364
|
+
async function downloadShardedFilesToFilesystem(hyperdriveKey, firstShardFileName, shardMetadata, progressCallback, seed, signal, hooks) {
|
|
365
365
|
if (signal?.aborted) {
|
|
366
366
|
throw new DownloadCancelledError();
|
|
367
367
|
}
|
|
@@ -374,9 +374,10 @@ async function downloadShardedFilesToFilesystem(hyperdriveKey, firstShardFileNam
|
|
|
374
374
|
const numberedShardCount = shardInfo.totalShards;
|
|
375
375
|
logger.info(`Downloading sharded model with ${numberedShardCount} numbered shards + ${allFiles.length - numberedShardCount} companion files to ${shardDir}`);
|
|
376
376
|
// Check which files need to be downloaded
|
|
377
|
-
const invalidIndices = await checkShardCompleteness(hyperdriveKey, allFiles, shardMetadata);
|
|
377
|
+
const invalidIndices = await checkShardCompleteness(hyperdriveKey, allFiles, shardMetadata, hooks ? (ms) => hooks.addChecksumValidationTimeMs(ms) : undefined);
|
|
378
378
|
if (invalidIndices.length === 0) {
|
|
379
379
|
logger.info(`✅ All ${allFiles.length} files already downloaded and validated`);
|
|
380
|
+
hooks?.markCacheHit();
|
|
380
381
|
if (progressCallback) {
|
|
381
382
|
const overallTotal = shardMetadata.reduce((sum, shard) => sum + shard.expectedSize, 0);
|
|
382
383
|
const lastFile = allFiles[allFiles.length - 1];
|
|
@@ -400,6 +401,7 @@ async function downloadShardedFilesToFilesystem(hyperdriveKey, firstShardFileNam
|
|
|
400
401
|
return getShardPath(hyperdriveKey, allFiles[0]);
|
|
401
402
|
}
|
|
402
403
|
logger.info(`📥 Need to download ${invalidIndices.length} of ${allFiles.length} files`);
|
|
404
|
+
hooks?.markCacheMiss();
|
|
403
405
|
// Setup hyperdrive once for all shards
|
|
404
406
|
const corestoreDir = getCorestoreDir(hyperdriveKey);
|
|
405
407
|
const setup = await setupHyperdrive(hyperdriveKey, corestoreDir);
|
|
@@ -462,7 +464,7 @@ async function downloadShardedFilesToFilesystem(hyperdriveKey, firstShardFileNam
|
|
|
462
464
|
},
|
|
463
465
|
}
|
|
464
466
|
: undefined;
|
|
465
|
-
await downloadAndValidateFile(setup.drive, file, filePath, fileMeta.expectedSize, fileMeta.sha256Checksum, progressContext, signal);
|
|
467
|
+
await downloadAndValidateFile(setup.drive, file, filePath, fileMeta.expectedSize, fileMeta.sha256Checksum, progressContext, signal, hooks);
|
|
466
468
|
if (signal?.aborted) {
|
|
467
469
|
throw new DownloadCancelledError();
|
|
468
470
|
}
|
|
@@ -516,17 +518,18 @@ async function downloadShardedFilesToFilesystem(hyperdriveKey, firstShardFileNam
|
|
|
516
518
|
}
|
|
517
519
|
return getShardPath(hyperdriveKey, allFiles[0]);
|
|
518
520
|
}
|
|
519
|
-
export async function downloadModelFromHyperdrive(hyperdriveKey, modelFileName, seed, progressCallback, expectedChecksum) {
|
|
521
|
+
export async function downloadModelFromHyperdrive(hyperdriveKey, modelFileName, seed, progressCallback, hooks, expectedChecksum) {
|
|
520
522
|
const downloadKey = createHyperdriveDownloadKey(hyperdriveKey, modelFileName);
|
|
521
523
|
// Check if already downloading
|
|
522
524
|
const existing = getActiveDownload(downloadKey);
|
|
523
525
|
if (existing) {
|
|
526
|
+
hooks?.markCacheMiss();
|
|
524
527
|
return existing.promise;
|
|
525
528
|
}
|
|
526
529
|
const shardInfo = detectShardedModel(modelFileName);
|
|
527
530
|
const model = getModelBySrc(modelFileName, hyperdriveKey);
|
|
528
531
|
if (shardInfo.isSharded && model?.shardMetadata) {
|
|
529
|
-
return createManagedDownload(downloadKey, hyperdriveKey, modelFileName, (signal) => downloadShardedFilesToFilesystem(hyperdriveKey, modelFileName, model.shardMetadata, progressCallback, seed, signal), progressCallback);
|
|
532
|
+
return createManagedDownload(downloadKey, hyperdriveKey, modelFileName, (signal) => downloadShardedFilesToFilesystem(hyperdriveKey, modelFileName, model.shardMetadata, progressCallback, seed, signal, hooks), progressCallback);
|
|
530
533
|
}
|
|
531
534
|
// Non-sharded model download
|
|
532
535
|
const corestoreDir = getCorestoreDir(hyperdriveKey);
|
|
@@ -535,8 +538,9 @@ export async function downloadModelFromHyperdrive(hyperdriveKey, modelFileName,
|
|
|
535
538
|
const modelPath = path.join(cacheDir, `${sourceHash}_${modelFileName}`);
|
|
536
539
|
// First, check if we already have a valid cached file (only if we have model metadata)
|
|
537
540
|
if (model) {
|
|
538
|
-
const cachedPath = await validateCachedFile(modelPath, modelFileName, model.expectedSize, expectedChecksum || model.sha256Checksum);
|
|
541
|
+
const cachedPath = await validateCachedFile(modelPath, modelFileName, model.expectedSize, expectedChecksum || model.sha256Checksum, hooks);
|
|
539
542
|
if (cachedPath) {
|
|
543
|
+
hooks?.markCacheHit();
|
|
540
544
|
if (progressCallback) {
|
|
541
545
|
progressCallback({
|
|
542
546
|
type: "modelProgress",
|
|
@@ -553,9 +557,10 @@ export async function downloadModelFromHyperdrive(hyperdriveKey, modelFileName,
|
|
|
553
557
|
return cachedPath;
|
|
554
558
|
}
|
|
555
559
|
}
|
|
560
|
+
hooks?.markCacheMiss();
|
|
556
561
|
return createManagedDownload(downloadKey, hyperdriveKey, modelFileName, async (signal) => {
|
|
557
562
|
const checksumToValidate = expectedChecksum || model?.sha256Checksum || "";
|
|
558
|
-
await downloadSingleFileToFilesystem(modelPath, modelFileName, hyperdriveKey, corestoreDir, downloadKey, checksumToValidate, progressCallback, seed, signal);
|
|
563
|
+
await downloadSingleFileToFilesystem(modelPath, modelFileName, hyperdriveKey, corestoreDir, downloadKey, checksumToValidate, progressCallback, seed, signal, hooks);
|
|
559
564
|
return modelPath;
|
|
560
565
|
}, progressCallback);
|
|
561
566
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ModelProgressUpdate } from "../../../../schemas/index";
|
|
2
|
+
import type { DownloadMetricsHooks } from "./types";
|
|
2
3
|
/**
|
|
3
4
|
* Download a model from the QVAC Registry.
|
|
4
5
|
*
|
|
@@ -6,5 +7,5 @@ import type { ModelProgressUpdate } from "../../../../schemas/index";
|
|
|
6
7
|
* skips the registry metadata sync entirely. Falls back to metadata-based
|
|
7
8
|
* download for unknown models.
|
|
8
9
|
*/
|
|
9
|
-
export declare function downloadModelFromRegistry(registryPath: string, registrySource: string, progressCallback?: (progress: ModelProgressUpdate) => void, expectedChecksum?: string): Promise<string>;
|
|
10
|
+
export declare function downloadModelFromRegistry(registryPath: string, registrySource: string, progressCallback?: (progress: ModelProgressUpdate) => void, expectedChecksum?: string, hooks?: DownloadMetricsHooks): Promise<string>;
|
|
10
11
|
//# sourceMappingURL=registry.d.ts.map
|