@qvac/sdk 0.5.0 → 0.6.1
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 +48 -11
- 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/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 -1
- package/dist/client/api/index.js +2 -1
- package/dist/client/api/load-model.js +6 -1
- 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 +1 -1
- package/dist/client/init-hooks.d.ts +4 -3
- package/dist/client/init-hooks.js +40 -31
- package/dist/client/rpc/bare-client.d.ts +1 -178
- package/dist/client/rpc/bare-client.js +42 -9
- package/dist/client/rpc/expo-rpc-client.js +57 -2
- package/dist/client/rpc/node-rpc-client.js +5 -1
- package/dist/client/rpc/rpc-client.d.ts +1 -1
- package/dist/client/rpc/rpc-client.js +11 -57
- 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/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 +4 -3
- package/dist/examples/embed-hyperdrive.js +4 -0
- package/dist/examples/kv-cache-custom-key.js +16 -1
- package/dist/examples/llamacpp-sharded.js +12 -3
- 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 +3 -2
- package/dist/index.js +3 -1
- package/dist/logging/addon.js +23 -7
- package/dist/logging/base-logger.js +2 -2
- package/dist/logging/client-logger.js +15 -4
- package/dist/logging/index.d.ts +1 -0
- package/dist/logging/index.js +1 -0
- package/dist/logging/logger.js +11 -3
- package/dist/logging/namespaces.d.ts +1 -0
- package/dist/logging/namespaces.js +1 -0
- package/dist/logging/registry.d.ts +5 -0
- package/dist/logging/registry.js +17 -5
- package/dist/logging/transport.js +2 -2
- package/dist/logging/utils.d.ts +2 -0
- package/dist/logging/utils.js +62 -0
- package/dist/models/hyperdrive/models.d.ts +1096 -178
- package/dist/models/hyperdrive/models.js +1476 -507
- 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 +582 -77
- package/dist/schemas/common.js +6 -1
- 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/get-model-info.d.ts +12 -10
- package/dist/schemas/get-model-info.js +9 -1
- package/dist/schemas/index.d.ts +6 -2
- package/dist/schemas/index.js +9 -2
- package/dist/schemas/llamacpp-config.d.ts +112 -8
- package/dist/schemas/llamacpp-config.js +40 -8
- package/dist/schemas/load-model.d.ts +2993 -525
- package/dist/schemas/load-model.js +88 -33
- package/dist/schemas/logging-stream.d.ts +2 -2
- package/dist/schemas/model-src-utils.d.ts +38 -16
- package/dist/schemas/model-src-utils.js +4 -8
- 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 +20 -8
- package/dist/schemas/reload-config.js +7 -5
- package/dist/schemas/runtime-context.d.ts +19 -0
- package/dist/schemas/runtime-context.js +7 -0
- package/dist/schemas/sdk-config.d.ts +697 -2
- package/dist/schemas/sdk-config.js +99 -1
- package/dist/schemas/sdk-errors-client.d.ts +1 -0
- package/dist/schemas/sdk-errors-client.js +5 -0
- package/dist/schemas/sdk-errors-server.d.ts +14 -0
- package/dist/schemas/sdk-errors-server.js +70 -0
- package/dist/schemas/shard.d.ts +21 -0
- package/dist/schemas/shard.js +17 -0
- package/dist/schemas/translate.d.ts +68 -23
- package/dist/schemas/translate.js +37 -11
- package/dist/schemas/translation-config.d.ts +272 -29
- package/dist/schemas/translation-config.js +63 -6
- 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 +3 -26
- 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 +43 -10
- 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/index.d.ts +3 -0
- package/dist/server/bare/addons/llamacpp-embedding/index.js +2 -0
- package/dist/server/bare/addons/load-model.js +28 -24
- 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/{whispercpp → whispercpp-transcription}/create-model.js +2 -1
- package/dist/server/bare/delegate-rpc-client.js +19 -1
- 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.js +11 -0
- package/dist/server/bare/registry/logging-stream-registry.js +3 -3
- 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 +110 -0
- package/dist/server/bare/registry/model-registry.d.ts +6 -29
- 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/handle-request.js +91 -9
- package/dist/server/rpc/handlers/cancelHandler.js +10 -1
- package/dist/server/rpc/handlers/completion-stream.js +1 -1
- package/dist/server/rpc/handlers/delete-cache.js +1 -1
- package/dist/server/rpc/handlers/embed.js +1 -1
- 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 -1
- package/dist/server/rpc/handlers/index.js +2 -0
- package/dist/server/rpc/handlers/load-model/download-manager.d.ts +11 -11
- package/dist/server/rpc/handlers/load-model/download-manager.js +36 -26
- 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 +342 -33
- package/dist/server/rpc/handlers/load-model/hyperdrive.js +5 -3
- 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 +32 -3
- package/dist/server/rpc/handlers/load-model-delegated.js +6 -3
- 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/rag.d.ts +2 -2
- package/dist/server/rpc/handlers/rag.js +107 -43
- package/dist/server/rpc/handlers/text-to-speech.js +1 -1
- package/dist/server/rpc/handlers/transcribe-stream.js +1 -1
- package/dist/server/rpc/handlers/translate.js +6 -15
- package/dist/server/utils/archive.d.ts +3 -0
- package/dist/server/utils/archive.js +171 -0
- package/dist/server/utils/audio/decoder.js +2 -2
- package/dist/server/utils/cache.d.ts +5 -5
- package/dist/server/utils/cache.js +6 -6
- package/dist/server/utils/config-transform.d.ts +2 -2
- package/dist/server/utils/config-transform.js +8 -6
- 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 +3 -1
- package/dist/server/utils/index.js +3 -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 +8 -3
- package/dist/utils/errors-base.d.ts +1 -1
- package/dist/utils/errors-base.js +2 -2
- package/dist/utils/errors-client.d.ts +12 -0
- package/dist/utils/errors-client.js +20 -0
- package/dist/utils/errors-server.d.ts +33 -0
- package/dist/utils/errors-server.js +55 -0
- package/package.json +42 -17
- package/dist/client/rpc/bare-rpc-client.d.ts +0 -4
- package/dist/client/rpc/bare-rpc-client.js +0 -94
- package/dist/examples/config/config-path.d.ts +0 -8
- package/dist/examples/config/config-path.js +0 -13
- 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/server/bare/addons/llamacpp/index.d.ts +0 -4
- package/dist/server/bare/addons/llamacpp/index.js +0 -3
- package/dist/server/bare/rag-hyperdb/rag-manager.d.ts +0 -5
- package/dist/server/bare/rag-hyperdb/rag-manager.js +0 -66
- package/dist/server/rpc/handlers/load-model.js +0 -111
- package/dist/server/utils/hash.d.ts +0 -5
- package/dist/server/utils/hash.js +0 -11
- package/dist/utils/getProcessSafe.d.ts +0 -7
- package/dist/utils/getProcessSafe.js +0 -17
- package/dist/utils/runtime.d.ts +0 -30
- package/dist/utils/runtime.js +0 -48
- /package/dist/server/bare/addons/{llamacpp → llamacpp-completion}/handlers/completion-stream.d.ts +0 -0
- /package/dist/server/bare/addons/{llamacpp → llamacpp-embedding}/handlers/embed.d.ts +0 -0
- /package/dist/server/bare/addons/{llamacpp → llamacpp-embedding}/handlers/embed.js +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}/handlers/transcribe-stream.js +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
package/dist/server/bare/addons/{llamacpp → llamacpp-completion}/handlers/completion-stream.js
RENAMED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {} from "../../../../../schemas/index.js";
|
|
2
|
-
import {
|
|
2
|
+
import { logCacheDisabled, logCacheInit, logCacheSave, logCacheStatus, logMessagesToAddon, } from "../cache-logger.js";
|
|
3
|
+
import { customCacheExists, extractSystemPrompt, findMatchingCache, generateConfigHash, getCacheFilePath, getCurrentCacheInfo, markCacheInitialized, renameCacheFile, } from "../kv-cache-utils.js";
|
|
3
4
|
import { getModel, getModelConfig, } from "../../../registry/model-registry.js";
|
|
4
5
|
import { checkForToolEvents, insertToolsIntoHistory, setupToolGrammar, } from "../../../../utils/tool-integration.js";
|
|
5
6
|
import { parseToolCalls } from "../../../../utils/tool-parser.js";
|
|
@@ -43,15 +44,19 @@ function transformMessages(messages) {
|
|
|
43
44
|
}
|
|
44
45
|
return transformed;
|
|
45
46
|
}
|
|
46
|
-
async function initSystemPromptCache(model, cachePathToUse, systemPromptToUse, tools) {
|
|
47
|
+
async function initSystemPromptCache(model, cachePathToUse, systemPromptToUse, cacheKey, tools) {
|
|
47
48
|
const primeMessages = [
|
|
48
49
|
{ role: "session", content: cachePathToUse },
|
|
49
50
|
{ role: "system", content: systemPromptToUse },
|
|
50
51
|
];
|
|
52
|
+
let toolCount = 0;
|
|
51
53
|
if (tools && tools.length > 0) {
|
|
52
54
|
const transformedTools = transformMessages(tools);
|
|
53
55
|
primeMessages.push(...transformedTools);
|
|
56
|
+
toolCount = tools.length;
|
|
54
57
|
}
|
|
58
|
+
logCacheInit(cacheKey, systemPromptToUse, toolCount);
|
|
59
|
+
logMessagesToAddon(primeMessages, "CACHE_INIT");
|
|
55
60
|
const primeResponse = await model.run(primeMessages);
|
|
56
61
|
primeResponse.once("output", () => {
|
|
57
62
|
void primeResponse.cancel();
|
|
@@ -95,6 +100,10 @@ async function* processModelResponse(model, messagesToSend, shouldSaveCache, too
|
|
|
95
100
|
toolCallsResult = toolCalls;
|
|
96
101
|
}
|
|
97
102
|
if (shouldSaveCache) {
|
|
103
|
+
const sessionMsg = messagesToSend.find((m) => m.role === "session");
|
|
104
|
+
if (sessionMsg?.content) {
|
|
105
|
+
logCacheSave(sessionMsg.content);
|
|
106
|
+
}
|
|
98
107
|
await model.run([{ role: "session", content: "save" }]);
|
|
99
108
|
}
|
|
100
109
|
const responseWithStats = response;
|
|
@@ -119,18 +128,22 @@ export async function* completion(params) {
|
|
|
119
128
|
if (kvCache) {
|
|
120
129
|
const modelConfig = getModelConfig(modelId);
|
|
121
130
|
const systemPromptFromHistory = extractSystemPrompt(history);
|
|
122
|
-
const configHash = generateConfigHash(
|
|
131
|
+
const configHash = generateConfigHash(systemPromptFromHistory, tools);
|
|
123
132
|
const systemPromptToUse = systemPromptFromHistory ||
|
|
124
133
|
modelConfig.system_prompt ||
|
|
125
134
|
"You are a helpful assistant.";
|
|
126
135
|
let cachePathToUse;
|
|
127
136
|
if (typeof kvCache === "string") {
|
|
128
137
|
cachePathToUse = await getCacheFilePath(modelId, configHash, kvCache);
|
|
129
|
-
|
|
138
|
+
let cacheExists = await customCacheExists(modelId, configHash, kvCache);
|
|
139
|
+
logCacheStatus(kvCache, cacheExists);
|
|
130
140
|
if (!cacheExists) {
|
|
131
|
-
await initSystemPromptCache(model, cachePathToUse, systemPromptToUse, tools && toolsEnabled ? tools : undefined);
|
|
141
|
+
await initSystemPromptCache(model, cachePathToUse, systemPromptToUse, kvCache, tools && toolsEnabled ? tools : undefined);
|
|
142
|
+
markCacheInitialized(modelId, configHash, kvCache);
|
|
143
|
+
cacheExists = true;
|
|
132
144
|
}
|
|
133
145
|
const messagesToSend = prepareMessagesForCache(cachePathToUse, cacheExists, history);
|
|
146
|
+
logMessagesToAddon(messagesToSend, "PROMPT_SEND");
|
|
134
147
|
return yield* processModelResponse(model, messagesToSend, true, tools);
|
|
135
148
|
}
|
|
136
149
|
else {
|
|
@@ -146,11 +159,15 @@ export async function* completion(params) {
|
|
|
146
159
|
existingCache !== null
|
|
147
160
|
? existingCache.cachePath
|
|
148
161
|
: currentCacheInfo.cachePath;
|
|
149
|
-
|
|
162
|
+
let cacheExists = existingCache !== null;
|
|
163
|
+
logCacheStatus("auto", cacheExists);
|
|
150
164
|
if (!cacheExists) {
|
|
151
|
-
await initSystemPromptCache(model, cachePathToUse, systemPromptToUse, tools && toolsEnabled ? tools : undefined);
|
|
165
|
+
await initSystemPromptCache(model, cachePathToUse, systemPromptToUse, "auto", tools && toolsEnabled ? tools : undefined);
|
|
166
|
+
markCacheInitialized(modelId, configHash, currentCacheInfo.cacheKey);
|
|
167
|
+
cacheExists = true;
|
|
152
168
|
}
|
|
153
169
|
const messagesToSend = prepareMessagesForCache(cachePathToUse, cacheExists, history);
|
|
170
|
+
logMessagesToAddon(messagesToSend, "PROMPT_SEND");
|
|
154
171
|
const result = yield* processModelResponse(model, messagesToSend, true, tools);
|
|
155
172
|
//If there was an existing cache, we rename it with new hash that includes the current message
|
|
156
173
|
if (existingCache !== null &&
|
|
@@ -161,6 +178,8 @@ export async function* completion(params) {
|
|
|
161
178
|
}
|
|
162
179
|
}
|
|
163
180
|
else {
|
|
181
|
+
logCacheDisabled();
|
|
182
|
+
logMessagesToAddon(transformedHistory, "NO_CACHE");
|
|
164
183
|
return yield* processModelResponse(model, transformedHistory, false, tools);
|
|
165
184
|
}
|
|
166
185
|
}
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
export declare function markCacheInitialized(modelId: string, configHash: string, cacheKey: string): void;
|
|
2
|
+
export declare function isCacheInitialized(modelId: string, configHash: string, cacheKey: string): boolean;
|
|
3
|
+
export declare function clearCacheRegistry(cacheKey?: string): void;
|
|
1
4
|
export interface CacheMessage {
|
|
2
5
|
role: string;
|
|
3
6
|
content: string;
|
|
@@ -6,7 +9,7 @@ export interface CacheMessage {
|
|
|
6
9
|
}[] | undefined;
|
|
7
10
|
}
|
|
8
11
|
export declare function extractSystemPrompt(messages: CacheMessage[]): string | null;
|
|
9
|
-
export declare function generateConfigHash(
|
|
12
|
+
export declare function generateConfigHash(systemPrompt: string | null, tools?: unknown): string;
|
|
10
13
|
export declare function generateCacheKey(messages: CacheMessage[]): string;
|
|
11
14
|
export declare function getCacheFilePath(modelId: string, configHash: string, cacheKey: string): Promise<string>;
|
|
12
15
|
export declare function findMatchingCache(modelId: string, configHash: string, currentHistory: CacheMessage[]): Promise<{
|
|
@@ -4,21 +4,48 @@ import path from "bare-path";
|
|
|
4
4
|
import { getKVCacheDir } from "../../../utils/index.js";
|
|
5
5
|
import { getServerLogger } from "../../../../logging/index.js";
|
|
6
6
|
const logger = getServerLogger();
|
|
7
|
+
// In-memory registry tracks caches initialized this session (addon defers disk writes)
|
|
8
|
+
const initializedCaches = new Set();
|
|
9
|
+
function getCacheRegistryKey(modelId, configHash, cacheKey) {
|
|
10
|
+
return `${modelId}:${configHash}:${cacheKey}`;
|
|
11
|
+
}
|
|
12
|
+
export function markCacheInitialized(modelId, configHash, cacheKey) {
|
|
13
|
+
initializedCaches.add(getCacheRegistryKey(modelId, configHash, cacheKey));
|
|
14
|
+
}
|
|
15
|
+
export function isCacheInitialized(modelId, configHash, cacheKey) {
|
|
16
|
+
return initializedCaches.has(getCacheRegistryKey(modelId, configHash, cacheKey));
|
|
17
|
+
}
|
|
18
|
+
export function clearCacheRegistry(cacheKey) {
|
|
19
|
+
if (cacheKey) {
|
|
20
|
+
for (const key of initializedCaches) {
|
|
21
|
+
if (key.includes(`:${cacheKey}`)) {
|
|
22
|
+
initializedCaches.delete(key);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
initializedCaches.clear();
|
|
28
|
+
}
|
|
29
|
+
}
|
|
7
30
|
export function extractSystemPrompt(messages) {
|
|
8
31
|
const systemMessage = messages.find((msg) => msg.role === "system");
|
|
9
32
|
return systemMessage ? systemMessage.content : null;
|
|
10
33
|
}
|
|
11
|
-
|
|
34
|
+
function getToolNamesForHash(tools) {
|
|
35
|
+
if (!Array.isArray(tools))
|
|
36
|
+
return [];
|
|
37
|
+
return tools
|
|
38
|
+
.map((t) => t.name)
|
|
39
|
+
.filter((n) => typeof n === "string")
|
|
40
|
+
.sort();
|
|
41
|
+
}
|
|
42
|
+
// Cache hash based on system prompt + tool names
|
|
43
|
+
// Different tools = different cache (tools anchored in first message, protected from n_discarded)
|
|
44
|
+
export function generateConfigHash(systemPrompt, tools) {
|
|
12
45
|
const hash = crypto.createHash("sha256");
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
tools,
|
|
17
|
-
});
|
|
18
|
-
const configBuffer = Buffer.from(configStr, "utf8");
|
|
19
|
-
hash.update(configBuffer);
|
|
20
|
-
const hashString = hash.digest("hex");
|
|
21
|
-
return hashString.substring(0, 16);
|
|
46
|
+
const toolNames = getToolNamesForHash(tools);
|
|
47
|
+
hash.update(Buffer.from(JSON.stringify({ systemPrompt, toolNames }), "utf8"));
|
|
48
|
+
return hash.digest("hex").substring(0, 16);
|
|
22
49
|
}
|
|
23
50
|
export function generateCacheKey(messages) {
|
|
24
51
|
const hash = crypto.createHash("sha256");
|
|
@@ -72,9 +99,15 @@ export async function renameCacheFile(oldPath, newPath) {
|
|
|
72
99
|
}
|
|
73
100
|
}
|
|
74
101
|
export async function customCacheExists(modelId, configHash, cacheKey) {
|
|
102
|
+
// Check in-memory registry first (addon defers disk writes)
|
|
103
|
+
if (isCacheInitialized(modelId, configHash, cacheKey)) {
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
// Then check file system (for caches from previous runs)
|
|
75
107
|
const cachePath = await getCacheFilePath(modelId, configHash, cacheKey);
|
|
76
108
|
try {
|
|
77
109
|
await fsPromises.access(cachePath);
|
|
110
|
+
markCacheInitialized(modelId, configHash, cacheKey);
|
|
78
111
|
return true;
|
|
79
112
|
}
|
|
80
113
|
catch {
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { AnyModel } from "../../registry/model-registry";
|
|
2
|
+
import type { EmbedConfig } from "../../../../schemas/index";
|
|
3
|
+
import FilesystemDL from "@qvac/dl-filesystem";
|
|
4
|
+
export declare function createEmbeddingsModel(modelId: string, modelPath: string, embedConfig: EmbedConfig): {
|
|
5
|
+
model: AnyModel;
|
|
6
|
+
loader: FilesystemDL;
|
|
7
|
+
};
|
|
8
|
+
//# sourceMappingURL=create-model.d.ts.map
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import EmbedLlamacpp, {} from "@qvac/embed-llamacpp";
|
|
2
|
+
import { ADDON_NAMESPACES, registerAddonLogger, createStreamLogger, } from "../../../../logging/index.js";
|
|
3
|
+
import { parseModelPath } from "../../../utils/index.js";
|
|
4
|
+
import FilesystemDL from "@qvac/dl-filesystem";
|
|
5
|
+
import { asLoader } from "../../utils/loader-adapter.js";
|
|
6
|
+
function transformEmbedConfig(embedConfig) {
|
|
7
|
+
if (embedConfig.rawConfig) {
|
|
8
|
+
return embedConfig.rawConfig;
|
|
9
|
+
}
|
|
10
|
+
const lines = [];
|
|
11
|
+
lines.push(`-ngl\t${embedConfig.gpuLayers}`);
|
|
12
|
+
lines.push(`-dev\t${embedConfig.device}`);
|
|
13
|
+
lines.push(`--batch_size\t${embedConfig.batchSize}`);
|
|
14
|
+
if (embedConfig.ctxSize) {
|
|
15
|
+
lines.push(`-c\t${embedConfig.ctxSize}`);
|
|
16
|
+
}
|
|
17
|
+
if (embedConfig.flashAttention) {
|
|
18
|
+
lines.push(`-fa\t${embedConfig.flashAttention}`);
|
|
19
|
+
}
|
|
20
|
+
return lines.join("\n");
|
|
21
|
+
}
|
|
22
|
+
export function createEmbeddingsModel(modelId, modelPath, embedConfig) {
|
|
23
|
+
const { dirPath, basePath } = parseModelPath(modelPath);
|
|
24
|
+
const loader = new FilesystemDL({ dirPath });
|
|
25
|
+
const logger = createStreamLogger(modelId, ADDON_NAMESPACES.LLAMACPP_EMBED);
|
|
26
|
+
registerAddonLogger(modelId, ADDON_NAMESPACES.LLAMACPP_EMBED, logger);
|
|
27
|
+
const config = transformEmbedConfig(embedConfig);
|
|
28
|
+
const args = {
|
|
29
|
+
loader: asLoader(loader),
|
|
30
|
+
opts: { stats: true },
|
|
31
|
+
logger,
|
|
32
|
+
diskPath: dirPath,
|
|
33
|
+
modelName: basePath,
|
|
34
|
+
modelPath,
|
|
35
|
+
};
|
|
36
|
+
const model = new EmbedLlamacpp(args, config);
|
|
37
|
+
return { model, loader };
|
|
38
|
+
}
|
|
@@ -1,18 +1,20 @@
|
|
|
1
|
-
import { loadModelServerParamsSchema, } from "../../../schemas/index.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
1
|
+
import { loadModelServerParamsSchema, ModelType, } from "../../../schemas/index.js";
|
|
2
|
+
import { createLlmModel } from "./llamacpp-completion/index.js";
|
|
3
|
+
import { createEmbeddingsModel } from "./llamacpp-embedding/index.js";
|
|
4
|
+
import { createNmtModel } from "./nmtcpp-translation/index.js";
|
|
5
|
+
import { createTtsModel } from "./onnx-tts/index.js";
|
|
6
|
+
import { createWhisperModel } from "./whispercpp-transcription/index.js";
|
|
7
|
+
import { createOCRModel } from "./onnx-ocr/index.js";
|
|
6
8
|
import { isModelLoaded, registerModel, } from "../registry/model-registry.js";
|
|
7
9
|
import { startLogBuffering, stopLogBufferingWithTimeout, } from "../registry/logging-stream-registry.js";
|
|
8
|
-
import { detectShardedModel, generateShardFilenames } from "../../utils/index.js";
|
|
9
|
-
import { ESpeakDataPathRequiredError, UnknownModelTypeError, ModelFileNotFoundError, ModelFileNotFoundInDirError, ModelFileLocateFailedError, } from "../../../utils/errors-server.js";
|
|
10
|
+
import { detectShardedModel, generateShardFilenames, validateShardedModelCache, } from "../../utils/index.js";
|
|
11
|
+
import { ESpeakDataPathRequiredError, ModelLoadFailedError, UnknownModelTypeError, ModelFileNotFoundError, ModelFileNotFoundInDirError, ModelFileLocateFailedError, } from "../../../utils/errors-server.js";
|
|
10
12
|
import { promises as fsPromises } from "bare-fs";
|
|
11
13
|
import path from "bare-path";
|
|
12
14
|
import { getServerLogger } from "../../../logging/index.js";
|
|
13
15
|
const logger = getServerLogger();
|
|
14
16
|
export async function loadModel(params) {
|
|
15
|
-
const { modelId, modelPath, options, projectionModelPath, vadModelPath, ttsConfigModelPath, eSpeakDataPath, modelName, } = loadModelServerParamsSchema.parse(params);
|
|
17
|
+
const { modelId, modelPath, options, projectionModelPath, vadModelPath, ttsConfigModelPath, eSpeakDataPath, detectorModelPath, modelName, } = loadModelServerParamsSchema.parse(params);
|
|
16
18
|
const { modelConfig, modelType } = options;
|
|
17
19
|
// Check if model is already loaded
|
|
18
20
|
if (isModelLoaded(modelId)) {
|
|
@@ -24,17 +26,12 @@ export async function loadModel(params) {
|
|
|
24
26
|
const shardInfo = detectShardedModel(modelFileName);
|
|
25
27
|
const isShardedModel = shardInfo.isSharded;
|
|
26
28
|
if (isShardedModel) {
|
|
27
|
-
// For sharded models, validate all
|
|
29
|
+
// For sharded models, validate all shards and tensors.txt exist
|
|
28
30
|
const shardDir = path.dirname(modelPath);
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
await fsPromises.access(shardPath);
|
|
34
|
-
}
|
|
35
|
-
catch (error) {
|
|
36
|
-
throw new ModelFileNotFoundError(`${shardFile}. Expected ${allRequiredFiles.length} files (shards + companion files) in ${shardDir}`, error);
|
|
37
|
-
}
|
|
31
|
+
const isValid = await validateShardedModelCache(shardDir, modelFileName);
|
|
32
|
+
if (!isValid) {
|
|
33
|
+
const numberedShards = generateShardFilenames(modelFileName);
|
|
34
|
+
throw new ModelFileNotFoundError(`Missing shards or ${shardInfo.baseFilename}.tensors.txt. Expected ${numberedShards.length} shard files + tensors.txt in ${shardDir}`);
|
|
38
35
|
}
|
|
39
36
|
}
|
|
40
37
|
else {
|
|
@@ -54,26 +51,33 @@ export async function loadModel(params) {
|
|
|
54
51
|
}
|
|
55
52
|
let result;
|
|
56
53
|
switch (modelType) {
|
|
57
|
-
case
|
|
54
|
+
case ModelType.llamacppCompletion:
|
|
58
55
|
result = createLlmModel(modelId, modelPath, modelConfig, projectionModelPath);
|
|
59
56
|
break;
|
|
60
|
-
case
|
|
57
|
+
case ModelType.whispercppTranscription:
|
|
61
58
|
result = createWhisperModel(modelId, modelPath, modelConfig, vadModelPath);
|
|
62
59
|
break;
|
|
63
|
-
case
|
|
60
|
+
case ModelType.llamacppEmbedding:
|
|
64
61
|
result = createEmbeddingsModel(modelId, modelPath, modelConfig);
|
|
65
62
|
break;
|
|
66
|
-
case
|
|
63
|
+
case ModelType.nmtcppTranslation:
|
|
67
64
|
result = createNmtModel(modelId, modelPath, modelConfig);
|
|
68
65
|
break;
|
|
69
|
-
case
|
|
66
|
+
case ModelType.onnxTts:
|
|
70
67
|
if (!eSpeakDataPath) {
|
|
71
68
|
throw new ESpeakDataPathRequiredError();
|
|
72
69
|
}
|
|
73
70
|
result = createTtsModel(modelId, modelPath, modelConfig, ttsConfigModelPath, eSpeakDataPath);
|
|
74
71
|
break;
|
|
72
|
+
case ModelType.onnxOcr:
|
|
73
|
+
if (!detectorModelPath) {
|
|
74
|
+
throw new ModelLoadFailedError("Detector model required for OCR. Use a hyperdrive source or provide detectorModelSrc");
|
|
75
|
+
}
|
|
76
|
+
// modelPath is the recognizer, detectorModelPath is auto-derived
|
|
77
|
+
result = createOCRModel(modelId, detectorModelPath, modelPath, modelConfig);
|
|
78
|
+
break;
|
|
75
79
|
default:
|
|
76
|
-
// Should never happen
|
|
80
|
+
// Should never happen - normalizeModelType validates input
|
|
77
81
|
throw new UnknownModelTypeError(modelType);
|
|
78
82
|
}
|
|
79
83
|
logger.info(`${modelType}: Loading model ${modelId}...`);
|
|
@@ -1,17 +1,18 @@
|
|
|
1
|
-
import TranslationNmtcpp from "@qvac/translation-nmtcpp";
|
|
1
|
+
import TranslationNmtcpp, {} from "@qvac/translation-nmtcpp";
|
|
2
2
|
import {} from "../../registry/model-registry.js";
|
|
3
|
-
import {
|
|
3
|
+
import {} from "../../../../schemas/index.js";
|
|
4
4
|
import { createStreamLogger } from "../../../../logging/index.js";
|
|
5
5
|
import { parseModelPath } from "../../../utils/index.js";
|
|
6
6
|
import FilesystemDL from "@qvac/dl-filesystem";
|
|
7
7
|
import { TranslationFailedError } from "../../../../utils/errors-server.js";
|
|
8
|
+
import { asLoader } from "../../utils/loader-adapter.js";
|
|
8
9
|
export function createNmtModel(modelId, modelPath, nmtConfig) {
|
|
9
10
|
const { dirPath, basePath } = parseModelPath(modelPath);
|
|
10
11
|
const loader = new FilesystemDL({ dirPath });
|
|
11
12
|
const logger = createStreamLogger(modelId, "nmtcpp");
|
|
12
|
-
const { mode, from, to,
|
|
13
|
+
const { mode, from, to, engine, beamsize, lengthpenalty, maxlength, repetitionpenalty, norepeatngramsize, temperature, topk, topp, } = nmtConfig;
|
|
13
14
|
const args = {
|
|
14
|
-
loader,
|
|
15
|
+
loader: asLoader(loader),
|
|
15
16
|
logger,
|
|
16
17
|
modelName: basePath,
|
|
17
18
|
diskPath: dirPath,
|
|
@@ -21,12 +22,26 @@ export function createNmtModel(modelId, modelPath, nmtConfig) {
|
|
|
21
22
|
dstLang: to,
|
|
22
23
|
},
|
|
23
24
|
};
|
|
25
|
+
const generationParams = {
|
|
26
|
+
beamsize,
|
|
27
|
+
lengthpenalty,
|
|
28
|
+
maxlength,
|
|
29
|
+
repetitionpenalty,
|
|
30
|
+
norepeatngramsize,
|
|
31
|
+
temperature,
|
|
32
|
+
topk,
|
|
33
|
+
topp,
|
|
34
|
+
};
|
|
24
35
|
const config = {
|
|
25
|
-
modelType:
|
|
26
|
-
INDICTRANS_LANGUAGES.includes(to)
|
|
27
|
-
? TranslationNmtcpp.ModelTypes.IndicTrans
|
|
28
|
-
: TranslationNmtcpp.ModelTypes.Opus,
|
|
36
|
+
modelType: TranslationNmtcpp.ModelTypes[engine],
|
|
29
37
|
...generationParams,
|
|
38
|
+
...(nmtConfig.engine === "Bergamot" && {
|
|
39
|
+
...(nmtConfig.srcVocabPath && { srcVocabPath: nmtConfig.srcVocabPath }),
|
|
40
|
+
...(nmtConfig.dstVocabPath && { dstVocabPath: nmtConfig.dstVocabPath }),
|
|
41
|
+
...(nmtConfig.normalize !== undefined && {
|
|
42
|
+
normalize: nmtConfig.normalize,
|
|
43
|
+
}),
|
|
44
|
+
}),
|
|
30
45
|
};
|
|
31
46
|
// Fail fast if model type is IndicTrans
|
|
32
47
|
if (config.modelType === TranslationNmtcpp.ModelTypes.IndicTrans) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { getModel } from "../../../registry/model-registry.js";
|
|
2
|
-
import { translateServerParamsSchema, } from "../../../../../schemas/index.js";
|
|
2
|
+
import { translateServerParamsSchema, normalizeModelType, ModelType, } from "../../../../../schemas/index.js";
|
|
3
3
|
import { getLangName } from "@qvac/langdetect-text";
|
|
4
4
|
function getLanguage(code) {
|
|
5
5
|
if (!code)
|
|
@@ -8,28 +8,52 @@ function getLanguage(code) {
|
|
|
8
8
|
return fullName ?? code.toUpperCase();
|
|
9
9
|
}
|
|
10
10
|
export async function* translate(params) {
|
|
11
|
-
const { modelId, text, modelType } = params;
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
const
|
|
11
|
+
const { modelId, text, modelType: inputModelType } = params;
|
|
12
|
+
const canonicalModelType = normalizeModelType(inputModelType);
|
|
13
|
+
const isLlm = canonicalModelType === ModelType.llamacppCompletion;
|
|
14
|
+
const from = isLlm ? params.from : undefined;
|
|
15
|
+
const to = isLlm ? params.to : undefined;
|
|
16
|
+
const context = isLlm ? params.context : undefined;
|
|
15
17
|
translateServerParamsSchema.parse(params);
|
|
16
18
|
const model = getModel(modelId);
|
|
17
19
|
const fromLanguage = getLanguage(from);
|
|
18
20
|
const toLanguage = getLanguage(to);
|
|
21
|
+
const startTime = Date.now();
|
|
22
|
+
let processedTokens = 0;
|
|
23
|
+
// Check if input is an array and model type is NMT
|
|
24
|
+
if (Array.isArray(text) &&
|
|
25
|
+
canonicalModelType === ModelType.nmtcppTranslation) {
|
|
26
|
+
// Use runBatch for batch processing
|
|
27
|
+
const translations = await model.runBatch(text);
|
|
28
|
+
// Yield each translation with a newline separator
|
|
29
|
+
for (const translation of translations) {
|
|
30
|
+
processedTokens++;
|
|
31
|
+
yield translation;
|
|
32
|
+
if (translations.indexOf(translation) < translations.length - 1) {
|
|
33
|
+
yield "\n";
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
const endTime = Date.now();
|
|
37
|
+
return {
|
|
38
|
+
processedTokens,
|
|
39
|
+
processingTime: endTime - startTime,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
// Single text processing (for NMT or LLM)
|
|
43
|
+
const singleText = Array.isArray(text) ? text[0] : text;
|
|
19
44
|
// Prepare input based on model type
|
|
20
|
-
const input =
|
|
21
|
-
?
|
|
45
|
+
const input = canonicalModelType === ModelType.nmtcppTranslation
|
|
46
|
+
? singleText
|
|
22
47
|
: [
|
|
23
48
|
{
|
|
24
49
|
role: "system",
|
|
25
|
-
content: `${context ? `${context}. ` : ""}Translate the following text from ${fromLanguage} into ${toLanguage}. Only output the translation, nothing else.\n\n${fromLanguage}: ${
|
|
50
|
+
content: `${context ? `${context}. ` : ""}Translate the following text from ${fromLanguage} into ${toLanguage}. Only output the translation, nothing else.\n\n${fromLanguage}: ${singleText}\n${toLanguage}:`,
|
|
26
51
|
},
|
|
27
52
|
];
|
|
28
|
-
const startTime = Date.now();
|
|
29
|
-
let processedTokens = 0;
|
|
30
53
|
const response = await model.run(input);
|
|
31
54
|
// Check if the response has an iterate method (like LLM models)
|
|
32
|
-
if (
|
|
55
|
+
if (canonicalModelType === ModelType.llamacppCompletion &&
|
|
56
|
+
typeof response.iterate === "function") {
|
|
33
57
|
for await (const token of response.iterate()) {
|
|
34
58
|
processedTokens++;
|
|
35
59
|
yield token;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { OCRConfig } from "../../../../schemas/ocr";
|
|
2
|
+
import { type AnyModel } from "../../registry/model-registry";
|
|
3
|
+
import FilesystemDL from "@qvac/dl-filesystem";
|
|
4
|
+
import { ONNXOcr } from "@qvac/ocr-onnx";
|
|
5
|
+
export type OCRModel = ONNXOcr;
|
|
6
|
+
export declare function createOCRModel(modelId: string, detectorPath: string, recognizerPath: string, ocrConfig: OCRConfig): {
|
|
7
|
+
model: AnyModel;
|
|
8
|
+
loader: FilesystemDL;
|
|
9
|
+
};
|
|
10
|
+
//# sourceMappingURL=create-model.d.ts.map
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import {} from "../../registry/model-registry.js";
|
|
2
|
+
import { createStreamLogger } from "../../../../logging/index.js";
|
|
3
|
+
import { parseModelPath } from "../../../utils/index.js";
|
|
4
|
+
import FilesystemDL from "@qvac/dl-filesystem";
|
|
5
|
+
import { ONNXOcr } from "@qvac/ocr-onnx";
|
|
6
|
+
export function createOCRModel(modelId, detectorPath, recognizerPath, ocrConfig) {
|
|
7
|
+
const { dirPath } = parseModelPath(detectorPath);
|
|
8
|
+
const loader = new FilesystemDL({ dirPath });
|
|
9
|
+
const logger = createStreamLogger(modelId, "ocr");
|
|
10
|
+
const params = {
|
|
11
|
+
pathDetector: detectorPath,
|
|
12
|
+
pathRecognizer: recognizerPath,
|
|
13
|
+
langList: ocrConfig.langList || ["en"],
|
|
14
|
+
useGPU: ocrConfig.useGPU ?? true,
|
|
15
|
+
...(ocrConfig.timeout !== undefined && { timeout: ocrConfig.timeout }),
|
|
16
|
+
...(ocrConfig.magRatio !== undefined && { magRatio: ocrConfig.magRatio }),
|
|
17
|
+
...(ocrConfig.defaultRotationAngles !== undefined && {
|
|
18
|
+
defaultRotationAngles: ocrConfig.defaultRotationAngles,
|
|
19
|
+
}),
|
|
20
|
+
...(ocrConfig.contrastRetry !== undefined && {
|
|
21
|
+
contrastRetry: ocrConfig.contrastRetry,
|
|
22
|
+
}),
|
|
23
|
+
...(ocrConfig.lowConfidenceThreshold !== undefined && {
|
|
24
|
+
lowConfidenceThreshold: ocrConfig.lowConfidenceThreshold,
|
|
25
|
+
}),
|
|
26
|
+
...(ocrConfig.recognizerBatchSize !== undefined && {
|
|
27
|
+
recognizerBatchSize: ocrConfig.recognizerBatchSize,
|
|
28
|
+
}),
|
|
29
|
+
};
|
|
30
|
+
const args = {
|
|
31
|
+
loader: loader,
|
|
32
|
+
logger,
|
|
33
|
+
params,
|
|
34
|
+
opts: { stats: true },
|
|
35
|
+
};
|
|
36
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
|
|
37
|
+
const model = new ONNXOcr(args);
|
|
38
|
+
return { model, loader };
|
|
39
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { OCRParams, OCRTextBlock } from "../../../../../schemas/ocr";
|
|
2
|
+
export declare function ocr(params: OCRParams): AsyncGenerator<{
|
|
3
|
+
blocks: OCRTextBlock[];
|
|
4
|
+
stats?: {
|
|
5
|
+
detectionTime?: number;
|
|
6
|
+
recognitionTime?: number;
|
|
7
|
+
totalTime?: number;
|
|
8
|
+
};
|
|
9
|
+
}, void, void>;
|
|
10
|
+
//# sourceMappingURL=ocr-stream.d.ts.map
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { getModel } from "../../../registry/model-registry.js";
|
|
2
|
+
import fs from "bare-fs";
|
|
3
|
+
import path from "bare-path";
|
|
4
|
+
import { getCacheDir } from "../../../../utils/index.js";
|
|
5
|
+
import { ImageFileNotFoundError, InvalidImageInputError, } from "../../../../../utils/errors-server.js";
|
|
6
|
+
function polygonToBbox(polygon) {
|
|
7
|
+
const xs = polygon.map((p) => p[0]);
|
|
8
|
+
const ys = polygon.map((p) => p[1]);
|
|
9
|
+
return [Math.min(...xs), Math.min(...ys), Math.max(...xs), Math.max(...ys)];
|
|
10
|
+
}
|
|
11
|
+
function normalizeBlock(block) {
|
|
12
|
+
if (block &&
|
|
13
|
+
typeof block === "object" &&
|
|
14
|
+
!Array.isArray(block) &&
|
|
15
|
+
"text" in block) {
|
|
16
|
+
const obj = block;
|
|
17
|
+
return {
|
|
18
|
+
text: obj.text || "",
|
|
19
|
+
...(obj.bbox && { bbox: obj.bbox }),
|
|
20
|
+
...(obj.confidence !== undefined && { confidence: obj.confidence }),
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
// Addon format: [polygon, text, confidence] where polygon is [[x1,y1], [x2,y2], [x3,y3], [x4,y4]]
|
|
24
|
+
if (Array.isArray(block) && block.length >= 2) {
|
|
25
|
+
const blockArr = block;
|
|
26
|
+
const [polygonOrBbox, text, confidence] = blockArr;
|
|
27
|
+
const textStr = typeof text === "string" ? text : "";
|
|
28
|
+
if (Array.isArray(polygonOrBbox) &&
|
|
29
|
+
polygonOrBbox.length === 4 &&
|
|
30
|
+
Array.isArray(polygonOrBbox[0]) &&
|
|
31
|
+
polygonOrBbox[0].length === 2) {
|
|
32
|
+
return {
|
|
33
|
+
text: textStr,
|
|
34
|
+
bbox: polygonToBbox(polygonOrBbox),
|
|
35
|
+
...(confidence !== undefined && { confidence: Number(confidence) }),
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
if (Array.isArray(polygonOrBbox) &&
|
|
39
|
+
polygonOrBbox.length === 4 &&
|
|
40
|
+
typeof polygonOrBbox[0] === "number") {
|
|
41
|
+
return {
|
|
42
|
+
text: textStr,
|
|
43
|
+
bbox: polygonOrBbox,
|
|
44
|
+
...(confidence !== undefined && { confidence: Number(confidence) }),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
export async function* ocr(params) {
|
|
51
|
+
const model = getModel(params.modelId);
|
|
52
|
+
let imagePath;
|
|
53
|
+
let cleanupPath = null;
|
|
54
|
+
switch (params.image.type) {
|
|
55
|
+
case "base64": {
|
|
56
|
+
const tempDir = getCacheDir("tmp");
|
|
57
|
+
const tempPath = path.join(tempDir, `ocr-${Date.now()}.png`);
|
|
58
|
+
fs.writeFileSync(tempPath, Buffer.from(params.image.value, "base64"));
|
|
59
|
+
imagePath = tempPath;
|
|
60
|
+
cleanupPath = tempPath;
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
case "filePath": {
|
|
64
|
+
imagePath = params.image.value;
|
|
65
|
+
try {
|
|
66
|
+
fs.accessSync(imagePath);
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
throw new ImageFileNotFoundError(imagePath, error);
|
|
70
|
+
}
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
default:
|
|
74
|
+
throw new InvalidImageInputError();
|
|
75
|
+
}
|
|
76
|
+
try {
|
|
77
|
+
const response = (await model.run({
|
|
78
|
+
path: imagePath,
|
|
79
|
+
...(params.options && { options: params.options }),
|
|
80
|
+
}));
|
|
81
|
+
const rawData = [];
|
|
82
|
+
await response
|
|
83
|
+
.onUpdate((data) => {
|
|
84
|
+
rawData.push(data);
|
|
85
|
+
return [];
|
|
86
|
+
})
|
|
87
|
+
.await();
|
|
88
|
+
const blocks = rawData
|
|
89
|
+
.flat(1)
|
|
90
|
+
.map(normalizeBlock)
|
|
91
|
+
.filter((b) => b !== null);
|
|
92
|
+
if (blocks.length > 0) {
|
|
93
|
+
yield { blocks };
|
|
94
|
+
}
|
|
95
|
+
if (response.stats) {
|
|
96
|
+
yield { blocks: [], stats: response.stats };
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
finally {
|
|
100
|
+
if (cleanupPath) {
|
|
101
|
+
try {
|
|
102
|
+
fs.unlinkSync(cleanupPath);
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
// Ignore cleanup errors
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|