@wq-hook/volcano-react 1.0.1 → 1.0.3

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.d.mts CHANGED
@@ -212,6 +212,8 @@ interface UseMessageTTSParams {
212
212
  onPlayResume?: () => void;
213
213
  /** 播放结束回调 */
214
214
  onPlayEnd?: () => void;
215
+ /** 播放停止回调(用户主动停止时触发) */
216
+ onStop?: () => void;
215
217
  /** 播放错误回调 */
216
218
  onError?: (error: Error) => void;
217
219
  /** 互斥播放控制(默认:true) */
@@ -220,6 +222,7 @@ interface UseMessageTTSParams {
220
222
  fallbackVoice?: string;
221
223
  /** 可视化配置 */
222
224
  visualization?: VisualizationConfig;
225
+ streamId?: string;
223
226
  }
224
227
  interface VisualizationConfig {
225
228
  /** 是否开启可视化数据自动更新 */
@@ -260,11 +263,16 @@ interface UseMessageTTSReturn {
260
263
  getFrequencyData: () => Uint8Array;
261
264
  /** 获取音浪时域数据(用于可视化) */
262
265
  getTimeDomainData: () => Uint8Array;
266
+ /** 是否正在流式播放 */
267
+ isStreamActive: boolean;
268
+ streamState: StreamPlaybackState;
263
269
  /** 实时可视化数据(仅当 visualization.enabled 为 true 时更新) */
264
270
  visualizationData: VisualizationData;
271
+ /** 判断是否可以恢复播放(session 存在且未被停止) */
272
+ canResume: () => boolean;
265
273
  }
266
274
 
267
- declare function useMessageTTS({ ttsConfig, audioParams, autoPlay, metricsCollector, onPlayStart, onPlayPause, onPlayResume, onPlayEnd, onError, exclusive, fallbackVoice, visualization, }: UseMessageTTSParams): UseMessageTTSReturn;
275
+ declare function useMessageTTS({ ttsConfig, audioParams, autoPlay, metricsCollector, onPlayStart, onPlayPause, onPlayResume, onPlayEnd, onStop, onError, fallbackVoice, visualization, streamId: externalStreamId, }: UseMessageTTSParams): UseMessageTTSReturn;
268
276
 
269
277
  /**
270
278
  * 流式文本分段
@@ -323,6 +331,7 @@ interface UseStreamTTSParams {
323
331
  * useStreamTTS 返回值
324
332
  */
325
333
  interface UseStreamTTSReturn {
334
+ streamId: string;
326
335
  /** WebSocket 是否已连接 */
327
336
  isConnected: boolean;
328
337
  /** 会话是否已启动 */
@@ -340,7 +349,7 @@ interface UseStreamTTSReturn {
340
349
  /** 播放进度(0-100) */
341
350
  progress: number;
342
351
  /** 建立 WebSocket 连接 */
343
- connect: () => Promise<void>;
352
+ connect: () => Promise<string>;
344
353
  /** 接收流式文本块 */
345
354
  onMessage: (chunk: string) => void;
346
355
  /** 结束流式输入 */
@@ -376,51 +385,131 @@ interface SessionAudioCacheEntry {
376
385
  speed: number;
377
386
  }
378
387
 
388
+ declare function useStreamTTS({ ttsConfig, audioParams, autoPlay, metricsCollector, onPlayStart, onPlayPause, onPlayResume, onPlayEnd, onError, visualization, maxSegmentLength, }: UseStreamTTSParams): UseStreamTTSReturn;
389
+
379
390
  /**
380
- * 流式 TTS Hook
381
- *
382
- * 适用于 AI 对话实时语音合成场景:
383
- * 1. connect() - 建立 WebSocket 连接
384
- * 2. onMessage(chunk) - 接收 SSE 流式文本并实时分段合成
385
- * 3. finishStream() - 结束流式输入,完成合成
386
- *
387
- * @example
388
- * ```tsx
389
- * const { connect, onMessage, finishStream, isPlaying } = useStreamTTS({
390
- * ttsConfig: { token, appid, resourceId },
391
- * audioParams: { speaker: "zh_female_tianmei" },
392
- * });
393
- *
394
- * // SSE 事件处理
395
- * useEffect(() => {
396
- * const eventSource = new EventSource("/api/chat");
397
- * eventSource.onopen = () => connect();
398
- * eventSource.onmessage = (e) => onMessage(e.data);
399
- * eventSource.onerror = async () => {
400
- * await finishStream();
401
- * eventSource.close();
402
- * };
403
- * }, []);
404
- * ```
391
+ * 流式播放状态
405
392
  */
406
- declare function useStreamTTS({ ttsConfig, audioParams, autoPlay, metricsCollector, onPlayStart, onPlayPause, onPlayResume, onPlayEnd, onError, visualization, maxSegmentLength, }: UseStreamTTSParams): UseStreamTTSReturn;
393
+ interface StreamPlaybackState {
394
+ isPlaying: boolean;
395
+ isPaused: boolean;
396
+ isSynthesizing: boolean;
397
+ progress: number;
398
+ visualizationData: VisualizationData;
399
+ error: string | null;
400
+ isConnected: boolean;
401
+ isSessionStarted: boolean;
402
+ /**
403
+ * 流式输入是否已结束(finishStream 已调用)
404
+ * 用于区分流式合成中和流式合成完成后的状态
405
+ */
406
+ isStreamFinished: boolean;
407
+ }
407
408
  /**
408
- * 获取 Session 音频缓存(供 useMessageTTS 使用)
409
- * @param instanceId - 实例 ID
409
+ * 播放会话配置
410
410
  */
411
- declare function getSessionAudioCache(instanceId: string): SessionAudioCacheEntry | undefined;
411
+ interface PlaybackSessionConfig {
412
+ ttsConfig: TTSConfig;
413
+ audioParams?: AudioParams;
414
+ autoPlay?: boolean;
415
+ metricsCollector?: MetricsCollector;
416
+ visualization?: VisualizationConfig;
417
+ maxSegmentLength?: number;
418
+ onPlayStart?: () => void;
419
+ onPlayPause?: () => void;
420
+ onPlayResume?: () => void;
421
+ onPlayEnd?: () => void;
422
+ onError?: (error: Error) => void;
423
+ }
412
424
  /**
413
- * 清除 Session 音频缓存
414
- * @param instanceId - 实例 ID
425
+ * 播放会话控制器
426
+ * 封装了 WebSocketMSE、Audio、可视化和状态管理
415
427
  */
416
- declare function clearSessionAudioCache(instanceId: string): void;
428
+ declare class PlaybackSession {
429
+ readonly id: string;
430
+ state: StreamPlaybackState;
431
+ private config;
432
+ private listeners;
433
+ private audio;
434
+ private audioContext;
435
+ private analyser;
436
+ private source;
437
+ private audioUrl;
438
+ private client;
439
+ private splitter;
440
+ private segmentQueue;
441
+ private isSending;
442
+ private isSessionStarting;
443
+ private streamText;
444
+ private sessionAudioBuffers;
445
+ private isStreamFinished;
446
+ private isSessionFinished;
447
+ private resolveAllSegmentsSent;
448
+ private animId;
449
+ private lastVisUpdate;
450
+ constructor(id: string, config: PlaybackSessionConfig);
451
+ /**
452
+ * 初始化 AudioContext(用于可视化)
453
+ */
454
+ private initAudioContext;
455
+ private setupAudioListeners;
456
+ /**
457
+ * 建立 WebSocket 连接
458
+ */
459
+ connect(): Promise<void>;
460
+ /**
461
+ * 发送流式文本
462
+ */
463
+ handleStreamChunk(chunk: string): void;
464
+ /**
465
+ * 结束流式输入
466
+ */
467
+ finishStream(): Promise<void>;
468
+ /**
469
+ * 处理非流式播放(直接播放整段文本)
470
+ */
471
+ play(text: string): Promise<void>;
472
+ private processQueue;
473
+ pause(): void;
474
+ resume(): void;
475
+ stop(): void;
476
+ seek(percentage: number): void;
477
+ private updateState;
478
+ subscribe(listener: (state: StreamPlaybackState) => void): () => boolean;
479
+ private notifyListeners;
480
+ private getFrequencyData;
481
+ private getTimeDomainData;
482
+ private startVisualizationLoop;
483
+ private stopVisualizationLoop;
484
+ }
417
485
  /**
418
- * 根据文本查找匹配的 Session 缓存
419
- * @param streamText - 流式文本
420
- * @param voice - 音色
421
- * @param speed - 语速
486
+ * 流式播放管理器(单例)
422
487
  */
423
- declare function findSessionCacheByText(streamText: string, voice: string, speed: number): SessionAudioCacheEntry | undefined;
488
+ declare class StreamPlaybackManagerImpl {
489
+ private sessions;
490
+ private activeStreamId;
491
+ /**
492
+ * 创建新的播放会话
493
+ */
494
+ createSession(id: string, config: PlaybackSessionConfig): PlaybackSession;
495
+ /**
496
+ * 获取会话
497
+ */
498
+ getSession(id: string): PlaybackSession | undefined;
499
+ /**
500
+ * 停止会话
501
+ */
502
+ stop(id: string): void;
503
+ /**
504
+ * 暂停会话
505
+ */
506
+ pause(id: string): void;
507
+ /**
508
+ * 恢复会话
509
+ */
510
+ resume(id: string): void;
511
+ }
512
+ declare const StreamPlaybackManager: StreamPlaybackManagerImpl;
424
513
 
425
514
  /**
426
515
  * 流式文本分段器
@@ -615,4 +704,4 @@ interface AudioProgressBarProps {
615
704
 
616
705
  declare const AudioProgressBar: React$1.FC<AudioProgressBarProps>;
617
706
 
618
- export { type ASRHookParams, type ASRHookReturn, type ASRStatus, type AudioParams, AudioProgressBar, type AudioProgressBarProps, AudioWaveVisualizer, type AudioWaveVisualizerProps, type AuthParams, type ConnectionStatus, type MessageStatus, type SessionAudioCacheEntry, type StreamTextSegment, type StreamingSplitOptions, StreamingTextSplitter, type TTSConfig, type TTSInstance, type TTSMessage, type TextSegment, type UseMessageTTSParams, type UseMessageTTSReturn, type UseStreamTTSParams, type UseStreamTTSReturn, type UseTTSParams, type UseVTSOptions, type UseVTSReturn, type VisualizationConfig, type VisualizationData, clearSessionAudioCache, findSessionCacheByText, getSessionAudioCache, splitTextByDelimiters, useMessageTTS, useStreamTTS, useVolcanoASR, useVolcanoTTS };
707
+ export { type ASRHookParams, type ASRHookReturn, type ASRStatus, type AudioParams, AudioProgressBar, type AudioProgressBarProps, AudioWaveVisualizer, type AudioWaveVisualizerProps, type AuthParams, type ConnectionStatus, type MessageStatus, type SessionAudioCacheEntry, StreamPlaybackManager, type StreamPlaybackState, type StreamTextSegment, type StreamingSplitOptions, StreamingTextSplitter, type TTSConfig, type TTSInstance, type TTSMessage, type TextSegment, type UseMessageTTSParams, type UseMessageTTSReturn, type UseStreamTTSParams, type UseStreamTTSReturn, type UseTTSParams, type UseVTSOptions, type UseVTSReturn, type VisualizationConfig, type VisualizationData, splitTextByDelimiters, useMessageTTS, useStreamTTS, useVolcanoASR, useVolcanoTTS };
package/dist/index.d.ts CHANGED
@@ -212,6 +212,8 @@ interface UseMessageTTSParams {
212
212
  onPlayResume?: () => void;
213
213
  /** 播放结束回调 */
214
214
  onPlayEnd?: () => void;
215
+ /** 播放停止回调(用户主动停止时触发) */
216
+ onStop?: () => void;
215
217
  /** 播放错误回调 */
216
218
  onError?: (error: Error) => void;
217
219
  /** 互斥播放控制(默认:true) */
@@ -220,6 +222,7 @@ interface UseMessageTTSParams {
220
222
  fallbackVoice?: string;
221
223
  /** 可视化配置 */
222
224
  visualization?: VisualizationConfig;
225
+ streamId?: string;
223
226
  }
224
227
  interface VisualizationConfig {
225
228
  /** 是否开启可视化数据自动更新 */
@@ -260,11 +263,16 @@ interface UseMessageTTSReturn {
260
263
  getFrequencyData: () => Uint8Array;
261
264
  /** 获取音浪时域数据(用于可视化) */
262
265
  getTimeDomainData: () => Uint8Array;
266
+ /** 是否正在流式播放 */
267
+ isStreamActive: boolean;
268
+ streamState: StreamPlaybackState;
263
269
  /** 实时可视化数据(仅当 visualization.enabled 为 true 时更新) */
264
270
  visualizationData: VisualizationData;
271
+ /** 判断是否可以恢复播放(session 存在且未被停止) */
272
+ canResume: () => boolean;
265
273
  }
266
274
 
267
- declare function useMessageTTS({ ttsConfig, audioParams, autoPlay, metricsCollector, onPlayStart, onPlayPause, onPlayResume, onPlayEnd, onError, exclusive, fallbackVoice, visualization, }: UseMessageTTSParams): UseMessageTTSReturn;
275
+ declare function useMessageTTS({ ttsConfig, audioParams, autoPlay, metricsCollector, onPlayStart, onPlayPause, onPlayResume, onPlayEnd, onStop, onError, fallbackVoice, visualization, streamId: externalStreamId, }: UseMessageTTSParams): UseMessageTTSReturn;
268
276
 
269
277
  /**
270
278
  * 流式文本分段
@@ -323,6 +331,7 @@ interface UseStreamTTSParams {
323
331
  * useStreamTTS 返回值
324
332
  */
325
333
  interface UseStreamTTSReturn {
334
+ streamId: string;
326
335
  /** WebSocket 是否已连接 */
327
336
  isConnected: boolean;
328
337
  /** 会话是否已启动 */
@@ -340,7 +349,7 @@ interface UseStreamTTSReturn {
340
349
  /** 播放进度(0-100) */
341
350
  progress: number;
342
351
  /** 建立 WebSocket 连接 */
343
- connect: () => Promise<void>;
352
+ connect: () => Promise<string>;
344
353
  /** 接收流式文本块 */
345
354
  onMessage: (chunk: string) => void;
346
355
  /** 结束流式输入 */
@@ -376,51 +385,131 @@ interface SessionAudioCacheEntry {
376
385
  speed: number;
377
386
  }
378
387
 
388
+ declare function useStreamTTS({ ttsConfig, audioParams, autoPlay, metricsCollector, onPlayStart, onPlayPause, onPlayResume, onPlayEnd, onError, visualization, maxSegmentLength, }: UseStreamTTSParams): UseStreamTTSReturn;
389
+
379
390
  /**
380
- * 流式 TTS Hook
381
- *
382
- * 适用于 AI 对话实时语音合成场景:
383
- * 1. connect() - 建立 WebSocket 连接
384
- * 2. onMessage(chunk) - 接收 SSE 流式文本并实时分段合成
385
- * 3. finishStream() - 结束流式输入,完成合成
386
- *
387
- * @example
388
- * ```tsx
389
- * const { connect, onMessage, finishStream, isPlaying } = useStreamTTS({
390
- * ttsConfig: { token, appid, resourceId },
391
- * audioParams: { speaker: "zh_female_tianmei" },
392
- * });
393
- *
394
- * // SSE 事件处理
395
- * useEffect(() => {
396
- * const eventSource = new EventSource("/api/chat");
397
- * eventSource.onopen = () => connect();
398
- * eventSource.onmessage = (e) => onMessage(e.data);
399
- * eventSource.onerror = async () => {
400
- * await finishStream();
401
- * eventSource.close();
402
- * };
403
- * }, []);
404
- * ```
391
+ * 流式播放状态
405
392
  */
406
- declare function useStreamTTS({ ttsConfig, audioParams, autoPlay, metricsCollector, onPlayStart, onPlayPause, onPlayResume, onPlayEnd, onError, visualization, maxSegmentLength, }: UseStreamTTSParams): UseStreamTTSReturn;
393
+ interface StreamPlaybackState {
394
+ isPlaying: boolean;
395
+ isPaused: boolean;
396
+ isSynthesizing: boolean;
397
+ progress: number;
398
+ visualizationData: VisualizationData;
399
+ error: string | null;
400
+ isConnected: boolean;
401
+ isSessionStarted: boolean;
402
+ /**
403
+ * 流式输入是否已结束(finishStream 已调用)
404
+ * 用于区分流式合成中和流式合成完成后的状态
405
+ */
406
+ isStreamFinished: boolean;
407
+ }
407
408
  /**
408
- * 获取 Session 音频缓存(供 useMessageTTS 使用)
409
- * @param instanceId - 实例 ID
409
+ * 播放会话配置
410
410
  */
411
- declare function getSessionAudioCache(instanceId: string): SessionAudioCacheEntry | undefined;
411
+ interface PlaybackSessionConfig {
412
+ ttsConfig: TTSConfig;
413
+ audioParams?: AudioParams;
414
+ autoPlay?: boolean;
415
+ metricsCollector?: MetricsCollector;
416
+ visualization?: VisualizationConfig;
417
+ maxSegmentLength?: number;
418
+ onPlayStart?: () => void;
419
+ onPlayPause?: () => void;
420
+ onPlayResume?: () => void;
421
+ onPlayEnd?: () => void;
422
+ onError?: (error: Error) => void;
423
+ }
412
424
  /**
413
- * 清除 Session 音频缓存
414
- * @param instanceId - 实例 ID
425
+ * 播放会话控制器
426
+ * 封装了 WebSocketMSE、Audio、可视化和状态管理
415
427
  */
416
- declare function clearSessionAudioCache(instanceId: string): void;
428
+ declare class PlaybackSession {
429
+ readonly id: string;
430
+ state: StreamPlaybackState;
431
+ private config;
432
+ private listeners;
433
+ private audio;
434
+ private audioContext;
435
+ private analyser;
436
+ private source;
437
+ private audioUrl;
438
+ private client;
439
+ private splitter;
440
+ private segmentQueue;
441
+ private isSending;
442
+ private isSessionStarting;
443
+ private streamText;
444
+ private sessionAudioBuffers;
445
+ private isStreamFinished;
446
+ private isSessionFinished;
447
+ private resolveAllSegmentsSent;
448
+ private animId;
449
+ private lastVisUpdate;
450
+ constructor(id: string, config: PlaybackSessionConfig);
451
+ /**
452
+ * 初始化 AudioContext(用于可视化)
453
+ */
454
+ private initAudioContext;
455
+ private setupAudioListeners;
456
+ /**
457
+ * 建立 WebSocket 连接
458
+ */
459
+ connect(): Promise<void>;
460
+ /**
461
+ * 发送流式文本
462
+ */
463
+ handleStreamChunk(chunk: string): void;
464
+ /**
465
+ * 结束流式输入
466
+ */
467
+ finishStream(): Promise<void>;
468
+ /**
469
+ * 处理非流式播放(直接播放整段文本)
470
+ */
471
+ play(text: string): Promise<void>;
472
+ private processQueue;
473
+ pause(): void;
474
+ resume(): void;
475
+ stop(): void;
476
+ seek(percentage: number): void;
477
+ private updateState;
478
+ subscribe(listener: (state: StreamPlaybackState) => void): () => boolean;
479
+ private notifyListeners;
480
+ private getFrequencyData;
481
+ private getTimeDomainData;
482
+ private startVisualizationLoop;
483
+ private stopVisualizationLoop;
484
+ }
417
485
  /**
418
- * 根据文本查找匹配的 Session 缓存
419
- * @param streamText - 流式文本
420
- * @param voice - 音色
421
- * @param speed - 语速
486
+ * 流式播放管理器(单例)
422
487
  */
423
- declare function findSessionCacheByText(streamText: string, voice: string, speed: number): SessionAudioCacheEntry | undefined;
488
+ declare class StreamPlaybackManagerImpl {
489
+ private sessions;
490
+ private activeStreamId;
491
+ /**
492
+ * 创建新的播放会话
493
+ */
494
+ createSession(id: string, config: PlaybackSessionConfig): PlaybackSession;
495
+ /**
496
+ * 获取会话
497
+ */
498
+ getSession(id: string): PlaybackSession | undefined;
499
+ /**
500
+ * 停止会话
501
+ */
502
+ stop(id: string): void;
503
+ /**
504
+ * 暂停会话
505
+ */
506
+ pause(id: string): void;
507
+ /**
508
+ * 恢复会话
509
+ */
510
+ resume(id: string): void;
511
+ }
512
+ declare const StreamPlaybackManager: StreamPlaybackManagerImpl;
424
513
 
425
514
  /**
426
515
  * 流式文本分段器
@@ -615,4 +704,4 @@ interface AudioProgressBarProps {
615
704
 
616
705
  declare const AudioProgressBar: React$1.FC<AudioProgressBarProps>;
617
706
 
618
- export { type ASRHookParams, type ASRHookReturn, type ASRStatus, type AudioParams, AudioProgressBar, type AudioProgressBarProps, AudioWaveVisualizer, type AudioWaveVisualizerProps, type AuthParams, type ConnectionStatus, type MessageStatus, type SessionAudioCacheEntry, type StreamTextSegment, type StreamingSplitOptions, StreamingTextSplitter, type TTSConfig, type TTSInstance, type TTSMessage, type TextSegment, type UseMessageTTSParams, type UseMessageTTSReturn, type UseStreamTTSParams, type UseStreamTTSReturn, type UseTTSParams, type UseVTSOptions, type UseVTSReturn, type VisualizationConfig, type VisualizationData, clearSessionAudioCache, findSessionCacheByText, getSessionAudioCache, splitTextByDelimiters, useMessageTTS, useStreamTTS, useVolcanoASR, useVolcanoTTS };
707
+ export { type ASRHookParams, type ASRHookReturn, type ASRStatus, type AudioParams, AudioProgressBar, type AudioProgressBarProps, AudioWaveVisualizer, type AudioWaveVisualizerProps, type AuthParams, type ConnectionStatus, type MessageStatus, type SessionAudioCacheEntry, StreamPlaybackManager, type StreamPlaybackState, type StreamTextSegment, type StreamingSplitOptions, StreamingTextSplitter, type TTSConfig, type TTSInstance, type TTSMessage, type TextSegment, type UseMessageTTSParams, type UseMessageTTSReturn, type UseStreamTTSParams, type UseStreamTTSReturn, type UseTTSParams, type UseVTSOptions, type UseVTSReturn, type VisualizationConfig, type VisualizationData, splitTextByDelimiters, useMessageTTS, useStreamTTS, useVolcanoASR, useVolcanoTTS };