30 lines
3.7 KiB
JavaScript
30 lines
3.7 KiB
JavaScript
import { DEFAULT_GLOBALS, autoLayout } from './engine.js';
|
|
|
|
export function nodeData(kind,label) {
|
|
return { kind,label,mode:'estimate',size:kind==='tts'?.6:kind==='asr'?.6:8,active:3,arch:'dense',hardware:'h200',cards:1,quant:'fp8',inputTokens:1024,outputTokens:128,reasoningTokens:0,contextGrowth:256,cacheRatio:0,speculative:1,maxSteps:1,expectedSteps:1,toolMs:0,finalOnly:true,streamingInput:true,durationMs:kind==='program'?80:kind==='merge'?20:kind==='asr'?100:kind==='output'?60:0,customTps:150,customFirstMs:100,customRtf:.25,resource:'',join:'all',target:true,outputType:'audio' };
|
|
}
|
|
const n=(id,kind,label,more={})=>({id,type:'stage',position:{x:0,y:0},data:{...nodeData(kind,label),...more}});
|
|
const e=(source,target,release='complete',more={})=>({id:`${source}-${target}`,source,target,type:'smoothstep',data:{release,tokens:8,...more}});
|
|
const preset=(name,description,nodes,edges,globals={})=>({name,description,version:1,nodes:autoLayout(nodes,edges),edges,globals:{...DEFAULT_GLOBALS,...globals}});
|
|
|
|
export const PRESETS = {
|
|
native:preset('原生全双工','输入与输出在同一模型内持续运行;另设独立的打断控制路径。',[
|
|
n('in','input','用户停止说话'),n('voice','speech','原生语音对话',{mode:'reference',profileId:'persona',size:7,customRtf:.45}),n('play','output','主回复播放'),n('cancel','program','打断检测与取消',{durationMs:80,target:false})
|
|
],[e('in','voice','first'),e('voice','play','first'),e('in','cancel','first',{networkMs:0,control:true})],{vadMs:0}),
|
|
cascade:preset('流式级联','边听边识别;文本积累8个token后启动TTS,输入与输出可重叠。',[
|
|
n('in','input','用户停止说话'),n('asr','asr','流式语音识别'),n('llm','llm','对话模型 · 8B'),n('tts','tts','流式TTS · 0.6B'),n('play','output','主回复播放'),n('cancel','program','并行打断控制',{durationMs:80,target:false})
|
|
],[e('in','asr','first'),e('asr','llm','complete'),e('llm','tts','chunk'),e('tts','play','first'),e('in','cancel','first',{networkMs:0,control:true})]),
|
|
parallel:preset('并行检索与汇总','检索和工具分支并行,汇总模型等到全部分支完成后组织回复。',[
|
|
n('in','input','用户停止说话'),n('asr','asr','流式语音识别'),n('plan','llm','意图与任务规划',{size:3,outputTokens:32}),n('search','program','知识检索',{durationMs:180}),n('tool','program','业务工具',{durationMs:350}),n('merge','llm','汇总模型 · 14B',{size:14,outputTokens:160}),n('tts','tts','流式TTS'),n('play','output','主回复播放')
|
|
],[e('in','asr','first'),e('asr','plan'),e('plan','search'),e('plan','tool'),e('search','merge'),e('tool','merge'),e('merge','tts','chunk'),e('tts','play','first')]),
|
|
agent:preset('Agent 多步循环','模型最多运行4步,每步输出96个token,步骤之间预留250ms工具等待。',[
|
|
n('in','input','用户停止说话'),n('asr','asr','流式语音识别'),n('agent','llm','工具Agent · 14B',{size:14,maxSteps:4,expectedSteps:2,outputTokens:96,reasoningTokens:64,contextGrowth:384,toolMs:250,finalOnly:true}),n('tts','tts','流式TTS'),n('play','output','最终结果播放')
|
|
],[e('in','asr','first'),e('asr','agent'),e('agent','tts','chunk'),e('tts','play','first')]),
|
|
blank:preset('空白流程','从左侧添加节点,也可用下方的连线表单连接。',[],[]),
|
|
};
|
|
|
|
export function makeDocument(key='cascade') { return structuredClone(PRESETS[key]); }
|
|
export function toDocument(nodes,edges,globals,name='自定义对话流程') {
|
|
return {version:1,name,createdAt:new Date().toISOString(),nodes:nodes.map(({id,type,position,data})=>({id,type,position,data})),edges:edges.map(({id,source,target,type,data})=>({id,source,target,type,data})),globals};
|
|
}
|