hama-js 1.3.2 → 1.3.4

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.
@@ -0,0 +1,340 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { InferenceSession, Tensor } from "onnxruntime-node";
5
+ import vocabData from "./assets/g2p_vocab.json";
6
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
7
+ const defaultWaveformModelPath = path.join(__dirname, "assets", "asr_waveform_fp16.onnx");
8
+ const resolveDefaultAsrModelPath = () => {
9
+ if (fs.existsSync(defaultWaveformModelPath)) {
10
+ return defaultWaveformModelPath;
11
+ }
12
+ throw new Error(`Missing waveform ASR asset: ${defaultWaveformModelPath}`);
13
+ };
14
+ const resolveName = (available, primary, ...fallbacks) => {
15
+ if (available.includes(primary))
16
+ return primary;
17
+ for (const fallback of fallbacks) {
18
+ if (available.includes(fallback))
19
+ return fallback;
20
+ }
21
+ const matches = available.filter((name) => name.startsWith(`${primary}.`) || name.startsWith(primary));
22
+ if (matches.length === 1)
23
+ return matches[0];
24
+ if (matches.length > 1) {
25
+ const numeric = matches.filter((name) => name.startsWith(`${primary}.`));
26
+ if (numeric.length === 1)
27
+ return numeric[0];
28
+ return matches[0];
29
+ }
30
+ throw new Error(`Could not resolve ONNX tensor name for '${primary}'. Available: ${available.join(", ")}`);
31
+ };
32
+ const scalarInt = (tensor) => {
33
+ const data = tensor.data;
34
+ const raw = data[0];
35
+ return typeof raw === "bigint" ? Number(raw) : Math.trunc(Number(raw));
36
+ };
37
+ export const decodeCtcTokens = (frameTokenIds, decoderTokens, options) => {
38
+ const collapseRepeats = options.collapseRepeats ?? true;
39
+ const tokenIds = [];
40
+ let prev = -1;
41
+ for (const tokenId of frameTokenIds) {
42
+ if (collapseRepeats && tokenId === prev) {
43
+ continue;
44
+ }
45
+ prev = tokenId;
46
+ if (tokenId === options.blankId) {
47
+ continue;
48
+ }
49
+ tokenIds.push(tokenId);
50
+ }
51
+ const rawTokens = tokenIds.map((tokenId) => decoderTokens[tokenId] ?? "<unk>");
52
+ const phonemes = rawTokens.filter((token) => token !== options.wordBoundaryToken);
53
+ const words = [];
54
+ let current = [];
55
+ for (const token of rawTokens) {
56
+ if (token === options.wordBoundaryToken) {
57
+ if (current.length > 0) {
58
+ words.push(current);
59
+ current = [];
60
+ }
61
+ continue;
62
+ }
63
+ current.push(token);
64
+ }
65
+ if (current.length > 0) {
66
+ words.push(current);
67
+ }
68
+ return { tokenIds, phonemes, words };
69
+ };
70
+ const loadDecoderTokens = (vocabPath) => {
71
+ let vocab;
72
+ if (vocabPath) {
73
+ const raw = fs.readFileSync(vocabPath, "utf-8");
74
+ vocab = JSON.parse(raw);
75
+ }
76
+ else {
77
+ vocab = vocabData;
78
+ }
79
+ if (!Array.isArray(vocab.decoder) || vocab.decoder.length === 0) {
80
+ throw new Error("Invalid vocabulary JSON: missing decoder token list");
81
+ }
82
+ return [...vocab.decoder, "<wb>", "<blank>"];
83
+ };
84
+ export class ASRNodeModel {
85
+ constructor(session, options) {
86
+ this.session = session;
87
+ this.sampleRate = options.sampleRate;
88
+ this.wordBoundaryToken = options.wordBoundaryToken;
89
+ this.blankBias = options.blankBias;
90
+ this.unkBias = options.unkBias;
91
+ this.collapseRepeats = options.collapseRepeats;
92
+ this.decoderTokens = loadDecoderTokens(options.vocabPath);
93
+ this.blankId = this.decoderTokens.indexOf(options.blankToken);
94
+ if (this.blankId < 0) {
95
+ throw new Error(`blank token '${options.blankToken}' not found in decoder tokens`);
96
+ }
97
+ const unk = this.decoderTokens.indexOf(options.unkToken);
98
+ this.unkId = unk >= 0 ? unk : null;
99
+ const inputNames = this.session.inputNames;
100
+ const hasWaveform = inputNames.includes("waveform")
101
+ || inputNames.some((name) => name.startsWith("waveform."));
102
+ if (!hasWaveform) {
103
+ throw new Error(`Unsupported ASR ONNX inputs: ${inputNames.join(", ")}. `
104
+ + "hama ASR requires a waveform-input model with waveform/waveform_lengths.");
105
+ }
106
+ this.waveformInputName = resolveName(inputNames, "waveform");
107
+ this.waveformLengthsInputName = resolveName(inputNames, "waveform_lengths", "waveform_length");
108
+ this.logProbsOutputName = resolveName(this.session.outputNames, "log_probs");
109
+ this.outLengthsOutputName = resolveName(this.session.outputNames, "out_lengths");
110
+ }
111
+ static async create(options = {}) {
112
+ const opts = {
113
+ modelPath: options.modelPath ?? resolveDefaultAsrModelPath(),
114
+ vocabPath: options.vocabPath ?? "",
115
+ sampleRate: options.sampleRate ?? 16000,
116
+ blankToken: options.blankToken ?? "<blank>",
117
+ unkToken: options.unkToken ?? "<unk>",
118
+ wordBoundaryToken: options.wordBoundaryToken ?? "<wb>",
119
+ blankBias: options.blankBias ?? -0.1,
120
+ unkBias: options.unkBias ?? 0.0,
121
+ collapseRepeats: options.collapseRepeats ?? true,
122
+ };
123
+ const session = await InferenceSession.create(opts.modelPath, {
124
+ graphOptimizationLevel: "disabled",
125
+ });
126
+ return new ASRNodeModel(session, opts);
127
+ }
128
+ get inputFormat() {
129
+ return "waveform";
130
+ }
131
+ async transcribeWavFile(wavPath) {
132
+ const { waveform, sampleRate } = readWavMono(wavPath);
133
+ return this.transcribeWaveform(waveform, sampleRate);
134
+ }
135
+ async transcribeWaveform(waveform, sampleRate) {
136
+ const mono = toFloat32Mono(waveform);
137
+ const resampled = sampleRate === this.sampleRate
138
+ ? mono
139
+ : resampleLinear(mono, sampleRate, this.sampleRate);
140
+ const waveformTensor = new Tensor("float32", resampled, [1, resampled.length]);
141
+ const lengthTensor = new Tensor("int64", BigInt64Array.from([BigInt(resampled.length)]), [1]);
142
+ const outputs = await this.session.run({
143
+ [this.waveformInputName]: waveformTensor,
144
+ [this.waveformLengthsInputName]: lengthTensor,
145
+ });
146
+ const logProbs = outputs[this.logProbsOutputName];
147
+ const outLengths = outputs[this.outLengthsOutputName];
148
+ const numFrames = Math.max(0, Math.min(scalarInt(outLengths), Number(logProbs.dims[1] ?? 0)));
149
+ const frameTokenIds = this.argmaxFrames(logProbs, numFrames);
150
+ const decoded = decodeCtcTokens(frameTokenIds, this.decoderTokens, {
151
+ blankId: this.blankId,
152
+ wordBoundaryToken: this.wordBoundaryToken,
153
+ collapseRepeats: this.collapseRepeats,
154
+ });
155
+ return {
156
+ phonemes: decoded.phonemes,
157
+ phonemeText: decoded.phonemes.join(" "),
158
+ wordPhonemeText: decoded.words.map((word) => word.join(" ")).join(" | "),
159
+ tokenIds: decoded.tokenIds,
160
+ frameTokenIds,
161
+ numFrames,
162
+ };
163
+ }
164
+ argmaxFrames(logProbs, numFrames) {
165
+ const dims = logProbs.dims.map(Number);
166
+ if (dims.length !== 3 || dims[0] !== 1) {
167
+ throw new Error(`Expected log_probs shape [1, T, C], got [${dims.join(", ")}]`);
168
+ }
169
+ const classes = dims[2];
170
+ const data = logProbs.data;
171
+ const out = [];
172
+ for (let t = 0; t < numFrames; t++) {
173
+ let bestIdx = 0;
174
+ let bestScore = -Infinity;
175
+ const base = t * classes;
176
+ for (let c = 0; c < classes; c++) {
177
+ const raw = Number(data[base + c]);
178
+ const score = raw
179
+ + (c === this.blankId ? this.blankBias : 0.0)
180
+ + (this.unkId !== null && c === this.unkId ? this.unkBias : 0.0);
181
+ if (score > bestScore) {
182
+ bestScore = score;
183
+ bestIdx = c;
184
+ }
185
+ }
186
+ out.push(bestIdx);
187
+ }
188
+ return out;
189
+ }
190
+ }
191
+ const readWavMono = (wavPath) => {
192
+ const buf = fs.readFileSync(wavPath);
193
+ if (buf.length < 44) {
194
+ throw new Error(`Invalid WAV file: too short (${wavPath})`);
195
+ }
196
+ const riff = buf.toString("ascii", 0, 4);
197
+ const wave = buf.toString("ascii", 8, 12);
198
+ if (riff !== "RIFF" || wave !== "WAVE") {
199
+ throw new Error(`Invalid WAV header: expected RIFF/WAVE (${wavPath})`);
200
+ }
201
+ let offset = 12;
202
+ let format = 0;
203
+ let channels = 0;
204
+ let sampleRate = 0;
205
+ let bitsPerSample = 0;
206
+ let dataOffset = -1;
207
+ let dataSize = 0;
208
+ while (offset + 8 <= buf.length) {
209
+ const chunkId = buf.toString("ascii", offset, offset + 4);
210
+ const chunkSize = buf.readUInt32LE(offset + 4);
211
+ const chunkDataOffset = offset + 8;
212
+ const next = chunkDataOffset + chunkSize + (chunkSize % 2);
213
+ if (chunkId === "fmt " && chunkSize >= 16) {
214
+ format = buf.readUInt16LE(chunkDataOffset);
215
+ channels = buf.readUInt16LE(chunkDataOffset + 2);
216
+ sampleRate = buf.readUInt32LE(chunkDataOffset + 4);
217
+ bitsPerSample = buf.readUInt16LE(chunkDataOffset + 14);
218
+ }
219
+ else if (chunkId === "data") {
220
+ dataOffset = chunkDataOffset;
221
+ dataSize = chunkSize;
222
+ break;
223
+ }
224
+ offset = next;
225
+ }
226
+ if (dataOffset < 0 || dataSize <= 0) {
227
+ throw new Error(`Invalid WAV: missing data chunk (${wavPath})`);
228
+ }
229
+ if (channels <= 0 || sampleRate <= 0) {
230
+ throw new Error(`Invalid WAV: malformed fmt chunk (${wavPath})`);
231
+ }
232
+ let samplesPerChannel = 0;
233
+ let interleaved;
234
+ if (format === 1) {
235
+ if (bitsPerSample === 8) {
236
+ samplesPerChannel = Math.floor(dataSize / channels);
237
+ interleaved = new Float32Array(samplesPerChannel * channels);
238
+ for (let i = 0; i < interleaved.length; i++) {
239
+ const v = buf.readUInt8(dataOffset + i);
240
+ interleaved[i] = (v - 128) / 128;
241
+ }
242
+ }
243
+ else if (bitsPerSample === 16) {
244
+ const bytesPerSample = 2;
245
+ samplesPerChannel = Math.floor(dataSize / (channels * bytesPerSample));
246
+ interleaved = new Float32Array(samplesPerChannel * channels);
247
+ for (let i = 0; i < interleaved.length; i++) {
248
+ const v = buf.readInt16LE(dataOffset + i * bytesPerSample);
249
+ interleaved[i] = v / 32768;
250
+ }
251
+ }
252
+ else if (bitsPerSample === 24) {
253
+ const bytesPerSample = 3;
254
+ samplesPerChannel = Math.floor(dataSize / (channels * bytesPerSample));
255
+ interleaved = new Float32Array(samplesPerChannel * channels);
256
+ for (let i = 0; i < interleaved.length; i++) {
257
+ const p = dataOffset + i * bytesPerSample;
258
+ let v = buf[p] | (buf[p + 1] << 8) | (buf[p + 2] << 16);
259
+ if (v & 0x800000)
260
+ v -= 0x1000000;
261
+ interleaved[i] = v / 8388608;
262
+ }
263
+ }
264
+ else if (bitsPerSample === 32) {
265
+ const bytesPerSample = 4;
266
+ samplesPerChannel = Math.floor(dataSize / (channels * bytesPerSample));
267
+ interleaved = new Float32Array(samplesPerChannel * channels);
268
+ for (let i = 0; i < interleaved.length; i++) {
269
+ const v = buf.readInt32LE(dataOffset + i * bytesPerSample);
270
+ interleaved[i] = v / 2147483648;
271
+ }
272
+ }
273
+ else {
274
+ throw new Error(`Unsupported PCM WAV bits_per_sample=${bitsPerSample}`);
275
+ }
276
+ }
277
+ else if (format === 3 && bitsPerSample === 32) {
278
+ const bytesPerSample = 4;
279
+ samplesPerChannel = Math.floor(dataSize / (channels * bytesPerSample));
280
+ interleaved = new Float32Array(samplesPerChannel * channels);
281
+ for (let i = 0; i < interleaved.length; i++) {
282
+ interleaved[i] = buf.readFloatLE(dataOffset + i * bytesPerSample);
283
+ }
284
+ }
285
+ else {
286
+ throw new Error(`Unsupported WAV format=${format} bits_per_sample=${bitsPerSample}`);
287
+ }
288
+ if (channels === 1) {
289
+ return { waveform: clampUnit(interleaved), sampleRate };
290
+ }
291
+ const mono = new Float32Array(samplesPerChannel);
292
+ for (let i = 0; i < samplesPerChannel; i++) {
293
+ let acc = 0;
294
+ for (let ch = 0; ch < channels; ch++) {
295
+ acc += interleaved[i * channels + ch];
296
+ }
297
+ mono[i] = acc / channels;
298
+ }
299
+ return { waveform: clampUnit(mono), sampleRate };
300
+ };
301
+ const toFloat32Mono = (waveform) => {
302
+ if (waveform instanceof Float32Array) {
303
+ return clampUnit(waveform);
304
+ }
305
+ if (!Array.isArray(waveform)) {
306
+ throw new Error("waveform must be Float32Array or number[]");
307
+ }
308
+ const out = new Float32Array(waveform.length);
309
+ for (let i = 0; i < waveform.length; i++) {
310
+ out[i] = Number(waveform[i]);
311
+ }
312
+ return clampUnit(out);
313
+ };
314
+ const clampUnit = (arr) => {
315
+ const out = new Float32Array(arr.length);
316
+ for (let i = 0; i < arr.length; i++) {
317
+ const v = arr[i];
318
+ out[i] = v < -1 ? -1 : v > 1 ? 1 : v;
319
+ }
320
+ return out;
321
+ };
322
+ const resampleLinear = (waveform, srcRate, dstRate) => {
323
+ if (srcRate === dstRate)
324
+ return waveform;
325
+ if (waveform.length === 0)
326
+ return waveform;
327
+ const duration = (waveform.length - 1) / srcRate;
328
+ const dstLen = Math.max(1, Math.round(duration * dstRate) + 1);
329
+ const out = new Float32Array(dstLen);
330
+ for (let i = 0; i < dstLen; i++) {
331
+ const t = i / dstRate;
332
+ const srcPos = t * srcRate;
333
+ const i0 = Math.floor(srcPos);
334
+ const i1 = Math.min(waveform.length - 1, i0 + 1);
335
+ const a = srcPos - i0;
336
+ out[i] = waveform[i0] * (1 - a) + waveform[i1] * a;
337
+ }
338
+ return out;
339
+ };
340
+ //# sourceMappingURL=asr.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"asr.js","sourceRoot":"","sources":["../../src/asr.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAE5D,OAAO,SAAS,MAAM,yBAAyB,CAAC;AAiChD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAC/D,MAAM,wBAAwB,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,EAAE,wBAAwB,CAAC,CAAC;AAE1F,MAAM,0BAA0B,GAAG,GAAW,EAAE;IAC9C,IAAI,EAAE,CAAC,UAAU,CAAC,wBAAwB,CAAC,EAAE,CAAC;QAC5C,OAAO,wBAAwB,CAAC;IAClC,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,+BAA+B,wBAAwB,EAAE,CAAC,CAAC;AAC7E,CAAC,CAAC;AAEF,MAAM,WAAW,GAAG,CAAC,SAA4B,EAAE,OAAe,EAAE,GAAG,SAAmB,EAAU,EAAE;IACpG,IAAI,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC;QAAE,OAAO,OAAO,CAAC;IAChD,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QACjC,IAAI,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC;YAAE,OAAO,QAAQ,CAAC;IACpD,CAAC;IACD,MAAM,OAAO,GAAG,SAAS,CAAC,MAAM,CAC9B,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,OAAO,GAAG,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CACrE,CAAC;IACF,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC;IAC5C,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,OAAO,GAAG,CAAC,CAAC,CAAC;QACzE,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC;QAC5C,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,2CAA2C,OAAO,iBAAiB,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AAC7G,CAAC,CAAC;AAEF,MAAM,SAAS,GAAG,CAAC,MAAc,EAAU,EAAE;IAC3C,MAAM,IAAI,GAAG,MAAM,CAAC,IAAkC,CAAC;IACvD,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,OAAO,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;AACzE,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,aAAgC,EAChC,aAAgC,EAChC,OAAyB,EACsC,EAAE;IACjE,MAAM,eAAe,GAAG,OAAO,CAAC,eAAe,IAAI,IAAI,CAAC;IAExD,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC;IACd,KAAK,MAAM,OAAO,IAAI,aAAa,EAAE,CAAC;QACpC,IAAI,eAAe,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;YACxC,SAAS;QACX,CAAC;QACD,IAAI,GAAG,OAAO,CAAC;QACf,IAAI,OAAO,KAAK,OAAO,CAAC,OAAO,EAAE,CAAC;YAChC,SAAS;QACX,CAAC;QACD,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACzB,CAAC;IAED,MAAM,SAAS,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,CAAC;IAC/E,MAAM,QAAQ,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,OAAO,CAAC,iBAAiB,CAAC,CAAC;IAClF,MAAM,KAAK,GAAe,EAAE,CAAC;IAC7B,IAAI,OAAO,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,KAAK,IAAI,SAAS,EAAE,CAAC;QAC9B,IAAI,KAAK,KAAK,OAAO,CAAC,iBAAiB,EAAE,CAAC;YACxC,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACvB,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;gBACpB,OAAO,GAAG,EAAE,CAAC;YACf,CAAC;YACD,SAAS;QACX,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACtB,CAAC;IACD,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACtB,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;AACvC,CAAC,CAAC;AAEF,MAAM,iBAAiB,GAAG,CAAC,SAAkB,EAAY,EAAE;IACzD,IAAI,KAAqB,CAAC;IAC1B,IAAI,SAAS,EAAE,CAAC;QACd,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QAChD,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAmB,CAAC;IAC5C,CAAC;SAAM,CAAC;QACN,KAAK,GAAG,SAA2B,CAAC;IACtC,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChE,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;IACzE,CAAC;IACD,OAAO,CAAC,GAAG,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC;AAC/C,CAAC,CAAC;AAEF,MAAM,OAAO,YAAY;IAevB,YAAoB,OAAyB,EAAE,OAAiC;QAC9E,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;QACrC,IAAI,CAAC,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC;QACnD,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;QACnC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;QAC/B,IAAI,CAAC,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC;QAC/C,IAAI,CAAC,aAAa,GAAG,iBAAiB,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAC1D,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QAC9D,IAAI,IAAI,CAAC,OAAO,GAAG,CAAC,EAAE,CAAC;YACrB,MAAM,IAAI,KAAK,CAAC,gBAAgB,OAAO,CAAC,UAAU,+BAA+B,CAAC,CAAC;QACrF,CAAC;QACD,MAAM,GAAG,GAAG,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACzD,IAAI,CAAC,KAAK,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;QAEnC,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC;QAC3C,MAAM,WAAW,GACf,UAAU,CAAC,QAAQ,CAAC,UAAU,CAAC;eAC5B,UAAU,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC,CAAC;QAC7D,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CACb,gCAAgC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI;kBACvD,0EAA0E,CAC7E,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,iBAAiB,GAAG,WAAW,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;QAC7D,IAAI,CAAC,wBAAwB,GAAG,WAAW,CAAC,UAAU,EAAE,kBAAkB,EAAE,iBAAiB,CAAC,CAAC;QAC/F,IAAI,CAAC,kBAAkB,GAAG,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;QAC7E,IAAI,CAAC,oBAAoB,GAAG,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;IACnF,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,UAA0B,EAAE;QAC9C,MAAM,IAAI,GAA6B;YACrC,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,0BAA0B,EAAE;YAC5D,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,EAAE;YAClC,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,KAAK;YACvC,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,SAAS;YAC3C,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,OAAO;YACrC,iBAAiB,EAAE,OAAO,CAAC,iBAAiB,IAAI,MAAM;YACtD,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,CAAC,GAAG;YACpC,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,GAAG;YAC/B,eAAe,EAAE,OAAO,CAAC,eAAe,IAAI,IAAI;SACjD,CAAC;QACF,MAAM,OAAO,GAAG,MAAM,gBAAgB,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE;YAC5D,sBAAsB,EAAE,UAAU;SACnC,CAAC,CAAC;QACH,OAAO,IAAI,YAAY,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IACzC,CAAC;IAED,IAAI,WAAW;QACb,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,KAAK,CAAC,iBAAiB,CAAC,OAAe;QACrC,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;QACtD,OAAO,IAAI,CAAC,kBAAkB,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;IACvD,CAAC;IAED,KAAK,CAAC,kBAAkB,CACtB,QAA0C,EAC1C,UAAkB;QAElB,MAAM,IAAI,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;QACrC,MAAM,SAAS,GACb,UAAU,KAAK,IAAI,CAAC,UAAU;YAC5B,CAAC,CAAC,IAAI;YACN,CAAC,CAAC,cAAc,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;QACxD,MAAM,cAAc,GAAG,IAAI,MAAM,CAAC,SAAS,EAAE,SAAS,EAAE,CAAC,CAAC,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;QAC/E,MAAM,YAAY,GAAG,IAAI,MAAM,CAAC,OAAO,EAAE,aAAa,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAC9F,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC;YACrC,CAAC,IAAI,CAAC,iBAAiB,CAAC,EAAE,cAAc;YACxC,CAAC,IAAI,CAAC,wBAAwB,CAAC,EAAE,YAAY;SAC9C,CAAC,CAAC;QAEH,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,kBAAkB,CAAW,CAAC;QAC5D,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,oBAAoB,CAAW,CAAC;QAChE,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QAC9F,MAAM,aAAa,GAAG,IAAI,CAAC,YAAY,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QAC7D,MAAM,OAAO,GAAG,eAAe,CAAC,aAAa,EAAE,IAAI,CAAC,aAAa,EAAE;YACjE,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,iBAAiB,EAAE,IAAI,CAAC,iBAAiB;YACzC,eAAe,EAAE,IAAI,CAAC,eAAe;SACtC,CAAC,CAAC;QACH,OAAO;YACL,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,WAAW,EAAE,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC;YACvC,eAAe,EAAE,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC;YACxE,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,aAAa;YACb,SAAS;SACV,CAAC;IACJ,CAAC;IAEO,YAAY,CAAC,QAAgB,EAAE,SAAiB;QACtD,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACvC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;YACvC,MAAM,IAAI,KAAK,CAAC,4CAA4C,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAClF,CAAC;QACD,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACxB,MAAM,IAAI,GAAG,QAAQ,CAAC,IAA+B,CAAC;QAEtD,MAAM,GAAG,GAAa,EAAE,CAAC;QACzB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,EAAE,CAAC,EAAE,EAAE,CAAC;YACnC,IAAI,OAAO,GAAG,CAAC,CAAC;YAChB,IAAI,SAAS,GAAG,CAAC,QAAQ,CAAC;YAC1B,MAAM,IAAI,GAAG,CAAC,GAAG,OAAO,CAAC;YACzB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,EAAE,CAAC,EAAE,EAAE,CAAC;gBACjC,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC;gBACnC,MAAM,KAAK,GACT,GAAG;sBACD,CAAC,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC;sBAC3C,CAAC,IAAI,CAAC,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;gBACnE,IAAI,KAAK,GAAG,SAAS,EAAE,CAAC;oBACtB,SAAS,GAAG,KAAK,CAAC;oBAClB,OAAO,GAAG,CAAC,CAAC;gBACd,CAAC;YACH,CAAC;YACD,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACpB,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;CACF;AAED,MAAM,WAAW,GAAG,CAAC,OAAe,EAAkD,EAAE;IACtF,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;IACrC,IAAI,GAAG,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CAAC,gCAAgC,OAAO,GAAG,CAAC,CAAC;IAC9D,CAAC;IAED,MAAM,IAAI,GAAG,GAAG,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IACzC,MAAM,IAAI,GAAG,GAAG,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;IAC1C,IAAI,IAAI,KAAK,MAAM,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;QACvC,MAAM,IAAI,KAAK,CAAC,2CAA2C,OAAO,GAAG,CAAC,CAAC;IACzE,CAAC;IAED,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,IAAI,UAAU,GAAG,CAAC,CAAC;IACnB,IAAI,aAAa,GAAG,CAAC,CAAC;IACtB,IAAI,UAAU,GAAG,CAAC,CAAC,CAAC;IACpB,IAAI,QAAQ,GAAG,CAAC,CAAC;IAEjB,OAAO,MAAM,GAAG,CAAC,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;QAChC,MAAM,OAAO,GAAG,GAAG,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,CAAC,CAAC,CAAC;QAC1D,MAAM,SAAS,GAAG,GAAG,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAC/C,MAAM,eAAe,GAAG,MAAM,GAAG,CAAC,CAAC;QACnC,MAAM,IAAI,GAAG,eAAe,GAAG,SAAS,GAAG,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC;QAE3D,IAAI,OAAO,KAAK,MAAM,IAAI,SAAS,IAAI,EAAE,EAAE,CAAC;YAC1C,MAAM,GAAG,GAAG,CAAC,YAAY,CAAC,eAAe,CAAC,CAAC;YAC3C,QAAQ,GAAG,GAAG,CAAC,YAAY,CAAC,eAAe,GAAG,CAAC,CAAC,CAAC;YACjD,UAAU,GAAG,GAAG,CAAC,YAAY,CAAC,eAAe,GAAG,CAAC,CAAC,CAAC;YACnD,aAAa,GAAG,GAAG,CAAC,YAAY,CAAC,eAAe,GAAG,EAAE,CAAC,CAAC;QACzD,CAAC;aAAM,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;YAC9B,UAAU,GAAG,eAAe,CAAC;YAC7B,QAAQ,GAAG,SAAS,CAAC;YACrB,MAAM;QACR,CAAC;QACD,MAAM,GAAG,IAAI,CAAC;IAChB,CAAC;IAED,IAAI,UAAU,GAAG,CAAC,IAAI,QAAQ,IAAI,CAAC,EAAE,CAAC;QACpC,MAAM,IAAI,KAAK,CAAC,oCAAoC,OAAO,GAAG,CAAC,CAAC;IAClE,CAAC;IACD,IAAI,QAAQ,IAAI,CAAC,IAAI,UAAU,IAAI,CAAC,EAAE,CAAC;QACrC,MAAM,IAAI,KAAK,CAAC,qCAAqC,OAAO,GAAG,CAAC,CAAC;IACnE,CAAC;IAED,IAAI,iBAAiB,GAAG,CAAC,CAAC;IAC1B,IAAI,WAAyB,CAAC;IAE9B,IAAI,MAAM,KAAK,CAAC,EAAE,CAAC;QACjB,IAAI,aAAa,KAAK,CAAC,EAAE,CAAC;YACxB,iBAAiB,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,QAAQ,CAAC,CAAC;YACpD,WAAW,GAAG,IAAI,YAAY,CAAC,iBAAiB,GAAG,QAAQ,CAAC,CAAC;YAC7D,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,WAAW,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC5C,MAAM,CAAC,GAAG,GAAG,CAAC,SAAS,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC;gBACxC,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC;YACnC,CAAC;QACH,CAAC;aAAM,IAAI,aAAa,KAAK,EAAE,EAAE,CAAC;YAChC,MAAM,cAAc,GAAG,CAAC,CAAC;YACzB,iBAAiB,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAC,QAAQ,GAAG,cAAc,CAAC,CAAC,CAAC;YACvE,WAAW,GAAG,IAAI,YAAY,CAAC,iBAAiB,GAAG,QAAQ,CAAC,CAAC;YAC7D,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,WAAW,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC5C,MAAM,CAAC,GAAG,GAAG,CAAC,WAAW,CAAC,UAAU,GAAG,CAAC,GAAG,cAAc,CAAC,CAAC;gBAC3D,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;YAC7B,CAAC;QACH,CAAC;aAAM,IAAI,aAAa,KAAK,EAAE,EAAE,CAAC;YAChC,MAAM,cAAc,GAAG,CAAC,CAAC;YACzB,iBAAiB,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAC,QAAQ,GAAG,cAAc,CAAC,CAAC,CAAC;YACvE,WAAW,GAAG,IAAI,YAAY,CAAC,iBAAiB,GAAG,QAAQ,CAAC,CAAC;YAC7D,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,WAAW,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC5C,MAAM,CAAC,GAAG,UAAU,GAAG,CAAC,GAAG,cAAc,CAAC;gBAC1C,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;gBACxD,IAAI,CAAC,GAAG,QAAQ;oBAAE,CAAC,IAAI,SAAS,CAAC;gBACjC,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC;YAC/B,CAAC;QACH,CAAC;aAAM,IAAI,aAAa,KAAK,EAAE,EAAE,CAAC;YAChC,MAAM,cAAc,GAAG,CAAC,CAAC;YACzB,iBAAiB,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAC,QAAQ,GAAG,cAAc,CAAC,CAAC,CAAC;YACvE,WAAW,GAAG,IAAI,YAAY,CAAC,iBAAiB,GAAG,QAAQ,CAAC,CAAC;YAC7D,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,WAAW,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC5C,MAAM,CAAC,GAAG,GAAG,CAAC,WAAW,CAAC,UAAU,GAAG,CAAC,GAAG,cAAc,CAAC,CAAC;gBAC3D,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,UAAU,CAAC;YAClC,CAAC;QACH,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,KAAK,CAAC,uCAAuC,aAAa,EAAE,CAAC,CAAC;QAC1E,CAAC;IACH,CAAC;SAAM,IAAI,MAAM,KAAK,CAAC,IAAI,aAAa,KAAK,EAAE,EAAE,CAAC;QAChD,MAAM,cAAc,GAAG,CAAC,CAAC;QACzB,iBAAiB,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAC,QAAQ,GAAG,cAAc,CAAC,CAAC,CAAC;QACvE,WAAW,GAAG,IAAI,YAAY,CAAC,iBAAiB,GAAG,QAAQ,CAAC,CAAC;QAC7D,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,WAAW,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC5C,WAAW,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,WAAW,CAAC,UAAU,GAAG,CAAC,GAAG,cAAc,CAAC,CAAC;QACpE,CAAC;IACH,CAAC;SAAM,CAAC;QACN,MAAM,IAAI,KAAK,CAAC,0BAA0B,MAAM,oBAAoB,aAAa,EAAE,CAAC,CAAC;IACvF,CAAC;IAED,IAAI,QAAQ,KAAK,CAAC,EAAE,CAAC;QACnB,OAAO,EAAE,QAAQ,EAAE,SAAS,CAAC,WAAW,CAAC,EAAE,UAAU,EAAE,CAAC;IAC1D,CAAC;IAED,MAAM,IAAI,GAAG,IAAI,YAAY,CAAC,iBAAiB,CAAC,CAAC;IACjD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,iBAAiB,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3C,IAAI,GAAG,GAAG,CAAC,CAAC;QACZ,KAAK,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,QAAQ,EAAE,EAAE,EAAE,EAAE,CAAC;YACrC,GAAG,IAAI,WAAW,CAAC,CAAC,GAAG,QAAQ,GAAG,EAAE,CAAC,CAAC;QACxC,CAAC;QACD,IAAI,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,QAAQ,CAAC;IAC3B,CAAC;IACD,OAAO,EAAE,QAAQ,EAAE,SAAS,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,CAAC;AACnD,CAAC,CAAC;AAEF,MAAM,aAAa,GAAG,CAAC,QAA0C,EAAgB,EAAE;IACjF,IAAI,QAAQ,YAAY,YAAY,EAAE,CAAC;QACrC,OAAO,SAAS,CAAC,QAAQ,CAAC,CAAC;IAC7B,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;IAC/D,CAAC;IACD,MAAM,GAAG,GAAG,IAAI,YAAY,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC9C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACzC,GAAG,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/B,CAAC;IACD,OAAO,SAAS,CAAC,GAAG,CAAC,CAAC;AACxB,CAAC,CAAC;AAEF,MAAM,SAAS,GAAG,CAAC,GAAiB,EAAgB,EAAE;IACpD,MAAM,GAAG,GAAG,IAAI,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACzC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACpC,MAAM,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;QACjB,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACvC,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC,CAAC;AAEF,MAAM,cAAc,GAAG,CAAC,QAAsB,EAAE,OAAe,EAAE,OAAe,EAAgB,EAAE;IAChG,IAAI,OAAO,KAAK,OAAO;QAAE,OAAO,QAAQ,CAAC;IACzC,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,QAAQ,CAAC;IAC3C,MAAM,QAAQ,GAAG,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,OAAO,CAAC;IACjD,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;IAC/D,MAAM,GAAG,GAAG,IAAI,YAAY,CAAC,MAAM,CAAC,CAAC;IACrC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAChC,MAAM,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC;QACtB,MAAM,MAAM,GAAG,CAAC,GAAG,OAAO,CAAC;QAC3B,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAC9B,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC;QACjD,MAAM,CAAC,GAAG,MAAM,GAAG,EAAE,CAAC;QACtB,GAAG,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;IACrD,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC,CAAC"}
Binary file
@@ -1,27 +1,104 @@
1
+ import fs from "node:fs";
1
2
  import path from "node:path";
2
3
  import { fileURLToPath } from "node:url";
3
4
  import { InferenceSession, Tensor } from "onnxruntime-node";
4
- import { decodeIdsToResult, encodeText } from "./tokenizer.js";
5
+ import { decodeIdsToResult, decoderIds, encodeText } from "./tokenizer.js";
5
6
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
6
7
  const defaultModelPath = path.join(__dirname, "assets", "g2p_fp16.onnx");
8
+ const defaultEncoderModelPath = path.join(__dirname, "assets", "encoder.onnx");
9
+ const defaultDecoderStepModelPath = path.join(__dirname, "assets", "decoder_step.onnx");
10
+ const resolveName = (available, primary, ...fallbacks) => {
11
+ if (available.includes(primary))
12
+ return primary;
13
+ for (const fallback of fallbacks) {
14
+ if (available.includes(fallback))
15
+ return fallback;
16
+ }
17
+ const matches = available.filter((name) => name.startsWith(`${primary}.`) || name.startsWith(primary));
18
+ if (matches.length === 1)
19
+ return matches[0];
20
+ if (matches.length > 1) {
21
+ const numeric = matches.filter((name) => name.startsWith(`${primary}.`));
22
+ if (numeric.length === 1)
23
+ return numeric[0];
24
+ return matches[0];
25
+ }
26
+ throw new Error(`Could not resolve ONNX tensor name for '${primary}'. Available: ${available.join(", ")}`);
27
+ };
7
28
  export class G2PNodeModel {
8
- constructor(session, opts) {
9
- this.session = session;
29
+ constructor(sessions, opts) {
30
+ this.session = sessions.session;
31
+ this.encoderSession = sessions.encoderSession;
32
+ this.decoderStepSession = sessions.decoderStepSession;
10
33
  this.maxInputLen = opts.maxInputLen;
11
34
  this.maxOutputLen = opts.maxOutputLen;
12
35
  }
13
36
  static async create(options = {}) {
37
+ if ((options.encoderModelPath === undefined) !== (options.decoderStepModelPath === undefined)) {
38
+ throw new Error("encoderModelPath and decoderStepModelPath must be provided together");
39
+ }
40
+ let resolvedModelPath = options.modelPath ?? defaultModelPath;
41
+ let resolvedEncoderPath = options.encoderModelPath ?? defaultEncoderModelPath;
42
+ let resolvedDecoderStepPath = options.decoderStepModelPath ?? defaultDecoderStepModelPath;
43
+ if (options.modelPath &&
44
+ fs.existsSync(options.modelPath) &&
45
+ fs.statSync(options.modelPath).isDirectory()) {
46
+ resolvedEncoderPath = path.join(options.modelPath, "encoder.onnx");
47
+ resolvedDecoderStepPath = path.join(options.modelPath, "decoder_step.onnx");
48
+ resolvedModelPath = path.join(options.modelPath, "g2p_fp16.onnx");
49
+ }
14
50
  const opts = {
15
- modelPath: options.modelPath ?? defaultModelPath,
51
+ modelPath: resolvedModelPath,
52
+ encoderModelPath: resolvedEncoderPath,
53
+ decoderStepModelPath: resolvedDecoderStepPath,
16
54
  maxInputLen: options.maxInputLen ?? 128,
55
+ // Retained for API compatibility; autoregressive ONNX sets output length in-graph.
17
56
  maxOutputLen: options.maxOutputLen ?? 32,
18
57
  };
19
- const session = await InferenceSession.create(opts.modelPath, {
20
- graphOptimizationLevel: "disabled",
21
- });
22
- return new G2PNodeModel(session, opts);
58
+ const sessionOptions = { graphOptimizationLevel: "disabled" };
59
+ const shouldUseSplit = (options.encoderModelPath !== undefined && options.decoderStepModelPath !== undefined) ||
60
+ (fs.existsSync(opts.encoderModelPath) && fs.existsSync(opts.decoderStepModelPath));
61
+ if (shouldUseSplit) {
62
+ const [encoderSession, decoderStepSession] = await Promise.all([
63
+ InferenceSession.create(opts.encoderModelPath, sessionOptions),
64
+ InferenceSession.create(opts.decoderStepModelPath, sessionOptions),
65
+ ]);
66
+ return new G2PNodeModel({ encoderSession, decoderStepSession }, opts);
67
+ }
68
+ const session = await InferenceSession.create(opts.modelPath, sessionOptions);
69
+ return new G2PNodeModel({ session }, opts);
70
+ }
71
+ async predict(text, options = {}) {
72
+ const splitDelimiter = options.splitDelimiter ?? /\s+/u;
73
+ const outputDelimiter = options.outputDelimiter ?? " ";
74
+ const segments = splitSegments(text, splitDelimiter);
75
+ if (segments.length === 0) {
76
+ return this.predictSingle(text, 0);
77
+ }
78
+ const results = await Promise.all(segments.map(async (segment) => this.predictSingle(segment.text, codePointOffset(text, segment.startCodeUnit))));
79
+ const ipaParts = [];
80
+ const alignments = [];
81
+ for (let i = 0; i < results.length; i++) {
82
+ if (i > 0)
83
+ ipaParts.push(outputDelimiter);
84
+ ipaParts.push(results[i].ipa);
85
+ for (const alignment of results[i].alignments) {
86
+ alignments.push({
87
+ phoneme: alignment.phoneme,
88
+ phonemeIndex: alignments.length,
89
+ charIndex: alignment.charIndex,
90
+ });
91
+ }
92
+ }
93
+ return { ipa: ipaParts.join(""), alignments };
23
94
  }
24
- async predict(text) {
95
+ async predictSingle(text, baseCharIndex) {
96
+ if (this.encoderSession && this.decoderStepSession) {
97
+ return this.predictSingleSplit(text, baseCharIndex);
98
+ }
99
+ if (!this.session) {
100
+ throw new Error("No ONNX session initialized");
101
+ }
25
102
  const encoded = encodeText(text, this.maxInputLen);
26
103
  const inputIds = new BigInt64Array(encoded.ids);
27
104
  const inputLengths = new BigInt64Array([BigInt(encoded.length || 1)]);
@@ -32,7 +109,150 @@ export class G2PNodeModel {
32
109
  const outputs = await this.session.run(feeds);
33
110
  const decoded = outputs.decoded_ids.data;
34
111
  const attn = outputs.attn_indices.data;
35
- return decodeIdsToResult(decoded, attn, encoded.positionMap);
112
+ const result = decodeIdsToResult(decoded, attn, encoded.positionMap);
113
+ return {
114
+ ipa: result.ipa,
115
+ alignments: result.alignments.map((alignment, idx) => ({
116
+ phoneme: alignment.phoneme,
117
+ phonemeIndex: idx,
118
+ charIndex: alignment.charIndex < 0 ? alignment.charIndex : alignment.charIndex + baseCharIndex,
119
+ })),
120
+ };
121
+ }
122
+ async predictSingleSplit(text, baseCharIndex) {
123
+ if (!this.encoderSession || !this.decoderStepSession) {
124
+ throw new Error("Split ONNX sessions are not initialized");
125
+ }
126
+ const encoded = encodeText(text, this.maxInputLen);
127
+ const inputIds = new BigInt64Array(encoded.ids);
128
+ const inputLengths = new BigInt64Array([BigInt(encoded.length || 1)]);
129
+ const encoderFeeds = {
130
+ input_ids: new Tensor("int64", inputIds, [1, this.maxInputLen]),
131
+ input_lengths: new Tensor("int64", inputLengths, [1]),
132
+ };
133
+ const encoderOutputs = await this.encoderSession.run(encoderFeeds);
134
+ const encoderOutputNames = this.encoderSession.outputNames;
135
+ const decoderInputNames = this.decoderStepSession.inputNames;
136
+ const decoderOutputNames = this.decoderStepSession.outputNames;
137
+ const encNames = {
138
+ encoder_outputs: resolveName(encoderOutputNames, "encoder_outputs"),
139
+ projected_keys: resolveName(encoderOutputNames, "projected_keys"),
140
+ encoder_mask: resolveName(encoderOutputNames, "encoder_mask"),
141
+ hidden: resolveName(encoderOutputNames, "hidden"),
142
+ prev_attn: resolveName(encoderOutputNames, "prev_attn"),
143
+ };
144
+ const decIn = {
145
+ decoder_input_ids: resolveName(decoderInputNames, "decoder_input_ids"),
146
+ encoder_outputs: resolveName(decoderInputNames, "encoder_outputs"),
147
+ projected_keys: resolveName(decoderInputNames, "projected_keys"),
148
+ encoder_mask: resolveName(decoderInputNames, "encoder_mask"),
149
+ prev_attn: resolveName(decoderInputNames, "prev_attn", "prev_attn_in"),
150
+ hidden: resolveName(decoderInputNames, "hidden", "hidden_in"),
151
+ positions: resolveName(decoderInputNames, "positions"),
152
+ };
153
+ const decOut = {
154
+ next_token_ids: resolveName(decoderOutputNames, "next_token_ids"),
155
+ hidden: resolveName(decoderOutputNames, "hidden_out", "hidden"),
156
+ prev_attn: resolveName(decoderOutputNames, "prev_attn_out", "prev_attn"),
157
+ attn_argmax: resolveName(decoderOutputNames, "attn_argmax"),
158
+ };
159
+ const encoderStates = {
160
+ encoder_outputs: encoderOutputs[encNames.encoder_outputs],
161
+ projected_keys: encoderOutputs[encNames.projected_keys],
162
+ encoder_mask: encoderOutputs[encNames.encoder_mask],
163
+ hidden: encoderOutputs[encNames.hidden],
164
+ prev_attn: encoderOutputs[encNames.prev_attn],
165
+ };
166
+ const srcLen = Number(encoderStates.encoder_outputs.dims[1] ?? 0);
167
+ const positions = new Float32Array(srcLen);
168
+ for (let i = 0; i < srcLen; i++)
169
+ positions[i] = i;
170
+ const positionsTensor = new Tensor("float32", positions, [1, srcLen]);
171
+ let decoderInput = new Tensor("int64", new BigInt64Array([BigInt(decoderIds.sos)]), [1, 1]);
172
+ let hidden = encoderStates.hidden;
173
+ let prevAttn = encoderStates.prev_attn;
174
+ const decoded = [];
175
+ const attnIndices = [];
176
+ for (let step = 0; step < this.maxOutputLen; step++) {
177
+ const stepOutputs = await this.decoderStepSession.run({
178
+ [decIn.decoder_input_ids]: decoderInput,
179
+ [decIn.encoder_outputs]: encoderStates.encoder_outputs,
180
+ [decIn.projected_keys]: encoderStates.projected_keys,
181
+ [decIn.encoder_mask]: encoderStates.encoder_mask,
182
+ [decIn.prev_attn]: prevAttn,
183
+ [decIn.hidden]: hidden,
184
+ [decIn.positions]: positionsTensor,
185
+ });
186
+ const nextToken = firstInt64(stepOutputs[decOut.next_token_ids]);
187
+ const attnIdx = firstInt64(stepOutputs[decOut.attn_argmax]);
188
+ decoded.push(nextToken);
189
+ attnIndices.push(attnIdx);
190
+ hidden = stepOutputs[decOut.hidden];
191
+ prevAttn = stepOutputs[decOut.prev_attn];
192
+ decoderInput = new Tensor("int64", new BigInt64Array([nextToken]), [1, 1]);
193
+ if (nextToken === BigInt(decoderIds.eos)) {
194
+ break;
195
+ }
196
+ }
197
+ const result = decodeIdsToResult(decoded, attnIndices, encoded.positionMap);
198
+ return {
199
+ ipa: result.ipa,
200
+ alignments: result.alignments.map((alignment, idx) => ({
201
+ phoneme: alignment.phoneme,
202
+ phonemeIndex: idx,
203
+ charIndex: alignment.charIndex < 0 ? alignment.charIndex : alignment.charIndex + baseCharIndex,
204
+ })),
205
+ };
36
206
  }
37
207
  }
208
+ const firstInt64 = (tensor) => {
209
+ const data = tensor.data;
210
+ const value = data[0];
211
+ return typeof value === "bigint" ? value : BigInt(Math.trunc(Number(value)));
212
+ };
213
+ const escapeRegex = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
214
+ const toGlobalRegex = (delimiter) => {
215
+ if (typeof delimiter === "string") {
216
+ if (delimiter.length === 0) {
217
+ throw new Error("splitDelimiter must not be an empty string");
218
+ }
219
+ return new RegExp(escapeRegex(delimiter), "gu");
220
+ }
221
+ const flags = delimiter.flags.includes("g") ? delimiter.flags : `${delimiter.flags}g`;
222
+ return new RegExp(delimiter.source, flags.includes("u") ? flags : `${flags}u`);
223
+ };
224
+ const splitSegments = (text, delimiter) => {
225
+ if (delimiter === null) {
226
+ return [{ text, startCodeUnit: 0 }];
227
+ }
228
+ const regex = toGlobalRegex(delimiter);
229
+ if (regex.test("")) {
230
+ throw new Error("splitDelimiter must not match an empty string");
231
+ }
232
+ regex.lastIndex = 0;
233
+ const segments = [];
234
+ let start = 0;
235
+ for (const match of text.matchAll(regex)) {
236
+ const end = match.index ?? 0;
237
+ if (end > start) {
238
+ segments.push({ text: text.slice(start, end), startCodeUnit: start });
239
+ }
240
+ start = end + match[0].length;
241
+ }
242
+ if (start < text.length) {
243
+ segments.push({ text: text.slice(start), startCodeUnit: start });
244
+ }
245
+ return segments;
246
+ };
247
+ const codePointOffset = (text, codeUnitOffset) => {
248
+ let codePointIndex = 0;
249
+ let i = 0;
250
+ while (i < codeUnitOffset) {
251
+ const cp = text.codePointAt(i) ?? 0;
252
+ i += cp > 0xffff ? 2 : 1;
253
+ codePointIndex += 1;
254
+ }
255
+ return codePointIndex;
256
+ };
257
+ export { ASRNodeModel, decodeCtcTokens, } from "./asr.js";
38
258
  //# sourceMappingURL=index.js.map