Update project and configurations
This commit is contained in:
642
docs/architecture_overview.html
Normal file
642
docs/architecture_overview.html
Normal file
@@ -0,0 +1,642 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>工业 AI 交互画布:流程总览</title>
|
||||
<style>
|
||||
:root {
|
||||
--bg: #f0f2f5;
|
||||
--card: #fff;
|
||||
--ink: #111827;
|
||||
--muted: #667085;
|
||||
--line: #d8dde6;
|
||||
--soft: #f1f4f8;
|
||||
--blue: #2563eb;
|
||||
--green: #059669;
|
||||
--amber: #d97706;
|
||||
--violet: #7c3aed;
|
||||
--dark: #111827;
|
||||
}
|
||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
body { background: var(--bg); color: var(--ink); font-family: "PingFang SC", "Microsoft YaHei", Arial, sans-serif; font-size: 14px; }
|
||||
button { font: inherit; cursor: pointer; border: none; }
|
||||
|
||||
.page { max-width: 1500px; margin: 0 auto; padding: 24px 24px 60px; }
|
||||
|
||||
/* Hero */
|
||||
.hero { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; margin-bottom: 18px; flex-wrap: wrap; }
|
||||
h1 { font-size: 22px; font-weight: 800; }
|
||||
.subtitle { color: var(--muted); font-size: 13px; margin-top: 5px; line-height: 1.6; }
|
||||
|
||||
/* Layout */
|
||||
.main-grid { display: grid; grid-template-columns: 252px minmax(0, 1fr); gap: 16px; align-items: start; }
|
||||
|
||||
/* Left panel */
|
||||
.l-panel { background: var(--card); border: 1px solid var(--line); border-radius: 12px; padding: 18px; }
|
||||
.panel-title { font-size: 14px; font-weight: 700; margin-bottom: 12px; color: var(--ink); }
|
||||
.stack { display: grid; gap: 8px; }
|
||||
.layer { display: grid; grid-template-columns: 30px 1fr; gap: 10px; align-items: center; border: 1px solid var(--line); border-left: 4px solid var(--dark); border-radius: 7px; padding: 9px 12px; }
|
||||
.layer[data-c="blue"] { border-left-color: #2563eb; }
|
||||
.layer[data-c="cyan"] { border-left-color: #0891b2; }
|
||||
.layer[data-c="violet"] { border-left-color: #7c3aed; }
|
||||
.layer[data-c="green"] { border-left-color: #059669; }
|
||||
.layer[data-c="amber"] { border-left-color: #d97706; }
|
||||
.layer[data-c="dark"] { border-left-color: #111827; }
|
||||
.ln { display: flex; height: 24px; width: 24px; align-items: center; justify-content: center; border-radius: 50%; background: var(--soft); font-weight: 800; font-size: 12px; color: #334155; }
|
||||
.lname { font-size: 12px; font-weight: 700; }
|
||||
.ldesc { font-size: 11px; color: var(--muted); margin-top: 2px; line-height: 1.3; }
|
||||
|
||||
/* Right: flow panel */
|
||||
.r-panel { background: var(--card); border: 1px solid var(--line); border-radius: 12px; overflow: hidden; }
|
||||
|
||||
/* Controls bar */
|
||||
.controls { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 14px 20px; border-bottom: 1px solid var(--line); background: #fafbfc; flex-wrap: wrap; }
|
||||
.tg { display: inline-flex; gap: 3px; padding: 3px; border: 1px solid var(--line); border-radius: 9px; background: var(--card); }
|
||||
.tbtn { background: transparent; color: #475467; padding: 8px 14px; border-radius: 6px; font-size: 13px; font-weight: 600; transition: all .15s; white-space: nowrap; }
|
||||
.tbtn.active-flow { background: var(--dark); color: #fff; }
|
||||
.tbtn.active-ux { background: #4f46e5; color: #fff; }
|
||||
.tbtn.active-tech { background: #0d9488; color: #fff; }
|
||||
|
||||
/* View indicator bar */
|
||||
.view-bar { height: 4px; width: 100%; }
|
||||
.view-bar.ux { background: linear-gradient(90deg, #818cf8, #a78bfa); }
|
||||
.view-bar.tech { background: linear-gradient(90deg, #0d9488, #059669); }
|
||||
|
||||
/* Flow body */
|
||||
.flow-body { padding: 22px 26px 30px; overflow-x: auto; }
|
||||
.flow-meta { margin-bottom: 18px; }
|
||||
.flow-meta h2 { font-size: 17px; font-weight: 800; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
|
||||
.flow-meta p { font-size: 13px; color: var(--muted); margin-top: 6px; line-height: 1.6; }
|
||||
.badge { display: inline-flex; align-items: center; font-size: 11px; font-weight: 600; padding: 2px 10px; border-radius: 20px; }
|
||||
.badge-a { background: #dbeafe; color: #1d4ed8; }
|
||||
.badge-b { background: #d1fae5; color: #065f46; }
|
||||
.badge-ux { background: #ede9fe; color: #4c1d95; }
|
||||
.badge-tech { background: #ccfbf1; color: #134e4a; }
|
||||
.badge-plan { background: #fef3c7; color: #92400e; border: 1px solid #fcd34d; }
|
||||
.plan-banner { margin: 0 0 16px; padding: 10px 16px; background: #fffbeb; border: 1px solid #fcd34d; border-radius: 8px; font-size: 12px; color: #78350f; line-height: 1.6; }
|
||||
|
||||
/* Legend */
|
||||
.legend { display: flex; gap: 10px; flex-wrap: wrap; padding: 9px 14px; background: var(--soft); border-radius: 8px; margin-bottom: 18px; }
|
||||
.lg { display: flex; align-items: center; gap: 5px; font-size: 11px; color: #475467; }
|
||||
.lg-dot { width: 10px; height: 10px; border-radius: 2px; flex-shrink: 0; }
|
||||
|
||||
/* ═══ FLOWCHART BASE ═══ */
|
||||
.fc { display: flex; flex-direction: column; align-items: center; min-width: 580px; }
|
||||
|
||||
/* Nodes */
|
||||
.nd { border-radius: 8px; padding: 9px 16px; text-align: center; border: 1.5px solid var(--line); background: #fff; }
|
||||
.nd .nt { font-size: 13px; font-weight: 700; line-height: 1.4; }
|
||||
.nd .ns { font-size: 11px; color: var(--muted); margin-top: 3px; line-height: 1.35; }
|
||||
|
||||
/* Node type variants */
|
||||
.nd-start { background: var(--dark); border: none; border-radius: 22px; min-width: 180px; }
|
||||
.nd-start .nt { color: #fff; font-size: 14px; }
|
||||
.nd-start .ns { color: rgba(255,255,255,0.6); }
|
||||
|
||||
/* UX node types */
|
||||
.nd-show { background: #f5f3ff; border-color: #a78bfa; } /* 画面显示 */
|
||||
.nd-show .nt { color: #4c1d95; }
|
||||
.nd-do { background: #ecfdf5; border-color: #34d399; } /* 用户操作 */
|
||||
.nd-do .nt { color: #065f46; }
|
||||
.nd-end { background: #f0fdf4; border-color: #86efac; } /* 结果/结束 */
|
||||
.nd-end .nt { color: #14532d; }
|
||||
.nd-trig { background: #fff7ed; border-color: #fdba74; } /* 触发条件/场景 */
|
||||
.nd-trig .nt { color: #9a3412; }
|
||||
.nd-tab { background: #f0f9ff; border-color: #7dd3fc; border-style: dashed; }
|
||||
.nd-tab .nt { color: #0c4a6e; }
|
||||
|
||||
/* Tech node types */
|
||||
.nd-route { background: #fffbeb; border-color: #fbbf24; }
|
||||
.nd-route .nt { color: #78350f; }
|
||||
.nd-bert { background: #f5f3ff; border-color: #c4b5fd; }
|
||||
.nd-bert .nt { color: #5b21b6; }
|
||||
.nd-llm { background: #fff7ed; border-color: #fdba74; }
|
||||
.nd-llm .nt { color: #9a3412; }
|
||||
.nd-tool { background: #dbeafe; border-color: #60a5fa; }
|
||||
.nd-tool .nt { color: #1e3a8a; }
|
||||
.nd-kb { background: #ecfdf5; border-color: #6ee7b7; }
|
||||
.nd-kb .nt { color: #064e3b; }
|
||||
.nd-art { background: #faf5ff; border-color: #c4b5fd; border-style: dashed; }
|
||||
.nd-art .nt { color: #5b21b6; }
|
||||
.nd-snap { background: #f0fdf4; border-color: #86efac; border-style: dashed; }
|
||||
.nd-snap .nt { color: #14532d; }
|
||||
.nd-minor { background: var(--soft); border-color: var(--line); }
|
||||
.nd-minor .nt { color: #475467; }
|
||||
|
||||
/* Tags inside nodes */
|
||||
.tag { display: inline-block; font-size: 9px; font-weight: 700; padding: 2px 6px; border-radius: 3px; margin: 3px 2px 0; }
|
||||
.t-bert { background: #ede9fe; color: #5b21b6; }
|
||||
.t-llm { background: #fff7ed; color: #9a3412; }
|
||||
.t-rule { background: #dcfce7; color: #166534; }
|
||||
.t-tool { background: #dbeafe; color: #1e40af; }
|
||||
.t-art { background: #faf5ff; color: #5b21b6; }
|
||||
|
||||
/* Connectors */
|
||||
.dn { width: 2px; background: #c9d0db; height: 20px; flex-shrink: 0; }
|
||||
.dn.tall { height: 30px; }
|
||||
.arr { width: 0; height: 0; border-left: 5px solid transparent; border-right: 5px solid transparent; border-top: 7px solid #b0b9c8; flex-shrink: 0; }
|
||||
|
||||
/* Branch spread link */
|
||||
.slink { position: relative; width: 100%; height: 24px; flex-shrink: 0; }
|
||||
|
||||
/* Branch columns */
|
||||
.brow { display: flex; width: 100%; align-items: flex-start; }
|
||||
.bcol { display: flex; flex-direction: column; align-items: center; flex: 1; padding: 0 7px; min-width: 0; }
|
||||
|
||||
/* Branch labels */
|
||||
.blbl { padding: 4px 11px; border-radius: 20px; font-size: 11px; font-weight: 700; white-space: nowrap; }
|
||||
.bl-b { background: #dbeafe; color: #1d4ed8; border: 1px solid #93c5fd; }
|
||||
.bl-g { background: #d1fae5; color: #065f46; border: 1px solid #6ee7b7; }
|
||||
.bl-a { background: #fef3c7; color: #92400e; border: 1px solid #fcd34d; }
|
||||
.bl-v { background: #ede9fe; color: #4c1d95; border: 1px solid #a78bfa; }
|
||||
.bl-gr { background: var(--soft); color: #475467; border: 1px solid var(--line); }
|
||||
.bl-hit { background: #d1fae5; color: #065f46; border: 1px solid #6ee7b7; }
|
||||
.bl-miss { background: #fef3c7; color: #92400e; border: 1px solid #fcd34d; }
|
||||
|
||||
/* Notes */
|
||||
.fnote { font-size: 11px; color: #64748b; margin-top: 4px; text-align: center; line-height: 1.4; }
|
||||
.fopt { font-size: 11px; color: #6d28d9; margin-top: 4px; text-align: center; font-style: italic; }
|
||||
.fwarn { font-size: 11px; color: #b91c1c; margin-top: 4px; text-align: center; }
|
||||
|
||||
/* Divider */
|
||||
.fc-sep { width: 100%; border: none; border-top: 1px dashed var(--line); margin: 4px 0; }
|
||||
|
||||
@media (max-width: 1080px) { .main-grid { grid-template-columns: 1fr; } }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main class="page">
|
||||
<header class="hero">
|
||||
<div>
|
||||
<h1>工业 AI 交互画布 · 操作流程与技术链路</h1>
|
||||
<p class="subtitle">选择视角,分别查看"用户界面交互路径"或"背后技术判断逻辑"。语音输入经过四阶段前置拦截后再进入 BERT NLU。</p>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<section class="main-grid">
|
||||
<!-- Left: Architecture Layers -->
|
||||
<aside class="l-panel">
|
||||
<div class="panel-title">主链路层级</div>
|
||||
<div class="stack">
|
||||
<div class="layer" data-c="blue">
|
||||
<div class="ln">1</div>
|
||||
<div><div class="lname">输入层</div><div class="ldesc">文字 / 语音(ASR) / 点击</div></div>
|
||||
</div>
|
||||
<div class="layer" data-c="cyan">
|
||||
<div class="ln">2</div>
|
||||
<div><div class="lname">前置拦截层</div><div class="ldesc">停止词 → UI语音点击 → Slot填写 → BERT</div></div>
|
||||
</div>
|
||||
<div class="layer" data-c="violet">
|
||||
<div class="ln">3</div>
|
||||
<div><div class="lname">路由层</div><div class="ldesc">decision: execute / clarify / route_to_cloud</div></div>
|
||||
</div>
|
||||
<div class="layer" data-c="green">
|
||||
<div class="ln">4</div>
|
||||
<div><div class="lname">编排层</div><div class="ldesc">工具选择 / 知识检索 / Artifact 生成</div></div>
|
||||
</div>
|
||||
<div class="layer" data-c="amber">
|
||||
<div class="ln">5</div>
|
||||
<div><div class="lname">执行层</div><div class="ldesc">PLC / HMI / 知识库调用</div></div>
|
||||
</div>
|
||||
<div class="layer" data-c="dark">
|
||||
<div class="ln">6</div>
|
||||
<div><div class="lname">画布层</div><div class="ldesc">渲染 Artifact + 状态快照</div></div>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<!-- Right: Flow Panel -->
|
||||
<section class="r-panel">
|
||||
<div class="controls">
|
||||
<div class="tg" id="flowTabs">
|
||||
<button class="tbtn active-flow" data-flow="A">大流程 A · 工控对话</button>
|
||||
<button class="tbtn" data-flow="B">大流程 B · 调机流程 <span style="font-size:10px;opacity:.7;">🚧 下一版本</span></button>
|
||||
</div>
|
||||
<div class="tg" id="viewTabs">
|
||||
<button class="tbtn active-ux" data-view="ux">👁 交互流程</button>
|
||||
<button class="tbtn" data-view="tech">⚙️ 技术流程</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="view-bar ux" id="viewBar"></div>
|
||||
<div class="flow-body" id="flowBody"></div>
|
||||
</section>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<script>
|
||||
// ─── State ──────────────────────────────────────────────────────────────
|
||||
const S = { flow: 'A', view: 'ux' };
|
||||
|
||||
// ─── Helpers ──────────────────────────────────────────────────────────────
|
||||
const dn = (h = 20) => `<div class="dn" style="height:${h}px"></div>`;
|
||||
const arr = () => `<div class="arr"></div>`;
|
||||
const da = (h = 20) => dn(h) + arr();
|
||||
|
||||
function nd(cls, title, sub = '', tags = []) {
|
||||
const ts = tags.map(t => `<span class="tag t-${t}">${t.toUpperCase()}</span>`).join('');
|
||||
return `<div class="nd ${cls}"><div class="nt">${title}</div>${sub ? `<div class="ns">${sub}</div>` : ''}${ts ? `<div>${ts}</div>` : ''}</div>`;
|
||||
}
|
||||
|
||||
function blbl(text, cls) {
|
||||
return `<div class="blbl ${cls}">${text}</div>`;
|
||||
}
|
||||
|
||||
// Horizontal branch spread link: n = 2 or 3
|
||||
function slink(n) {
|
||||
if (n === 3) {
|
||||
return `<div class="slink">
|
||||
<div style="position:absolute;top:0;left:16.67%;right:16.67%;height:2px;background:#c9d0db;"></div>
|
||||
<div style="position:absolute;top:0;left:calc(16.67% - 1px);width:2px;height:24px;background:#c9d0db;"></div>
|
||||
<div style="position:absolute;top:0;left:calc(50% - 1px);width:2px;height:24px;background:#c9d0db;"></div>
|
||||
<div style="position:absolute;top:0;right:calc(16.67% - 1px);width:2px;height:24px;background:#c9d0db;"></div>
|
||||
</div>`;
|
||||
}
|
||||
return `<div class="slink">
|
||||
<div style="position:absolute;top:0;left:25%;right:25%;height:2px;background:#c9d0db;"></div>
|
||||
<div style="position:absolute;top:0;left:calc(25% - 1px);width:2px;height:24px;background:#c9d0db;"></div>
|
||||
<div style="position:absolute;top:0;right:calc(25% - 1px);width:2px;height:24px;background:#c9d0db;"></div>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
// ─── Legends ─────────────────────────────────────────────────────────────
|
||||
const legendUX = `<div class="legend">
|
||||
<div class="lg"><div class="lg-dot" style="background:#f5f3ff;border:1px solid #a78bfa;"></div> 界面展示内容</div>
|
||||
<div class="lg"><div class="lg-dot" style="background:#ecfdf5;border:1px solid #34d399;"></div> 用户可做的操作</div>
|
||||
<div class="lg"><div class="lg-dot" style="background:#f0fdf4;border:1px solid #86efac;"></div> 最终结果/结束态</div>
|
||||
<div class="lg"><div class="lg-dot" style="background:#f0f9ff;border:1px solid #7dd3fc;border-style:dashed;"></div> Tab 分页展示(不覆盖主卡)</div>
|
||||
</div>`;
|
||||
|
||||
const legendTech = `<div class="legend">
|
||||
<div class="lg"><div class="lg-dot" style="background:#fffbeb;border:1px solid #fbbf24;"></div> 路由判断节点</div>
|
||||
<div class="lg"><div class="lg-dot" style="background:#f5f3ff;border:1px solid #c4b5fd;"></div> BERT / NLU</div>
|
||||
<div class="lg"><div class="lg-dot" style="background:#fff7ed;border:1px solid #fdba74;"></div> LLM 推断</div>
|
||||
<div class="lg"><div class="lg-dot" style="background:#dbeafe;border:1px solid #60a5fa;"></div> 工具调用</div>
|
||||
<div class="lg"><div class="lg-dot" style="background:#ecfdf5;border:1px solid #6ee7b7;"></div> 知识库检索</div>
|
||||
<div class="lg"><div class="lg-dot" style="background:#faf5ff;border:1px solid #c4b5fd;border-style:dashed;"></div> Artifact 生成</div>
|
||||
</div>`;
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
// FLOW A · UX VIEW
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
function renderA_UX() {
|
||||
return `
|
||||
<div class="flow-meta">
|
||||
<h2>大流程 A · 普通对话 <span class="badge badge-a">无调机流程</span> <span class="badge badge-ux">👁 交互流程</span></h2>
|
||||
<p>操作员从零开始发起一次输入。界面根据输入内容呈现三种不同的画布组件,操作员按提示进行确认或查阅。</p>
|
||||
</div>
|
||||
${legendUX}
|
||||
<div class="fc">
|
||||
|
||||
${nd('nd-start', '👤 操作员输入文字或语音', '当前画布无激活流程')}
|
||||
${da()}
|
||||
|
||||
${nd('nd-trig', '系统识别输入类型,分三种场景响应', '用户感知到的是画布出现了不同内容')}
|
||||
${slink(3)}
|
||||
|
||||
<div class="brow">
|
||||
|
||||
<!-- Branch 1 -->
|
||||
<div class="bcol">
|
||||
${blbl('场景 1 · 操控设备', 'bl-b')}
|
||||
${da()}
|
||||
${nd('nd-show', '画布出现操控确认卡', '参数变更卡 或 设备动画卡')}
|
||||
${da()}
|
||||
${nd('nd-do', '操作员选择:确认或取消', '点击按钮 或 输入"确认/取消"')}
|
||||
${da()}
|
||||
${nd('nd-end', '画布显示执行结果', '成功 / 失败 / 重试')}
|
||||
</div>
|
||||
|
||||
<!-- Branch 2 -->
|
||||
<div class="bcol">
|
||||
${blbl('场景 2 · 询问设备问题', 'bl-g')}
|
||||
${da()}
|
||||
${nd('nd-show', '画布出现知识教学卡', 'SOP / 报警处理 / 说明书内容')}
|
||||
${da()}
|
||||
${nd('nd-do', '操作员查阅内容', '可展开详情、查看步骤')}
|
||||
${da()}
|
||||
${nd('nd-end', '内容展示完毕')}
|
||||
</div>
|
||||
|
||||
<!-- Branch 3 -->
|
||||
<div class="bcol">
|
||||
${blbl('场景 3 · 通用 / 无关', 'bl-gr')}
|
||||
${da()}
|
||||
${nd('nd-show', '对话框返回文字回答', '打招呼、天气、闲聊等内容')}
|
||||
${da()}
|
||||
${nd('nd-end', '回答完毕', '不影响工业主流程')}
|
||||
<div class="fwarn">⚠ 非核心场景</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
// FLOW A · TECH VIEW
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
function renderA_Tech() {
|
||||
return `
|
||||
<div class="flow-meta">
|
||||
<h2>大流程 A · 普通对话 <span class="badge badge-a">工控对话</span> <span class="badge badge-tech">⚙️ 技术流程</span></h2>
|
||||
<p>语音输入经过四阶段前置拦截(停止词→UI语音点击→Slot填写→BERT),只有前三阶段全部未命中的输入才进入 BERT NLU,再由 decision 字段驱动工具调用、知识检索或 LLM 作答。</p>
|
||||
</div>
|
||||
${legendTech}
|
||||
<div class="fc">
|
||||
|
||||
${nd('nd-start', '语音 / 文字输入', '来自 ASR 转录文本 / 直接文字')}
|
||||
${da()}
|
||||
|
||||
${nd('nd-route', '阶段 0 · 停止词检测', '命中 cancel 词表 → 直接生成 stop_action,流程终止', ['rule'])}
|
||||
<div class="fnote">词表来自 voice_aliases.yml · cancel_words(静态构建)</div>
|
||||
${da()}
|
||||
|
||||
${nd('nd-route', '阶段 1 · UI 可见元素语音点击匹配', '优先级:waiting_confirmation affirm/deny > 当前Artifact按钮 > 全局固定操作', ['rule'])}
|
||||
${slink(2)}
|
||||
|
||||
<div class="brow">
|
||||
<div class="bcol">
|
||||
${blbl('命中 · 语音点击', 'bl-hit')}
|
||||
${da()}
|
||||
${nd('nd-tool', '生成 ActionEvent', 'actionId / artifactId / sourceText', ['rule'])}
|
||||
${da()}
|
||||
${nd('nd-snap', '画布状态机直接响应', '不调用 BERT,不产生新 Artifact')}
|
||||
</div>
|
||||
<div class="bcol">
|
||||
${blbl('未命中 · 继续', 'bl-miss')}
|
||||
${da()}
|
||||
${nd('nd-route', '阶段 1.5 · waiting_slot + inform 检测', 'session.status=waiting_slot AND 输入为数字/数值', ['rule'])}
|
||||
${slink(2)}
|
||||
<div class="brow" style="width:100%;">
|
||||
<div class="bcol">
|
||||
${blbl('命中 · 填槽', 'bl-hit')}
|
||||
${da()}
|
||||
${nd('nd-tool', 'fill_slots 接口', '直接补全当前 slot,不走 BERT', ['rule'])}
|
||||
</div>
|
||||
<div class="bcol">
|
||||
${blbl('未命中 · 进入 BERT', 'bl-miss')}
|
||||
${da()}
|
||||
${nd('nd-bert', '阶段 2 · BERT NLU(intelligent_cabin)', 'POST /api/v1/agent/chat\n返回 intent_id + decision + slots', ['bert'])}
|
||||
<div class="fnote">inference 报错直接抛出,不降级</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
${da(30)}
|
||||
${nd('nd-route', 'decision 字段路由', 'execute / clarify / route_to_cloud / reject', ['rule'])}
|
||||
${slink(3)}
|
||||
|
||||
<div class="brow">
|
||||
|
||||
<!-- Branch 1 -->
|
||||
<div class="bcol">
|
||||
${blbl('execute · 设备控制域', 'bl-b')}
|
||||
${da()}
|
||||
${nd('nd-route', 'domain = machine_control\nconfidence_grade = high\nintent_id = wirecut_*')}
|
||||
${da()}
|
||||
${nd('nd-tool', '工业工具调用', 'DBus 写参 / 设备控制指令', ['tool'])}
|
||||
${da()}
|
||||
${nd('nd-art', '生成 Artifact', 'ParameterChangeArtifact\nDeviceActionArtifact', ['art'])}
|
||||
${da()}
|
||||
${nd('nd-snap', '画布渲染 + 等待 ActionEvent')}
|
||||
</div>
|
||||
|
||||
<!-- Branch 2 -->
|
||||
<div class="bcol">
|
||||
${blbl('route_to_cloud · 知识域', 'bl-g')}
|
||||
${da()}
|
||||
${nd('nd-route', 'domain = equipment_knowledge\n或 confidence 偏低')}
|
||||
${da()}
|
||||
${nd('nd-llm', 'LLM 语义兜底分析', '提取检索关键词', ['llm'])}
|
||||
${da()}
|
||||
${nd('nd-kb', '知识库检索', '说明书 / SOP / 报警手册', ['tool'])}
|
||||
${da()}
|
||||
${nd('nd-llm', 'LLM 组织检索结果', '生成教学结构', ['llm'])}
|
||||
${da()}
|
||||
${nd('nd-art', '生成 KnowledgeLessonArtifact', '', ['art'])}
|
||||
${da()}
|
||||
${nd('nd-snap', '画布渲染')}
|
||||
</div>
|
||||
|
||||
<!-- Branch 3 -->
|
||||
<div class="bcol">
|
||||
${blbl('reject · smalltalk / fallback', 'bl-gr')}
|
||||
${da()}
|
||||
${nd('nd-route', 'domain = smalltalk\n或无法匹配工业 domain')}
|
||||
${da()}
|
||||
${nd('nd-llm', 'LLM 直接作答', '', ['llm'])}
|
||||
${da()}
|
||||
${nd('nd-minor', '文字回复,不生成 Artifact')}
|
||||
<div class="fnote">不写入 ArtifactStore</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
// FLOW B · UX VIEW (🚧 下一版本计划中,暂未实现)
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
function renderB_UX() {
|
||||
return `
|
||||
<div class="flow-meta">
|
||||
<h2>大流程 B · 调机流程中 <span class="badge badge-b">Guided Procedure 激活</span> <span class="badge badge-ux">👁 交互流程</span> <span class="badge badge-plan">🚧 下一版本 · 计划中</span></h2>
|
||||
<p>操作员确认进入调机向导后,调机流程卡占据画布主位。后续输入优先驱动当前步骤,其他内容以 Tab 或浮层展示,调机卡不被覆盖。</p>
|
||||
</div>
|
||||
<div class="plan-banner">⚠️ 此流程为下一版本设计规划,当前版本暂未实现。此图仅用于交互设计参考。</div>
|
||||
${legendUX}
|
||||
<div class="fc">
|
||||
|
||||
${nd('nd-show', '调机向导卡在画布主位展示', '步骤列表 · 当前步骤高亮 · 步骤指令可见')}
|
||||
${da()}
|
||||
|
||||
${nd('nd-trig', '操作员输入或点击', '文字 / 语音 / 直接点击步骤按钮')}
|
||||
${slink(2)}
|
||||
|
||||
<div class="brow">
|
||||
|
||||
<!-- HIT -->
|
||||
<div class="bcol">
|
||||
${blbl('✅ 场景 1 · 操作当前步骤', 'bl-hit')}
|
||||
${da()}
|
||||
${nd('nd-do', '输入"已完成/下一步/确认"或直接点击', '等同于用语音/文字替代手点击')}
|
||||
${da()}
|
||||
${nd('nd-show', '当前步骤标记完成,流程卡更新', '进入下一步 · 调机卡不离开主位')}
|
||||
${da()}
|
||||
${nd('nd-end', '所有步骤完成,调机流程收尾', '显示操作汇总')}
|
||||
</div>
|
||||
|
||||
<!-- NOT HIT -->
|
||||
<div class="bcol">
|
||||
${blbl('🔀 场景 2 · 其他内容输入', 'bl-miss')}
|
||||
${da()}
|
||||
${nd('nd-trig', '输入与当前步骤无关', '系统识别为新的操控/知识/通用内容')}
|
||||
${slink(3)}
|
||||
|
||||
<div class="brow" style="width:100%;">
|
||||
|
||||
<div class="bcol">
|
||||
${blbl('操控工具', 'bl-b')}
|
||||
${da()}
|
||||
${nd('nd-tab', 'Tab 出现工具执行结果', '调机 | 工具结果', [])}
|
||||
${da()}
|
||||
${nd('nd-do', '操作员查看后可确认')}
|
||||
<div class="fnote">调机卡保持主位</div>
|
||||
</div>
|
||||
|
||||
<div class="bcol">
|
||||
${blbl('知识查询', 'bl-g')}
|
||||
${da()}
|
||||
${nd('nd-tab', 'Tab 出现知识卡', '调机 | 知识参考', [])}
|
||||
${da()}
|
||||
${nd('nd-do', '操作员查阅后继续流程')}
|
||||
<div class="fnote">调机卡保持主位</div>
|
||||
</div>
|
||||
|
||||
<div class="bcol">
|
||||
${blbl('通用提问', 'bl-gr')}
|
||||
${da()}
|
||||
${nd('nd-show', '临时浮层文字回答', '不占画布主位')}
|
||||
${da()}
|
||||
${nd('nd-end', '回答完毕自动收起')}
|
||||
<div class="fnote">调机卡保持主位</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
// FLOW B · TECH VIEW (🚧 下一版本计划中,暂未实现)
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
function renderB_Tech() {
|
||||
return `
|
||||
<div class="flow-meta">
|
||||
<h2>大流程 B · 调机流程中 <span class="badge badge-b">Guided Procedure 激活</span> <span class="badge badge-tech">⚙️ 技术流程</span> <span class="badge badge-plan">🚧 下一版本 · 计划中</span></h2>
|
||||
<p>GuidedProcedure Artifact 激活后,输入路由优先做 textAliases 规则匹配(类汽车语音点击),命中则直接更新状态机;未命中再走 BERT 新意图识别,结果以 Tab 渲染,不修改主 Artifact 实例。</p>
|
||||
</div>
|
||||
<div class="plan-banner">⚠️ 此流程为下一版本设计规划,当前版本暂未实现。此图仅用于技术设计参考。</div>
|
||||
${legendTech}
|
||||
<div class="fc">
|
||||
|
||||
${nd('nd-art', 'GuidedProcedure Artifact 激活', 'currentStepId · steps[] · actions[textAliases]')}
|
||||
${da()}
|
||||
|
||||
${nd('nd-start', '文本输入', '来自文字 / ASR / 点击')}
|
||||
${da()}
|
||||
|
||||
${nd('nd-route', '路由层:优先匹配当前步骤 textAliases', '规则匹配为主,BERT 置信度辅助确认', ['rule', 'bert'])}
|
||||
${slink(2)}
|
||||
|
||||
<div class="brow">
|
||||
|
||||
<!-- HIT -->
|
||||
<div class="bcol">
|
||||
${blbl('命中 · textAliases 匹配成功', 'bl-hit')}
|
||||
${da()}
|
||||
${nd('nd-route', '生成 ArtifactActionEvent', 'actionId / source="text" / transcript', ['rule'])}
|
||||
${da()}
|
||||
${nd('nd-tool', '执行步骤对应工具动作', '写入测量値 / 推进步骤状态')}
|
||||
${da()}
|
||||
${nd('nd-bert', 'Reducer 更新 Artifact 状态', 'currentStepId → nextStepId\nstep.status → "completed"')}
|
||||
${da()}
|
||||
${nd('nd-snap', '快照保存(snapshotPolicy: persistent)', '步骤记录存档,支持复盘')}
|
||||
</div>
|
||||
|
||||
<!-- NOT HIT -->
|
||||
<div class="bcol">
|
||||
${blbl('未命中 · 进入新意图识别', 'bl-miss')}
|
||||
${da()}
|
||||
${nd('nd-bert', 'BERT NLU 识别新意图', '在当前调机上下文中重新分类 domain/intent', ['bert'])}
|
||||
${slink(3)}
|
||||
|
||||
<div class="brow" style="width:100%;">
|
||||
|
||||
<div class="bcol">
|
||||
${blbl('tool_call', 'bl-b')}
|
||||
${da()}
|
||||
${nd('nd-tool', '工具执行', '不修改主 Artifact', ['tool'])}
|
||||
${da()}
|
||||
${nd('nd-art', 'Tab 渲染结果', '主 Artifact 不受影响', ['art'])}
|
||||
<div class="fnote">ArtifactStore 主实例不变</div>
|
||||
</div>
|
||||
|
||||
<div class="bcol">
|
||||
${blbl('knowledge_query', 'bl-g')}
|
||||
${da()}
|
||||
${nd('nd-kb', '知识库检索\n+ LLM 组织', '', ['llm'])}
|
||||
${da()}
|
||||
${nd('nd-art', 'Tab 渲染知识卡', '主 Artifact 不受影响', ['art'])}
|
||||
<div class="fnote">ArtifactStore 主实例不变</div>
|
||||
</div>
|
||||
|
||||
<div class="bcol">
|
||||
${blbl('smalltalk', 'bl-gr')}
|
||||
${da()}
|
||||
${nd('nd-llm', 'LLM 直接作答', '', ['llm'])}
|
||||
${da()}
|
||||
${nd('nd-minor', '临时浮层,不写入\nArtifactStore')}
|
||||
<div class="fnote">主 Artifact 完全不受影响</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
// ─── Render Dispatch ──────────────────────────────────────────────────────
|
||||
const renderers = {
|
||||
A: { ux: renderA_UX, tech: renderA_Tech },
|
||||
B: { ux: renderB_UX, tech: renderB_Tech },
|
||||
};
|
||||
|
||||
function render() {
|
||||
const { flow, view } = S;
|
||||
|
||||
// Flow tabs
|
||||
document.querySelectorAll('#flowTabs .tbtn').forEach(b => {
|
||||
b.classList.toggle('active-flow', b.dataset.flow === flow);
|
||||
});
|
||||
|
||||
// View tabs
|
||||
document.querySelectorAll('#viewTabs .tbtn').forEach(b => {
|
||||
b.classList.remove('active-ux', 'active-tech');
|
||||
if (b.dataset.view === view) {
|
||||
b.classList.add(view === 'ux' ? 'active-ux' : 'active-tech');
|
||||
}
|
||||
});
|
||||
|
||||
// Color bar
|
||||
const bar = document.getElementById('viewBar');
|
||||
bar.className = `view-bar ${view}`;
|
||||
|
||||
// Content
|
||||
document.getElementById('flowBody').innerHTML = renderers[flow][view]();
|
||||
}
|
||||
|
||||
// ─── Events ───────────────────────────────────────────────────────────────
|
||||
document.getElementById('flowTabs').addEventListener('click', e => {
|
||||
const btn = e.target.closest('.tbtn');
|
||||
if (btn && btn.dataset.flow) { S.flow = btn.dataset.flow; render(); }
|
||||
});
|
||||
|
||||
document.getElementById('viewTabs').addEventListener('click', e => {
|
||||
const btn = e.target.closest('.tbtn');
|
||||
if (btn && btn.dataset.view) { S.view = btn.dataset.view; render(); }
|
||||
});
|
||||
|
||||
render();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user