feat(aia): Protocol Agent MVP complete with one-click generation and Word export
- Add one-click research protocol generation with streaming output - Implement Word document export via Pandoc integration - Add dynamic dual-panel layout with resizable split pane - Implement collapsible content for StatePanel stages - Add conversation history management with title auto-update - Fix scroll behavior, markdown rendering, and UI layout issues - Simplify conversation creation logic for reliability
This commit is contained in:
@@ -1,16 +1,16 @@
|
||||
# AIA AI智能问答模块 - 当前状态与开发指南
|
||||
|
||||
> **文档版本:** v3.0
|
||||
> **文档版本:** v3.1
|
||||
> **创建日期:** 2026-01-14
|
||||
> **维护者:** AIA模块开发团队
|
||||
> **最后更新:** 2026-01-24 🎉 **V3.0版本发布 - Protocol Agent MVP完成**
|
||||
> **最后更新:** 2026-01-25 🎉 **V3.1版本发布 - Protocol Agent MVP完整交付**
|
||||
> **重大里程碑:**
|
||||
> - 🏆 通用流式响应服务(OpenAI Compatible)
|
||||
> - 🎨 现代感UI(100%还原原型图V11)
|
||||
> - 🚀 Ant Design X 深度集成
|
||||
> - ✨ 12个智能体配置完成
|
||||
> - 🆕 Prompt管理系统集成(灰度预览、版本管理)
|
||||
> - 🎉 **Protocol Agent MVP完成(可复用Agent框架+5阶段对话流程)**
|
||||
> - 🎉 **Protocol Agent MVP完整交付(一键生成研究方案+Word导出)**
|
||||
|
||||
---
|
||||
|
||||
@@ -42,9 +42,9 @@ AIA(AI Intelligent Assistant)模块提供覆盖临床研究全生命周期
|
||||
|
||||
### 当前状态
|
||||
|
||||
- **开发阶段:** ✅ **V3.0 Protocol Agent MVP完成**
|
||||
- **架构版本:** V3.0(通用Agent框架 + Protocol Agent)
|
||||
- **完成度:** 75%(MVP核心流程完成,待前后端联调)
|
||||
- **开发阶段:** 🎉 **V3.1 Protocol Agent MVP完整交付**
|
||||
- **架构版本:** V3.1(通用Agent框架 + Protocol Agent + 一键生成)
|
||||
- **完成度:** 90%(MVP完整可用,待生产测试)
|
||||
|
||||
### ✅ V2.1 新增功能(2026-01-18)
|
||||
|
||||
@@ -85,7 +85,40 @@ AIA(AI Intelligent Assistant)模块提供覆盖临床研究全生命周期
|
||||
- [x] 前端:三栏布局,5阶段状态面板,100%还原原型图
|
||||
- [x] 5阶段流程:科学问题→PICO→研究设计→样本量→观察指标
|
||||
|
||||
**待完成:** 前后端联调、一键生成、Word导出
|
||||
---
|
||||
|
||||
### 🎉 V3.1 Protocol Agent 完整交付(2026-01-25)
|
||||
|
||||
**一键生成研究方案:**
|
||||
- [x] 动态双面板布局(ResizableSplitPane,可拖拽调整)
|
||||
- [x] 视图切换(研究摘要 / 完整方案)
|
||||
- [x] A4 纸张预览效果(DocumentPanel)
|
||||
- [x] 流式生成 + Markdown 渲染 + 滚动跟随
|
||||
- [x] 12章节完整临床研究方案结构
|
||||
|
||||
**Word 文档导出:**
|
||||
- [x] Python 微服务(pypandoc + Pandoc)
|
||||
- [x] Node.js API 端点(/export/docx)
|
||||
- [x] 前端一键下载
|
||||
|
||||
**用户体验优化:**
|
||||
- [x] StatePanel 折叠/展开(CollapsibleContent)
|
||||
- [x] 科学问题/PICO/样本量/观察指标完整显示
|
||||
- [x] 延迟创建对话(避免空记录)
|
||||
- [x] 对话标题自动更新
|
||||
- [x] Prompt 工程优化(阶段约束、数据凝练放宽)
|
||||
|
||||
**Bug 修复:**
|
||||
- [x] 滚动条显示问题(flex min-height: 0)
|
||||
- [x] 模型阶段混乱问题(Prompt 增强)
|
||||
- [x] 数据类型错误(toArray 辅助函数)
|
||||
- [x] 顶部标题两行、欢迎语过大、列表编号错误
|
||||
|
||||
**代码统计:**
|
||||
- 前端新增:~1,200行(累计~3,300行)
|
||||
- 后端新增:~400行(累计~4,700行)
|
||||
- Python新增:~110行
|
||||
- **总计:~8,500行**
|
||||
|
||||
---
|
||||
|
||||
|
||||
50
docs/03-业务模块/AIA-AI智能问答/00-系统设计/UI_Layout_Ratio_Analysis.md
Normal file
50
docs/03-业务模块/AIA-AI智能问答/00-系统设计/UI_Layout_Ratio_Analysis.md
Normal file
@@ -0,0 +1,50 @@
|
||||
# **UI 布局深度分析:Chat vs. Document 比例问题**
|
||||
|
||||
**核心冲突:**
|
||||
|
||||
* **Chat**: 主要是控制台,指令短,但历史记录长。
|
||||
* **Document**: 是交付物,内容宽,需要沉浸式阅读。
|
||||
* **Context Panel**: 是辅助信息,卡片式,不需要太宽。
|
||||
|
||||
## **1\. 为什么“固定比例”不是最优解?**
|
||||
|
||||
如果强行统一比例,两头都不讨好:
|
||||
|
||||
* **如果统一为 70% (Chat) : 30% (Right)**
|
||||
* *问题*: 右侧只能放 PICO 卡片。一旦开始生成文档,A4 纸被挤成“长条”,用户必须横向滚动或者字变得极小,根本没法阅读。
|
||||
* **如果统一为 40% (Chat) : 60% (Right)**
|
||||
* *问题*: 在前期的 PICO 收集阶段,右侧面板(只有几个卡片)会留出大片空白,显得界面空旷、重心失衡。
|
||||
|
||||
## **2\. 推荐方案:动态自适应布局 (Dynamic Split View)**
|
||||
|
||||
我们要根据 **“用户当前的注意力焦点”** 自动调整比例。
|
||||
|
||||
### **阶段 A:要素收集期 (Focus on Chat)**
|
||||
|
||||
* **状态**:AI 在问,用户在答。右侧只是辅助展示“已提取的 PICO”。
|
||||
* **比例**:**Chat 65% : Context 35%**
|
||||
* **理由**:此时用户的视线主要在聊天流上,右侧只是个“仪表盘”。
|
||||
|
||||
### **阶段 B:方案生成期 (Focus on Document)**
|
||||
|
||||
* **状态**:AI 在写长文,用户在审阅。聊天框只用来发简单的修改指令。
|
||||
* **比例**:**Chat 35% : Document 65%**
|
||||
* **理由**:此时右侧的 A4 纸是主角。A4 纸的最佳阅读宽度通常需要 800px+,否则排版会乱(尤其是表格)。
|
||||
|
||||
### **阶段 C:终极自由 (User Control)**
|
||||
|
||||
* **功能**:在两栏中间加一个 **Drag Handle (拖拽手柄)**,允许用户自己拖动宽度。
|
||||
* **记忆**:记住用户的最后设置。
|
||||
|
||||
## **3\. 视觉优化细节**
|
||||
|
||||
1. **平滑过渡**:当从阶段 A 切换到阶段 B 时,使用 CSS transition 让分界线平滑移动,而不是突变。
|
||||
2. **折叠按钮**:允许用户完全折叠左侧 Chat,进入 **“全屏沉浸阅读模式”** (100% Doc)。
|
||||
|
||||
## **4\. 结论**
|
||||
|
||||
**不要统一。**
|
||||
|
||||
请采用 **“模式驱动的默认比例 \+ 手动拖拽”** 的策略。
|
||||
|
||||
* 默认:**PICO 模式 (60/40)** \-\> **生成模式 (35/65)**。
|
||||
277
docs/03-业务模块/AIA-AI智能问答/00-系统设计/研究方案一键生成.html
Normal file
277
docs/03-业务模块/AIA-AI智能问答/00-系统设计/研究方案一键生成.html
Normal file
@@ -0,0 +1,277 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Protocol Agent V3.0 - 生成全流程</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<script src="https://unpkg.com/lucide@latest"></script>
|
||||
<style>
|
||||
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600&family=Noto+Sans+SC:wght@300;400;500;700&family=Noto+Serif+SC:wght@400;700&display=swap');
|
||||
|
||||
body { font-family: 'Inter', 'Noto Sans SC', sans-serif; }
|
||||
|
||||
/* 聊天气泡 */
|
||||
.chat-bubble-ai { background-color: #F3F4F6; border-radius: 12px 12px 12px 2px; }
|
||||
.chat-bubble-user { background-color: #4F46E5; color: white; border-radius: 12px 12px 2px 12px; }
|
||||
|
||||
/* A4 纸张效果 (预览模式) */
|
||||
.a4-paper {
|
||||
width: 100%;
|
||||
max-width: 210mm;
|
||||
min-height: 297mm;
|
||||
padding: 20mm;
|
||||
background: white;
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
margin: 0 auto;
|
||||
font-family: 'Noto Serif SC', serif; /* 宋体风格 */
|
||||
color: #1F2937;
|
||||
line-height: 1.8;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
/* 打字机光标 */
|
||||
.typing-cursor::after { content: '❘'; animation: blink 1s infinite; color: #4F46E5; }
|
||||
@keyframes blink { 50% { opacity: 0; } }
|
||||
|
||||
/* 右侧面板切换动画 */
|
||||
.panel-transition { transition: opacity 0.3s ease, transform 0.3s ease; }
|
||||
.panel-hidden { opacity: 0; transform: translateX(20px); pointer-events: none; position: absolute; top:0; left:0; right:0; }
|
||||
.panel-visible { opacity: 1; transform: translateX(0); position: relative; }
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-gray-100 h-screen flex flex-col overflow-hidden">
|
||||
|
||||
<!-- Header -->
|
||||
<header class="bg-white border-b border-gray-200 h-14 flex items-center justify-between px-4 shadow-sm z-20 shrink-0">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-8 h-8 bg-indigo-600 rounded-lg flex items-center justify-center text-white font-bold">
|
||||
<i data-lucide="bot" class="w-5 h-5"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h1 class="font-bold text-gray-800 text-sm">Protocol Agent</h1>
|
||||
<div class="flex items-center gap-1.5">
|
||||
<span class="w-2 h-2 bg-green-500 rounded-full"></span>
|
||||
<span class="text-[10px] text-gray-500">PICO Ready</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Tab Switcher (用于演示) -->
|
||||
<div class="flex bg-gray-100 p-1 rounded-lg">
|
||||
<button id="btn-view-context" class="px-3 py-1 text-xs font-medium bg-white shadow-sm rounded text-gray-700">视图: 关键要素</button>
|
||||
<button id="btn-view-doc" class="px-3 py-1 text-xs font-medium text-gray-500 hover:text-gray-700">视图: 完整方案</button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="flex-1 flex overflow-hidden">
|
||||
|
||||
<!-- Left: Chat (35%) -->
|
||||
<section class="w-[400px] flex flex-col bg-white border-r border-gray-200 z-10 shadow-lg">
|
||||
<div id="chat-box" class="flex-1 overflow-y-auto p-4 space-y-6 bg-slate-50">
|
||||
|
||||
<!-- History -->
|
||||
<div class="flex gap-3">
|
||||
<div class="w-8 h-8 rounded-full bg-indigo-100 flex items-center justify-center shrink-0"><i data-lucide="bot" class="w-4 h-4 text-indigo-600"></i></div>
|
||||
<div class="chat-bubble-ai p-3 text-sm text-gray-700 shadow-sm">
|
||||
样本量计算已完成 (N=386)。至此,您的研究方案 <strong>5 个关键要素</strong> 已全部收集完毕。
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 核心:生成按钮 Action Card -->
|
||||
<div class="flex justify-center" id="action-area">
|
||||
<div class="bg-white border-2 border-indigo-100 rounded-xl p-4 shadow-md w-full max-w-sm hover:border-indigo-300 transition-all cursor-default">
|
||||
<div class="flex items-center gap-3 mb-3">
|
||||
<div class="bg-indigo-600 text-white p-2 rounded-lg"><i data-lucide="sparkles" class="w-5 h-5"></i></div>
|
||||
<div>
|
||||
<h3 class="font-bold text-gray-800 text-sm">要素已就绪</h3>
|
||||
<p class="text-xs text-gray-500">基于已确认的 PICO 与样本量</p>
|
||||
</div>
|
||||
</div>
|
||||
<button onclick="startGeneration()" class="w-full bg-indigo-600 hover:bg-indigo-700 text-white text-sm font-bold py-2.5 rounded-lg shadow-sm flex items-center justify-center gap-2 transition-transform active:scale-95">
|
||||
开始撰写完整方案
|
||||
<i data-lucide="arrow-right" class="w-4 h-4"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 生成中的状态 (初始隐藏) -->
|
||||
<div id="generating-msg" class="hidden flex gap-3 animate-fade-in">
|
||||
<div class="w-8 h-8 rounded-full bg-indigo-100 flex items-center justify-center shrink-0"><i data-lucide="pen-tool" class="w-4 h-4 text-indigo-600 animate-pulse"></i></div>
|
||||
<div class="chat-bubble-ai p-3 text-sm text-gray-700 shadow-sm w-full">
|
||||
<p class="font-bold text-indigo-600 mb-2 text-xs">正在撰写...</p>
|
||||
<div class="space-y-2">
|
||||
<div class="flex items-center justify-between text-xs">
|
||||
<span class="text-gray-600">1. 研究背景</span>
|
||||
<i data-lucide="check-circle" class="w-3 h-3 text-green-500"></i>
|
||||
</div>
|
||||
<div class="flex items-center justify-between text-xs">
|
||||
<span class="text-gray-600">2. 研究目的</span>
|
||||
<i data-lucide="check-circle" class="w-3 h-3 text-green-500"></i>
|
||||
</div>
|
||||
<div class="flex items-center justify-between text-xs">
|
||||
<span class="text-indigo-600 font-medium">3. 研究设计</span>
|
||||
<i data-lucide="loader-2" class="w-3 h-3 text-indigo-500 animate-spin"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Input -->
|
||||
<div class="p-3 border-t border-gray-200 bg-white">
|
||||
<div class="relative">
|
||||
<input type="text" placeholder="对生成结果不满意?输入修改指令..." class="w-full pl-4 pr-10 py-3 bg-gray-50 border border-gray-200 rounded-xl text-sm focus:outline-none focus:ring-2 focus:ring-indigo-500">
|
||||
<button class="absolute right-2 top-1/2 -translate-y-1/2 p-1.5 text-indigo-600"><i data-lucide="send" class="w-4 h-4"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Right: Dual Panel (Context vs Document) -->
|
||||
<section class="flex-1 bg-slate-100 relative overflow-hidden">
|
||||
|
||||
<!-- Panel 1: Context View (结构化数据) -->
|
||||
<div id="panel-context" class="absolute inset-0 p-8 overflow-y-auto panel-visible panel-transition">
|
||||
<div class="max-w-3xl mx-auto">
|
||||
<div class="flex items-center justify-between mb-6">
|
||||
<h2 class="text-lg font-bold text-gray-800 flex items-center gap-2">
|
||||
<i data-lucide="database" class="w-5 h-5 text-gray-500"></i>
|
||||
关键要素 (Context Data)
|
||||
</h2>
|
||||
<span class="text-xs bg-white border border-gray-200 px-3 py-1 rounded-full text-gray-500">数据源: Postgres JSONB</span>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 gap-4">
|
||||
<!-- PICO Card -->
|
||||
<div class="bg-white p-5 rounded-xl border border-gray-200 shadow-sm">
|
||||
<div class="text-xs font-bold text-gray-400 uppercase mb-3">PICO 模型</div>
|
||||
<div class="space-y-3">
|
||||
<div class="flex"><span class="w-8 font-bold text-blue-600">P</span><span class="text-sm text-gray-700">≥65岁原发性高血压患者</span></div>
|
||||
<div class="flex"><span class="w-8 font-bold text-indigo-600">I</span><span class="text-sm text-gray-700">阿司匹林肠溶片 100mg/d</span></div>
|
||||
<div class="flex"><span class="w-8 font-bold text-orange-600">C</span><span class="text-sm text-gray-700">安慰剂</span></div>
|
||||
<div class="flex"><span class="w-8 font-bold text-green-600">O</span><span class="text-sm text-gray-700">5年内缺血性脑卒中发生率</span></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sample Size Card -->
|
||||
<div class="bg-white p-5 rounded-xl border border-gray-200 shadow-sm flex items-center justify-between">
|
||||
<div>
|
||||
<div class="text-xs font-bold text-gray-400 uppercase mb-1">样本量估算</div>
|
||||
<div class="text-sm text-gray-600">Alpha=0.05, Power=0.8</div>
|
||||
</div>
|
||||
<div class="text-2xl font-bold text-indigo-600 font-mono">N=386</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-8 text-center text-sm text-gray-400">
|
||||
<i data-lucide="arrow-left" class="w-4 h-4 inline mr-1"></i>
|
||||
点击左侧 "开始撰写" 将基于以上数据生成文档
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Panel 2: Document View (A4 Preview) -->
|
||||
<div id="panel-doc" class="absolute inset-0 p-8 overflow-y-auto panel-hidden panel-transition bg-gray-200/50">
|
||||
<!-- Toolbar -->
|
||||
<div class="absolute top-4 right-8 flex gap-2 z-10">
|
||||
<button class="bg-white hover:bg-gray-50 text-gray-700 px-3 py-1.5 rounded border border-gray-300 text-xs font-medium shadow-sm flex items-center gap-1">
|
||||
<i data-lucide="copy" class="w-3 h-3"></i> 复制
|
||||
</button>
|
||||
<button class="bg-indigo-600 hover:bg-indigo-700 text-white px-3 py-1.5 rounded border border-transparent text-xs font-medium shadow-sm flex items-center gap-1">
|
||||
<i data-lucide="download" class="w-3 h-3"></i> 导出 Word
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Paper -->
|
||||
<div class="a4-paper">
|
||||
<h1 class="text-2xl font-bold text-center mb-10 pt-4">阿司匹林预防老年高血压患者缺血性脑卒中的<br>前瞻性、随机、双盲对照研究方案</h1>
|
||||
|
||||
<div class="space-y-6">
|
||||
<div>
|
||||
<h2 class="text-lg font-bold mb-2 border-b border-gray-800 pb-1">1. 研究背景 (Background)</h2>
|
||||
<p class="text-justify indent-8">
|
||||
脑卒中是全球范围内导致死亡和长期残疾的主要原因之一。流行病学数据显示,在65岁以上的老年人群中,高血压是缺血性脑卒中最重要的独立危险因素...
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h2 class="text-lg font-bold mb-2 border-b border-gray-800 pb-1">2. 研究目的 (Objectives)</h2>
|
||||
<p class="text-justify indent-8">
|
||||
<strong>主要目的:</strong> 评价每日口服 100mg 阿司匹林肠溶片对比安慰剂,在降低 65 岁及以上原发性高血压患者 5 年内缺血性脑卒中发生率方面的有效性。
|
||||
</p>
|
||||
<p class="text-justify indent-8 mt-2">
|
||||
<strong>次要目的:</strong> 评估阿司匹林组与安慰剂组在全因死亡率、出血性脑卒中发生率及主要出血事件(如消化道出血)方面的差异。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h2 class="text-lg font-bold mb-2 border-b border-gray-800 pb-1">3. 研究设计 (Study Design)</h2>
|
||||
<p class="text-justify indent-8 typing-cursor">
|
||||
本研究采用多中心、随机、双盲、安慰剂对照设计 (RCT)。入组后的受试者将通过中央随机系统以 1:1 的比例分配至试验组(阿司匹林)或对照组(安慰剂)。
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="h-20"></div> <!-- Bottom Spacer -->
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
</main>
|
||||
|
||||
<script>
|
||||
lucide.createIcons();
|
||||
|
||||
const panelContext = document.getElementById('panel-context');
|
||||
const panelDoc = document.getElementById('panel-doc');
|
||||
const btnViewContext = document.getElementById('btn-view-context');
|
||||
const btnViewDoc = document.getElementById('btn-view-doc');
|
||||
const actionArea = document.getElementById('action-area');
|
||||
const generatingMsg = document.getElementById('generating-msg');
|
||||
const chatBox = document.getElementById('chat-box');
|
||||
|
||||
function switchTab(view) {
|
||||
if (view === 'context') {
|
||||
panelContext.classList.remove('panel-hidden');
|
||||
panelContext.classList.add('panel-visible');
|
||||
panelDoc.classList.remove('panel-visible');
|
||||
panelDoc.classList.add('panel-hidden');
|
||||
|
||||
btnViewContext.classList.add('bg-white', 'shadow-sm', 'text-gray-700');
|
||||
btnViewContext.classList.remove('text-gray-500');
|
||||
btnViewDoc.classList.remove('bg-white', 'shadow-sm', 'text-gray-700');
|
||||
btnViewDoc.classList.add('text-gray-500');
|
||||
} else {
|
||||
panelContext.classList.remove('panel-visible');
|
||||
panelContext.classList.add('panel-hidden');
|
||||
panelDoc.classList.remove('panel-hidden');
|
||||
panelDoc.classList.add('panel-visible');
|
||||
|
||||
btnViewDoc.classList.add('bg-white', 'shadow-sm', 'text-gray-700');
|
||||
btnViewDoc.classList.remove('text-gray-500');
|
||||
btnViewContext.classList.remove('bg-white', 'shadow-sm', 'text-gray-700');
|
||||
btnViewContext.classList.add('text-gray-500');
|
||||
}
|
||||
}
|
||||
|
||||
function startGeneration() {
|
||||
// 1. 切换到文档视图
|
||||
switchTab('doc');
|
||||
|
||||
// 2. Chat UI 更新
|
||||
actionArea.style.display = 'none'; // 隐藏按钮
|
||||
generatingMsg.classList.remove('hidden'); // 显示进度条
|
||||
|
||||
// 滚动到底部
|
||||
chatBox.scrollTo({ top: chatBox.scrollHeight, behavior: 'smooth' });
|
||||
}
|
||||
|
||||
// 绑定 Tab 点击事件
|
||||
btnViewContext.onclick = () => switchTab('context');
|
||||
btnViewDoc.onclick = () => switchTab('doc');
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -896,3 +896,4 @@ export interface SlashCommand {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -496,3 +496,4 @@ class StatisticsAgentOrchestrator extends BaseAgentOrchestrator<StatisticsContex
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1125,3 +1125,4 @@ export function createProtocolAgentDependencies(
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,57 +1,80 @@
|
||||
# 一键生成研究方案 - 开发计划
|
||||
|
||||
> **版本**: v1.1
|
||||
> **版本**: v2.0
|
||||
> **创建日期**: 2026-01-24
|
||||
> **最后更新**: 2026-01-24
|
||||
> **最后更新**: 2026-01-25
|
||||
> **负责人**: AI Assistant
|
||||
> **状态**: 待开发
|
||||
> **状态**: 开发中
|
||||
|
||||
---
|
||||
|
||||
## 一、功能概述
|
||||
|
||||
### 目标
|
||||
基于 Protocol Agent 收集的 5 个核心要素,一键生成完整的临床研究方案文档,支持在线编辑和 Word 导出。
|
||||
基于 Protocol Agent 收集的 5 个核心要素,一键生成完整的临床研究方案文档,支持对话式修改和 Word 导出。
|
||||
|
||||
### 核心价值
|
||||
- 将 5-10 小时的方案撰写工作缩短至 30 分钟
|
||||
- AI 生成 + 人工编辑,保证专业性和个性化
|
||||
- AI 生成 + 对话式修改 + Word 精修,保证专业性和个性化
|
||||
- 输出符合伦理委员会审查要求的标准文档
|
||||
|
||||
### 技术策略:No-Editor First(无编辑器优先)
|
||||
|
||||
**核心洞察**:
|
||||
> 用户最终会在 Word 中精修,我们的价值是 **"AI 生成高质量初稿"**,而不是 **"提供一个编辑器"**。
|
||||
|
||||
---
|
||||
|
||||
## 二、交互设计:两阶段渐进式生成
|
||||
## 二、交互设计:对话流生成
|
||||
|
||||
### 第一阶段:对话框生成摘要
|
||||
### 用户流程
|
||||
|
||||
```
|
||||
用户点击"一键生成研究方案"
|
||||
用户完成 5 阶段要素收集
|
||||
↓
|
||||
AI 在对话框中流式输出研究方案摘要(约500字)
|
||||
点击"一键生成研究方案"
|
||||
↓
|
||||
用户确认摘要 → 进入第二阶段
|
||||
用户不满意 → 在对话中继续调整要素
|
||||
AI 在对话框中流式输出完整方案(Markdown)
|
||||
↓
|
||||
用户对话修改:"把样本量部分改一下..."
|
||||
↓
|
||||
AI 流式输出修改后的章节
|
||||
↓
|
||||
用户满意 → 点击"导出 Word"
|
||||
↓
|
||||
下载符合伦理委员会格式的 Word 文档
|
||||
```
|
||||
|
||||
**摘要内容**:
|
||||
- 研究题目
|
||||
- 研究目的(主要/次要)
|
||||
- 研究设计概述
|
||||
- 样本量结论
|
||||
- 主要结局指标
|
||||
|
||||
### 第二阶段:方案编辑器生成完整方案
|
||||
### 交互示意
|
||||
|
||||
```
|
||||
用户点击"生成完整方案"
|
||||
↓
|
||||
跳转到方案编辑器页面
|
||||
↓
|
||||
流式生成完整研究方案(5000-8000字)
|
||||
↓
|
||||
用户在线编辑 / AI协作润色
|
||||
↓
|
||||
导出 Word 文档
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ ← 返回 全流程研究方案制定 │
|
||||
├────────────────────────────────────────┬────────────────────┤
|
||||
│ │ 📋 研究方案状态 │
|
||||
│ [AI] 根据您确认的信息,我已生成研究方案: │ │
|
||||
│ │ ✅ 科学问题 │
|
||||
│ # 1. 研究题目 │ ✅ PICO要素 │
|
||||
│ 糖尿病患者使用二甲双胍与格列美脲... │ ✅ 研究设计 │
|
||||
│ │ ✅ 样本量 │
|
||||
│ # 2. 研究背景 │ ✅ 观察指标 │
|
||||
│ 2型糖尿病是全球性公共卫生问题... │ │
|
||||
│ │ ──────────────── │
|
||||
│ ... │ │
|
||||
│ │ [📥 导出 Word] │
|
||||
│ ┌────────────────────────────────┐ │ [🔄 重新生成] │
|
||||
│ │ 📥 导出Word │ 🔄 修改本章节 │ │ │
|
||||
│ └────────────────────────────────┘ │ │
|
||||
│ │ │
|
||||
│ [用户] 把样本量从200改成300,并说明原因 │ │
|
||||
│ │ │
|
||||
│ [AI] 好的,我已修改样本量部分: │ │
|
||||
│ ## 6. 样本量估算 │ │
|
||||
│ 根据前期预实验数据...样本量调整为300例 │ │
|
||||
│ │ │
|
||||
├────────────────────────────────────────┴────────────────────┤
|
||||
│ [输入消息...] [发送] │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
@@ -79,229 +102,344 @@ AI 在对话框中流式输出研究方案摘要(约500字)
|
||||
|
||||
---
|
||||
|
||||
## 四、方案编辑器设计
|
||||
## 四、技术方案
|
||||
|
||||
### 布局结构
|
||||
### 架构概览
|
||||
|
||||
```
|
||||
┌────────────────────────────────────────────────────────────────┐
|
||||
│ ← 返回 📄 研究方案编辑器 [自动保存✓] [导出Word] [发布] │
|
||||
├──────────┬─────────────────────────────────────┬───────────────┤
|
||||
│ 📑 大纲 │ 📝 编辑区 │ 🤖 AI助手 │
|
||||
│ │ │ │
|
||||
│ 可点击 │ Notion 风格分块编辑 │ 选中文本后: │
|
||||
│ 快速跳转 │ 支持 Markdown + 富文本 │ - /ai 润色 │
|
||||
│ │ Slash 命令 (/) │ - /ai 扩写 │
|
||||
│ │ 拖拽排序章节 │ - /ai 精简 │
|
||||
└──────────┴─────────────────────────────────────┴───────────────┘
|
||||
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
|
||||
│ 前端 │ │ Node.js │ │ Python │
|
||||
│ ChatArea │ ──▶ │ Backend │ ──▶ │ Service │
|
||||
│ │ │ │ │ (Pandoc) │
|
||||
└─────────────┘ └─────────────┘ └─────────────┘
|
||||
│ │ │
|
||||
│ 流式输出 │ 调用 LLM │ Markdown→Word
|
||||
│ Markdown │ 生成方案 │ 格式转换
|
||||
▼ ▼ ▼
|
||||
┌─────────────────────────────────────────────────────┐
|
||||
│ 用户下载 Word │
|
||||
└─────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 核心功能
|
||||
|
||||
| 功能 | 说明 | 优先级 |
|
||||
|------|------|--------|
|
||||
| **Slash 命令** | 输入 / 唤起菜单,支持 /ai 调用生成 | P0 |
|
||||
| **分块编辑** | 每个章节独立编辑,支持拖拽排序 | P0 |
|
||||
| **大纲导航** | 左侧目录,点击跳转 | P0 |
|
||||
| **自动保存** | 每30秒 + 失焦时保存 | P0 |
|
||||
| **导出Word** | Tiptap JSON → docx | P0 |
|
||||
| **AI润色** | 选中文本,/ai polish 优化 | P1 |
|
||||
| **AI扩写** | 选中章节,/ai expand 补充 | P1 |
|
||||
| **Ghost Text** | AI 生成时显示幽灵文字预览 | P1 |
|
||||
| **版本历史** | 查看修改记录,回滚 | P2 |
|
||||
|
||||
---
|
||||
|
||||
## 五、技术方案
|
||||
|
||||
### 技术选型:Novel (Fork)
|
||||
|
||||
**选型结论**:Fork [Novel](https://github.com/steven-tey/novel) 源码,而非 npm 包引入。
|
||||
|
||||
**选择 Novel 的理由**:
|
||||
|
||||
| 因素 | Novel 优势 |
|
||||
|------|-----------|
|
||||
| **AI 原生** | 专为 AI 写作设计,已处理流式生成的 UX 细节(Ghost Text、光标锁定) |
|
||||
| **标准 Tiptap** | 直接暴露 Tiptap 配置,可插入交互组件(样本量计算器、引用卡片) |
|
||||
| **可控性** | 源码在手,100% 可定制 UI 和逻辑 |
|
||||
| **对接成本** | 替换 useCompletion → useAIStream 即可对接现有后端 |
|
||||
|
||||
**Fork 策略**:
|
||||
### 技术栈
|
||||
|
||||
```
|
||||
不要 npm install novel
|
||||
|
||||
将 novel/packages/core/src 复制到:
|
||||
frontend-v2/src/shared/components/ProtocolEditor/
|
||||
|
||||
目录结构:
|
||||
├── index.tsx # 主组件
|
||||
├── extensions/ # Tiptap 扩展
|
||||
│ ├── ai-autocomplete.ts # 替换为 useAIStream
|
||||
│ ├── slash-command.tsx # 保留 Slash 菜单
|
||||
│ ├── citation.ts # Phase 2: 文献引用
|
||||
│ └── medical-table.ts # Phase 2: 复杂表格
|
||||
├── components/ # UI 组件
|
||||
│ ├── EditorContent.tsx
|
||||
│ ├── SlashMenu.tsx
|
||||
│ └── BubbleMenu.tsx
|
||||
└── styles/ # 样式(处理 Tailwind 冲突)
|
||||
└── editor.css
|
||||
```
|
||||
|
||||
**Tailwind CSS 冲突处理**:
|
||||
|
||||
```css
|
||||
/* 方案:CSS 命名空间隔离 */
|
||||
.novel-editor-scope {
|
||||
/* Novel 的 Tailwind 样式限制在此作用域 */
|
||||
}
|
||||
```
|
||||
|
||||
### 技术栈总览
|
||||
|
||||
```
|
||||
前端编辑器:Novel (Fork) - 基于 Tiptap/ProseMirror
|
||||
├── 优点:AI 原生、Notion 风格、源码可控
|
||||
├── 核心:Slash 命令、Ghost Text、拖拽排序
|
||||
前端:复用现有 ChatArea + useAIStream
|
||||
├── 增加"导出 Word"按钮
|
||||
├── 增加"修改本章节"交互
|
||||
│
|
||||
AI 调用:复用现有 useAIStream Hook
|
||||
├── 替换 Novel 的 useCompletion (Vercel AI SDK)
|
||||
├── 对接 /api/v1/aia/protocol-agent/generate
|
||||
后端 (Node.js):
|
||||
├── POST /api/v1/aia/protocol-agent/generate/full # 生成完整方案
|
||||
├── POST /api/v1/aia/protocol-agent/regenerate # 重新生成指定章节
|
||||
├── POST /api/v1/aia/protocol-agent/export/docx # 导出 Word
|
||||
│
|
||||
文档导出:docx.js 或 @tiptap-pro/extension-export-docx
|
||||
│
|
||||
数据存储:PostgreSQL (protocol_generations 表)
|
||||
后端 (Python):
|
||||
├── Pandoc 集成
|
||||
├── Reference Doc 模板控制样式
|
||||
```
|
||||
|
||||
### 数据模型
|
||||
|
||||
```sql
|
||||
-- 方案生成记录表
|
||||
CREATE TABLE protocol_generations (
|
||||
id UUID PRIMARY KEY,
|
||||
conversation_id UUID REFERENCES conversations(id),
|
||||
user_id UUID REFERENCES users(id),
|
||||
|
||||
-- 内容
|
||||
summary TEXT, -- 摘要(第一阶段)
|
||||
full_content JSONB, -- 完整方案(Tiptap JSON,标准格式)
|
||||
|
||||
-- 状态
|
||||
status VARCHAR(20), -- draft | generating | completed
|
||||
version INT DEFAULT 1,
|
||||
|
||||
-- 元数据
|
||||
word_file_url TEXT, -- 导出的Word文件URL
|
||||
created_at TIMESTAMP,
|
||||
updated_at TIMESTAMP
|
||||
);
|
||||
-- 方案生成记录表(复用现有 protocol_generations)
|
||||
ALTER TABLE protocol_schema.protocol_generations ADD COLUMN IF NOT EXISTS
|
||||
sections JSONB; -- 分章节存储,支持局部修改
|
||||
|
||||
-- sections 结构示例
|
||||
{
|
||||
"title": "糖尿病患者使用二甲双胍...",
|
||||
"background": "2型糖尿病是全球性...",
|
||||
"objectives": "...",
|
||||
"design": "...",
|
||||
"subjects": "...",
|
||||
"sample_size": "...",
|
||||
"implementation": "...",
|
||||
"endpoints": "...",
|
||||
"data_management": "...",
|
||||
"safety": "...",
|
||||
"statistics": "...",
|
||||
"ethics": "...",
|
||||
"timeline": "...",
|
||||
"references": "..."
|
||||
}
|
||||
```
|
||||
|
||||
### API 设计
|
||||
|
||||
```typescript
|
||||
// 第一阶段:生成摘要(流式)
|
||||
POST /api/v1/aia/protocol-agent/generate/summary
|
||||
Request: { conversationId: string }
|
||||
Response: SSE 流式输出摘要
|
||||
|
||||
// 第二阶段:生成完整方案(流式)
|
||||
// 生成完整方案(流式)
|
||||
POST /api/v1/aia/protocol-agent/generate/full
|
||||
Request: { conversationId: string }
|
||||
Response: SSE 流式输出完整方案
|
||||
Response: SSE 流式输出完整 Markdown
|
||||
|
||||
// 保存编辑
|
||||
PUT /api/v1/aia/protocol-agent/generation/:id
|
||||
Request: { content: TiptapJSON }
|
||||
|
||||
// 导出Word
|
||||
POST /api/v1/aia/protocol-agent/generation/:id/export
|
||||
Response: { downloadUrl: string }
|
||||
|
||||
// AI编辑(润色/扩写)
|
||||
POST /api/v1/aia/protocol-agent/generation/:id/ai-edit
|
||||
// 重新生成指定章节(流式)
|
||||
POST /api/v1/aia/protocol-agent/regenerate
|
||||
Request: {
|
||||
action: 'polish' | 'expand' | 'simplify',
|
||||
selectedText: string,
|
||||
context: string
|
||||
conversationId: string,
|
||||
section: 'sample_size' | 'background' | ...,
|
||||
instruction: "把样本量从200改成300"
|
||||
}
|
||||
Response: SSE 流式输出
|
||||
Response: SSE 流式输出该章节
|
||||
|
||||
// 导出 Word
|
||||
POST /api/v1/aia/protocol-agent/export/docx
|
||||
Request: { conversationId: string }
|
||||
Response: Binary (application/vnd.openxmlformats-officedocument.wordprocessingml.document)
|
||||
|
||||
// 获取当前方案内容
|
||||
GET /api/v1/aia/protocol-agent/generation/:conversationId
|
||||
Response: { sections: {...}, fullMarkdown: "...", version: 3 }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 五、核心实现
|
||||
|
||||
### 5.1 Python 微服务:Pandoc 转换器
|
||||
|
||||
**Dockerfile 增加依赖:**
|
||||
```dockerfile
|
||||
RUN apt-get update && apt-get install -y pandoc
|
||||
RUN pip install pypandoc
|
||||
```
|
||||
|
||||
**Service 代码:**
|
||||
```python
|
||||
# python-service/app/services/doc_service.py
|
||||
import pypandoc
|
||||
import os
|
||||
|
||||
def convert_md_to_docx(markdown_text: str, output_path: str):
|
||||
# 使用参考文档控制样式(字体、字号、页眉)
|
||||
reference_doc = os.path.join(
|
||||
os.path.dirname(__file__),
|
||||
'assets/protocol_template.docx'
|
||||
)
|
||||
|
||||
pypandoc.convert_text(
|
||||
markdown_text,
|
||||
'docx',
|
||||
format='markdown',
|
||||
outputfile=output_path,
|
||||
extra_args=[f'--reference-doc={reference_doc}']
|
||||
)
|
||||
return output_path
|
||||
```
|
||||
|
||||
**API 端点:**
|
||||
```python
|
||||
# python-service/app/routers/doc_router.py
|
||||
from fastapi import APIRouter, Response
|
||||
from ..services.doc_service import convert_md_to_docx
|
||||
import tempfile
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
@router.post("/convert/docx")
|
||||
async def convert_to_docx(request: dict):
|
||||
markdown = request.get("content", "")
|
||||
|
||||
with tempfile.NamedTemporaryFile(suffix='.docx', delete=False) as f:
|
||||
output_path = f.name
|
||||
|
||||
convert_md_to_docx(markdown, output_path)
|
||||
|
||||
with open(output_path, 'rb') as f:
|
||||
content = f.read()
|
||||
|
||||
return Response(
|
||||
content=content,
|
||||
media_type="application/vnd.openxmlformats-officedocument.wordprocessingml.document"
|
||||
)
|
||||
```
|
||||
|
||||
### 5.2 Node.js 后端:导出 API
|
||||
|
||||
```typescript
|
||||
// backend/src/modules/agent/protocol/controllers/ProtocolGenerateController.ts
|
||||
|
||||
export class ProtocolGenerateController {
|
||||
|
||||
// 生成完整方案
|
||||
async generateFull(request: FastifyRequest, reply: FastifyReply) {
|
||||
const { conversationId } = request.body as { conversationId: string };
|
||||
|
||||
// 获取 Protocol Context(5 阶段数据)
|
||||
const context = await this.contextService.getContext(conversationId);
|
||||
|
||||
// 构建生成 Prompt
|
||||
const prompt = this.buildGeneratePrompt(context);
|
||||
|
||||
// 流式生成
|
||||
const streamingService = createStreamingService(reply, {
|
||||
onChunk: async (chunk) => {
|
||||
// 保存到数据库
|
||||
await this.saveChunk(conversationId, chunk);
|
||||
}
|
||||
});
|
||||
|
||||
await streamingService.streamGenerate([
|
||||
{ role: 'system', content: this.getSystemPrompt() },
|
||||
{ role: 'user', content: prompt }
|
||||
]);
|
||||
}
|
||||
|
||||
// 重新生成指定章节
|
||||
async regenerateSection(request: FastifyRequest, reply: FastifyReply) {
|
||||
const { conversationId, section, instruction } = request.body;
|
||||
|
||||
const context = await this.contextService.getContext(conversationId);
|
||||
const currentGeneration = await this.getGeneration(conversationId);
|
||||
|
||||
const prompt = `
|
||||
请根据以下指令修改"${section}"章节:
|
||||
|
||||
用户指令:${instruction}
|
||||
|
||||
当前章节内容:
|
||||
${currentGeneration.sections[section]}
|
||||
|
||||
研究背景信息:
|
||||
${JSON.stringify(context)}
|
||||
|
||||
请输出修改后的完整章节内容(Markdown 格式):
|
||||
`;
|
||||
|
||||
// 流式输出修改后的章节
|
||||
const streamingService = createStreamingService(reply);
|
||||
await streamingService.streamGenerate([
|
||||
{ role: 'system', content: '你是临床研究方案撰写专家...' },
|
||||
{ role: 'user', content: prompt }
|
||||
]);
|
||||
}
|
||||
|
||||
// 导出 Word
|
||||
async exportDocx(request: FastifyRequest, reply: FastifyReply) {
|
||||
const { conversationId } = request.body as { conversationId: string };
|
||||
|
||||
// 获取完整 Markdown
|
||||
const generation = await this.getGeneration(conversationId);
|
||||
const markdown = this.sectionsToMarkdown(generation.sections);
|
||||
|
||||
// 调用 Python 微服务转换
|
||||
const response = await axios.post(
|
||||
`${PYTHON_SERVICE_URL}/convert/docx`,
|
||||
{ content: markdown },
|
||||
{ responseType: 'arraybuffer' }
|
||||
);
|
||||
|
||||
reply.header('Content-Type', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document');
|
||||
reply.header('Content-Disposition', 'attachment; filename="research_protocol.docx"');
|
||||
return reply.send(response.data);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5.3 前端:ChatArea 增强
|
||||
|
||||
```tsx
|
||||
// frontend-v2/src/modules/aia/protocol-agent/components/ChatArea.tsx
|
||||
|
||||
// 在消息气泡中增加导出按钮
|
||||
const ProtocolMessageActions = ({ content, conversationId }) => {
|
||||
const [exporting, setExporting] = useState(false);
|
||||
|
||||
const handleExport = async () => {
|
||||
setExporting(true);
|
||||
try {
|
||||
const response = await fetch('/api/v1/aia/protocol-agent/export/docx', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ conversationId })
|
||||
});
|
||||
|
||||
const blob = await response.blob();
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = '研究方案.docx';
|
||||
a.click();
|
||||
} finally {
|
||||
setExporting(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="protocol-message-actions">
|
||||
<Button
|
||||
icon={<DownloadOutlined />}
|
||||
onClick={handleExport}
|
||||
loading={exporting}
|
||||
>
|
||||
导出 Word
|
||||
</Button>
|
||||
<Button icon={<EditOutlined />}>
|
||||
修改章节
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 六、开发计划
|
||||
|
||||
### Phase 1:Fork Novel + 对接后端(3天)
|
||||
|
||||
**目标**:3天内跑通"编辑器 + AI 流式生成"
|
||||
### Phase 1:MVP 核心功能(2 天)
|
||||
|
||||
| 天数 | 任务 | 交付物 |
|
||||
|------|------|--------|
|
||||
| Day 1 | Fork Novel 源码 + 项目集成 | 编辑器基础渲染、Slash 菜单可用 |
|
||||
| Day 2 | 替换 AI 调用 → useAIStream | /ai 命令可调用后端生成 |
|
||||
| Day 3 | 摘要生成 API + 编辑器页面路由 | 完整的"对话→摘要→编辑器"流程 |
|
||||
| Day 1 | Python 微服务集成 Pandoc | `/convert/docx` API 可用 |
|
||||
| Day 1 | Node.js 导出 API | `/export/docx` 端点完成 |
|
||||
| Day 2 | 前端导出按钮 | ChatArea 增加导出功能 |
|
||||
| Day 2 | 完整方案生成 Prompt | 生成质量优化 |
|
||||
|
||||
**Phase 1 交付**:
|
||||
- ✅ Notion 风格编辑器可用
|
||||
- ✅ /ai 命令可调用 Protocol Agent
|
||||
- ✅ 支持 Markdown 导出
|
||||
- ✅ 一键生成完整研究方案(Markdown)
|
||||
- ✅ 导出符合格式的 Word 文档
|
||||
- ✅ 基础对话式修改
|
||||
|
||||
### Phase 2:完整方案生成 + Word 导出(3天)
|
||||
### Phase 2:分章节修改(2 天)
|
||||
|
||||
| 天数 | 任务 | 交付物 |
|
||||
|------|------|--------|
|
||||
| Day 4 | 完整方案生成 API(流式) | 编辑器中流式显示完整方案 |
|
||||
| Day 5 | 自动保存 + 版本管理 | 数据库存储、草稿恢复 |
|
||||
| Day 6 | Word 导出功能 | docx 文件下载 |
|
||||
| Day 3 | 分章节存储模型 | sections JSONB 字段 |
|
||||
| Day 3 | 章节重新生成 API | `/regenerate` 端点 |
|
||||
| Day 4 | 前端章节选择器 | 点击章节触发修改对话 |
|
||||
| Day 4 | 版本历史 | 修改记录存储 |
|
||||
|
||||
**Phase 2 交付**:
|
||||
- ✅ 完整方案流式生成
|
||||
- ✅ 自动保存
|
||||
- ✅ Word 导出
|
||||
- ✅ 分章节存储和修改
|
||||
- ✅ 智能识别修改章节
|
||||
- ✅ 版本历史追踪
|
||||
|
||||
### Phase 3:医疗特性增强(4天)
|
||||
### Phase 3:体验优化(1 天)
|
||||
|
||||
| 天数 | 任务 | 交付物 |
|
||||
|------|------|--------|
|
||||
| Day 7 | 集成 Tiptap Table 扩展 | 复杂表格支持(访视排期表) |
|
||||
| Day 8 | 开发 CitationBlock | 文献引用组件(对接 PKB) |
|
||||
| Day 9 | AI 润色/扩写优化 | 选中文本 AI 编辑体验 |
|
||||
| Day 10 | 测试 + UI 美化 | 完整功能测试 |
|
||||
|
||||
**Phase 3 交付**:
|
||||
- ✅ 复杂表格支持
|
||||
- ✅ 文献引用功能
|
||||
- ✅ AI 协作编辑完善
|
||||
| Day 5 | Word 模板优化 | 符合伦理委员会格式 |
|
||||
| Day 5 | UI 美化 | 导出进度、预览 |
|
||||
| Day 5 | 测试与修复 | 完整功能测试 |
|
||||
|
||||
---
|
||||
|
||||
## 七、风险与依赖
|
||||
## 七、与编辑器方案对比
|
||||
|
||||
| 风险 | 影响 | 缓解措施 |
|
||||
|------|------|----------|
|
||||
| Tailwind CSS 冲突 | 样式混乱 | CSS 命名空间隔离 |
|
||||
| Novel 源码维护成本 | 后续升级困难 | 代码量小(~2000行),可独立维护 |
|
||||
| LLM 生成质量不稳定 | 方案内容不专业 | 优化 Prompt + 人工模板 |
|
||||
| 长文本生成超时 | 用户等待过久 | 分章节流式生成 |
|
||||
| Word 导出格式问题 | 格式错乱 | 预设 Word 模板 |
|
||||
| 维度 | 无编辑器方案(当前) | 编辑器方案(备选) |
|
||||
|------|---------------------|-------------------|
|
||||
| **开发周期** | 5 天 | 10 天 |
|
||||
| **维护成本** | 低(复用现有组件) | 高(Fork Novel) |
|
||||
| **格式控制** | ⭐⭐⭐⭐⭐ Pandoc 精确控制 | ⭐⭐⭐ 需自己处理 |
|
||||
| **修改体验** | 对话式(稍慢) | 直接编辑(更快) |
|
||||
| **用户习惯** | 符合(Word 精修) | 需适应新界面 |
|
||||
| **适用场景** | MVP / 快速验证 | 高频编辑场景 |
|
||||
|
||||
### 依赖项
|
||||
### 何时考虑上编辑器?
|
||||
|
||||
- [x] Protocol Agent 5阶段数据收集(已完成)
|
||||
- [x] StreamingService 流式输出(已完成)
|
||||
- [x] useAIStream Hook(已完成)
|
||||
- [ ] Novel 源码 Fork(待执行)
|
||||
- [ ] docx.js 导出功能(待开发)
|
||||
|
||||
### 兜底方案
|
||||
|
||||
如果 Fork 的 Novel 代码难以维护:
|
||||
- 可回退到 **Tiptap Headless**
|
||||
- 用 Ant Design 重写 UI
|
||||
- **数据模型 (Tiptap JSON) 完全兼容**,用户数据不丢失
|
||||
如果用户反馈以下问题,再考虑引入编辑器:
|
||||
1. "对话修改太慢,我想直接改某个字"
|
||||
2. "我需要频繁调整段落顺序"
|
||||
3. "我想同时看到多个章节并对比"
|
||||
|
||||
---
|
||||
|
||||
@@ -309,43 +447,69 @@ Response: SSE 流式输出
|
||||
|
||||
### 功能验收
|
||||
|
||||
- [ ] 点击"一键生成",对话框流式输出摘要
|
||||
- [ ] 点击"生成完整方案",跳转编辑器并流式生成
|
||||
- [ ] 编辑器支持 Slash 命令 (/)
|
||||
- [ ] 编辑器支持章节拖拽排序
|
||||
- [ ] 选中文本可调用 AI 润色/扩写
|
||||
- [ ] 可导出标准格式的 Word 文档
|
||||
- [ ] 支持复杂表格编辑
|
||||
- [ ] 点击"一键生成",对话框流式输出完整方案
|
||||
- [ ] 点击"导出 Word",下载格式正确的 docx 文件
|
||||
- [ ] 输入"修改样本量",AI 只重新生成该章节
|
||||
- [ ] Word 文档符合伦理委员会格式要求
|
||||
|
||||
### 性能指标
|
||||
|
||||
| 指标 | 目标 |
|
||||
|------|------|
|
||||
| 摘要生成时间 | < 30秒 |
|
||||
| 完整方案生成时间 | < 3分钟 |
|
||||
| 自动保存延迟 | < 1秒 |
|
||||
| Word导出时间 | < 5秒 |
|
||||
| 完整方案生成时间 | < 2 分钟 |
|
||||
| Word 导出时间 | < 5 秒 |
|
||||
| 章节修改响应时间 | < 30 秒 |
|
||||
|
||||
---
|
||||
|
||||
## 九、后续迭代
|
||||
## 九、Word 模板设计
|
||||
|
||||
- **v1.1**: 方案模板库(不同研究类型)
|
||||
- **v1.2**: 多人协作编辑
|
||||
- **v1.3**: 方案审核流程
|
||||
- **v1.4**: 与伦理系统对接
|
||||
### 格式要求(伦理委员会标准)
|
||||
|
||||
```
|
||||
字体:正文宋体小四,标题黑体三号
|
||||
行距:1.5 倍
|
||||
页边距:上下 2.54cm,左右 3.17cm
|
||||
页眉:研究方案 + 版本号
|
||||
页脚:页码
|
||||
```
|
||||
|
||||
### Reference Doc 制作
|
||||
|
||||
1. 在 Word 中创建符合格式的模板文档
|
||||
2. 定义样式:标题1、标题2、正文、表格等
|
||||
3. 保存为 `protocol_template.docx`
|
||||
4. 放置到 `python-service/app/services/assets/`
|
||||
|
||||
---
|
||||
|
||||
## 十、参考文档
|
||||
## 十、后续迭代
|
||||
|
||||
- [Novel GitHub](https://github.com/steven-tey/novel)
|
||||
- [Tiptap 官方文档](https://tiptap.dev/)
|
||||
- [编辑器选型深度评估](./编辑器选型深度评估与落地建议.md)
|
||||
- [Novel vs BlockNote 对比分析](./Novel_vs_BlockNote_深度对比分析.md)
|
||||
### v1.1:编辑器增强(可选)
|
||||
如果用户反馈需要更直接的编辑体验:
|
||||
- 引入 Novel/Tiptap 编辑器
|
||||
- 支持实时编辑 + AI 辅助
|
||||
|
||||
### v1.2:模板库
|
||||
- 不同研究类型的方案模板
|
||||
- RCT、队列研究、病例对照等
|
||||
|
||||
### v1.3:协作与审核
|
||||
- 多人协作编辑
|
||||
- 方案审核流程
|
||||
- 与伦理系统对接
|
||||
|
||||
---
|
||||
|
||||
## 十一、参考文档
|
||||
|
||||
- [基于对话流的文档生成技术方案](./基于对话流的文档生成与导出技术方案.md)
|
||||
- [编辑器选型深度评估](./编辑器选型深度评估与落地建议.md)(备选方案)
|
||||
- [Novel vs BlockNote 对比分析](./Novel_vs_BlockNote_深度对比分析.md)(备选方案)
|
||||
|
||||
---
|
||||
|
||||
**文档更新记录**:
|
||||
- 2026-01-24 v1.0: 初始版本(技术选型:Tiptap/BlockNote)
|
||||
- 2026-01-24 v1.1: 技术选型改为 **Novel (Fork)**,更新开发计划
|
||||
- 2026-01-24 v1.1: 技术选型改为 Novel (Fork)
|
||||
- 2026-01-25 v2.0: **重大调整:采用无编辑器方案**,优先实现对话流生成 + Word 导出
|
||||
|
||||
349
docs/03-业务模块/AIA-AI智能问答/04-开发计划/06-一键生成研究方案开发计划V2.md
Normal file
349
docs/03-业务模块/AIA-AI智能问答/04-开发计划/06-一键生成研究方案开发计划V2.md
Normal file
@@ -0,0 +1,349 @@
|
||||
# 一键生成研究方案 - 开发计划 V2
|
||||
|
||||
> **版本**: 2.0
|
||||
> **日期**: 2026-01-25
|
||||
> **状态**: 规划中
|
||||
> **前置依赖**: Pandoc Word 导出已完成 ✅
|
||||
|
||||
---
|
||||
|
||||
## 一、设计目标
|
||||
|
||||
### 1.1 核心理念
|
||||
|
||||
```
|
||||
"关键要素就绪 → 一键生成方案"
|
||||
```
|
||||
|
||||
**解耦设计**:方案生成功能**不依赖** AI 对话流程。无论用户通过 AI 对话收集要素,还是手动填写要素,只要必填项完成即可生成。
|
||||
|
||||
### 1.2 用户场景
|
||||
|
||||
| 场景 | 用户行为 | 系统响应 |
|
||||
|------|---------|---------|
|
||||
| **场景 A** | 用户通过 AI 对话完成 5 阶段 | 自动提示可生成,点击生成 |
|
||||
| **场景 B** | 用户手动填写关键要素 | 校验通过后,直接点击生成 |
|
||||
| **场景 C** | 用户对生成内容不满意 | 针对某章节"讨论与优化" |
|
||||
|
||||
### 1.3 必填要素校验
|
||||
|
||||
| 要素 | 是否必填 | 说明 |
|
||||
|------|---------|------|
|
||||
| 科学问题 | ✅ 必填 | 方案的核心目的 |
|
||||
| PICO | ✅ 必填 | 研究框架基础 |
|
||||
| 研究设计 | ✅ 必填 | 决定方案结构 |
|
||||
| 观察指标 | ✅ 必填 | 结局评价依据 |
|
||||
| 样本量 | ⚪ 可选 | 可后续补充 |
|
||||
|
||||
**校验规则**:4/5 必填项完成 → 可生成基础方案
|
||||
|
||||
---
|
||||
|
||||
## 二、UI 架构设计
|
||||
|
||||
### 2.1 双阶段动态布局
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Protocol Agent Page │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ 阶段 A: 要素收集期 │
|
||||
│ ┌─────────────────────────┬───────────────────────────┐ │
|
||||
│ │ ChatPanel │ ContextPanel │ │
|
||||
│ │ 65% │ 35% │ │
|
||||
│ │ │ ┌───────────────────┐ │ │
|
||||
│ │ [AI 对话区域] │ │ 科学问题 [✓][✏️] │ │ │
|
||||
│ │ │ │ PICO [✓][✏️] │ │ │
|
||||
│ │ │ │ 研究设计 [✓][✏️] │ │ │
|
||||
│ │ │ │ 样本量 [○] │ │ │
|
||||
│ │ │ │ 观察指标 [✓][✏️] │ │ │
|
||||
│ │ │ ├───────────────────┤ │ │
|
||||
│ │ │ │ 进度: 80% (4/5) │ │ │
|
||||
│ │ │ │ [✨ 一键生成方案] │ │ │
|
||||
│ │ │ │ [📥 导出 Word] │ │ │
|
||||
│ │ │ └───────────────────┘ │ │
|
||||
│ └─────────────────────────┴───────────────────────────┘ │
|
||||
│ ↕ 拖拽手柄 │
|
||||
│ │
|
||||
│ 阶段 B: 方案生成期 │
|
||||
│ ┌───────────────────┬─────────────────────────────────┐ │
|
||||
│ │ ChatPanel │ DocumentPanel │ │
|
||||
│ │ 35% │ 65% │ │
|
||||
│ │ │ ┌─────────────────────────┐ │ │
|
||||
│ │ [正在撰写...] │ │ [复制] [导出 Word] │ │ │
|
||||
│ │ 1. 研究背景 ✓ │ ├─────────────────────────┤ │ │
|
||||
│ │ 2. 研究目的 ✓ │ │ │ │ │
|
||||
│ │ 3. 研究设计 ⟳ │ │ ══ A4 文档预览 ══ │ │ │
|
||||
│ │ │ │ │ │ │
|
||||
│ │ [修改指令输入] │ │ 1. 研究背景 │ │ │
|
||||
│ │ │ │ [讨论与优化] │ │ │
|
||||
│ │ │ │ 内容... │ │ │
|
||||
│ │ │ │ │ │ │
|
||||
│ │ │ │ 2. 研究目的 │ │ │
|
||||
│ │ │ │ [讨论与优化] │ │ │
|
||||
│ │ │ │ 内容... │ │ │
|
||||
│ │ │ │ │ │ │
|
||||
│ └───────────────────┴─────────────────────────────────┘ │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 2.2 视图切换机制
|
||||
|
||||
```typescript
|
||||
type ViewMode = 'context' | 'document';
|
||||
|
||||
// 切换条件
|
||||
const shouldSwitchToDocument = (event: string) => {
|
||||
return event === 'GENERATION_STARTED';
|
||||
};
|
||||
|
||||
// 布局比例
|
||||
const LAYOUT_RATIO = {
|
||||
context: { chat: 65, right: 35 },
|
||||
document: { chat: 35, right: 65 },
|
||||
};
|
||||
```
|
||||
|
||||
### 2.3 视图切换按钮
|
||||
|
||||
顶部 Header 区域添加视图切换:
|
||||
```
|
||||
[视图: 关键要素] [视图: 完整方案]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 三、功能模块详细设计
|
||||
|
||||
### 3.1 ContextPanel (要素面板) - 已有,需增强
|
||||
|
||||
**现有功能**:
|
||||
- ✅ 五阶段卡片展示
|
||||
- ✅ 完成状态编辑按钮
|
||||
- ✅ 导出 Word 按钮
|
||||
|
||||
**需新增**:
|
||||
1. **一键生成按钮位置调整**:移到面板顶部醒目位置
|
||||
2. **生成条件提示**:显示 `已完成 4/5 必填项,可生成方案`
|
||||
3. **手动添加要素入口**:未完成阶段也显示 [➕ 添加] 按钮
|
||||
|
||||
### 3.2 DocumentPanel (文档面板) - 新增
|
||||
|
||||
**核心功能**:
|
||||
- A4 纸张预览效果(宋体、首行缩进、分节标题)
|
||||
- 流式输出 + 打字机光标
|
||||
- 分章节"讨论与优化"按钮
|
||||
- 顶部工具栏:复制、导出 Word
|
||||
|
||||
**章节结构**:
|
||||
```markdown
|
||||
# 研究方案标题
|
||||
|
||||
## 1. 研究背景 (Background)
|
||||
## 2. 研究目的 (Objectives)
|
||||
## 3. 研究设计 (Study Design)
|
||||
## 4. 研究对象 (Subjects)
|
||||
## 5. 样本量估算 (Sample Size)
|
||||
## 6. 研究实施步骤 (Implementation)
|
||||
## 7. 观察指标 (Endpoints)
|
||||
## 8. 数据管理与质量控制
|
||||
## 9. 统计分析计划
|
||||
## 10. 伦理与知情同意
|
||||
## 11. 研究时间表
|
||||
## 12. 参考文献
|
||||
```
|
||||
|
||||
### 3.3 "讨论与优化" 功能
|
||||
|
||||
**交互流程**:
|
||||
1. 用户点击某章节的 [讨论与优化] 按钮
|
||||
2. 左侧 Chat 自动切换到"章节讨论模式"
|
||||
3. AI 理解上下文,针对该章节进行对话
|
||||
4. 用户可发送修改建议
|
||||
5. AI 重新生成该章节内容
|
||||
6. 右侧文档实时更新
|
||||
|
||||
**技术实现**:
|
||||
```typescript
|
||||
interface SectionContext {
|
||||
sectionId: string; // 如 'background', 'objectives'
|
||||
sectionTitle: string; // 如 '研究背景'
|
||||
currentContent: string; // 当前内容
|
||||
conversationMode: 'section'; // 章节讨论模式
|
||||
}
|
||||
```
|
||||
|
||||
### 3.4 动态布局组件
|
||||
|
||||
```typescript
|
||||
// ResizableSplitPane.tsx
|
||||
interface ResizableSplitPaneProps {
|
||||
defaultRatio: number; // 默认比例 (0-100)
|
||||
minRatio: number; // 最小比例
|
||||
maxRatio: number; // 最大比例
|
||||
onRatioChange: (ratio: number) => void;
|
||||
leftPanel: React.ReactNode;
|
||||
rightPanel: React.ReactNode;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 四、开发计划 (分阶段)
|
||||
|
||||
### Phase 1: 核心功能 MVP (5天)
|
||||
|
||||
| 天数 | 任务 | 交付物 |
|
||||
|------|------|--------|
|
||||
| Day 1 | 动态布局组件 | `ResizableSplitPane` + 视图切换按钮 |
|
||||
| Day 2 | DocumentPanel 基础 | A4 预览 + 流式渲染 + 打字机效果 |
|
||||
| Day 3 | 生成 API 对接 | 分章节流式生成 + 前后端联调 |
|
||||
| Day 4 | 生成按钮 & 校验 | 必填项校验 + 双位置生成按钮 |
|
||||
| Day 5 | 集成测试 & Bug Fix | 端到端测试 |
|
||||
|
||||
**Phase 1 交付标准**:
|
||||
- [x] 用户可从 ContextPanel 点击生成
|
||||
- [x] 方案在 DocumentPanel 流式展示
|
||||
- [x] 布局可根据阶段自动切换
|
||||
- [x] Word 导出功能正常
|
||||
|
||||
### Phase 2: "讨论与优化" (3天)
|
||||
|
||||
| 天数 | 任务 | 交付物 |
|
||||
|------|------|--------|
|
||||
| Day 6 | 章节按钮 UI | 每个章节显示 [讨论与优化] 按钮 |
|
||||
| Day 7 | 章节对话模式 | Chat 切换到章节讨论模式 + API |
|
||||
| Day 8 | 章节重新生成 | 单章节流式更新 + 文档同步 |
|
||||
|
||||
**Phase 2 交付标准**:
|
||||
- [x] 用户点击章节按钮,左侧进入讨论模式
|
||||
- [x] AI 理解当前章节上下文
|
||||
- [x] 重新生成的内容替换原章节
|
||||
|
||||
### Phase 3: 体验优化 (2天)
|
||||
|
||||
| 天数 | 任务 | 交付物 |
|
||||
|------|------|--------|
|
||||
| Day 9 | 手动添加要素 | 未完成阶段的 [➕ 添加] 入口 |
|
||||
| Day 10 | 拖拽 & 记忆 | 拖拽手柄 + localStorage 记忆比例 |
|
||||
|
||||
---
|
||||
|
||||
## 五、技术要点
|
||||
|
||||
### 5.1 流式渲染方案
|
||||
|
||||
```typescript
|
||||
// 使用现有 useAIStream hook
|
||||
const { streamingContent, isStreaming } = useAIStream({
|
||||
onChunk: (chunk) => {
|
||||
// 实时更新 DocumentPanel
|
||||
updateDocumentContent(chunk);
|
||||
},
|
||||
onComplete: (fullContent) => {
|
||||
// 保存完整方案
|
||||
saveProtocol(fullContent);
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### 5.2 章节解析
|
||||
|
||||
```typescript
|
||||
// 将流式 Markdown 解析为章节
|
||||
const parseMarkdownSections = (markdown: string): Section[] => {
|
||||
const sections: Section[] = [];
|
||||
const regex = /^## (\d+)\. (.+)$/gm;
|
||||
// ... 解析逻辑
|
||||
return sections;
|
||||
};
|
||||
```
|
||||
|
||||
### 5.3 状态管理
|
||||
|
||||
```typescript
|
||||
interface ProtocolGenerationState {
|
||||
viewMode: 'context' | 'document';
|
||||
layoutRatio: number;
|
||||
generationStatus: 'idle' | 'generating' | 'completed';
|
||||
currentSection: string | null; // 当前讨论的章节
|
||||
sections: Section[];
|
||||
canGenerate: boolean; // 基于必填项校验
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 六、文件结构
|
||||
|
||||
```
|
||||
frontend-v2/src/modules/aia/protocol-agent/
|
||||
├── components/
|
||||
│ ├── ProtocolAgentPage.tsx # 主页面 (修改)
|
||||
│ ├── ChatPanel.tsx # 聊天面板 (已有)
|
||||
│ ├── StatePanel.tsx # 要素面板 (修改)
|
||||
│ ├── DocumentPanel.tsx # 文档面板 (新增)
|
||||
│ ├── ResizableSplitPane.tsx # 可拖拽分栏 (新增)
|
||||
│ ├── SectionRenderer.tsx # 章节渲染器 (新增)
|
||||
│ └── ViewSwitcher.tsx # 视图切换器 (新增)
|
||||
├── hooks/
|
||||
│ ├── useProtocolGeneration.ts # 方案生成 hook (新增)
|
||||
│ └── useLayoutRatio.ts # 布局比例 hook (新增)
|
||||
├── styles/
|
||||
│ ├── protocol-agent.css # 主样式 (修改)
|
||||
│ └── document-panel.css # 文档面板样式 (新增)
|
||||
└── types/
|
||||
└── index.ts # 类型定义 (修改)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 七、风险与应对
|
||||
|
||||
| 风险 | 影响 | 应对措施 |
|
||||
|------|------|---------|
|
||||
| 长文档流式渲染性能 | 卡顿 | 虚拟滚动 + 分片渲染 |
|
||||
| 章节解析复杂性 | 解析错误 | 规范化 Markdown 模板 |
|
||||
| 布局切换体验 | 突兀 | CSS transition 平滑过渡 |
|
||||
|
||||
---
|
||||
|
||||
## 八、验收标准
|
||||
|
||||
### MVP (Phase 1)
|
||||
|
||||
- [ ] 4/5 必填项完成后,生成按钮可点击
|
||||
- [ ] 点击生成后,自动切换到文档视图 (35:65)
|
||||
- [ ] 文档以 A4 纸样式流式展示
|
||||
- [ ] 生成完成后可导出 Word
|
||||
|
||||
### 完整版 (Phase 1+2+3)
|
||||
|
||||
- [ ] 每个章节有"讨论与优化"按钮
|
||||
- [ ] 章节可单独重新生成
|
||||
- [ ] 未完成阶段可手动添加要素
|
||||
- [ ] 布局比例可拖拽调整并记忆
|
||||
|
||||
---
|
||||
|
||||
## 九、附录
|
||||
|
||||
### A. 参考原型
|
||||
|
||||
- `AIclinicalresearch/docs/03-业务模块/AIA-AI智能问答/00-系统设计/研究方案一键生成.html`
|
||||
|
||||
### B. 相关文档
|
||||
|
||||
- `UI_Layout_Ratio_Analysis.md` - 布局比例分析
|
||||
- `基于对话流的文档生成与导出技术方案.md` - 技术方案
|
||||
|
||||
### C. 已完成依赖
|
||||
|
||||
- ✅ Pandoc 系统安装 (3.8.3)
|
||||
- ✅ pypandoc Python 包
|
||||
- ✅ Python `/api/convert/docx` 端点
|
||||
- ✅ Node.js `ProtocolExportService`
|
||||
- ✅ 前端导出按钮
|
||||
|
||||
110
docs/03-业务模块/AIA-AI智能问答/04-开发计划/Novel_CRF_Extension_Guide.md
Normal file
110
docs/03-业务模块/AIA-AI智能问答/04-开发计划/Novel_CRF_Extension_Guide.md
Normal file
@@ -0,0 +1,110 @@
|
||||
# **基于 Novel (Tiptap) 的 CRF 表单扩展开发指南**
|
||||
|
||||
**目标**: 在编辑器中实现 "填空"、"单选"、"日期选择" 等 CRF 控件,并支持导出 Word。
|
||||
|
||||
## **1\. 自定义 CRF 节点开发 (Tiptap Extensions)**
|
||||
|
||||
我们需要开发一组 **Node Extensions**,让编辑器理解表单元素。
|
||||
|
||||
### **1.1 填空输入框 (UnderlineInput)**
|
||||
|
||||
// extensions/underline-input.tsx
|
||||
import { Node, mergeAttributes } from '@tiptap/core';
|
||||
import { ReactNodeViewRenderer, NodeViewWrapper } from '@tiptap/react';
|
||||
|
||||
export const UnderlineInput \= Node.create({
|
||||
name: 'underlineInput',
|
||||
group: 'inline',
|
||||
inline: true,
|
||||
atom: true, // 作为一个整体,不可分割
|
||||
|
||||
addAttributes() {
|
||||
return {
|
||||
placeholder: { default: '请输入...' },
|
||||
value: { default: '' },
|
||||
}
|
||||
},
|
||||
|
||||
parseHTML() {
|
||||
return \[{ tag: 'span\[data-type="input"\]' }\]
|
||||
},
|
||||
|
||||
renderHTML({ HTMLAttributes }) {
|
||||
return \['span', mergeAttributes(HTMLAttributes, { 'data-type': 'input' })\]
|
||||
},
|
||||
|
||||
// React 组件渲染
|
||||
addNodeView() {
|
||||
return ReactNodeViewRenderer(({ node, updateAttributes }) \=\> {
|
||||
return (
|
||||
\<NodeViewWrapper as="span" className="inline-block mx-1"\>
|
||||
\<input
|
||||
className="border-b border-black outline-none px-1 w-24 bg-transparent text-center focus:border-blue-500"
|
||||
placeholder={node.attrs.placeholder}
|
||||
value={node.attrs.value}
|
||||
onChange={(e) \=\> updateAttributes({ value: e.target.value })}
|
||||
/\>
|
||||
\</NodeViewWrapper\>
|
||||
)
|
||||
})
|
||||
},
|
||||
});
|
||||
|
||||
### **1.2 单选组 (RadioGroup)**
|
||||
|
||||
// extensions/radio-group.tsx
|
||||
// 类似逻辑,渲染一组 radio buttons
|
||||
|
||||
## **2\. AI 生成与解析策略**
|
||||
|
||||
如何让 AI 生成这些控件?我们约定一套 **"占位符语法"**。
|
||||
|
||||
* **Prompt**: "生成一个性别选择项,包含男、女。"
|
||||
* **AI Output**: 性别: {{radio:男,女}}
|
||||
* **前端解析 (Replacement Logic)**:
|
||||
|
||||
// 在 useAIStream 的 onStream 更新中
|
||||
const parseContent \= (text) \=\> {
|
||||
// 正则替换
|
||||
if (text.includes('{{input}}')) {
|
||||
editor.chain().focus().insertContent({ type: 'underlineInput' }).run();
|
||||
}
|
||||
// ...
|
||||
};
|
||||
|
||||
## **3\. Word 导出逻辑 (docx.js)**
|
||||
|
||||
针对自定义节点的导出映射。
|
||||
|
||||
// utils/export-docx.ts
|
||||
import { TextRun, UnderlineType } from "docx";
|
||||
|
||||
export const transformNode \= (node) \=\> {
|
||||
switch (node.type) {
|
||||
|
||||
// 导出填空框 \-\> 带下划线的空格
|
||||
case 'underlineInput':
|
||||
return new TextRun({
|
||||
text: node.attrs.value || " ", // 有值填值,无值填空格
|
||||
underline: {
|
||||
type: UnderlineType.SINGLE,
|
||||
},
|
||||
});
|
||||
|
||||
// 导出复选框 \-\> 特殊字符
|
||||
case 'taskItem':
|
||||
const isChecked \= node.attrs.checked;
|
||||
return new TextRun({
|
||||
text: isChecked ? "☑ " : "☐ ", // Unicode 字符
|
||||
font: "Arial Unicode MS", // 确保字体支持
|
||||
});
|
||||
|
||||
// ... 其他节点
|
||||
}
|
||||
};
|
||||
|
||||
## **4\. 总结**
|
||||
|
||||
Novel (Tiptap) 完全有能力承载 CRF 的需求。
|
||||
|
||||
虽然这需要一些 **"Extension 开发"** 的工作量,但相比自己从头写一个 Form Builder,这是性价比最高的方案,而且还能保持文档的流式阅读体验。
|
||||
105
docs/03-业务模块/AIA-AI智能问答/04-开发计划/基于对话流的文档生成与导出技术方案.md
Normal file
105
docs/03-业务模块/AIA-AI智能问答/04-开发计划/基于对话流的文档生成与导出技术方案.md
Normal file
@@ -0,0 +1,105 @@
|
||||
# **基于对话流的文档生成与导出技术方案**
|
||||
|
||||
**核心策略**: No-Editor (无编辑器模式)
|
||||
|
||||
**目标**: 在 Chat 界面完成方案生成与修改,后端直接合成 Word 下载。
|
||||
|
||||
## **1\. 业务流程 (User Flow)**
|
||||
|
||||
sequenceDiagram
|
||||
participant User
|
||||
participant ChatUI
|
||||
participant Agent (Node.js)
|
||||
participant PandocSvc (Python)
|
||||
|
||||
User-\>\>ChatUI: "生成完整方案"
|
||||
ChatUI-\>\>Agent: POST /generate
|
||||
Agent--\>\>ChatUI: Stream Markdown ("\# 1\. 研究背景...")
|
||||
|
||||
User-\>\>ChatUI: "把样本量部分改一下..."
|
||||
ChatUI-\>\>Agent: POST /regenerate
|
||||
Agent--\>\>ChatUI: Stream Updated Markdown
|
||||
|
||||
User-\>\>ChatUI: 点击 \[📥 导出 Word\]
|
||||
ChatUI-\>\>Agent: POST /export/docx { markdown }
|
||||
Agent-\>\>PandocSvc: Convert(markdown, reference.docx)
|
||||
PandocSvc--\>\>Agent: Buffer (Binary)
|
||||
Agent--\>\>ChatUI: Blob (Download)
|
||||
|
||||
## **2\. 核心技术实现**
|
||||
|
||||
### **2.1 Python 微服务:Pandoc 转换器**
|
||||
|
||||
利用你们现有的 Python 微服务,集成 pypandoc。
|
||||
|
||||
**Dockerfile 增加依赖:**
|
||||
|
||||
RUN apt-get update && apt-get install \-y pandoc
|
||||
|
||||
**Service 代码 (python-service/app/services/doc\_service.py):**
|
||||
|
||||
import pypandoc
|
||||
import os
|
||||
|
||||
def convert\_md\_to\_docx(markdown\_text: str, output\_path: str):
|
||||
\# 使用参考文档 (Reference Doc) 来控制样式(字体、字号、页眉)
|
||||
reference\_doc \= os.path.join(os.path.dirname(\_\_file\_\_), 'assets/style\_template.docx')
|
||||
|
||||
pypandoc.convert\_text(
|
||||
markdown\_text,
|
||||
'docx',
|
||||
format='markdown',
|
||||
outputfile=output\_path,
|
||||
extra\_args=\[f'--reference-doc={reference\_doc}'\]
|
||||
)
|
||||
|
||||
### **2.2 Node.js 后端:导出 API**
|
||||
|
||||
// backend/src/modules/aia/controllers/exportController.ts
|
||||
|
||||
export const exportToWord \= async (req, reply) \=\> {
|
||||
const { markdown } \= req.body;
|
||||
|
||||
// 1\. 调用 Python 微服务
|
||||
const response \= await pythonService.post('/convert/docx', { content: markdown }, { responseType: 'arraybuffer' });
|
||||
|
||||
// 2\. 返回文件流
|
||||
reply.header('Content-Type', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document');
|
||||
reply.header('Content-Disposition', 'attachment; filename="protocol.docx"');
|
||||
return reply.send(response.data);
|
||||
};
|
||||
|
||||
### **2.3 前端:Chat 组件增强**
|
||||
|
||||
在 AIStreamChat 的消息组件中,增加导出按钮。
|
||||
|
||||
// frontend-v2/src/shared/components/Chat/MessageBubble.tsx
|
||||
|
||||
const MessageBubble \= ({ content, role }) \=\> {
|
||||
const handleDownload \= async () \=\> {
|
||||
const blob \= await api.post('/aia/export/docx', { markdown: content }, { responseType: 'blob' });
|
||||
saveAs(blob, '研究方案.docx');
|
||||
};
|
||||
|
||||
return (
|
||||
\<div className="message-bubble"\>
|
||||
\<Markdown\>{content}\</Markdown\>
|
||||
|
||||
{role \=== 'assistant' && (
|
||||
\<div className="toolbar"\>
|
||||
\<Button icon={\<DownloadIcon /\>} onClick={handleDownload}\>
|
||||
导出 Word
|
||||
\</Button\>
|
||||
\</div\>
|
||||
)}
|
||||
\</div\>
|
||||
);
|
||||
};
|
||||
|
||||
## **3\. 方案优势总结**
|
||||
|
||||
1. **格式完美**:通过 Pandoc 的 Reference Doc,可以保证导出的 Word 完全符合医院的格式要求(如宋体小四、行间距等),这是前端编辑器很难做到的。
|
||||
2. **开发极快**:不需要处理 Tiptap 的状态管理、协同冲突、光标位置等复杂问题。
|
||||
3. **符合直觉**:用户习惯在 Word 里做最后的精修。
|
||||
|
||||
**结论:** 这是一个非常务实且高效的决策。我们可以先不上编辑器,把精力花在 **AI 生成内容的质量** 和 **Word 导出的样式** 上。
|
||||
@@ -201,3 +201,4 @@ export type AgentStage = 'topic' | 'design' | 'review' | 'data' | 'writing';
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -291,3 +291,4 @@ POST /api/v1/aia/protocol-agent/generation/:id/export 导出Word
|
||||
|
||||
**预计交付时间**:Week 5(1周后)
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,352 @@
|
||||
# Protocol Agent MVP 完整交付记录
|
||||
|
||||
> 日期:2026-01-25
|
||||
> 开发者:AI Assistant
|
||||
> 状态:🎉 **MVP 完整交付**
|
||||
> 里程碑:**研究方案制定Agent + 一键生成研究方案 + Word导出**
|
||||
|
||||
---
|
||||
|
||||
## 📋 开发概述
|
||||
|
||||
在 2026-01-24 完成 Agent 框架基础后,今天完成了**一键生成研究方案**功能的全部开发工作,实现了从关键要素收集到完整研究方案输出的全流程,并解决了大量测试中发现的问题。
|
||||
|
||||
**这是一个重要的里程碑**:Protocol Agent MVP 已完整可用!
|
||||
|
||||
---
|
||||
|
||||
## 🎯 今日完成的功能
|
||||
|
||||
### 一、一键生成研究方案(核心功能)
|
||||
|
||||
#### 1. 动态双面板布局
|
||||
|
||||
| 功能 | 实现 |
|
||||
|------|------|
|
||||
| **ResizableSplitPane** | 可拖拽调整左右面板宽度 |
|
||||
| **ViewSwitcher** | "研究摘要" / "完整方案" 切换 |
|
||||
| **DocumentPanel** | A4 纸张预览效果 |
|
||||
| **动态比例** | 收集要素 65:35,生成方案 35:65 |
|
||||
|
||||
#### 2. 研究方案生成
|
||||
|
||||
| 功能 | 实现 |
|
||||
|------|------|
|
||||
| **流式生成** | SSE 实时输出,打字机效果 |
|
||||
| **Markdown渲染** | 自定义 MarkdownContent 组件 |
|
||||
| **章节滚动** | 生成时自动滚动跟随 |
|
||||
| **12章节结构** | 完整临床研究方案结构 |
|
||||
|
||||
#### 3. Word 文档导出
|
||||
|
||||
| 组件 | 技术 | 状态 |
|
||||
|------|------|------|
|
||||
| Python 微服务 | pypandoc + Pandoc | ✅ |
|
||||
| Node.js API | `/export/docx` 端点 | ✅ |
|
||||
| 前端下载 | Blob + download | ✅ |
|
||||
|
||||
---
|
||||
|
||||
### 二、用户体验优化(大量细节)
|
||||
|
||||
#### 滚动问题修复
|
||||
- 🔧 添加 `min-height: 0` 到所有 flex 容器
|
||||
- 🔧 自定义滚动条样式(更宽、更可见)
|
||||
- 🔧 Firefox 兼容性处理
|
||||
|
||||
#### UI/UX 改进
|
||||
|
||||
| 问题 | 解决方案 |
|
||||
|------|----------|
|
||||
| 关键要素 → 研究摘要 | 重命名更准确 |
|
||||
| 顶部标题两行 | CSS flex-direction: row !important |
|
||||
| 欢迎语占满屏 | 精简内容 + 减少间距 |
|
||||
| 列表编号1,1,1 | CSS list-style-type: decimal |
|
||||
| 侧边栏按钮过长 | 紧凑设计 + 文字精简 |
|
||||
|
||||
#### StatePanel 优化
|
||||
|
||||
| 阶段 | 优化内容 |
|
||||
|------|----------|
|
||||
| 科学问题 | 可折叠显示,完整内容 |
|
||||
| PICO | 四要素分行,可折叠 |
|
||||
| 样本量 | 显示计算过程、参数、分组 |
|
||||
| 观察指标 | 基线/暴露/结局/混杂完整展示 |
|
||||
|
||||
**CollapsibleContent 组件**:
|
||||
- 默认显示预览(2-3行)
|
||||
- 渐变遮罩效果
|
||||
- "展开全部"按钮
|
||||
- 各阶段不同预览高度
|
||||
|
||||
---
|
||||
|
||||
### 三、Prompt 工程优化
|
||||
|
||||
#### 阶段指引 Prompt 增强
|
||||
|
||||
```typescript
|
||||
// 新增 STAGE_ORDER 常量和 getStageInstructions 方法
|
||||
// 明确当前阶段任务,严禁讨论已完成或未来阶段
|
||||
```
|
||||
|
||||
**解决问题**:模型在"观察指标"阶段误讨论"样本量计算"
|
||||
|
||||
#### 数据凝练 Prompt 放宽
|
||||
|
||||
| 阶段 | 调整 |
|
||||
|------|------|
|
||||
| 科学问题 | 100-200字(原50字) |
|
||||
| PICO | 每项50-100字(原20字) |
|
||||
| 样本量 | 包含计算过程、参数、分组 |
|
||||
| 观察指标 | 完整定义、测量方法、时间点 |
|
||||
|
||||
#### 方案生成 Prompt
|
||||
|
||||
- 移除 LLM 开场白("好的,作为一名资深...")
|
||||
- 12章节结构化输出
|
||||
- 基于关键要素动态生成标题
|
||||
|
||||
---
|
||||
|
||||
### 四、对话历史管理
|
||||
|
||||
#### 延迟创建模式
|
||||
|
||||
```
|
||||
点击"新建对话" → 导航到 /new(不创建记录)
|
||||
↓
|
||||
发送第一条消息 → 创建对话 + 发送消息
|
||||
↓
|
||||
对话出现在历史列表中
|
||||
```
|
||||
|
||||
**优势**:避免空对话污染历史列表(类似 ChatGPT)
|
||||
|
||||
#### 标题自动更新
|
||||
|
||||
- 首条消息前20字符作为对话标题
|
||||
- PATCH API 更新数据库
|
||||
|
||||
#### API 完善
|
||||
|
||||
| 端点 | 功能 |
|
||||
|------|------|
|
||||
| `GET /conversations?agentId=PROTOCOL_AGENT` | 过滤获取 |
|
||||
| `PATCH /conversations/:id` | 更新标题 |
|
||||
| `GET /messages/:conversationId` | 获取历史消息 |
|
||||
|
||||
---
|
||||
|
||||
### 五、Bug 修复
|
||||
|
||||
| 问题 | 原因 | 解决方案 |
|
||||
|------|------|----------|
|
||||
| TypeError: .map is not a function | 后端返回字符串而非数组 | `toArray()` 辅助函数 |
|
||||
| 页面无法滚动 | flex 子元素未设 min-height | 添加 `min-height: 0` |
|
||||
| Word 导出内容不全 | 传递的是模板而非生成内容 | 修改为传递实际内容 |
|
||||
| "Table of Contents" 出现 | Pandoc --toc 参数 | 移除 toc 参数 |
|
||||
| 模型讨论错误阶段 | Prompt 约束不足 | 增强阶段指引 |
|
||||
|
||||
---
|
||||
|
||||
## 📊 代码变更统计
|
||||
|
||||
### 新增/修改文件
|
||||
|
||||
| 类别 | 文件 | 变更 |
|
||||
|------|------|------|
|
||||
| **前端组件** | | |
|
||||
| | ResizableSplitPane.tsx | 新增 ~150行 |
|
||||
| | ViewSwitcher.tsx | 新增 ~50行 |
|
||||
| | DocumentPanel.tsx | 新增 ~335行 |
|
||||
| | MarkdownContent.tsx | 新增 ~200行 |
|
||||
| | CollapsibleContent(StageCard内) | 新增 ~100行 |
|
||||
| **前端 Hooks** | | |
|
||||
| | useProtocolGeneration.ts | 新增 ~261行 |
|
||||
| | useProtocolConversations.ts | 修改 +60行 |
|
||||
| **前端样式** | | |
|
||||
| | protocol-agent.css | 修改 +800行(共2500行) |
|
||||
| **后端服务** | | |
|
||||
| | ProtocolExportService.ts | 新增 ~100行 |
|
||||
| | ProtocolAgentController.ts | 修改 +200行 |
|
||||
| | ProtocolOrchestrator.ts | 修改 +100行 |
|
||||
| **Python 微服务** | | |
|
||||
| | doc_export_service.py | 新增 ~80行 |
|
||||
| | main.py | 修改 +30行 |
|
||||
|
||||
### 代码总量
|
||||
|
||||
| 模块 | 今日新增 | 累计 |
|
||||
|------|----------|------|
|
||||
| 前端 | ~1,200行 | ~3,300行 |
|
||||
| 后端 | ~400行 | ~4,700行 |
|
||||
| Python | ~110行 | ~500行 |
|
||||
| **总计** | **~1,700行** | **~8,500行** |
|
||||
|
||||
---
|
||||
|
||||
## 🧪 测试验证
|
||||
|
||||
### 功能测试
|
||||
|
||||
| 测试项 | 状态 |
|
||||
|--------|------|
|
||||
| 5阶段对话流程 | ✅ |
|
||||
| 数据同步到状态面板 | ✅ |
|
||||
| 样本量可选跳过 | ✅ |
|
||||
| 一键生成研究方案 | ✅ |
|
||||
| 生成时滚动跟随 | ✅ |
|
||||
| Word 导出下载 | ✅ |
|
||||
| 对话历史保存 | ✅ |
|
||||
| 新建对话清空界面 | ✅ |
|
||||
| 延迟创建(无空记录) | ✅ |
|
||||
| StatePanel 折叠展开 | ✅ |
|
||||
|
||||
### 已知问题(已解决)
|
||||
|
||||
- ✅ 滚动条不显示
|
||||
- ✅ 顶部标题两行
|
||||
- ✅ 欢迎语空间过大
|
||||
- ✅ 列表编号错误
|
||||
- ✅ 模型阶段混乱
|
||||
- ✅ 数据类型错误
|
||||
- ✅ 空对话保存
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ 架构亮点
|
||||
|
||||
### 1. 无编辑器方案(MVP)
|
||||
|
||||
```
|
||||
对话中收集关键要素
|
||||
↓
|
||||
一键生成 Markdown
|
||||
↓
|
||||
A4 预览 + 讨论优化
|
||||
↓
|
||||
Pandoc 转换 Word 导出
|
||||
```
|
||||
|
||||
**优势**:
|
||||
- 开发速度快(3天完成)
|
||||
- Word 格式完美
|
||||
- 符合用户习惯
|
||||
|
||||
### 2. 动态布局适配
|
||||
|
||||
```
|
||||
收集要素阶段:Chat 65% : Context 35%
|
||||
生成方案阶段:Chat 35% : Document 65%
|
||||
```
|
||||
|
||||
### 3. 延迟创建对话
|
||||
|
||||
- 点击新建不创建数据库记录
|
||||
- 首条消息时才真正创建
|
||||
- 避免空对话污染
|
||||
|
||||
---
|
||||
|
||||
## 📝 文件结构
|
||||
|
||||
```
|
||||
frontend-v2/src/modules/aia/protocol-agent/
|
||||
├── ProtocolAgentPage.tsx # 主页面(362行)
|
||||
├── components/
|
||||
│ ├── ChatArea.tsx # 聊天区域(574行)
|
||||
│ ├── StatePanel.tsx # 状态面板(198行)
|
||||
│ ├── StageCard.tsx # 阶段卡片(450行,含折叠)
|
||||
│ ├── DocumentPanel.tsx # 文档预览(335行)
|
||||
│ ├── ResizableSplitPane.tsx # 可调整面板(150行)
|
||||
│ ├── ViewSwitcher.tsx # 视图切换(50行)
|
||||
│ ├── MarkdownContent.tsx # MD渲染(200行)
|
||||
│ └── StageEditModal.tsx # 编辑弹窗
|
||||
├── hooks/
|
||||
│ ├── useProtocolContext.ts # 上下文管理
|
||||
│ ├── useProtocolConversations.ts # 对话管理(194行)
|
||||
│ └── useProtocolGeneration.ts # 生成管理(261行)
|
||||
├── styles/
|
||||
│ └── protocol-agent.css # 样式(2500行)
|
||||
└── types.ts # 类型定义
|
||||
|
||||
backend/src/modules/agent/protocol/
|
||||
├── controllers/
|
||||
│ └── ProtocolAgentController.ts # 控制器(778行)
|
||||
├── services/
|
||||
│ ├── ProtocolOrchestrator.ts # 编排器(475行)
|
||||
│ ├── ProtocolContextService.ts # 上下文服务(320行)
|
||||
│ └── ProtocolExportService.ts # 导出服务(100行)
|
||||
├── prompts/
|
||||
│ └── protocolGenerationPrompts.ts # 生成Prompt
|
||||
└── routes/
|
||||
└── index.ts # 路由(170行)
|
||||
|
||||
extraction_service/
|
||||
├── services/
|
||||
│ └── doc_export_service.py # Word导出(80行)
|
||||
└── main.py # FastAPI入口
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎉 里程碑达成
|
||||
|
||||
| 里程碑 | 状态 | 日期 |
|
||||
|--------|------|------|
|
||||
| M1: Agent框架 | ✅ | 2026-01-24 |
|
||||
| M2: 5阶段流程 | ✅ | 2026-01-24 |
|
||||
| M3: 前端UI | ✅ | 2026-01-24 |
|
||||
| **M4: 一键生成** | ✅ | **2026-01-25** |
|
||||
| **M5: Word导出** | ✅ | **2026-01-25** |
|
||||
| **MVP 完整交付** | 🎉 | **2026-01-25** |
|
||||
|
||||
---
|
||||
|
||||
## 📋 后续计划
|
||||
|
||||
### Phase 2: 章节讨论模式(可选)
|
||||
|
||||
- [ ] "讨论与优化"按钮
|
||||
- [ ] 单章节重新生成
|
||||
- [ ] 修改建议实时预览
|
||||
|
||||
### Phase 3: 手动要素补充
|
||||
|
||||
- [ ] 右侧面板手动添加入口
|
||||
- [ ] 支持跳过对话直接填写
|
||||
- [ ] 拖拽比例记忆
|
||||
|
||||
### 长期优化
|
||||
|
||||
- [ ] EKB 知识库集成
|
||||
- [ ] RAG 检索增强
|
||||
- [ ] Prompt 持续调优
|
||||
- [ ] 多语言支持
|
||||
|
||||
---
|
||||
|
||||
## 📚 相关文档
|
||||
|
||||
- [开发计划 V2](../04-开发计划/06-一键生成研究方案开发计划V2.md)
|
||||
- [无编辑器技术方案](../04-开发计划/基于对话流的文档生成与导出技术方案.md)
|
||||
- [UI布局比例分析](../00-系统设计/UI_Layout_Ratio_Analysis.md)
|
||||
- [Protocol Agent 架构设计](../04-开发计划/04-Protocol_Agent开发计划/01-架构设计.md)
|
||||
|
||||
---
|
||||
|
||||
## 🏆 技术总结
|
||||
|
||||
1. **Pandoc 集成**:通过 Python 微服务实现高质量 Word 导出
|
||||
2. **流式渲染**:SSE + 自定义 Markdown 组件实现打字机效果
|
||||
3. **延迟创建**:类 ChatGPT 的对话管理体验
|
||||
4. **Prompt 工程**:阶段约束 + 数据凝练的精细化设计
|
||||
5. **响应式布局**:动态比例适配不同工作阶段
|
||||
|
||||
---
|
||||
|
||||
**MVP 已完整交付!** 🎉
|
||||
|
||||
下一步:进入生产测试和用户反馈收集阶段。
|
||||
|
||||
Reference in New Issue
Block a user