import type { Ref } from 'vue'import type { ActionQueueItem } from '../types'import { generateSSML } from '../utils'interface SpeakOptions { isStart?: boolean // 是否为流式对话起始 isEnd?: boolean // 是否为流式对话结束}interface ActionManagerOptions { instanceRef: Ref onVoiceReady?: () => void onVoiceEnd?: () => void}export class ActionManager { private queue: ActionQueueItem[] = [] private isSpeaking = false private instanceRef: Ref private onVoiceReady?: () => void private onVoiceEnd?: () => void constructor(options: ActionManagerOptions) { this.instanceRef = options.instanceRef this.onVoiceReady = options.onVoiceReady this.onVoiceEnd = options.onVoiceEnd } speak(text: string, options: SpeakOptions = { const ssml = generateSSML(text.replace(/\n+/g, '\n')) this.queue.push({ ssml, isStart: options.isStart ?? false, isEnd: options.isEnd ?? false }) this.processQueue() } reset() { this.queue = [] this.isSpeaking = false } private async processQueue() { if (this.isSpeaking) return if (!this.queue.length) return const instance = this.instanceRef.value if (!instance) return this.isSpeaking = true while (this.queue.length) { const item = this.queue.shift() if (!item) break this.onVoiceReady?.() instance.speak(item.ssml, item.isStart, item.isEnd) // 如果是流式中间段,不等待直接继续 if (!item.isEnd) { continue } // 等待 speak 完成 await new Promise(resolve => setTimeout(resolve, 50)) } this.isSpeaking = false this.onVoiceEnd?.() }}核心设计:SSML 封装:每段文本通过 generateSSML() 转换为 SSML 格式,支持音调、语速、音量参数队列管理:即使多段文本同时到达,也按 FIFO 顺序逐段播报isStart / isEnd 标记:告知 SDK 当前段落是流式对话的开始、中间还是结束,SDK 据此控制动作连贯性流式中间段不等待:if (!item.isEnd) continue 确保中间段落快速入队,降低播报延迟4.6 流式播报分段策略灵引采用「智能分段 + 首句优先」策略,在 LLM 流式输出过程中实时将文本推送给数字人:
8.earendil-works/pi 🏷️ 项目名称: earendil-works/pi🔗 项目地址: https://github.
我们来试试找个 按照动图教程找个应该就行 这样就出来了,挺方便的,我试试放原理图上。
宏有时候可以做函数做不到的事情。⽐如:宏的参数可以出现类型,但是函数做不到。#include #include #define MALLOC(num, type) (type*)malloc((num) * sizeof(type)) int main() { // 分配10个int大小的空间 int* p = MALLOC(10, int); // 使用这块内存 for (int i = 0; i < 10; i++) { p[i] = i + 1; } for (int i = 0; i < 10; i++) { printf("%d ", p[i]); } printf("\n"); // 释放内存 free(p); p = NULL; return 0; } 宏展开后 int* p = (int*)malloc((10) * sizeof(int)); MALLOC(10, int) --> (int*)malloc((10) * sizeof(int)) 也可以分配其他类型 // 分配5个double double* d = MALLOC(5, double); // 分配20个char char* c = MALLOC(20, char); 注意事项: 加括号的重要性: #define MALLOC(num, type) (type*)malloc((num) * sizeof(type)) 如果 num 传的是 3+2,不加括号就会变成 3+2 * sizeof(type),结果就不对了。
3% 提升至 38.3%,增加 10.0 个百分点; Terminus-2 从 26.