@ignix-social/editor 0.1.18 → 0.1.19
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/package.json +1 -1
- package/src/transcribe.mjs +29 -7
package/package.json
CHANGED
package/src/transcribe.mjs
CHANGED
|
@@ -5,19 +5,40 @@
|
|
|
5
5
|
import { spawnSync } from 'node:child_process';
|
|
6
6
|
import { mkdtempSync, readFileSync, rmSync, statSync } from 'node:fs';
|
|
7
7
|
import { tmpdir } from 'node:os';
|
|
8
|
-
import { join } from 'node:path';
|
|
8
|
+
import { basename, dirname, join, relative } from 'node:path';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Dónde trabaja whisper. En Windows, whisper.cpp NO abre rutas con caracteres fuera del ASCII
|
|
12
|
+
* (pasó con «C:\Users\José María»: el modelo, el audio y la salida cuelgan todos de esa
|
|
13
|
+
* carpeta, %TEMP% incluido). Así que se le ejecuta DESDE la carpeta del modelo y se le pasan
|
|
14
|
+
* solo rutas relativas, que son ASCII: el modelo por su nombre y el audio y la salida en una
|
|
15
|
+
* subcarpeta temporal de ahí. ffmpeg y el arranque del proceso sí entienden Unicode.
|
|
16
|
+
*/
|
|
17
|
+
function whisperWorkspace(model) {
|
|
18
|
+
if (process.platform === 'win32') {
|
|
19
|
+
try {
|
|
20
|
+
const cwd = dirname(model);
|
|
21
|
+
const tmp = mkdtempSync(join(cwd, 'asr-'));
|
|
22
|
+
return { tmp, cwd, modelArg: basename(model), arg: (p) => relative(cwd, p) };
|
|
23
|
+
} catch {
|
|
24
|
+
/* carpeta del modelo sin permiso de escritura: como en el resto de sistemas */
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return { tmp: mkdtempSync(join(tmpdir(), 'ignix-editor-asr-')), cwd: undefined, modelArg: model, arg: (p) => p };
|
|
28
|
+
}
|
|
9
29
|
|
|
10
30
|
const norm = (s) => s.toLowerCase().normalize('NFD').replace(/[̀-ͯ]/g, '').replace(/[^\p{L}\p{N}]/gu, '');
|
|
11
31
|
|
|
12
32
|
export function transcribe({ ffmpeg, whisper, model, input, language = 'es', threads = 8 }) {
|
|
13
|
-
const
|
|
33
|
+
const ws = whisperWorkspace(model);
|
|
34
|
+
const tmp = ws.tmp;
|
|
14
35
|
try {
|
|
15
36
|
const wav = join(tmp, 'audio.wav');
|
|
16
37
|
const a = spawnSync(ffmpeg, ['-nostdin', '-hide_banner', '-loglevel', 'error', '-y', '-i', input, '-vn', '-ar', '16000', '-ac', '1', '-c:a', 'pcm_s16le', wav], { encoding: 'utf8' });
|
|
17
38
|
if (a.status !== 0) throw new Error(`Could not read the audio of ${input}: ${a.stderr.slice(-300)}`);
|
|
18
39
|
const out = join(tmp, 'out');
|
|
19
|
-
const args = ['-m',
|
|
20
|
-
const run = (extra) => spawnSync(whisper, [...extra, ...args], { encoding: 'utf8', maxBuffer: 64 * 1024 * 1024 });
|
|
40
|
+
const args = ['-m', ws.modelArg, '-l', language, '-ml', '1', '-sow', '-oj', '-of', ws.arg(out), '-t', String(threads), '-f', ws.arg(wav)];
|
|
41
|
+
const run = (extra) => spawnSync(whisper, [...extra, ...args], { encoding: 'utf8', maxBuffer: 64 * 1024 * 1024, cwd: ws.cwd });
|
|
21
42
|
// En Mac Intel la GPU (Metal) se cuelga con whisper: CPU directamente. En el resto, GPU y,
|
|
22
43
|
// si falla, otra vez por CPU.
|
|
23
44
|
const intelMac = process.platform === 'darwin' && process.arch === 'x64';
|
|
@@ -75,15 +96,16 @@ export function alignToScript(script, tokens, end) {
|
|
|
75
96
|
* confianza (media de sus tokens) y las frases (cortadas en un punto o en una pausa).
|
|
76
97
|
*/
|
|
77
98
|
export function transcribeDetailed({ ffmpeg, whisper, model, input, language = null, threads = 8, maxWords = 6000, maxSegments = 800 }) {
|
|
78
|
-
const
|
|
99
|
+
const ws = whisperWorkspace(model);
|
|
100
|
+
const tmp = ws.tmp;
|
|
79
101
|
try {
|
|
80
102
|
const wav = join(tmp, 'audio.wav');
|
|
81
103
|
const a = spawnSync(ffmpeg, ['-nostdin', '-hide_banner', '-loglevel', 'error', '-y', '-i', input, '-vn', '-ar', '16000', '-ac', '1', '-c:a', 'pcm_s16le', wav], { encoding: 'utf8' });
|
|
82
104
|
if (a.status !== 0) throw new Error(`Could not read the audio of ${input}: ${a.stderr.slice(-300)}`);
|
|
83
105
|
const duration = statSync(wav).size > 44 ? (statSync(wav).size - 44) / 32000 : 0;
|
|
84
106
|
const out = join(tmp, 'out');
|
|
85
|
-
const args = ['-m',
|
|
86
|
-
const run = (extra) => spawnSync(whisper, [...extra, ...args], { encoding: 'utf8', maxBuffer: 64 * 1024 * 1024 });
|
|
107
|
+
const args = ['-m', ws.modelArg, '-l', language || 'auto', '-ml', '1', '-sow', '-ojf', '-of', ws.arg(out), '-t', String(threads), '-f', ws.arg(wav)];
|
|
108
|
+
const run = (extra) => spawnSync(whisper, [...extra, ...args], { encoding: 'utf8', maxBuffer: 64 * 1024 * 1024, cwd: ws.cwd });
|
|
87
109
|
const intelMac = process.platform === 'darwin' && process.arch === 'x64';
|
|
88
110
|
let w = run(intelMac ? ['-ng'] : []);
|
|
89
111
|
let device = intelMac ? 'cpu' : 'gpu';
|