@qvac/sdk 0.4.1 → 0.6.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/README.md +365 -200
- package/bare-imports.json +35 -0
- package/dist/client/api/cancel.d.ts +12 -3
- package/dist/client/api/cancel.js +12 -3
- package/dist/client/api/completion-stream.d.ts +15 -5
- package/dist/client/api/completion-stream.js +50 -14
- package/dist/client/api/embed.d.ts +17 -3
- package/dist/client/api/embed.js +0 -8
- package/dist/client/api/get-model-info.d.ts +2 -2
- package/dist/client/api/get-model-info.js +2 -2
- package/dist/client/api/index.d.ts +2 -2
- package/dist/client/api/index.js +2 -2
- package/dist/client/api/load-model.d.ts +37 -11
- package/dist/client/api/load-model.js +34 -117
- package/dist/client/api/logging-stream.d.ts +6 -3
- package/dist/client/api/logging-stream.js +6 -3
- package/dist/client/api/ocr.d.ts +31 -0
- package/dist/client/api/ocr.js +88 -0
- package/dist/client/api/rag.d.ts +215 -20
- package/dist/client/api/rag.js +382 -23
- package/dist/client/api/translate.js +10 -11
- package/dist/client/api/unload-model.js +6 -3
- package/dist/client/config-loader/config-utils.d.ts +5 -0
- package/dist/client/config-loader/config-utils.js +20 -0
- package/dist/client/config-loader/resolve-config.bare.d.ts +9 -0
- package/dist/client/config-loader/resolve-config.bare.js +87 -0
- package/dist/client/config-loader/resolve-config.expo.d.ts +11 -0
- package/dist/client/config-loader/resolve-config.expo.js +62 -0
- package/dist/client/config-loader/resolve-config.node.d.ts +9 -0
- package/dist/client/config-loader/resolve-config.node.js +118 -0
- package/dist/client/init-hooks.d.ts +18 -3
- package/dist/client/init-hooks.js +57 -29
- package/dist/client/logging-stream-registry.d.ts +1 -1
- package/dist/client/logging-stream-registry.js +14 -13
- package/dist/client/rpc/bare-client.d.ts +3 -184
- package/dist/client/rpc/bare-client.js +67 -8
- package/dist/client/rpc/expo-rpc-client.d.ts +2 -2
- package/dist/client/rpc/expo-rpc-client.js +70 -12
- package/dist/client/rpc/node-rpc-client.d.ts +1 -1
- package/dist/client/rpc/node-rpc-client.js +14 -7
- package/dist/client/rpc/rpc-client.d.ts +1 -1
- package/dist/client/rpc/rpc-client.js +13 -58
- package/dist/examples/config/blind-relay/blind-relay.config.d.ts +5 -0
- package/dist/examples/config/blind-relay/blind-relay.config.js +7 -0
- package/dist/examples/config/default/default.config.d.ts +8 -0
- package/dist/examples/config/default/default.config.js +6 -0
- package/dist/examples/config-reload.d.ts +2 -0
- package/dist/examples/config-reload.js +49 -0
- package/dist/examples/default-config-usage.d.ts +17 -0
- package/dist/examples/default-config-usage.js +47 -0
- package/dist/examples/delegated-inference/consumer.js +1 -0
- package/dist/examples/download-with-blind-relays.js +22 -21
- package/dist/examples/embed-hyperdrive.js +39 -3
- package/dist/examples/kv-cache-cleanup.js +1 -1
- package/dist/examples/kv-cache-custom-key.js +16 -1
- package/dist/examples/kv-cache-example.js +1 -1
- package/dist/examples/llamacpp-hyperdrive.js +1 -1
- package/dist/examples/llamacpp-sharded.js +13 -4
- package/dist/examples/logging-file-transport.d.ts +2 -0
- package/dist/examples/{llamacpp-file-logging.js → logging-file-transport.js} +3 -7
- package/dist/examples/logging-streaming.d.ts +2 -0
- package/dist/examples/logging-streaming.js +75 -0
- package/dist/examples/mcp-websearch.d.ts +13 -0
- package/dist/examples/mcp-websearch.js +176 -0
- package/dist/examples/ocr-fasttext.d.ts +2 -0
- package/dist/examples/ocr-fasttext.js +52 -0
- package/dist/examples/quickstart.d.ts +2 -0
- package/dist/examples/quickstart.js +28 -0
- package/dist/examples/rag/rag-hyperdb/cancellation.d.ts +2 -0
- package/dist/examples/rag/rag-hyperdb/cancellation.js +75 -0
- package/dist/examples/rag/rag-hyperdb/ingest.d.ts +2 -0
- package/dist/examples/rag/{rag-hyperdb.js → rag-hyperdb/ingest.js} +10 -4
- package/dist/examples/rag/rag-hyperdb/pipeline.d.ts +2 -0
- package/dist/examples/rag/rag-hyperdb/pipeline.js +74 -0
- package/dist/examples/rag/rag-hyperdb/workspaces.d.ts +2 -0
- package/dist/examples/rag/rag-hyperdb/workspaces.js +178 -0
- package/dist/examples/translation/translation-bergamot-batch.d.ts +2 -0
- package/dist/examples/translation/translation-bergamot-batch.js +49 -0
- package/dist/examples/translation/translation-bergamot.d.ts +2 -0
- package/dist/examples/translation/translation-bergamot.js +39 -0
- package/dist/examples/translation/translation-indic.js +1 -0
- package/dist/examples/translation/translation-opus.js +1 -0
- package/dist/examples/translation/translation-stream.js +1 -0
- package/dist/expo/plugins/withMobileBundle.js +29 -10
- package/dist/index.d.ts +5 -4
- package/dist/index.js +4 -2
- package/dist/logging/addon.d.ts +6 -0
- package/dist/logging/addon.js +75 -0
- package/dist/logging/base-logger.js +26 -16
- package/dist/logging/client-logger.d.ts +3 -0
- package/dist/logging/client-logger.js +24 -0
- package/dist/logging/index.d.ts +7 -1
- package/dist/logging/index.js +7 -1
- package/dist/logging/logger.d.ts +0 -2
- package/dist/logging/logger.js +11 -6
- package/dist/logging/namespaces.d.ts +12 -0
- package/dist/logging/namespaces.js +12 -0
- package/dist/logging/registry.d.ts +31 -0
- package/dist/logging/registry.js +48 -0
- package/dist/logging/server-logger.d.ts +3 -0
- package/dist/logging/server-logger.js +16 -0
- package/dist/logging/stream-logger.d.ts +1 -1
- package/dist/logging/stream-logger.js +6 -3
- package/dist/logging/transport.js +2 -2
- package/dist/logging/types.d.ts +2 -0
- package/dist/logging/utils.d.ts +2 -0
- package/dist/logging/utils.js +62 -0
- package/dist/models/hyperdrive/models.d.ts +1886 -230
- package/dist/models/hyperdrive/models.js +2191 -443
- package/dist/schemas/archive.d.ts +9 -0
- package/dist/schemas/archive.js +17 -0
- package/dist/schemas/cancel.d.ts +6 -0
- package/dist/schemas/cancel.js +5 -0
- package/dist/schemas/common.d.ts +660 -92
- package/dist/schemas/common.js +6 -4
- package/dist/schemas/delegate.d.ts +1 -0
- package/dist/schemas/delegate.js +1 -0
- package/dist/schemas/download-asset.d.ts +21 -9
- package/dist/schemas/embed.d.ts +3 -3
- package/dist/schemas/embed.js +9 -2
- package/dist/schemas/get-model-info.d.ts +12 -10
- package/dist/schemas/get-model-info.js +9 -1
- package/dist/schemas/index.d.ts +9 -1
- package/dist/schemas/index.js +12 -1
- package/dist/schemas/json-schema.d.ts +16 -0
- package/dist/schemas/json-schema.js +2 -0
- package/dist/schemas/llamacpp-config.d.ts +117 -12
- package/dist/schemas/llamacpp-config.js +46 -12
- package/dist/schemas/load-model.d.ts +3669 -481
- package/dist/schemas/load-model.js +95 -34
- package/dist/schemas/logging-stream.d.ts +11 -4
- package/dist/schemas/logging-stream.js +4 -3
- package/dist/schemas/mcp-adapter.d.ts +47 -0
- package/dist/schemas/mcp-adapter.js +1 -0
- package/dist/schemas/model-src-utils.d.ts +38 -14
- package/dist/schemas/model-src-utils.js +4 -3
- package/dist/schemas/model-types.d.ts +154 -0
- package/dist/schemas/model-types.js +140 -0
- package/dist/schemas/ocr.d.ts +88 -0
- package/dist/schemas/ocr.js +52 -0
- package/dist/schemas/rag.d.ts +183 -52
- package/dist/schemas/rag.js +148 -23
- package/dist/schemas/reload-config.d.ts +356 -0
- package/dist/schemas/reload-config.js +44 -0
- package/dist/schemas/runtime-context.d.ts +19 -0
- package/dist/schemas/runtime-context.js +7 -0
- package/dist/schemas/sdk-config.d.ts +717 -0
- package/dist/schemas/sdk-config.js +131 -0
- package/dist/schemas/sdk-errors-client.d.ts +5 -0
- package/dist/schemas/sdk-errors-client.js +25 -0
- package/dist/schemas/sdk-errors-server.d.ts +17 -0
- package/dist/schemas/sdk-errors-server.js +85 -0
- package/dist/schemas/shard.d.ts +21 -0
- package/dist/schemas/shard.js +17 -0
- package/dist/schemas/tools.d.ts +3 -0
- package/dist/schemas/translate.d.ts +68 -23
- package/dist/schemas/translate.js +37 -11
- package/dist/schemas/translation-config.d.ts +337 -13
- package/dist/schemas/translation-config.js +65 -9
- package/dist/schemas/whispercpp-config.d.ts +9 -1
- package/dist/schemas/whispercpp-config.js +2 -1
- package/dist/scripts/run-unit-tests.d.ts +2 -0
- package/dist/scripts/run-unit-tests.js +17 -0
- package/dist/server/bare/addons/llamacpp-completion/cache-logger.d.ts +6 -0
- package/dist/server/bare/addons/llamacpp-completion/cache-logger.js +34 -0
- package/dist/server/bare/addons/{llamacpp → llamacpp-completion}/create-model.d.ts +1 -5
- package/dist/server/bare/addons/{llamacpp → llamacpp-completion}/create-model.js +6 -20
- package/dist/server/bare/addons/{llamacpp → llamacpp-completion}/handlers/completion-stream.js +26 -7
- package/dist/server/bare/addons/llamacpp-completion/index.d.ts +4 -0
- package/dist/server/bare/addons/llamacpp-completion/index.js +3 -0
- package/dist/server/bare/addons/{llamacpp → llamacpp-completion}/kv-cache-utils.d.ts +4 -1
- package/dist/server/bare/addons/{llamacpp → llamacpp-completion}/kv-cache-utils.js +49 -14
- package/dist/server/bare/addons/llamacpp-embedding/create-model.d.ts +8 -0
- package/dist/server/bare/addons/llamacpp-embedding/create-model.js +38 -0
- package/dist/server/bare/addons/llamacpp-embedding/handlers/embed.d.ts +12 -0
- package/dist/server/bare/addons/{llamacpp → llamacpp-embedding}/handlers/embed.js +18 -4
- package/dist/server/bare/addons/llamacpp-embedding/index.d.ts +3 -0
- package/dist/server/bare/addons/llamacpp-embedding/index.js +2 -0
- package/dist/server/bare/addons/load-model.js +38 -28
- package/dist/server/bare/addons/{translation → nmtcpp-translation}/create-model.js +23 -8
- package/dist/server/bare/addons/{translation → nmtcpp-translation}/handlers/translate.js +35 -11
- package/dist/server/bare/addons/onnx-ocr/create-model.d.ts +10 -0
- package/dist/server/bare/addons/onnx-ocr/create-model.js +39 -0
- package/dist/server/bare/addons/onnx-ocr/handlers/ocr-stream.d.ts +10 -0
- package/dist/server/bare/addons/onnx-ocr/handlers/ocr-stream.js +109 -0
- package/dist/server/bare/addons/onnx-ocr/index.d.ts +3 -0
- package/dist/server/bare/addons/onnx-ocr/index.js +2 -0
- package/dist/server/bare/addons/unload-model.js +6 -3
- package/dist/server/bare/addons/{whispercpp → whispercpp-transcription}/create-model.js +2 -1
- package/dist/server/bare/addons/whispercpp-transcription/handlers/transcribe-stream.js +82 -0
- package/dist/server/bare/delegate-rpc-client.js +31 -11
- package/dist/server/bare/hyperswarm.js +7 -5
- package/dist/server/bare/rag-hyperdb/handlers/chunk.d.ts +3 -0
- package/dist/server/bare/rag-hyperdb/handlers/chunk.js +7 -0
- package/dist/server/bare/rag-hyperdb/handlers/close-workspace.d.ts +3 -0
- package/dist/server/bare/rag-hyperdb/handlers/close-workspace.js +9 -0
- package/dist/server/bare/rag-hyperdb/handlers/delete-embeddings.d.ts +1 -1
- package/dist/server/bare/rag-hyperdb/handlers/delete-embeddings.js +9 -10
- package/dist/server/bare/rag-hyperdb/handlers/delete-workspace.d.ts +3 -0
- package/dist/server/bare/rag-hyperdb/handlers/delete-workspace.js +14 -0
- package/dist/server/bare/rag-hyperdb/handlers/ingest.d.ts +9 -0
- package/dist/server/bare/rag-hyperdb/handlers/ingest.js +18 -0
- package/dist/server/bare/rag-hyperdb/handlers/list-workspaces.d.ts +3 -0
- package/dist/server/bare/rag-hyperdb/handlers/list-workspaces.js +4 -0
- package/dist/server/bare/rag-hyperdb/handlers/reindex.d.ts +9 -0
- package/dist/server/bare/rag-hyperdb/handlers/reindex.js +16 -0
- package/dist/server/bare/rag-hyperdb/handlers/save-embeddings.d.ts +7 -4
- package/dist/server/bare/rag-hyperdb/handlers/save-embeddings.js +13 -14
- package/dist/server/bare/rag-hyperdb/handlers/search.js +10 -10
- package/dist/server/bare/rag-hyperdb/index.d.ts +8 -1
- package/dist/server/bare/rag-hyperdb/index.js +8 -1
- package/dist/server/bare/rag-hyperdb/rag-operation-manager.d.ts +7 -0
- package/dist/server/bare/rag-hyperdb/rag-operation-manager.js +39 -0
- package/dist/server/bare/rag-hyperdb/rag-workspace-manager.d.ts +15 -0
- package/dist/server/bare/rag-hyperdb/rag-workspace-manager.js +135 -0
- package/dist/server/bare/registry/config-registry.d.ts +13 -4
- package/dist/server/bare/registry/config-registry.js +53 -10
- package/dist/server/bare/registry/logging-stream-registry.d.ts +24 -7
- package/dist/server/bare/registry/logging-stream-registry.js +99 -20
- package/dist/server/bare/registry/model-config-registry.d.ts +4 -0
- package/dist/server/bare/registry/model-config-registry.js +15 -0
- package/dist/server/bare/registry/model-config-utils.d.ts +15 -0
- package/dist/server/bare/registry/model-config-utils.js +121 -0
- package/dist/server/bare/registry/model-registry.d.ts +6 -26
- package/dist/server/bare/registry/model-registry.js +9 -6
- package/dist/server/bare/registry/runtime-context-registry.d.ts +7 -0
- package/dist/server/bare/registry/runtime-context-registry.js +26 -0
- package/dist/server/bare/utils/loader-adapter.d.ts +7 -0
- package/dist/server/bare/utils/loader-adapter.js +9 -0
- package/dist/server/error-handlers.js +4 -2
- package/dist/server/rpc/create-server.js +5 -3
- package/dist/server/rpc/handle-request.js +115 -19
- package/dist/server/rpc/handlers/cancelHandler.js +13 -2
- package/dist/server/rpc/handlers/completion-stream-delegated.js +4 -2
- package/dist/server/rpc/handlers/completion-stream.js +1 -1
- package/dist/server/rpc/handlers/delete-cache.js +4 -2
- package/dist/server/rpc/handlers/download-asset.js +3 -1
- package/dist/server/rpc/handlers/embed.js +4 -2
- package/dist/server/rpc/handlers/get-model-info.d.ts +1 -1
- package/dist/server/rpc/handlers/get-model-info.js +22 -10
- package/dist/server/rpc/handlers/index.d.ts +4 -2
- package/dist/server/rpc/handlers/index.js +2 -2
- package/dist/server/rpc/handlers/load-model/download-manager.d.ts +11 -11
- package/dist/server/rpc/handlers/load-model/download-manager.js +40 -28
- package/dist/server/rpc/handlers/{load-model.d.ts → load-model/handler.d.ts} +2 -2
- package/dist/server/rpc/handlers/load-model/handler.js +179 -0
- package/dist/server/rpc/handlers/load-model/http.js +361 -50
- package/dist/server/rpc/handlers/load-model/hyperdrive.js +26 -22
- package/dist/server/rpc/handlers/load-model/index.d.ts +2 -2
- package/dist/server/rpc/handlers/load-model/index.js +2 -2
- package/dist/server/rpc/handlers/load-model/resolve.js +39 -8
- package/dist/server/rpc/handlers/load-model-delegated.d.ts +2 -2
- package/dist/server/rpc/handlers/load-model-delegated.js +15 -10
- package/dist/server/rpc/handlers/logging-stream.js +4 -4
- package/dist/server/rpc/handlers/ocr-stream.d.ts +3 -0
- package/dist/server/rpc/handlers/ocr-stream.js +39 -0
- package/dist/server/rpc/handlers/provideHandler/connection.js +12 -10
- package/dist/server/rpc/handlers/provideHandler/handler.js +18 -16
- package/dist/server/rpc/handlers/provideHandler/proxy.js +8 -6
- package/dist/server/rpc/handlers/rag.d.ts +2 -2
- package/dist/server/rpc/handlers/rag.js +107 -41
- package/dist/server/rpc/handlers/stopProvideHandler.js +3 -1
- package/dist/server/rpc/handlers/text-to-speech.js +1 -1
- package/dist/server/rpc/handlers/transcribe-stream.js +4 -2
- package/dist/server/rpc/handlers/translate.js +9 -16
- package/dist/server/rpc/handlers/unload-model.js +4 -2
- package/dist/server/utils/archive.d.ts +3 -0
- package/dist/server/utils/archive.js +171 -0
- package/dist/server/utils/audio/decoder.d.ts +2 -1
- package/dist/server/utils/audio/decoder.js +48 -11
- package/dist/server/utils/cache.d.ts +5 -5
- package/dist/server/utils/cache.js +13 -11
- package/dist/server/utils/config-transform.d.ts +3 -0
- package/dist/server/utils/config-transform.js +23 -0
- package/dist/server/utils/formatting.d.ts +13 -0
- package/dist/server/utils/formatting.js +26 -0
- package/dist/server/utils/gguf-tensor-extractor.d.ts +15 -0
- package/dist/server/utils/gguf-tensor-extractor.js +314 -0
- package/dist/server/utils/index.d.ts +4 -1
- package/dist/server/utils/index.js +4 -1
- package/dist/server/utils/shard-utils.d.ts +42 -16
- package/dist/server/utils/shard-utils.js +95 -7
- package/dist/server/worker.js +49 -19
- package/dist/utils/errors-base.d.ts +1 -1
- package/dist/utils/errors-base.js +2 -2
- package/dist/utils/errors-client.d.ts +24 -0
- package/dist/utils/errors-client.js +40 -0
- package/dist/utils/errors-server.d.ts +42 -0
- package/dist/utils/errors-server.js +71 -0
- package/dist/utils/mcp-adapter.d.ts +12 -0
- package/dist/utils/mcp-adapter.js +103 -0
- package/dist/utils/object.d.ts +2 -0
- package/dist/utils/object.js +3 -0
- package/dist/utils/tool-helpers.d.ts +10 -2
- package/dist/utils/tool-helpers.js +24 -11
- package/package.json +74 -36
- package/dist/client/api/set-config.d.ts +0 -7
- package/dist/client/api/set-config.js +0 -20
- package/dist/client/config-manager.d.ts +0 -4
- package/dist/client/config-manager.js +0 -8
- package/dist/client/rpc/bare-rpc-client.d.ts +0 -4
- package/dist/client/rpc/bare-rpc-client.js +0 -91
- package/dist/examples/llamacpp-file-logging.d.ts +0 -2
- package/dist/examples/rag/rag-hyperdb-workspaces.d.ts +0 -2
- package/dist/examples/rag/rag-hyperdb-workspaces.js +0 -106
- package/dist/examples/rag/rag-hyperdb.d.ts +0 -2
- package/dist/schemas/set-config.d.ts +0 -21
- package/dist/schemas/set-config.js +0 -14
- package/dist/server/bare/addons/llamacpp/handlers/embed.d.ts +0 -4
- package/dist/server/bare/addons/llamacpp/index.d.ts +0 -4
- package/dist/server/bare/addons/llamacpp/index.js +0 -3
- package/dist/server/bare/addons/whispercpp/handlers/transcribe-stream.js +0 -63
- package/dist/server/bare/rag-hyperdb/rag-manager.d.ts +0 -5
- package/dist/server/bare/rag-hyperdb/rag-manager.js +0 -64
- package/dist/server/rpc/handlers/load-model.js +0 -59
- package/dist/server/rpc/handlers/set-config.d.ts +0 -3
- package/dist/server/rpc/handlers/set-config.js +0 -18
- package/dist/server/utils/hash.d.ts +0 -5
- package/dist/server/utils/hash.js +0 -11
- /package/dist/server/bare/addons/{llamacpp → llamacpp-completion}/handlers/completion-stream.d.ts +0 -0
- /package/dist/server/bare/addons/{translation → nmtcpp-translation}/create-model.d.ts +0 -0
- /package/dist/server/bare/addons/{translation → nmtcpp-translation}/handlers/translate.d.ts +0 -0
- /package/dist/server/bare/addons/{translation → nmtcpp-translation}/index.d.ts +0 -0
- /package/dist/server/bare/addons/{translation → nmtcpp-translation}/index.js +0 -0
- /package/dist/server/bare/addons/{tts → onnx-tts}/create-model.d.ts +0 -0
- /package/dist/server/bare/addons/{tts → onnx-tts}/create-model.js +0 -0
- /package/dist/server/bare/addons/{tts → onnx-tts}/handlers/text-to-speech.d.ts +0 -0
- /package/dist/server/bare/addons/{tts → onnx-tts}/handlers/text-to-speech.js +0 -0
- /package/dist/server/bare/addons/{tts → onnx-tts}/index.d.ts +0 -0
- /package/dist/server/bare/addons/{tts → onnx-tts}/index.js +0 -0
- /package/dist/server/bare/addons/{whispercpp → whispercpp-transcription}/create-model.d.ts +0 -0
- /package/dist/server/bare/addons/{whispercpp → whispercpp-transcription}/handlers/transcribe-stream.d.ts +0 -0
- /package/dist/server/bare/addons/{whispercpp → whispercpp-transcription}/index.d.ts +0 -0
- /package/dist/server/bare/addons/{whispercpp → whispercpp-transcription}/index.js +0 -0
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
import fs, { promises as fsPromises } from "bare-fs";
|
|
2
|
+
import path from "bare-path";
|
|
2
3
|
import { Readable } from "bare-stream";
|
|
3
4
|
import fetch from "bare-fetch";
|
|
4
5
|
import { AbortController } from "bare-abort-controller";
|
|
5
|
-
import {
|
|
6
|
+
import { withTimeout } from "../../../../utils/withTimeout.js";
|
|
7
|
+
import { getModelsCacheDir, getShardedModelCacheDir, generateShortHash, detectShardedModel, parsePatternBasedShardUrl, extractTensorsFromShards, calculatePercentage, isArchiveUrl, extractAndValidateShardedArchive, validateShardedModelCache, checkAllShardsExist, generateShardFilenames, hasValidGGUFHeader, } from "../../../utils/index.js";
|
|
8
|
+
import { getSDKConfig } from "../../../bare/registry/config-registry.js";
|
|
6
9
|
import { getActiveDownload, registerDownload, unregisterDownload, createHttpDownloadKey, shouldClearCache, clearClearCacheFlag, } from "./download-manager.js";
|
|
7
|
-
import { DownloadCancelledError, HTTPError, NoResponseBodyError, ResponseBodyNotReadableError, } from "../../../../utils/errors-server.js";
|
|
10
|
+
import { DownloadCancelledError, HTTPError, NoResponseBodyError, PartialDownloadOfflineError, ResponseBodyNotReadableError, } from "../../../../utils/errors-server.js";
|
|
11
|
+
import { getServerLogger } from "../../../../logging/index.js";
|
|
12
|
+
const logger = getServerLogger();
|
|
13
|
+
const DEFAULT_CONCURRENCY = 3;
|
|
14
|
+
const DEFAULT_HTTP_CONNECTION_TIMEOUT_MS = 10_000;
|
|
8
15
|
function extractFilenameFromUrl(url) {
|
|
9
16
|
// Parse URL to get the filename from the path
|
|
10
17
|
const urlParts = url.split("/");
|
|
@@ -18,28 +25,44 @@ async function validateCachedFile(modelPath, url, signal) {
|
|
|
18
25
|
await fsPromises.access(modelPath);
|
|
19
26
|
const localStats = await fsPromises.stat(modelPath);
|
|
20
27
|
const localSize = localStats.size;
|
|
21
|
-
|
|
28
|
+
const config = getSDKConfig();
|
|
29
|
+
const connectionTimeout = config.httpConnectionTimeoutMs ?? DEFAULT_HTTP_CONNECTION_TIMEOUT_MS;
|
|
22
30
|
let expectedSize = 0;
|
|
23
31
|
try {
|
|
24
|
-
const response = await fetch(url, {
|
|
32
|
+
const response = await withTimeout(fetch(url, {
|
|
25
33
|
method: "HEAD",
|
|
26
34
|
...(signal && { signal }),
|
|
27
|
-
});
|
|
35
|
+
}), connectionTimeout);
|
|
28
36
|
expectedSize = parseInt(response.headers.get("content-length") || "0");
|
|
29
37
|
}
|
|
30
|
-
catch (
|
|
31
|
-
|
|
38
|
+
catch (headError) {
|
|
39
|
+
logger.warn(`⚠️ HEAD request failed: ${headError instanceof Error ? headError.message : String(headError)}`);
|
|
40
|
+
logger.info(`📴 Falling back to GGUF header validation...`);
|
|
41
|
+
const hasValidHeader = await hasValidGGUFHeader(modelPath);
|
|
42
|
+
if (hasValidHeader) {
|
|
43
|
+
logger.info(`✅ Offline - GGUF header valid, using cached file: ${modelPath}`);
|
|
44
|
+
return modelPath;
|
|
45
|
+
}
|
|
46
|
+
if (localSize > 0) {
|
|
47
|
+
logger.error(`❌ Offline with partial download (${localSize} bytes). Cannot resume without network.`);
|
|
48
|
+
throw new PartialDownloadOfflineError(url, localSize);
|
|
49
|
+
}
|
|
50
|
+
logger.warn(`⚠️ Offline and GGUF validation failed - file may be incomplete`);
|
|
32
51
|
return null;
|
|
33
52
|
}
|
|
34
53
|
if (localSize !== expectedSize) {
|
|
35
|
-
|
|
54
|
+
logger.info(`📥 Cached file size mismatch. Expected: ${expectedSize}, Found: ${localSize}. Re-downloading...`);
|
|
36
55
|
return null;
|
|
37
56
|
}
|
|
38
|
-
|
|
57
|
+
logger.info(`✅ Using cached HTTP model: ${modelPath}`);
|
|
39
58
|
return modelPath;
|
|
40
59
|
}
|
|
41
|
-
catch {
|
|
42
|
-
//
|
|
60
|
+
catch (error) {
|
|
61
|
+
// Re-throw PartialDownloadOfflineError
|
|
62
|
+
if (error instanceof PartialDownloadOfflineError) {
|
|
63
|
+
throw error;
|
|
64
|
+
}
|
|
65
|
+
// File doesn't exist or other access error
|
|
43
66
|
return null;
|
|
44
67
|
}
|
|
45
68
|
}
|
|
@@ -47,7 +70,7 @@ async function performHttpDownload(url, modelPath, downloadKey, progressCallback
|
|
|
47
70
|
if (signal?.aborted) {
|
|
48
71
|
throw new DownloadCancelledError();
|
|
49
72
|
}
|
|
50
|
-
|
|
73
|
+
logger.info(`📥 Downloading model from HTTP: ${url}`);
|
|
51
74
|
// Check if file exists for resuming
|
|
52
75
|
let startOffset = 0;
|
|
53
76
|
let downloadedBytes = 0;
|
|
@@ -55,10 +78,10 @@ async function performHttpDownload(url, modelPath, downloadKey, progressCallback
|
|
|
55
78
|
const existingStats = await fsPromises.stat(modelPath);
|
|
56
79
|
startOffset = existingStats.size;
|
|
57
80
|
downloadedBytes = startOffset;
|
|
58
|
-
|
|
81
|
+
logger.info(`📥 Resuming download from byte ${startOffset}`);
|
|
59
82
|
}
|
|
60
83
|
catch {
|
|
61
|
-
|
|
84
|
+
logger.info(`📥 Starting fresh download`);
|
|
62
85
|
}
|
|
63
86
|
// Prepare headers for resume if needed
|
|
64
87
|
const headers = {
|
|
@@ -67,17 +90,30 @@ async function performHttpDownload(url, modelPath, downloadKey, progressCallback
|
|
|
67
90
|
if (startOffset > 0) {
|
|
68
91
|
headers["Range"] = `bytes=${startOffset}-`;
|
|
69
92
|
}
|
|
70
|
-
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
93
|
+
const config = getSDKConfig();
|
|
94
|
+
const connectionTimeout = config.httpConnectionTimeoutMs ?? DEFAULT_HTTP_CONNECTION_TIMEOUT_MS;
|
|
95
|
+
let response;
|
|
96
|
+
try {
|
|
97
|
+
response = await withTimeout(fetch(url, {
|
|
98
|
+
method: "GET",
|
|
99
|
+
headers,
|
|
100
|
+
...(signal && { signal }),
|
|
101
|
+
}), connectionTimeout);
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
// Check if it was parent abort
|
|
105
|
+
if (signal?.aborted) {
|
|
106
|
+
throw new DownloadCancelledError();
|
|
107
|
+
}
|
|
108
|
+
// Connection timeout or network error
|
|
109
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
110
|
+
logger.error(`❌ Connection failed: ${errorMsg}. URL: ${url}`);
|
|
111
|
+
throw new HTTPError(0, `Connection failed: ${errorMsg}`, error);
|
|
112
|
+
}
|
|
77
113
|
if (!response.ok) {
|
|
78
114
|
// Check if it's a 416 (Range Not Satisfiable) - file already complete
|
|
79
115
|
if (response.status === 416 && startOffset > 0) {
|
|
80
|
-
|
|
116
|
+
logger.info(`✅ File already completely downloaded`);
|
|
81
117
|
// Send 100% progress for already complete file
|
|
82
118
|
if (progressCallback) {
|
|
83
119
|
progressCallback({
|
|
@@ -92,22 +128,20 @@ async function performHttpDownload(url, modelPath, downloadKey, progressCallback
|
|
|
92
128
|
}
|
|
93
129
|
// Check if server doesn't support range requests
|
|
94
130
|
if (response.status === 200 && startOffset > 0) {
|
|
95
|
-
|
|
131
|
+
logger.warn(`⚠️ Server doesn't support resume, starting fresh download`);
|
|
96
132
|
startOffset = 0;
|
|
97
133
|
downloadedBytes = 0;
|
|
98
134
|
// Retry without Range header
|
|
99
|
-
|
|
135
|
+
response = await fetch(url, {
|
|
100
136
|
method: "GET",
|
|
101
137
|
headers: {
|
|
102
|
-
"User-Agent": "qvac-sdk
|
|
138
|
+
"User-Agent": "qvac-sdk",
|
|
103
139
|
},
|
|
104
140
|
...(signal && { signal }),
|
|
105
141
|
});
|
|
106
|
-
if (!
|
|
107
|
-
throw new HTTPError(
|
|
142
|
+
if (!response.ok) {
|
|
143
|
+
throw new HTTPError(response.status, response.statusText);
|
|
108
144
|
}
|
|
109
|
-
// Use the fresh response
|
|
110
|
-
Object.assign(response, freshResponse);
|
|
111
145
|
}
|
|
112
146
|
else if (response.status !== 206) {
|
|
113
147
|
// 206 is Partial Content (successful resume)
|
|
@@ -131,7 +165,7 @@ async function performHttpDownload(url, modelPath, downloadKey, progressCallback
|
|
|
131
165
|
// For fresh downloads
|
|
132
166
|
totalBytes = contentLength ? parseInt(contentLength) : 0;
|
|
133
167
|
}
|
|
134
|
-
|
|
168
|
+
logger.info(`📏 Total size: ${totalBytes} bytes (${(totalBytes / 1024 / 1024).toFixed(2)} MB)`);
|
|
135
169
|
// Create write stream (append if resuming)
|
|
136
170
|
const writeStreamOptions = startOffset > 0 && response.status === 206 ? { flags: "a" } : {};
|
|
137
171
|
const writeStream = fs.createWriteStream(modelPath, writeStreamOptions);
|
|
@@ -154,7 +188,7 @@ async function performHttpDownload(url, modelPath, downloadKey, progressCallback
|
|
|
154
188
|
type: "modelProgress",
|
|
155
189
|
downloaded: downloadedBytes,
|
|
156
190
|
total: totalBytes,
|
|
157
|
-
percentage:
|
|
191
|
+
percentage: calculatePercentage(downloadedBytes, totalBytes),
|
|
158
192
|
downloadKey,
|
|
159
193
|
});
|
|
160
194
|
}
|
|
@@ -174,7 +208,7 @@ async function performHttpDownload(url, modelPath, downloadKey, progressCallback
|
|
|
174
208
|
signal.addEventListener("abort", abortHandler);
|
|
175
209
|
}
|
|
176
210
|
writeStream.on("finish", () => {
|
|
177
|
-
|
|
211
|
+
logger.info(`✅ Model downloaded successfully to ${modelPath}`);
|
|
178
212
|
if (signal) {
|
|
179
213
|
signal.removeEventListener("abort", abortHandler);
|
|
180
214
|
}
|
|
@@ -199,7 +233,7 @@ async function performHttpDownload(url, modelPath, downloadKey, progressCallback
|
|
|
199
233
|
type: "modelProgress",
|
|
200
234
|
downloaded: downloadedBytes,
|
|
201
235
|
total: totalBytes,
|
|
202
|
-
percentage:
|
|
236
|
+
percentage: calculatePercentage(downloadedBytes, totalBytes),
|
|
203
237
|
downloadKey,
|
|
204
238
|
});
|
|
205
239
|
}
|
|
@@ -216,7 +250,7 @@ async function performHttpDownload(url, modelPath, downloadKey, progressCallback
|
|
|
216
250
|
// Close the write stream
|
|
217
251
|
await new Promise((resolve, reject) => {
|
|
218
252
|
writeStream.end(() => {
|
|
219
|
-
|
|
253
|
+
logger.info(`✅ Model downloaded successfully to ${modelPath}`);
|
|
220
254
|
resolve();
|
|
221
255
|
});
|
|
222
256
|
writeStream.on("error", reject);
|
|
@@ -241,7 +275,7 @@ async function performHttpDownload(url, modelPath, downloadKey, progressCallback
|
|
|
241
275
|
type: "modelProgress",
|
|
242
276
|
downloaded: downloadedBytes,
|
|
243
277
|
total: totalBytes,
|
|
244
|
-
percentage:
|
|
278
|
+
percentage: calculatePercentage(downloadedBytes, totalBytes),
|
|
245
279
|
downloadKey,
|
|
246
280
|
});
|
|
247
281
|
}
|
|
@@ -262,7 +296,7 @@ async function performHttpDownload(url, modelPath, downloadKey, progressCallback
|
|
|
262
296
|
// Close the write stream
|
|
263
297
|
await new Promise((resolve, reject) => {
|
|
264
298
|
writeStream.end(() => {
|
|
265
|
-
|
|
299
|
+
logger.info(`✅ Model downloaded successfully to ${modelPath}`);
|
|
266
300
|
resolve();
|
|
267
301
|
});
|
|
268
302
|
writeStream.on("error", reject);
|
|
@@ -275,21 +309,27 @@ async function performHttpDownload(url, modelPath, downloadKey, progressCallback
|
|
|
275
309
|
}
|
|
276
310
|
catch (error) {
|
|
277
311
|
writeStream.destroy();
|
|
278
|
-
|
|
312
|
+
logger.error("Error during download:", error instanceof Error ? error.message : String(error));
|
|
279
313
|
throw error instanceof Error ? error : new Error(String(error));
|
|
280
314
|
}
|
|
281
315
|
}
|
|
282
316
|
export async function downloadModelFromHttp(url, progressCallback) {
|
|
317
|
+
const filename = extractFilenameFromUrl(url);
|
|
318
|
+
if (isArchiveUrl(url)) {
|
|
319
|
+
return downloadShardedModelFromArchive(url, progressCallback);
|
|
320
|
+
}
|
|
321
|
+
const shardInfo = detectShardedModel(filename);
|
|
322
|
+
if (shardInfo.isSharded && shardInfo.totalShards) {
|
|
323
|
+
return downloadShardedModelFromHttp(url, progressCallback);
|
|
324
|
+
}
|
|
283
325
|
const downloadKey = createHttpDownloadKey(url);
|
|
284
|
-
// Check if already downloading
|
|
285
326
|
const existing = getActiveDownload(downloadKey);
|
|
286
327
|
if (existing) {
|
|
287
|
-
|
|
328
|
+
logger.info(`📥 Reusing existing download for: ${downloadKey}`);
|
|
288
329
|
return existing.promise;
|
|
289
330
|
}
|
|
290
331
|
const cacheDir = getModelsCacheDir();
|
|
291
332
|
const sourceHash = generateShortHash(url);
|
|
292
|
-
const filename = extractFilenameFromUrl(url);
|
|
293
333
|
const modelPath = `${cacheDir}/${sourceHash}_${filename}`;
|
|
294
334
|
// Create managed download with AbortController
|
|
295
335
|
const abortController = new AbortController();
|
|
@@ -309,8 +349,11 @@ export async function downloadModelFromHttp(url, progressCallback) {
|
|
|
309
349
|
downloadKey,
|
|
310
350
|
});
|
|
311
351
|
}
|
|
312
|
-
catch {
|
|
313
|
-
|
|
352
|
+
catch (error) {
|
|
353
|
+
logger.debug("Failed to get file stats for progress callback", {
|
|
354
|
+
path: cachedPath,
|
|
355
|
+
error,
|
|
356
|
+
});
|
|
314
357
|
}
|
|
315
358
|
}
|
|
316
359
|
return cachedPath;
|
|
@@ -329,28 +372,34 @@ export async function downloadModelFromHttp(url, progressCallback) {
|
|
|
329
372
|
downloadKey,
|
|
330
373
|
});
|
|
331
374
|
}
|
|
332
|
-
catch {
|
|
333
|
-
|
|
375
|
+
catch (error) {
|
|
376
|
+
logger.debug("Failed to get file stats for final progress update", {
|
|
377
|
+
path: modelPath,
|
|
378
|
+
error,
|
|
379
|
+
});
|
|
334
380
|
}
|
|
335
381
|
}
|
|
336
382
|
return modelPath;
|
|
337
383
|
}
|
|
338
384
|
catch (error) {
|
|
339
|
-
|
|
385
|
+
logger.error("❌ Error downloading model:", error instanceof Error ? error.message : String(error));
|
|
340
386
|
// Check if we should delete the partial file (clearCache was requested)
|
|
341
387
|
if (error instanceof Error && error.message === "Download cancelled") {
|
|
342
388
|
if (shouldClearCache(downloadKey)) {
|
|
343
|
-
|
|
389
|
+
logger.info("🗑️ Clearing cache - deleting partial file");
|
|
344
390
|
try {
|
|
345
391
|
await fsPromises.unlink(modelPath);
|
|
346
|
-
|
|
392
|
+
logger.info(`✅ Deleted partial file: ${modelPath}`);
|
|
347
393
|
}
|
|
348
|
-
catch {
|
|
349
|
-
|
|
394
|
+
catch (error) {
|
|
395
|
+
logger.debug("Failed to delete partial file during cleanup", {
|
|
396
|
+
path: modelPath,
|
|
397
|
+
error,
|
|
398
|
+
});
|
|
350
399
|
}
|
|
351
400
|
}
|
|
352
401
|
else {
|
|
353
|
-
|
|
402
|
+
logger.info("📥 Download paused - partial file preserved for resume");
|
|
354
403
|
}
|
|
355
404
|
clearClearCacheFlag(downloadKey);
|
|
356
405
|
}
|
|
@@ -376,3 +425,265 @@ export async function downloadModelFromHttp(url, progressCallback) {
|
|
|
376
425
|
registerDownload(downloadKey, downloadEntry);
|
|
377
426
|
return downloadPromise;
|
|
378
427
|
}
|
|
428
|
+
async function downloadShardedModelFromHttp(shardUrl, progressCallback) {
|
|
429
|
+
const config = getSDKConfig();
|
|
430
|
+
const concurrency = config.httpDownloadConcurrency ?? DEFAULT_CONCURRENCY;
|
|
431
|
+
const { shardUrls: shardInfos, cacheKey } = parsePatternBasedShardUrl(shardUrl);
|
|
432
|
+
const downloadKey = `http-sharded:${cacheKey}`;
|
|
433
|
+
logger.info(`📥 HTTP sharded download: ${shardInfos.length} shards detected from ${shardUrl}`);
|
|
434
|
+
const existing = getActiveDownload(downloadKey);
|
|
435
|
+
if (existing) {
|
|
436
|
+
logger.info(`📥 Reusing existing sharded download for: ${downloadKey}`);
|
|
437
|
+
return existing.promise;
|
|
438
|
+
}
|
|
439
|
+
const abortController = new AbortController();
|
|
440
|
+
const shardDir = getShardedModelCacheDir(cacheKey);
|
|
441
|
+
const downloadPromise = (async () => {
|
|
442
|
+
try {
|
|
443
|
+
const shardStates = await Promise.all(shardInfos.map(async (shard, index) => {
|
|
444
|
+
const shardPath = path.join(shardDir, shard.filename);
|
|
445
|
+
let expectedSize = 0;
|
|
446
|
+
try {
|
|
447
|
+
const response = await fetch(shard.url, {
|
|
448
|
+
method: "HEAD",
|
|
449
|
+
signal: abortController.signal,
|
|
450
|
+
});
|
|
451
|
+
expectedSize = parseInt(response.headers.get("content-length") || "0");
|
|
452
|
+
}
|
|
453
|
+
catch (error) {
|
|
454
|
+
logger.warn("Failed to get shard size via HEAD request", {
|
|
455
|
+
url: shard.url,
|
|
456
|
+
error,
|
|
457
|
+
});
|
|
458
|
+
// expectedSize remains 0, progress percentage will be 0
|
|
459
|
+
}
|
|
460
|
+
return {
|
|
461
|
+
index,
|
|
462
|
+
shard,
|
|
463
|
+
shardPath,
|
|
464
|
+
expectedSize,
|
|
465
|
+
downloadedBytes: 0,
|
|
466
|
+
isComplete: false,
|
|
467
|
+
};
|
|
468
|
+
}));
|
|
469
|
+
const overallTotal = shardStates.reduce((sum, s) => sum + s.expectedSize, 0);
|
|
470
|
+
logger.info(`📏 Total size: ${overallTotal} bytes (${(overallTotal / 1024 / 1024).toFixed(2)} MB)`);
|
|
471
|
+
const cacheChecks = await Promise.all(shardStates.map(async (state) => {
|
|
472
|
+
const cached = await validateCachedFile(state.shardPath, state.shard.url, abortController.signal);
|
|
473
|
+
return { state, isCached: cached !== null };
|
|
474
|
+
}));
|
|
475
|
+
const shardsToDownload = cacheChecks
|
|
476
|
+
.filter((c) => !c.isCached)
|
|
477
|
+
.map((c) => c.state);
|
|
478
|
+
for (const check of cacheChecks) {
|
|
479
|
+
if (check.isCached) {
|
|
480
|
+
check.state.isComplete = true;
|
|
481
|
+
check.state.downloadedBytes = check.state.expectedSize;
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
logger.info(`📥 ${shardsToDownload.length} of ${shardInfos.length} shards need downloading`);
|
|
485
|
+
await downloadShardsWithConcurrency(shardsToDownload, shardStates, concurrency, abortController.signal, downloadKey, overallTotal, progressCallback);
|
|
486
|
+
logger.info(`✅ All ${shardInfos.length} shards downloaded successfully`);
|
|
487
|
+
await extractTensorsFromShards(shardDir, shardInfos[0].filename);
|
|
488
|
+
return path.join(shardDir, shardInfos[0].filename);
|
|
489
|
+
}
|
|
490
|
+
catch (error) {
|
|
491
|
+
logger.error("❌ Error during sharded download:", error instanceof Error ? error.message : String(error));
|
|
492
|
+
if (error instanceof Error && error.message === "Download cancelled") {
|
|
493
|
+
if (shouldClearCache(downloadKey)) {
|
|
494
|
+
logger.info("🗑️ Clearing cache - deleting partial shard files");
|
|
495
|
+
try {
|
|
496
|
+
await fsPromises.rm(shardDir, { recursive: true, force: true });
|
|
497
|
+
logger.info(`✅ Deleted shard directory: ${shardDir}`);
|
|
498
|
+
}
|
|
499
|
+
catch (cleanupError) {
|
|
500
|
+
logger.debug("Failed to delete shard directory during cleanup", {
|
|
501
|
+
path: shardDir,
|
|
502
|
+
error: cleanupError,
|
|
503
|
+
});
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
throw error;
|
|
508
|
+
}
|
|
509
|
+
finally {
|
|
510
|
+
unregisterDownload(downloadKey);
|
|
511
|
+
clearClearCacheFlag(downloadKey);
|
|
512
|
+
}
|
|
513
|
+
})();
|
|
514
|
+
registerDownload(downloadKey, {
|
|
515
|
+
key: downloadKey,
|
|
516
|
+
promise: downloadPromise,
|
|
517
|
+
abortController,
|
|
518
|
+
startTime: Date.now(),
|
|
519
|
+
type: "http",
|
|
520
|
+
url: shardUrl,
|
|
521
|
+
modelPath: shardDir,
|
|
522
|
+
});
|
|
523
|
+
return downloadPromise;
|
|
524
|
+
}
|
|
525
|
+
async function downloadShardedModelFromArchive(archiveUrl, progressCallback) {
|
|
526
|
+
const filename = extractFilenameFromUrl(archiveUrl);
|
|
527
|
+
const sourceHash = generateShortHash(archiveUrl);
|
|
528
|
+
const downloadKey = `http-archive:${sourceHash}`;
|
|
529
|
+
logger.info(`📦 HTTP archive download: ${filename}`);
|
|
530
|
+
const existing = getActiveDownload(downloadKey);
|
|
531
|
+
if (existing) {
|
|
532
|
+
logger.info(`📥 Reusing existing archive download for: ${downloadKey}`);
|
|
533
|
+
return existing.promise;
|
|
534
|
+
}
|
|
535
|
+
const abortController = new AbortController();
|
|
536
|
+
const extractDir = getShardedModelCacheDir(sourceHash);
|
|
537
|
+
const archivePath = path.join(extractDir, `${sourceHash}_${filename}`);
|
|
538
|
+
const downloadPromise = (async () => {
|
|
539
|
+
try {
|
|
540
|
+
await fsPromises.mkdir(extractDir, { recursive: true });
|
|
541
|
+
const files = await fsPromises.readdir(extractDir);
|
|
542
|
+
const shardedFile = files.find((f) => detectShardedModel(String(f)).isSharded);
|
|
543
|
+
if (!shardedFile) {
|
|
544
|
+
return downloadAndExtractArchive();
|
|
545
|
+
}
|
|
546
|
+
const shardFilename = String(shardedFile);
|
|
547
|
+
const allShardsExist = await checkAllShardsExist(extractDir, shardFilename);
|
|
548
|
+
if (!allShardsExist) {
|
|
549
|
+
logger.warn(`⚠️ Incomplete shards found, re-downloading archive`);
|
|
550
|
+
return downloadAndExtractArchive();
|
|
551
|
+
}
|
|
552
|
+
const shardFilenames = generateShardFilenames(shardFilename);
|
|
553
|
+
const firstShard = path.join(extractDir, shardFilenames[0]);
|
|
554
|
+
const isComplete = await validateShardedModelCache(extractDir, shardFilename);
|
|
555
|
+
if (isComplete) {
|
|
556
|
+
logger.info(`✅ Archive already extracted: ${extractDir}`);
|
|
557
|
+
if (progressCallback) {
|
|
558
|
+
progressCallback({
|
|
559
|
+
type: "modelProgress",
|
|
560
|
+
downloaded: 1,
|
|
561
|
+
total: 1,
|
|
562
|
+
percentage: 100,
|
|
563
|
+
downloadKey,
|
|
564
|
+
});
|
|
565
|
+
}
|
|
566
|
+
return firstShard;
|
|
567
|
+
}
|
|
568
|
+
logger.info(`📝 All shards present but tensors.txt missing, extracting tensors...`);
|
|
569
|
+
try {
|
|
570
|
+
await extractTensorsFromShards(extractDir, shardFilename);
|
|
571
|
+
logger.info(`✅ Tensors extracted successfully`);
|
|
572
|
+
if (progressCallback) {
|
|
573
|
+
progressCallback({
|
|
574
|
+
type: "modelProgress",
|
|
575
|
+
downloaded: 1,
|
|
576
|
+
total: 1,
|
|
577
|
+
percentage: 100,
|
|
578
|
+
downloadKey,
|
|
579
|
+
});
|
|
580
|
+
}
|
|
581
|
+
return firstShard;
|
|
582
|
+
}
|
|
583
|
+
catch (error) {
|
|
584
|
+
logger.warn(`Failed to extract tensors, will re-download archive`, {
|
|
585
|
+
error,
|
|
586
|
+
});
|
|
587
|
+
return downloadAndExtractArchive();
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
catch (error) {
|
|
591
|
+
logger.error("❌ Error downloading/extracting archive:", error);
|
|
592
|
+
throw error;
|
|
593
|
+
}
|
|
594
|
+
finally {
|
|
595
|
+
unregisterDownload(downloadKey);
|
|
596
|
+
}
|
|
597
|
+
async function downloadAndExtractArchive() {
|
|
598
|
+
await performHttpDownload(archiveUrl, archivePath, downloadKey, progressCallback, abortController.signal);
|
|
599
|
+
logger.info(`✅ Archive downloaded, extracting to: ${extractDir}`);
|
|
600
|
+
const firstShardPath = await extractAndValidateShardedArchive(archivePath, extractDir, abortController.signal);
|
|
601
|
+
try {
|
|
602
|
+
await fsPromises.unlink(archivePath);
|
|
603
|
+
logger.info(`🗑️ Cleaned up archive file: ${archivePath}`);
|
|
604
|
+
}
|
|
605
|
+
catch (cleanupError) {
|
|
606
|
+
logger.debug("Failed to delete archive file during cleanup", {
|
|
607
|
+
path: archivePath,
|
|
608
|
+
error: cleanupError,
|
|
609
|
+
});
|
|
610
|
+
}
|
|
611
|
+
return firstShardPath;
|
|
612
|
+
}
|
|
613
|
+
})();
|
|
614
|
+
registerDownload(downloadKey, {
|
|
615
|
+
key: downloadKey,
|
|
616
|
+
promise: downloadPromise,
|
|
617
|
+
abortController,
|
|
618
|
+
startTime: Date.now(),
|
|
619
|
+
type: "http",
|
|
620
|
+
url: archiveUrl,
|
|
621
|
+
modelPath: archivePath,
|
|
622
|
+
});
|
|
623
|
+
return downloadPromise;
|
|
624
|
+
}
|
|
625
|
+
async function downloadShardsWithConcurrency(shardsToDownload, allShards, concurrency, signal, downloadKey, overallTotal, progressCallback) {
|
|
626
|
+
const queue = [...shardsToDownload];
|
|
627
|
+
const inFlight = new Set();
|
|
628
|
+
while (queue.length > 0 || inFlight.size > 0) {
|
|
629
|
+
if (signal.aborted) {
|
|
630
|
+
throw new DownloadCancelledError();
|
|
631
|
+
}
|
|
632
|
+
while (queue.length > 0 && inFlight.size < concurrency) {
|
|
633
|
+
const state = queue.shift();
|
|
634
|
+
const downloadPromise = (async () => {
|
|
635
|
+
logger.info(`📥 Downloading shard ${state.index + 1}: ${state.shard.filename}`);
|
|
636
|
+
await performHttpDownload(state.shard.url, state.shardPath, downloadKey, (progress) => {
|
|
637
|
+
state.downloadedBytes = progress.downloaded;
|
|
638
|
+
if (progressCallback) {
|
|
639
|
+
const overallDownloaded = allShards.reduce((sum, s) => sum + s.downloadedBytes, 0);
|
|
640
|
+
progressCallback({
|
|
641
|
+
type: "modelProgress",
|
|
642
|
+
downloaded: state.downloadedBytes,
|
|
643
|
+
total: state.expectedSize,
|
|
644
|
+
percentage: calculatePercentage(state.downloadedBytes, state.expectedSize),
|
|
645
|
+
downloadKey,
|
|
646
|
+
shardInfo: {
|
|
647
|
+
currentShard: state.index + 1,
|
|
648
|
+
totalShards: allShards.length,
|
|
649
|
+
shardName: state.shard.filename,
|
|
650
|
+
overallDownloaded,
|
|
651
|
+
overallTotal,
|
|
652
|
+
overallPercentage: calculatePercentage(overallDownloaded, overallTotal),
|
|
653
|
+
},
|
|
654
|
+
});
|
|
655
|
+
}
|
|
656
|
+
}, signal);
|
|
657
|
+
logger.info(`✅ Shard ${state.index + 1} complete: ${state.shard.filename}`);
|
|
658
|
+
})().finally(() => {
|
|
659
|
+
inFlight.delete(downloadPromise);
|
|
660
|
+
});
|
|
661
|
+
inFlight.add(downloadPromise);
|
|
662
|
+
}
|
|
663
|
+
if (inFlight.size > 0) {
|
|
664
|
+
await Promise.race(inFlight);
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
// Mark all downloaded shards as complete
|
|
668
|
+
for (const state of shardsToDownload) {
|
|
669
|
+
state.isComplete = true;
|
|
670
|
+
state.downloadedBytes = state.expectedSize;
|
|
671
|
+
}
|
|
672
|
+
if (progressCallback) {
|
|
673
|
+
progressCallback({
|
|
674
|
+
type: "modelProgress",
|
|
675
|
+
downloaded: overallTotal,
|
|
676
|
+
total: overallTotal,
|
|
677
|
+
percentage: 100,
|
|
678
|
+
downloadKey,
|
|
679
|
+
shardInfo: {
|
|
680
|
+
currentShard: allShards.length,
|
|
681
|
+
totalShards: allShards.length,
|
|
682
|
+
shardName: allShards[allShards.length - 1].shard.filename,
|
|
683
|
+
overallDownloaded: overallTotal,
|
|
684
|
+
overallTotal,
|
|
685
|
+
overallPercentage: 100,
|
|
686
|
+
},
|
|
687
|
+
});
|
|
688
|
+
}
|
|
689
|
+
}
|