From 821f3c1c4e8584048571874ba2e41cc1f67148cb Mon Sep 17 00:00:00 2001 From: admin Date: Tue, 13 Oct 2026 11:04:32 +0800 Subject: [PATCH] =?UTF-8?q?feat(bioflow):=20=E5=BC=95=E5=AF=BC=E5=B8=A7?= =?UTF-8?q?=E2=80=94=E2=80=94=E5=8D=A1=E7=89=87=E7=8E=AF=E8=8A=82=E8=A1=A5?= =?UTF-8?q?=E8=87=AA=E7=84=B6=E8=AF=AD=E8=A8=80=E5=BC=95=E5=AF=BC=E6=B0=94?= =?UTF-8?q?=E6=B3=A1(=E6=96=87=E4=BB=B6/=E5=8F=82=E6=95=B0/=E5=AD=98?= =?UTF-8?q?=E6=A1=A3/=E8=BF=9B=E5=BA=A6)=20(#006/#007/#008/#010)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bioflow_service/app/services/bioflow/runner.py | 10 ++++++++++ ui/src/stores/chat.js | 17 +++++++++++++++-- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/bioflow_service/app/services/bioflow/runner.py b/bioflow_service/app/services/bioflow/runner.py index 36e7083..ef9c7f4 100644 --- a/bioflow_service/app/services/bioflow/runner.py +++ b/bioflow_service/app/services/bioflow/runner.py @@ -803,6 +803,7 @@ class Runner: "title": record.title, "progress": 100, "elapsed_sec": None, + "guidance": "分析已完成,可以存档复用,或直接查看报告。", }) except asyncio.CancelledError: # 任务级取消:不落脏状态(阶段取消由 _run_stage 单独处理) @@ -865,9 +866,17 @@ class Runner: self._set_stage(record, stage, status=STAGE_WAITING_CONFIRM) await self._persist_stage(record, stage) defaults = self._form_defaults(stage, record) + if defaults: + param_str = "、".join( + f"{p.get('name')}(默认 {p.get('default')})" for p in defaults + ) + guidance = f"阶段 {stage} 需要确认参数:{param_str}。不调整可直接继续。" + else: + guidance = f"阶段 {stage} 需要你确认后继续。" self.events.publish("stage_await_confirm", { "job_id": record.id, "stage": stage, "form_defaults": defaults, + "guidance": guidance, }) return "await" @@ -1041,6 +1050,7 @@ class Runner: "job_id": record.id, "stage": stage, "exit_code": exit_code, "manifest_ref": manifest.path, "metrics": manifest.metrics, + "summary": f"阶段 {stage} 已完成", }) return "done" diff --git a/ui/src/stores/chat.js b/ui/src/stores/chat.js index 6c3397e..b45a132 100644 --- a/ui/src/stores/chat.js +++ b/ui/src/stores/chat.js @@ -502,6 +502,15 @@ export function patchBioflowForm(aMsg, data, { rerun = false } = {}) { } /** 阶段待文件 → 文件引导块(FR-BIO-005) */ +export function patchBioflowGuidance(aMsg, text) { + // 自然语言引导气泡(方案:自然语言主通道,卡片辅助)——弹卡片前先插入一条 text 块。 + if (!text) return null; + const html = renderMarkdown(String(text)); + if ((aMsg.blocks || []).some((b) => b && b.type === 'text' && b.html === html)) return null; + aMsg.blocks.push({ type: 'text', html }); + return true; +} + export function patchBioflowFile(aMsg, data) { const stage = data.stage; if (!stage) return null; @@ -1159,9 +1168,10 @@ export const useChatStore = defineStore('chat', { onEvent: (type, data) => { const frame = patchBioflowEvent(m, { type, data }); if (frame) this.scrollSeq++; - if (type === 'stage_await_confirm' && data) { patchBioflowForm(m, data); this.scrollSeq++; } - else if (type === 'stage_await_files' && data) { patchBioflowFile(m, data); this.scrollSeq++; } + if (type === 'stage_await_confirm' && data) { patchBioflowGuidance(m, data.guidance); patchBioflowForm(m, data); this.scrollSeq++; } + else if (type === 'stage_await_files' && data) { patchBioflowGuidance(m, data.guidance || data.message); patchBioflowFile(m, data); this.scrollSeq++; } else if (type === 'job_done' && data) { + patchBioflowGuidance(m, data.guidance); const ab = patchBioflowArchiveSuggest(m, data.job_id || jobId); if (ab) ab.jobId = data.job_id || jobId; this.scrollSeq++; @@ -2255,12 +2265,15 @@ export const useChatStore = defineStore('chat', { const frame = patchBioflowEvent(aMsg, { type, data }); if (frame) this.scrollSeq++; if (type === 'stage_await_confirm' && data) { + patchBioflowGuidance(aMsg, data.guidance); patchBioflowForm(aMsg, data); this.scrollSeq++; } else if (type === 'stage_await_files' && data) { + patchBioflowGuidance(aMsg, data.guidance || data.message); patchBioflowFile(aMsg, data); this.scrollSeq++; } else if (type === 'job_done' && data) { + patchBioflowGuidance(aMsg, data.guidance); const blk = patchBioflowArchiveSuggest(aMsg, data.job_id || jobId); if (blk) blk.jobId = data.job_id || jobId; bioflow.registerReport({