@storyteller-platform/ghost-story 0.0.1
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/LICENSE.md +611 -0
- package/README.md +18 -0
- package/dist/api/APIOptions.cjs +16 -0
- package/dist/api/APIOptions.d.cts +18 -0
- package/dist/api/APIOptions.d.ts +18 -0
- package/dist/api/APIOptions.js +0 -0
- package/dist/api/Recognition.cjs +263 -0
- package/dist/api/Recognition.d.cts +77 -0
- package/dist/api/Recognition.d.ts +77 -0
- package/dist/api/Recognition.js +233 -0
- package/dist/api/VoiceActivityDetection.cjs +77 -0
- package/dist/api/VoiceActivityDetection.d.cts +24 -0
- package/dist/api/VoiceActivityDetection.d.ts +24 -0
- package/dist/api/VoiceActivityDetection.js +43 -0
- package/dist/audio/AudioConverter.cjs +331 -0
- package/dist/audio/AudioConverter.d.cts +53 -0
- package/dist/audio/AudioConverter.d.ts +53 -0
- package/dist/audio/AudioConverter.js +310 -0
- package/dist/audio/AudioFormat.cjs +151 -0
- package/dist/audio/AudioFormat.d.cts +25 -0
- package/dist/audio/AudioFormat.d.ts +25 -0
- package/dist/audio/AudioFormat.js +123 -0
- package/dist/audio/AudioSource.cjs +119 -0
- package/dist/audio/AudioSource.d.cts +33 -0
- package/dist/audio/AudioSource.d.ts +33 -0
- package/dist/audio/AudioSource.js +88 -0
- package/dist/audio/index.cjs +74 -0
- package/dist/audio/index.d.cts +6 -0
- package/dist/audio/index.d.ts +6 -0
- package/dist/audio/index.js +54 -0
- package/dist/cli/bin.cjs +277 -0
- package/dist/cli/bin.d.cts +1 -0
- package/dist/cli/bin.d.ts +1 -0
- package/dist/cli/bin.js +275 -0
- package/dist/cli/config.cjs +347 -0
- package/dist/cli/config.d.cts +33 -0
- package/dist/cli/config.d.ts +33 -0
- package/dist/cli/config.js +285 -0
- package/dist/cli/install.cjs +334 -0
- package/dist/cli/install.d.cts +62 -0
- package/dist/cli/install.d.ts +62 -0
- package/dist/cli/install.js +316 -0
- package/dist/cli/whisper-server.cjs +172 -0
- package/dist/cli/whisper-server.d.cts +24 -0
- package/dist/cli/whisper-server.d.ts +24 -0
- package/dist/cli/whisper-server.js +152 -0
- package/dist/config.cjs +60 -0
- package/dist/config.d.cts +12 -0
- package/dist/config.d.ts +12 -0
- package/dist/config.js +32 -0
- package/dist/convert.cjs +88 -0
- package/dist/convert.d.cts +12 -0
- package/dist/convert.d.ts +12 -0
- package/dist/convert.js +63 -0
- package/dist/encodings/Ascii.cjs +75 -0
- package/dist/encodings/Ascii.d.cts +13 -0
- package/dist/encodings/Ascii.d.ts +13 -0
- package/dist/encodings/Ascii.js +48 -0
- package/dist/encodings/Base64.cjs +155 -0
- package/dist/encodings/Base64.d.cts +5 -0
- package/dist/encodings/Base64.d.ts +5 -0
- package/dist/encodings/Base64.js +129 -0
- package/dist/encodings/TextEncodingsCommon.cjs +16 -0
- package/dist/encodings/TextEncodingsCommon.d.cts +6 -0
- package/dist/encodings/TextEncodingsCommon.d.ts +6 -0
- package/dist/encodings/TextEncodingsCommon.js +0 -0
- package/dist/index.cjs +153 -0
- package/dist/index.d.cts +15 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +140 -0
- package/dist/recognition/AmazonTranscribeSTT.cjs +188 -0
- package/dist/recognition/AmazonTranscribeSTT.d.cts +21 -0
- package/dist/recognition/AmazonTranscribeSTT.d.ts +21 -0
- package/dist/recognition/AmazonTranscribeSTT.js +160 -0
- package/dist/recognition/AzureCognitiveServicesSTT.cjs +124 -0
- package/dist/recognition/AzureCognitiveServicesSTT.d.cts +21 -0
- package/dist/recognition/AzureCognitiveServicesSTT.d.ts +21 -0
- package/dist/recognition/AzureCognitiveServicesSTT.js +95 -0
- package/dist/recognition/DeepgramSTT.cjs +172 -0
- package/dist/recognition/DeepgramSTT.d.cts +23 -0
- package/dist/recognition/DeepgramSTT.d.ts +23 -0
- package/dist/recognition/DeepgramSTT.js +153 -0
- package/dist/recognition/GoogleCloudSTT.cjs +125 -0
- package/dist/recognition/GoogleCloudSTT.d.cts +35 -0
- package/dist/recognition/GoogleCloudSTT.d.ts +35 -0
- package/dist/recognition/GoogleCloudSTT.js +107 -0
- package/dist/recognition/OpenAICloudSTT.cjs +180 -0
- package/dist/recognition/OpenAICloudSTT.d.cts +29 -0
- package/dist/recognition/OpenAICloudSTT.d.ts +29 -0
- package/dist/recognition/OpenAICloudSTT.js +150 -0
- package/dist/recognition/WhisperCppSTT.cjs +296 -0
- package/dist/recognition/WhisperCppSTT.d.cts +40 -0
- package/dist/recognition/WhisperCppSTT.d.ts +40 -0
- package/dist/recognition/WhisperCppSTT.js +275 -0
- package/dist/recognition/WhisperServerSTT.cjs +119 -0
- package/dist/recognition/WhisperServerSTT.d.cts +24 -0
- package/dist/recognition/WhisperServerSTT.d.ts +24 -0
- package/dist/recognition/WhisperServerSTT.js +105 -0
- package/dist/utilities/FileSystem.cjs +54 -0
- package/dist/utilities/FileSystem.d.cts +3 -0
- package/dist/utilities/FileSystem.d.ts +3 -0
- package/dist/utilities/FileSystem.js +20 -0
- package/dist/utilities/Locale.cjs +46 -0
- package/dist/utilities/Locale.d.cts +9 -0
- package/dist/utilities/Locale.d.ts +9 -0
- package/dist/utilities/Locale.js +20 -0
- package/dist/utilities/ObjectUtilities.cjs +41 -0
- package/dist/utilities/ObjectUtilities.d.cts +3 -0
- package/dist/utilities/ObjectUtilities.d.ts +3 -0
- package/dist/utilities/ObjectUtilities.js +7 -0
- package/dist/utilities/Timeline.cjs +120 -0
- package/dist/utilities/Timeline.d.cts +23 -0
- package/dist/utilities/Timeline.d.ts +23 -0
- package/dist/utilities/Timeline.js +94 -0
- package/dist/utilities/Timing.cjs +287 -0
- package/dist/utilities/Timing.d.cts +64 -0
- package/dist/utilities/Timing.d.ts +64 -0
- package/dist/utilities/Timing.js +256 -0
- package/dist/utilities/WhisperTimeline.cjs +344 -0
- package/dist/utilities/WhisperTimeline.d.cts +86 -0
- package/dist/utilities/WhisperTimeline.d.ts +86 -0
- package/dist/utilities/WhisperTimeline.js +313 -0
- package/dist/vad/ActiveGate.cjs +357 -0
- package/dist/vad/ActiveGate.d.cts +53 -0
- package/dist/vad/ActiveGate.d.ts +53 -0
- package/dist/vad/ActiveGate.js +329 -0
- package/dist/vad/ActiveGateOg.cjs +1366 -0
- package/dist/vad/ActiveGateOg.d.cts +33 -0
- package/dist/vad/ActiveGateOg.d.ts +33 -0
- package/dist/vad/ActiveGateOg.js +1341 -0
- package/dist/vad/Silero.cjs +174 -0
- package/dist/vad/Silero.d.cts +25 -0
- package/dist/vad/Silero.d.ts +25 -0
- package/dist/vad/Silero.js +153 -0
- package/package.json +125 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
var VoiceActivityDetection_exports = {};
|
|
30
|
+
__export(VoiceActivityDetection_exports, {
|
|
31
|
+
detectVoiceActivity: () => detectVoiceActivity
|
|
32
|
+
});
|
|
33
|
+
module.exports = __toCommonJS(VoiceActivityDetection_exports);
|
|
34
|
+
var import_ObjectUtilities = require("../utilities/ObjectUtilities.cjs");
|
|
35
|
+
const defaultVoiceActivityDetectionOptions = {
|
|
36
|
+
engine: "active-gate-og"
|
|
37
|
+
};
|
|
38
|
+
async function detectVoiceActivity(inputPath, options = defaultVoiceActivityDetectionOptions) {
|
|
39
|
+
const opts = (0, import_ObjectUtilities.extendDeep)(defaultVoiceActivityDetectionOptions, options);
|
|
40
|
+
switch (opts.engine) {
|
|
41
|
+
case "silero": {
|
|
42
|
+
const SileroVAD = await import("../vad/Silero.cjs");
|
|
43
|
+
const sileroOpts = "silero" in opts ? opts.silero : void 0;
|
|
44
|
+
return SileroVAD.detectVoiceActivity(inputPath, sileroOpts);
|
|
45
|
+
}
|
|
46
|
+
case "active-gate-og": {
|
|
47
|
+
const ActiveGateOgVAD = await import("../vad/ActiveGateOg.cjs");
|
|
48
|
+
const activeGateOgOpts = "activeGateOg" in opts ? opts.activeGateOg : void 0;
|
|
49
|
+
const timeline = await ActiveGateOgVAD.detectVoiceActivity(
|
|
50
|
+
inputPath,
|
|
51
|
+
activeGateOgOpts
|
|
52
|
+
);
|
|
53
|
+
return timeline.map((seg) => ({
|
|
54
|
+
startTime: seg.startTime,
|
|
55
|
+
endTime: seg.endTime,
|
|
56
|
+
isSpeech: seg.type === "segment" && seg.text === "active"
|
|
57
|
+
}));
|
|
58
|
+
}
|
|
59
|
+
case "active-gate": {
|
|
60
|
+
const ActiveGateVAD = await import("../vad/ActiveGate.cjs");
|
|
61
|
+
const activeGateOpts = "activeGate" in opts ? opts.activeGate : void 0;
|
|
62
|
+
const segments = await ActiveGateVAD.vadFromFile(
|
|
63
|
+
inputPath,
|
|
64
|
+
activeGateOpts
|
|
65
|
+
);
|
|
66
|
+
return segments.map((seg) => ({
|
|
67
|
+
startTime: seg.startTime,
|
|
68
|
+
endTime: seg.endTime,
|
|
69
|
+
isSpeech: seg.isActive
|
|
70
|
+
}));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
75
|
+
0 && (module.exports = {
|
|
76
|
+
detectVoiceActivity
|
|
77
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { StreamOptions } from '../vad/ActiveGate.cjs';
|
|
2
|
+
import { AdaptiveGateVADOptions } from '../vad/ActiveGateOg.cjs';
|
|
3
|
+
import { SileroOptions } from '../vad/Silero.cjs';
|
|
4
|
+
import 'node:stream';
|
|
5
|
+
import '../utilities/Timeline.cjs';
|
|
6
|
+
|
|
7
|
+
interface VadSegment {
|
|
8
|
+
startTime: number;
|
|
9
|
+
endTime: number;
|
|
10
|
+
isSpeech: boolean;
|
|
11
|
+
}
|
|
12
|
+
type VoiceActivityDetectionOptions = {
|
|
13
|
+
engine: "silero";
|
|
14
|
+
silero?: SileroOptions;
|
|
15
|
+
} | {
|
|
16
|
+
engine: "active-gate";
|
|
17
|
+
activeGate?: StreamOptions;
|
|
18
|
+
} | {
|
|
19
|
+
engine: "active-gate-og";
|
|
20
|
+
activeGateOg?: AdaptiveGateVADOptions;
|
|
21
|
+
};
|
|
22
|
+
declare function detectVoiceActivity(inputPath: string, options?: VoiceActivityDetectionOptions): Promise<VadSegment[]>;
|
|
23
|
+
|
|
24
|
+
export { type VadSegment, type VoiceActivityDetectionOptions, detectVoiceActivity };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { StreamOptions } from '../vad/ActiveGate.js';
|
|
2
|
+
import { AdaptiveGateVADOptions } from '../vad/ActiveGateOg.js';
|
|
3
|
+
import { SileroOptions } from '../vad/Silero.js';
|
|
4
|
+
import 'node:stream';
|
|
5
|
+
import '../utilities/Timeline.js';
|
|
6
|
+
|
|
7
|
+
interface VadSegment {
|
|
8
|
+
startTime: number;
|
|
9
|
+
endTime: number;
|
|
10
|
+
isSpeech: boolean;
|
|
11
|
+
}
|
|
12
|
+
type VoiceActivityDetectionOptions = {
|
|
13
|
+
engine: "silero";
|
|
14
|
+
silero?: SileroOptions;
|
|
15
|
+
} | {
|
|
16
|
+
engine: "active-gate";
|
|
17
|
+
activeGate?: StreamOptions;
|
|
18
|
+
} | {
|
|
19
|
+
engine: "active-gate-og";
|
|
20
|
+
activeGateOg?: AdaptiveGateVADOptions;
|
|
21
|
+
};
|
|
22
|
+
declare function detectVoiceActivity(inputPath: string, options?: VoiceActivityDetectionOptions): Promise<VadSegment[]>;
|
|
23
|
+
|
|
24
|
+
export { type VadSegment, type VoiceActivityDetectionOptions, detectVoiceActivity };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { extendDeep } from "../utilities/ObjectUtilities.js";
|
|
2
|
+
const defaultVoiceActivityDetectionOptions = {
|
|
3
|
+
engine: "active-gate-og"
|
|
4
|
+
};
|
|
5
|
+
async function detectVoiceActivity(inputPath, options = defaultVoiceActivityDetectionOptions) {
|
|
6
|
+
const opts = extendDeep(defaultVoiceActivityDetectionOptions, options);
|
|
7
|
+
switch (opts.engine) {
|
|
8
|
+
case "silero": {
|
|
9
|
+
const SileroVAD = await import("../vad/Silero.js");
|
|
10
|
+
const sileroOpts = "silero" in opts ? opts.silero : void 0;
|
|
11
|
+
return SileroVAD.detectVoiceActivity(inputPath, sileroOpts);
|
|
12
|
+
}
|
|
13
|
+
case "active-gate-og": {
|
|
14
|
+
const ActiveGateOgVAD = await import("../vad/ActiveGateOg.js");
|
|
15
|
+
const activeGateOgOpts = "activeGateOg" in opts ? opts.activeGateOg : void 0;
|
|
16
|
+
const timeline = await ActiveGateOgVAD.detectVoiceActivity(
|
|
17
|
+
inputPath,
|
|
18
|
+
activeGateOgOpts
|
|
19
|
+
);
|
|
20
|
+
return timeline.map((seg) => ({
|
|
21
|
+
startTime: seg.startTime,
|
|
22
|
+
endTime: seg.endTime,
|
|
23
|
+
isSpeech: seg.type === "segment" && seg.text === "active"
|
|
24
|
+
}));
|
|
25
|
+
}
|
|
26
|
+
case "active-gate": {
|
|
27
|
+
const ActiveGateVAD = await import("../vad/ActiveGate.js");
|
|
28
|
+
const activeGateOpts = "activeGate" in opts ? opts.activeGate : void 0;
|
|
29
|
+
const segments = await ActiveGateVAD.vadFromFile(
|
|
30
|
+
inputPath,
|
|
31
|
+
activeGateOpts
|
|
32
|
+
);
|
|
33
|
+
return segments.map((seg) => ({
|
|
34
|
+
startTime: seg.startTime,
|
|
35
|
+
endTime: seg.endTime,
|
|
36
|
+
isSpeech: seg.isActive
|
|
37
|
+
}));
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
export {
|
|
42
|
+
detectVoiceActivity
|
|
43
|
+
};
|
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var AudioConverter_exports = {};
|
|
20
|
+
__export(AudioConverter_exports, {
|
|
21
|
+
convertToBuffer: () => convertToBuffer,
|
|
22
|
+
convertToFile: () => convertToFile,
|
|
23
|
+
convertToStream: () => convertToStream,
|
|
24
|
+
createStreamForUpload: () => createStreamForUpload,
|
|
25
|
+
createStreamingConversion: () => createStreamingConversion,
|
|
26
|
+
getAudioDuration: () => getAudioDuration,
|
|
27
|
+
prepareForService: () => prepareForService,
|
|
28
|
+
prepareWavForService: () => prepareWavForService
|
|
29
|
+
});
|
|
30
|
+
module.exports = __toCommonJS(AudioConverter_exports);
|
|
31
|
+
var import_node_child_process = require("node:child_process");
|
|
32
|
+
var import_node_fs = require("node:fs");
|
|
33
|
+
var import_promises = require("node:fs/promises");
|
|
34
|
+
var import_node_os = require("node:os");
|
|
35
|
+
var import_node_path = require("node:path");
|
|
36
|
+
var import_promises2 = require("node:stream/promises");
|
|
37
|
+
var import_node_util = require("node:util");
|
|
38
|
+
var import_ffmpeg_stream = require("ffmpeg-stream");
|
|
39
|
+
var import_config = require("../config.cjs");
|
|
40
|
+
var import_AudioFormat = require("./AudioFormat.cjs");
|
|
41
|
+
var import_AudioSource = require("./AudioSource.cjs");
|
|
42
|
+
const execFilePromisified = (0, import_node_util.promisify)(import_node_child_process.execFile);
|
|
43
|
+
async function execFileAsync(cmd, args) {
|
|
44
|
+
return execFilePromisified(cmd, args);
|
|
45
|
+
}
|
|
46
|
+
function getFFmpegFormatOptions(format, sampleRate, channels) {
|
|
47
|
+
const opts = {};
|
|
48
|
+
switch (format) {
|
|
49
|
+
case "wav":
|
|
50
|
+
opts["f"] = "wav";
|
|
51
|
+
opts["acodec"] = "pcm_s16le";
|
|
52
|
+
break;
|
|
53
|
+
case "flac":
|
|
54
|
+
opts["f"] = "flac";
|
|
55
|
+
opts["acodec"] = "flac";
|
|
56
|
+
break;
|
|
57
|
+
case "opus":
|
|
58
|
+
opts["f"] = "ogg";
|
|
59
|
+
opts["acodec"] = "libopus";
|
|
60
|
+
break;
|
|
61
|
+
case "ogg":
|
|
62
|
+
opts["f"] = "ogg";
|
|
63
|
+
opts["acodec"] = "libvorbis";
|
|
64
|
+
break;
|
|
65
|
+
case "mp3":
|
|
66
|
+
opts["f"] = "mp3";
|
|
67
|
+
opts["acodec"] = "libmp3lame";
|
|
68
|
+
break;
|
|
69
|
+
default:
|
|
70
|
+
opts["f"] = format;
|
|
71
|
+
}
|
|
72
|
+
if (sampleRate) {
|
|
73
|
+
opts["ar"] = String(sampleRate);
|
|
74
|
+
}
|
|
75
|
+
if (channels) {
|
|
76
|
+
opts["ac"] = String(channels);
|
|
77
|
+
}
|
|
78
|
+
return opts;
|
|
79
|
+
}
|
|
80
|
+
function getFFmpegInputFormat(format) {
|
|
81
|
+
switch (format) {
|
|
82
|
+
case "pcm":
|
|
83
|
+
return { f: "s16le", ar: "16000", ac: "1" };
|
|
84
|
+
default:
|
|
85
|
+
return {};
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
async function convertToFile(source, options) {
|
|
89
|
+
const tempPath = (0, import_node_path.join)(
|
|
90
|
+
(0, import_node_os.tmpdir)(),
|
|
91
|
+
`audio-convert-${Date.now()}${(0, import_AudioFormat.formatToExtension)(options.targetFormat)}`
|
|
92
|
+
);
|
|
93
|
+
const converter = new import_ffmpeg_stream.Converter();
|
|
94
|
+
const inputPath = (0, import_AudioSource.toFilePath)(source);
|
|
95
|
+
if (inputPath) {
|
|
96
|
+
converter.createInputFromFile(inputPath);
|
|
97
|
+
} else {
|
|
98
|
+
const inputOpts = getFFmpegInputFormat(source.format);
|
|
99
|
+
const inputStream = converter.createInputStream(inputOpts);
|
|
100
|
+
const readable = (0, import_AudioSource.toReadStream)(source);
|
|
101
|
+
readable.pipe(inputStream);
|
|
102
|
+
}
|
|
103
|
+
const outputOpts = getFFmpegFormatOptions(
|
|
104
|
+
options.targetFormat,
|
|
105
|
+
options.sampleRate,
|
|
106
|
+
options.channels
|
|
107
|
+
);
|
|
108
|
+
converter.createOutputToFile(tempPath, outputOpts);
|
|
109
|
+
await converter.run();
|
|
110
|
+
return {
|
|
111
|
+
source: (0, import_AudioSource.audioSourceFromFile)(tempPath, options.targetFormat),
|
|
112
|
+
cleanup: async () => {
|
|
113
|
+
await (0, import_promises.rm)(tempPath, { force: true }).catch(() => {
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
async function convertToBuffer(source, options) {
|
|
119
|
+
const converter = new import_ffmpeg_stream.Converter();
|
|
120
|
+
const inputPath = (0, import_AudioSource.toFilePath)(source);
|
|
121
|
+
if (inputPath) {
|
|
122
|
+
converter.createInputFromFile(inputPath);
|
|
123
|
+
} else {
|
|
124
|
+
const inputOpts = getFFmpegInputFormat(source.format);
|
|
125
|
+
const inputStream = converter.createInputStream(inputOpts);
|
|
126
|
+
const readable = (0, import_AudioSource.toReadStream)(source);
|
|
127
|
+
readable.pipe(inputStream);
|
|
128
|
+
}
|
|
129
|
+
const outputOpts = getFFmpegFormatOptions(
|
|
130
|
+
options.targetFormat,
|
|
131
|
+
options.sampleRate,
|
|
132
|
+
options.channels
|
|
133
|
+
);
|
|
134
|
+
const outputStream = converter.createOutputStream(outputOpts);
|
|
135
|
+
const chunks = [];
|
|
136
|
+
outputStream.on("data", (chunk) => chunks.push(chunk));
|
|
137
|
+
const bufferPromise = new Promise((resolve, reject) => {
|
|
138
|
+
outputStream.on("end", () => {
|
|
139
|
+
resolve(Buffer.concat(chunks));
|
|
140
|
+
});
|
|
141
|
+
outputStream.on("error", reject);
|
|
142
|
+
});
|
|
143
|
+
await converter.run();
|
|
144
|
+
const buffer = await bufferPromise;
|
|
145
|
+
return {
|
|
146
|
+
source: (0, import_AudioSource.audioSourceFromBuffer)(buffer, options.targetFormat),
|
|
147
|
+
cleanup: async () => {
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
function convertToStream(source, options) {
|
|
152
|
+
const converter = new import_ffmpeg_stream.Converter();
|
|
153
|
+
const inputPath = (0, import_AudioSource.toFilePath)(source);
|
|
154
|
+
if (inputPath) {
|
|
155
|
+
converter.createInputFromFile(inputPath);
|
|
156
|
+
} else {
|
|
157
|
+
const inputOpts = getFFmpegInputFormat(source.format);
|
|
158
|
+
const inputStream = converter.createInputStream(inputOpts);
|
|
159
|
+
const readable = (0, import_AudioSource.toReadStream)(source);
|
|
160
|
+
readable.pipe(inputStream);
|
|
161
|
+
}
|
|
162
|
+
const outputOpts = getFFmpegFormatOptions(
|
|
163
|
+
options.targetFormat,
|
|
164
|
+
options.sampleRate,
|
|
165
|
+
options.channels
|
|
166
|
+
);
|
|
167
|
+
const outputStream = converter.createOutputStream(outputOpts);
|
|
168
|
+
return {
|
|
169
|
+
stream: outputStream,
|
|
170
|
+
runConversion: () => converter.run()
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
async function prepareForService(source, options) {
|
|
174
|
+
const caps = import_AudioFormat.serviceCapabilities[options.service];
|
|
175
|
+
if (!caps) {
|
|
176
|
+
throw new Error(`Unknown service: ${options.service}`);
|
|
177
|
+
}
|
|
178
|
+
const inputFormat = source.format;
|
|
179
|
+
const requiresConversion = (0, import_AudioFormat.needsConversion)(inputFormat, options.service);
|
|
180
|
+
const targetFormat = (0, import_AudioFormat.getTargetFormat)(inputFormat, options.service);
|
|
181
|
+
if (!requiresConversion) {
|
|
182
|
+
if (caps.requiresFile && source.type !== "file") {
|
|
183
|
+
return writeToTempFile(source);
|
|
184
|
+
}
|
|
185
|
+
return { source, cleanup: async () => {
|
|
186
|
+
} };
|
|
187
|
+
}
|
|
188
|
+
const conversionOptions = {
|
|
189
|
+
targetFormat,
|
|
190
|
+
sampleRate: caps.preferredSampleRate,
|
|
191
|
+
channels: caps.preferredChannels
|
|
192
|
+
};
|
|
193
|
+
if (caps.requiresFile || options.preferFile) {
|
|
194
|
+
return convertToFile(source, conversionOptions);
|
|
195
|
+
}
|
|
196
|
+
if (caps.requiresBase64) {
|
|
197
|
+
return convertToBuffer(source, conversionOptions);
|
|
198
|
+
}
|
|
199
|
+
return convertToFile(source, conversionOptions);
|
|
200
|
+
}
|
|
201
|
+
async function writeToTempFile(source) {
|
|
202
|
+
const tempPath = (0, import_node_path.join)(
|
|
203
|
+
(0, import_node_os.tmpdir)(),
|
|
204
|
+
`audio-temp-${Date.now()}${(0, import_AudioFormat.formatToExtension)(source.format)}`
|
|
205
|
+
);
|
|
206
|
+
const readable = (0, import_AudioSource.toReadStream)(source);
|
|
207
|
+
const writable = (0, import_node_fs.createWriteStream)(tempPath);
|
|
208
|
+
await (0, import_promises2.pipeline)(readable, writable);
|
|
209
|
+
return {
|
|
210
|
+
source: (0, import_AudioSource.audioSourceFromFile)(tempPath, source.format),
|
|
211
|
+
cleanup: async () => {
|
|
212
|
+
await (0, import_promises.rm)(tempPath, { force: true }).catch(() => {
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
async function prepareWavForService(source, options = {}) {
|
|
218
|
+
if (source.format === "wav" && source.type === "file") {
|
|
219
|
+
return { source, cleanup: async () => {
|
|
220
|
+
} };
|
|
221
|
+
}
|
|
222
|
+
return convertToFile(source, {
|
|
223
|
+
targetFormat: "wav",
|
|
224
|
+
sampleRate: options.sampleRate ?? 16e3,
|
|
225
|
+
channels: options.channels ?? 1
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
function createStreamingConversion(source, options) {
|
|
229
|
+
const { stream, runConversion } = convertToStream(source, options);
|
|
230
|
+
return { stream, start: runConversion };
|
|
231
|
+
}
|
|
232
|
+
async function createStreamForUpload(options) {
|
|
233
|
+
const mode = options.mode ?? (0, import_config.getConversionMode)();
|
|
234
|
+
const needsConvert = options.source.format !== options.targetFormat;
|
|
235
|
+
if (!needsConvert) {
|
|
236
|
+
const stream = (0, import_AudioSource.toReadStream)(options.source);
|
|
237
|
+
return {
|
|
238
|
+
stream,
|
|
239
|
+
format: options.source.format,
|
|
240
|
+
cleanup: async () => {
|
|
241
|
+
},
|
|
242
|
+
mode
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
if (mode === "file-first") {
|
|
246
|
+
const tempPath = (0, import_node_path.join)(
|
|
247
|
+
(0, import_node_os.tmpdir)(),
|
|
248
|
+
`upload-${Date.now()}${(0, import_AudioFormat.formatToExtension)(options.targetFormat)}`
|
|
249
|
+
);
|
|
250
|
+
const converter2 = new import_ffmpeg_stream.Converter();
|
|
251
|
+
const inputPath2 = (0, import_AudioSource.toFilePath)(options.source);
|
|
252
|
+
if (inputPath2) {
|
|
253
|
+
converter2.createInputFromFile(inputPath2);
|
|
254
|
+
} else {
|
|
255
|
+
const inputOpts = getFFmpegInputFormat(options.source.format);
|
|
256
|
+
const inputStream = converter2.createInputStream(inputOpts);
|
|
257
|
+
const readable = (0, import_AudioSource.toReadStream)(options.source);
|
|
258
|
+
readable.pipe(inputStream);
|
|
259
|
+
}
|
|
260
|
+
const outputOpts2 = getFFmpegFormatOptions(
|
|
261
|
+
options.targetFormat,
|
|
262
|
+
options.sampleRate,
|
|
263
|
+
options.channels
|
|
264
|
+
);
|
|
265
|
+
converter2.createOutputToFile(tempPath, outputOpts2);
|
|
266
|
+
await converter2.run();
|
|
267
|
+
const stream = (0, import_node_fs.createReadStream)(tempPath);
|
|
268
|
+
return {
|
|
269
|
+
stream,
|
|
270
|
+
format: options.targetFormat,
|
|
271
|
+
cleanup: async () => {
|
|
272
|
+
await (0, import_promises.rm)(tempPath, { force: true }).catch(() => {
|
|
273
|
+
});
|
|
274
|
+
},
|
|
275
|
+
mode
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
const converter = new import_ffmpeg_stream.Converter();
|
|
279
|
+
const inputPath = (0, import_AudioSource.toFilePath)(options.source);
|
|
280
|
+
if (inputPath) {
|
|
281
|
+
converter.createInputFromFile(inputPath);
|
|
282
|
+
} else {
|
|
283
|
+
const inputOpts = getFFmpegInputFormat(options.source.format);
|
|
284
|
+
const inputStream = converter.createInputStream(inputOpts);
|
|
285
|
+
const readable = (0, import_AudioSource.toReadStream)(options.source);
|
|
286
|
+
readable.pipe(inputStream);
|
|
287
|
+
}
|
|
288
|
+
const outputOpts = getFFmpegFormatOptions(
|
|
289
|
+
options.targetFormat,
|
|
290
|
+
options.sampleRate,
|
|
291
|
+
options.channels
|
|
292
|
+
);
|
|
293
|
+
const outputStream = converter.createOutputStream(outputOpts);
|
|
294
|
+
return {
|
|
295
|
+
stream: outputStream,
|
|
296
|
+
format: options.targetFormat,
|
|
297
|
+
cleanup: async () => {
|
|
298
|
+
},
|
|
299
|
+
start: () => converter.run(),
|
|
300
|
+
mode
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
async function getAudioDuration(filePath) {
|
|
304
|
+
const { stdout } = await execFileAsync("ffprobe", [
|
|
305
|
+
"-v",
|
|
306
|
+
"quiet",
|
|
307
|
+
"-show_entries",
|
|
308
|
+
"format=duration",
|
|
309
|
+
"-of",
|
|
310
|
+
"default=noprint_wrappers=1:nokey=1",
|
|
311
|
+
filePath
|
|
312
|
+
]);
|
|
313
|
+
const duration = parseFloat(stdout.trim());
|
|
314
|
+
if (Number.isNaN(duration)) {
|
|
315
|
+
throw new Error(
|
|
316
|
+
`Failed to parse audio duration from ffprobe output: ${stdout}`
|
|
317
|
+
);
|
|
318
|
+
}
|
|
319
|
+
return duration;
|
|
320
|
+
}
|
|
321
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
322
|
+
0 && (module.exports = {
|
|
323
|
+
convertToBuffer,
|
|
324
|
+
convertToFile,
|
|
325
|
+
convertToStream,
|
|
326
|
+
createStreamForUpload,
|
|
327
|
+
createStreamingConversion,
|
|
328
|
+
getAudioDuration,
|
|
329
|
+
prepareForService,
|
|
330
|
+
prepareWavForService
|
|
331
|
+
});
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { AudioFormat } from './AudioFormat.cjs';
|
|
2
|
+
import { AudioSource } from './AudioSource.cjs';
|
|
3
|
+
import { Readable } from 'node:stream';
|
|
4
|
+
import { ConversionMode } from '../config.cjs';
|
|
5
|
+
import 'node:fs';
|
|
6
|
+
|
|
7
|
+
interface ConversionOptions {
|
|
8
|
+
targetFormat: AudioFormat;
|
|
9
|
+
sampleRate?: number | undefined;
|
|
10
|
+
channels?: number | undefined;
|
|
11
|
+
}
|
|
12
|
+
interface PreparedAudio {
|
|
13
|
+
source: AudioSource;
|
|
14
|
+
cleanup: () => Promise<void>;
|
|
15
|
+
}
|
|
16
|
+
declare function convertToFile(source: AudioSource, options: ConversionOptions): Promise<PreparedAudio>;
|
|
17
|
+
declare function convertToBuffer(source: AudioSource, options: ConversionOptions): Promise<PreparedAudio>;
|
|
18
|
+
declare function convertToStream(source: AudioSource, options: ConversionOptions): {
|
|
19
|
+
stream: Readable;
|
|
20
|
+
runConversion: () => Promise<void>;
|
|
21
|
+
};
|
|
22
|
+
interface PrepareForServiceOptions {
|
|
23
|
+
service: string;
|
|
24
|
+
preferFile?: boolean;
|
|
25
|
+
preferStream?: boolean;
|
|
26
|
+
}
|
|
27
|
+
declare function prepareForService(source: AudioSource, options: PrepareForServiceOptions): Promise<PreparedAudio>;
|
|
28
|
+
declare function prepareWavForService(source: AudioSource, options?: {
|
|
29
|
+
sampleRate?: number | undefined;
|
|
30
|
+
channels?: number | undefined;
|
|
31
|
+
}): Promise<PreparedAudio>;
|
|
32
|
+
declare function createStreamingConversion(source: AudioSource, options: ConversionOptions): {
|
|
33
|
+
stream: Readable;
|
|
34
|
+
start: () => Promise<void>;
|
|
35
|
+
};
|
|
36
|
+
interface StreamForUploadOptions {
|
|
37
|
+
source: AudioSource;
|
|
38
|
+
targetFormat: AudioFormat;
|
|
39
|
+
sampleRate?: number | undefined;
|
|
40
|
+
channels?: number | undefined;
|
|
41
|
+
mode?: ConversionMode | undefined;
|
|
42
|
+
}
|
|
43
|
+
interface StreamForUploadResult {
|
|
44
|
+
stream: Readable;
|
|
45
|
+
format: AudioFormat;
|
|
46
|
+
cleanup: () => Promise<void>;
|
|
47
|
+
start?: () => Promise<void>;
|
|
48
|
+
mode: ConversionMode;
|
|
49
|
+
}
|
|
50
|
+
declare function createStreamForUpload(options: StreamForUploadOptions): Promise<StreamForUploadResult>;
|
|
51
|
+
declare function getAudioDuration(filePath: string): Promise<number>;
|
|
52
|
+
|
|
53
|
+
export { type ConversionOptions, type PrepareForServiceOptions, type PreparedAudio, type StreamForUploadOptions, type StreamForUploadResult, convertToBuffer, convertToFile, convertToStream, createStreamForUpload, createStreamingConversion, getAudioDuration, prepareForService, prepareWavForService };
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { AudioFormat } from './AudioFormat.js';
|
|
2
|
+
import { AudioSource } from './AudioSource.js';
|
|
3
|
+
import { Readable } from 'node:stream';
|
|
4
|
+
import { ConversionMode } from '../config.js';
|
|
5
|
+
import 'node:fs';
|
|
6
|
+
|
|
7
|
+
interface ConversionOptions {
|
|
8
|
+
targetFormat: AudioFormat;
|
|
9
|
+
sampleRate?: number | undefined;
|
|
10
|
+
channels?: number | undefined;
|
|
11
|
+
}
|
|
12
|
+
interface PreparedAudio {
|
|
13
|
+
source: AudioSource;
|
|
14
|
+
cleanup: () => Promise<void>;
|
|
15
|
+
}
|
|
16
|
+
declare function convertToFile(source: AudioSource, options: ConversionOptions): Promise<PreparedAudio>;
|
|
17
|
+
declare function convertToBuffer(source: AudioSource, options: ConversionOptions): Promise<PreparedAudio>;
|
|
18
|
+
declare function convertToStream(source: AudioSource, options: ConversionOptions): {
|
|
19
|
+
stream: Readable;
|
|
20
|
+
runConversion: () => Promise<void>;
|
|
21
|
+
};
|
|
22
|
+
interface PrepareForServiceOptions {
|
|
23
|
+
service: string;
|
|
24
|
+
preferFile?: boolean;
|
|
25
|
+
preferStream?: boolean;
|
|
26
|
+
}
|
|
27
|
+
declare function prepareForService(source: AudioSource, options: PrepareForServiceOptions): Promise<PreparedAudio>;
|
|
28
|
+
declare function prepareWavForService(source: AudioSource, options?: {
|
|
29
|
+
sampleRate?: number | undefined;
|
|
30
|
+
channels?: number | undefined;
|
|
31
|
+
}): Promise<PreparedAudio>;
|
|
32
|
+
declare function createStreamingConversion(source: AudioSource, options: ConversionOptions): {
|
|
33
|
+
stream: Readable;
|
|
34
|
+
start: () => Promise<void>;
|
|
35
|
+
};
|
|
36
|
+
interface StreamForUploadOptions {
|
|
37
|
+
source: AudioSource;
|
|
38
|
+
targetFormat: AudioFormat;
|
|
39
|
+
sampleRate?: number | undefined;
|
|
40
|
+
channels?: number | undefined;
|
|
41
|
+
mode?: ConversionMode | undefined;
|
|
42
|
+
}
|
|
43
|
+
interface StreamForUploadResult {
|
|
44
|
+
stream: Readable;
|
|
45
|
+
format: AudioFormat;
|
|
46
|
+
cleanup: () => Promise<void>;
|
|
47
|
+
start?: () => Promise<void>;
|
|
48
|
+
mode: ConversionMode;
|
|
49
|
+
}
|
|
50
|
+
declare function createStreamForUpload(options: StreamForUploadOptions): Promise<StreamForUploadResult>;
|
|
51
|
+
declare function getAudioDuration(filePath: string): Promise<number>;
|
|
52
|
+
|
|
53
|
+
export { type ConversionOptions, type PrepareForServiceOptions, type PreparedAudio, type StreamForUploadOptions, type StreamForUploadResult, convertToBuffer, convertToFile, convertToStream, createStreamForUpload, createStreamingConversion, getAudioDuration, prepareForService, prepareWavForService };
|