forked from mozilla/DeepSpeech
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathclient.ts
More file actions
150 lines (131 loc) · 4.99 KB
/
Copy pathclient.ts
File metadata and controls
150 lines (131 loc) · 4.99 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
#!/usr/bin/env node
// This is required for process.versions.electron below
/// <reference types="electron" />
import * as Ds from "./index";
import * as Fs from "fs";
import Sox from "sox-stream";
import * as argparse from "argparse";
const MemoryStream = require("memory-stream");
const Wav = require("node-wav");
const Duplex = require("stream").Duplex;
class VersionAction extends argparse.Action {
call(parser: argparse.ArgumentParser, namespace: argparse.Namespace, values: string | string[], optionString: string | null) {
console.log('DeepSpeech ' + Ds.Version());
let runtime = 'Node';
if (process.versions.electron) {
runtime = 'Electron';
}
console.error('Runtime: ' + runtime);
process.exit(0);
}
}
let parser = new argparse.ArgumentParser({addHelp: true, description: 'Running DeepSpeech inference.'});
parser.addArgument(['--model'], {required: true, help: 'Path to the model (protocol buffer binary file)'});
parser.addArgument(['--scorer'], {help: 'Path to the external scorer file'});
parser.addArgument(['--audio'], {required: true, help: 'Path to the audio file to run (WAV format)'});
parser.addArgument(['--version'], {action: VersionAction, nargs: 0, help: 'Print version and exits'});
parser.addArgument(['--extended'], {action: 'storeTrue', help: 'Output string from extended metadata'});
parser.addArgument(['--stream'], {action: 'storeTrue', help: 'Use streaming code path (for tests)'});
let args = parser.parseArgs();
function totalTime(hrtimeValue: number[]): string {
return (hrtimeValue[0] + hrtimeValue[1] / 1000000000).toPrecision(4);
}
function candidateTranscriptToString(transcript: Ds.CandidateTranscript): string {
var retval = ""
for (var i = 0; i < transcript.tokens.length; ++i) {
retval += transcript.tokens[i].text;
}
return retval;
}
// sphinx-doc: js_ref_model_start
console.error('Loading model from file %s', args['model']);
const model_load_start = process.hrtime();
let model = new Ds.Model(args['model']);
const model_load_end = process.hrtime(model_load_start);
console.error('Loaded model in %ds.', totalTime(model_load_end));
if (args['beam_width']) {
model.setBeamWidth(args['beam_width']);
}
// sphinx-doc: js_ref_model_stop
let desired_sample_rate = model.sampleRate();
if (args['scorer']) {
console.error('Loading scorer from file %s', args['scorer']);
const scorer_load_start = process.hrtime();
model.enableExternalScorer(args['scorer']);
const scorer_load_end = process.hrtime(scorer_load_start);
console.error('Loaded scorer in %ds.', totalTime(scorer_load_end));
if (args['lm_alpha'] && args['lm_beta']) {
model.setScorerAlphaBeta(args['lm_alpha'], args['lm_beta']);
}
}
const buffer = Fs.readFileSync(args['audio']);
const result = Wav.decode(buffer);
if (result.sampleRate < desired_sample_rate) {
console.error(`Warning: original sample rate ( ${result.sampleRate})` +
`is lower than ${desired_sample_rate} Hz. ` +
`Up-sampling might produce erratic speech recognition.`);
}
function bufferToStream(buffer: Buffer) {
var stream = new Duplex();
stream.push(buffer);
stream.push(null);
return stream;
}
let conversionStream = bufferToStream(buffer).
pipe(Sox({
global: {
'no-dither': true,
'replay-gain': 'off',
},
output: {
bits: 16,
rate: desired_sample_rate,
channels: 1,
encoding: 'signed-integer',
endian: 'little',
compression: 0.0,
type: 'raw'
}
}));
if (!args['stream']) {
let audioStream = new MemoryStream();
conversionStream.pipe(audioStream);
audioStream.on('finish', () => {
let audioBuffer = audioStream.toBuffer();
const inference_start = process.hrtime();
console.error('Running inference.');
const audioLength = (audioBuffer.length / 2) * (1 / desired_sample_rate);
// sphinx-doc: js_ref_inference_start
if (args['extended']) {
let metadata = model.sttWithMetadata(audioBuffer, 1);
console.log(candidateTranscriptToString(metadata.transcripts[0]));
Ds.FreeMetadata(metadata);
} else {
console.log(model.stt(audioBuffer));
}
// sphinx-doc: js_ref_inference_stop
const inference_stop = process.hrtime(inference_start);
console.error('Inference took %ds for %ds audio file.', totalTime(inference_stop), audioLength.toPrecision(4));
Ds.FreeModel(model);
process.exit(0);
});
} else {
let stream = model.createStream();
conversionStream.on('data', (chunk: Buffer) => {
stream.feedAudioContent(chunk);
if (args['extended']) {
let metadata = stream.intermediateDecodeWithMetadata();
console.error('intermediate: ' + candidateTranscriptToString(metadata.transcripts[0]));
} else {
console.error('intermediate: ' + stream.intermediateDecode());
}
});
conversionStream.on('end', () => {
if (args['extended']) {
let metadata = stream.finishStreamWithMetadata();
console.log(candidateTranscriptToString(metadata.transcripts[0]));
} else {
console.log(stream.finishStream());
}
});
}