deeeed commited on
Commit
0fe2bca
·
verified ·
1 Parent(s): 7d78416

Upload wasm/runtime/sherpa-onnx-language-id.js with huggingface_hub

Browse files
wasm/runtime/sherpa-onnx-language-id.js ADDED
@@ -0,0 +1,194 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * sherpa-onnx-language-id.js
3
+ *
4
+ * Spoken Language Identification functionality for SherpaOnnx
5
+ * Requires sherpa-onnx-core.js to be loaded first
6
+ */
7
+
8
+ (function(global) {
9
+ if (!global.SherpaOnnx) {
10
+ console.error('SherpaOnnx namespace not found. Make sure to load sherpa-onnx-core.js first.');
11
+ return;
12
+ }
13
+
14
+ const SherpaOnnx = global.SherpaOnnx;
15
+
16
+ // --- WASM struct init helpers ---
17
+
18
+ // SherpaOnnxSpokenLanguageIdentificationWhisperConfig = { encoder: ptr, decoder: ptr, tail_paddings: i32 }
19
+ // SherpaOnnxSpokenLanguageIdentificationConfig = { whisper: WhisperConfig, num_threads: i32, debug: i32, provider: ptr }
20
+
21
+ function initLanguageIdConfig(config, Module) {
22
+ // whisper.encoder
23
+ const encoderStr = (config.whisper && config.whisper.encoder) || '';
24
+ const encoderLen = Module.lengthBytesUTF8(encoderStr) + 1;
25
+ const encoderBuf = Module._malloc(encoderLen);
26
+ Module.stringToUTF8(encoderStr, encoderBuf, encoderLen);
27
+
28
+ // whisper.decoder
29
+ const decoderStr = (config.whisper && config.whisper.decoder) || '';
30
+ const decoderLen = Module.lengthBytesUTF8(decoderStr) + 1;
31
+ const decoderBuf = Module._malloc(decoderLen);
32
+ Module.stringToUTF8(decoderStr, decoderBuf, decoderLen);
33
+
34
+ // provider
35
+ const providerStr = config.provider || 'cpu';
36
+ const providerLen = Module.lengthBytesUTF8(providerStr) + 1;
37
+ const providerBuf = Module._malloc(providerLen);
38
+ Module.stringToUTF8(providerStr, providerBuf, providerLen);
39
+
40
+ // Flat struct layout:
41
+ // encoder: ptr (4)
42
+ // decoder: ptr (4)
43
+ // tail_paddings: i32 (4)
44
+ // num_threads: i32 (4)
45
+ // debug: i32 (4)
46
+ // provider: ptr (4)
47
+ // Total = 24 bytes
48
+ const totalLen = 6 * 4;
49
+ const ptr = Module._malloc(totalLen);
50
+ let offset = 0;
51
+
52
+ Module.setValue(ptr + offset, encoderBuf, 'i8*'); offset += 4;
53
+ Module.setValue(ptr + offset, decoderBuf, 'i8*'); offset += 4;
54
+ Module.setValue(ptr + offset, (config.whisper && config.whisper.tailPaddings) || -1, 'i32'); offset += 4;
55
+ Module.setValue(ptr + offset, config.numThreads || 1, 'i32'); offset += 4;
56
+ Module.setValue(ptr + offset, config.debug || 0, 'i32'); offset += 4;
57
+ Module.setValue(ptr + offset, providerBuf, 'i8*'); offset += 4;
58
+
59
+ return {
60
+ ptr: ptr,
61
+ buffers: [encoderBuf, decoderBuf, providerBuf],
62
+ };
63
+ }
64
+
65
+ function freeLanguageIdConfig(config, Module) {
66
+ for (const buf of config.buffers) {
67
+ Module._free(buf);
68
+ }
69
+ Module._free(config.ptr);
70
+ }
71
+
72
+ // --- SpokenLanguageIdentification class ---
73
+
74
+ class SpokenLanguageIdentification {
75
+ constructor(configObj, Module) {
76
+ const config = initLanguageIdConfig(configObj, Module);
77
+ const handle = Module._SherpaOnnxCreateSpokenLanguageIdentification(config.ptr);
78
+ freeLanguageIdConfig(config, Module);
79
+
80
+ if (!handle) {
81
+ throw new Error('Failed to create spoken language identification - null handle');
82
+ }
83
+
84
+ this.handle = handle;
85
+ this.Module = Module;
86
+ }
87
+
88
+ free() {
89
+ if (this.handle) {
90
+ this.Module._SherpaOnnxDestroySpokenLanguageIdentification(this.handle);
91
+ this.handle = 0;
92
+ }
93
+ }
94
+
95
+ createStream() {
96
+ const streamHandle = this.Module._SherpaOnnxSpokenLanguageIdentificationCreateOfflineStream(this.handle);
97
+ if (!streamHandle) {
98
+ throw new Error('Failed to create language ID offline stream');
99
+ }
100
+ return streamHandle;
101
+ }
102
+
103
+ /**
104
+ * Feed audio samples into a stream
105
+ */
106
+ acceptWaveform(stream, sampleRate, samples) {
107
+ const pointer = this.Module._malloc(samples.length * samples.BYTES_PER_ELEMENT);
108
+ this.Module.HEAPF32.set(samples, pointer / samples.BYTES_PER_ELEMENT);
109
+ this.Module._SherpaOnnxAcceptWaveformOffline(stream, sampleRate, pointer, samples.length);
110
+ this.Module._free(pointer);
111
+ }
112
+
113
+ /**
114
+ * Compute the language
115
+ * @param {number} stream - Stream handle
116
+ * @returns {string} - Language code (e.g. 'en', 'de', 'zh')
117
+ */
118
+ compute(stream) {
119
+ const resultPtr = this.Module._SherpaOnnxSpokenLanguageIdentificationCompute(this.handle, stream);
120
+
121
+ if (!resultPtr) {
122
+ this.Module._SherpaOnnxDestroyOfflineStream(stream);
123
+ return '';
124
+ }
125
+
126
+ // SherpaOnnxSpokenLanguageIdentificationResult = { lang: ptr }
127
+ const langPtr = this.Module.HEAP32[resultPtr / 4];
128
+ const lang = langPtr ? this.Module.UTF8ToString(langPtr) : '';
129
+
130
+ this.Module._SherpaOnnxDestroySpokenLanguageIdentificationResult(resultPtr);
131
+ this.Module._SherpaOnnxDestroyOfflineStream(stream);
132
+
133
+ return lang;
134
+ }
135
+ }
136
+
137
+ // --- Namespace API ---
138
+
139
+ SherpaOnnx.LanguageId = {
140
+ loadModel: async function(modelConfig) {
141
+ const debug = modelConfig.debug || false;
142
+ const modelDir = modelConfig.modelDir || 'language-id-models';
143
+
144
+ if (debug) console.log(`LanguageId.loadModel: dir=${modelDir}`);
145
+
146
+ SherpaOnnx.FileSystem.removePath(modelDir, debug);
147
+
148
+ const files = [
149
+ { url: modelConfig.encoder || 'assets/language-id/tiny-encoder.onnx', filename: 'tiny-encoder.onnx' },
150
+ { url: modelConfig.decoder || 'assets/language-id/tiny-decoder.onnx', filename: 'tiny-decoder.onnx' },
151
+ ];
152
+
153
+ const result = await SherpaOnnx.FileSystem.prepareModelDirectory(files, modelDir, debug);
154
+ if (!result.success) {
155
+ throw new Error('Failed to load language ID model files');
156
+ }
157
+
158
+ const encoderFile = result.files.find(f => f.success && f.original.filename === 'tiny-encoder.onnx');
159
+ const decoderFile = result.files.find(f => f.success && f.original.filename === 'tiny-decoder.onnx');
160
+
161
+ return {
162
+ modelDir: result.modelDir,
163
+ encoderPath: encoderFile ? encoderFile.path : `${result.modelDir}/tiny-encoder.onnx`,
164
+ decoderPath: decoderFile ? decoderFile.path : `${result.modelDir}/tiny-decoder.onnx`,
165
+ };
166
+ },
167
+
168
+ createLanguageId: function(loadedModel, options = {}) {
169
+ const debug = options.debug !== undefined ? options.debug : false;
170
+ const config = {
171
+ whisper: {
172
+ encoder: loadedModel.encoderPath,
173
+ decoder: loadedModel.decoderPath,
174
+ tailPaddings: options.tailPaddings || -1,
175
+ },
176
+ numThreads: options.numThreads || 1,
177
+ debug: debug ? 1 : 0,
178
+ provider: options.provider || 'cpu',
179
+ };
180
+
181
+ const lid = new SpokenLanguageIdentification(config, global.Module);
182
+
183
+ if (SherpaOnnx.trackResource) {
184
+ SherpaOnnx.trackResource('languageId', lid);
185
+ }
186
+
187
+ return lid;
188
+ },
189
+ };
190
+
191
+ if (typeof module !== 'undefined' && module.exports) {
192
+ module.exports = SherpaOnnx;
193
+ }
194
+ })(typeof window !== 'undefined' ? window : global);