@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 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
- url,
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(url);
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 == null ? void 0 : onReady();
121
+ onReady?.();
52
122
  resolve();
53
123
  }
54
124
  if (data.type === "input_audio_buffer.speech_started") {
55
- onSpeechStart == null ? void 0 : onSpeechStart();
125
+ onSpeechStart?.();
56
126
  }
57
127
  if (data.type === "input_audio_buffer.speech_stopped") {
58
- onSpeechEnd == null ? void 0 : onSpeechEnd();
128
+ onSpeechEnd?.();
59
129
  }
60
130
  if (data.type === "conversation.item.input_audio_transcription.text") {
61
- onTranscript == null ? void 0 : onTranscript(data.text || "", false);
131
+ onTranscript?.(data.text || "", false);
62
132
  }
63
133
  if (data.type === "conversation.item.input_audio_transcription.completed") {
64
- onTranscript == null ? void 0 : onTranscript(data.text || data.transcript || "", true);
134
+ onTranscript?.(data.text || data.transcript || "", true);
65
135
  }
66
136
  if (data.type === "error") {
67
- const err = new Error(((_a = data.error) == null ? void 0 : _a.message) || "Unknown error");
68
- onError == null ? void 0 : onError(err);
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 == null ? void 0 : onError(err);
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 pcm = new Int16Array(inputData.length);
105
- for (let i = 0; i < inputData.length; i++) {
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 < bytes.length; 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 == null ? void 0 : onError(err);
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
@@ -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":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACIA,IAAM,WAAW;AASjB,eAAsB,OACpB,cACqB;AACrB,QAAM,KAAK,IAAI,UAAU,QAAQ;AACjC,MAAI,cAAkC;AACtC,MAAI,eAAoC;AACxC,MAAI,YAAwC;AAE5C,QAAM,OAAO,MAAM;AACjB,QAAI,aAAa;AAAE,kBAAY,UAAU,EAAE,QAAQ,OAAK,EAAE,KAAK,CAAC;AAAG,oBAAc;AAAA,IAAM;AACvF,QAAI,WAAW;AAAE,gBAAU,WAAW;AAAG,kBAAY;AAAA,IAAM;AAC3D,QAAI,cAAc;AAAE,mBAAa,MAAM;AAAG,qBAAe;AAAA,IAAM;AAC/D,QAAI,GAAG,eAAe,UAAU,MAAM;AACpC,SAAG,KAAK,KAAK,UAAU,EAAE,MAAM,4BAA4B,CAAC,CAAC;AAC7D,SAAG,MAAM;AAAA,IACX;AAAA,EACF;AAEA,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,OAAG,YAAY,OAAO,UAAU;AAC9B,YAAM,OAAO,KAAK,MAAM,MAAM,IAAI;AAElC,UAAI,KAAK,SAAS,mBAAmB;AAEnC,YAAI;AACF,wBAAc,MAAM,UAAU,aAAa,aAAa;AAAA,YACtD,OAAO,EAAE,YAAY,MAAO,cAAc,GAAG,kBAAkB,KAAK;AAAA,UACtE,CAAC;AACD,yBAAe,IAAI,aAAa,EAAE,YAAY,KAAM,CAAC;AACrD,gBAAM,SAAS,aAAa,wBAAwB,WAAW;AAC/D,sBAAY,aAAa,sBAAsB,MAAM,GAAG,CAAC;AAEzD,oBAAU,iBAAiB,CAAC,MAAM;AAChC,gBAAI,GAAG,eAAe,UAAU,KAAM;AACtC,kBAAM,QAAQ,EAAE,YAAY,eAAe,CAAC;AAC5C,kBAAM,MAAM,IAAI,WAAW,MAAM,MAAM;AACvC,qBAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,oBAAM,IAAI,KAAK,IAAI,IAAI,KAAK,IAAI,GAAG,MAAM,CAAC,CAAE,CAAC;AAC7C,kBAAI,CAAC,IAAI,IAAI,IAAI,IAAI,QAAQ,IAAI;AAAA,YACnC;AACA,kBAAM,QAAQ,IAAI,WAAW,IAAI,MAAM;AACvC,gBAAI,SAAS;AACb,qBAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,IAAK,WAAU,OAAO,aAAa,MAAM,CAAC,CAAE;AAC9E,eAAG,KAAK,KAAK,UAAU,EAAE,MAAM,6BAA6B,OAAO,KAAK,MAAM,EAAE,CAAC,CAAC;AAAA,UACpF;AAEA,iBAAO,QAAQ,SAAS;AACxB,oBAAU,QAAQ,aAAa,WAAW;AAC1C,kBAAQ,IAAI;AAAA,QACd,SAAS,KAAK;AACZ,iBAAO,GAAG;AAAA,QACZ;AAAA,MACF;AAEA,UAAI,KAAK,SAAS,oDAAoD;AACpE,qBAAa,KAAK,QAAQ,IAAI,KAAK;AAAA,MACrC;AAEA,UAAI,KAAK,SAAS,yDAAyD;AACzE,qBAAa,KAAK,QAAQ,KAAK,cAAc,IAAI,IAAI;AAAA,MACvD;AAEA,UAAI,KAAK,SAAS,SAAS;AACzB,aAAK;AACL,eAAO,IAAI,MAAM,KAAK,OAAO,WAAW,WAAW,CAAC;AAAA,MACtD;AAAA,IACF;AAEA,OAAG,UAAU,MAAM,OAAO,IAAI,MAAM,uBAAuB,CAAC;AAAA,EAC9D,CAAC;AACH;AA8BO,SAAS,gBAAgB,QAAoC;AAClE,QAAM;AAAA;AAAA,IAEJ,aAAa;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI;AAEJ,MAAI,KAAuB;AAC3B,MAAI,cAAkC;AACtC,MAAI,eAAoC;AACxC,MAAI,YAAwC;AAE5C,iBAAe,UAAyB;AACtC,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,WAAK,IAAI,UAAU,QAAQ;AAE3B,SAAG,SAAS,MAAM;AAAA,MAAC;AAEnB,SAAG,YAAY,CAAC,UAAU;AACxB,cAAM,OAAO,KAAK,MAAM,MAAM,IAAI;AAElC,YAAI,KAAK,SAAS,mBAAmB;AACnC,oBAAU;AACV,kBAAQ;AAAA,QACV;AAEA,YAAI,KAAK,SAAS,qCAAqC;AACrD,0BAAgB;AAAA,QAClB;AAEA,YAAI,KAAK,SAAS,qCAAqC;AACrD,wBAAc;AAAA,QAChB;AAEA,YAAI,KAAK,SAAS,oDAAoD;AACpE,yBAAe,KAAK,QAAQ,IAAI,KAAK;AAAA,QACvC;AAEA,YAAI,KAAK,SAAS,yDAAyD;AACzE,yBAAe,KAAK,QAAQ,KAAK,cAAc,IAAI,IAAI;AAAA,QACzD;AAEA,YAAI,KAAK,SAAS,SAAS;AACzB,gBAAM,MAAM,IAAI,MAAM,KAAK,OAAO,WAAW,eAAe;AAC5D,oBAAU,GAAG;AACb,iBAAO,GAAG;AAAA,QACZ;AAAA,MACF;AAEA,SAAG,UAAU,MAAM;AACjB,cAAM,MAAM,IAAI,MAAM,4BAA4B;AAClD,kBAAU,GAAG;AACb,eAAO,GAAG;AAAA,MACZ;AAEA,SAAG,UAAU,MAAM;AACjB,aAAK;AAAA,MACP;AAAA,IACF,CAAC;AAAA,EACH;AAEA,iBAAe,iBAAgC;AAC7C,QAAI,OAAO,WAAW,aAAa;AACjC,YAAM,IAAI,MAAM,qCAAqC;AAAA,IACvD;AAEA,QAAI,CAAC,MAAM,GAAG,eAAe,UAAU,MAAM;AAC3C,YAAM,IAAI,MAAM,yBAAyB;AAAA,IAC3C;AAEA,QAAI;AACF,oBAAc,MAAM,UAAU,aAAa,aAAa;AAAA,QACtD,OAAO;AAAA,UACL;AAAA,UACA,cAAc;AAAA,UACd,kBAAkB;AAAA,UAClB,kBAAkB;AAAA,QACpB;AAAA,MACF,CAAC;AAED,qBAAe,IAAI,aAAa,EAAE,WAAW,CAAC;AAC9C,YAAM,SAAS,aAAa,wBAAwB,WAAW;AAC/D,kBAAY,aAAa,sBAAsB,MAAM,GAAG,CAAC;AAEzD,gBAAU,iBAAiB,CAAC,MAAM;AAChC,YAAI,CAAC,MAAM,GAAG,eAAe,UAAU,KAAM;AAE7C,cAAM,YAAY,EAAE,YAAY,eAAe,CAAC;AAChD,cAAM,WAAW,UAAU;AAE3B,cAAM,MAAM,IAAI,WAAW,QAAQ;AACnC,iBAAS,IAAI,GAAG,IAAI,UAAU,KAAK;AACjC,gBAAM,IAAI,KAAK,IAAI,IAAI,KAAK,IAAI,GAAG,UAAU,CAAC,CAAE,CAAC;AACjD,cAAI,CAAC,IAAI,IAAI,IAAI,IAAI,QAAQ,IAAI;AAAA,QACnC;AAEA,cAAM,QAAQ,IAAI,WAAW,IAAI,MAAM;AACvC,cAAM,MAAM,MAAM;AAClB,YAAI,SAAS;AACb,iBAAS,IAAI,GAAG,IAAI,KAAK,KAAK;AAC5B,oBAAU,OAAO,aAAa,MAAM,CAAC,CAAE;AAAA,QACzC;AACA,cAAM,SAAS,KAAK,MAAM;AAE1B,WAAG,KAAK,KAAK,UAAU;AAAA,UACrB,MAAM;AAAA,UACN,OAAO;AAAA,QACT,CAAC,CAAC;AAAA,MACJ;AAEA,aAAO,QAAQ,SAAS;AACxB,gBAAU,QAAQ,aAAa,WAAW;AAAA,IAC5C,SAAS,KAAK;AACZ,gBAAU,GAAY;AACtB,YAAM;AAAA,IACR;AAAA,EACF;AAEA,WAAS,gBAAgB;AACvB,QAAI,aAAa;AACf,kBAAY,UAAU,EAAE,QAAQ,WAAS,MAAM,KAAK,CAAC;AACrD,oBAAc;AAAA,IAChB;AAEA,QAAI,WAAW;AACb,gBAAU,WAAW;AACrB,kBAAY;AAAA,IACd;AAEA,QAAI,cAAc;AAChB,mBAAa,MAAM;AACnB,qBAAe;AAAA,IACjB;AAEA,QAAI,MAAM,GAAG,eAAe,UAAU,MAAM;AAC1C,SAAG,KAAK,KAAK,UAAU,EAAE,MAAM,4BAA4B,CAAC,CAAC;AAAA,IAC/D;AAAA,EACF;AAEA,WAAS,QAAQ;AACf,kBAAc;AACd,QAAI,IAAI;AACN,SAAG,MAAM;AACT,WAAK;AAAA,IACP;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;","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
- url,
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(url);
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 == null ? void 0 : onReady();
93
+ onReady?.();
27
94
  resolve();
28
95
  }
29
96
  if (data.type === "input_audio_buffer.speech_started") {
30
- onSpeechStart == null ? void 0 : onSpeechStart();
97
+ onSpeechStart?.();
31
98
  }
32
99
  if (data.type === "input_audio_buffer.speech_stopped") {
33
- onSpeechEnd == null ? void 0 : onSpeechEnd();
100
+ onSpeechEnd?.();
34
101
  }
35
102
  if (data.type === "conversation.item.input_audio_transcription.text") {
36
- onTranscript == null ? void 0 : onTranscript(data.text || "", false);
103
+ onTranscript?.(data.text || "", false);
37
104
  }
38
105
  if (data.type === "conversation.item.input_audio_transcription.completed") {
39
- onTranscript == null ? void 0 : onTranscript(data.text || data.transcript || "", true);
106
+ onTranscript?.(data.text || data.transcript || "", true);
40
107
  }
41
108
  if (data.type === "error") {
42
- const err = new Error(((_a = data.error) == null ? void 0 : _a.message) || "Unknown error");
43
- onError == null ? void 0 : onError(err);
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 == null ? void 0 : onError(err);
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 pcm = new Int16Array(inputData.length);
80
- for (let i = 0; i < inputData.length; i++) {
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 < bytes.length; 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 == null ? void 0 : onError(err);
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":";AAkCO,SAAS,gBAAgB,QAAoC;AAClE,QAAM;AAAA,IACJ;AAAA,IACA,cAAc;AAAA,IACd,aAAa;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI;AAEJ,MAAI,KAAuB;AAC3B,MAAI,cAAkC;AACtC,MAAI,eAAoC;AACxC,MAAI,YAAwC;AAE5C,iBAAe,UAAyB;AACtC,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,WAAK,IAAI,UAAU,GAAG;AAEtB,SAAG,SAAS,MAAM;AAAA,MAAC;AAEnB,SAAG,YAAY,CAAC,UAAU;AAzDhC;AA0DQ,cAAM,OAAO,KAAK,MAAM,MAAM,IAAI;AAElC,YAAI,KAAK,SAAS,mBAAmB;AACnC;AACA,kBAAQ;AAAA,QACV;AAEA,YAAI,KAAK,SAAS,qCAAqC;AACrD;AAAA,QACF;AAEA,YAAI,KAAK,SAAS,qCAAqC;AACrD;AAAA,QACF;AAEA,YAAI,KAAK,SAAS,oDAAoD;AACpE,uDAAe,KAAK,QAAQ,IAAI;AAAA,QAClC;AAEA,YAAI,KAAK,SAAS,yDAAyD;AACzE,uDAAe,KAAK,QAAQ,KAAK,cAAc,IAAI;AAAA,QACrD;AAEA,YAAI,KAAK,SAAS,SAAS;AACzB,gBAAM,MAAM,IAAI,QAAM,UAAK,UAAL,mBAAY,YAAW,eAAe;AAC5D,6CAAU;AACV,iBAAO,GAAG;AAAA,QACZ;AAAA,MACF;AAEA,SAAG,UAAU,MAAM;AACjB,cAAM,MAAM,IAAI,MAAM,4BAA4B;AAClD,2CAAU;AACV,eAAO,GAAG;AAAA,MACZ;AAEA,SAAG,UAAU,MAAM;AACjB,aAAK;AAAA,MACP;AAAA,IACF,CAAC;AAAA,EACH;AAEA,iBAAe,iBAAgC;AAC7C,QAAI,OAAO,WAAW,aAAa;AACjC,YAAM,IAAI,MAAM,qCAAqC;AAAA,IACvD;AAEA,QAAI,CAAC,MAAM,GAAG,eAAe,UAAU,MAAM;AAC3C,YAAM,IAAI,MAAM,yBAAyB;AAAA,IAC3C;AAEA,QAAI;AACF,oBAAc,MAAM,UAAU,aAAa,aAAa;AAAA,QACtD,OAAO;AAAA,UACL;AAAA,UACA,cAAc;AAAA,UACd,kBAAkB;AAAA,UAClB,kBAAkB;AAAA,QACpB;AAAA,MACF,CAAC;AAED,qBAAe,IAAI,aAAa,EAAE,WAAW,CAAC;AAC9C,YAAM,SAAS,aAAa,wBAAwB,WAAW;AAC/D,kBAAY,aAAa,sBAAsB,MAAM,GAAG,CAAC;AAEzD,gBAAU,iBAAiB,CAAC,MAAM;AAChC,YAAI,CAAC,MAAM,GAAG,eAAe,UAAU,KAAM;AAE7C,cAAM,YAAY,EAAE,YAAY,eAAe,CAAC;AAEhD,cAAM,MAAM,IAAI,WAAW,UAAU,MAAM;AAC3C,iBAAS,IAAI,GAAG,IAAI,UAAU,QAAQ,KAAK;AACzC,gBAAM,IAAI,KAAK,IAAI,IAAI,KAAK,IAAI,GAAG,UAAU,CAAC,CAAC,CAAC;AAChD,cAAI,CAAC,IAAI,IAAI,IAAI,IAAI,QAAQ,IAAI;AAAA,QACnC;AAEA,cAAM,QAAQ,IAAI,WAAW,IAAI,MAAM;AACvC,YAAI,SAAS;AACb,iBAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,oBAAU,OAAO,aAAa,MAAM,CAAC,CAAC;AAAA,QACxC;AACA,cAAM,SAAS,KAAK,MAAM;AAE1B,WAAG,KAAK,KAAK,UAAU;AAAA,UACrB,MAAM;AAAA,UACN,OAAO;AAAA,QACT,CAAC,CAAC;AAAA,MACJ;AAEA,aAAO,QAAQ,SAAS;AACxB,gBAAU,QAAQ,aAAa,WAAW;AAAA,IAC5C,SAAS,KAAK;AACZ,yCAAU;AACV,YAAM;AAAA,IACR;AAAA,EACF;AAEA,WAAS,gBAAgB;AACvB,QAAI,aAAa;AACf,kBAAY,UAAU,EAAE,QAAQ,WAAS,MAAM,KAAK,CAAC;AACrD,oBAAc;AAAA,IAChB;AAEA,QAAI,WAAW;AACb,gBAAU,WAAW;AACrB,kBAAY;AAAA,IACd;AAEA,QAAI,cAAc;AAChB,mBAAa,MAAM;AACnB,qBAAe;AAAA,IACjB;AAEA,QAAI,MAAM,GAAG,eAAe,UAAU,MAAM;AAC1C,SAAG,KAAK,KAAK,UAAU,EAAE,MAAM,4BAA4B,CAAC,CAAC;AAAA,IAC/D;AAAA,EACF;AAEA,WAAS,QAAQ;AACf,kBAAc;AACd,QAAI,IAAI;AACN,SAAG,MAAM;AACT,WAAK;AAAA,IACP;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;","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.1",
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": [