generated from qber-soft/Ave-React-Template
-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathasr.ts
149 lines (131 loc) · 4.21 KB
/
asr.ts
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
import axios from "axios";
import path from "path";
import fs from "fs";
import childProcess from "child_process";
import { IAsrEngine, IAsrEngineOptions, ISentence } from "./base";
import { emptySentence, shadowRelated } from "../shadow";
import { postasr } from "./postasr";
import { inspectLog, ErrorEvent } from "../server";
enum AsrVersion {
v100,
v110,
v120,
}
export class VoskAsrEngine implements IAsrEngine {
private options: IAsrEngineOptions;
private asr: childProcess.ChildProcessWithoutNullStreams;
private version: AsrVersion;
constructor(options: IAsrEngineOptions) {
this.options = options;
this.version = AsrVersion.v100;
}
getAsrPath() {
const port = this.options.asrPort;
const voskPort = this.options.asrSocketPort;
const v120 = path.resolve(process.cwd(), "asr-server-v1.2.0");
if (fs.existsSync(v120)) {
this.version = AsrVersion.v120;
console.log("use asr-server-v1.2.0");
return { asrDir: v120, exePath: path.resolve(v120, "./ASR-API.exe"), args: [`--port=${port}`, `--vosk-port=${voskPort}`] };
}
const v110 = path.resolve(process.cwd(), "asr-server-v1.1.0");
if (fs.existsSync(v110)) {
this.version = AsrVersion.v110;
console.log("use asr-server-v1.1.0");
return { asrDir: v110, exePath: path.resolve(v110, "./ASR-API.exe") };
}
const v100 = path.resolve(process.cwd(), "asr-server");
if (fs.existsSync(v100)) {
console.log("use asr-server-v1.0.0");
return { asrDir: v100, exePath: path.resolve(v100, "./ASR-API.exe") };
}
return { asrDir: "", exePath: "" };
}
async init() {
console.log("try to init vosk asr engine");
const { asrDir, exePath, args = [] } = this.getAsrPath();
if (asrDir && exePath) {
return new Promise((resolve, reject) => {
console.log("asrDir exists, start asr server", asrDir);
const asr = childProcess.spawn(exePath, args, { windowsHide: true, detached: false /** hide console */ });
this.asr = asr;
asr.stdout.on("data", (data) => {
const isError = inspectLog(data?.toString());
if(isError) {
reject(false);
}
console.log(`stdout: ${data}`);
if (data.includes("has been started")) {
console.log("asr server started");
resolve(true);
}
});
asr.stderr.on("data", (data) => {
const isError = inspectLog(data?.toString());
if(isError) {
reject(false);
}
console.error(`stderr: ${data}`);
});
asr.on("close", (code) => {
console.log(`asr server exit: ${code}`);
reject(false);
});
});
} else {
console.log(ErrorEvent.AsrServerNotExist.log);
inspectLog(ErrorEvent.AsrServerNotExist.log);
}
}
async destroy() {
if (this.asr) {
console.log("exit asr server process");
this.asr.kill();
process.kill(this.asr?.pid);
process.exit();
}
}
private async asrApi(): Promise<string> {
const port = this.options.asrPort;
if (this.version === AsrVersion.v100) {
const response = await axios.post(`http://localhost:${port}/asr`, {}, { timeout: 2000 });
const result = response?.data?.result;
const data = JSON.parse(result || "{}");
const asrText = data.partial || "";
return asrText;
} else {
const response = await axios.post(`http://localhost:${port}/asr_queue`, {}, { timeout: 1000 });
const result = response?.data?.result;
const data = JSON.parse(result[result.length - 1] || "{}");
const asrText = data.partial || "";
return asrText;
}
}
async getAsrResult(): Promise<string> {
let asrResult = "";
try {
asrResult = await this.asrApi();
} catch (error) {
console.log(`asr failed: ${error.message}`);
} finally {
return asrResult;
}
}
async recognize(): Promise<ISentence> {
let sentence: ISentence = emptySentence;
try {
const asrText = await this.getAsrResult();
if (shadowRelated.shouldBreakLongText) {
const result = await postasr(asrText);
sentence = { text: result, asr: asrText };
} else {
sentence = { text: asrText, asr: asrText };
}
} catch (error) {
console.log(`asr failed: ${error.message}`);
this.options?.onError(error.message);
} finally {
return sentence;
}
}
}