@remotion/install-whisper-cpp 4.0.155 → 4.0.156
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/dist/download-whisper-model.d.ts +2 -1
- package/dist/download-whisper-model.js +24 -3
- package/dist/download.d.ts +2 -1
- package/dist/download.js +4 -2
- package/dist/index.d.ts +1 -1
- package/dist/install-whisper-cpp.d.ts +2 -1
- package/dist/install-whisper-cpp.js +53 -16
- package/dist/transcribe.d.ts +4 -1
- package/dist/transcribe.js +17 -7
- package/package.json +1 -1
|
@@ -2,9 +2,10 @@ import { type OnProgress } from './download';
|
|
|
2
2
|
declare const models: readonly ["tiny", "tiny.en", "base", "base.en", "small", "small.en", "medium", "medium.en", "large-v1", "large-v2", "large-v3"];
|
|
3
3
|
export type WhisperModel = (typeof models)[number];
|
|
4
4
|
export declare const getModelPath: (folder: string, model: WhisperModel) => string;
|
|
5
|
-
export declare const downloadWhisperModel: ({ model, folder, printOutput, onProgress, }: {
|
|
5
|
+
export declare const downloadWhisperModel: ({ model, folder, printOutput, onProgress, signal, }: {
|
|
6
6
|
model: WhisperModel;
|
|
7
7
|
folder: string;
|
|
8
|
+
signal?: AbortSignal | undefined;
|
|
8
9
|
printOutput?: boolean | undefined;
|
|
9
10
|
onProgress?: OnProgress | undefined;
|
|
10
11
|
}) => Promise<{
|
|
@@ -43,20 +43,40 @@ const models = [
|
|
|
43
43
|
'large-v2',
|
|
44
44
|
'large-v3',
|
|
45
45
|
];
|
|
46
|
+
const modelSizes = {
|
|
47
|
+
'medium.en': 1533774781,
|
|
48
|
+
'base.en': 147964211,
|
|
49
|
+
'large-v1': 3094623691,
|
|
50
|
+
'large-v2': 3094623691,
|
|
51
|
+
'large-v3': 3095033483,
|
|
52
|
+
small: 487601967,
|
|
53
|
+
tiny: 77691713,
|
|
54
|
+
'small.en': 487614201,
|
|
55
|
+
'tiny.en': 77704715,
|
|
56
|
+
base: 147951465,
|
|
57
|
+
medium: 1533774781,
|
|
58
|
+
};
|
|
46
59
|
const getModelPath = (folder, model) => {
|
|
47
60
|
return path_1.default.join(folder, `ggml-${model}.bin`);
|
|
48
61
|
};
|
|
49
62
|
exports.getModelPath = getModelPath;
|
|
50
|
-
const downloadWhisperModel = async ({ model, folder, printOutput = true, onProgress, }) => {
|
|
63
|
+
const downloadWhisperModel = async ({ model, folder, printOutput = true, onProgress, signal, }) => {
|
|
51
64
|
if (!models.includes(model)) {
|
|
52
65
|
throw new Error(`Invalid whisper model ${model}. Available: ${models.join(', ')}`);
|
|
53
66
|
}
|
|
54
67
|
const filePath = (0, exports.getModelPath)(folder, model);
|
|
55
68
|
if ((0, fs_1.existsSync)(filePath)) {
|
|
69
|
+
const { size } = fs_1.default.statSync(filePath);
|
|
70
|
+
if (size === modelSizes[model]) {
|
|
71
|
+
if (printOutput) {
|
|
72
|
+
console.log(`Model already exists at ${filePath}`);
|
|
73
|
+
}
|
|
74
|
+
return Promise.resolve({ alreadyExisted: true });
|
|
75
|
+
}
|
|
56
76
|
if (printOutput) {
|
|
57
|
-
|
|
77
|
+
throw new Error(`Model ${model} already exists at ${filePath}, but the size is ${size} bytes (expected ${modelSizes[model]} bytes). Delete ${filePath} and try again.`);
|
|
58
78
|
}
|
|
59
|
-
return Promise.resolve({ alreadyExisted:
|
|
79
|
+
return Promise.resolve({ alreadyExisted: false });
|
|
60
80
|
}
|
|
61
81
|
const baseModelUrl = `https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-${model}.bin`;
|
|
62
82
|
if (printOutput) {
|
|
@@ -68,6 +88,7 @@ const downloadWhisperModel = async ({ model, folder, printOutput = true, onProgr
|
|
|
68
88
|
url: baseModelUrl,
|
|
69
89
|
printOutput,
|
|
70
90
|
onProgress,
|
|
91
|
+
signal: signal !== null && signal !== void 0 ? signal : null,
|
|
71
92
|
});
|
|
72
93
|
return { alreadyExisted: false };
|
|
73
94
|
};
|
package/dist/download.d.ts
CHANGED
|
@@ -6,9 +6,10 @@
|
|
|
6
6
|
/// <reference types="bun-types" />
|
|
7
7
|
/// <reference types="bun-types" />
|
|
8
8
|
export type OnProgress = (downloadedBytes: number, totalBytes: number) => void;
|
|
9
|
-
export declare const downloadFile: ({ fileStream, url, printOutput, onProgress, }: {
|
|
9
|
+
export declare const downloadFile: ({ fileStream, url, printOutput, onProgress, signal, }: {
|
|
10
10
|
fileStream: NodeJS.WritableStream;
|
|
11
11
|
url: string;
|
|
12
12
|
printOutput: boolean;
|
|
13
13
|
onProgress: OnProgress | undefined;
|
|
14
|
+
signal: AbortSignal | null;
|
|
14
15
|
}) => Promise<void>;
|
package/dist/download.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.downloadFile = void 0;
|
|
4
|
-
const downloadFile = async ({ fileStream, url, printOutput, onProgress, }) => {
|
|
5
|
-
const { body, headers } = await fetch(url
|
|
4
|
+
const downloadFile = async ({ fileStream, url, printOutput, onProgress, signal, }) => {
|
|
5
|
+
const { body, headers } = await fetch(url, {
|
|
6
|
+
signal,
|
|
7
|
+
});
|
|
6
8
|
const contentLength = headers.get('content-length');
|
|
7
9
|
if (body === null) {
|
|
8
10
|
throw new Error('Failed to download whisper model');
|
package/dist/index.d.ts
CHANGED
|
@@ -3,4 +3,4 @@ export type { OnProgress } from './download';
|
|
|
3
3
|
export { WhisperModel, downloadWhisperModel } from './download-whisper-model';
|
|
4
4
|
export { installWhisperCpp } from './install-whisper-cpp';
|
|
5
5
|
export type { Language } from './languages';
|
|
6
|
-
export { TranscriptionJson, transcribe } from './transcribe';
|
|
6
|
+
export { TranscribeOnProgress, TranscriptionJson, transcribe, } from './transcribe';
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
export declare const getWhisperExecutablePath: (whisperPath: string) => string;
|
|
2
|
-
export declare const installWhisperCpp: ({ version, to, printOutput, }: {
|
|
2
|
+
export declare const installWhisperCpp: ({ version, to, printOutput, signal, }: {
|
|
3
3
|
version: string;
|
|
4
4
|
to: string;
|
|
5
|
+
signal?: AbortSignal | null | undefined;
|
|
5
6
|
printOutput?: boolean | undefined;
|
|
6
7
|
}) => Promise<{
|
|
7
8
|
alreadyExisted: boolean;
|
|
@@ -27,15 +27,34 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
27
27
|
};
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
29
|
exports.installWhisperCpp = exports.getWhisperExecutablePath = void 0;
|
|
30
|
+
const child_process_1 = require("child_process");
|
|
30
31
|
const fs_1 = __importStar(require("fs"));
|
|
31
|
-
const node_child_process_1 = require("node:child_process");
|
|
32
32
|
const os_1 = __importDefault(require("os"));
|
|
33
33
|
const path_1 = __importDefault(require("path"));
|
|
34
34
|
const download_1 = require("./download");
|
|
35
35
|
const getIsSemVer = (str) => {
|
|
36
36
|
return /^[\d]{1}\.[\d]{1,2}\.+/.test(str);
|
|
37
37
|
};
|
|
38
|
-
const
|
|
38
|
+
const execute = ({ command, printOutput, signal, cwd, shell, }) => {
|
|
39
|
+
const stdio = printOutput ? 'inherit' : 'ignore';
|
|
40
|
+
return new Promise((resolve, reject) => {
|
|
41
|
+
const [bin, ...args] = command.split(' ');
|
|
42
|
+
const child = (0, child_process_1.spawn)(bin, args, {
|
|
43
|
+
stdio,
|
|
44
|
+
signal: signal !== null && signal !== void 0 ? signal : undefined,
|
|
45
|
+
cwd: cwd !== null && cwd !== void 0 ? cwd : undefined,
|
|
46
|
+
shell: shell !== null && shell !== void 0 ? shell : undefined,
|
|
47
|
+
});
|
|
48
|
+
child.on('exit', (code, exitSignal) => {
|
|
49
|
+
if (code !== 0) {
|
|
50
|
+
reject(new Error(`Error while executing ${command}. Exit code: ${code}, signal: ${exitSignal}`));
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
resolve();
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
};
|
|
57
|
+
const installForWindows = async ({ version, to, printOutput, signal, }) => {
|
|
39
58
|
if (!getIsSemVer(version)) {
|
|
40
59
|
throw new Error(`Non-semantic version provided. Only releases of Whisper.cpp are supported on Windows (e.g., 1.5.4). Provided version:
|
|
41
60
|
${version}. See https://www.remotion.dev/docs/install-whisper-cpp/install-whisper-cpp#version for more information.`);
|
|
@@ -50,26 +69,39 @@ const installForWindows = async ({ version, to, printOutput, }) => {
|
|
|
50
69
|
printOutput,
|
|
51
70
|
url,
|
|
52
71
|
onProgress: undefined,
|
|
72
|
+
signal,
|
|
53
73
|
});
|
|
54
|
-
(
|
|
74
|
+
execute({
|
|
75
|
+
command: `Expand-Archive -Force ${filePath} ${to}`,
|
|
55
76
|
shell: 'powershell',
|
|
56
|
-
|
|
77
|
+
printOutput,
|
|
78
|
+
signal,
|
|
79
|
+
cwd: null,
|
|
57
80
|
});
|
|
58
81
|
(0, fs_1.rmSync)(filePath);
|
|
59
82
|
};
|
|
60
|
-
const installWhisperForUnix = ({ version, to, printOutput, }) => {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
83
|
+
const installWhisperForUnix = async ({ version, to, printOutput, signal, }) => {
|
|
84
|
+
await execute({
|
|
85
|
+
command: `git clone https://github.com/ggerganov/whisper.cpp.git ${to}`,
|
|
86
|
+
printOutput,
|
|
87
|
+
signal,
|
|
88
|
+
cwd: null,
|
|
89
|
+
shell: null,
|
|
64
90
|
});
|
|
65
91
|
const ref = getIsSemVer(version) ? `v${version}` : version;
|
|
66
|
-
|
|
67
|
-
|
|
92
|
+
await execute({
|
|
93
|
+
command: `git checkout ${ref}`,
|
|
94
|
+
printOutput,
|
|
68
95
|
cwd: to,
|
|
96
|
+
signal,
|
|
97
|
+
shell: null,
|
|
69
98
|
});
|
|
70
|
-
|
|
99
|
+
await execute({
|
|
100
|
+
command: 'make',
|
|
71
101
|
cwd: to,
|
|
72
|
-
|
|
102
|
+
signal,
|
|
103
|
+
printOutput,
|
|
104
|
+
shell: null,
|
|
73
105
|
});
|
|
74
106
|
};
|
|
75
107
|
const getWhisperExecutablePath = (whisperPath) => {
|
|
@@ -78,11 +110,11 @@ const getWhisperExecutablePath = (whisperPath) => {
|
|
|
78
110
|
: path_1.default.join(whisperPath, './main');
|
|
79
111
|
};
|
|
80
112
|
exports.getWhisperExecutablePath = getWhisperExecutablePath;
|
|
81
|
-
const installWhisperCpp = async ({ version, to, printOutput = true, }) => {
|
|
113
|
+
const installWhisperCpp = async ({ version, to, printOutput = true, signal, }) => {
|
|
82
114
|
if ((0, fs_1.existsSync)(to)) {
|
|
83
115
|
if (!(0, fs_1.existsSync)((0, exports.getWhisperExecutablePath)(to))) {
|
|
84
116
|
if (printOutput) {
|
|
85
|
-
|
|
117
|
+
throw new Error(`Whisper folder ${to} exists but the executable (${(0, exports.getWhisperExecutablePath)(to)}) is missing. Delete ${to} and try again.`);
|
|
86
118
|
}
|
|
87
119
|
return Promise.resolve({ alreadyExisted: false });
|
|
88
120
|
}
|
|
@@ -92,11 +124,16 @@ const installWhisperCpp = async ({ version, to, printOutput = true, }) => {
|
|
|
92
124
|
return Promise.resolve({ alreadyExisted: true });
|
|
93
125
|
}
|
|
94
126
|
if (process.platform === 'darwin' || process.platform === 'linux') {
|
|
95
|
-
installWhisperForUnix({
|
|
127
|
+
await installWhisperForUnix({
|
|
128
|
+
version,
|
|
129
|
+
to,
|
|
130
|
+
printOutput,
|
|
131
|
+
signal: signal !== null && signal !== void 0 ? signal : null,
|
|
132
|
+
});
|
|
96
133
|
return Promise.resolve({ alreadyExisted: false });
|
|
97
134
|
}
|
|
98
135
|
if (process.platform === 'win32') {
|
|
99
|
-
await installForWindows({ version, to, printOutput });
|
|
136
|
+
await installForWindows({ version, to, printOutput, signal: signal !== null && signal !== void 0 ? signal : null });
|
|
100
137
|
return Promise.resolve({ alreadyExisted: false });
|
|
101
138
|
}
|
|
102
139
|
throw new Error(`Unsupported platform: ${process.platform}`);
|
package/dist/transcribe.d.ts
CHANGED
|
@@ -58,7 +58,8 @@ export type TranscriptionJson<WithTokenLevelTimestamp extends boolean> = {
|
|
|
58
58
|
result: Result;
|
|
59
59
|
transcription: true extends WithTokenLevelTimestamp ? TranscriptionItemWithTimestamp[] : TranscriptionItem[];
|
|
60
60
|
};
|
|
61
|
-
export
|
|
61
|
+
export type TranscribeOnProgress = (progress: number) => void;
|
|
62
|
+
export declare const transcribe: <HasTokenLevelTimestamps extends boolean>({ inputPath, whisperPath, model, modelFolder, translateToEnglish, tokenLevelTimestamps, printOutput, tokensPerItem, language, signal, onProgress, }: {
|
|
62
63
|
inputPath: string;
|
|
63
64
|
whisperPath: string;
|
|
64
65
|
model: WhisperModel;
|
|
@@ -68,5 +69,7 @@ export declare const transcribe: <HasTokenLevelTimestamps extends boolean>({ inp
|
|
|
68
69
|
printOutput?: boolean | undefined;
|
|
69
70
|
tokensPerItem?: (true extends HasTokenLevelTimestamps ? never : number | null) | undefined;
|
|
70
71
|
language?: Language | null | undefined;
|
|
72
|
+
signal?: AbortSignal | undefined;
|
|
73
|
+
onProgress?: TranscribeOnProgress | undefined;
|
|
71
74
|
}) => Promise<TranscriptionJson<HasTokenLevelTimestamps>>;
|
|
72
75
|
export {};
|
package/dist/transcribe.js
CHANGED
|
@@ -43,7 +43,7 @@ const readJson = async (jsonPath) => {
|
|
|
43
43
|
const data = await node_fs_1.default.promises.readFile(jsonPath, 'utf8');
|
|
44
44
|
return JSON.parse(data);
|
|
45
45
|
};
|
|
46
|
-
const
|
|
46
|
+
const transcribeToTemporaryFile = async ({ fileToTranscribe, whisperPath, model, tmpJSONPath, modelFolder, translate, tokenLevelTimestamps, printOutput, tokensPerItem, language, signal, onProgress, }) => {
|
|
47
47
|
const modelPath = (0, download_whisper_model_1.getModelPath)(modelFolder !== null && modelFolder !== void 0 ? modelFolder : whisperPath, model);
|
|
48
48
|
if (!node_fs_1.default.existsSync(modelPath)) {
|
|
49
49
|
throw new Error(`Error: Model ${model} does not exist at ${modelFolder ? modelFolder : modelPath}. Check out the downloadWhisperModel() API at https://www.remotion.dev/docs/install-whisper-cpp/download-whisper-model to see how to install whisper models`);
|
|
@@ -59,6 +59,7 @@ const transcribeToTempJSON = async ({ fileToTranscribe, whisperPath, model, tmpJ
|
|
|
59
59
|
'-ojf', // Output full JSON
|
|
60
60
|
tokenLevelTimestamps ? ['--dtw', model] : null,
|
|
61
61
|
model ? [`-m`, `${modelPath}`] : null,
|
|
62
|
+
['-pp'], // print progress
|
|
62
63
|
translate ? '-tr' : null,
|
|
63
64
|
language ? ['-l', language.toLowerCase()] : null,
|
|
64
65
|
]
|
|
@@ -67,11 +68,17 @@ const transcribeToTempJSON = async ({ fileToTranscribe, whisperPath, model, tmpJ
|
|
|
67
68
|
const outputPath = await new Promise((resolve, reject) => {
|
|
68
69
|
const task = (0, node_child_process_1.spawn)(executable, args, {
|
|
69
70
|
cwd: whisperPath,
|
|
71
|
+
signal: signal !== null && signal !== void 0 ? signal : undefined,
|
|
70
72
|
});
|
|
71
73
|
const predictedPath = `${tmpJSONPath}.json`;
|
|
72
74
|
let output = '';
|
|
73
75
|
const onData = (data) => {
|
|
74
76
|
const str = data.toString('utf-8');
|
|
77
|
+
const hasProgress = str.includes('progress =');
|
|
78
|
+
if (hasProgress) {
|
|
79
|
+
const progress = parseFloat(str.split('progress =')[1].trim());
|
|
80
|
+
onProgress === null || onProgress === void 0 ? void 0 : onProgress(progress / 100);
|
|
81
|
+
}
|
|
75
82
|
output += str;
|
|
76
83
|
// Sometimes it hangs here
|
|
77
84
|
if (str.includes('ggml_metal_free: deallocating')) {
|
|
@@ -92,15 +99,16 @@ const transcribeToTempJSON = async ({ fileToTranscribe, whisperPath, model, tmpJ
|
|
|
92
99
|
};
|
|
93
100
|
task.stdout.on('data', onStdout);
|
|
94
101
|
task.stderr.on('data', onStderr);
|
|
95
|
-
task.on('exit', (code,
|
|
102
|
+
task.on('exit', (code, exitSignal) => {
|
|
96
103
|
// Whisper sometimes files also with error code 0
|
|
97
104
|
// https://github.com/ggerganov/whisper.cpp/pull/1952/files
|
|
98
105
|
if ((0, node_fs_1.existsSync)(predictedPath)) {
|
|
99
106
|
resolve(predictedPath);
|
|
107
|
+
onProgress === null || onProgress === void 0 ? void 0 : onProgress(1);
|
|
100
108
|
return;
|
|
101
109
|
}
|
|
102
|
-
if (
|
|
103
|
-
reject(new Error(`Process was killed with signal ${
|
|
110
|
+
if (exitSignal) {
|
|
111
|
+
reject(new Error(`Process was killed with signal ${exitSignal}: ${output}`));
|
|
104
112
|
return;
|
|
105
113
|
}
|
|
106
114
|
reject(new Error(`No transcription was created (process exited with code ${code}): ${output}`));
|
|
@@ -108,7 +116,7 @@ const transcribeToTempJSON = async ({ fileToTranscribe, whisperPath, model, tmpJ
|
|
|
108
116
|
});
|
|
109
117
|
return { outputPath };
|
|
110
118
|
};
|
|
111
|
-
const transcribe = async ({ inputPath, whisperPath, model, modelFolder, translateToEnglish = false, tokenLevelTimestamps, printOutput = true, tokensPerItem, language, }) => {
|
|
119
|
+
const transcribe = async ({ inputPath, whisperPath, model, modelFolder, translateToEnglish = false, tokenLevelTimestamps, printOutput = true, tokensPerItem, language, signal, onProgress, }) => {
|
|
112
120
|
if (!(0, node_fs_1.existsSync)(whisperPath)) {
|
|
113
121
|
throw new Error(`Whisper does not exist at ${whisperPath}. Double-check the passed whisperPath. If you havent installed whisper, check out the installWhisperCpp() API at https://www.remotion.dev/docs/install-whisper-cpp/install-whisper-cpp to see how to install whisper programatically.`);
|
|
114
122
|
}
|
|
@@ -119,7 +127,7 @@ const transcribe = async ({ inputPath, whisperPath, model, modelFolder, translat
|
|
|
119
127
|
throw new Error('Invalid inputFile type. The provided file is not a wav file!');
|
|
120
128
|
}
|
|
121
129
|
const tmpJSONDir = node_path_1.default.join(process.cwd(), 'tmp');
|
|
122
|
-
const { outputPath: tmpJSONPath } = await
|
|
130
|
+
const { outputPath: tmpJSONPath } = await transcribeToTemporaryFile({
|
|
123
131
|
fileToTranscribe: inputPath,
|
|
124
132
|
whisperPath,
|
|
125
133
|
model,
|
|
@@ -129,7 +137,9 @@ const transcribe = async ({ inputPath, whisperPath, model, modelFolder, translat
|
|
|
129
137
|
tokenLevelTimestamps,
|
|
130
138
|
printOutput,
|
|
131
139
|
tokensPerItem: tokenLevelTimestamps ? 1 : tokensPerItem !== null && tokensPerItem !== void 0 ? tokensPerItem : 1,
|
|
132
|
-
language,
|
|
140
|
+
language: language !== null && language !== void 0 ? language : null,
|
|
141
|
+
signal: signal !== null && signal !== void 0 ? signal : null,
|
|
142
|
+
onProgress: onProgress !== null && onProgress !== void 0 ? onProgress : null,
|
|
133
143
|
});
|
|
134
144
|
const json = (await readJson(tmpJSONPath));
|
|
135
145
|
node_fs_1.default.unlinkSync(tmpJSONPath);
|