arcane-os 0.63.0 → 0.65.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/CHANGELOG.md +48 -0
- package/README.md +1 -1
- package/browser-runtime/core/client.mjs +69 -7
- package/docs/guides/native-whisper-openvino.md +334 -0
- package/docs/reference/README.md +6 -0
- package/docs/reference/arcane-ollama.md +1 -1
- package/docs/reference/codex-app-server.md +269 -0
- package/docs/reference/core-client.md +71 -4
- package/docs/reference/core-development.md +157 -0
- package/docs/reference/core-native-packaging.md +48 -6
- package/docs/reference/core-repositories.md +258 -0
- package/docs/reference/inventory/package-api.json +199 -3
- package/docs/reference/inventory/runtime-modules.json +3 -2
- package/docs/reference/local-ai.md +77 -4
- package/docs/reference/local-image-flux.md +1 -1
- package/docs/reference/local-image-generation.md +11 -0
- package/docs/reference/local-image-sdxl.md +139 -0
- package/docs/reference/local-whisper.md +219 -0
- package/docs/reference/mcp-stdio.md +263 -0
- package/docs/reference/native-speech.md +51 -2
- package/docs/reference/runtime-components.md +18 -1
- package/docs/reference/runtime-modules.md +26 -4
- package/docs/reference/sdk-api.md +412 -2
- package/package.json +9 -2
- package/runtime/arcane/components/speech.html +15 -3
- package/runtime/arcane/components/voice-transcription.html +19 -3
- package/runtime/arcane/modules/AI.js +406 -40
- package/runtime/arcane/modules/AIProviderRuntime.js +20 -3
- package/runtime/arcane/modules/AIRuntimeState.js +15 -2
- package/runtime/arcane/modules/ComponentContracts.js +3 -0
- package/runtime/arcane/modules/Ollama.js +1 -1
- package/runtime/arcane/modules/OllamaModelIdentifier.js +13 -0
- package/schemas/arcane-app.schema.json +60 -2
- package/schemas/arcane-package.schema.json +60 -2
- package/src/codex/app-server.mjs +845 -0
- package/src/core/development.mjs +457 -0
- package/src/core/repositories.mjs +375 -0
- package/src/core/services/local-ai.mjs +80 -10
- package/src/core/services/speech.mjs +1 -0
- package/src/dev-server.mjs +3 -2
- package/src/index.mjs +1 -0
- package/src/local-ai/config.mjs +7 -3
- package/src/local-ai/dev.mjs +85 -401
- package/src/local-ai/image-library.mjs +9 -0
- package/src/local-ai/image-models/sdxl.mjs +18 -0
- package/src/local-ai/install.mjs +26 -7
- package/src/local-ai/whisper/build.mjs +48 -0
- package/src/local-ai/whisper/config.mjs +89 -0
- package/src/local-ai/whisper/index.mjs +572 -0
- package/src/local-ai/whisper/install.mjs +332 -0
- package/src/local-ai/whisper/native/CMakeLists.txt +98 -0
- package/src/local-ai/whisper/native/NOTICE +18 -0
- package/src/local-ai/whisper/native/README.md +104 -0
- package/src/local-ai/whisper/native/main.cpp +520 -0
- package/src/local-ai/whisper/openvino-build.mjs +138 -0
- package/src/mcp/stdio-server.mjs +579 -0
- package/src/native/portable-layout.mjs +39 -7
- package/src/toolchain.mjs +19 -8
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import {fileURLToPath} from 'node:url';
|
|
3
|
+
import {mkdir} from 'node:fs/promises';
|
|
4
|
+
import Is from 'strong-type';
|
|
5
|
+
import {runProcess} from '../../process.mjs';
|
|
6
|
+
|
|
7
|
+
const is = new Is(false);
|
|
8
|
+
|
|
9
|
+
/** Build only the persistent first-party helper against an installed runtime. */
|
|
10
|
+
export async function buildWhisperHelper({
|
|
11
|
+
runtime,
|
|
12
|
+
outputRoot,
|
|
13
|
+
cmake = 'cmake',
|
|
14
|
+
generator,
|
|
15
|
+
cmakeArgs = [],
|
|
16
|
+
env,
|
|
17
|
+
signal,
|
|
18
|
+
onEvent
|
|
19
|
+
} = {}) {
|
|
20
|
+
if (!is.string(runtime?.directory) || !is.string(runtime?.sourceDirectory) || !is.string(outputRoot)) {
|
|
21
|
+
throw new TypeError('The selected Whisper runtime directory, matching sourceDirectory, and helper outputRoot are required.');
|
|
22
|
+
}
|
|
23
|
+
const root = path.resolve(outputRoot);
|
|
24
|
+
const build = path.join(root, 'build');
|
|
25
|
+
const source = fileURLToPath(new URL('./native/', import.meta.url));
|
|
26
|
+
await mkdir(root, {recursive: true});
|
|
27
|
+
const options = {env, signal, onEvent};
|
|
28
|
+
const configure = await runProcess(cmake, [
|
|
29
|
+
'-S', source,
|
|
30
|
+
'-B', build,
|
|
31
|
+
...(generator ? ['-G', generator] : []),
|
|
32
|
+
`-DWHISPER_SOURCE_DIRECTORY=${path.resolve(runtime.sourceDirectory)}`,
|
|
33
|
+
`-DWHISPER_RUNTIME_DIRECTORY=${path.resolve(runtime.directory)}`,
|
|
34
|
+
`-DCMAKE_INSTALL_PREFIX=${root}`,
|
|
35
|
+
'-DCMAKE_BUILD_TYPE=Release',
|
|
36
|
+
...cmakeArgs
|
|
37
|
+
], options);
|
|
38
|
+
const compile = await runProcess(cmake, ['--build', build, '--config', 'Release'], options);
|
|
39
|
+
const install = await runProcess(cmake, ['--install', build, '--config', 'Release'], options);
|
|
40
|
+
return {
|
|
41
|
+
platform: process.platform,
|
|
42
|
+
architecture: process.arch,
|
|
43
|
+
root,
|
|
44
|
+
executable: path.join(root, 'bin', process.platform === 'win32' ? 'arcane-whisper.exe' : 'arcane-whisper'),
|
|
45
|
+
runtimeDirectory: path.resolve(runtime.directory),
|
|
46
|
+
diagnostics: {configure, compile, install}
|
|
47
|
+
};
|
|
48
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import Is from 'strong-type';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import {ArcaneError, ERROR_CODES} from '../../errors.mjs';
|
|
4
|
+
|
|
5
|
+
const is = new Is(false);
|
|
6
|
+
|
|
7
|
+
export const WHISPER_SMALL_MODEL = {
|
|
8
|
+
id: 'whisper-small',
|
|
9
|
+
url: 'https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-small.bin',
|
|
10
|
+
filename: 'ggml-small.bin'
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export const WHISPER_SMALL_OPENVINO_MODEL = {
|
|
14
|
+
id: 'whisper-small',
|
|
15
|
+
archiveUrl: 'https://huggingface.co/Intel/whisper.cpp-openvino-models/resolve/main/ggml-small-models.zip',
|
|
16
|
+
filename: 'ggml-small.bin',
|
|
17
|
+
encoderFilename: 'ggml-small-encoder-openvino.xml',
|
|
18
|
+
encoderDataFilename: 'ggml-small-encoder-openvino.bin'
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/** Describe a selected native runtime and models without acquiring them. */
|
|
22
|
+
export function normalizeWhisperRuntimeRequirement(record) {
|
|
23
|
+
if (record.helperRoot !== undefined && (!is.string(record.helperRoot) || !record.helperRoot)) {
|
|
24
|
+
throw new ArcaneError(ERROR_CODES.usage, 'Whisper helperRoot must name the complete selected helper directory.');
|
|
25
|
+
}
|
|
26
|
+
const helperRoot = record.helperRoot ?? (is.string(record.helperExecutable) ? path.dirname(record.helperExecutable) : undefined);
|
|
27
|
+
const backend = record.backend ?? 'auto';
|
|
28
|
+
if (!['auto', 'cuda', 'metal', 'cpu'].includes(backend)) {
|
|
29
|
+
throw new ArcaneError(ERROR_CODES.usage, `Unknown whisper.cpp backend: ${String(backend)}.`);
|
|
30
|
+
}
|
|
31
|
+
if (record.encoder !== undefined && record.encoder !== 'openvino-npu') {
|
|
32
|
+
throw new ArcaneError(ERROR_CODES.usage, `Unknown whisper.cpp encoder: ${String(record.encoder)}.`);
|
|
33
|
+
}
|
|
34
|
+
if (record.models !== undefined && !is.array(record.models)) {
|
|
35
|
+
throw new ArcaneError(ERROR_CODES.usage, 'whisper.cpp models must be an array of selected model IDs or descriptors.');
|
|
36
|
+
}
|
|
37
|
+
const models = (record.models ?? []).map(function selectedWhisperModel(value) {
|
|
38
|
+
const model = value === 'whisper-small'
|
|
39
|
+
? record.encoder === 'openvino-npu' ? WHISPER_SMALL_OPENVINO_MODEL : WHISPER_SMALL_MODEL
|
|
40
|
+
: value;
|
|
41
|
+
if (!model || !is.object(model) || is.array(model) || !is.string(model.id) || !model.id) {
|
|
42
|
+
throw new ArcaneError(ERROR_CODES.usage, 'A Whisper model needs a descriptor with an id, or the built-in whisper-small model ID.');
|
|
43
|
+
}
|
|
44
|
+
if ((!is.string(model.path) || !model.path) && (!is.string(model.url) || !model.url)
|
|
45
|
+
&& (!is.string(model.archiveUrl) || !model.archiveUrl)) {
|
|
46
|
+
throw new ArcaneError(ERROR_CODES.usage, `Whisper model ${model.id} needs its selected path, URL, or model archive URL.`);
|
|
47
|
+
}
|
|
48
|
+
if (!model.path && model.archiveUrl && (!is.string(model.filename) || !model.filename)) {
|
|
49
|
+
throw new ArcaneError(ERROR_CODES.usage, `Whisper model ${model.id} needs its model filename inside the selected archive.`);
|
|
50
|
+
}
|
|
51
|
+
if (record.encoder === 'openvino-npu') {
|
|
52
|
+
const pairedFiles = model.path
|
|
53
|
+
? [model.path, model.encoderPath, model.encoderDataPath]
|
|
54
|
+
: [model.archiveUrl, model.filename, model.encoderFilename, model.encoderDataFilename];
|
|
55
|
+
if (!pairedFiles.every(function selectedEncoderFile(value) { return is.string(value) && value !== ''; })) {
|
|
56
|
+
throw new ArcaneError(ERROR_CODES.usage, `Whisper model ${model.id} needs its matching GGML, OpenVINO XML, and encoder BIN files.`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return {...model};
|
|
60
|
+
});
|
|
61
|
+
if (record.variants !== undefined && (!is.array(record.variants) || record.variants.length === 0)) {
|
|
62
|
+
throw new ArcaneError(ERROR_CODES.usage, 'whisper.cpp variants must be a nonempty array when supplied.');
|
|
63
|
+
}
|
|
64
|
+
const variants = record.variants?.map(function selectedWhisperVariant(variant) {
|
|
65
|
+
if (!variant || !is.object(variant) || is.array(variant) || !['cuda', 'metal', 'cpu'].includes(variant.backend)) {
|
|
66
|
+
throw new ArcaneError(ERROR_CODES.usage, 'Each Whisper runtime variant needs its cuda, metal, or cpu backend.');
|
|
67
|
+
}
|
|
68
|
+
if ((!is.string(variant.root) || !variant.root) && (!is.string(variant.url) || !variant.url)) {
|
|
69
|
+
throw new ArcaneError(ERROR_CODES.usage, `Whisper ${variant.backend} needs its complete runtime root or archive URL.`);
|
|
70
|
+
}
|
|
71
|
+
if (variant.encoder !== undefined && variant.encoder !== 'openvino-npu') {
|
|
72
|
+
throw new ArcaneError(ERROR_CODES.usage, `Unknown Whisper variant encoder: ${String(variant.encoder)}.`);
|
|
73
|
+
}
|
|
74
|
+
return {...variant};
|
|
75
|
+
});
|
|
76
|
+
if (record.modelId !== undefined && (!is.string(record.modelId) || !models.some(function matchingModel(model) {
|
|
77
|
+
return model.id === record.modelId;
|
|
78
|
+
}))) {
|
|
79
|
+
throw new ArcaneError(ERROR_CODES.usage, 'Whisper modelId must name one of the explicitly selected models.');
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
...record,
|
|
83
|
+
version: record.version ?? '1.9.4',
|
|
84
|
+
backend,
|
|
85
|
+
models,
|
|
86
|
+
...(helperRoot === undefined ? {} : {helperRoot}),
|
|
87
|
+
...(variants ? {variants} : {})
|
|
88
|
+
};
|
|
89
|
+
}
|