@storyteller-platform/align 0.1.17 → 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/dist/align/align.cjs +8 -8
- package/dist/align/align.d.cts +1 -0
- package/dist/align/align.d.ts +1 -0
- package/dist/align/align.js +8 -8
- package/dist/cli/bin.cjs +1 -1
- package/dist/cli/bin.js +2 -2
- package/dist/common/ffmpeg.cjs +12 -12
- package/dist/common/ffmpeg.js +12 -12
- package/dist/errorAlign/backtraceGraph.cjs +5 -8
- package/dist/errorAlign/backtraceGraph.js +5 -8
- package/dist/errorAlign/beamSearch.cjs +1 -2
- package/dist/errorAlign/beamSearch.js +1 -2
- package/dist/markup/markup.cjs +3 -4
- package/dist/markup/markup.js +3 -4
- package/dist/markup/serializeDom.cjs +1 -1
- package/dist/markup/serializeDom.js +1 -1
- package/dist/markup/transform.cjs +6 -1
- package/dist/markup/transform.js +6 -1
- package/dist/process/processAudiobook.cjs +8 -12
- package/dist/process/processAudiobook.js +8 -12
- package/dist/process/ranges.cjs +3 -3
- package/dist/process/ranges.js +3 -3
- package/dist/transcribe/transcribe.cjs +9 -14
- package/dist/transcribe/transcribe.js +9 -14
- package/package.json +2 -2
package/dist/align/align.cjs
CHANGED
|
@@ -258,7 +258,8 @@ class Aligner {
|
|
|
258
258
|
matchedSentence: chapterSentences[endSentence],
|
|
259
259
|
nextSentence: chapterSentences[endSentence + 1] ?? null
|
|
260
260
|
},
|
|
261
|
-
chapterSentenceCount:
|
|
261
|
+
chapterSentenceCount: chapterSentences.length,
|
|
262
|
+
alignedSentenceCount: sentenceRanges.length,
|
|
262
263
|
audioFiles: sentenceRanges.reduce((acc, range) => {
|
|
263
264
|
const existing = acc.find(
|
|
264
265
|
(context) => context.filepath === range.audiofile
|
|
@@ -347,7 +348,6 @@ class Aligner {
|
|
|
347
348
|
return narrowed;
|
|
348
349
|
}
|
|
349
350
|
async alignBook(onProgress) {
|
|
350
|
-
var _a, _b, _c, _d, _e, _f;
|
|
351
351
|
const locale = this.languageOverride ?? await this.epub.getLanguage() ?? new Intl.Locale("en-US");
|
|
352
352
|
this.timing.setMetadata("language", locale.toString());
|
|
353
353
|
this.timing.setMetadata("granularity", this.granularity);
|
|
@@ -358,13 +358,13 @@ class Aligner {
|
|
|
358
358
|
locale
|
|
359
359
|
);
|
|
360
360
|
for (let index = 0; index < spine.length; index++) {
|
|
361
|
-
onProgress
|
|
361
|
+
onProgress?.(index / spine.length);
|
|
362
362
|
const spineItem = spine[index];
|
|
363
|
-
|
|
363
|
+
this.logger?.info(
|
|
364
364
|
`Aligning epub item #${index} : ${(0, import_posix.basename)(spineItem.href)}`
|
|
365
365
|
);
|
|
366
366
|
const chapterId = spineItem.id;
|
|
367
|
-
if (
|
|
367
|
+
if (manifest[chapterId]?.properties?.includes("nav")) {
|
|
368
368
|
continue;
|
|
369
369
|
}
|
|
370
370
|
const chapterSentences = await this.getChapterSentences(chapterId);
|
|
@@ -375,12 +375,12 @@ class Aligner {
|
|
|
375
375
|
);
|
|
376
376
|
}
|
|
377
377
|
if (chapterSentences.length === 0) {
|
|
378
|
-
|
|
378
|
+
this.logger?.info(`Chapter #${index} has no text; skipping`);
|
|
379
379
|
continue;
|
|
380
380
|
}
|
|
381
381
|
if (chapterSentences.length < 2 && // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
382
382
|
chapterSentences[0].split(" ").length < 4) {
|
|
383
|
-
|
|
383
|
+
this.logger?.info(
|
|
384
384
|
`Chapter #${index} is fewer than four words; skipping`
|
|
385
385
|
);
|
|
386
386
|
continue;
|
|
@@ -390,7 +390,7 @@ class Aligner {
|
|
|
390
390
|
transcriptionText
|
|
391
391
|
);
|
|
392
392
|
if (!boundaries) {
|
|
393
|
-
|
|
393
|
+
this.logger?.info(
|
|
394
394
|
`Could not find chapter #${index} in the transcripton`
|
|
395
395
|
);
|
|
396
396
|
continue;
|
package/dist/align/align.d.cts
CHANGED
package/dist/align/align.d.ts
CHANGED
package/dist/align/align.js
CHANGED
|
@@ -192,7 +192,8 @@ class Aligner {
|
|
|
192
192
|
matchedSentence: chapterSentences[endSentence],
|
|
193
193
|
nextSentence: chapterSentences[endSentence + 1] ?? null
|
|
194
194
|
},
|
|
195
|
-
chapterSentenceCount:
|
|
195
|
+
chapterSentenceCount: chapterSentences.length,
|
|
196
|
+
alignedSentenceCount: sentenceRanges.length,
|
|
196
197
|
audioFiles: sentenceRanges.reduce((acc, range) => {
|
|
197
198
|
const existing = acc.find(
|
|
198
199
|
(context) => context.filepath === range.audiofile
|
|
@@ -281,7 +282,6 @@ class Aligner {
|
|
|
281
282
|
return narrowed;
|
|
282
283
|
}
|
|
283
284
|
async alignBook(onProgress) {
|
|
284
|
-
var _a, _b, _c, _d, _e, _f;
|
|
285
285
|
const locale = this.languageOverride ?? await this.epub.getLanguage() ?? new Intl.Locale("en-US");
|
|
286
286
|
this.timing.setMetadata("language", locale.toString());
|
|
287
287
|
this.timing.setMetadata("granularity", this.granularity);
|
|
@@ -292,13 +292,13 @@ class Aligner {
|
|
|
292
292
|
locale
|
|
293
293
|
);
|
|
294
294
|
for (let index = 0; index < spine.length; index++) {
|
|
295
|
-
onProgress
|
|
295
|
+
onProgress?.(index / spine.length);
|
|
296
296
|
const spineItem = spine[index];
|
|
297
|
-
|
|
297
|
+
this.logger?.info(
|
|
298
298
|
`Aligning epub item #${index} : ${basename(spineItem.href)}`
|
|
299
299
|
);
|
|
300
300
|
const chapterId = spineItem.id;
|
|
301
|
-
if (
|
|
301
|
+
if (manifest[chapterId]?.properties?.includes("nav")) {
|
|
302
302
|
continue;
|
|
303
303
|
}
|
|
304
304
|
const chapterSentences = await this.getChapterSentences(chapterId);
|
|
@@ -309,12 +309,12 @@ class Aligner {
|
|
|
309
309
|
);
|
|
310
310
|
}
|
|
311
311
|
if (chapterSentences.length === 0) {
|
|
312
|
-
|
|
312
|
+
this.logger?.info(`Chapter #${index} has no text; skipping`);
|
|
313
313
|
continue;
|
|
314
314
|
}
|
|
315
315
|
if (chapterSentences.length < 2 && // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
316
316
|
chapterSentences[0].split(" ").length < 4) {
|
|
317
|
-
|
|
317
|
+
this.logger?.info(
|
|
318
318
|
`Chapter #${index} is fewer than four words; skipping`
|
|
319
319
|
);
|
|
320
320
|
continue;
|
|
@@ -324,7 +324,7 @@ class Aligner {
|
|
|
324
324
|
transcriptionText
|
|
325
325
|
);
|
|
326
326
|
if (!boundaries) {
|
|
327
|
-
|
|
327
|
+
this.logger?.info(
|
|
328
328
|
`Could not find chapter #${index} in the transcripton`
|
|
329
329
|
);
|
|
330
330
|
continue;
|
package/dist/cli/bin.cjs
CHANGED
|
@@ -137,7 +137,7 @@ async function main() {
|
|
|
137
137
|
const controller = new AbortController();
|
|
138
138
|
let progressBar;
|
|
139
139
|
function resetProgressBar() {
|
|
140
|
-
progressBar
|
|
140
|
+
progressBar?.stop();
|
|
141
141
|
progressBar = new import_cli_progress.SingleBar(
|
|
142
142
|
{ etaBuffer: 4, hideCursor: null, noTTYOutput: !process.stderr.isTTY },
|
|
143
143
|
import_cli_progress.Presets.shades_classic
|
package/dist/cli/bin.js
CHANGED
|
@@ -23,7 +23,7 @@ import { run } from "@optique/run";
|
|
|
23
23
|
import { path } from "@optique/run/valueparser";
|
|
24
24
|
import { Presets, SingleBar } from "cli-progress";
|
|
25
25
|
import { Epub } from "@storyteller-platform/epub";
|
|
26
|
-
import packageJson from "../../package.json";
|
|
26
|
+
import packageJson from "../../package.json" with { type: "json" };
|
|
27
27
|
import { align } from "../align/align.js";
|
|
28
28
|
import { alignCommand, alignParser } from "../align/parse.js";
|
|
29
29
|
import { createLogger } from "../common/logging.js";
|
|
@@ -88,7 +88,7 @@ async function main() {
|
|
|
88
88
|
const controller = new AbortController();
|
|
89
89
|
let progressBar;
|
|
90
90
|
function resetProgressBar() {
|
|
91
|
-
progressBar
|
|
91
|
+
progressBar?.stop();
|
|
92
92
|
progressBar = new SingleBar(
|
|
93
93
|
{ etaBuffer: 4, hideCursor: null, noTTYOutput: !process.stderr.isTTY },
|
|
94
94
|
Presets.shades_classic
|
package/dist/common/ffmpeg.cjs
CHANGED
|
@@ -58,8 +58,8 @@ async function execCmd(command, logger, signal) {
|
|
|
58
58
|
"stdout maxBuffer length exceeded. This likely means that youre trying to process a very large file, and the ffmpeg process is running out of memory. Maybe check the image size of your cover art."
|
|
59
59
|
);
|
|
60
60
|
}
|
|
61
|
-
logger
|
|
62
|
-
logger
|
|
61
|
+
logger?.error(error);
|
|
62
|
+
logger?.info(stdout);
|
|
63
63
|
throw new Error(stderr);
|
|
64
64
|
}
|
|
65
65
|
}
|
|
@@ -157,8 +157,8 @@ function commonFfmpegArguments(sourceExtension, destExtension, codec, bitrate) {
|
|
|
157
157
|
}
|
|
158
158
|
async function splitFile(input, output, start, end, encoding, signal, logger) {
|
|
159
159
|
if (start === end) return false;
|
|
160
|
-
logger
|
|
161
|
-
`Splitting ${input} start: ${start} end: ${end}${
|
|
160
|
+
logger?.info(
|
|
161
|
+
`Splitting ${input} start: ${start} end: ${end}${encoding?.codec ? ` codec: ${encoding.codec}` : ""}`
|
|
162
162
|
);
|
|
163
163
|
const command = "ffmpeg";
|
|
164
164
|
const args = [
|
|
@@ -172,8 +172,8 @@ async function splitFile(input, output, start, end, encoding, signal, logger) {
|
|
|
172
172
|
...commonFfmpegArguments(
|
|
173
173
|
(0, import_node_path.extname)(input),
|
|
174
174
|
(0, import_node_path.extname)(output),
|
|
175
|
-
|
|
176
|
-
|
|
175
|
+
encoding?.codec ?? null,
|
|
176
|
+
encoding?.bitrate ?? null
|
|
177
177
|
),
|
|
178
178
|
(0, import_shell.quotePath)(output)
|
|
179
179
|
];
|
|
@@ -189,15 +189,15 @@ async function splitFile(input, output, start, end, encoding, signal, logger) {
|
|
|
189
189
|
return true;
|
|
190
190
|
}
|
|
191
191
|
async function transcodeFile(input, output, encoding, signal, logger) {
|
|
192
|
-
if (!
|
|
193
|
-
logger
|
|
192
|
+
if (!encoding?.codec && (0, import_mime.areSameType)(input, output)) {
|
|
193
|
+
logger?.info(
|
|
194
194
|
`Input and output container and codec are the same, copying ${input} to output directory`
|
|
195
195
|
);
|
|
196
196
|
await (0, import_promises.copyFile)(input, output);
|
|
197
197
|
return;
|
|
198
198
|
}
|
|
199
|
-
logger
|
|
200
|
-
`Transcoding ${input}${
|
|
199
|
+
logger?.info(
|
|
200
|
+
`Transcoding ${input}${encoding?.codec ? ` codec: ${encoding.codec}` : ""}`
|
|
201
201
|
);
|
|
202
202
|
const command = "ffmpeg";
|
|
203
203
|
const args = [
|
|
@@ -207,8 +207,8 @@ async function transcodeFile(input, output, encoding, signal, logger) {
|
|
|
207
207
|
...commonFfmpegArguments(
|
|
208
208
|
(0, import_node_path.extname)(input),
|
|
209
209
|
(0, import_node_path.extname)(output),
|
|
210
|
-
|
|
211
|
-
|
|
210
|
+
encoding?.codec ?? null,
|
|
211
|
+
encoding?.bitrate ?? null
|
|
212
212
|
),
|
|
213
213
|
(0, import_shell.quotePath)(output)
|
|
214
214
|
];
|
package/dist/common/ffmpeg.js
CHANGED
|
@@ -23,8 +23,8 @@ async function execCmd(command, logger, signal) {
|
|
|
23
23
|
"stdout maxBuffer length exceeded. This likely means that youre trying to process a very large file, and the ffmpeg process is running out of memory. Maybe check the image size of your cover art."
|
|
24
24
|
);
|
|
25
25
|
}
|
|
26
|
-
logger
|
|
27
|
-
logger
|
|
26
|
+
logger?.error(error);
|
|
27
|
+
logger?.info(stdout);
|
|
28
28
|
throw new Error(stderr);
|
|
29
29
|
}
|
|
30
30
|
}
|
|
@@ -122,8 +122,8 @@ function commonFfmpegArguments(sourceExtension, destExtension, codec, bitrate) {
|
|
|
122
122
|
}
|
|
123
123
|
async function splitFile(input, output, start, end, encoding, signal, logger) {
|
|
124
124
|
if (start === end) return false;
|
|
125
|
-
logger
|
|
126
|
-
`Splitting ${input} start: ${start} end: ${end}${
|
|
125
|
+
logger?.info(
|
|
126
|
+
`Splitting ${input} start: ${start} end: ${end}${encoding?.codec ? ` codec: ${encoding.codec}` : ""}`
|
|
127
127
|
);
|
|
128
128
|
const command = "ffmpeg";
|
|
129
129
|
const args = [
|
|
@@ -137,8 +137,8 @@ async function splitFile(input, output, start, end, encoding, signal, logger) {
|
|
|
137
137
|
...commonFfmpegArguments(
|
|
138
138
|
extname(input),
|
|
139
139
|
extname(output),
|
|
140
|
-
|
|
141
|
-
|
|
140
|
+
encoding?.codec ?? null,
|
|
141
|
+
encoding?.bitrate ?? null
|
|
142
142
|
),
|
|
143
143
|
quotePath(output)
|
|
144
144
|
];
|
|
@@ -154,15 +154,15 @@ async function splitFile(input, output, start, end, encoding, signal, logger) {
|
|
|
154
154
|
return true;
|
|
155
155
|
}
|
|
156
156
|
async function transcodeFile(input, output, encoding, signal, logger) {
|
|
157
|
-
if (!
|
|
158
|
-
logger
|
|
157
|
+
if (!encoding?.codec && areSameType(input, output)) {
|
|
158
|
+
logger?.info(
|
|
159
159
|
`Input and output container and codec are the same, copying ${input} to output directory`
|
|
160
160
|
);
|
|
161
161
|
await copyFile(input, output);
|
|
162
162
|
return;
|
|
163
163
|
}
|
|
164
|
-
logger
|
|
165
|
-
`Transcoding ${input}${
|
|
164
|
+
logger?.info(
|
|
165
|
+
`Transcoding ${input}${encoding?.codec ? ` codec: ${encoding.codec}` : ""}`
|
|
166
166
|
);
|
|
167
167
|
const command = "ffmpeg";
|
|
168
168
|
const args = [
|
|
@@ -172,8 +172,8 @@ async function transcodeFile(input, output, encoding, signal, logger) {
|
|
|
172
172
|
...commonFfmpegArguments(
|
|
173
173
|
extname(input),
|
|
174
174
|
extname(output),
|
|
175
|
-
|
|
176
|
-
|
|
175
|
+
encoding?.codec ?? null,
|
|
176
|
+
encoding?.bitrate ?? null
|
|
177
177
|
),
|
|
178
178
|
quotePath(output)
|
|
179
179
|
];
|
|
@@ -69,15 +69,14 @@ class Node {
|
|
|
69
69
|
class NodeMap {
|
|
70
70
|
map;
|
|
71
71
|
constructor(entries) {
|
|
72
|
-
const keyedEntries = entries
|
|
72
|
+
const keyedEntries = entries?.map(
|
|
73
73
|
([index, node]) => [`${index[0]}-${index[1]}`, { index, node }]
|
|
74
74
|
);
|
|
75
75
|
this.map = new Map(keyedEntries);
|
|
76
76
|
}
|
|
77
77
|
get([hypIndex, refIndex]) {
|
|
78
|
-
var _a;
|
|
79
78
|
const key = `${hypIndex}-${refIndex}`;
|
|
80
|
-
return
|
|
79
|
+
return this.map.get(key)?.node;
|
|
81
80
|
}
|
|
82
81
|
set([hypIndex, refIndex], node) {
|
|
83
82
|
const key = `${hypIndex}-${refIndex}`;
|
|
@@ -159,7 +158,7 @@ class BacktraceGraph {
|
|
|
159
158
|
*/
|
|
160
159
|
getPath({ sample } = { sample: false }) {
|
|
161
160
|
let node = this.getNode(0, 0);
|
|
162
|
-
(0, import_node_assert.default)(node
|
|
161
|
+
(0, import_node_assert.default)(node?.isRoot, "The node at (-1, -1) was expected to be a root node.");
|
|
163
162
|
const path = [];
|
|
164
163
|
while (!node.isTerminal) {
|
|
165
164
|
const opType = sample ? choose(Array.from(node.children.keys())) : (
|
|
@@ -211,7 +210,6 @@ class BacktraceGraph {
|
|
|
211
210
|
* @returns A list of index tuples representing the end node of unambiguous span matches.
|
|
212
211
|
*/
|
|
213
212
|
getUnambiguousTokenSpanMatches(ref) {
|
|
214
|
-
var _a;
|
|
215
213
|
ref = "_" + ref;
|
|
216
214
|
const monoMatchEndNodes = /* @__PURE__ */ new Set();
|
|
217
215
|
const refIndexes = new import_utils.Counter();
|
|
@@ -226,7 +224,7 @@ class BacktraceGraph {
|
|
|
226
224
|
if (!this.nodes.has(_index)) {
|
|
227
225
|
break;
|
|
228
226
|
}
|
|
229
|
-
if (!
|
|
227
|
+
if (!this.nodes.get(_index)?.parents) {
|
|
230
228
|
break;
|
|
231
229
|
}
|
|
232
230
|
if (ref[_refIndex] === import_utils.END_DELIMITER) {
|
|
@@ -272,8 +270,7 @@ class BacktraceGraph {
|
|
|
272
270
|
* Add parents to the node at the given index based on the backtrace matrix.
|
|
273
271
|
*/
|
|
274
272
|
addParentsFromBacktrace(index) {
|
|
275
|
-
|
|
276
|
-
const node = (_a = this._nodes) == null ? void 0 : _a.get(index);
|
|
273
|
+
const node = this._nodes?.get(index);
|
|
277
274
|
(0, import_node_assert.default)(
|
|
278
275
|
!!node,
|
|
279
276
|
`Node at index ${index.toString()} does not exist in the graph.`
|
|
@@ -42,15 +42,14 @@ class Node {
|
|
|
42
42
|
class NodeMap {
|
|
43
43
|
map;
|
|
44
44
|
constructor(entries) {
|
|
45
|
-
const keyedEntries = entries
|
|
45
|
+
const keyedEntries = entries?.map(
|
|
46
46
|
([index, node]) => [`${index[0]}-${index[1]}`, { index, node }]
|
|
47
47
|
);
|
|
48
48
|
this.map = new Map(keyedEntries);
|
|
49
49
|
}
|
|
50
50
|
get([hypIndex, refIndex]) {
|
|
51
|
-
var _a;
|
|
52
51
|
const key = `${hypIndex}-${refIndex}`;
|
|
53
|
-
return
|
|
52
|
+
return this.map.get(key)?.node;
|
|
54
53
|
}
|
|
55
54
|
set([hypIndex, refIndex], node) {
|
|
56
55
|
const key = `${hypIndex}-${refIndex}`;
|
|
@@ -132,7 +131,7 @@ class BacktraceGraph {
|
|
|
132
131
|
*/
|
|
133
132
|
getPath({ sample } = { sample: false }) {
|
|
134
133
|
let node = this.getNode(0, 0);
|
|
135
|
-
assert(node
|
|
134
|
+
assert(node?.isRoot, "The node at (-1, -1) was expected to be a root node.");
|
|
136
135
|
const path = [];
|
|
137
136
|
while (!node.isTerminal) {
|
|
138
137
|
const opType = sample ? choose(Array.from(node.children.keys())) : (
|
|
@@ -184,7 +183,6 @@ class BacktraceGraph {
|
|
|
184
183
|
* @returns A list of index tuples representing the end node of unambiguous span matches.
|
|
185
184
|
*/
|
|
186
185
|
getUnambiguousTokenSpanMatches(ref) {
|
|
187
|
-
var _a;
|
|
188
186
|
ref = "_" + ref;
|
|
189
187
|
const monoMatchEndNodes = /* @__PURE__ */ new Set();
|
|
190
188
|
const refIndexes = new Counter();
|
|
@@ -199,7 +197,7 @@ class BacktraceGraph {
|
|
|
199
197
|
if (!this.nodes.has(_index)) {
|
|
200
198
|
break;
|
|
201
199
|
}
|
|
202
|
-
if (!
|
|
200
|
+
if (!this.nodes.get(_index)?.parents) {
|
|
203
201
|
break;
|
|
204
202
|
}
|
|
205
203
|
if (ref[_refIndex] === END_DELIMITER) {
|
|
@@ -245,8 +243,7 @@ class BacktraceGraph {
|
|
|
245
243
|
* Add parents to the node at the given index based on the backtrace matrix.
|
|
246
244
|
*/
|
|
247
245
|
addParentsFromBacktrace(index) {
|
|
248
|
-
|
|
249
|
-
const node = (_a = this._nodes) == null ? void 0 : _a.get(index);
|
|
246
|
+
const node = this._nodes?.get(index);
|
|
250
247
|
assert(
|
|
251
248
|
!!node,
|
|
252
249
|
`Node at index ${index.toString()} does not exist in the graph.`
|
|
@@ -242,7 +242,6 @@ function isSubstitution(hypIndex, refIndex, lastHypIndex, lastRefIndex) {
|
|
|
242
242
|
return !(refIndex === lastRefIndex || hypIndex === lastHypIndex);
|
|
243
243
|
}
|
|
244
244
|
function errorAlignBeamSearch(src, beamSize = 100) {
|
|
245
|
-
var _a;
|
|
246
245
|
const startPath = new Path(src);
|
|
247
246
|
let beam = [startPath];
|
|
248
247
|
let pruneMap = {};
|
|
@@ -278,7 +277,7 @@ function errorAlignBeamSearch(src, beamSize = 100) {
|
|
|
278
277
|
return a.normCost - b.normCost;
|
|
279
278
|
});
|
|
280
279
|
beam = newBeamPaths.slice(0, beamSize);
|
|
281
|
-
if (
|
|
280
|
+
if (beam[0]?.atUnambiguousMatchNode) {
|
|
282
281
|
beam = beam.slice(0, 1);
|
|
283
282
|
pruneMap = {};
|
|
284
283
|
}
|
|
@@ -209,7 +209,6 @@ function isSubstitution(hypIndex, refIndex, lastHypIndex, lastRefIndex) {
|
|
|
209
209
|
return !(refIndex === lastRefIndex || hypIndex === lastHypIndex);
|
|
210
210
|
}
|
|
211
211
|
function errorAlignBeamSearch(src, beamSize = 100) {
|
|
212
|
-
var _a;
|
|
213
212
|
const startPath = new Path(src);
|
|
214
213
|
let beam = [startPath];
|
|
215
214
|
let pruneMap = {};
|
|
@@ -245,7 +244,7 @@ function errorAlignBeamSearch(src, beamSize = 100) {
|
|
|
245
244
|
return a.normCost - b.normCost;
|
|
246
245
|
});
|
|
247
246
|
beam = newBeamPaths.slice(0, beamSize);
|
|
248
|
-
if (
|
|
247
|
+
if (beam[0]?.atUnambiguousMatchNode) {
|
|
249
248
|
beam = beam.slice(0, 1);
|
|
250
249
|
pruneMap = {};
|
|
251
250
|
}
|
package/dist/markup/markup.cjs
CHANGED
|
@@ -77,7 +77,6 @@ var import_segmentation = require("./segmentation.cjs");
|
|
|
77
77
|
var import_serializeDom = require("./serializeDom.cjs");
|
|
78
78
|
var import_transform = require("./transform.cjs");
|
|
79
79
|
async function markup(input, output, options) {
|
|
80
|
-
var _a, _b, _c, _d;
|
|
81
80
|
var _stack = [];
|
|
82
81
|
try {
|
|
83
82
|
const timing = (0, import_ghost_story.createAggregator)();
|
|
@@ -88,13 +87,13 @@ async function markup(input, output, options) {
|
|
|
88
87
|
const spine = await epub.getSpineItems();
|
|
89
88
|
const manifest = await epub.getManifest();
|
|
90
89
|
for (let index = 0; index < spine.length; index++) {
|
|
91
|
-
|
|
90
|
+
options.onProgress?.(index / spine.length);
|
|
92
91
|
const spineItem = spine[index];
|
|
93
|
-
|
|
92
|
+
options.logger?.info(
|
|
94
93
|
`Marking up epub item #${index}: ${(0, import_posix.basename)(spineItem.href)}`
|
|
95
94
|
);
|
|
96
95
|
const chapterId = spineItem.id;
|
|
97
|
-
if (
|
|
96
|
+
if (manifest[chapterId]?.properties?.includes("nav")) {
|
|
98
97
|
continue;
|
|
99
98
|
}
|
|
100
99
|
const chapterXml = await epub.readXhtmlItemContents(chapterId);
|
package/dist/markup/markup.js
CHANGED
|
@@ -15,7 +15,6 @@ import { getXhtmlSegmentation } from "./segmentation.js";
|
|
|
15
15
|
import { serializeDom } from "./serializeDom.js";
|
|
16
16
|
import { addMark } from "./transform.js";
|
|
17
17
|
async function markup(input, output, options) {
|
|
18
|
-
var _a, _b, _c, _d;
|
|
19
18
|
var _stack = [];
|
|
20
19
|
try {
|
|
21
20
|
const timing = createAggregator();
|
|
@@ -26,13 +25,13 @@ async function markup(input, output, options) {
|
|
|
26
25
|
const spine = await epub.getSpineItems();
|
|
27
26
|
const manifest = await epub.getManifest();
|
|
28
27
|
for (let index = 0; index < spine.length; index++) {
|
|
29
|
-
|
|
28
|
+
options.onProgress?.(index / spine.length);
|
|
30
29
|
const spineItem = spine[index];
|
|
31
|
-
|
|
30
|
+
options.logger?.info(
|
|
32
31
|
`Marking up epub item #${index}: ${basename(spineItem.href)}`
|
|
33
32
|
);
|
|
34
33
|
const chapterId = spineItem.id;
|
|
35
|
-
if (
|
|
34
|
+
if (manifest[chapterId]?.properties?.includes("nav")) {
|
|
36
35
|
continue;
|
|
37
36
|
}
|
|
38
37
|
const chapterXml = await epub.readXhtmlItemContents(chapterId);
|
|
@@ -49,7 +49,7 @@ function serializeDomNodes(nodes) {
|
|
|
49
49
|
}
|
|
50
50
|
const childFirstMark = child.marks[0];
|
|
51
51
|
const lastChildFirstMark = lastChild.marks[0];
|
|
52
|
-
if (childFirstMark === lastChildFirstMark ||
|
|
52
|
+
if (childFirstMark === lastChildFirstMark || childFirstMark?.eq(lastChildFirstMark)) {
|
|
53
53
|
return [
|
|
54
54
|
...acc.slice(0, acc.length - 1),
|
|
55
55
|
[...lastPartition.slice(0, lastPartition.length), child]
|
|
@@ -26,7 +26,7 @@ function serializeDomNodes(nodes) {
|
|
|
26
26
|
}
|
|
27
27
|
const childFirstMark = child.marks[0];
|
|
28
28
|
const lastChildFirstMark = lastChild.marks[0];
|
|
29
|
-
if (childFirstMark === lastChildFirstMark ||
|
|
29
|
+
if (childFirstMark === lastChildFirstMark || childFirstMark?.eq(lastChildFirstMark)) {
|
|
30
30
|
return [
|
|
31
31
|
...acc.slice(0, acc.length - 1),
|
|
32
32
|
[...lastPartition.slice(0, lastPartition.length), child]
|
|
@@ -58,7 +58,12 @@ function liftText(root) {
|
|
|
58
58
|
if (node.isBlock) {
|
|
59
59
|
return !!node.textContent.match(/\S/);
|
|
60
60
|
}
|
|
61
|
-
if (!(node instanceof import_model.TextNode))
|
|
61
|
+
if (!(node instanceof import_model.TextNode)) {
|
|
62
|
+
if (node.isLeaf && parent.isBlock && index === parent.children.length - 1 && !text.endsWith("\n")) {
|
|
63
|
+
text += "\n";
|
|
64
|
+
}
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
62
67
|
if (mapping.map(pos) - mapping.map(lastTextEnd)) {
|
|
63
68
|
mapping.appendMap(
|
|
64
69
|
new import_map.StepMap([
|
package/dist/markup/transform.js
CHANGED
|
@@ -38,7 +38,12 @@ function liftText(root) {
|
|
|
38
38
|
if (node.isBlock) {
|
|
39
39
|
return !!node.textContent.match(/\S/);
|
|
40
40
|
}
|
|
41
|
-
if (!(node instanceof TextNode))
|
|
41
|
+
if (!(node instanceof TextNode)) {
|
|
42
|
+
if (node.isLeaf && parent.isBlock && index === parent.children.length - 1 && !text.endsWith("\n")) {
|
|
43
|
+
text += "\n";
|
|
44
|
+
}
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
42
47
|
if (mapping.map(pos) - mapping.map(lastTextEnd)) {
|
|
43
48
|
mapping.appendMap(
|
|
44
49
|
new StepMap([
|
|
@@ -75,15 +75,14 @@ var import_ghost_story = require("@storyteller-platform/ghost-story");
|
|
|
75
75
|
var import_ffmpeg = require("../common/ffmpeg.cjs");
|
|
76
76
|
var import_ranges = require("./ranges.cjs");
|
|
77
77
|
async function processAudiobook(input, output, options) {
|
|
78
|
-
var _a, _b, _c;
|
|
79
78
|
const timing = (0, import_ghost_story.createAggregator)();
|
|
80
|
-
timing.setMetadata("codec",
|
|
81
|
-
timing.setMetadata("bitrate",
|
|
79
|
+
timing.setMetadata("codec", options.encoding?.codec ?? "unspecified");
|
|
80
|
+
timing.setMetadata("bitrate", options.encoding?.bitrate ?? "unspecified");
|
|
82
81
|
timing.setMetadata("max-length", `${(options.maxLength ?? 2) * 60} minutes`);
|
|
83
82
|
await (0, import_promises.mkdir)(output, { recursive: true });
|
|
84
83
|
const allFiles = await (0, import_promises.readdir)(input, { recursive: true });
|
|
85
84
|
const filenames = allFiles.filter((f) => (0, import_audiobook.isAudioFile)(f) || (0, import_audiobook.isZipArchive)(f));
|
|
86
|
-
|
|
85
|
+
options.logger?.debug(`Found ${filenames.length} files to process`);
|
|
87
86
|
const outputFiles = [];
|
|
88
87
|
const controller = new AbortController();
|
|
89
88
|
const signal = AbortSignal.any([
|
|
@@ -97,15 +96,14 @@ async function processAudiobook(input, output, options) {
|
|
|
97
96
|
if (signal.aborted) throw new Error("Aborted");
|
|
98
97
|
const filepath = (0, import_node_path.join)(input, filename);
|
|
99
98
|
function onFileProgress(progress) {
|
|
100
|
-
var _a2, _b2;
|
|
101
99
|
perFileProgress.set(index, progress);
|
|
102
100
|
const updatedProgress = Array.from(perFileProgress.values()).reduce(
|
|
103
101
|
(acc, p) => acc + p
|
|
104
102
|
);
|
|
105
|
-
|
|
103
|
+
options.logger?.info(
|
|
106
104
|
`Progress: ${Math.floor(updatedProgress * 100)}%`
|
|
107
105
|
);
|
|
108
|
-
|
|
106
|
+
options.onProgress?.(updatedProgress);
|
|
109
107
|
}
|
|
110
108
|
const fileOptions = {
|
|
111
109
|
...options,
|
|
@@ -150,12 +148,11 @@ async function processFile(input, output, prefix, options) {
|
|
|
150
148
|
);
|
|
151
149
|
await Promise.all(
|
|
152
150
|
ranges.map(async (range, index) => {
|
|
153
|
-
var _a, _b;
|
|
154
151
|
var _stack2 = [];
|
|
155
152
|
try {
|
|
156
153
|
const outputExtension = determineExtension(
|
|
157
154
|
range.filepath,
|
|
158
|
-
|
|
155
|
+
options.encoding?.codec
|
|
159
156
|
);
|
|
160
157
|
const outputFilename = `${prefix}${(index + 1).toString().padStart(5, "0")}${outputExtension}`;
|
|
161
158
|
const outputFilepath = (0, import_node_path.join)(output, outputFilename);
|
|
@@ -164,11 +161,10 @@ async function processFile(input, output, prefix, options) {
|
|
|
164
161
|
options.lock.release();
|
|
165
162
|
});
|
|
166
163
|
await options.lock.wait();
|
|
167
|
-
if (
|
|
164
|
+
if (options.signal?.aborted) throw new Error("Aborted");
|
|
168
165
|
await timing.timeAsync(
|
|
169
166
|
`${range.filepath},${range.start}:${range.end}`,
|
|
170
167
|
async () => {
|
|
171
|
-
var _a2;
|
|
172
168
|
const wasSplit = await (0, import_ffmpeg.splitFile)(
|
|
173
169
|
range.filepath,
|
|
174
170
|
outputFilepath,
|
|
@@ -180,7 +176,7 @@ async function processFile(input, output, prefix, options) {
|
|
|
180
176
|
);
|
|
181
177
|
if (wasSplit) {
|
|
182
178
|
outputFiles.push(outputFilename);
|
|
183
|
-
|
|
179
|
+
options.onProgress?.((outputFiles.length + 1) / ranges.length);
|
|
184
180
|
}
|
|
185
181
|
}
|
|
186
182
|
);
|
|
@@ -22,15 +22,14 @@ import {
|
|
|
22
22
|
import { splitFile } from "../common/ffmpeg.js";
|
|
23
23
|
import { getSafeChapterRanges } from "./ranges.js";
|
|
24
24
|
async function processAudiobook(input, output, options) {
|
|
25
|
-
var _a, _b, _c;
|
|
26
25
|
const timing = createAggregator();
|
|
27
|
-
timing.setMetadata("codec",
|
|
28
|
-
timing.setMetadata("bitrate",
|
|
26
|
+
timing.setMetadata("codec", options.encoding?.codec ?? "unspecified");
|
|
27
|
+
timing.setMetadata("bitrate", options.encoding?.bitrate ?? "unspecified");
|
|
29
28
|
timing.setMetadata("max-length", `${(options.maxLength ?? 2) * 60} minutes`);
|
|
30
29
|
await mkdir(output, { recursive: true });
|
|
31
30
|
const allFiles = await readdir(input, { recursive: true });
|
|
32
31
|
const filenames = allFiles.filter((f) => isAudioFile(f) || isZipArchive(f));
|
|
33
|
-
|
|
32
|
+
options.logger?.debug(`Found ${filenames.length} files to process`);
|
|
34
33
|
const outputFiles = [];
|
|
35
34
|
const controller = new AbortController();
|
|
36
35
|
const signal = AbortSignal.any([
|
|
@@ -44,15 +43,14 @@ async function processAudiobook(input, output, options) {
|
|
|
44
43
|
if (signal.aborted) throw new Error("Aborted");
|
|
45
44
|
const filepath = join(input, filename);
|
|
46
45
|
function onFileProgress(progress) {
|
|
47
|
-
var _a2, _b2;
|
|
48
46
|
perFileProgress.set(index, progress);
|
|
49
47
|
const updatedProgress = Array.from(perFileProgress.values()).reduce(
|
|
50
48
|
(acc, p) => acc + p
|
|
51
49
|
);
|
|
52
|
-
|
|
50
|
+
options.logger?.info(
|
|
53
51
|
`Progress: ${Math.floor(updatedProgress * 100)}%`
|
|
54
52
|
);
|
|
55
|
-
|
|
53
|
+
options.onProgress?.(updatedProgress);
|
|
56
54
|
}
|
|
57
55
|
const fileOptions = {
|
|
58
56
|
...options,
|
|
@@ -97,12 +95,11 @@ async function processFile(input, output, prefix, options) {
|
|
|
97
95
|
);
|
|
98
96
|
await Promise.all(
|
|
99
97
|
ranges.map(async (range, index) => {
|
|
100
|
-
var _a, _b;
|
|
101
98
|
var _stack2 = [];
|
|
102
99
|
try {
|
|
103
100
|
const outputExtension = determineExtension(
|
|
104
101
|
range.filepath,
|
|
105
|
-
|
|
102
|
+
options.encoding?.codec
|
|
106
103
|
);
|
|
107
104
|
const outputFilename = `${prefix}${(index + 1).toString().padStart(5, "0")}${outputExtension}`;
|
|
108
105
|
const outputFilepath = join(output, outputFilename);
|
|
@@ -111,11 +108,10 @@ async function processFile(input, output, prefix, options) {
|
|
|
111
108
|
options.lock.release();
|
|
112
109
|
});
|
|
113
110
|
await options.lock.wait();
|
|
114
|
-
if (
|
|
111
|
+
if (options.signal?.aborted) throw new Error("Aborted");
|
|
115
112
|
await timing.timeAsync(
|
|
116
113
|
`${range.filepath},${range.start}:${range.end}`,
|
|
117
114
|
async () => {
|
|
118
|
-
var _a2;
|
|
119
115
|
const wasSplit = await splitFile(
|
|
120
116
|
range.filepath,
|
|
121
117
|
outputFilepath,
|
|
@@ -127,7 +123,7 @@ async function processFile(input, output, prefix, options) {
|
|
|
127
123
|
);
|
|
128
124
|
if (wasSplit) {
|
|
129
125
|
outputFiles.push(outputFilename);
|
|
130
|
-
|
|
126
|
+
options.onProgress?.((outputFiles.length + 1) / ranges.length);
|
|
131
127
|
}
|
|
132
128
|
}
|
|
133
129
|
);
|
package/dist/process/ranges.cjs
CHANGED
|
@@ -75,7 +75,7 @@ var import_vad = require("@storyteller-platform/ghost-story/vad");
|
|
|
75
75
|
var import_ffmpeg = require("../common/ffmpeg.cjs");
|
|
76
76
|
async function getSafeChapterRanges(input, duration, chapters, maxSeconds, signal, logger) {
|
|
77
77
|
if (!chapters.length) {
|
|
78
|
-
logger
|
|
78
|
+
logger?.info(
|
|
79
79
|
`Track is longer than ${maxSeconds / 60} minutes (${duration / 60}m); using VAD to determine safe split points.`
|
|
80
80
|
);
|
|
81
81
|
const ranges2 = await getSafeRanges(input, duration, maxSeconds, 0, signal);
|
|
@@ -103,7 +103,7 @@ async function getSafeChapterRanges(input, duration, chapters, maxSeconds, signa
|
|
|
103
103
|
ranges.push(range);
|
|
104
104
|
continue;
|
|
105
105
|
}
|
|
106
|
-
logger
|
|
106
|
+
logger?.info(
|
|
107
107
|
`Chapter is longer than ${maxSeconds / 60} minutes (${duration / 60}m); using VAD to determine safe split points.`
|
|
108
108
|
);
|
|
109
109
|
const chapterRanges = await getSafeRanges(
|
|
@@ -132,7 +132,7 @@ async function getSafeRanges(input, duration, maxSeconds, start = 0, signal, log
|
|
|
132
132
|
});
|
|
133
133
|
const ranges = [{ start, end: duration + start }];
|
|
134
134
|
for (let i = 0; i + 1 < duration / maxSeconds; i++) {
|
|
135
|
-
if (signal
|
|
135
|
+
if (signal?.aborted) throw new Error("Aborted");
|
|
136
136
|
const tmpFilepath = (0, import_node_path.join)(tmpDir, i.toString(), `${rawFilename}.wav`);
|
|
137
137
|
await (0, import_promises.mkdir)((0, import_node_path.dirname)(tmpFilepath), { recursive: true });
|
|
138
138
|
const approxCutPoint = start + maxSeconds * (i + 1);
|
package/dist/process/ranges.js
CHANGED
|
@@ -10,7 +10,7 @@ import { detectVoiceActivity } from "@storyteller-platform/ghost-story/vad";
|
|
|
10
10
|
import { splitFile } from "../common/ffmpeg.js";
|
|
11
11
|
async function getSafeChapterRanges(input, duration, chapters, maxSeconds, signal, logger) {
|
|
12
12
|
if (!chapters.length) {
|
|
13
|
-
logger
|
|
13
|
+
logger?.info(
|
|
14
14
|
`Track is longer than ${maxSeconds / 60} minutes (${duration / 60}m); using VAD to determine safe split points.`
|
|
15
15
|
);
|
|
16
16
|
const ranges2 = await getSafeRanges(input, duration, maxSeconds, 0, signal);
|
|
@@ -38,7 +38,7 @@ async function getSafeChapterRanges(input, duration, chapters, maxSeconds, signa
|
|
|
38
38
|
ranges.push(range);
|
|
39
39
|
continue;
|
|
40
40
|
}
|
|
41
|
-
logger
|
|
41
|
+
logger?.info(
|
|
42
42
|
`Chapter is longer than ${maxSeconds / 60} minutes (${duration / 60}m); using VAD to determine safe split points.`
|
|
43
43
|
);
|
|
44
44
|
const chapterRanges = await getSafeRanges(
|
|
@@ -67,7 +67,7 @@ async function getSafeRanges(input, duration, maxSeconds, start = 0, signal, log
|
|
|
67
67
|
});
|
|
68
68
|
const ranges = [{ start, end: duration + start }];
|
|
69
69
|
for (let i = 0; i + 1 < duration / maxSeconds; i++) {
|
|
70
|
-
if (signal
|
|
70
|
+
if (signal?.aborted) throw new Error("Aborted");
|
|
71
71
|
const tmpFilepath = join(tmpDir, i.toString(), `${rawFilename}.wav`);
|
|
72
72
|
await mkdir(dirname(tmpFilepath), { recursive: true });
|
|
73
73
|
const approxCutPoint = start + maxSeconds * (i + 1);
|
|
@@ -84,7 +84,6 @@ var import_async_semaphore = require("@esfx/async-semaphore");
|
|
|
84
84
|
var import_audiobook = require("@storyteller-platform/audiobook");
|
|
85
85
|
var import_ghost_story = require("@storyteller-platform/ghost-story");
|
|
86
86
|
async function transcribe(input, output, locale, options) {
|
|
87
|
-
var _a;
|
|
88
87
|
if (process.env["DEBUG_TRANSCRIBE"] === "true") {
|
|
89
88
|
const inspector = await import("node:inspector");
|
|
90
89
|
inspector.open(9231, "0.0.0.0", true);
|
|
@@ -109,7 +108,7 @@ async function transcribe(input, output, locale, options) {
|
|
|
109
108
|
await (0, import_ghost_story.ensureWhisperInstalled)({
|
|
110
109
|
model,
|
|
111
110
|
printOutput: ["debug", "info"].includes(
|
|
112
|
-
|
|
111
|
+
options.logger?.level ?? "silent"
|
|
113
112
|
),
|
|
114
113
|
signal
|
|
115
114
|
});
|
|
@@ -126,7 +125,6 @@ async function transcribe(input, output, locale, options) {
|
|
|
126
125
|
timing.setMetadata("threads", options.threads ?? 4);
|
|
127
126
|
await Promise.all(
|
|
128
127
|
filenames.map(async (filename) => {
|
|
129
|
-
var _a2, _b, _c;
|
|
130
128
|
var _stack = [];
|
|
131
129
|
try {
|
|
132
130
|
if (aborted()) throw new Error("Aborted");
|
|
@@ -140,7 +138,7 @@ async function transcribe(input, output, locale, options) {
|
|
|
140
138
|
encoding: "utf-8",
|
|
141
139
|
signal
|
|
142
140
|
});
|
|
143
|
-
|
|
141
|
+
options.logger?.info(`Found existing transcription for ${filepath}`);
|
|
144
142
|
transcriptions.push(transcriptionFilepath);
|
|
145
143
|
} catch {
|
|
146
144
|
}
|
|
@@ -151,13 +149,12 @@ async function transcribe(input, output, locale, options) {
|
|
|
151
149
|
});
|
|
152
150
|
await semaphore.wait();
|
|
153
151
|
function onFileProgress(progress) {
|
|
154
|
-
var _a3, _b2;
|
|
155
152
|
perFileProgress.set(filename, progress);
|
|
156
153
|
const updatedProgress = Array.from(perFileProgress.values()).reduce((acc, p) => acc + p) / filenames.length;
|
|
157
|
-
|
|
154
|
+
options.logger?.info(
|
|
158
155
|
`Progress: ${Math.floor(updatedProgress * 100)}%`
|
|
159
156
|
);
|
|
160
|
-
|
|
157
|
+
options.onProgress?.(updatedProgress);
|
|
161
158
|
}
|
|
162
159
|
const transcription = await transcribeFile(filepath, locale, {
|
|
163
160
|
...options,
|
|
@@ -168,7 +165,7 @@ async function transcribe(input, output, locale, options) {
|
|
|
168
165
|
threads: options.threads ?? 4,
|
|
169
166
|
onProgress: onFileProgress
|
|
170
167
|
});
|
|
171
|
-
|
|
168
|
+
options.logger?.info(
|
|
172
169
|
(0, import_ghost_story.formatSingleReport)(
|
|
173
170
|
transcription.timing,
|
|
174
171
|
`Transcription Timing Report for ${filepath}`
|
|
@@ -184,7 +181,7 @@ async function transcribe(input, output, locale, options) {
|
|
|
184
181
|
{ signal }
|
|
185
182
|
);
|
|
186
183
|
transcriptions.push(transcriptionFilepath);
|
|
187
|
-
|
|
184
|
+
options.onProgress?.((transcriptions.length + 1) / filenames.length);
|
|
188
185
|
} catch (_) {
|
|
189
186
|
var _error = _, _hasError = true;
|
|
190
187
|
} finally {
|
|
@@ -200,7 +197,6 @@ async function transcribe(input, output, locale, options) {
|
|
|
200
197
|
return timing;
|
|
201
198
|
}
|
|
202
199
|
async function transcribeFile(input, locale, options) {
|
|
203
|
-
var _a, _b;
|
|
204
200
|
const audioFilepath = (0, import_node_path.resolve)(process.cwd(), input);
|
|
205
201
|
const sharedOptions = {
|
|
206
202
|
signal: options.signal,
|
|
@@ -215,11 +211,11 @@ async function transcribeFile(input, locale, options) {
|
|
|
215
211
|
model: options.model,
|
|
216
212
|
variant: fallbackVariant,
|
|
217
213
|
printOutput: ["debug", "info"].includes(
|
|
218
|
-
|
|
214
|
+
options.logger?.level ?? "silent"
|
|
219
215
|
),
|
|
220
216
|
signal: options.signal
|
|
221
217
|
});
|
|
222
|
-
|
|
218
|
+
options.logger?.info(`Transcribing audio file ${audioFilepath}`);
|
|
223
219
|
return (0, import_ghost_story.recognize)(audioFilepath, {
|
|
224
220
|
engine: options.engine,
|
|
225
221
|
options: {
|
|
@@ -228,12 +224,11 @@ async function transcribeFile(input, locale, options) {
|
|
|
228
224
|
processors: options.processors,
|
|
229
225
|
threads: options.threads,
|
|
230
226
|
onProgress: (progress) => {
|
|
231
|
-
var _a2;
|
|
232
227
|
if (options.onProgress) {
|
|
233
228
|
options.onProgress(progress);
|
|
234
229
|
return;
|
|
235
230
|
}
|
|
236
|
-
|
|
231
|
+
options.logger?.info(
|
|
237
232
|
`Transcribing ${audioFilepath} progress: ${Math.floor(progress * 100)}%`
|
|
238
233
|
);
|
|
239
234
|
},
|
|
@@ -15,7 +15,6 @@ import {
|
|
|
15
15
|
recognize
|
|
16
16
|
} from "@storyteller-platform/ghost-story";
|
|
17
17
|
async function transcribe(input, output, locale, options) {
|
|
18
|
-
var _a;
|
|
19
18
|
if (process.env["DEBUG_TRANSCRIBE"] === "true") {
|
|
20
19
|
const inspector = await import("node:inspector");
|
|
21
20
|
inspector.open(9231, "0.0.0.0", true);
|
|
@@ -40,7 +39,7 @@ async function transcribe(input, output, locale, options) {
|
|
|
40
39
|
await ensureWhisperInstalled({
|
|
41
40
|
model,
|
|
42
41
|
printOutput: ["debug", "info"].includes(
|
|
43
|
-
|
|
42
|
+
options.logger?.level ?? "silent"
|
|
44
43
|
),
|
|
45
44
|
signal
|
|
46
45
|
});
|
|
@@ -57,7 +56,6 @@ async function transcribe(input, output, locale, options) {
|
|
|
57
56
|
timing.setMetadata("threads", options.threads ?? 4);
|
|
58
57
|
await Promise.all(
|
|
59
58
|
filenames.map(async (filename) => {
|
|
60
|
-
var _a2, _b, _c;
|
|
61
59
|
var _stack = [];
|
|
62
60
|
try {
|
|
63
61
|
if (aborted()) throw new Error("Aborted");
|
|
@@ -71,7 +69,7 @@ async function transcribe(input, output, locale, options) {
|
|
|
71
69
|
encoding: "utf-8",
|
|
72
70
|
signal
|
|
73
71
|
});
|
|
74
|
-
|
|
72
|
+
options.logger?.info(`Found existing transcription for ${filepath}`);
|
|
75
73
|
transcriptions.push(transcriptionFilepath);
|
|
76
74
|
} catch {
|
|
77
75
|
}
|
|
@@ -82,13 +80,12 @@ async function transcribe(input, output, locale, options) {
|
|
|
82
80
|
});
|
|
83
81
|
await semaphore.wait();
|
|
84
82
|
function onFileProgress(progress) {
|
|
85
|
-
var _a3, _b2;
|
|
86
83
|
perFileProgress.set(filename, progress);
|
|
87
84
|
const updatedProgress = Array.from(perFileProgress.values()).reduce((acc, p) => acc + p) / filenames.length;
|
|
88
|
-
|
|
85
|
+
options.logger?.info(
|
|
89
86
|
`Progress: ${Math.floor(updatedProgress * 100)}%`
|
|
90
87
|
);
|
|
91
|
-
|
|
88
|
+
options.onProgress?.(updatedProgress);
|
|
92
89
|
}
|
|
93
90
|
const transcription = await transcribeFile(filepath, locale, {
|
|
94
91
|
...options,
|
|
@@ -99,7 +96,7 @@ async function transcribe(input, output, locale, options) {
|
|
|
99
96
|
threads: options.threads ?? 4,
|
|
100
97
|
onProgress: onFileProgress
|
|
101
98
|
});
|
|
102
|
-
|
|
99
|
+
options.logger?.info(
|
|
103
100
|
formatSingleReport(
|
|
104
101
|
transcription.timing,
|
|
105
102
|
`Transcription Timing Report for ${filepath}`
|
|
@@ -115,7 +112,7 @@ async function transcribe(input, output, locale, options) {
|
|
|
115
112
|
{ signal }
|
|
116
113
|
);
|
|
117
114
|
transcriptions.push(transcriptionFilepath);
|
|
118
|
-
|
|
115
|
+
options.onProgress?.((transcriptions.length + 1) / filenames.length);
|
|
119
116
|
} catch (_) {
|
|
120
117
|
var _error = _, _hasError = true;
|
|
121
118
|
} finally {
|
|
@@ -131,7 +128,6 @@ async function transcribe(input, output, locale, options) {
|
|
|
131
128
|
return timing;
|
|
132
129
|
}
|
|
133
130
|
async function transcribeFile(input, locale, options) {
|
|
134
|
-
var _a, _b;
|
|
135
131
|
const audioFilepath = resolve(process.cwd(), input);
|
|
136
132
|
const sharedOptions = {
|
|
137
133
|
signal: options.signal,
|
|
@@ -146,11 +142,11 @@ async function transcribeFile(input, locale, options) {
|
|
|
146
142
|
model: options.model,
|
|
147
143
|
variant: fallbackVariant,
|
|
148
144
|
printOutput: ["debug", "info"].includes(
|
|
149
|
-
|
|
145
|
+
options.logger?.level ?? "silent"
|
|
150
146
|
),
|
|
151
147
|
signal: options.signal
|
|
152
148
|
});
|
|
153
|
-
|
|
149
|
+
options.logger?.info(`Transcribing audio file ${audioFilepath}`);
|
|
154
150
|
return recognize(audioFilepath, {
|
|
155
151
|
engine: options.engine,
|
|
156
152
|
options: {
|
|
@@ -159,12 +155,11 @@ async function transcribeFile(input, locale, options) {
|
|
|
159
155
|
processors: options.processors,
|
|
160
156
|
threads: options.threads,
|
|
161
157
|
onProgress: (progress) => {
|
|
162
|
-
var _a2;
|
|
163
158
|
if (options.onProgress) {
|
|
164
159
|
options.onProgress(progress);
|
|
165
160
|
return;
|
|
166
161
|
}
|
|
167
|
-
|
|
162
|
+
options.logger?.info(
|
|
168
163
|
`Transcribing ${audioFilepath} progress: ${Math.floor(progress * 100)}%`
|
|
169
164
|
);
|
|
170
165
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@storyteller-platform/align",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.19",
|
|
4
4
|
"description": "A library and CLI for automatically aligning audiobooks and EPUBs to produce Media Overlays",
|
|
5
5
|
"author": "Shane Friedman",
|
|
6
6
|
"license": "MIT",
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"@optique/run": "^0.10.7",
|
|
62
62
|
"@storyteller-platform/audiobook": "^0.3.10",
|
|
63
63
|
"@storyteller-platform/epub": "^0.4.8",
|
|
64
|
-
"@storyteller-platform/ghost-story": "^0.1.
|
|
64
|
+
"@storyteller-platform/ghost-story": "^0.1.7",
|
|
65
65
|
"@storyteller-platform/transliteration": "^3.1.1",
|
|
66
66
|
"chalk": "^5.4.1",
|
|
67
67
|
"cli-progress": "^3.12.0",
|