lookatstudy-termux-voice 0.12.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/README.md +11 -0
- package/addon-static-import.js +70 -0
- package/addon.js +98 -0
- package/audio-tagg.js +45 -0
- package/keyword-spotter.js +68 -0
- package/libonnxruntime.so +0 -0
- package/libsherpa-onnx-c-api.so +0 -0
- package/non-streaming-asr.js +158 -0
- package/non-streaming-speaker-diarization.js +38 -0
- package/non-streaming-speech-denoiser.js +32 -0
- package/non-streaming-tts.js +116 -0
- package/online-speech-denoiser.js +46 -0
- package/package.json +68 -0
- package/punctuation.js +43 -0
- package/resampler.js +80 -0
- package/sherpa-onnx.js +49 -0
- package/sherpa-onnx.node +0 -0
- package/speaker-identification.js +152 -0
- package/spoken-language-identification.js +38 -0
- package/streaming-asr.js +130 -0
- package/types.js +787 -0
- package/vad.js +134 -0
package/README.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Introduction
|
|
2
|
+
|
|
3
|
+
Please see
|
|
4
|
+
https://github.com/k2-fsa/sherpa-onnx/blob/master/nodejs-addon-examples/README.md
|
|
5
|
+
for usages.
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
||Method|Support multiple threads|Minimum required node version|
|
|
9
|
+
|---|---|---|---|
|
|
10
|
+
|this package| https://github.com/nodejs/node-addon-api | Yes | v16|
|
|
11
|
+
|https://www.npmjs.com/package/sherpa-onnx| WebAssembly | No | v18|
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
const os = require('os');
|
|
2
|
+
|
|
3
|
+
let addon = null;
|
|
4
|
+
|
|
5
|
+
const platform = os.platform() === 'win32' ? 'win' : os.platform();
|
|
6
|
+
const arch = os.arch();
|
|
7
|
+
|
|
8
|
+
try {
|
|
9
|
+
if (arch === 'x64') {
|
|
10
|
+
if (platform === 'win') {
|
|
11
|
+
// @ts-expect-error
|
|
12
|
+
addon = require('../sherpa-onnx-win-x64/sherpa-onnx.node')
|
|
13
|
+
} else if (platform === 'darwin') {
|
|
14
|
+
// @ts-expect-error
|
|
15
|
+
addon = require('../sherpa-onnx-darwin-x64/sherpa-onnx.node')
|
|
16
|
+
} else if (platform === 'linux') {
|
|
17
|
+
// @ts-expect-error
|
|
18
|
+
addon = require('../sherpa-onnx-linux-x64/sherpa-onnx.node')
|
|
19
|
+
}
|
|
20
|
+
} else if (arch === 'arm64') {
|
|
21
|
+
if (platform === 'darwin') {
|
|
22
|
+
// @ts-expect-error
|
|
23
|
+
addon = require('../sherpa-onnx-darwin-arm64/sherpa-onnx.node')
|
|
24
|
+
} else if (platform === 'linux') {
|
|
25
|
+
// @ts-expect-error
|
|
26
|
+
addon = require('../sherpa-onnx-linux-arm64/sherpa-onnx.node')
|
|
27
|
+
}
|
|
28
|
+
} else if (arch === 'ia32') {
|
|
29
|
+
if (platform === 'win') {
|
|
30
|
+
// @ts-expect-error
|
|
31
|
+
addon = require('../sherpa-onnx-win-ia32/sherpa-onnx.node')
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
} catch (error) {
|
|
35
|
+
//
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (!addon) {
|
|
39
|
+
try {
|
|
40
|
+
if (arch === 'x64') {
|
|
41
|
+
if (platform === 'win') {
|
|
42
|
+
// @ts-expect-error
|
|
43
|
+
addon = require('./node_modules/sherpa-onnx-win-x64/sherpa-onnx.node')
|
|
44
|
+
} else if (platform === 'darwin') {
|
|
45
|
+
// @ts-expect-error
|
|
46
|
+
addon = require('./node_modules/sherpa-onnx-darwin-x64/sherpa-onnx.node')
|
|
47
|
+
} else if (platform === 'linux') {
|
|
48
|
+
// @ts-expect-error
|
|
49
|
+
addon = require('./node_modules/sherpa-onnx-linux-x64/sherpa-onnx.node')
|
|
50
|
+
}
|
|
51
|
+
} else if (arch === 'arm64') {
|
|
52
|
+
if (platform === 'darwin') {
|
|
53
|
+
// @ts-expect-error
|
|
54
|
+
addon = require('./node_modules/sherpa-onnx-darwin-arm64/sherpa-onnx.node')
|
|
55
|
+
} else if (platform === 'linux') {
|
|
56
|
+
// @ts-expect-error
|
|
57
|
+
addon = require('./node_modules/sherpa-onnx-linux-arm64/sherpa-onnx.node')
|
|
58
|
+
}
|
|
59
|
+
} else if (arch === 'ia32') {
|
|
60
|
+
if (platform === 'win') {
|
|
61
|
+
// @ts-expect-error
|
|
62
|
+
addon = require('./node_modules/sherpa-onnx-win-ia32/sherpa-onnx.node')
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
} catch (error) {
|
|
66
|
+
//
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
module.exports = addon;
|
package/addon.js
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/** @typedef {import('./types').WaveObject} WaveObject */
|
|
2
|
+
|
|
3
|
+
const os = require('os');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const addonStaticImport = require('./addon-static-import');
|
|
6
|
+
|
|
7
|
+
// Package name triggered spam for sherpa-onnx-win32-x64
|
|
8
|
+
// so we have renamed it to sherpa-onnx-win-x64
|
|
9
|
+
const platform = os.platform() === 'win32' ? 'win' : os.platform();
|
|
10
|
+
const arch = os.arch();
|
|
11
|
+
const platform_arch = `${platform}-${arch}`;
|
|
12
|
+
const possible_paths = [
|
|
13
|
+
'../build/Release/sherpa-onnx.node',
|
|
14
|
+
'../build/Debug/sherpa-onnx.node',
|
|
15
|
+
`./node_modules/sherpa-onnx-${platform_arch}/sherpa-onnx.node`,
|
|
16
|
+
`../sherpa-onnx-${platform_arch}/sherpa-onnx.node`,
|
|
17
|
+
'./sherpa-onnx.node',
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
let addon = addonStaticImport;
|
|
21
|
+
|
|
22
|
+
if (!addon) {
|
|
23
|
+
for (const p of possible_paths) {
|
|
24
|
+
try {
|
|
25
|
+
addon = require(p);
|
|
26
|
+
break;
|
|
27
|
+
} catch (error) {
|
|
28
|
+
// do nothing; try the next option
|
|
29
|
+
;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
module.exports = addon;
|
|
35
|
+
|
|
36
|
+
if (!addon) {
|
|
37
|
+
let addon_path =
|
|
38
|
+
`${process.env.PWD}/node_modules/sherpa-onnx-${platform_arch}`;
|
|
39
|
+
const pnpmIndex = __dirname.indexOf(`node_modules${path.sep}.pnpm`);
|
|
40
|
+
if (pnpmIndex !== -1) {
|
|
41
|
+
const parts = __dirname.slice(pnpmIndex).split(path.sep);
|
|
42
|
+
parts.pop();
|
|
43
|
+
addon_path =
|
|
44
|
+
`${process.env.PWD}/${parts.join('/')}/sherpa-onnx-${platform_arch}`;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
let msg = `Could not find sherpa-onnx-node. Tried\n\n ${
|
|
48
|
+
possible_paths.join('\n ')}\n`
|
|
49
|
+
if (os.platform() == 'darwin' &&
|
|
50
|
+
(!process.env.DYLD_LIBRARY_PATH ||
|
|
51
|
+
!process.env.DYLD_LIBRARY_PATH.includes(
|
|
52
|
+
`node_modules/sherpa-onnx-${platform_arch}`))) {
|
|
53
|
+
msg +=
|
|
54
|
+
'Please remember to set the following environment variable and try again:\n';
|
|
55
|
+
|
|
56
|
+
msg += `export DYLD_LIBRARY_PATH=${addon_path}`;
|
|
57
|
+
|
|
58
|
+
msg += ':$DYLD_LIBRARY_PATH\n';
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (os.platform() == 'linux' &&
|
|
62
|
+
(!process.env.LD_LIBRARY_PATH ||
|
|
63
|
+
!process.env.LD_LIBRARY_PATH.includes(
|
|
64
|
+
`node_modules/sherpa-onnx-${platform_arch}`))) {
|
|
65
|
+
msg +=
|
|
66
|
+
'Please remember to set the following environment variable and try again:\n';
|
|
67
|
+
|
|
68
|
+
msg += `export LD_LIBRARY_PATH=${addon_path}`;
|
|
69
|
+
|
|
70
|
+
msg += ':$LD_LIBRARY_PATH\n';
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
throw new Error(msg)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Read a wave file from disk.
|
|
78
|
+
* @function module.exports.readWave
|
|
79
|
+
* @param {string} filename
|
|
80
|
+
* @param {boolean} [enableExternalBuffer=true]
|
|
81
|
+
* @returns {WaveObject}
|
|
82
|
+
*/
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Read a wave from binary buffer.
|
|
86
|
+
* @function module.exports.readWaveFromBinary
|
|
87
|
+
* @param {Uint8Array} data - Binary contents of a wave file.
|
|
88
|
+
* @param {boolean} [enableExternalBuffer=true]
|
|
89
|
+
* @returns {WaveObject}
|
|
90
|
+
*/
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Write a wave file to disk.
|
|
94
|
+
* @function module.exports.writeWave
|
|
95
|
+
* @param {string} filename
|
|
96
|
+
* @param {WaveObject} obj - { samples: Float32Array, sampleRate: number }
|
|
97
|
+
* @returns {boolean}
|
|
98
|
+
*/
|
package/audio-tagg.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/** @typedef {import('./types').AudioTaggingConfig} AudioTaggingConfig */
|
|
2
|
+
/** @typedef {import('./types').AudioEvent} AudioEvent */
|
|
3
|
+
/** @typedef {import('./types').AudioTaggingHandle} AudioTaggingHandle */
|
|
4
|
+
/** @typedef {import('./non-streaming-asr').OfflineStream} OfflineStream */
|
|
5
|
+
|
|
6
|
+
const addon = require('./addon.js');
|
|
7
|
+
const non_streaming_asr = require('./non-streaming-asr.js');
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* AudioTagging utility.
|
|
11
|
+
* @class
|
|
12
|
+
*/
|
|
13
|
+
class AudioTagging {
|
|
14
|
+
/**
|
|
15
|
+
* Create an AudioTagging instance.
|
|
16
|
+
* @param {AudioTaggingConfig} config
|
|
17
|
+
*/
|
|
18
|
+
constructor(config) {
|
|
19
|
+
this.handle = addon.createAudioTagging(config);
|
|
20
|
+
this.config = config;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Create an offline stream bound to this AudioTagging instance.
|
|
25
|
+
* @returns {OfflineStream}
|
|
26
|
+
*/
|
|
27
|
+
createStream() {
|
|
28
|
+
return new non_streaming_asr.OfflineStream(
|
|
29
|
+
addon.audioTaggingCreateOfflineStream(this.handle));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Compute audio tags from an offline stream.
|
|
34
|
+
* @param {OfflineStream} stream - An offline stream created by `AudioTagging.createStream()`.
|
|
35
|
+
* @param {number} [topK=-1] - Return top K results; -1 for all.
|
|
36
|
+
* @returns {AudioEvent[]}
|
|
37
|
+
*/
|
|
38
|
+
compute(stream, topK = -1) {
|
|
39
|
+
return addon.audioTaggingCompute(this.handle, stream.handle, topK);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
module.exports = {
|
|
44
|
+
AudioTagging,
|
|
45
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/** @typedef {import('./types').KeywordSpotterConfig} KeywordSpotterConfig */
|
|
2
|
+
/** @typedef {import('./types').KeywordSpotterHandle} KeywordSpotterHandle */
|
|
3
|
+
/** @typedef {import('./types').KeywordResult} KeywordResult */
|
|
4
|
+
/** @typedef {import('./streaming-asr').OnlineStream} OnlineStream */
|
|
5
|
+
|
|
6
|
+
const addon = require('./addon.js');
|
|
7
|
+
const streaming_asr = require('./streaming-asr.js');
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* KeywordSpotter handles keyword detection.
|
|
11
|
+
*/
|
|
12
|
+
class KeywordSpotter {
|
|
13
|
+
/**
|
|
14
|
+
* @param {KeywordSpotterConfig} config
|
|
15
|
+
*/
|
|
16
|
+
constructor(config) {
|
|
17
|
+
this.handle = addon.createKeywordSpotter(config);
|
|
18
|
+
this.config = config
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Create an OnlineStream for the spotter.
|
|
23
|
+
* @returns {OnlineStream}
|
|
24
|
+
*/
|
|
25
|
+
createStream() {
|
|
26
|
+
const handle = addon.createKeywordStream(this.handle);
|
|
27
|
+
return new streaming_asr.OnlineStream(handle);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @param {OnlineStream} stream
|
|
32
|
+
* @returns {boolean}
|
|
33
|
+
*/
|
|
34
|
+
isReady(stream) {
|
|
35
|
+
return addon.isKeywordStreamReady(this.handle, stream.handle);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Trigger decode on a stream.
|
|
40
|
+
* @param {OnlineStream} stream
|
|
41
|
+
*/
|
|
42
|
+
decode(stream) {
|
|
43
|
+
addon.decodeKeywordStream(this.handle, stream.handle);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Reset a stream.
|
|
48
|
+
* @param {OnlineStream} stream
|
|
49
|
+
*/
|
|
50
|
+
reset(stream) {
|
|
51
|
+
addon.resetKeywordStream(this.handle, stream.handle);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Get the keyword result for a stream.
|
|
56
|
+
* @param {OnlineStream} stream
|
|
57
|
+
* @returns {KeywordResult}
|
|
58
|
+
*/
|
|
59
|
+
getResult(stream) {
|
|
60
|
+
const jsonStr = addon.getKeywordResultAsJson(this.handle, stream.handle);
|
|
61
|
+
|
|
62
|
+
return JSON.parse(jsonStr);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
module.exports = {
|
|
67
|
+
KeywordSpotter,
|
|
68
|
+
}
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/** @typedef {import('./types').OfflineStreamObject} OfflineStreamObject */
|
|
2
|
+
/** @typedef {import('./types').OfflineStreamHandle} OfflineStreamHandle */
|
|
3
|
+
/** @typedef {import('./types').OfflineRecognizerHandle} OfflineRecognizerHandle */
|
|
4
|
+
/** @typedef {import('./types').Waveform} Waveform */
|
|
5
|
+
/**
|
|
6
|
+
* @typedef {import('./types').OfflineRecognizerConfig} OfflineRecognizerConfig
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* @typedef {import('./types').OfflineRecognizerResult} OfflineRecognizerResult
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const addon = require('./addon.js');
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Internal symbol to mark async-created recognizers.
|
|
16
|
+
* Not accessible unless someone has a reference to this Symbol.
|
|
17
|
+
*/
|
|
18
|
+
const kFromAsyncFactory = Symbol('OfflineRecognizer.fromAsync');
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* OfflineStream represents a synchronous offline audio stream.
|
|
22
|
+
*/
|
|
23
|
+
class OfflineStream {
|
|
24
|
+
/**
|
|
25
|
+
* @param {OfflineStreamObject|Object} handle
|
|
26
|
+
*/
|
|
27
|
+
constructor(handle) {
|
|
28
|
+
this.handle = handle;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Accept a chunk of waveform samples.
|
|
33
|
+
* @param {Waveform} obj - { samples: Float32Array, sampleRate: number }
|
|
34
|
+
*/
|
|
35
|
+
acceptWaveform(obj) {
|
|
36
|
+
addon.acceptWaveformOffline(this.handle, obj);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Set a string option on the underlying offline stream.
|
|
41
|
+
* @param {string} key
|
|
42
|
+
* @param {string} value
|
|
43
|
+
*/
|
|
44
|
+
setOption(key, value) {
|
|
45
|
+
addon.offlineStreamSetOption(this.handle, key, value);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* OfflineRecognizer wraps the native offline recognizer.
|
|
51
|
+
*/
|
|
52
|
+
class OfflineRecognizer {
|
|
53
|
+
/**
|
|
54
|
+
* Constructor (SYNC path).
|
|
55
|
+
*
|
|
56
|
+
* Users call:
|
|
57
|
+
* new OfflineRecognizer(config)
|
|
58
|
+
*
|
|
59
|
+
* Async factory calls this with an internal descriptor.
|
|
60
|
+
*
|
|
61
|
+
* @param {OfflineRecognizerConfig | Object} configOrInternal
|
|
62
|
+
*/
|
|
63
|
+
constructor(configOrInternal) {
|
|
64
|
+
// ----- async factory path -----
|
|
65
|
+
if (configOrInternal && typeof configOrInternal === 'object' &&
|
|
66
|
+
configOrInternal[kFromAsyncFactory]) {
|
|
67
|
+
this.handle = configOrInternal.handle;
|
|
68
|
+
this.config = configOrInternal.config;
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// ----- sync constructor path -----
|
|
73
|
+
this.config = configOrInternal;
|
|
74
|
+
this.handle = addon.createOfflineRecognizer(this.config);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Create an OfflineRecognizer asynchronously (non-blocking).
|
|
79
|
+
*
|
|
80
|
+
* @param {OfflineRecognizerConfig} config
|
|
81
|
+
* @returns {Promise<OfflineRecognizer>}
|
|
82
|
+
*/
|
|
83
|
+
static async createAsync(config) {
|
|
84
|
+
const handle = await addon.createOfflineRecognizerAsync(config);
|
|
85
|
+
|
|
86
|
+
return new OfflineRecognizer({
|
|
87
|
+
[kFromAsyncFactory]: true,
|
|
88
|
+
handle,
|
|
89
|
+
config,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Create a new OfflineStream bound to this recognizer.
|
|
95
|
+
*
|
|
96
|
+
* The optional hotwords argument enables contextual biasing for this
|
|
97
|
+
* stream only. Hotwords are supported only by transducer models decoded
|
|
98
|
+
* with decodingMethod 'modified_beam_search'. Separate multiple phrases
|
|
99
|
+
* with '/', and optionally append a per-phrase boosting score, e.g.
|
|
100
|
+
* 'PHOEBE :2.0/DON QUIXOTE'. When modelConfig.modelingUnit and
|
|
101
|
+
* modelConfig.bpeVocab are set, phrases are given as normal words;
|
|
102
|
+
* otherwise each phrase must be a sequence of tokens from tokens.txt
|
|
103
|
+
* separated by spaces. See also
|
|
104
|
+
* https://k2-fsa.github.io/sherpa/onnx/hotwords/index.html
|
|
105
|
+
*
|
|
106
|
+
* @param {string} [hotwords] Optional hotwords for this stream.
|
|
107
|
+
* @returns {OfflineStream}
|
|
108
|
+
*/
|
|
109
|
+
createStream(hotwords) {
|
|
110
|
+
const handle = hotwords === undefined ?
|
|
111
|
+
addon.createOfflineStream(this.handle) :
|
|
112
|
+
addon.createOfflineStream(this.handle, hotwords);
|
|
113
|
+
return new OfflineStream(handle);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Replace the recognizer config at runtime.
|
|
118
|
+
* @param {OfflineRecognizerConfig} config
|
|
119
|
+
*/
|
|
120
|
+
setConfig(config) {
|
|
121
|
+
this.config = config;
|
|
122
|
+
addon.offlineRecognizerSetConfig(this.handle, config);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Decode an offline stream (synchronous).
|
|
127
|
+
* @param {OfflineStream} stream
|
|
128
|
+
*/
|
|
129
|
+
decode(stream) {
|
|
130
|
+
addon.decodeOfflineStream(this.handle, stream.handle);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Decode an offline stream asynchronously (non-blocking).
|
|
135
|
+
* @param {OfflineStream} stream
|
|
136
|
+
* @returns {Promise<OfflineRecognizerResult>}
|
|
137
|
+
*/
|
|
138
|
+
async decodeAsync(stream) {
|
|
139
|
+
const jsonStr =
|
|
140
|
+
await addon.decodeOfflineStreamAsync(this.handle, stream.handle);
|
|
141
|
+
return JSON.parse(jsonStr);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Get recognition result for a stream.
|
|
146
|
+
* @param {OfflineStream} stream
|
|
147
|
+
* @returns {OfflineRecognizerResult}
|
|
148
|
+
*/
|
|
149
|
+
getResult(stream) {
|
|
150
|
+
const jsonStr = addon.getOfflineStreamResultAsJson(stream.handle);
|
|
151
|
+
return JSON.parse(jsonStr);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
module.exports = {
|
|
156
|
+
OfflineRecognizer,
|
|
157
|
+
OfflineStream,
|
|
158
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/** @typedef {import('./types').OfflineSpeakerDiarizationConfig} OfflineSpeakerDiarizationConfig */
|
|
2
|
+
/** @typedef {import('./types').OfflineSpeakerDiarizationHandle} OfflineSpeakerDiarizationHandle */
|
|
3
|
+
/** @typedef {import('./types').SpeakerDiarizationSegment} SpeakerDiarizationSegment */
|
|
4
|
+
|
|
5
|
+
const addon = require('./addon.js');
|
|
6
|
+
|
|
7
|
+
class OfflineSpeakerDiarization {
|
|
8
|
+
/**
|
|
9
|
+
* @param {OfflineSpeakerDiarizationConfig} config
|
|
10
|
+
*/
|
|
11
|
+
constructor(config) {
|
|
12
|
+
this.handle = addon.createOfflineSpeakerDiarization(config);
|
|
13
|
+
this.config = config;
|
|
14
|
+
|
|
15
|
+
this.sampleRate = addon.getOfflineSpeakerDiarizationSampleRate(this.handle);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @param {Float32Array} samples - 1-D float32 array in [-1, 1]
|
|
20
|
+
* @returns {SpeakerDiarizationSegment[]}
|
|
21
|
+
*/
|
|
22
|
+
process(samples) {
|
|
23
|
+
return addon.offlineSpeakerDiarizationProcess(this.handle, samples);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Set clustering configuration.
|
|
28
|
+
* @param {{clustering: import('./types').FastClusteringConfig}} config
|
|
29
|
+
*/
|
|
30
|
+
setConfig(config) {
|
|
31
|
+
addon.offlineSpeakerDiarizationSetConfig(this.handle, config);
|
|
32
|
+
this.config.clustering = config.clustering;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
module.exports = {
|
|
37
|
+
OfflineSpeakerDiarization,
|
|
38
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/** @typedef {import('./types').OfflineSpeechDenoiserConfig} OfflineSpeechDenoiserConfig */
|
|
2
|
+
/** @typedef {import('./types').OfflineSpeechDenoiserHandle} OfflineSpeechDenoiserHandle */
|
|
3
|
+
/** @typedef {import('./types').GeneratedAudio} GeneratedAudio */
|
|
4
|
+
/** @typedef {import('./types').AudioProcessRequest} AudioProcessRequest */
|
|
5
|
+
|
|
6
|
+
const addon = require('./addon.js');
|
|
7
|
+
|
|
8
|
+
class OfflineSpeechDenoiser {
|
|
9
|
+
/**
|
|
10
|
+
* @param {OfflineSpeechDenoiserConfig} config
|
|
11
|
+
*/
|
|
12
|
+
constructor(config) {
|
|
13
|
+
this.handle = addon.createOfflineSpeechDenoiser(config);
|
|
14
|
+
this.config = config;
|
|
15
|
+
|
|
16
|
+
this.sampleRate =
|
|
17
|
+
addon.offlineSpeechDenoiserGetSampleRateWrapper(this.handle);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Run denoiser synchronously.
|
|
22
|
+
* @param {AudioProcessRequest} obj - { samples: Float32Array, sampleRate: number, enableExternalBuffer?: boolean }
|
|
23
|
+
* @returns {GeneratedAudio}
|
|
24
|
+
*/
|
|
25
|
+
run(obj) {
|
|
26
|
+
return addon.offlineSpeechDenoiserRunWrapper(this.handle, obj);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
module.exports = {
|
|
31
|
+
OfflineSpeechDenoiser,
|
|
32
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/** @typedef {import('./types').OfflineTtsConfig} OfflineTtsConfig */
|
|
2
|
+
/** @typedef {import('./types').OfflineTtsHandle} OfflineTtsHandle */
|
|
3
|
+
/** @typedef {import('./types').TtsRequest} TtsRequest */
|
|
4
|
+
/** @typedef {import('./types').GeneratedAudio} GeneratedAudio */
|
|
5
|
+
|
|
6
|
+
const addon = require('./addon.js');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Internal symbol to mark async-created TTS instances.
|
|
10
|
+
*/
|
|
11
|
+
const kFromAsyncFactory = Symbol('OfflineTts.fromAsync');
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class GenerationConfig {
|
|
15
|
+
constructor(opts = {}) {
|
|
16
|
+
Object.assign(this, opts);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class OfflineTts {
|
|
22
|
+
/**
|
|
23
|
+
* Constructor (sync path).
|
|
24
|
+
*
|
|
25
|
+
* Users call:
|
|
26
|
+
* new OfflineTts(config)
|
|
27
|
+
*
|
|
28
|
+
* Async factory calls this with an internal descriptor.
|
|
29
|
+
*
|
|
30
|
+
* @param {OfflineTtsConfig|Object} configOrInternal
|
|
31
|
+
*/
|
|
32
|
+
constructor(configOrInternal) {
|
|
33
|
+
if (configOrInternal && typeof configOrInternal === 'object' &&
|
|
34
|
+
configOrInternal[kFromAsyncFactory]) {
|
|
35
|
+
// ----- async factory path -----
|
|
36
|
+
this.handle = configOrInternal.handle;
|
|
37
|
+
this.config = configOrInternal.config;
|
|
38
|
+
} else {
|
|
39
|
+
// ----- sync constructor path -----
|
|
40
|
+
this.config = configOrInternal;
|
|
41
|
+
this.handle = addon.createOfflineTts(this.config);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Common initialization
|
|
45
|
+
this.numSpeakers = addon.getOfflineTtsNumSpeakers(this.handle);
|
|
46
|
+
this.sampleRate = addon.getOfflineTtsSampleRate(this.handle);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Create an OfflineTts asynchronously (non-blocking).
|
|
51
|
+
* @param {OfflineTtsConfig} config
|
|
52
|
+
* @returns {Promise<OfflineTts>}
|
|
53
|
+
*/
|
|
54
|
+
static async createAsync(config) {
|
|
55
|
+
const handle = await addon.createOfflineTtsAsync(config);
|
|
56
|
+
return new OfflineTts({
|
|
57
|
+
[kFromAsyncFactory]: true,
|
|
58
|
+
handle,
|
|
59
|
+
config,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Generate audio synchronously.
|
|
65
|
+
* @param {TtsRequest} obj
|
|
66
|
+
* @returns {GeneratedAudio}
|
|
67
|
+
*/
|
|
68
|
+
generate(obj) {
|
|
69
|
+
if (!obj || typeof obj !== 'object') {
|
|
70
|
+
throw new TypeError('generate() expects an object');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// If generationConfig is present, use new API
|
|
74
|
+
if (obj.generationConfig !== undefined) {
|
|
75
|
+
return addon.offlineTtsGenerateWithConfig(this.handle, obj);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Fallback to legacy path
|
|
79
|
+
return addon.offlineTtsGenerate(this.handle, obj);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Generate audio asynchronously with optional generationConfig and progress
|
|
83
|
+
* callback
|
|
84
|
+
*
|
|
85
|
+
* The progress callback receives streaming audio chunks.
|
|
86
|
+
*
|
|
87
|
+
* @param {TtsRequest & { generationConfig?: GenerationConfig, onProgress?: (info: {
|
|
88
|
+
* samples: Float32Array, progress: number }) => number | boolean | void
|
|
89
|
+
* }} obj
|
|
90
|
+
* @returns {Promise<GeneratedAudio>}
|
|
91
|
+
*/
|
|
92
|
+
generateAsync(obj) {
|
|
93
|
+
const {onProgress, ...rest} = obj;
|
|
94
|
+
|
|
95
|
+
const hasConfig = obj.generationConfig !== undefined;
|
|
96
|
+
|
|
97
|
+
const fn = hasConfig ? addon.offlineTtsGenerateAsyncWithConfig :
|
|
98
|
+
addon.offlineTtsGenerateAsync;
|
|
99
|
+
|
|
100
|
+
return fn(this.handle, {
|
|
101
|
+
...rest,
|
|
102
|
+
callback: typeof onProgress === 'function' ?
|
|
103
|
+
(info) => {
|
|
104
|
+
const ret = onProgress(info);
|
|
105
|
+
return ret === 0 || ret === false ? 0 : 1;
|
|
106
|
+
} :
|
|
107
|
+
undefined,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
module.exports = {
|
|
114
|
+
OfflineTts,
|
|
115
|
+
GenerationConfig,
|
|
116
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/** @typedef {import('./types').OnlineSpeechDenoiserConfig} OnlineSpeechDenoiserConfig */
|
|
2
|
+
/** @typedef {import('./types').OnlineSpeechDenoiserHandle} OnlineSpeechDenoiserHandle */
|
|
3
|
+
/** @typedef {import('./types').GeneratedAudio} GeneratedAudio */
|
|
4
|
+
/** @typedef {import('./types').AudioProcessRequest} AudioProcessRequest */
|
|
5
|
+
|
|
6
|
+
const addon = require('./addon.js');
|
|
7
|
+
|
|
8
|
+
class OnlineSpeechDenoiser {
|
|
9
|
+
/**
|
|
10
|
+
* @param {OnlineSpeechDenoiserConfig} config
|
|
11
|
+
*/
|
|
12
|
+
constructor(config) {
|
|
13
|
+
this.handle = addon.createOnlineSpeechDenoiser(config);
|
|
14
|
+
this.config = config;
|
|
15
|
+
|
|
16
|
+
this.sampleRate =
|
|
17
|
+
addon.onlineSpeechDenoiserGetSampleRateWrapper(this.handle);
|
|
18
|
+
this.frameShiftInSamples =
|
|
19
|
+
addon.onlineSpeechDenoiserGetFrameShiftInSamplesWrapper(this.handle);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @param {AudioProcessRequest} obj
|
|
24
|
+
* @returns {GeneratedAudio}
|
|
25
|
+
*/
|
|
26
|
+
run(obj) {
|
|
27
|
+
return addon.onlineSpeechDenoiserRunWrapper(this.handle, obj);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @param {boolean} [enableExternalBuffer=true]
|
|
32
|
+
* @returns {GeneratedAudio}
|
|
33
|
+
*/
|
|
34
|
+
flush(enableExternalBuffer = true) {
|
|
35
|
+
return addon.onlineSpeechDenoiserFlushWrapper(
|
|
36
|
+
this.handle, enableExternalBuffer);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
reset() {
|
|
40
|
+
addon.onlineSpeechDenoiserResetWrapper(this.handle);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
module.exports = {
|
|
45
|
+
OnlineSpeechDenoiser,
|
|
46
|
+
};
|