@vunk/plus 1.7.2 → 1.7.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.
Files changed (65) hide show
  1. package/components/agent-chat-provider/index.mjs +1 -1
  2. package/components/avatar/index.mjs +1 -1
  3. package/components/broadcasting-markdown/index.mjs +103 -240
  4. package/components/broadcasting-markdown/src/ctx.d.ts +1 -4
  5. package/components/broadcasting-markdown/src/howler-speech.vue.d.ts +49 -88
  6. package/components/broadcasting-markdown/src/index.vue.d.ts +44 -103
  7. package/components/broadcasting-markdown/src/types.d.ts +1 -1
  8. package/components/broadcasting-markdown/src/use.d.ts +6 -8
  9. package/components/bubble-templates/index.css +4 -0
  10. package/components/bubble-templates/index.mjs +2 -2
  11. package/components/chat-independent/index.mjs +1 -1
  12. package/components/index2.mjs +7 -7
  13. package/components/index3.mjs +1 -1
  14. package/components/lottie-animation/index.mjs +1 -1
  15. package/components/metahuman-broadcasting/index.mjs +9 -6
  16. package/components/metahuman-broadcasting/src/index.vue.d.ts +62 -114
  17. package/components/monaco-editor/index.mjs +1 -1
  18. package/components/monaco-environment/index.mjs +1 -1
  19. package/components/pixi-frame/src/apng.vue.d.ts +3 -3
  20. package/components/pixi-frame/src/bitmap.vue.d.ts +5 -5
  21. package/components/pixi-frame/src/core.vue.d.ts +5 -5
  22. package/components/pixi-frame/src/index.vue.d.ts +12 -12
  23. package/components/pixi-frame/src/video.vue.d.ts +3 -3
  24. package/components/recorder-button/index.mjs +1 -1
  25. package/components/routes-menu-content/index.mjs +3 -3
  26. package/components/sender/index.mjs +2 -2
  27. package/components/speech-button/index.mjs +3 -3
  28. package/components/table-columns/index.mjs +1 -1
  29. package/components/tables-v1/index.mjs +7 -6
  30. package/components/tables-v1/src/index.vue.d.ts +129 -0
  31. package/components/tables-v1-checkbox/index.mjs +1 -1
  32. package/components/tables-v1-checkbox/src/index.vue.d.ts +129 -0
  33. package/components/text/index.mjs +1 -1
  34. package/components/typing-markdown/index.mjs +5 -8
  35. package/components/vditor/index.mjs +3 -3
  36. package/components/vditor/src/ctx.d.ts +1 -1
  37. package/components/vditor/src/index.vue.d.ts +1 -1
  38. package/icons/end/index.mjs +1 -1
  39. package/icons/keyboard/index.mjs +1 -1
  40. package/icons/start/index.mjs +1 -1
  41. package/icons/voice/index.mjs +1 -1
  42. package/index.css +5 -0
  43. package/package.json +4 -1
  44. package/shared/StreamingInferenceService.mjs +4 -1
  45. package/shared/audioToFrames/index.mjs +2 -5
  46. package/shared/audioToFrames/src/audio/StreamingFeatureExtractorService.d.ts +20 -4
  47. package/shared/audioToFrames/src/audio/index.d.ts +0 -2
  48. package/shared/audioToFrames/src/audio/index.mjs +84 -157
  49. package/shared/audioToFrames/src/core/constants.d.ts +0 -22
  50. package/shared/audioToFrames/src/core/index.mjs +16 -2643
  51. package/shared/audioToFrames/src/core/utils.d.ts +1 -68
  52. package/shared/audioToFrames/src/inference/StreamingInferenceService.d.ts +43 -0
  53. package/shared/audioToFrames/src/media/index.d.ts +0 -5
  54. package/shared/audioToFrames/src/media/index.mjs +180 -610
  55. package/shared/constants.mjs +1 -12
  56. package/shared/PredictiveFrameLoader.mjs +0 -367
  57. package/shared/audioToFrames/src/audio/AudioProcessor.d.ts +0 -25
  58. package/shared/audioToFrames/src/audio/FeatureExtractorService.d.ts +0 -31
  59. package/shared/audioToFrames/src/inference/types.d.ts +0 -102
  60. package/shared/audioToFrames/src/media/ImageBitmapPool.d.ts +0 -63
  61. package/shared/audioToFrames/src/media/ImageProcessor.d.ts +0 -47
  62. package/shared/audioToFrames/src/media/PlaybackService.d.ts +0 -56
  63. package/shared/audioToFrames/src/media/WebGLPlaybackService.d.ts +0 -74
  64. package/shared/audioToFrames/src/media/WebGLRenderer.d.ts +0 -66
  65. package/shared/utils.mjs +0 -123
@@ -8,6 +8,18 @@
8
8
  *
9
9
  * @author Zhonghan Li
10
10
  */
11
+ /**
12
+ * 创建AudioContext的兼容函数,处理Safari的限制。
13
+ * 在Safari中,AudioContext需要在用户交互后才能创建。
14
+ */
15
+ export declare function createAudioContext(): Promise<AudioContext>;
16
+ /**
17
+ * 特征提取结果接口
18
+ */
19
+ export interface FeatureExtractionResult {
20
+ features: Float32Array;
21
+ dimensions: number[];
22
+ }
11
23
  /**
12
24
  * 单个chunk的特征提取结果结构体。
13
25
  */
@@ -57,8 +69,6 @@ export declare class StreamingFeatureExtractorService {
57
69
  private queue;
58
70
  /** 回调函数集合 */
59
71
  private callbacks;
60
- /** 性能计时器 */
61
- private timer;
62
72
  /** 存储每个chunk的处理结果,用于最终合并 */
63
73
  private chunkResults;
64
74
  /** 音频总chunk数 */
@@ -73,8 +83,8 @@ export declare class StreamingFeatureExtractorService {
73
83
  private audioBuffer;
74
84
  /** 音频上下文实例,用于创建AudioBuffer */
75
85
  private audioContext;
76
- /** 复用的特征提取器实例,以提高性能 */
77
- private featureExtractor;
86
+ /** 复用的Worker实例,以提高性能 */
87
+ private worker;
78
88
  /**
79
89
  * 创建AudioBuffer的兼容方法,处理Safari的限制。
80
90
  * @param numberOfChannels 声道数
@@ -83,6 +93,12 @@ export declare class StreamingFeatureExtractorService {
83
93
  * @returns AudioBuffer实例
84
94
  */
85
95
  private createAudioBuffer;
96
+ /**
97
+ * 使用Worker处理AudioBuffer,提取特征
98
+ * @param audioBuffer 输入的AudioBuffer
99
+ * @returns Promise<FeatureExtractionResult>
100
+ */
101
+ private processWithWorker;
86
102
  /**
87
103
  * 启动流式音频特征提取。
88
104
  * @param audioBuffer 输入的音频缓冲区。
@@ -2,6 +2,4 @@
2
2
  * @file 音频处理服务模块导出
3
3
  * @author Zhonghan Li
4
4
  */
5
- export * from './AudioProcessor';
6
- export * from './FeatureExtractorService';
7
5
  export * from './StreamingFeatureExtractorService';
@@ -1,111 +1,5 @@
1
- import { W as WINDOW_NUM_CHUNKS, d as WINDOW_NUM_CHUNKS_HALF, C as CHUNK_DURATION_SECONDS, a as NUM_SEQUENCE_FRAMES, N as NUM_MEL_BINS } from '../../../constants.mjs';
2
1
  import { w as workerConfig } from '../../../config.mjs';
3
- import { c as createErrorHandler, P as PerformanceTimer } from '../../../utils.mjs';
4
-
5
- function getAudioWindow(allAudioFeatures, allAudioDims, centerChunkIndex) {
6
- if (allAudioDims.length !== 3) {
7
- throw new Error(
8
- "Invalid dimensions array provided to getAudioWindow. Expected length 3."
9
- );
10
- }
11
- const [numChunks, chunkSize, melBins] = allAudioDims;
12
- const finalWindowData = new Float32Array(
13
- WINDOW_NUM_CHUNKS * chunkSize * melBins
14
- );
15
- const chunkTotalSize = chunkSize * melBins;
16
- for (let j = 0; j < WINDOW_NUM_CHUNKS; j++) {
17
- const sourceChunkIndex = centerChunkIndex - WINDOW_NUM_CHUNKS_HALF + j;
18
- const clampedSourceIndex = Math.max(
19
- 0,
20
- Math.min(sourceChunkIndex, numChunks - 1)
21
- );
22
- const sourceChunkStart = clampedSourceIndex * chunkTotalSize;
23
- const sourceChunkEnd = sourceChunkStart + chunkTotalSize;
24
- const chunkData = allAudioFeatures.subarray(
25
- sourceChunkStart,
26
- sourceChunkEnd
27
- );
28
- const destChunkStart = j * chunkTotalSize;
29
- finalWindowData.set(chunkData, destChunkStart);
30
- }
31
- return finalWindowData;
32
- }
33
- async function createAudioContext() {
34
- const AudioContextClass = window.AudioContext || window.webkitAudioContext;
35
- if (!AudioContextClass) {
36
- throw new Error("\u60A8\u7684\u6D4F\u89C8\u5668\u4E0D\u652F\u6301Web Audio API");
37
- }
38
- const audioContext = new AudioContextClass();
39
- if (audioContext.state === "suspended") {
40
- await audioContext.resume();
41
- }
42
- return audioContext;
43
- }
44
-
45
- class FeatureExtractorService {
46
- constructor() {
47
- this.errorHandler = createErrorHandler("FeatureExtractorService");
48
- this.worker = new Worker(
49
- /* @vite-ignore */
50
- `${workerConfig.path}/feature.worker.js`,
51
- { type: "module" }
52
- );
53
- }
54
- /**
55
- * 处理 AudioBuffer,在后台线程中提取特征。
56
- * @param audioBuffer Web Audio API 的 AudioBuffer 对象。
57
- * @returns 一个 Promise,成功时解析为特征结果,失败时拒绝并返回错误信息。
58
- */
59
- async process(audioBuffer) {
60
- try {
61
- const leftChannel = audioBuffer.getChannelData(0);
62
- const rightChannel = audioBuffer.numberOfChannels > 1 ? audioBuffer.getChannelData(1) : void 0;
63
- const message = {
64
- leftChannel,
65
- rightChannel,
66
- sampleRate: audioBuffer.sampleRate
67
- };
68
- const transferList = [leftChannel.buffer, rightChannel?.buffer].filter(Boolean);
69
- const result = await this.createWorkerPromise(
70
- message,
71
- transferList
72
- );
73
- return result;
74
- } catch (error) {
75
- throw this.errorHandler(error);
76
- }
77
- }
78
- /**
79
- * 创建Worker Promise,直接处理消息传递
80
- */
81
- createWorkerPromise(message, transferList) {
82
- return new Promise((resolve, reject) => {
83
- const handleMessage = (event) => {
84
- this.worker.removeEventListener("message", handleMessage);
85
- this.worker.removeEventListener("error", handleError);
86
- if (event.data.status === "success") {
87
- resolve(event.data.payload);
88
- } else {
89
- reject(new Error(event.data.error || "Unknown worker error"));
90
- }
91
- };
92
- function handleError(error) {
93
- this.worker.removeEventListener("message", handleMessage);
94
- this.worker.removeEventListener("error", handleError);
95
- reject(error);
96
- }
97
- this.worker.addEventListener("message", handleMessage);
98
- this.worker.addEventListener("error", handleError);
99
- this.worker.postMessage(message, transferList);
100
- });
101
- }
102
- /**
103
- * 终止Worker
104
- */
105
- terminate() {
106
- this.worker.terminate();
107
- }
108
- }
2
+ import { C as CHUNK_DURATION_SECONDS, a as NUM_SEQUENCE_FRAMES, N as NUM_MEL_BINS } from '../../../constants.mjs';
109
3
 
110
4
  var __defProp = Object.defineProperty;
111
5
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
@@ -239,13 +133,22 @@ var _AsyncQueue = class _AsyncQueue {
239
133
  __name(_AsyncQueue, "AsyncQueue");
240
134
  var AsyncQueue = _AsyncQueue;
241
135
 
136
+ async function createAudioContext() {
137
+ const AudioContextClass = window.AudioContext || window.webkitAudioContext;
138
+ if (!AudioContextClass) {
139
+ throw new Error("\u60A8\u7684\u6D4F\u89C8\u5668\u4E0D\u652F\u6301Web Audio API");
140
+ }
141
+ const audioContext = new AudioContextClass();
142
+ if (audioContext.state === "suspended") {
143
+ await audioContext.resume();
144
+ }
145
+ return audioContext;
146
+ }
242
147
  class StreamingFeatureExtractorService {
243
148
  constructor() {
244
149
  this.queue = new AsyncQueue();
245
150
  /** 回调函数集合 */
246
151
  this.callbacks = {};
247
- /** 性能计时器 */
248
- this.timer = new PerformanceTimer();
249
152
  /** 存储每个chunk的处理结果,用于最终合并 */
250
153
  this.chunkResults = [];
251
154
  /** 音频总chunk数 */
@@ -260,8 +163,8 @@ class StreamingFeatureExtractorService {
260
163
  this.audioBuffer = null;
261
164
  /** 音频上下文实例,用于创建AudioBuffer */
262
165
  this.audioContext = null;
263
- /** 复用的特征提取器实例,以提高性能 */
264
- this.featureExtractor = null;
166
+ /** 复用的Worker实例,以提高性能 */
167
+ this.worker = null;
265
168
  }
266
169
  /**
267
170
  * 创建AudioBuffer的兼容方法,处理Safari的限制。
@@ -289,6 +192,47 @@ class StreamingFeatureExtractorService {
289
192
  );
290
193
  }
291
194
  }
195
+ /**
196
+ * 使用Worker处理AudioBuffer,提取特征
197
+ * @param audioBuffer 输入的AudioBuffer
198
+ * @returns Promise<FeatureExtractionResult>
199
+ */
200
+ async processWithWorker(audioBuffer) {
201
+ if (!this.worker) {
202
+ throw new Error("Worker not initialized");
203
+ }
204
+ return new Promise((resolve, reject) => {
205
+ const cleanup = () => {
206
+ if (this.worker) {
207
+ this.worker.removeEventListener("message", handleMessage);
208
+ this.worker.removeEventListener("error", handleError);
209
+ }
210
+ };
211
+ function handleMessage(event) {
212
+ cleanup();
213
+ if (event.data.status === "success") {
214
+ resolve(event.data.payload);
215
+ } else {
216
+ reject(new Error(event.data.error || "Unknown worker error"));
217
+ }
218
+ }
219
+ function handleError(error) {
220
+ cleanup();
221
+ reject(error);
222
+ }
223
+ this.worker.addEventListener("message", handleMessage);
224
+ this.worker.addEventListener("error", handleError);
225
+ const leftChannel = audioBuffer.getChannelData(0);
226
+ const rightChannel = audioBuffer.numberOfChannels > 1 ? audioBuffer.getChannelData(1) : void 0;
227
+ const message = {
228
+ leftChannel,
229
+ rightChannel,
230
+ sampleRate: audioBuffer.sampleRate
231
+ };
232
+ const transferList = [leftChannel.buffer, rightChannel?.buffer].filter(Boolean);
233
+ this.worker.postMessage(message, transferList);
234
+ });
235
+ }
292
236
  /**
293
237
  * 启动流式音频特征提取。
294
238
  * @param audioBuffer 输入的音频缓冲区。
@@ -305,22 +249,24 @@ class StreamingFeatureExtractorService {
305
249
  this.chunkResults = [];
306
250
  this.completedChunks = 0;
307
251
  this.totalFramesProcessed = 0;
308
- this.featureExtractor = new FeatureExtractorService();
252
+ if (!this.worker) {
253
+ this.worker = new Worker(
254
+ /* @vite-ignore */
255
+ `${workerConfig.path}/feature.worker.js`,
256
+ { type: "module" }
257
+ );
258
+ }
309
259
  const durationSeconds = audioBuffer.duration;
310
260
  this.totalChunks = Math.ceil(durationSeconds / CHUNK_DURATION_SECONDS);
311
261
  try {
312
- this.timer.start("totalProcessing");
313
262
  for (let chunkIndex = 0; chunkIndex < this.totalChunks; chunkIndex++) {
314
263
  if (!this.isRunning)
315
264
  break;
316
- this.timer.start(`chunk_${chunkIndex}`);
317
265
  await this.processChunk(chunkIndex);
318
- this.timer.end(`chunk_${chunkIndex}`);
319
266
  }
320
267
  if (this.isRunning) {
321
268
  await this.finalize();
322
269
  }
323
- this.timer.end("totalProcessing");
324
270
  } catch (error) {
325
271
  const errorMessage = error instanceof Error ? error.message : "Unknown error";
326
272
  this.callbacks.onError?.(errorMessage);
@@ -334,7 +280,7 @@ class StreamingFeatureExtractorService {
334
280
  * @param chunkIndex chunk的索引(从0开始)。
335
281
  */
336
282
  async processChunk(chunkIndex) {
337
- if (!this.audioBuffer || !this.featureExtractor)
283
+ if (!this.audioBuffer || !this.worker)
338
284
  return;
339
285
  const startTimeSeconds = chunkIndex * CHUNK_DURATION_SECONDS;
340
286
  const endTimeSeconds = Math.min(
@@ -346,11 +292,6 @@ class StreamingFeatureExtractorService {
346
292
  );
347
293
  const endSample = Math.floor(endTimeSeconds * this.audioBuffer.sampleRate);
348
294
  const chunkLength = endSample - startSample;
349
- console.log(
350
- `\u5904\u7406chunk ${chunkIndex}: ${startTimeSeconds.toFixed(
351
- 2
352
- )}s - ${endTimeSeconds.toFixed(2)}s`
353
- );
354
295
  const chunkBuffer = await this.createAudioBuffer(
355
296
  this.audioBuffer.numberOfChannels,
356
297
  chunkLength,
@@ -361,36 +302,25 @@ class StreamingFeatureExtractorService {
361
302
  const chunkData = chunkBuffer.getChannelData(channel);
362
303
  chunkData.set(sourceData.subarray(startSample, endSample));
363
304
  }
364
- try {
365
- this.timer.start(`extract_chunk_${chunkIndex}`);
366
- const result = await this.featureExtractor.process(chunkBuffer);
367
- this.timer.end(`extract_chunk_${chunkIndex}`);
368
- const chunkResult = {
369
- chunkIndex,
370
- features: result.features,
371
- dimensions: result.dimensions,
372
- startTimeSeconds,
373
- endTimeSeconds
374
- };
375
- this.totalFramesProcessed += chunkResult.dimensions[0];
376
- this.chunkResults[chunkIndex] = chunkResult;
377
- this.completedChunks++;
378
- console.log(
379
- `Chunk ${chunkIndex} \u5B8C\u6210\uFF0C\u7279\u5F81\u7EF4\u5EA6: [${result.dimensions.join(", ")}]`
380
- );
381
- this.callbacks.onChunkComplete?.(chunkResult);
382
- this.callbacks.onProgress?.(this.completedChunks, this.totalChunks);
383
- this.chunkResults[chunkIndex] = null;
384
- } catch (error) {
385
- console.error(`\u5904\u7406chunk ${chunkIndex} \u65F6\u53D1\u751F\u9519\u8BEF:`, error);
386
- throw error;
387
- }
305
+ const result = await this.processWithWorker(chunkBuffer);
306
+ const chunkResult = {
307
+ chunkIndex,
308
+ features: result.features,
309
+ dimensions: result.dimensions,
310
+ startTimeSeconds,
311
+ endTimeSeconds
312
+ };
313
+ this.totalFramesProcessed += chunkResult.dimensions[0];
314
+ this.chunkResults[chunkIndex] = chunkResult;
315
+ this.completedChunks++;
316
+ this.callbacks.onChunkComplete?.(chunkResult);
317
+ this.callbacks.onProgress?.(this.completedChunks, this.totalChunks);
318
+ this.chunkResults[chunkIndex] = null;
388
319
  }
389
320
  /**
390
321
  * 所有chunk处理完成后,合并特征并调用onComplete。
391
322
  */
392
323
  async finalize() {
393
- console.log("\u6700\u7EC8\u786E\u5B9A\u6240\u6709chunk\u7684\u5904\u7406...");
394
324
  if (this.completedChunks === 0) {
395
325
  this.callbacks.onError?.("No chunks were processed.");
396
326
  return;
@@ -400,7 +330,6 @@ class StreamingFeatureExtractorService {
400
330
  NUM_SEQUENCE_FRAMES,
401
331
  NUM_MEL_BINS
402
332
  ];
403
- console.log(`\u7279\u5F81\u5904\u7406\u5B8C\u6210, \u603B\u7EF4\u5EA6: [${totalDimensions.join(", ")}]`);
404
333
  this.callbacks.onComplete?.(totalDimensions);
405
334
  }
406
335
  /**
@@ -409,9 +338,9 @@ class StreamingFeatureExtractorService {
409
338
  cleanup() {
410
339
  this.isRunning = false;
411
340
  this.audioBuffer = null;
412
- if (this.featureExtractor) {
413
- this.featureExtractor.terminate();
414
- this.featureExtractor = null;
341
+ if (this.worker) {
342
+ this.worker.terminate();
343
+ this.worker = null;
415
344
  }
416
345
  this.chunkResults.forEach((chunk) => {
417
346
  if (chunk && chunk.features) {
@@ -423,18 +352,16 @@ class StreamingFeatureExtractorService {
423
352
  this.completedChunks = 0;
424
353
  this.totalChunks = 0;
425
354
  this.totalFramesProcessed = 0;
426
- this.timer.reset();
427
355
  }
428
356
  /**
429
357
  * 停止当前的流式处理。
430
358
  */
431
359
  stop() {
432
360
  if (this.isRunning) {
433
- console.log("\u505C\u6B62\u6D41\u5F0F\u97F3\u9891\u5904\u7406");
434
361
  this.isRunning = false;
435
- if (this.featureExtractor) {
436
- this.featureExtractor.terminate();
437
- this.featureExtractor = null;
362
+ if (this.worker) {
363
+ this.worker.terminate();
364
+ this.worker = null;
438
365
  }
439
366
  this.callbacks = {};
440
367
  this.chunkResults = [];
@@ -445,4 +372,4 @@ class StreamingFeatureExtractorService {
445
372
  }
446
373
  }
447
374
 
448
- export { FeatureExtractorService, NUM_MEL_BINS, NUM_SEQUENCE_FRAMES, StreamingFeatureExtractorService, createAudioContext, getAudioWindow };
375
+ export { StreamingFeatureExtractorService, createAudioContext };
@@ -11,29 +11,7 @@ export declare const NUM_MEL_BINS = 80;
11
11
  export declare const NUM_SEQUENCE_FRAMES = 4;
12
12
  /** 每个chunk的时长(秒) */
13
13
  export declare const CHUNK_DURATION_SECONDS = 5;
14
- /** 目标帧率 (FPS) */
15
- export declare const TARGET_FPS = 25;
16
- /** 每帧之间的间隔时间 (毫秒) */
17
- export declare const FRAME_INTERVAL_MS: number;
18
- /** 音频采样率 (Hz) */
19
- export declare const SAMPLE_RATE = 16000;
20
- /** 音频帧长度 (毫秒) */
21
- export declare const FRAME_LENGTH_MS = 25;
22
- /** 音频帧移 (毫秒) */
23
- export declare const FRAME_SHIFT_MS = 10;
24
- /** 能量下限,用于防止在对数计算中出现 log(0) 的情况 */
25
- export declare const ENERGY_FLOOR = 1e-10;
26
- /** 预加重系数 */
27
- export declare const PREEMPH_COEFF = 0.97;
28
14
  /** 上下文窗口中的总块数 */
29
15
  export declare const WINDOW_NUM_CHUNKS = 32;
30
16
  /** 上下文窗口的单边块数(半径) */
31
17
  export declare const WINDOW_NUM_CHUNKS_HALF: number;
32
- /** 批处理大小,用于批量推理以提高吞吐量 */
33
- export declare const BATCH_SIZE = 32;
34
- /** 默认的低频截止频率 (Hz) */
35
- export declare const DEFAULT_LOW_FREQ = 20;
36
- /** 是否移除直流分量(DC offset) */
37
- export declare const REMOVE_DC_OFFSET = true;
38
- /** FFT 计算大小是否向上舍入到最近的2的幂 */
39
- export declare const ROUND_TO_POWER_OF_TWO = true;