@qvac/sdk 0.17.0 → 0.18.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 +83 -18
- package/README.md +19 -0
- package/dist/client/api/audio-gen.d.ts +17 -0
- package/dist/client/api/audio-gen.js +17 -0
- package/dist/client/api/finetune.d.ts +2 -0
- package/dist/client/api/finetune.js +7 -1
- package/dist/client/api/index.d.ts +1 -1
- package/dist/client/api/index.js +1 -1
- package/dist/client/api/load-model.d.ts +8 -0
- package/dist/client/api/transcribe.d.ts +19 -2
- package/dist/client/api/transcribe.js +66 -27
- package/dist/client/api/translate.d.ts +3 -2
- package/dist/client/api/translate.js +42 -21
- package/dist/client/api/vla.d.ts +42 -1
- package/dist/client/api/vla.js +50 -1
- package/dist/commands/bundle/entry-gen.d.ts +4 -0
- package/dist/commands/bundle/entry-gen.js +6 -0
- package/dist/commands/bundle/index.js +19 -12
- package/dist/examples/asr/parakeet-indic-conformer-filesystem.d.ts +2 -0
- package/dist/examples/asr/parakeet-indic-conformer-filesystem.js +52 -0
- package/dist/examples/audiogen/generate-cover.d.ts +2 -0
- package/dist/examples/audiogen/generate-cover.js +100 -0
- package/dist/examples/llamacpp-fallback.d.ts +2 -0
- package/dist/examples/llamacpp-fallback.js +34 -0
- package/dist/examples/multi-job-completion.d.ts +28 -0
- package/dist/examples/multi-job-completion.js +128 -0
- package/dist/examples/profiling/basic.js +32 -1
- package/dist/examples/system-resources.d.ts +2 -0
- package/dist/examples/system-resources.js +86 -0
- package/dist/examples/tts/audio8.d.ts +2 -0
- package/dist/examples/tts/audio8.js +54 -0
- package/dist/examples/tts/cosyvoice3.d.ts +2 -0
- package/dist/examples/tts/cosyvoice3.js +52 -0
- package/dist/examples/vla-groot.js +92 -49
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/models/registry/models.d.ts +782 -6
- package/dist/models/registry/models.js +2664 -1859
- package/dist/schemas/audio-gen.d.ts +103 -0
- package/dist/schemas/audio-gen.js +135 -4
- package/dist/schemas/common.d.ts +550 -11
- package/dist/schemas/constants-registry.d.ts +18 -4
- package/dist/schemas/constants-registry.js +16 -3
- package/dist/schemas/index.d.ts +1 -1
- package/dist/schemas/index.js +1 -1
- package/dist/schemas/llamacpp-config.d.ts +10 -10
- package/dist/schemas/llamacpp-config.js +12 -5
- package/dist/schemas/load-model.d.ts +3678 -323
- package/dist/schemas/load-model.js +21 -3
- package/dist/schemas/sdk-config.d.ts +60 -24
- package/dist/schemas/sdk-errors-server.d.ts +1 -0
- package/dist/schemas/sdk-errors-server.js +5 -0
- package/dist/schemas/text-to-speech.d.ts +1086 -110
- package/dist/schemas/text-to-speech.js +194 -4
- package/dist/schemas/tools.d.ts +0 -16
- package/dist/schemas/tools.js +0 -15
- package/dist/schemas/transcription-config.d.ts +2 -0
- package/dist/schemas/transcription-config.js +10 -4
- package/dist/schemas/transcription.d.ts +3 -0
- package/dist/schemas/vla.d.ts +83 -0
- package/dist/schemas/vla.js +105 -2
- package/dist/scripts/link-workspace-inference.d.ts +2 -0
- package/dist/scripts/link-workspace-inference.js +31 -0
- package/dist/server/bare/ops/cancel.d.ts +1 -1
- package/dist/server/bare/ops/cancel.js +1 -1
- package/dist/server/bare/ops/kv-cache-retention.js +11 -0
- package/dist/server/bare/ops/kv-cache-utils.d.ts +1 -1
- package/dist/server/bare/ops/kv-cache-utils.js +40 -12
- package/dist/server/bare/ops/transcribe.d.ts +2 -2
- package/dist/server/bare/ops/transcribe.js +54 -48
- package/dist/server/bare/ops/translate-stats.d.ts +5 -0
- package/dist/server/bare/ops/translate-stats.js +11 -0
- package/dist/server/bare/ops/translate.js +66 -38
- package/dist/server/bare/ops/unload-model.js +30 -24
- package/dist/server/bare/plugins/audiogen-ggml/ops/audio-gen-input.d.ts +20 -0
- package/dist/server/bare/plugins/audiogen-ggml/ops/audio-gen-input.js +153 -0
- package/dist/server/bare/plugins/audiogen-ggml/ops/audio-gen-stream.js +52 -1
- package/dist/server/bare/plugins/audiogen-ggml/plugin.d.ts +28 -0
- package/dist/server/bare/plugins/ggml-ocr/plugin.js +3 -1
- package/dist/server/bare/plugins/ggml-vla/ops/vla-set-embodiment.d.ts +3 -0
- package/dist/server/bare/plugins/ggml-vla/ops/vla-set-embodiment.js +9 -0
- package/dist/server/bare/plugins/ggml-vla/plugin.d.ts +37 -0
- package/dist/server/bare/plugins/ggml-vla/plugin.js +21 -4
- package/dist/server/bare/plugins/llamacpp-completion/ops/batch-completion-stream.js +16 -15
- package/dist/server/bare/plugins/llamacpp-completion/ops/cache-logger.d.ts +1 -1
- package/dist/server/bare/plugins/llamacpp-completion/ops/cache-logger.js +2 -2
- package/dist/server/bare/plugins/llamacpp-completion/ops/completion-stats.d.ts +6 -0
- package/dist/server/bare/plugins/llamacpp-completion/ops/completion-stats.js +10 -0
- package/dist/server/bare/plugins/llamacpp-completion/ops/completion-stream.d.ts +1 -0
- package/dist/server/bare/plugins/llamacpp-completion/ops/completion-stream.js +131 -123
- package/dist/server/bare/plugins/llamacpp-completion/ops/finetune.js +110 -20
- package/dist/server/bare/plugins/llamacpp-completion/ops/kv-cache-session.d.ts +49 -23
- package/dist/server/bare/plugins/llamacpp-completion/ops/kv-cache-session.js +308 -143
- package/dist/server/bare/plugins/llamacpp-completion/ops/kv-cache-state.d.ts +1 -0
- package/dist/server/bare/plugins/llamacpp-completion/ops/kv-cache-state.js +2 -2
- package/dist/server/bare/plugins/llamacpp-completion/plugin.d.ts +6 -6
- package/dist/server/bare/plugins/llamacpp-completion/plugin.js +55 -36
- package/dist/server/bare/plugins/llamacpp-completion/transform.js +1 -7
- package/dist/server/bare/plugins/llamacpp-embedding/plugin.js +2 -3
- package/dist/server/bare/plugins/nmtcpp-translation/plugin.js +6 -5
- package/dist/server/bare/plugins/parakeet-transcription/plugin.js +27 -16
- package/dist/server/bare/plugins/tts-ggml/ops/parler-options.js +23 -3
- package/dist/server/bare/plugins/tts-ggml/plugin.d.ts +302 -4
- package/dist/server/bare/plugins/tts-ggml/plugin.js +131 -0
- package/dist/server/bare/plugins/whispercpp-transcription/plugin.js +48 -39
- package/dist/server/bare/registry/model-registry.d.ts +1 -0
- package/dist/server/bare/runtime/request-registry-singleton.js +29 -15
- package/dist/server/bare/runtime/request-registry.d.ts +27 -0
- package/dist/server/bare/runtime/request-registry.js +246 -76
- package/dist/server/bare/types/addon-responses.d.ts +4 -12
- package/dist/server/rpc/handlers/load-model/handler.js +2 -2
- package/dist/server/rpc/handlers/load-model/resolve-session.d.ts +1 -1
- package/dist/server/rpc/handlers/load-model/resolve-session.js +3 -3
- package/dist/server/rpc/handlers/load-model/resolve.d.ts +12 -2
- package/dist/server/rpc/handlers/load-model/resolve.js +90 -12
- package/dist/server/utils/audio/decoder.d.ts +37 -1
- package/dist/server/utils/audio/decoder.js +81 -51
- package/dist/server/utils/config-transform.d.ts +3 -0
- package/dist/server/utils/config-transform.js +6 -0
- package/dist/server/utils/index.d.ts +0 -1
- package/dist/server/utils/index.js +0 -1
- package/dist/server/utils/shard-utils.d.ts +1 -0
- package/dist/server/utils/shard-utils.js +14 -0
- package/dist/server/utils/tool-integration.d.ts +3 -10
- package/dist/server/utils/tool-integration.js +3 -12
- package/dist/utils/errors-server.d.ts +3 -0
- package/dist/utils/errors-server.js +5 -0
- package/package.json +12 -14
- package/dist/examples/llamacpp-dynamic-tools.d.ts +0 -2
- package/dist/examples/llamacpp-dynamic-tools.js +0 -152
- package/dist/models/update-models/codegen.d.ts +0 -3
- package/dist/models/update-models/codegen.js +0 -196
- package/dist/models/update-models/companions.d.ts +0 -30
- package/dist/models/update-models/companions.js +0 -296
- package/dist/models/update-models/history.d.ts +0 -24
- package/dist/models/update-models/history.js +0 -107
- package/dist/models/update-models/index.d.ts +0 -2
- package/dist/models/update-models/index.js +0 -123
- package/dist/models/update-models/naming.d.ts +0 -4
- package/dist/models/update-models/naming.js +0 -396
- package/dist/models/update-models/processing.d.ts +0 -8
- package/dist/models/update-models/processing.js +0 -65
- package/dist/models/update-models/registry.d.ts +0 -5
- package/dist/models/update-models/registry.js +0 -87
- package/dist/models/update-models/shards.d.ts +0 -4
- package/dist/models/update-models/shards.js +0 -57
- package/dist/models/update-models/types.d.ts +0 -88
- package/dist/models/update-models/types.js +0 -1
- package/dist/models/update-models/utils.d.ts +0 -3
- package/dist/models/update-models/utils.js +0 -21
- package/dist/server/bare/plugins/llamacpp-completion/ops/batch-cancelled.d.ts +0 -23
- package/dist/server/bare/plugins/llamacpp-completion/ops/batch-cancelled.js +0 -30
- package/dist/server/utils/expand-gguf-shards.d.ts +0 -3
- package/dist/server/utils/expand-gguf-shards.js +0 -22
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Dynamic-tools mode example.
|
|
3
|
-
*
|
|
4
|
-
* In `dynamic` mode each user prompt can carry its own tool set: the addon
|
|
5
|
-
* anchors tools after the last user message, runs the tool-call chain, then
|
|
6
|
-
* trims the tools + chain output from the kv-cache so a later turn can ship
|
|
7
|
-
* a different tool list without poisoning the cache. Compare with
|
|
8
|
-
* `llamacpp-native-tools.ts`, which uses the default `static` mode where
|
|
9
|
-
* one shared tool set lives at the top of the session.
|
|
10
|
-
*
|
|
11
|
-
* Run with:
|
|
12
|
-
* bun run build
|
|
13
|
-
* bun run bare:example dist/examples/llamacpp-dynamic-tools.js
|
|
14
|
-
*/
|
|
15
|
-
import { z } from 'zod';
|
|
16
|
-
import { completion, loadModel, unloadModel, QWEN3_1_7B_INST_Q4 } from '@qvac/sdk';
|
|
17
|
-
const weatherSchema = z.object({
|
|
18
|
-
city: z.string().describe('City name')
|
|
19
|
-
});
|
|
20
|
-
const horoscopeSchema = z.object({
|
|
21
|
-
sign: z.string().describe('An astrological sign, e.g. Taurus or Aquarius')
|
|
22
|
-
});
|
|
23
|
-
const dateSchema = z.object({});
|
|
24
|
-
const toolSchemas = {
|
|
25
|
-
get_weather: weatherSchema,
|
|
26
|
-
get_horoscope: horoscopeSchema,
|
|
27
|
-
get_date: dateSchema
|
|
28
|
-
};
|
|
29
|
-
const weatherTools = [
|
|
30
|
-
{
|
|
31
|
-
name: 'get_weather',
|
|
32
|
-
description: 'Get current weather for a city',
|
|
33
|
-
parameters: weatherSchema
|
|
34
|
-
}
|
|
35
|
-
];
|
|
36
|
-
const horoscopeTools = [
|
|
37
|
-
{
|
|
38
|
-
name: 'get_horoscope',
|
|
39
|
-
description: "Get today's horoscope for an astrological sign",
|
|
40
|
-
parameters: horoscopeSchema
|
|
41
|
-
}
|
|
42
|
-
];
|
|
43
|
-
const dateTools = [
|
|
44
|
-
{
|
|
45
|
-
name: 'get_date',
|
|
46
|
-
description: "Get today's date",
|
|
47
|
-
parameters: dateSchema
|
|
48
|
-
}
|
|
49
|
-
];
|
|
50
|
-
function executeToolCall(call) {
|
|
51
|
-
if (call.name === 'get_weather') {
|
|
52
|
-
const args = call.arguments;
|
|
53
|
-
return `The weather in ${args.city} is rainy, 8°C with heavy clouds.`;
|
|
54
|
-
}
|
|
55
|
-
if (call.name === 'get_horoscope') {
|
|
56
|
-
const args = call.arguments;
|
|
57
|
-
return `Horoscope for ${args.sign}: a great day for new beginnings.`;
|
|
58
|
-
}
|
|
59
|
-
if (call.name === 'get_date') {
|
|
60
|
-
return new Date().toISOString().slice(0, 10);
|
|
61
|
-
}
|
|
62
|
-
return `Unknown tool: ${call.name}`;
|
|
63
|
-
}
|
|
64
|
-
async function chatTurn({ modelId, kvCache, history, tools }) {
|
|
65
|
-
const result = completion({
|
|
66
|
-
modelId,
|
|
67
|
-
history,
|
|
68
|
-
tools,
|
|
69
|
-
kvCache,
|
|
70
|
-
stream: true
|
|
71
|
-
});
|
|
72
|
-
const tokensTask = (async () => {
|
|
73
|
-
for await (const token of result.tokenStream) {
|
|
74
|
-
process.stdout.write(token);
|
|
75
|
-
}
|
|
76
|
-
})();
|
|
77
|
-
const toolEventsTask = (async () => {
|
|
78
|
-
for await (const evt of result.toolCallStream) {
|
|
79
|
-
console.log(`\n▸ tool call: ${evt.call.name}(${JSON.stringify(evt.call.arguments)})`);
|
|
80
|
-
}
|
|
81
|
-
})();
|
|
82
|
-
await Promise.all([tokensTask, toolEventsTask]);
|
|
83
|
-
const text = await result.text;
|
|
84
|
-
const toolCalls = await result.toolCalls;
|
|
85
|
-
if (toolCalls.length === 0) {
|
|
86
|
-
history.push({ role: 'assistant', content: text });
|
|
87
|
-
return;
|
|
88
|
-
}
|
|
89
|
-
for (const call of toolCalls) {
|
|
90
|
-
const schema = toolSchemas[call.name];
|
|
91
|
-
if (schema) {
|
|
92
|
-
const parsed = schema.safeParse(call.arguments);
|
|
93
|
-
if (!parsed.success) {
|
|
94
|
-
console.log(`✖ validation failed for ${call.name}:`, parsed.error);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
history.push({ role: 'assistant', content: text });
|
|
99
|
-
for (const call of toolCalls) {
|
|
100
|
-
history.push({ role: 'tool', content: executeToolCall(call) });
|
|
101
|
-
}
|
|
102
|
-
// Follow-up turn so the model can incorporate the tool results.
|
|
103
|
-
await chatTurn({ modelId, kvCache, history, tools });
|
|
104
|
-
}
|
|
105
|
-
async function main() {
|
|
106
|
-
const modelId = await loadModel({
|
|
107
|
-
modelSrc: QWEN3_1_7B_INST_Q4,
|
|
108
|
-
modelConfig: {
|
|
109
|
-
ctx_size: 4096,
|
|
110
|
-
tools: true,
|
|
111
|
-
toolsMode: 'dynamic'
|
|
112
|
-
},
|
|
113
|
-
onProgress: (p) => {
|
|
114
|
-
const mb = (n) => (n / 1e6).toFixed(1);
|
|
115
|
-
const line = `▸ Downloading ${p.percentage.toFixed(0)}% (${mb(p.downloaded)}/${mb(p.total)} MB)`;
|
|
116
|
-
process.stderr.write(process.stderr.isTTY ? `\r${line}` : `${line}\n`);
|
|
117
|
-
if (p.percentage >= 100)
|
|
118
|
-
process.stderr.write('\n');
|
|
119
|
-
}
|
|
120
|
-
});
|
|
121
|
-
console.log(`▸ Model loaded: ${modelId}`);
|
|
122
|
-
const kvCache = `dynamic-tools-${Date.now()}`;
|
|
123
|
-
const history = [
|
|
124
|
-
{
|
|
125
|
-
role: 'system',
|
|
126
|
-
content: 'You are a helpful assistant that uses tools when they are available. ' +
|
|
127
|
-
"User's cat is named Windy and dog is named Butch."
|
|
128
|
-
}
|
|
129
|
-
];
|
|
130
|
-
// Turn 1 — only weather tools available.
|
|
131
|
-
history.push({ role: 'user', content: "What's the weather in Tokyo?" });
|
|
132
|
-
console.log('\n▸ Turn 1 (tools=weather):\n');
|
|
133
|
-
await chatTurn({ modelId, kvCache, history, tools: weatherTools });
|
|
134
|
-
// Turn 2 — same session, swap to horoscope tools. Dynamic mode lets the
|
|
135
|
-
// model see a different tool set without invalidating the kv-cache.
|
|
136
|
-
history.push({
|
|
137
|
-
role: 'user',
|
|
138
|
-
content: 'Now check my horoscope for Aquarius.'
|
|
139
|
-
});
|
|
140
|
-
console.log('\n\n▸ Turn 2 (tools=horoscope):\n');
|
|
141
|
-
await chatTurn({ modelId, kvCache, history, tools: horoscopeTools });
|
|
142
|
-
// Turn 3 — swap to a parameterless tool to confirm empty-arg flows work.
|
|
143
|
-
history.push({ role: 'user', content: "What's today's date?" });
|
|
144
|
-
console.log('\n\n▸ Turn 3 (tools=date):\n');
|
|
145
|
-
await chatTurn({ modelId, kvCache, history, tools: dateTools });
|
|
146
|
-
console.log('\n\n▸ Done.');
|
|
147
|
-
await unloadModel({ modelId, clearStorage: false });
|
|
148
|
-
}
|
|
149
|
-
main().catch((err) => {
|
|
150
|
-
console.error('✖', err);
|
|
151
|
-
process.exit(1);
|
|
152
|
-
});
|
|
@@ -1,196 +0,0 @@
|
|
|
1
|
-
import { generateExportName } from './naming.js';
|
|
2
|
-
export function generateModelsFileContent(models) {
|
|
3
|
-
const usedNames = new Set();
|
|
4
|
-
const named = new Map();
|
|
5
|
-
const exportable = models.filter((m) => !m.isCompanionOnly);
|
|
6
|
-
const companionOnly = models.filter((m) => m.isCompanionOnly);
|
|
7
|
-
for (const m of exportable) {
|
|
8
|
-
named.set(m, assignName(m, usedNames));
|
|
9
|
-
}
|
|
10
|
-
for (const m of companionOnly) {
|
|
11
|
-
named.set(m, assignName(m, usedNames));
|
|
12
|
-
}
|
|
13
|
-
const modelsWithNames = models.map((m) => ({
|
|
14
|
-
...m,
|
|
15
|
-
name: named.get(m)
|
|
16
|
-
}));
|
|
17
|
-
return generateFileContentWithNames(modelsWithNames);
|
|
18
|
-
}
|
|
19
|
-
function assignName(m, usedNames) {
|
|
20
|
-
return generateExportName({
|
|
21
|
-
path: m.registryPath,
|
|
22
|
-
engine: m.engine,
|
|
23
|
-
name: m.modelName,
|
|
24
|
-
quantization: m.quantization,
|
|
25
|
-
params: m.params,
|
|
26
|
-
tags: m.tags,
|
|
27
|
-
usedNames
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
function generateFileContentWithNames(modelsWithNames) {
|
|
31
|
-
const entries = modelsWithNames
|
|
32
|
-
.map((m) => {
|
|
33
|
-
const addonAlias = m.addon;
|
|
34
|
-
let entry = ` {
|
|
35
|
-
name: "${m.name}",
|
|
36
|
-
registryPath: "${m.registryPath}",
|
|
37
|
-
registrySource: "${m.registrySource}",
|
|
38
|
-
blobCoreKey: "${m.blobCoreKey}",
|
|
39
|
-
blobBlockOffset: ${m.blobBlockOffset},
|
|
40
|
-
blobBlockLength: ${m.blobBlockLength},
|
|
41
|
-
blobByteOffset: ${m.blobByteOffset},
|
|
42
|
-
modelId: "${m.modelId}",
|
|
43
|
-
addon: "${addonAlias}",
|
|
44
|
-
expectedSize: ${m.expectedSize},
|
|
45
|
-
sha256Checksum: "${m.sha256Checksum}",
|
|
46
|
-
engine: "${m.engine}",
|
|
47
|
-
quantization: "${m.quantization || ''}",
|
|
48
|
-
params: "${m.params || ''}"`;
|
|
49
|
-
if (m.shardMetadata) {
|
|
50
|
-
entry += `,\n shardMetadata: ${JSON.stringify(m.shardMetadata)}`;
|
|
51
|
-
}
|
|
52
|
-
if (m.companionSet) {
|
|
53
|
-
entry += `,\n companionSet: ${JSON.stringify(m.companionSet)}`;
|
|
54
|
-
}
|
|
55
|
-
entry += '\n }';
|
|
56
|
-
return entry;
|
|
57
|
-
})
|
|
58
|
-
.join(',\n');
|
|
59
|
-
const exports = modelsWithNames
|
|
60
|
-
.filter((m) => !m.isCompanionOnly)
|
|
61
|
-
.map((m) => {
|
|
62
|
-
const i = modelsWithNames.indexOf(m);
|
|
63
|
-
return `export const ${m.name} = {
|
|
64
|
-
name: "${m.name}",
|
|
65
|
-
src: \`registry://\${models[${i}].registrySource}/\${models[${i}].registryPath}\`,
|
|
66
|
-
registryPath: models[${i}].registryPath,
|
|
67
|
-
registrySource: models[${i}].registrySource,
|
|
68
|
-
blobCoreKey: models[${i}].blobCoreKey,
|
|
69
|
-
blobBlockOffset: models[${i}].blobBlockOffset,
|
|
70
|
-
blobBlockLength: models[${i}].blobBlockLength,
|
|
71
|
-
blobByteOffset: models[${i}].blobByteOffset,
|
|
72
|
-
modelId: models[${i}].modelId,
|
|
73
|
-
expectedSize: models[${i}].expectedSize,
|
|
74
|
-
sha256Checksum: models[${i}].sha256Checksum,
|
|
75
|
-
addon: models[${i}].addon,
|
|
76
|
-
engine: models[${i}].engine,
|
|
77
|
-
quantization: models[${i}].quantization,
|
|
78
|
-
params: models[${i}].params,
|
|
79
|
-
} as const;`;
|
|
80
|
-
})
|
|
81
|
-
.join('\n\n');
|
|
82
|
-
return `// THIS FILE IS AUTO-GENERATED BY models/update-models
|
|
83
|
-
// DO NOT MODIFY MANUALLY
|
|
84
|
-
|
|
85
|
-
import type {
|
|
86
|
-
ModelRegistryEngine,
|
|
87
|
-
ModelRegistryEntryAddon,
|
|
88
|
-
} from "../../schemas/registry.js";
|
|
89
|
-
import type { ENGINE_TO_ADDON } from "../../schemas/engine-addon-map.js";
|
|
90
|
-
|
|
91
|
-
type AddonOfEngine<E extends ModelRegistryEngine> = (typeof ENGINE_TO_ADDON)[E];
|
|
92
|
-
|
|
93
|
-
export type RegistryItem = {
|
|
94
|
-
name: string;
|
|
95
|
-
registryPath: string;
|
|
96
|
-
registrySource: string;
|
|
97
|
-
blobCoreKey: string;
|
|
98
|
-
blobBlockOffset: number;
|
|
99
|
-
blobBlockLength: number;
|
|
100
|
-
blobByteOffset: number;
|
|
101
|
-
modelId: string;
|
|
102
|
-
addon: ModelRegistryEntryAddon;
|
|
103
|
-
expectedSize: number;
|
|
104
|
-
sha256Checksum: string;
|
|
105
|
-
engine: ModelRegistryEngine;
|
|
106
|
-
quantization: string;
|
|
107
|
-
params: string;
|
|
108
|
-
shardMetadata?: readonly {
|
|
109
|
-
filename: string;
|
|
110
|
-
expectedSize: number;
|
|
111
|
-
sha256Checksum: string;
|
|
112
|
-
blobCoreKey: string;
|
|
113
|
-
blobBlockOffset: number;
|
|
114
|
-
blobBlockLength: number;
|
|
115
|
-
blobByteOffset: number;
|
|
116
|
-
}[];
|
|
117
|
-
companionSet?: {
|
|
118
|
-
setKey: string;
|
|
119
|
-
primaryKey: string;
|
|
120
|
-
files: readonly {
|
|
121
|
-
key: string;
|
|
122
|
-
registryPath: string;
|
|
123
|
-
registrySource: string;
|
|
124
|
-
targetName: string;
|
|
125
|
-
expectedSize: number;
|
|
126
|
-
sha256Checksum: string;
|
|
127
|
-
blobCoreKey: string;
|
|
128
|
-
blobBlockOffset: number;
|
|
129
|
-
blobBlockLength: number;
|
|
130
|
-
blobByteOffset: number;
|
|
131
|
-
primary?: boolean;
|
|
132
|
-
}[];
|
|
133
|
-
};
|
|
134
|
-
};
|
|
135
|
-
|
|
136
|
-
/** Generic so callers can preserve per-constant literals: \`ModelConstant<"llamacpp-completion">\`. */
|
|
137
|
-
export type ModelConstant<
|
|
138
|
-
TEngine extends ModelRegistryEngine = ModelRegistryEngine,
|
|
139
|
-
> = {
|
|
140
|
-
name: string;
|
|
141
|
-
src: string;
|
|
142
|
-
registryPath: string;
|
|
143
|
-
registrySource: string;
|
|
144
|
-
blobCoreKey: string;
|
|
145
|
-
blobBlockOffset: number;
|
|
146
|
-
blobBlockLength: number;
|
|
147
|
-
blobByteOffset: number;
|
|
148
|
-
modelId: string;
|
|
149
|
-
expectedSize: number;
|
|
150
|
-
sha256Checksum: string;
|
|
151
|
-
addon: AddonOfEngine<TEngine>;
|
|
152
|
-
engine: TEngine;
|
|
153
|
-
quantization: string;
|
|
154
|
-
params: string;
|
|
155
|
-
};
|
|
156
|
-
|
|
157
|
-
export const models = [
|
|
158
|
-
${entries}
|
|
159
|
-
] as const satisfies readonly RegistryItem[];
|
|
160
|
-
|
|
161
|
-
// Individual model constants for direct import/use with loadModel
|
|
162
|
-
// These contain all metadata and can be used directly: loadModel({ modelSrc: WHISPER_TINY, ... })
|
|
163
|
-
${exports}
|
|
164
|
-
|
|
165
|
-
/**
|
|
166
|
-
* Looks up a model in the built-in catalog by its constant name.
|
|
167
|
-
*
|
|
168
|
-
* @param name - The model constant name (e.g. \`"WHISPER_TINY"\`) to look up.
|
|
169
|
-
* @returns The matching \`RegistryItem\`, or \`undefined\` when no catalog entry has that name.
|
|
170
|
-
*/
|
|
171
|
-
export function getModelByName(name: string): RegistryItem | undefined {
|
|
172
|
-
return models.find((model) => model.name === name);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
/**
|
|
176
|
-
* Looks up a model in the built-in catalog by its registry path.
|
|
177
|
-
*
|
|
178
|
-
* @param registryPath - Registry-relative path of the model to look up.
|
|
179
|
-
* @returns The matching \`RegistryItem\`, or \`undefined\` when no catalog entry has that registry path.
|
|
180
|
-
*/
|
|
181
|
-
export function getModelByPath(registryPath: string): RegistryItem | undefined {
|
|
182
|
-
return models.find((model) => model.registryPath === registryPath);
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* Looks up a model in the built-in catalog by model file ID and blob core key.
|
|
187
|
-
*
|
|
188
|
-
* @param modelId - The model file ID to match against the catalog.
|
|
189
|
-
* @param blobCoreKey - The Hyperdrive blob core key to match against the catalog.
|
|
190
|
-
* @returns The matching \`RegistryItem\`, or \`undefined\` when no catalog entry has both the given \`modelId\` and \`blobCoreKey\`.
|
|
191
|
-
*/
|
|
192
|
-
export function getModelBySrc(modelId: string, blobCoreKey: string): RegistryItem | undefined {
|
|
193
|
-
return models.find((model) => model.modelId === modelId && model.blobCoreKey === blobCoreKey);
|
|
194
|
-
}
|
|
195
|
-
`;
|
|
196
|
-
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import type { ProcessedModel } from './types.js';
|
|
2
|
-
/**
|
|
3
|
-
* Detects companion file relationships among processed models and
|
|
4
|
-
* attaches `companionSet` metadata to each primary entry.
|
|
5
|
-
* Companion-only entries are marked with `isCompanionOnly` so
|
|
6
|
-
* codegen can exclude them from exported model constants.
|
|
7
|
-
*
|
|
8
|
-
* Detection families:
|
|
9
|
-
* ONNX pairs:
|
|
10
|
-
* Primary: registryPath ends with `.onnx`
|
|
11
|
-
* Companion: `${primaryPath}_data` or `${primaryPath}.data`
|
|
12
|
-
*
|
|
13
|
-
* Bergamot NMT sets (directory-based):
|
|
14
|
-
* Primary: `model.<langPair>.intgemm.alphas.bin`
|
|
15
|
-
* Companions in same directory: lex, vocab/srcvocab+trgvocab, metadata
|
|
16
|
-
*
|
|
17
|
-
* BCI whisper.cpp sets (directory-based):
|
|
18
|
-
* Primary: `ggml-bci-windowed.bin`
|
|
19
|
-
* Companion in same directory: `bci-embedder.bin`
|
|
20
|
-
* The addon resolves the embedder by exact filename next to the model
|
|
21
|
-
* (`dirname(model)/bci-embedder.bin`), so the two files must be
|
|
22
|
-
* physically co-located — which the companion-set cache layout guarantees.
|
|
23
|
-
*
|
|
24
|
-
* Chatterbox MeCab/IPAdic sets (directory-based):
|
|
25
|
-
* Primary: `char.bin`
|
|
26
|
-
* Companions in same directory: dicrc, matrix.bin, mecabrc, sys.dic, unk.dic
|
|
27
|
-
* The TTS addon receives the containing directory for Japanese tokenization.
|
|
28
|
-
*/
|
|
29
|
-
export declare function groupCompanionSets(models: ProcessedModel[]): ProcessedModel[];
|
|
30
|
-
//# sourceMappingURL=companions.d.ts.map
|
|
@@ -1,296 +0,0 @@
|
|
|
1
|
-
import { createHash } from 'crypto';
|
|
2
|
-
import { BERGAMOT_MODEL_RE } from '../../schemas/index.js';
|
|
3
|
-
/**
|
|
4
|
-
* Detects companion file relationships among processed models and
|
|
5
|
-
* attaches `companionSet` metadata to each primary entry.
|
|
6
|
-
* Companion-only entries are marked with `isCompanionOnly` so
|
|
7
|
-
* codegen can exclude them from exported model constants.
|
|
8
|
-
*
|
|
9
|
-
* Detection families:
|
|
10
|
-
* ONNX pairs:
|
|
11
|
-
* Primary: registryPath ends with `.onnx`
|
|
12
|
-
* Companion: `${primaryPath}_data` or `${primaryPath}.data`
|
|
13
|
-
*
|
|
14
|
-
* Bergamot NMT sets (directory-based):
|
|
15
|
-
* Primary: `model.<langPair>.intgemm.alphas.bin`
|
|
16
|
-
* Companions in same directory: lex, vocab/srcvocab+trgvocab, metadata
|
|
17
|
-
*
|
|
18
|
-
* BCI whisper.cpp sets (directory-based):
|
|
19
|
-
* Primary: `ggml-bci-windowed.bin`
|
|
20
|
-
* Companion in same directory: `bci-embedder.bin`
|
|
21
|
-
* The addon resolves the embedder by exact filename next to the model
|
|
22
|
-
* (`dirname(model)/bci-embedder.bin`), so the two files must be
|
|
23
|
-
* physically co-located — which the companion-set cache layout guarantees.
|
|
24
|
-
*
|
|
25
|
-
* Chatterbox MeCab/IPAdic sets (directory-based):
|
|
26
|
-
* Primary: `char.bin`
|
|
27
|
-
* Companions in same directory: dicrc, matrix.bin, mecabrc, sys.dic, unk.dic
|
|
28
|
-
* The TTS addon receives the containing directory for Japanese tokenization.
|
|
29
|
-
*/
|
|
30
|
-
export function groupCompanionSets(models) {
|
|
31
|
-
const bySourcePath = new Map();
|
|
32
|
-
for (const model of models) {
|
|
33
|
-
bySourcePath.set(sourceKey(model.registrySource, model.registryPath), model);
|
|
34
|
-
}
|
|
35
|
-
const companionKeys = new Set();
|
|
36
|
-
groupOnnxCompanions(models, bySourcePath, companionKeys);
|
|
37
|
-
groupBergamotCompanions(models, bySourcePath, companionKeys);
|
|
38
|
-
groupBciCompanions(models, bySourcePath, companionKeys);
|
|
39
|
-
groupMecabCompanions(models, bySourcePath, companionKeys);
|
|
40
|
-
return models.map((model) => {
|
|
41
|
-
const key = sourceKey(model.registrySource, model.registryPath);
|
|
42
|
-
if (companionKeys.has(key)) {
|
|
43
|
-
return { ...model, isCompanionOnly: true };
|
|
44
|
-
}
|
|
45
|
-
return model;
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
function groupOnnxCompanions(models, bySourcePath, companionKeys) {
|
|
49
|
-
for (const model of models) {
|
|
50
|
-
if (!model.registryPath.endsWith('.onnx'))
|
|
51
|
-
continue;
|
|
52
|
-
const dataKey = findOnnxCompanionKey(model.registrySource, model.registryPath, bySourcePath);
|
|
53
|
-
if (!dataKey)
|
|
54
|
-
continue;
|
|
55
|
-
const companion = bySourcePath.get(dataKey);
|
|
56
|
-
const primaryFilename = model.registryPath.split('/').pop() || model.registryPath;
|
|
57
|
-
const dataFilename = companion.registryPath.split('/').pop() || companion.registryPath;
|
|
58
|
-
const setKey = shortHash(`${model.registrySource}:${model.registryPath}`);
|
|
59
|
-
const primaryEntry = {
|
|
60
|
-
key: 'modelPath',
|
|
61
|
-
registryPath: model.registryPath,
|
|
62
|
-
registrySource: model.registrySource,
|
|
63
|
-
targetName: primaryFilename,
|
|
64
|
-
expectedSize: model.expectedSize,
|
|
65
|
-
sha256Checksum: model.sha256Checksum,
|
|
66
|
-
blobCoreKey: model.blobCoreKey,
|
|
67
|
-
blobBlockOffset: model.blobBlockOffset,
|
|
68
|
-
blobBlockLength: model.blobBlockLength,
|
|
69
|
-
blobByteOffset: model.blobByteOffset,
|
|
70
|
-
primary: true
|
|
71
|
-
};
|
|
72
|
-
const dataEntry = {
|
|
73
|
-
key: 'dataPath',
|
|
74
|
-
registryPath: companion.registryPath,
|
|
75
|
-
registrySource: companion.registrySource,
|
|
76
|
-
targetName: dataFilename,
|
|
77
|
-
expectedSize: companion.expectedSize,
|
|
78
|
-
sha256Checksum: companion.sha256Checksum,
|
|
79
|
-
blobCoreKey: companion.blobCoreKey,
|
|
80
|
-
blobBlockOffset: companion.blobBlockOffset,
|
|
81
|
-
blobBlockLength: companion.blobBlockLength,
|
|
82
|
-
blobByteOffset: companion.blobByteOffset
|
|
83
|
-
};
|
|
84
|
-
const companionSetMetadata = {
|
|
85
|
-
setKey,
|
|
86
|
-
primaryKey: 'modelPath',
|
|
87
|
-
files: [primaryEntry, dataEntry]
|
|
88
|
-
};
|
|
89
|
-
model.companionSet = companionSetMetadata;
|
|
90
|
-
companionKeys.add(dataKey);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
function groupBergamotCompanions(models, bySourcePath, companionKeys) {
|
|
94
|
-
for (const model of models) {
|
|
95
|
-
const match = model.registryPath.match(BERGAMOT_MODEL_RE);
|
|
96
|
-
if (!match?.[1] || !match[2])
|
|
97
|
-
continue;
|
|
98
|
-
const dirPrefix = match[1];
|
|
99
|
-
const langPair = match[2];
|
|
100
|
-
const source = model.registrySource;
|
|
101
|
-
const companions = findBergamotCompanions(source, dirPrefix, langPair, bySourcePath);
|
|
102
|
-
if (companions.length === 0)
|
|
103
|
-
continue;
|
|
104
|
-
const primaryFilename = model.registryPath.split('/').pop();
|
|
105
|
-
const setKey = shortHash(`${source}:${model.registryPath}`);
|
|
106
|
-
const primaryEntry = {
|
|
107
|
-
key: 'modelPath',
|
|
108
|
-
registryPath: model.registryPath,
|
|
109
|
-
registrySource: source,
|
|
110
|
-
targetName: primaryFilename,
|
|
111
|
-
expectedSize: model.expectedSize,
|
|
112
|
-
sha256Checksum: model.sha256Checksum,
|
|
113
|
-
blobCoreKey: model.blobCoreKey,
|
|
114
|
-
blobBlockOffset: model.blobBlockOffset,
|
|
115
|
-
blobBlockLength: model.blobBlockLength,
|
|
116
|
-
blobByteOffset: model.blobByteOffset,
|
|
117
|
-
primary: true
|
|
118
|
-
};
|
|
119
|
-
const companionEntries = [];
|
|
120
|
-
for (const { key: entryKey, model: comp } of companions) {
|
|
121
|
-
const filename = comp.registryPath.split('/').pop();
|
|
122
|
-
companionEntries.push({
|
|
123
|
-
key: entryKey,
|
|
124
|
-
registryPath: comp.registryPath,
|
|
125
|
-
registrySource: comp.registrySource,
|
|
126
|
-
targetName: filename,
|
|
127
|
-
expectedSize: comp.expectedSize,
|
|
128
|
-
sha256Checksum: comp.sha256Checksum,
|
|
129
|
-
blobCoreKey: comp.blobCoreKey,
|
|
130
|
-
blobBlockOffset: comp.blobBlockOffset,
|
|
131
|
-
blobBlockLength: comp.blobBlockLength,
|
|
132
|
-
blobByteOffset: comp.blobByteOffset
|
|
133
|
-
});
|
|
134
|
-
companionKeys.add(sourceKey(comp.registrySource, comp.registryPath));
|
|
135
|
-
}
|
|
136
|
-
model.companionSet = {
|
|
137
|
-
setKey,
|
|
138
|
-
primaryKey: 'modelPath',
|
|
139
|
-
files: [primaryEntry, ...companionEntries]
|
|
140
|
-
};
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
const BCI_PRIMARY_FILENAME = 'ggml-bci-windowed.bin';
|
|
144
|
-
const BCI_EMBEDDER_FILENAME = 'bci-embedder.bin';
|
|
145
|
-
function groupBciCompanions(models, bySourcePath, companionKeys) {
|
|
146
|
-
for (const model of models) {
|
|
147
|
-
const filename = model.registryPath.split('/').pop();
|
|
148
|
-
if (filename !== BCI_PRIMARY_FILENAME)
|
|
149
|
-
continue;
|
|
150
|
-
const lastSep = model.registryPath.lastIndexOf('/');
|
|
151
|
-
const dirPrefix = lastSep >= 0 ? model.registryPath.slice(0, lastSep + 1) : '';
|
|
152
|
-
const source = model.registrySource;
|
|
153
|
-
const embedderPath = `${dirPrefix}${BCI_EMBEDDER_FILENAME}`;
|
|
154
|
-
const embedder = bySourcePath.get(sourceKey(source, embedderPath));
|
|
155
|
-
if (!embedder)
|
|
156
|
-
continue;
|
|
157
|
-
const setKey = shortHash(`${source}:${model.registryPath}`);
|
|
158
|
-
const primaryEntry = {
|
|
159
|
-
key: 'modelPath',
|
|
160
|
-
registryPath: model.registryPath,
|
|
161
|
-
registrySource: source,
|
|
162
|
-
targetName: BCI_PRIMARY_FILENAME,
|
|
163
|
-
expectedSize: model.expectedSize,
|
|
164
|
-
sha256Checksum: model.sha256Checksum,
|
|
165
|
-
blobCoreKey: model.blobCoreKey,
|
|
166
|
-
blobBlockOffset: model.blobBlockOffset,
|
|
167
|
-
blobBlockLength: model.blobBlockLength,
|
|
168
|
-
blobByteOffset: model.blobByteOffset,
|
|
169
|
-
primary: true
|
|
170
|
-
};
|
|
171
|
-
const embedderEntry = {
|
|
172
|
-
key: 'embedderPath',
|
|
173
|
-
registryPath: embedder.registryPath,
|
|
174
|
-
registrySource: embedder.registrySource,
|
|
175
|
-
targetName: BCI_EMBEDDER_FILENAME,
|
|
176
|
-
expectedSize: embedder.expectedSize,
|
|
177
|
-
sha256Checksum: embedder.sha256Checksum,
|
|
178
|
-
blobCoreKey: embedder.blobCoreKey,
|
|
179
|
-
blobBlockOffset: embedder.blobBlockOffset,
|
|
180
|
-
blobBlockLength: embedder.blobBlockLength,
|
|
181
|
-
blobByteOffset: embedder.blobByteOffset
|
|
182
|
-
};
|
|
183
|
-
model.companionSet = {
|
|
184
|
-
setKey,
|
|
185
|
-
primaryKey: 'modelPath',
|
|
186
|
-
files: [primaryEntry, embedderEntry]
|
|
187
|
-
};
|
|
188
|
-
companionKeys.add(sourceKey(embedder.registrySource, embedder.registryPath));
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
const MECAB_PRIMARY_FILENAME = 'char.bin';
|
|
192
|
-
const MECAB_REQUIRED_FILENAMES = ['dicrc', 'matrix.bin', 'mecabrc', 'sys.dic', 'unk.dic'];
|
|
193
|
-
const MECAB_IPADIC_DIR_SUFFIX = '/mecab-ipadic/';
|
|
194
|
-
function groupMecabCompanions(models, bySourcePath, companionKeys) {
|
|
195
|
-
for (const model of models) {
|
|
196
|
-
if (!model.registryPath.includes(MECAB_IPADIC_DIR_SUFFIX))
|
|
197
|
-
continue;
|
|
198
|
-
const lastSep = model.registryPath.lastIndexOf('/');
|
|
199
|
-
const filename = lastSep >= 0 ? model.registryPath.slice(lastSep + 1) : model.registryPath;
|
|
200
|
-
if (filename !== MECAB_PRIMARY_FILENAME)
|
|
201
|
-
continue;
|
|
202
|
-
const dirPrefix = lastSep >= 0 ? model.registryPath.slice(0, lastSep + 1) : '';
|
|
203
|
-
const source = model.registrySource;
|
|
204
|
-
const companions = findMecabCompanions(source, dirPrefix, bySourcePath);
|
|
205
|
-
if (companions.length !== MECAB_REQUIRED_FILENAMES.length)
|
|
206
|
-
continue;
|
|
207
|
-
const setKey = shortHash(`${source}:${dirPrefix}`);
|
|
208
|
-
const primaryEntry = {
|
|
209
|
-
key: 'mecabDictPath',
|
|
210
|
-
registryPath: model.registryPath,
|
|
211
|
-
registrySource: source,
|
|
212
|
-
targetName: MECAB_PRIMARY_FILENAME,
|
|
213
|
-
expectedSize: model.expectedSize,
|
|
214
|
-
sha256Checksum: model.sha256Checksum,
|
|
215
|
-
blobCoreKey: model.blobCoreKey,
|
|
216
|
-
blobBlockOffset: model.blobBlockOffset,
|
|
217
|
-
blobBlockLength: model.blobBlockLength,
|
|
218
|
-
blobByteOffset: model.blobByteOffset,
|
|
219
|
-
primary: true
|
|
220
|
-
};
|
|
221
|
-
const companionEntries = companions.map(({ filename, model: comp }) => {
|
|
222
|
-
companionKeys.add(sourceKey(comp.registrySource, comp.registryPath));
|
|
223
|
-
return {
|
|
224
|
-
key: `mecab:${filename}`,
|
|
225
|
-
registryPath: comp.registryPath,
|
|
226
|
-
registrySource: comp.registrySource,
|
|
227
|
-
targetName: filename,
|
|
228
|
-
expectedSize: comp.expectedSize,
|
|
229
|
-
sha256Checksum: comp.sha256Checksum,
|
|
230
|
-
blobCoreKey: comp.blobCoreKey,
|
|
231
|
-
blobBlockOffset: comp.blobBlockOffset,
|
|
232
|
-
blobBlockLength: comp.blobBlockLength,
|
|
233
|
-
blobByteOffset: comp.blobByteOffset
|
|
234
|
-
};
|
|
235
|
-
});
|
|
236
|
-
model.companionSet = {
|
|
237
|
-
setKey,
|
|
238
|
-
primaryKey: 'mecabDictPath',
|
|
239
|
-
files: [primaryEntry, ...companionEntries]
|
|
240
|
-
};
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
function findBergamotCompanions(source, dirPrefix, langPair, bySourcePath) {
|
|
244
|
-
const found = [];
|
|
245
|
-
const lexPath = `${dirPrefix}lex.50.50.${langPair}.s2t.bin`;
|
|
246
|
-
const lexModel = bySourcePath.get(sourceKey(source, lexPath));
|
|
247
|
-
if (lexModel) {
|
|
248
|
-
found.push({ key: 'lexPath', model: lexModel });
|
|
249
|
-
}
|
|
250
|
-
const sharedVocabPath = `${dirPrefix}vocab.${langPair}.spm`;
|
|
251
|
-
const sharedVocab = bySourcePath.get(sourceKey(source, sharedVocabPath));
|
|
252
|
-
if (sharedVocab) {
|
|
253
|
-
found.push({ key: 'sharedVocabPath', model: sharedVocab });
|
|
254
|
-
}
|
|
255
|
-
else {
|
|
256
|
-
const srcVocabPath = `${dirPrefix}srcvocab.${langPair}.spm`;
|
|
257
|
-
const trgVocabPath = `${dirPrefix}trgvocab.${langPair}.spm`;
|
|
258
|
-
const srcVocab = bySourcePath.get(sourceKey(source, srcVocabPath));
|
|
259
|
-
const trgVocab = bySourcePath.get(sourceKey(source, trgVocabPath));
|
|
260
|
-
if (srcVocab && trgVocab) {
|
|
261
|
-
found.push({ key: 'srcVocabPath', model: srcVocab });
|
|
262
|
-
found.push({ key: 'dstVocabPath', model: trgVocab });
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
const metadataPath = `${dirPrefix}metadata.json`;
|
|
266
|
-
const metadata = bySourcePath.get(sourceKey(source, metadataPath));
|
|
267
|
-
if (metadata) {
|
|
268
|
-
found.push({ key: 'metadataPath', model: metadata });
|
|
269
|
-
}
|
|
270
|
-
return found;
|
|
271
|
-
}
|
|
272
|
-
function findMecabCompanions(source, dirPrefix, bySourcePath) {
|
|
273
|
-
const found = [];
|
|
274
|
-
for (const filename of MECAB_REQUIRED_FILENAMES) {
|
|
275
|
-
const model = bySourcePath.get(sourceKey(source, `${dirPrefix}${filename}`));
|
|
276
|
-
if (!model)
|
|
277
|
-
return [];
|
|
278
|
-
found.push({ filename, model });
|
|
279
|
-
}
|
|
280
|
-
return found;
|
|
281
|
-
}
|
|
282
|
-
function sourceKey(source, path) {
|
|
283
|
-
return `${source}:${path}`;
|
|
284
|
-
}
|
|
285
|
-
function findOnnxCompanionKey(source, primaryPath, bySourcePath) {
|
|
286
|
-
const candidates = [`${primaryPath}_data`, `${primaryPath}.data`];
|
|
287
|
-
for (const candidate of candidates) {
|
|
288
|
-
const key = sourceKey(source, candidate);
|
|
289
|
-
if (bySourcePath.has(key))
|
|
290
|
-
return key;
|
|
291
|
-
}
|
|
292
|
-
return undefined;
|
|
293
|
-
}
|
|
294
|
-
function shortHash(input) {
|
|
295
|
-
return createHash('sha256').update(input).digest('hex').substring(0, 16);
|
|
296
|
-
}
|