@amaster.ai/asr-client 1.0.0-beta.1 → 1.0.0-beta.12
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/index.cjs +92 -18
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -3
- package/dist/index.d.ts +9 -3
- package/dist/index.js +88 -17
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
var __defProp = Object.defineProperty;
|
|
2
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
@@ -19,15 +20,85 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
19
20
|
// src/index.ts
|
|
20
21
|
var index_exports = {};
|
|
21
22
|
__export(index_exports, {
|
|
22
|
-
createASRClient: () => createASRClient
|
|
23
|
+
createASRClient: () => createASRClient,
|
|
24
|
+
createAsrClient: () => createASRClient,
|
|
25
|
+
listen: () => listen
|
|
23
26
|
});
|
|
24
27
|
module.exports = __toCommonJS(index_exports);
|
|
25
28
|
|
|
26
29
|
// src/asr-client.ts
|
|
30
|
+
var ASR_PATH = "/api/proxy/builtin/platform/qwen-asr-realtime/api-ws/v1/realtime";
|
|
31
|
+
async function listen(onTranscript) {
|
|
32
|
+
const ws = new WebSocket(ASR_PATH);
|
|
33
|
+
let mediaStream = null;
|
|
34
|
+
let audioContext = null;
|
|
35
|
+
let processor = null;
|
|
36
|
+
const stop = () => {
|
|
37
|
+
if (mediaStream) {
|
|
38
|
+
mediaStream.getTracks().forEach((t) => t.stop());
|
|
39
|
+
mediaStream = null;
|
|
40
|
+
}
|
|
41
|
+
if (processor) {
|
|
42
|
+
processor.disconnect();
|
|
43
|
+
processor = null;
|
|
44
|
+
}
|
|
45
|
+
if (audioContext) {
|
|
46
|
+
audioContext.close();
|
|
47
|
+
audioContext = null;
|
|
48
|
+
}
|
|
49
|
+
if (ws.readyState === WebSocket.OPEN) {
|
|
50
|
+
ws.send(JSON.stringify({ type: "input_audio_buffer.commit" }));
|
|
51
|
+
ws.close();
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
return new Promise((resolve, reject) => {
|
|
55
|
+
ws.onmessage = async (event) => {
|
|
56
|
+
const data = JSON.parse(event.data);
|
|
57
|
+
if (data.type === "session.created") {
|
|
58
|
+
try {
|
|
59
|
+
mediaStream = await navigator.mediaDevices.getUserMedia({
|
|
60
|
+
audio: { sampleRate: 16e3, channelCount: 1, echoCancellation: true }
|
|
61
|
+
});
|
|
62
|
+
audioContext = new AudioContext({ sampleRate: 16e3 });
|
|
63
|
+
const source = audioContext.createMediaStreamSource(mediaStream);
|
|
64
|
+
processor = audioContext.createScriptProcessor(4096, 1, 1);
|
|
65
|
+
processor.onaudioprocess = (e) => {
|
|
66
|
+
if (ws.readyState !== WebSocket.OPEN) return;
|
|
67
|
+
const input = e.inputBuffer.getChannelData(0);
|
|
68
|
+
const pcm = new Int16Array(input.length);
|
|
69
|
+
for (let i = 0; i < input.length; i++) {
|
|
70
|
+
const s = Math.max(-1, Math.min(1, input[i]));
|
|
71
|
+
pcm[i] = s < 0 ? s * 32768 : s * 32767;
|
|
72
|
+
}
|
|
73
|
+
const bytes = new Uint8Array(pcm.buffer);
|
|
74
|
+
let binary = "";
|
|
75
|
+
for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]);
|
|
76
|
+
ws.send(JSON.stringify({ type: "input_audio_buffer.append", audio: btoa(binary) }));
|
|
77
|
+
};
|
|
78
|
+
source.connect(processor);
|
|
79
|
+
processor.connect(audioContext.destination);
|
|
80
|
+
resolve(stop);
|
|
81
|
+
} catch (err) {
|
|
82
|
+
reject(err);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
if (data.type === "conversation.item.input_audio_transcription.text") {
|
|
86
|
+
onTranscript(data.text || "", false);
|
|
87
|
+
}
|
|
88
|
+
if (data.type === "conversation.item.input_audio_transcription.completed") {
|
|
89
|
+
onTranscript(data.text || data.transcript || "", true);
|
|
90
|
+
}
|
|
91
|
+
if (data.type === "error") {
|
|
92
|
+
stop();
|
|
93
|
+
reject(new Error(data.error?.message || "ASR error"));
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
ws.onerror = () => reject(new Error("ASR connection failed"));
|
|
97
|
+
});
|
|
98
|
+
}
|
|
27
99
|
function createASRClient(config) {
|
|
28
100
|
const {
|
|
29
|
-
|
|
30
|
-
audioFormat = "pcm16",
|
|
101
|
+
// audioFormat = 'pcm16',
|
|
31
102
|
sampleRate = 16e3,
|
|
32
103
|
onReady,
|
|
33
104
|
onSpeechStart,
|
|
@@ -41,37 +112,36 @@ function createASRClient(config) {
|
|
|
41
112
|
let processor = null;
|
|
42
113
|
async function connect() {
|
|
43
114
|
return new Promise((resolve, reject) => {
|
|
44
|
-
ws = new WebSocket(
|
|
115
|
+
ws = new WebSocket(ASR_PATH);
|
|
45
116
|
ws.onopen = () => {
|
|
46
117
|
};
|
|
47
118
|
ws.onmessage = (event) => {
|
|
48
|
-
var _a;
|
|
49
119
|
const data = JSON.parse(event.data);
|
|
50
120
|
if (data.type === "session.created") {
|
|
51
|
-
onReady
|
|
121
|
+
onReady?.();
|
|
52
122
|
resolve();
|
|
53
123
|
}
|
|
54
124
|
if (data.type === "input_audio_buffer.speech_started") {
|
|
55
|
-
onSpeechStart
|
|
125
|
+
onSpeechStart?.();
|
|
56
126
|
}
|
|
57
127
|
if (data.type === "input_audio_buffer.speech_stopped") {
|
|
58
|
-
onSpeechEnd
|
|
128
|
+
onSpeechEnd?.();
|
|
59
129
|
}
|
|
60
130
|
if (data.type === "conversation.item.input_audio_transcription.text") {
|
|
61
|
-
onTranscript
|
|
131
|
+
onTranscript?.(data.text || "", false);
|
|
62
132
|
}
|
|
63
133
|
if (data.type === "conversation.item.input_audio_transcription.completed") {
|
|
64
|
-
onTranscript
|
|
134
|
+
onTranscript?.(data.text || data.transcript || "", true);
|
|
65
135
|
}
|
|
66
136
|
if (data.type === "error") {
|
|
67
|
-
const err = new Error(
|
|
68
|
-
onError
|
|
137
|
+
const err = new Error(data.error?.message || "Unknown error");
|
|
138
|
+
onError?.(err);
|
|
69
139
|
reject(err);
|
|
70
140
|
}
|
|
71
141
|
};
|
|
72
142
|
ws.onerror = () => {
|
|
73
143
|
const err = new Error("WebSocket connection error");
|
|
74
|
-
onError
|
|
144
|
+
onError?.(err);
|
|
75
145
|
reject(err);
|
|
76
146
|
};
|
|
77
147
|
ws.onclose = () => {
|
|
@@ -101,14 +171,16 @@ function createASRClient(config) {
|
|
|
101
171
|
processor.onaudioprocess = (e) => {
|
|
102
172
|
if (!ws || ws.readyState !== WebSocket.OPEN) return;
|
|
103
173
|
const inputData = e.inputBuffer.getChannelData(0);
|
|
104
|
-
const
|
|
105
|
-
|
|
174
|
+
const inputLen = inputData.length;
|
|
175
|
+
const pcm = new Int16Array(inputLen);
|
|
176
|
+
for (let i = 0; i < inputLen; i++) {
|
|
106
177
|
const s = Math.max(-1, Math.min(1, inputData[i]));
|
|
107
178
|
pcm[i] = s < 0 ? s * 32768 : s * 32767;
|
|
108
179
|
}
|
|
109
180
|
const bytes = new Uint8Array(pcm.buffer);
|
|
181
|
+
const len = bytes.length;
|
|
110
182
|
let binary = "";
|
|
111
|
-
for (let i = 0; i <
|
|
183
|
+
for (let i = 0; i < len; i++) {
|
|
112
184
|
binary += String.fromCharCode(bytes[i]);
|
|
113
185
|
}
|
|
114
186
|
const base64 = btoa(binary);
|
|
@@ -120,7 +192,7 @@ function createASRClient(config) {
|
|
|
120
192
|
source.connect(processor);
|
|
121
193
|
processor.connect(audioContext.destination);
|
|
122
194
|
} catch (err) {
|
|
123
|
-
onError
|
|
195
|
+
onError?.(err);
|
|
124
196
|
throw err;
|
|
125
197
|
}
|
|
126
198
|
}
|
|
@@ -157,6 +229,8 @@ function createASRClient(config) {
|
|
|
157
229
|
}
|
|
158
230
|
// Annotate the CommonJS export names for ESM import in node:
|
|
159
231
|
0 && (module.exports = {
|
|
160
|
-
createASRClient
|
|
232
|
+
createASRClient,
|
|
233
|
+
createAsrClient,
|
|
234
|
+
listen
|
|
161
235
|
});
|
|
162
236
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/asr-client.ts"],"sourcesContent":["export type { ASRClient, ASRClientConfig } from './asr-client';\nexport { createASRClient } from './asr-client';\n","/**\n * ASR Realtime WebSocket Client\n */\n\nexport interface ASRClientConfig {\n /** WebSocket endpoint URL */\n url: string;\n /** Audio format, default 'pcm16' */\n audioFormat?: 'pcm16' | 'g711a' | 'g711u';\n /** Sample rate, default 16000 */\n sampleRate?: number;\n /** Called when connection is ready */\n onReady?: () => void;\n /** Called when speech is detected */\n onSpeechStart?: () => void;\n /** Called when speech stops */\n onSpeechEnd?: () => void;\n /** Called on transcript result */\n onTranscript?: (text: string, isFinal: boolean) => void;\n /** Called on error */\n onError?: (error: Error) => void;\n}\n\nexport interface ASRClient {\n /** Connect to ASR service */\n connect(): Promise<void>;\n /** Start recording from microphone */\n startRecording(): Promise<void>;\n /** Stop recording */\n stopRecording(): void;\n /** Close connection */\n close(): void;\n}\n\nexport function createASRClient(config: ASRClientConfig): ASRClient {\n const {\n url,\n audioFormat = 'pcm16',\n sampleRate = 16000,\n onReady,\n onSpeechStart,\n onSpeechEnd,\n onTranscript,\n onError,\n } = config;\n\n let ws: WebSocket | null = null;\n let mediaStream: MediaStream | null = null;\n let audioContext: AudioContext | null = null;\n let processor: ScriptProcessorNode | null = null;\n\n async function connect(): Promise<void> {\n return new Promise((resolve, reject) => {\n ws = new WebSocket(url);\n\n ws.onopen = () => {};\n\n ws.onmessage = (event) => {\n const data = JSON.parse(event.data);\n\n if (data.type === 'session.created') {\n onReady?.();\n resolve();\n }\n\n if (data.type === 'input_audio_buffer.speech_started') {\n onSpeechStart?.();\n }\n\n if (data.type === 'input_audio_buffer.speech_stopped') {\n onSpeechEnd?.();\n }\n\n if (data.type === 'conversation.item.input_audio_transcription.text') {\n onTranscript?.(data.text || '', false);\n }\n\n if (data.type === 'conversation.item.input_audio_transcription.completed') {\n onTranscript?.(data.text || data.transcript || '', true);\n }\n\n if (data.type === 'error') {\n const err = new Error(data.error?.message || 'Unknown error');\n onError?.(err);\n reject(err);\n }\n };\n\n ws.onerror = () => {\n const err = new Error('WebSocket connection error');\n onError?.(err);\n reject(err);\n };\n\n ws.onclose = () => {\n ws = null;\n };\n });\n }\n\n async function startRecording(): Promise<void> {\n if (typeof window === 'undefined') {\n throw new Error('Recording only supported in browser');\n }\n\n if (!ws || ws.readyState !== WebSocket.OPEN) {\n throw new Error('WebSocket not connected');\n }\n\n try {\n mediaStream = await navigator.mediaDevices.getUserMedia({\n audio: {\n sampleRate,\n channelCount: 1,\n echoCancellation: true,\n noiseSuppression: true,\n },\n });\n\n audioContext = new AudioContext({ sampleRate });\n const source = audioContext.createMediaStreamSource(mediaStream);\n processor = audioContext.createScriptProcessor(4096, 1, 1);\n\n processor.onaudioprocess = (e) => {\n if (!ws || ws.readyState !== WebSocket.OPEN) return;\n\n const inputData = e.inputBuffer.getChannelData(0);\n\n const pcm = new Int16Array(inputData.length);\n for (let i = 0; i < inputData.length; i++) {\n const s = Math.max(-1, Math.min(1, inputData[i]));\n pcm[i] = s < 0 ? s * 32768 : s * 32767;\n }\n\n const bytes = new Uint8Array(pcm.buffer);\n let binary = '';\n for (let i = 0; i < bytes.length; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n const base64 = btoa(binary);\n\n ws.send(JSON.stringify({\n type: 'input_audio_buffer.append',\n audio: base64,\n }));\n };\n\n source.connect(processor);\n processor.connect(audioContext.destination);\n } catch (err) {\n onError?.(err as Error);\n throw err;\n }\n }\n\n function stopRecording() {\n if (mediaStream) {\n mediaStream.getTracks().forEach(track => track.stop());\n mediaStream = null;\n }\n\n if (processor) {\n processor.disconnect();\n processor = null;\n }\n\n if (audioContext) {\n audioContext.close();\n audioContext = null;\n }\n\n if (ws && ws.readyState === WebSocket.OPEN) {\n ws.send(JSON.stringify({ type: 'input_audio_buffer.commit' }));\n }\n }\n\n function close() {\n stopRecording();\n if (ws) {\n ws.close();\n ws = null;\n }\n }\n\n return {\n connect,\n startRecording,\n stopRecording,\n close,\n };\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/asr-client.ts"],"sourcesContent":["export { listen } from './asr-client';\nexport type { ASRClient, ASRClientConfig } from './asr-client';\nexport { createASRClient, createASRClient as createAsrClient } from './asr-client';\n","/**\n * ASR Realtime WebSocket Client\n */\n\nconst ASR_PATH = '/api/proxy/builtin/platform/qwen-asr-realtime/api-ws/v1/realtime';\n\n/**\n * Simple ASR: start listening and get transcript\n * @returns stop function\n * @example\n * const stop = await listen((text, isFinal) => console.log(text))\n * // later: stop()\n */\nexport async function listen(\n onTranscript: (text: string, isFinal: boolean) => void\n): Promise<() => void> {\n const ws = new WebSocket(ASR_PATH);\n let mediaStream: MediaStream | null = null;\n let audioContext: AudioContext | null = null;\n let processor: ScriptProcessorNode | null = null;\n\n const stop = () => {\n if (mediaStream) { mediaStream.getTracks().forEach(t => t.stop()); mediaStream = null; }\n if (processor) { processor.disconnect(); processor = null; }\n if (audioContext) { audioContext.close(); audioContext = null; }\n if (ws.readyState === WebSocket.OPEN) {\n ws.send(JSON.stringify({ type: 'input_audio_buffer.commit' }));\n ws.close();\n }\n };\n\n return new Promise((resolve, reject) => {\n ws.onmessage = async (event) => {\n const data = JSON.parse(event.data);\n\n if (data.type === 'session.created') {\n // Start recording\n try {\n mediaStream = await navigator.mediaDevices.getUserMedia({\n audio: { sampleRate: 16000, channelCount: 1, echoCancellation: true }\n });\n audioContext = new AudioContext({ sampleRate: 16000 });\n const source = audioContext.createMediaStreamSource(mediaStream);\n processor = audioContext.createScriptProcessor(4096, 1, 1);\n\n processor.onaudioprocess = (e) => {\n if (ws.readyState !== WebSocket.OPEN) return;\n const input = e.inputBuffer.getChannelData(0);\n const pcm = new Int16Array(input.length);\n for (let i = 0; i < input.length; i++) {\n const s = Math.max(-1, Math.min(1, input[i]!));\n pcm[i] = s < 0 ? s * 32768 : s * 32767;\n }\n const bytes = new Uint8Array(pcm.buffer);\n let binary = '';\n for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]!);\n ws.send(JSON.stringify({ type: 'input_audio_buffer.append', audio: btoa(binary) }));\n };\n\n source.connect(processor);\n processor.connect(audioContext.destination);\n resolve(stop);\n } catch (err) {\n reject(err);\n }\n }\n\n if (data.type === 'conversation.item.input_audio_transcription.text') {\n onTranscript(data.text || '', false);\n }\n\n if (data.type === 'conversation.item.input_audio_transcription.completed') {\n onTranscript(data.text || data.transcript || '', true);\n }\n\n if (data.type === 'error') {\n stop();\n reject(new Error(data.error?.message || 'ASR error'));\n }\n };\n\n ws.onerror = () => reject(new Error('ASR connection failed'));\n });\n}\n\nexport interface ASRClientConfig {\n /** Audio format, default 'pcm16' */\n audioFormat?: 'pcm16' | 'g711a' | 'g711u';\n /** Sample rate, default 16000 */\n sampleRate?: number;\n /** Called when connection is ready */\n onReady?: () => void;\n /** Called when speech is detected */\n onSpeechStart?: () => void;\n /** Called when speech stops */\n onSpeechEnd?: () => void;\n /** Called on transcript result */\n onTranscript?: (text: string, isFinal: boolean) => void;\n /** Called on error */\n onError?: (error: Error) => void;\n}\n\nexport interface ASRClient {\n /** Connect to ASR service */\n connect(): Promise<void>;\n /** Start recording from microphone */\n startRecording(): Promise<void>;\n /** Stop recording */\n stopRecording(): void;\n /** Close connection */\n close(): void;\n}\n\nexport function createASRClient(config: ASRClientConfig): ASRClient {\n const {\n // audioFormat = 'pcm16',\n sampleRate = 16000,\n onReady,\n onSpeechStart,\n onSpeechEnd,\n onTranscript,\n onError,\n } = config;\n\n let ws: WebSocket | null = null;\n let mediaStream: MediaStream | null = null;\n let audioContext: AudioContext | null = null;\n let processor: ScriptProcessorNode | null = null;\n\n async function connect(): Promise<void> {\n return new Promise((resolve, reject) => {\n ws = new WebSocket(ASR_PATH);\n\n ws.onopen = () => {};\n\n ws.onmessage = (event) => {\n const data = JSON.parse(event.data);\n\n if (data.type === 'session.created') {\n onReady?.();\n resolve();\n }\n\n if (data.type === 'input_audio_buffer.speech_started') {\n onSpeechStart?.();\n }\n\n if (data.type === 'input_audio_buffer.speech_stopped') {\n onSpeechEnd?.();\n }\n\n if (data.type === 'conversation.item.input_audio_transcription.text') {\n onTranscript?.(data.text || '', false);\n }\n\n if (data.type === 'conversation.item.input_audio_transcription.completed') {\n onTranscript?.(data.text || data.transcript || '', true);\n }\n\n if (data.type === 'error') {\n const err = new Error(data.error?.message || 'Unknown error');\n onError?.(err);\n reject(err);\n }\n };\n\n ws.onerror = () => {\n const err = new Error('WebSocket connection error');\n onError?.(err);\n reject(err);\n };\n\n ws.onclose = () => {\n ws = null;\n };\n });\n }\n\n async function startRecording(): Promise<void> {\n if (typeof window === 'undefined') {\n throw new Error('Recording only supported in browser');\n }\n\n if (!ws || ws.readyState !== WebSocket.OPEN) {\n throw new Error('WebSocket not connected');\n }\n\n try {\n mediaStream = await navigator.mediaDevices.getUserMedia({\n audio: {\n sampleRate,\n channelCount: 1,\n echoCancellation: true,\n noiseSuppression: true,\n },\n });\n\n audioContext = new AudioContext({ sampleRate });\n const source = audioContext.createMediaStreamSource(mediaStream);\n processor = audioContext.createScriptProcessor(4096, 1, 1);\n\n processor.onaudioprocess = (e) => {\n if (!ws || ws.readyState !== WebSocket.OPEN) return;\n\n const inputData = e.inputBuffer.getChannelData(0);\n const inputLen = inputData.length;\n\n const pcm = new Int16Array(inputLen);\n for (let i = 0; i < inputLen; i++) {\n const s = Math.max(-1, Math.min(1, inputData[i]!));\n pcm[i] = s < 0 ? s * 32768 : s * 32767;\n }\n\n const bytes = new Uint8Array(pcm.buffer);\n const len = bytes.length;\n let binary = '';\n for (let i = 0; i < len; i++) {\n binary += String.fromCharCode(bytes[i]!);\n }\n const base64 = btoa(binary);\n\n ws.send(JSON.stringify({\n type: 'input_audio_buffer.append',\n audio: base64,\n }));\n };\n\n source.connect(processor);\n processor.connect(audioContext.destination);\n } catch (err) {\n onError?.(err as Error);\n throw err;\n }\n }\n\n function stopRecording() {\n if (mediaStream) {\n mediaStream.getTracks().forEach(track => track.stop());\n mediaStream = null;\n }\n\n if (processor) {\n processor.disconnect();\n processor = null;\n }\n\n if (audioContext) {\n audioContext.close();\n audioContext = null;\n }\n\n if (ws && ws.readyState === WebSocket.OPEN) {\n ws.send(JSON.stringify({ type: 'input_audio_buffer.commit' }));\n }\n }\n\n function close() {\n stopRecording();\n if (ws) {\n ws.close();\n ws = null;\n }\n }\n\n return {\n connect,\n startRecording,\n stopRecording,\n close,\n };\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* ASR Realtime WebSocket Client
|
|
3
3
|
*/
|
|
4
|
+
/**
|
|
5
|
+
* Simple ASR: start listening and get transcript
|
|
6
|
+
* @returns stop function
|
|
7
|
+
* @example
|
|
8
|
+
* const stop = await listen((text, isFinal) => console.log(text))
|
|
9
|
+
* // later: stop()
|
|
10
|
+
*/
|
|
11
|
+
declare function listen(onTranscript: (text: string, isFinal: boolean) => void): Promise<() => void>;
|
|
4
12
|
interface ASRClientConfig {
|
|
5
|
-
/** WebSocket endpoint URL */
|
|
6
|
-
url: string;
|
|
7
13
|
/** Audio format, default 'pcm16' */
|
|
8
14
|
audioFormat?: 'pcm16' | 'g711a' | 'g711u';
|
|
9
15
|
/** Sample rate, default 16000 */
|
|
@@ -31,4 +37,4 @@ interface ASRClient {
|
|
|
31
37
|
}
|
|
32
38
|
declare function createASRClient(config: ASRClientConfig): ASRClient;
|
|
33
39
|
|
|
34
|
-
export { type ASRClient, type ASRClientConfig, createASRClient };
|
|
40
|
+
export { type ASRClient, type ASRClientConfig, createASRClient, createASRClient as createAsrClient, listen };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* ASR Realtime WebSocket Client
|
|
3
3
|
*/
|
|
4
|
+
/**
|
|
5
|
+
* Simple ASR: start listening and get transcript
|
|
6
|
+
* @returns stop function
|
|
7
|
+
* @example
|
|
8
|
+
* const stop = await listen((text, isFinal) => console.log(text))
|
|
9
|
+
* // later: stop()
|
|
10
|
+
*/
|
|
11
|
+
declare function listen(onTranscript: (text: string, isFinal: boolean) => void): Promise<() => void>;
|
|
4
12
|
interface ASRClientConfig {
|
|
5
|
-
/** WebSocket endpoint URL */
|
|
6
|
-
url: string;
|
|
7
13
|
/** Audio format, default 'pcm16' */
|
|
8
14
|
audioFormat?: 'pcm16' | 'g711a' | 'g711u';
|
|
9
15
|
/** Sample rate, default 16000 */
|
|
@@ -31,4 +37,4 @@ interface ASRClient {
|
|
|
31
37
|
}
|
|
32
38
|
declare function createASRClient(config: ASRClientConfig): ASRClient;
|
|
33
39
|
|
|
34
|
-
export { type ASRClient, type ASRClientConfig, createASRClient };
|
|
40
|
+
export { type ASRClient, type ASRClientConfig, createASRClient, createASRClient as createAsrClient, listen };
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,76 @@
|
|
|
1
1
|
// src/asr-client.ts
|
|
2
|
+
var ASR_PATH = "/api/proxy/builtin/platform/qwen-asr-realtime/api-ws/v1/realtime";
|
|
3
|
+
async function listen(onTranscript) {
|
|
4
|
+
const ws = new WebSocket(ASR_PATH);
|
|
5
|
+
let mediaStream = null;
|
|
6
|
+
let audioContext = null;
|
|
7
|
+
let processor = null;
|
|
8
|
+
const stop = () => {
|
|
9
|
+
if (mediaStream) {
|
|
10
|
+
mediaStream.getTracks().forEach((t) => t.stop());
|
|
11
|
+
mediaStream = null;
|
|
12
|
+
}
|
|
13
|
+
if (processor) {
|
|
14
|
+
processor.disconnect();
|
|
15
|
+
processor = null;
|
|
16
|
+
}
|
|
17
|
+
if (audioContext) {
|
|
18
|
+
audioContext.close();
|
|
19
|
+
audioContext = null;
|
|
20
|
+
}
|
|
21
|
+
if (ws.readyState === WebSocket.OPEN) {
|
|
22
|
+
ws.send(JSON.stringify({ type: "input_audio_buffer.commit" }));
|
|
23
|
+
ws.close();
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
return new Promise((resolve, reject) => {
|
|
27
|
+
ws.onmessage = async (event) => {
|
|
28
|
+
const data = JSON.parse(event.data);
|
|
29
|
+
if (data.type === "session.created") {
|
|
30
|
+
try {
|
|
31
|
+
mediaStream = await navigator.mediaDevices.getUserMedia({
|
|
32
|
+
audio: { sampleRate: 16e3, channelCount: 1, echoCancellation: true }
|
|
33
|
+
});
|
|
34
|
+
audioContext = new AudioContext({ sampleRate: 16e3 });
|
|
35
|
+
const source = audioContext.createMediaStreamSource(mediaStream);
|
|
36
|
+
processor = audioContext.createScriptProcessor(4096, 1, 1);
|
|
37
|
+
processor.onaudioprocess = (e) => {
|
|
38
|
+
if (ws.readyState !== WebSocket.OPEN) return;
|
|
39
|
+
const input = e.inputBuffer.getChannelData(0);
|
|
40
|
+
const pcm = new Int16Array(input.length);
|
|
41
|
+
for (let i = 0; i < input.length; i++) {
|
|
42
|
+
const s = Math.max(-1, Math.min(1, input[i]));
|
|
43
|
+
pcm[i] = s < 0 ? s * 32768 : s * 32767;
|
|
44
|
+
}
|
|
45
|
+
const bytes = new Uint8Array(pcm.buffer);
|
|
46
|
+
let binary = "";
|
|
47
|
+
for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]);
|
|
48
|
+
ws.send(JSON.stringify({ type: "input_audio_buffer.append", audio: btoa(binary) }));
|
|
49
|
+
};
|
|
50
|
+
source.connect(processor);
|
|
51
|
+
processor.connect(audioContext.destination);
|
|
52
|
+
resolve(stop);
|
|
53
|
+
} catch (err) {
|
|
54
|
+
reject(err);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (data.type === "conversation.item.input_audio_transcription.text") {
|
|
58
|
+
onTranscript(data.text || "", false);
|
|
59
|
+
}
|
|
60
|
+
if (data.type === "conversation.item.input_audio_transcription.completed") {
|
|
61
|
+
onTranscript(data.text || data.transcript || "", true);
|
|
62
|
+
}
|
|
63
|
+
if (data.type === "error") {
|
|
64
|
+
stop();
|
|
65
|
+
reject(new Error(data.error?.message || "ASR error"));
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
ws.onerror = () => reject(new Error("ASR connection failed"));
|
|
69
|
+
});
|
|
70
|
+
}
|
|
2
71
|
function createASRClient(config) {
|
|
3
72
|
const {
|
|
4
|
-
|
|
5
|
-
audioFormat = "pcm16",
|
|
73
|
+
// audioFormat = 'pcm16',
|
|
6
74
|
sampleRate = 16e3,
|
|
7
75
|
onReady,
|
|
8
76
|
onSpeechStart,
|
|
@@ -16,37 +84,36 @@ function createASRClient(config) {
|
|
|
16
84
|
let processor = null;
|
|
17
85
|
async function connect() {
|
|
18
86
|
return new Promise((resolve, reject) => {
|
|
19
|
-
ws = new WebSocket(
|
|
87
|
+
ws = new WebSocket(ASR_PATH);
|
|
20
88
|
ws.onopen = () => {
|
|
21
89
|
};
|
|
22
90
|
ws.onmessage = (event) => {
|
|
23
|
-
var _a;
|
|
24
91
|
const data = JSON.parse(event.data);
|
|
25
92
|
if (data.type === "session.created") {
|
|
26
|
-
onReady
|
|
93
|
+
onReady?.();
|
|
27
94
|
resolve();
|
|
28
95
|
}
|
|
29
96
|
if (data.type === "input_audio_buffer.speech_started") {
|
|
30
|
-
onSpeechStart
|
|
97
|
+
onSpeechStart?.();
|
|
31
98
|
}
|
|
32
99
|
if (data.type === "input_audio_buffer.speech_stopped") {
|
|
33
|
-
onSpeechEnd
|
|
100
|
+
onSpeechEnd?.();
|
|
34
101
|
}
|
|
35
102
|
if (data.type === "conversation.item.input_audio_transcription.text") {
|
|
36
|
-
onTranscript
|
|
103
|
+
onTranscript?.(data.text || "", false);
|
|
37
104
|
}
|
|
38
105
|
if (data.type === "conversation.item.input_audio_transcription.completed") {
|
|
39
|
-
onTranscript
|
|
106
|
+
onTranscript?.(data.text || data.transcript || "", true);
|
|
40
107
|
}
|
|
41
108
|
if (data.type === "error") {
|
|
42
|
-
const err = new Error(
|
|
43
|
-
onError
|
|
109
|
+
const err = new Error(data.error?.message || "Unknown error");
|
|
110
|
+
onError?.(err);
|
|
44
111
|
reject(err);
|
|
45
112
|
}
|
|
46
113
|
};
|
|
47
114
|
ws.onerror = () => {
|
|
48
115
|
const err = new Error("WebSocket connection error");
|
|
49
|
-
onError
|
|
116
|
+
onError?.(err);
|
|
50
117
|
reject(err);
|
|
51
118
|
};
|
|
52
119
|
ws.onclose = () => {
|
|
@@ -76,14 +143,16 @@ function createASRClient(config) {
|
|
|
76
143
|
processor.onaudioprocess = (e) => {
|
|
77
144
|
if (!ws || ws.readyState !== WebSocket.OPEN) return;
|
|
78
145
|
const inputData = e.inputBuffer.getChannelData(0);
|
|
79
|
-
const
|
|
80
|
-
|
|
146
|
+
const inputLen = inputData.length;
|
|
147
|
+
const pcm = new Int16Array(inputLen);
|
|
148
|
+
for (let i = 0; i < inputLen; i++) {
|
|
81
149
|
const s = Math.max(-1, Math.min(1, inputData[i]));
|
|
82
150
|
pcm[i] = s < 0 ? s * 32768 : s * 32767;
|
|
83
151
|
}
|
|
84
152
|
const bytes = new Uint8Array(pcm.buffer);
|
|
153
|
+
const len = bytes.length;
|
|
85
154
|
let binary = "";
|
|
86
|
-
for (let i = 0; i <
|
|
155
|
+
for (let i = 0; i < len; i++) {
|
|
87
156
|
binary += String.fromCharCode(bytes[i]);
|
|
88
157
|
}
|
|
89
158
|
const base64 = btoa(binary);
|
|
@@ -95,7 +164,7 @@ function createASRClient(config) {
|
|
|
95
164
|
source.connect(processor);
|
|
96
165
|
processor.connect(audioContext.destination);
|
|
97
166
|
} catch (err) {
|
|
98
|
-
onError
|
|
167
|
+
onError?.(err);
|
|
99
168
|
throw err;
|
|
100
169
|
}
|
|
101
170
|
}
|
|
@@ -131,6 +200,8 @@ function createASRClient(config) {
|
|
|
131
200
|
};
|
|
132
201
|
}
|
|
133
202
|
export {
|
|
134
|
-
createASRClient
|
|
203
|
+
createASRClient,
|
|
204
|
+
createASRClient as createAsrClient,
|
|
205
|
+
listen
|
|
135
206
|
};
|
|
136
207
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/asr-client.ts"],"sourcesContent":["/**\n * ASR Realtime WebSocket Client\n */\n\nexport interface ASRClientConfig {\n /** WebSocket endpoint URL */\n url: string;\n /** Audio format, default 'pcm16' */\n audioFormat?: 'pcm16' | 'g711a' | 'g711u';\n /** Sample rate, default 16000 */\n sampleRate?: number;\n /** Called when connection is ready */\n onReady?: () => void;\n /** Called when speech is detected */\n onSpeechStart?: () => void;\n /** Called when speech stops */\n onSpeechEnd?: () => void;\n /** Called on transcript result */\n onTranscript?: (text: string, isFinal: boolean) => void;\n /** Called on error */\n onError?: (error: Error) => void;\n}\n\nexport interface ASRClient {\n /** Connect to ASR service */\n connect(): Promise<void>;\n /** Start recording from microphone */\n startRecording(): Promise<void>;\n /** Stop recording */\n stopRecording(): void;\n /** Close connection */\n close(): void;\n}\n\nexport function createASRClient(config: ASRClientConfig): ASRClient {\n const {\n url,\n audioFormat = 'pcm16',\n sampleRate = 16000,\n onReady,\n onSpeechStart,\n onSpeechEnd,\n onTranscript,\n onError,\n } = config;\n\n let ws: WebSocket | null = null;\n let mediaStream: MediaStream | null = null;\n let audioContext: AudioContext | null = null;\n let processor: ScriptProcessorNode | null = null;\n\n async function connect(): Promise<void> {\n return new Promise((resolve, reject) => {\n ws = new WebSocket(url);\n\n ws.onopen = () => {};\n\n ws.onmessage = (event) => {\n const data = JSON.parse(event.data);\n\n if (data.type === 'session.created') {\n onReady?.();\n resolve();\n }\n\n if (data.type === 'input_audio_buffer.speech_started') {\n onSpeechStart?.();\n }\n\n if (data.type === 'input_audio_buffer.speech_stopped') {\n onSpeechEnd?.();\n }\n\n if (data.type === 'conversation.item.input_audio_transcription.text') {\n onTranscript?.(data.text || '', false);\n }\n\n if (data.type === 'conversation.item.input_audio_transcription.completed') {\n onTranscript?.(data.text || data.transcript || '', true);\n }\n\n if (data.type === 'error') {\n const err = new Error(data.error?.message || 'Unknown error');\n onError?.(err);\n reject(err);\n }\n };\n\n ws.onerror = () => {\n const err = new Error('WebSocket connection error');\n onError?.(err);\n reject(err);\n };\n\n ws.onclose = () => {\n ws = null;\n };\n });\n }\n\n async function startRecording(): Promise<void> {\n if (typeof window === 'undefined') {\n throw new Error('Recording only supported in browser');\n }\n\n if (!ws || ws.readyState !== WebSocket.OPEN) {\n throw new Error('WebSocket not connected');\n }\n\n try {\n mediaStream = await navigator.mediaDevices.getUserMedia({\n audio: {\n sampleRate,\n channelCount: 1,\n echoCancellation: true,\n noiseSuppression: true,\n },\n });\n\n audioContext = new AudioContext({ sampleRate });\n const source = audioContext.createMediaStreamSource(mediaStream);\n processor = audioContext.createScriptProcessor(4096, 1, 1);\n\n processor.onaudioprocess = (e) => {\n if (!ws || ws.readyState !== WebSocket.OPEN) return;\n\n const inputData = e.inputBuffer.getChannelData(0);\n\n const pcm = new Int16Array(inputData.length);\n for (let i = 0; i < inputData.length; i++) {\n const s = Math.max(-1, Math.min(1, inputData[i]));\n pcm[i] = s < 0 ? s * 32768 : s * 32767;\n }\n\n const bytes = new Uint8Array(pcm.buffer);\n let binary = '';\n for (let i = 0; i < bytes.length; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n const base64 = btoa(binary);\n\n ws.send(JSON.stringify({\n type: 'input_audio_buffer.append',\n audio: base64,\n }));\n };\n\n source.connect(processor);\n processor.connect(audioContext.destination);\n } catch (err) {\n onError?.(err as Error);\n throw err;\n }\n }\n\n function stopRecording() {\n if (mediaStream) {\n mediaStream.getTracks().forEach(track => track.stop());\n mediaStream = null;\n }\n\n if (processor) {\n processor.disconnect();\n processor = null;\n }\n\n if (audioContext) {\n audioContext.close();\n audioContext = null;\n }\n\n if (ws && ws.readyState === WebSocket.OPEN) {\n ws.send(JSON.stringify({ type: 'input_audio_buffer.commit' }));\n }\n }\n\n function close() {\n stopRecording();\n if (ws) {\n ws.close();\n ws = null;\n }\n }\n\n return {\n connect,\n startRecording,\n stopRecording,\n close,\n };\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/asr-client.ts"],"sourcesContent":["/**\n * ASR Realtime WebSocket Client\n */\n\nconst ASR_PATH = '/api/proxy/builtin/platform/qwen-asr-realtime/api-ws/v1/realtime';\n\n/**\n * Simple ASR: start listening and get transcript\n * @returns stop function\n * @example\n * const stop = await listen((text, isFinal) => console.log(text))\n * // later: stop()\n */\nexport async function listen(\n onTranscript: (text: string, isFinal: boolean) => void\n): Promise<() => void> {\n const ws = new WebSocket(ASR_PATH);\n let mediaStream: MediaStream | null = null;\n let audioContext: AudioContext | null = null;\n let processor: ScriptProcessorNode | null = null;\n\n const stop = () => {\n if (mediaStream) { mediaStream.getTracks().forEach(t => t.stop()); mediaStream = null; }\n if (processor) { processor.disconnect(); processor = null; }\n if (audioContext) { audioContext.close(); audioContext = null; }\n if (ws.readyState === WebSocket.OPEN) {\n ws.send(JSON.stringify({ type: 'input_audio_buffer.commit' }));\n ws.close();\n }\n };\n\n return new Promise((resolve, reject) => {\n ws.onmessage = async (event) => {\n const data = JSON.parse(event.data);\n\n if (data.type === 'session.created') {\n // Start recording\n try {\n mediaStream = await navigator.mediaDevices.getUserMedia({\n audio: { sampleRate: 16000, channelCount: 1, echoCancellation: true }\n });\n audioContext = new AudioContext({ sampleRate: 16000 });\n const source = audioContext.createMediaStreamSource(mediaStream);\n processor = audioContext.createScriptProcessor(4096, 1, 1);\n\n processor.onaudioprocess = (e) => {\n if (ws.readyState !== WebSocket.OPEN) return;\n const input = e.inputBuffer.getChannelData(0);\n const pcm = new Int16Array(input.length);\n for (let i = 0; i < input.length; i++) {\n const s = Math.max(-1, Math.min(1, input[i]!));\n pcm[i] = s < 0 ? s * 32768 : s * 32767;\n }\n const bytes = new Uint8Array(pcm.buffer);\n let binary = '';\n for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]!);\n ws.send(JSON.stringify({ type: 'input_audio_buffer.append', audio: btoa(binary) }));\n };\n\n source.connect(processor);\n processor.connect(audioContext.destination);\n resolve(stop);\n } catch (err) {\n reject(err);\n }\n }\n\n if (data.type === 'conversation.item.input_audio_transcription.text') {\n onTranscript(data.text || '', false);\n }\n\n if (data.type === 'conversation.item.input_audio_transcription.completed') {\n onTranscript(data.text || data.transcript || '', true);\n }\n\n if (data.type === 'error') {\n stop();\n reject(new Error(data.error?.message || 'ASR error'));\n }\n };\n\n ws.onerror = () => reject(new Error('ASR connection failed'));\n });\n}\n\nexport interface ASRClientConfig {\n /** Audio format, default 'pcm16' */\n audioFormat?: 'pcm16' | 'g711a' | 'g711u';\n /** Sample rate, default 16000 */\n sampleRate?: number;\n /** Called when connection is ready */\n onReady?: () => void;\n /** Called when speech is detected */\n onSpeechStart?: () => void;\n /** Called when speech stops */\n onSpeechEnd?: () => void;\n /** Called on transcript result */\n onTranscript?: (text: string, isFinal: boolean) => void;\n /** Called on error */\n onError?: (error: Error) => void;\n}\n\nexport interface ASRClient {\n /** Connect to ASR service */\n connect(): Promise<void>;\n /** Start recording from microphone */\n startRecording(): Promise<void>;\n /** Stop recording */\n stopRecording(): void;\n /** Close connection */\n close(): void;\n}\n\nexport function createASRClient(config: ASRClientConfig): ASRClient {\n const {\n // audioFormat = 'pcm16',\n sampleRate = 16000,\n onReady,\n onSpeechStart,\n onSpeechEnd,\n onTranscript,\n onError,\n } = config;\n\n let ws: WebSocket | null = null;\n let mediaStream: MediaStream | null = null;\n let audioContext: AudioContext | null = null;\n let processor: ScriptProcessorNode | null = null;\n\n async function connect(): Promise<void> {\n return new Promise((resolve, reject) => {\n ws = new WebSocket(ASR_PATH);\n\n ws.onopen = () => {};\n\n ws.onmessage = (event) => {\n const data = JSON.parse(event.data);\n\n if (data.type === 'session.created') {\n onReady?.();\n resolve();\n }\n\n if (data.type === 'input_audio_buffer.speech_started') {\n onSpeechStart?.();\n }\n\n if (data.type === 'input_audio_buffer.speech_stopped') {\n onSpeechEnd?.();\n }\n\n if (data.type === 'conversation.item.input_audio_transcription.text') {\n onTranscript?.(data.text || '', false);\n }\n\n if (data.type === 'conversation.item.input_audio_transcription.completed') {\n onTranscript?.(data.text || data.transcript || '', true);\n }\n\n if (data.type === 'error') {\n const err = new Error(data.error?.message || 'Unknown error');\n onError?.(err);\n reject(err);\n }\n };\n\n ws.onerror = () => {\n const err = new Error('WebSocket connection error');\n onError?.(err);\n reject(err);\n };\n\n ws.onclose = () => {\n ws = null;\n };\n });\n }\n\n async function startRecording(): Promise<void> {\n if (typeof window === 'undefined') {\n throw new Error('Recording only supported in browser');\n }\n\n if (!ws || ws.readyState !== WebSocket.OPEN) {\n throw new Error('WebSocket not connected');\n }\n\n try {\n mediaStream = await navigator.mediaDevices.getUserMedia({\n audio: {\n sampleRate,\n channelCount: 1,\n echoCancellation: true,\n noiseSuppression: true,\n },\n });\n\n audioContext = new AudioContext({ sampleRate });\n const source = audioContext.createMediaStreamSource(mediaStream);\n processor = audioContext.createScriptProcessor(4096, 1, 1);\n\n processor.onaudioprocess = (e) => {\n if (!ws || ws.readyState !== WebSocket.OPEN) return;\n\n const inputData = e.inputBuffer.getChannelData(0);\n const inputLen = inputData.length;\n\n const pcm = new Int16Array(inputLen);\n for (let i = 0; i < inputLen; i++) {\n const s = Math.max(-1, Math.min(1, inputData[i]!));\n pcm[i] = s < 0 ? s * 32768 : s * 32767;\n }\n\n const bytes = new Uint8Array(pcm.buffer);\n const len = bytes.length;\n let binary = '';\n for (let i = 0; i < len; i++) {\n binary += String.fromCharCode(bytes[i]!);\n }\n const base64 = btoa(binary);\n\n ws.send(JSON.stringify({\n type: 'input_audio_buffer.append',\n audio: base64,\n }));\n };\n\n source.connect(processor);\n processor.connect(audioContext.destination);\n } catch (err) {\n onError?.(err as Error);\n throw err;\n }\n }\n\n function stopRecording() {\n if (mediaStream) {\n mediaStream.getTracks().forEach(track => track.stop());\n mediaStream = null;\n }\n\n if (processor) {\n processor.disconnect();\n processor = null;\n }\n\n if (audioContext) {\n audioContext.close();\n audioContext = null;\n }\n\n if (ws && ws.readyState === WebSocket.OPEN) {\n ws.send(JSON.stringify({ type: 'input_audio_buffer.commit' }));\n }\n }\n\n function close() {\n stopRecording();\n if (ws) {\n ws.close();\n ws = null;\n }\n }\n\n return {\n connect,\n startRecording,\n stopRecording,\n close,\n };\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@amaster.ai/asr-client",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.12",
|
|
4
4
|
"description": "Qwen ASR Realtime WebSocket client with microphone recording",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -8,9 +8,9 @@
|
|
|
8
8
|
"types": "./dist/index.d.ts",
|
|
9
9
|
"exports": {
|
|
10
10
|
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
11
12
|
"import": "./dist/index.js",
|
|
12
|
-
"require": "./dist/index.cjs"
|
|
13
|
-
"types": "./dist/index.d.ts"
|
|
13
|
+
"require": "./dist/index.cjs"
|
|
14
14
|
}
|
|
15
15
|
},
|
|
16
16
|
"files": [
|