- {task.editorialScore !== undefined && (
-
-
= 80 ? 'bg-green-500' : task.editorialScore >= 60 ? 'bg-amber-500' : 'bg-red-500'}`} />
- 规范性:
- = 80 ? 'text-green-700' : task.editorialScore >= 60 ? 'text-amber-700' : 'text-red-700'}`}>
- {task.editorialScore}分
-
-
- )}
- {task.methodologyStatus && (
-
-
-
方法学:
-
- {task.methodologyStatus}
-
-
- )}
-
- );
- }
-
- return null;
- };
-
- // 渲染操作按钮
- const renderActions = (task: ReviewTask) => {
- // 待审稿:[开始审稿] [删除]
- if (task.status === 'pending') {
- return (
-
-
-
-
- );
- }
-
- // 处理中:[查看进度]
- if (['extracting', 'reviewing', 'reviewing_editorial', 'reviewing_methodology'].includes(task.status)) {
- return (
-
- );
- }
-
- // 已完成:[查看报告] [重新审稿] [删除]
- if (task.status === 'completed') {
- return (
-
-
-
-
-
- );
- }
-
- // 失败:[重新审稿] [删除]
- if (task.status === 'failed') {
- return (
-
-
-
-
- );
- }
-
- return null;
- };
-
- if (tasks.length === 0) {
- return (
-
- );
- }
-
- return (
-
-
-
-
- |
-
- |
- 文件名称 / 信息 |
- 上传时间 |
- 审稿维度 |
- 结果摘要 |
- 操作 |
-
-
-
- {tasks.map(task => (
-
- |
- toggleSelect(task.id)}
- className="rounded border-gray-300 text-indigo-600 focus:ring-indigo-500 cursor-pointer"
- />
- |
-
-
-
- {getFileIcon(task.fileName)}
-
-
- task.status === 'completed' && onViewReport(task)}
- >
- {task.fileName}
-
-
- {formatFileSize(task.fileSize)}
- {task.wordCount && (
- <>
- •
- {task.wordCount.toLocaleString()} 字
- >
- )}
-
-
-
- |
-
- {formatTime(task.createdAt)}
- |
-
- {renderAgentTags(task)}
- |
-
- {renderResultSummary(task)}
- |
-
- {renderActions(task)}
- |
-
- ))}
-
-
-
- );
-}
-
-
-
diff --git a/frontend/src/pages/rvw/components/index.ts b/frontend/src/pages/rvw/components/index.ts
deleted file mode 100644
index 78dcb90e..00000000
--- a/frontend/src/pages/rvw/components/index.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-/**
- * RVW组件导出
- */
-export { default as Sidebar } from './Sidebar';
-export { default as Header } from './Header';
-export { default as FilterChips } from './FilterChips';
-export { default as TaskTable } from './TaskTable';
-export { default as BatchToolbar } from './BatchToolbar';
-export { default as AgentModal } from './AgentModal';
-export { default as ScoreRing } from './ScoreRing';
-export { default as EditorialReport } from './EditorialReport';
-export { default as MethodologyReport } from './MethodologyReport';
-export { default as ReportDetail } from './ReportDetail';
-export { default as TaskDetail } from './TaskDetail';
-
-
diff --git a/frontend/src/pages/rvw/index.ts b/frontend/src/pages/rvw/index.ts
deleted file mode 100644
index 169bc06f..00000000
--- a/frontend/src/pages/rvw/index.ts
+++ /dev/null
@@ -1,36 +0,0 @@
-/**
- * RVW模块入口
- */
-export { default as RvwDashboard } from './Dashboard';
-export * from './types';
-export * from './api';
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/frontend/src/pages/rvw/styles.css b/frontend/src/pages/rvw/styles.css
deleted file mode 100644
index a36fa76a..00000000
--- a/frontend/src/pages/rvw/styles.css
+++ /dev/null
@@ -1,262 +0,0 @@
-/**
- * RVW模块样式
- * 基于原型图 V7 的高保真还原
- */
-
-/* ==================== 状态标签 ==================== */
-.tag {
- display: inline-flex;
- align-items: center;
- padding: 2px 8px;
- border-radius: 4px;
- font-size: 11px;
- font-weight: 600;
- line-height: 1.5;
- border: 1px solid transparent;
-}
-
-.tag-blue {
- background: #eff6ff;
- color: #1d4ed8;
- border-color: #dbeafe;
-}
-
-.tag-purple {
- background: #f5f3ff;
- color: #6d28d9;
- border-color: #ede9fe;
-}
-
-.tag-green {
- background: #f0fdf4;
- color: #15803d;
- border-color: #dcfce7;
-}
-
-.tag-amber {
- background: #fffbeb;
- color: #b45309;
- border-color: #fef3c7;
-}
-
-.tag-red {
- background: #fef2f2;
- color: #dc2626;
- border-color: #fecaca;
-}
-
-.tag-gray {
- background: #f8fafc;
- color: #64748b;
- border-color: #e2e8f0;
-}
-
-/* ==================== 筛选 Chips ==================== */
-.filter-chip {
- padding: 4px 12px;
- border-radius: 9999px;
- font-size: 13px;
- font-weight: 500;
- cursor: pointer;
- transition: all 0.2s;
- border: 1px solid transparent;
- color: #64748b;
- background: transparent;
-}
-
-.filter-chip:hover {
- background-color: #f1f5f9;
- color: #0f172a;
-}
-
-.filter-chip.active {
- background-color: #eff6ff;
- color: #2563eb;
- border-color: #bfdbfe;
- font-weight: 600;
-}
-
-/* ==================== 侧边栏 Tooltip ==================== */
-.sidebar-tooltip {
- position: absolute;
- left: 100%;
- top: 50%;
- transform: translateY(-50%);
- margin-left: 12px;
- background: #1e293b;
- color: white;
- padding: 6px 10px;
- border-radius: 6px;
- font-size: 12px;
- white-space: nowrap;
- z-index: 50;
- box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
- opacity: 0;
- visibility: hidden;
- transition: opacity 0.2s, visibility 0.2s;
- pointer-events: none;
-}
-
-.sidebar-btn:hover .sidebar-tooltip {
- opacity: 1;
- visibility: visible;
-}
-
-/* ==================== 动画 ==================== */
-.fade-in {
- animation: fadeIn 0.4s cubic-bezier(0.16, 1, 0.3, 1);
-}
-
-.slide-up {
- animation: slideUp 0.4s cubic-bezier(0.16, 1, 0.3, 1);
-}
-
-@keyframes fadeIn {
- from {
- opacity: 0;
- }
- to {
- opacity: 1;
- }
-}
-
-@keyframes slideUp {
- from {
- opacity: 0;
- transform: translateY(20px);
- }
- to {
- opacity: 1;
- transform: translateY(0);
- }
-}
-
-/* ==================== 表格悬停效果 ==================== */
-.task-table tbody tr {
- transition: background-color 0.15s ease;
-}
-
-.task-table tbody tr:hover {
- background-color: #f8fafc;
-}
-
-.task-table tbody tr.selected {
- background-color: #eff6ff;
-}
-
-/* ==================== 评分环 ==================== */
-.score-circle {
- width: 80px;
- height: 80px;
- border-radius: 50%;
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
-}
-
-.score-circle.pass {
- border-color: #22c55e;
- background: #f0fdf4;
- color: #15803d;
-}
-
-.score-circle.warn {
- border-color: #f59e0b;
- background: #fffbeb;
- color: #b45309;
-}
-
-.score-circle.fail {
- border-color: #ef4444;
- background: #fef2f2;
- color: #dc2626;
-}
-
-/* ==================== 按钮样式 ==================== */
-.btn-primary {
- background-color: #4f46e5;
- color: white;
- font-weight: 600;
- padding: 8px 16px;
- border-radius: 8px;
- transition: all 0.2s;
- box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
-}
-
-.btn-primary:hover {
- background-color: #4338ca;
- transform: translateY(-1px);
-}
-
-.btn-secondary {
- background-color: white;
- color: #374151;
- font-weight: 500;
- padding: 8px 16px;
- border-radius: 8px;
- border: 1px solid #d1d5db;
- transition: all 0.2s;
-}
-
-.btn-secondary:hover {
- background-color: #f9fafb;
- border-color: #9ca3af;
-}
-
-/* ==================== 滚动条美化 ==================== */
-.overflow-auto::-webkit-scrollbar {
- width: 8px;
- height: 8px;
-}
-
-.overflow-auto::-webkit-scrollbar-track {
- background: #f1f5f9;
- border-radius: 4px;
-}
-
-.overflow-auto::-webkit-scrollbar-thumb {
- background: #cbd5e1;
- border-radius: 4px;
-}
-
-.overflow-auto::-webkit-scrollbar-thumb:hover {
- background: #94a3b8;
-}
-
-/* ==================== 响应式调整 ==================== */
-@media (max-width: 1024px) {
- .sidebar-tooltip {
- display: none;
- }
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/frontend/src/pages/rvw/types.ts b/frontend/src/pages/rvw/types.ts
deleted file mode 100644
index 6c1f6899..00000000
--- a/frontend/src/pages/rvw/types.ts
+++ /dev/null
@@ -1,95 +0,0 @@
-/**
- * RVW模块类型定义
- */
-
-// 任务状态
-export type TaskStatus =
- | 'pending' // 待处理
- | 'extracting' // 提取文本中
- | 'reviewing' // 审查中
- | 'reviewing_editorial' // 正在审查稿约规范性
- | 'reviewing_methodology' // 正在审查方法学
- | 'completed' // 已完成
- | 'failed'; // 失败
-
-// 智能体类型
-export type AgentType = 'editorial' | 'methodology';
-
-// 审查任务
-export interface ReviewTask {
- id: string;
- fileName: string;
- fileSize: number;
- status: TaskStatus;
- selectedAgents: AgentType[];
- wordCount?: number;
- overallScore?: number;
- editorialScore?: number;
- methodologyStatus?: string;
- errorMessage?: string;
- createdAt: string;
- completedAt?: string;
- durationSeconds?: number;
-}
-
-// 规范性评估项
-export interface EditorialItem {
- criterion: string;
- status: 'pass' | 'warning' | 'fail';
- score: number;
- issues?: string[];
- suggestions?: string[];
-}
-
-// 规范性评估结果
-export interface EditorialReviewResult {
- overall_score: number;
- summary: string;
- items: EditorialItem[];
-}
-
-// 方法学问题
-export interface MethodologyIssue {
- type: string;
- severity: 'major' | 'minor';
- description: string;
- location: string;
- suggestion: string;
-}
-
-// 方法学评估部分
-export interface MethodologyPart {
- part: string;
- score: number;
- issues: MethodologyIssue[];
-}
-
-// 方法学评估结果
-export interface MethodologyReviewResult {
- overall_score: number;
- summary: string;
- parts: MethodologyPart[];
-}
-
-// 完整审查报告
-export interface ReviewReport extends ReviewTask {
- editorialReview?: EditorialReviewResult;
- methodologyReview?: MethodologyReviewResult;
- modelUsed?: string;
-}
-
-// API响应
-export interface ApiResponse
{
- success: boolean;
- data?: T;
- message?: string;
- error?: string;
-}
-
-// 筛选条件
-export interface TaskFilters {
- status: 'all' | 'pending' | 'completed';
- timeRange: 'all' | 'today' | 'week';
-}
-
-
diff --git a/frontend/src/stores/useKnowledgeBaseStore.ts b/frontend/src/stores/useKnowledgeBaseStore.ts
deleted file mode 100644
index 8e338656..00000000
--- a/frontend/src/stores/useKnowledgeBaseStore.ts
+++ /dev/null
@@ -1,218 +0,0 @@
-import { create } from 'zustand';
-import type { KnowledgeBase, Document } from '../api/knowledgeBaseApi';
-import { knowledgeBaseApi, documentApi } from '../api/knowledgeBaseApi';
-
-interface KnowledgeBaseState {
- // 知识库列表
- knowledgeBases: KnowledgeBase[];
- currentKb: KnowledgeBase | null;
-
- // 文档列表
- documents: Document[];
-
- // 加载状态
- loading: boolean;
- error: string | null;
-
- // 操作方法
- fetchKnowledgeBases: () => Promise;
- fetchKnowledgeBaseById: (id: string) => Promise;
- createKnowledgeBase: (name: string, description?: string) => Promise;
- updateKnowledgeBase: (id: string, name?: string, description?: string) => Promise;
- deleteKnowledgeBase: (id: string) => Promise;
-
- // 文档操作
- fetchDocuments: (kbId: string) => Promise;
- uploadDocument: (kbId: string, file: File, onProgress?: (progress: number) => void) => Promise;
- deleteDocument: (id: string) => Promise;
- reprocessDocument: (id: string) => Promise;
-
- // 辅助方法
- setCurrentKb: (kb: KnowledgeBase | null) => void;
- clearError: () => void;
-}
-
-export const useKnowledgeBaseStore = create((set, get) => ({
- knowledgeBases: [],
- currentKb: null,
- documents: [],
- loading: false,
- error: null,
-
- // 获取知识库列表
- fetchKnowledgeBases: async () => {
- set({ loading: true, error: null });
- try {
- const knowledgeBases = await knowledgeBaseApi.getList();
- set({ knowledgeBases, loading: false });
- } catch (error: any) {
- set({
- error: error.response?.data?.message || '获取知识库列表失败',
- loading: false
- });
- }
- },
-
- // 获取知识库详情
- fetchKnowledgeBaseById: async (id: string) => {
- set({ loading: true, error: null });
- try {
- const kb = await knowledgeBaseApi.getById(id);
- set({ currentKb: kb, loading: false });
-
- // 同时获取文档列表
- if (kb.id) {
- await get().fetchDocuments(kb.id);
- }
- } catch (error: any) {
- set({
- error: error.response?.data?.message || '获取知识库详情失败',
- loading: false
- });
- }
- },
-
- // 创建知识库
- createKnowledgeBase: async (name: string, description?: string) => {
- set({ loading: true, error: null });
- try {
- const kb = await knowledgeBaseApi.create({ name, description });
-
- // 更新列表
- const knowledgeBases = [...get().knowledgeBases, kb];
- set({ knowledgeBases, loading: false });
-
- return kb;
- } catch (error: any) {
- const errorMsg = error.response?.data?.message || '创建知识库失败';
- set({ error: errorMsg, loading: false });
- throw new Error(errorMsg);
- }
- },
-
- // 更新知识库
- updateKnowledgeBase: async (id: string, name?: string, description?: string) => {
- set({ loading: true, error: null });
- try {
- const updatedKb = await knowledgeBaseApi.update(id, { name, description });
-
- // 更新列表
- const knowledgeBases = get().knowledgeBases.map(kb =>
- kb.id === id ? updatedKb : kb
- );
-
- // 更新当前知识库
- const currentKb = get().currentKb?.id === id ? updatedKb : get().currentKb;
-
- set({ knowledgeBases, currentKb, loading: false });
- } catch (error: any) {
- set({
- error: error.response?.data?.message || '更新知识库失败',
- loading: false
- });
- throw error;
- }
- },
-
- // 删除知识库
- deleteKnowledgeBase: async (id: string) => {
- set({ loading: true, error: null });
- try {
- await knowledgeBaseApi.delete(id);
-
- // 更新列表
- const knowledgeBases = get().knowledgeBases.filter(kb => kb.id !== id);
-
- // 清除当前知识库(如果是被删除的)
- const currentKb = get().currentKb?.id === id ? null : get().currentKb;
-
- set({ knowledgeBases, currentKb, loading: false });
- } catch (error: any) {
- set({
- error: error.response?.data?.message || '删除知识库失败',
- loading: false
- });
- throw error;
- }
- },
-
- // 获取文档列表
- fetchDocuments: async (kbId: string) => {
- try {
- const documents = await documentApi.getList(kbId);
- set({ documents });
- } catch (error: any) {
- set({
- error: error.response?.data?.message || '获取文档列表失败'
- });
- }
- },
-
- // 上传文档
- uploadDocument: async (kbId: string, file: File, onProgress?: (progress: number) => void) => {
- set({ loading: true, error: null });
- try {
- const document = await documentApi.upload(kbId, file, onProgress);
-
- // 更新文档列表
- const documents = [document, ...get().documents];
- set({ documents, loading: false });
-
- return document;
- } catch (error: any) {
- const errorMsg = error.response?.data?.message || '上传文档失败';
- set({ error: errorMsg, loading: false });
- throw new Error(errorMsg);
- }
- },
-
- // 删除文档
- deleteDocument: async (id: string) => {
- set({ loading: true, error: null });
- try {
- await documentApi.delete(id);
-
- // 更新文档列表
- const documents = get().documents.filter(doc => doc.id !== id);
- set({ documents, loading: false });
- } catch (error: any) {
- set({
- error: error.response?.data?.message || '删除文档失败',
- loading: false
- });
- throw error;
- }
- },
-
- // 重新处理文档
- reprocessDocument: async (id: string) => {
- set({ loading: true, error: null });
- try {
- await documentApi.reprocess(id);
-
- // 更新文档状态
- const documents = get().documents.map(doc =>
- doc.id === id ? { ...doc, status: 'parsing' as const, progress: 0 } : doc
- );
- set({ documents, loading: false });
- } catch (error: any) {
- set({
- error: error.response?.data?.message || '重新处理文档失败',
- loading: false
- });
- throw error;
- }
- },
-
- // 设置当前知识库
- setCurrentKb: (kb: KnowledgeBase | null) => {
- set({ currentKb: kb });
- },
-
- // 清除错误
- clearError: () => {
- set({ error: null });
- },
-}));
-
-
diff --git a/frontend/src/stores/useProjectStore.ts b/frontend/src/stores/useProjectStore.ts
deleted file mode 100644
index 8ccaac78..00000000
--- a/frontend/src/stores/useProjectStore.ts
+++ /dev/null
@@ -1,97 +0,0 @@
-import { create } from 'zustand';
-import { projectApi } from '../api/projectApi';
-import { message } from 'antd';
-
-export interface Project {
- id: string;
- name: string;
- background: string;
- researchType: 'observational' | 'interventional';
- createdAt: string;
- updatedAt: string;
-}
-
-interface ProjectState {
- // 当前选中的项目
- currentProject: Project | null;
-
- // 所有项目列表
- projects: Project[];
-
- // 加载状态
- loading: boolean;
-
- // 是否显示创建项目对话框
- showCreateDialog: boolean;
-
- // 是否显示编辑项目对话框
- showEditDialog: boolean;
-
- // Actions
- setCurrentProject: (project: Project | null) => void;
- setProjects: (projects: Project[]) => void;
- addProject: (project: Project) => void;
- updateProject: (id: string, updates: Partial) => void;
- deleteProject: (id: string) => void;
- setShowCreateDialog: (show: boolean) => void;
- setShowEditDialog: (show: boolean) => void;
- setLoading: (loading: boolean) => void;
- fetchProjects: () => Promise;
-}
-
-export const useProjectStore = create((set) => ({
- currentProject: null,
- projects: [],
- loading: false,
- showCreateDialog: false,
- showEditDialog: false,
-
- setCurrentProject: (project) => set({ currentProject: project }),
-
- setProjects: (projects) => set({ projects }),
-
- addProject: (project) => set((state) => ({
- projects: [...state.projects, project],
- })),
-
- updateProject: (id, updates) => set((state) => ({
- projects: state.projects.map((p) =>
- p.id === id ? { ...p, ...updates } : p
- ),
- currentProject:
- state.currentProject?.id === id
- ? { ...state.currentProject, ...updates }
- : state.currentProject,
- })),
-
- deleteProject: (id) => set((state) => ({
- projects: state.projects.filter((p) => p.id !== id),
- currentProject:
- state.currentProject?.id === id ? null : state.currentProject,
- })),
-
- setShowCreateDialog: (show) => set({ showCreateDialog: show }),
-
- setShowEditDialog: (show) => set({ showEditDialog: show }),
-
- setLoading: (loading) => set({ loading }),
-
- // 获取项目列表
- fetchProjects: async () => {
- try {
- set({ loading: true });
- const response = await projectApi.getProjects();
- if (response.success && response.data) {
- set({ projects: response.data });
- } else {
- message.error(response.message || '获取项目列表失败');
- }
- } catch (error) {
- console.error('获取项目列表失败:', error);
- message.error('获取项目列表失败');
- } finally {
- set({ loading: false });
- }
- },
-}));
-
diff --git a/frontend/src/types/chat.ts b/frontend/src/types/chat.ts
deleted file mode 100644
index 5e877ba7..00000000
--- a/frontend/src/types/chat.ts
+++ /dev/null
@@ -1,91 +0,0 @@
-/**
- * Phase 2: 聊天模式相关类型定义
- */
-
-import { Document } from './index'
-
-/**
- * 聊天基础模式
- */
-export type ChatBaseMode = 'general' | 'knowledge_base'
-
-/**
- * 知识库工作模式
- */
-export type KnowledgeBaseMode = 'full_text' | 'deep_read' | 'batch'
-
-/**
- * 聊天页面状态
- */
-export interface ChatPageState {
- // 基础模式
- baseMode: ChatBaseMode
-
- // 知识库配置
- selectedKbId?: string
- kbMode?: KnowledgeBaseMode
-
- // 全文阅读模式状态
- fullTextState?: FullTextModeState
-
- // 逐篇精读模式状态
- deepReadState?: DeepReadModeState
-}
-
-/**
- * 全文阅读模式状态
- */
-export interface FullTextModeState {
- loadedDocs: Document[]
- totalFiles: number
- selectedFiles: number
- totalTokens: number
- usedTokens: number
- availableTokens: number
- reason: 'all_included' | 'file_limit' | 'token_limit'
-}
-
-/**
- * 逐篇精读模式状态
- */
-export interface DeepReadModeState {
- selectedDocs: Document[]
- currentDocId: string
- currentDoc?: Document
- currentConversation: ChatMessage[]
- conversationPerDoc: Map
- totalTokens: number
-}
-
-/**
- * 聊天消息
- */
-export interface ChatMessage {
- id: string
- role: 'user' | 'assistant' | 'system'
- content: string
- timestamp: Date
- metadata?: any
-}
-
-/**
- * 文档选择结果(从API返回)
- */
-export interface DocumentSelectionResult {
- knowledgeBaseId: string
- knowledgeBaseName: string
- limits: {
- maxFiles: number
- maxTokens: number
- }
- selection: {
- selectedCount: number
- selectedTokens: number
- excludedCount: number
- availableTokens: number
- reason: 'all_included' | 'file_limit' | 'token_limit'
- }
- selectedDocuments: Document[]
- excludedDocuments: Document[]
-}
-
diff --git a/frontend/src/types/index.ts b/frontend/src/types/index.ts
deleted file mode 100644
index 93a0d824..00000000
--- a/frontend/src/types/index.ts
+++ /dev/null
@@ -1,98 +0,0 @@
-// 用户类型
-export interface User {
- id: string
- email: string
- name?: string
- avatarUrl?: string
- role: 'user' | 'admin'
-}
-
-// 项目类型
-export interface Project {
- id: string
- userId: string
- name: string
- description: string
- conversationCount: number
- createdAt: string
- updatedAt: string
-}
-
-// 会话类型
-export interface Conversation {
- id: string
- userId: string
- projectId?: string
- agentId: string
- title: string
- modelName: string
- messageCount: number
- totalTokens: number
- createdAt: string
- updatedAt: string
-}
-
-// 消息类型
-export interface Message {
- id: string
- conversationId: string
- role: 'user' | 'assistant'
- content: string
- metadata?: {
- kbReferences?: string[]
- citations?: any[]
- modelParams?: any
- }
- tokens?: number
- isPinned: boolean
- createdAt: string
-}
-
-// 知识库类型
-export interface KnowledgeBase {
- id: string
- userId: string
- name: string
- description?: string
- difyDatasetId: string
- fileCount: number
- totalSizeBytes: number
- createdAt: string
- updatedAt: string
-}
-
-// 文档类型
-export interface Document {
- id: string
- kbId: string
- userId: string
- filename: string
- fileType: string
- fileSizeBytes: number
- fileUrl: string
- difyDocumentId: string
- status: 'uploading' | 'processing' | 'completed' | 'failed'
- progress: number
- errorMessage?: string
- segmentsCount?: number
- tokensCount?: number
- uploadedAt: string
- processedAt?: string
- // Phase 2: 全文阅读模式新增字段
- extractionMethod?: string // pymupdf/nougat/mammoth/direct
- extractionQuality?: number // 0-1质量分数
- charCount?: number // 字符数
- language?: string // 检测到的语言
- extractedText?: string // 提取的文本内容
-}
-
-// API响应类型
-export interface ApiResponse {
- success: boolean
- data: T
- message?: string
-}
-
-
-
-
diff --git a/frontend/src/vite-env.d.ts b/frontend/src/vite-env.d.ts
deleted file mode 100644
index 94308114..00000000
--- a/frontend/src/vite-env.d.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-///
-
-interface ImportMetaEnv {
- readonly VITE_API_BASE_URL: string
- // 可以在这里添加更多环境变量
-}
-
-interface ImportMeta {
- readonly env: ImportMetaEnv
-}
-
-
-
-
diff --git a/frontend/tailwind.config.js b/frontend/tailwind.config.js
deleted file mode 100644
index f7474efc..00000000
--- a/frontend/tailwind.config.js
+++ /dev/null
@@ -1,18 +0,0 @@
-/** @type {import('tailwindcss').Config} */
-export default {
- content: [
- "./index.html",
- "./src/**/*.{js,ts,jsx,tsx}",
- ],
- theme: {
- extend: {},
- },
- plugins: [],
- corePlugins: {
- preflight: false, // 禁用 Tailwind 的基础样式重置,避免与 Ant Design 冲突
- },
-}
-
-
-
-
diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json
deleted file mode 100644
index 3eb0f724..00000000
--- a/frontend/tsconfig.json
+++ /dev/null
@@ -1,35 +0,0 @@
-{
- "compilerOptions": {
- "target": "ES2020",
- "useDefineForClassFields": true,
- "lib": ["ES2020", "DOM", "DOM.Iterable"],
- "module": "ESNext",
- "skipLibCheck": true,
-
- /* Bundler mode */
- "moduleResolution": "bundler",
- "allowImportingTsExtensions": true,
- "resolveJsonModule": true,
- "isolatedModules": true,
- "noEmit": true,
- "jsx": "react-jsx",
-
- /* Linting */
- "strict": true,
- "noUnusedLocals": true,
- "noUnusedParameters": true,
- "noFallthroughCasesInSwitch": true,
-
- /* Path alias */
- "baseUrl": ".",
- "paths": {
- "@/*": ["src/*"]
- }
- },
- "include": ["src"],
- "references": [{ "path": "./tsconfig.node.json" }]
-}
-
-
-
-
diff --git a/frontend/tsconfig.node.json b/frontend/tsconfig.node.json
deleted file mode 100644
index f14a6932..00000000
--- a/frontend/tsconfig.node.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "compilerOptions": {
- "composite": true,
- "skipLibCheck": true,
- "module": "ESNext",
- "moduleResolution": "bundler",
- "allowSyntheticDefaultImports": true,
- "strict": true
- },
- "include": ["vite.config.ts"]
-}
-
-
-
-
diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts
deleted file mode 100644
index 4b643d5b..00000000
--- a/frontend/vite.config.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-import { defineConfig } from 'vite'
-import react from '@vitejs/plugin-react'
-import path from 'path'
-
-// https://vitejs.dev/config/
-export default defineConfig({
- plugins: [react()],
- resolve: {
- alias: {
- '@': path.resolve(__dirname, './src'),
- },
- },
- server: {
- port: 3000,
- proxy: {
- '/api': {
- target: 'http://localhost:3001',
- changeOrigin: true,
- // Phase 2: 全文阅读模式需要更长的超时时间
- timeout: 300000, // 5分钟
- proxyTimeout: 300000, // 5分钟
- },
- },
- },
-})
-
-
-
-
diff --git a/frontend/启动前端.bat b/frontend/启动前端.bat
deleted file mode 100644
index 0cce3ba9..00000000
--- a/frontend/启动前端.bat
+++ /dev/null
@@ -1,16 +0,0 @@
-@echo off
-chcp 65001 >nul
-echo ====================================
-echo AI临床研究平台 - 前端开发服务器
-echo ====================================
-echo.
-cd /d %~dp0
-echo 正在启动前端开发服务器...
-echo 访问地址: http://localhost:3000
-echo.
-call npm run dev
-pause
-
-
-
-
diff --git a/orAIclinicalresearch b/orAIclinicalresearch
deleted file mode 100644
index 1d25cad9..00000000
--- a/orAIclinicalresearch
+++ /dev/null
@@ -1,46 +0,0 @@
-[33mcommit 2eef7522a1649cd359e10ee7f6aed9a0b52160f5[m[33m ([m[1;36mHEAD[m[33m -> [m[1;32mmaster[m[33m, [m[1;31morigin/master[m[33m)[m
-Author: HaHafeng
-Date: Fri Jan 2 18:20:18 2026 +0800
-
- feat(iit): Complete Day 2 - REDCap real-time integration
-
- Summary:
- - Implement RedcapAdapter (271 lines, 7 API methods)
- - Implement WebhookController (327 lines, <10ms response)
- - Implement SyncManager (398 lines, incremental/full sync)
- - Register Workers (iit_quality_check + iit_redcap_poll)
- - Configure routes with form-urlencoded parser
- - Add 3 integration test scripts (912 lines total)
- - Complete development documentation
-
- Technical Highlights:
- - REDCap DET real-time trigger (0ms delay)
- - Webhook + scheduled polling dual mechanism
- - Form-urlencoded format support for REDCap DET
- - Postgres-Only architecture with pg-boss queue
- - Full compliance with team development standards
-
- Test Results:
- - Integration tests: 12/12 passed
- - Real scenario validation: PASSED
- - Performance: Webhook response <10ms
- - Data accuracy: 100%
-
- Progress:
- - Module completion: 18% -> 35%
- - Day 2 development: COMPLETED
- - Production ready: YES
-
- .../modules/iit-manager/adapters/RedcapAdapter.ts | 309 [32m++++++++++[m
- .../iit-manager/controllers/WebhookController.ts | 326 [32m+++++++++++[m
- backend/src/modules/iit-manager/index.ts | 73 [32m++[m[31m-[m
- backend/src/modules/iit-manager/routes/index.ts | 180 [32m+++++[m[31m-[m
- .../modules/iit-manager/services/SyncManager.ts | 397 [32m+++++++++++++[m
- backend/src/modules/iit-manager/test-redcap-api.ts | 188 [32m++++++[m
- .../modules/iit-manager/test-redcap-integration.ts | 448 [32m+++++++++++++++[m
- .../src/modules/iit-manager/test-redcap-webhook.ts | 273 [32m+++++++++[m
- docs/00-系统总体设计/00-系统当前状态与开发指南.md | 103 [32m+++[m[31m-[m
- .../IIT Manager Agent/00-模块当前状态与开发指南.md | 42 [32m+[m[31m-[m
- .../IIT Manager Agent/04-开发计划/Day2-开发完成总结.md | 336 [32m+++++++++++[m
- .../06-开发记录/Day2-REDCap实时集成开发完成记录.md | 636 [32m+++++++++++++++++++++[m
- 12 files changed, 3272 insertions(+), 39 deletions(-)
diff --git a/package-lock.json b/package-lock.json
deleted file mode 100644
index ffd3ca63..00000000
--- a/package-lock.json
+++ /dev/null
@@ -1,41 +0,0 @@
-{
- "name": "AIclinicalresearch",
- "lockfileVersion": 3,
- "requires": true,
- "packages": {
- "": {
- "dependencies": {
- "zustand": "^5.0.8"
- }
- },
- "node_modules/zustand": {
- "version": "5.0.8",
- "resolved": "https://registry.npmmirror.com/zustand/-/zustand-5.0.8.tgz",
- "integrity": "sha512-gyPKpIaxY9XcO2vSMrLbiER7QMAMGOQZVRdJ6Zi782jkbzZygq5GI9nG8g+sMgitRtndwaBSl7uiqC49o1SSiw==",
- "license": "MIT",
- "engines": {
- "node": ">=12.20.0"
- },
- "peerDependencies": {
- "@types/react": ">=18.0.0",
- "immer": ">=9.0.6",
- "react": ">=18.0.0",
- "use-sync-external-store": ">=1.2.0"
- },
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- },
- "immer": {
- "optional": true
- },
- "react": {
- "optional": true
- },
- "use-sync-external-store": {
- "optional": true
- }
- }
- }
- }
-}
diff --git a/package.json b/package.json
deleted file mode 100644
index d56050c1..00000000
--- a/package.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "dependencies": {
- "zustand": "^5.0.8"
- }
-}
diff --git a/python-microservice/operations/__init__.py b/python-microservice/operations/__init__.py
deleted file mode 100644
index 3e5b8875..00000000
--- a/python-microservice/operations/__init__.py
+++ /dev/null
@@ -1,87 +0,0 @@
-"""
-数据操作函数模块
-
-提供预写的、经过测试的数据处理函数,供功能按钮调用。
-
-模块列表:
-- filter: 高级筛选
-- recode: 数值映射(重编码)
-- binning: 生成分类变量(分箱)
-- conditional: 条件生成列
-- missing: 缺失值处理
-- duplicate: 去重
-"""
-
-__version__ = '1.0.0'
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/python-microservice/operations/binning.py b/python-microservice/operations/binning.py
deleted file mode 100644
index 0cb61753..00000000
--- a/python-microservice/operations/binning.py
+++ /dev/null
@@ -1,194 +0,0 @@
-"""
-生成分类变量(分箱)操作
-
-将连续数值变量转换为分类变量。
-支持三种方法:自定义切点、等宽分箱、等频分箱。
-"""
-
-import pandas as pd
-import numpy as np
-from typing import List, Optional, Literal, Union
-
-
-def apply_binning(
- df: pd.DataFrame,
- column: str,
- method: Literal['custom', 'equal_width', 'equal_freq'],
- new_column_name: str,
- bins: Optional[List[Union[int, float]]] = None,
- labels: Optional[List[Union[str, int]]] = None,
- num_bins: int = 3
-) -> pd.DataFrame:
- """
- 应用分箱操作
-
- Args:
- df: 输入数据框
- column: 要分箱的列名
- method: 分箱方法
- - 'custom': 自定义切点
- - 'equal_width': 等宽分箱
- - 'equal_freq': 等频分箱
- new_column_name: 新列名
- bins: 自定义切点列表(仅method='custom'时使用),如 [18, 60] → <18, 18-60, >60
- labels: 标签列表(可选)
- num_bins: 分组数量(仅method='equal_width'或'equal_freq'时使用)
-
- Returns:
- 分箱后的数据框
-
- Examples:
- >>> df = pd.DataFrame({'年龄': [15, 25, 35, 45, 55, 65, 75]})
- >>> result = apply_binning(df, '年龄', 'custom', '年龄分组',
- ... bins=[18, 60], labels=['青少年', '成年', '老年'])
- >>> result['年龄分组'].tolist()
- ['青少年', '成年', '成年', '成年', '成年', '老年', '老年']
- """
- if df.empty:
- return df
-
- # 验证列是否存在
- if column not in df.columns:
- raise KeyError(f"列 '{column}' 不存在")
-
- # 验证数据类型
- if not pd.api.types.is_numeric_dtype(df[column]):
- raise TypeError(f"列 '{column}' 不是数值类型,无法进行分箱")
-
- # 创建结果数据框
- result = df.copy()
-
- # 根据方法进行分箱
- if method == 'custom':
- # 自定义切点
- if not bins or len(bins) < 2:
- raise ValueError('自定义切点至少需要2个值')
-
- # 验证切点是否升序
- if bins != sorted(bins):
- raise ValueError('切点必须按升序排列')
-
- # 验证标签数量
- if labels and len(labels) != len(bins) - 1:
- raise ValueError(f'标签数量({len(labels)})必须等于切点数量-1({len(bins)-1})')
-
- result[new_column_name] = pd.cut(
- result[column],
- bins=bins,
- labels=labels,
- right=False,
- include_lowest=True
- )
-
- elif method == 'equal_width':
- # 等宽分箱
- if num_bins < 2:
- raise ValueError('分组数量至少为2')
-
- result[new_column_name] = pd.cut(
- result[column],
- bins=num_bins,
- labels=labels,
- include_lowest=True
- )
-
- elif method == 'equal_freq':
- # 等频分箱
- if num_bins < 2:
- raise ValueError('分组数量至少为2')
-
- result[new_column_name] = pd.qcut(
- result[column],
- q=num_bins,
- labels=labels,
- duplicates='drop' # 处理重复边界值
- )
-
- else:
- raise ValueError(f"不支持的分箱方法: {method}")
-
- # 统计分布
- print(f'分箱结果分布:')
- value_counts = result[new_column_name].value_counts().sort_index()
- for category, count in value_counts.items():
- percentage = count / len(result) * 100
- print(f' {category}: {count} 行 ({percentage:.1f}%)')
-
- # 缺失值统计
- missing_count = result[new_column_name].isna().sum()
- if missing_count > 0:
- print(f'警告: {missing_count} 个值无法分箱(可能是缺失值或边界问题)')
-
- return result
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/python-microservice/operations/filter.py b/python-microservice/operations/filter.py
deleted file mode 100644
index 0b4cf849..00000000
--- a/python-microservice/operations/filter.py
+++ /dev/null
@@ -1,180 +0,0 @@
-"""
-高级筛选操作
-
-提供多条件筛选功能,支持AND/OR逻辑组合。
-"""
-
-import pandas as pd
-from typing import List, Dict, Any, Literal
-
-
-def apply_filter(
- df: pd.DataFrame,
- conditions: List[Dict[str, Any]],
- logic: Literal['and', 'or'] = 'and'
-) -> pd.DataFrame:
- """
- 应用筛选条件
-
- Args:
- df: 输入数据框
- conditions: 筛选条件列表,每个条件包含:
- - column: 列名
- - operator: 运算符 (=, !=, >, <, >=, <=, contains, not_contains,
- starts_with, ends_with, is_null, not_null)
- - value: 值(is_null和not_null不需要)
- logic: 逻辑组合方式 ('and' 或 'or')
-
- Returns:
- 筛选后的数据框
-
- Examples:
- >>> df = pd.DataFrame({'年龄': [25, 35, 45], '性别': ['男', '女', '男']})
- >>> conditions = [
- ... {'column': '年龄', 'operator': '>', 'value': 30},
- ... {'column': '性别', 'operator': '=', 'value': '男'}
- ... ]
- >>> result = apply_filter(df, conditions, logic='and')
- >>> len(result)
- 1
- """
- if not conditions:
- raise ValueError('筛选条件不能为空')
-
- if df.empty:
- return df
-
- # 生成各个条件的mask
- masks = []
- for cond in conditions:
- column = cond['column']
- operator = cond['operator']
- value = cond.get('value')
-
- # 验证列是否存在
- if column not in df.columns:
- raise KeyError(f"列 '{column}' 不存在")
-
- # 根据运算符生成mask
- if operator == '=':
- mask = df[column] == value
- elif operator == '!=':
- mask = df[column] != value
- elif operator == '>':
- mask = df[column] > value
- elif operator == '<':
- mask = df[column] < value
- elif operator == '>=':
- mask = df[column] >= value
- elif operator == '<=':
- mask = df[column] <= value
- elif operator == 'contains':
- mask = df[column].astype(str).str.contains(str(value), na=False)
- elif operator == 'not_contains':
- mask = ~df[column].astype(str).str.contains(str(value), na=False)
- elif operator == 'starts_with':
- mask = df[column].astype(str).str.startswith(str(value), na=False)
- elif operator == 'ends_with':
- mask = df[column].astype(str).str.endswith(str(value), na=False)
- elif operator == 'is_null':
- mask = df[column].isna()
- elif operator == 'not_null':
- mask = df[column].notna()
- else:
- raise ValueError(f"不支持的运算符: {operator}")
-
- masks.append(mask)
-
- # 组合所有条件
- if logic == 'and':
- final_mask = pd.concat(masks, axis=1).all(axis=1)
- elif logic == 'or':
- final_mask = pd.concat(masks, axis=1).any(axis=1)
- else:
- raise ValueError(f"不支持的逻辑运算: {logic}")
-
- # 应用筛选
- result = df[final_mask].copy()
-
- # 打印统计信息
- original_rows = len(df)
- filtered_rows = len(result)
- removed_rows = original_rows - filtered_rows
-
- print(f'原始数据: {original_rows} 行')
- print(f'筛选后: {filtered_rows} 行')
- print(f'删除: {removed_rows} 行 ({removed_rows/original_rows*100:.1f}%)')
-
- return result
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/python-microservice/operations/recode.py b/python-microservice/operations/recode.py
deleted file mode 100644
index 8f9d000e..00000000
--- a/python-microservice/operations/recode.py
+++ /dev/null
@@ -1,150 +0,0 @@
-"""
-数值映射(重编码)操作
-
-将分类变量的原始值映射为新值(如:男→1,女→2)。
-"""
-
-import pandas as pd
-from typing import Dict, Any, Optional
-
-
-def apply_recode(
- df: pd.DataFrame,
- column: str,
- mapping: Dict[Any, Any],
- create_new_column: bool = True,
- new_column_name: Optional[str] = None
-) -> pd.DataFrame:
- """
- 应用数值映射
-
- Args:
- df: 输入数据框
- column: 要重编码的列名
- mapping: 映射字典,如 {'男': 1, '女': 2}
- create_new_column: 是否创建新列(True)或覆盖原列(False)
- new_column_name: 新列名(create_new_column=True时使用)
-
- Returns:
- 重编码后的数据框
-
- Examples:
- >>> df = pd.DataFrame({'性别': ['男', '女', '男', '女']})
- >>> mapping = {'男': 1, '女': 2}
- >>> result = apply_recode(df, '性别', mapping, True, '性别_编码')
- >>> result['性别_编码'].tolist()
- [1, 2, 1, 2]
- """
- if df.empty:
- return df
-
- # 验证列是否存在
- if column not in df.columns:
- raise KeyError(f"列 '{column}' 不存在")
-
- if not mapping:
- raise ValueError('映射字典不能为空')
-
- # 确定目标列名
- if create_new_column:
- target_column = new_column_name or f'{column}_编码'
- else:
- target_column = column
-
- # 创建结果数据框(避免修改原数据)
- result = df.copy()
-
- # 应用映射
- result[target_column] = result[column].map(mapping)
-
- # 统计结果
- mapped_count = result[target_column].notna().sum()
- unmapped_count = result[target_column].isna().sum()
- total_count = len(result)
-
- print(f'映射完成: {mapped_count} 个值成功映射')
-
- if unmapped_count > 0:
- print(f'警告: {unmapped_count} 个值未找到对应映射')
- # 找出未映射的唯一值
- unmapped_mask = result[target_column].isna()
- unmapped_values = result.loc[unmapped_mask, column].unique()
- print(f'未映射的值: {list(unmapped_values)[:10]}') # 最多显示10个
-
- # 映射成功率
- success_rate = (mapped_count / total_count * 100) if total_count > 0 else 0
- print(f'映射成功率: {success_rate:.1f}%')
-
- return result
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/rds_init_20251224_154529.sql b/rds_init_20251224_154529.sql
deleted file mode 100644
index 92855662..00000000
Binary files a/rds_init_20251224_154529.sql and /dev/null differ
diff --git a/redcap-docker-dev/.gitattributes b/redcap-docker-dev/.gitattributes
deleted file mode 100644
index 14d8feb2..00000000
--- a/redcap-docker-dev/.gitattributes
+++ /dev/null
@@ -1,74 +0,0 @@
-# Git attributes for REDCap Docker deployment
-# 确保跨平台一致性,防止CRLF/LF问题
-
-# PHP文件统一使用LF换行符(Linux标准)
-*.php text eol=lf
-*.inc text eol=lf
-
-# Shell脚本统一使用LF
-*.sh text eol=lf
-
-# PowerShell脚本保持CRLF(Windows标准)
-*.ps1 text eol=crlf
-
-# 配置文件统一使用LF
-*.conf text eol=lf
-*.ini text eol=lf
-*.yml text eol=lf
-*.yaml text eol=lf
-
-# Markdown和文档
-*.md text eol=lf
-*.txt text eol=lf
-
-# 二进制文件不做转换
-*.png binary
-*.jpg binary
-*.jpeg binary
-*.gif binary
-*.ico binary
-*.pdf binary
-*.zip binary
-*.tar binary
-*.gz binary
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/redcap-docker-dev/.gitignore b/redcap-docker-dev/.gitignore
deleted file mode 100644
index 2eff5979..00000000
--- a/redcap-docker-dev/.gitignore
+++ /dev/null
@@ -1,105 +0,0 @@
-# REDCap Docker环境 - Git忽略文件
-# 版本:v1.0
-# 日期:2026-01-01
-
-# ========== 环境变量文件(包含敏感信息) ==========
-.env
-.env.local
-.env.*.local
-
-# ========== Docker数据卷挂载点(如使用本地挂载) ==========
-data/
-mysql-data/
-edocs/
-temp/
-modules/
-
-# ========== SSL证书(敏感) ==========
-ssl/
-*.crt
-*.key
-*.pem
-
-# ========== 日志文件 ==========
-logs/
-*.log
-
-# ========== 备份文件 ==========
-backups/
-*.sql
-*.tar
-*.tar.gz
-*.zip
-
-# ========== 临时文件 ==========
-tmp/
-temp/
-*.tmp
-*.swp
-*~
-
-# ========== IDE配置 ==========
-.vscode/
-.idea/
-*.code-workspace
-
-# ========== 操作系统文件 ==========
-# Windows
-Thumbs.db
-Desktop.ini
-
-# macOS
-.DS_Store
-.AppleDouble
-.LSOverride
-
-# ========== 其他 ==========
-# 不要忽略README.md
-!README.md
-
-# 不要忽略配置模板
-!env.template
-!*.example
-!*.template
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/redcap-docker-dev/Dockerfile.redcap b/redcap-docker-dev/Dockerfile.redcap
deleted file mode 100644
index b2cbcd37..00000000
--- a/redcap-docker-dev/Dockerfile.redcap
+++ /dev/null
@@ -1,94 +0,0 @@
-# REDCap Docker镜像定义
-# 基于:PHP 8.1 Apache官方镜像
-# 版本:v1.0
-# 日期:2026-01-01
-# 适用:开发/测试/生产环境
-
-FROM php:8.1-apache
-
-LABEL maintainer="IIT Manager Team"
-LABEL description="REDCap 15.8.0 Docker Image for IIT Manager Agent"
-LABEL version="1.0"
-
-# ========== 设置时区 ==========
-ENV TZ=Asia/Shanghai
-RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
-
-# ========== 配置APT使用阿里云镜像源(加速国内构建) ==========
-RUN sed -i 's/deb.debian.org/mirrors.aliyun.com/g' /etc/apt/sources.list.d/debian.sources || \
- sed -i 's/deb.debian.org/mirrors.aliyun.com/g' /etc/apt/sources.list
-
-# ========== 安装系统依赖 ==========
-RUN apt-get update && apt-get install -y \
- # 图片处理库(GD扩展需要)
- libpng-dev \
- libjpeg-dev \
- libfreetype6-dev \
- # ZIP扩展
- libzip-dev \
- # LDAP扩展(可选,企业认证用)
- libldap2-dev \
- # SOAP扩展(可选,Web Service用)
- libxml2-dev \
- # Cron定时任务
- cron \
- # 常用工具
- curl \
- vim \
- unzip \
- # 清理APT缓存
- && rm -rf /var/lib/apt/lists/*
-
-# ========== 安装PHP扩展 ==========
-# GD扩展(图片处理)
-RUN docker-php-ext-configure gd --with-freetype --with-jpeg && \
- docker-php-ext-install -j$(nproc) gd
-
-# 数据库扩展
-RUN docker-php-ext-install -j$(nproc) \
- mysqli \
- pdo_mysql
-
-# 其他必需扩展
-RUN docker-php-ext-install -j$(nproc) \
- zip \
- soap \
- calendar \
- bcmath
-
-# LDAP扩展(可选)
-RUN docker-php-ext-configure ldap --with-libdir=lib/x86_64-linux-gnu/ && \
- docker-php-ext-install ldap
-
-# ========== 启用Apache模块 ==========
-RUN a2enmod rewrite ssl headers
-
-# ========== 创建必需目录 ==========
-RUN mkdir -p /var/www/html/redcap/edocs && \
- mkdir -p /var/www/html/redcap/temp && \
- mkdir -p /var/www/html/redcap/modules && \
- chown -R www-data:www-data /var/www/html
-
-# ========== 配置Cron定时任务 ==========
-# REDCap需要定期运行cron.php
-RUN echo "* * * * * www-data /usr/local/bin/php /var/www/html/redcap/cron.php > /proc/1/fd/1 2>&1" >> /etc/crontab && \
- echo "" >> /etc/crontab
-
-# ========== 复制启动脚本 ==========
-COPY docker-entrypoint.sh /usr/local/bin/
-RUN chmod +x /usr/local/bin/docker-entrypoint.sh
-
-# ========== 暴露端口 ==========
-EXPOSE 80 443
-
-# ========== 健康检查 ==========
-HEALTHCHECK --interval=30s --timeout=10s --retries=3 \
- CMD curl -f http://localhost/ || exit 1
-
-# ========== 工作目录 ==========
-WORKDIR /var/www/html
-
-# ========== 启动命令 ==========
-ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]
-CMD ["apache2-foreground"]
-
diff --git a/redcap-docker-dev/README.md b/redcap-docker-dev/README.md
deleted file mode 100644
index 99533ab4..00000000
--- a/redcap-docker-dev/README.md
+++ /dev/null
@@ -1,406 +0,0 @@
-# REDCap Docker部署环境
-
-> **IIT Manager Agent项目 - REDCap开发/生产一致性环境**
-> 版本:v1.0 | 日期:2026-01-01
-
----
-
-## 📋 目录
-
-1. [快速开始](#快速开始)
-2. [项目结构](#项目结构)
-3. [环境要求](#环境要求)
-4. [详细部署步骤](#详细部署步骤)
-5. [常用命令](#常用命令)
-6. [故障排查](#故障排查)
-7. [生产环境部署](#生产环境部署)
-
----
-
-## 🚀 快速开始
-
-### 一键部署(推荐)
-
-```powershell
-# 进入项目目录
-cd redcap-docker-dev
-
-# 运行一键部署脚本
-.\scripts\setup-redcap.ps1
-
-# 访问REDCap
-# http://localhost:8080/install.php
-```
-
-### 手动部署
-
-```powershell
-# 1. 复制环境变量模板
-copy env.template .env
-
-# 2. 构建并启动容器
-docker-compose up -d
-
-# 3. 查看容器状态
-docker-compose ps
-```
-
----
-
-## 📁 项目结构
-
-```
-redcap-docker-dev/
-├── docker-compose.yml # Docker编排(开发环境)
-├── docker-compose.prod.yml # Docker编排(生产环境)
-├── Dockerfile.redcap # REDCap镜像定义
-├── docker-entrypoint.sh # 容器启动脚本
-├── env.template # 环境变量模板
-├── .gitignore # Git忽略规则
-│
-├── config/ # 配置文件目录
-│ ├── apache/
-│ │ └── redcap.conf # Apache虚拟主机配置
-│ ├── php/
-│ │ └── php.ini # PHP配置
-│ └── database.php # REDCap数据库配置
-│
-├── scripts/ # 运维脚本
-│ ├── setup-redcap.ps1 # 一键部署
-│ ├── start-redcap.ps1 # 启动服务
-│ ├── stop-redcap.ps1 # 停止服务
-│ ├── logs-redcap.ps1 # 查看日志
-│ └── clean-redcap.ps1 # 清理环境
-│
-└── README.md # 本文档
-```
-
----
-
-## 💻 环境要求
-
-### 软件要求
-
-- **Docker Desktop**:20.10+ (Windows/Mac)
-- **PowerShell**:5.1+ 或 PowerShell Core 7+
-- **内存**:至少4GB可用
-- **磁盘**:至少10GB可用空间
-
-### REDCap源码
-
-确保REDCap源码位于正确位置:
-```
-AIclinicalresearch/
-├── redcap15.8.0/
-│ └── redcap/
-└── redcap-docker-dev/ # 当前目录
-```
-
----
-
-## 📖 详细部署步骤
-
-### 步骤1:准备环境变量
-
-```powershell
-# 复制模板
-copy env.template .env
-
-# (可选)编辑.env修改密码
-notepad .env
-```
-
-**默认配置(开发环境)**:
-- MySQL Root密码:`redcap_root_dev_2026`
-- MySQL数据库:`redcap`
-- MySQL用户:`redcap_user`
-- MySQL密码:`redcap_pass_dev_456`
-
-⚠️ **生产环境必须修改所有密码!**
-
-### 步骤2:构建Docker镜像
-
-```powershell
-docker-compose build
-```
-
-**预计时间**:5-10分钟(首次)
-
-### 步骤3:启动容器
-
-```powershell
-docker-compose up -d
-```
-
-**启动的服务**:
-- `redcap-mysql`:MySQL 8.0数据库
-- `redcap-apache`:REDCap Web服务
-- `redcap-phpmyadmin`:数据库管理工具(可选)
-
-### 步骤4:等待服务就绪
-
-```powershell
-# 等待30秒让MySQL完全启动
-# 然后访问:http://localhost:8080/install.php
-```
-
-### 步骤5:安装REDCap
-
-访问:http://localhost:8080/install.php
-
-**数据库配置**:
-- Hostname:`redcap-db`
-- Database:`redcap`
-- Username:`redcap_user`
-- Password:`redcap_pass_dev_456`
-- Salt:`iit_dev_salt_2026_redcap_v15_do_not_change`
-
-**管理员账户(示例)**:
-- Username:`admin`
-- Password:`Admin@123456`(开发环境)
-- Email:`dev@example.com`
-
-**SMTP配置**:
-- 选择"Skip SMTP Configuration"(开发环境不需要邮件)
-
----
-
-## 🔧 常用命令
-
-### 启动/停止
-
-```powershell
-# 启动服务
-.\scripts\start-redcap.ps1
-
-# 停止服务(保留数据)
-.\scripts\stop-redcap.ps1
-
-# 重启服务
-.\scripts\stop-redcap.ps1
-.\scripts\start-redcap.ps1
-```
-
-### 查看日志
-
-```powershell
-# 查看所有服务日志
-.\scripts\logs-redcap.ps1
-
-# 查看特定服务
-.\scripts\logs-redcap.ps1 -Service redcap-web
-
-# 实时跟踪日志
-.\scripts\logs-redcap.ps1 -Follow
-
-# 显示更多行
-.\scripts\logs-redcap.ps1 -Tail 100
-```
-
-### 容器管理
-
-```powershell
-# 查看容器状态
-docker-compose ps
-
-# 进入容器
-docker exec -it redcap-apache bash
-
-# 重启特定容器
-docker-compose restart redcap-web
-
-# 查看资源使用
-docker stats
-```
-
-### 数据库管理
-
-```powershell
-# 通过phpMyAdmin
-# 访问:http://localhost:8081
-# 用户:root
-# 密码:redcap_root_dev_2026
-
-# 或通过命令行
-docker exec -it redcap-mysql mysql -uroot -predcap_root_dev_2026 redcap
-```
-
-### 清理环境
-
-```powershell
-# 完全清理(删除所有数据)
-.\scripts\clean-redcap.ps1
-```
-
-⚠️ **警告**:此命令会删除所有数据,无法恢复!
-
----
-
-## 🔍 故障排查
-
-### 问题1:容器无法启动
-
-```powershell
-# 检查Docker状态
-docker info
-
-# 查看容器日志
-docker-compose logs
-
-# 检查端口占用
-netstat -ano | findstr :8080
-```
-
-### 问题2:无法访问REDCap
-
-```powershell
-# 检查容器运行状态
-docker-compose ps
-
-# 检查Apache日志
-docker-compose logs redcap-web
-
-# 进入容器诊断
-docker exec -it redcap-apache bash
-curl localhost
-```
-
-### 问题3:数据库连接失败
-
-```powershell
-# 检查MySQL日志
-docker-compose logs redcap-db
-
-# 等待MySQL完全启动(30秒)
-Start-Sleep -Seconds 30
-
-# 测试连接
-docker exec -it redcap-mysql mysql -uredcap_user -predcap_pass_dev_456 -e "SHOW DATABASES;"
-```
-
-### 问题4:端口冲突
-
-```powershell
-# 修改docker-compose.yml中的端口映射
-# 例如将8080改为8888:
-ports:
- - "8888:80" # 主机端口:容器端口
-```
-
----
-
-## 🏗️ 生产环境部署
-
-### 使用生产配置
-
-```powershell
-# 使用生产环境配置文件
-docker-compose -f docker-compose.prod.yml up -d
-```
-
-### 关键差异
-
-| 配置项 | 开发环境 | 生产环境 |
-|--------|---------|---------|
-| **phpMyAdmin** | ✅ 启用 | ❌ 禁用(安全) |
-| **MySQL** | Docker容器 | 阿里云RDS(推荐) |
-| **密码** | 简单密码 | 强密码(32+字符) |
-| **SSL** | 不需要 | 必需(HTTPS) |
-| **日志** | 详细 | 精简 |
-| **资源限制** | 无 | 配置限制 |
-
-### 生产环境检查清单
-
-- [ ] 修改所有默认密码
-- [ ] 配置RDS MySQL连接
-- [ ] 移除phpMyAdmin容器
-- [ ] 启用HTTPS(SSL证书)
-- [ ] 配置防火墙规则
-- [ ] 配置自动备份
-- [ ] 配置监控告警
-- [ ] 限制SSH访问
-
-### 详细生产部署文档
-
-参考:`docs/03-业务模块/Redcap/03-REDCap本地Docker开发环境部署方案.md`
-
----
-
-## 📚 相关文档
-
-- [REDCap本地Docker开发环境部署方案](../../docs/03-业务模块/Redcap/03-REDCap本地Docker开发环境部署方案.md)
-- [REDCap生产环境部署:ECS vs SAE深度决议报告](../../docs/03-业务模块/Redcap/REDCap%20生产环境部署:ECS%20vs%20SAE%20深度决议报告.md)
-- [REDCap二次开发深度指南](../../docs/03-业务模块/Redcap/REDCap%20二次开发深度指南.md)
-- [IIT Manager Agent MVP开发任务清单](../../docs/03-业务模块/IIT%20Manager%20Agent/04-开发计划/MVP开发任务清单.md)
-
----
-
-## 📞 技术支持
-
-**需要帮助?**
-
-1. 查看详细文档(上方链接)
-2. 查看容器日志:`.\scripts\logs-redcap.ps1`
-3. 参考REDCap官方文档:https://projectredcap.org/
-4. 联系IIT Manager开发团队
-
----
-
-## 🎯 下一步
-
-**部署成功后**:
-
-1. ✅ **完成REDCap安装**(install.php)
-2. ✅ **创建测试项目**(IIT试验项目)
-3. ✅ **生成API Token**
-4. ✅ **开始Day 2开发**(REDCap API Adapter)
-
-参考:[MVP开发任务清单](../../docs/03-业务模块/IIT%20Manager%20Agent/04-开发计划/MVP开发任务清单.md)
-
----
-
-> **文档维护**:IIT Manager开发团队
-> **最后更新**:2026-01-01
-> **版本**:v1.0
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/redcap-docker-dev/config/apache/redcap.conf b/redcap-docker-dev/config/apache/redcap.conf
deleted file mode 100644
index 4df5e161..00000000
--- a/redcap-docker-dev/config/apache/redcap.conf
+++ /dev/null
@@ -1,126 +0,0 @@
-# REDCap Apache虚拟主机配置
-# 版本:v1.0
-# 日期:2026-01-01
-# 适用:开发/测试/生产环境
-
-
- ServerName localhost
- ServerAdmin admin@localhost
- DocumentRoot /var/www/html/redcap
-
- # ========== 目录配置 ==========
-
- # 禁止目录浏览(安全)
- Options -Indexes +FollowSymLinks
-
- # 允许.htaccess覆盖
- AllowOverride All
-
- # 访问权限
- Require all granted
-
- # 默认首页
- DirectoryIndex index.php index.html
-
-
- # ========== 限制特定目录访问(安全) ==========
- # 禁止直接访问temp目录
-
- Require all denied
-
-
- # 禁止直接访问modules源码(仅允许通过REDCap访问)
-
- Require all denied
-
-
- # ========== 日志配置 ==========
- ErrorLog ${APACHE_LOG_DIR}/redcap-error.log
- CustomLog ${APACHE_LOG_DIR}/redcap-access.log combined
-
- # 日志级别(开发环境:info,生产环境:warn)
- LogLevel warn
-
- # ========== 安全头(推荐) ==========
- # 防止点击劫持
- Header always set X-Frame-Options "SAMEORIGIN"
-
- # 防止MIME类型嗅探
- Header always set X-Content-Type-Options "nosniff"
-
- # XSS保护
- Header always set X-XSS-Protection "1; mode=block"
-
- # Referrer策略
- Header always set Referrer-Policy "strict-origin-when-cross-origin"
-
- # ========== PHP配置覆盖 ==========
- # 文件上传限制
- php_value upload_max_filesize 32M
- php_value post_max_size 32M
-
- # 执行时间限制(数据导出需要)
- php_value max_execution_time 300
- php_value max_input_time 300
-
- # 内存限制
- php_value memory_limit 256M
-
- # ========== 性能优化 ==========
- # 启用gzip压缩(暂时禁用,解决浏览器解码问题)
- #
- # AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript application/javascript application/json
- #
-
- # 浏览器缓存(静态资源)
-
- ExpiresActive On
- ExpiresByType image/jpg "access plus 1 month"
- ExpiresByType image/jpeg "access plus 1 month"
- ExpiresByType image/png "access plus 1 month"
- ExpiresByType image/gif "access plus 1 month"
- ExpiresByType text/css "access plus 1 week"
- ExpiresByType application/javascript "access plus 1 week"
-
-
-
-# ========== HTTPS配置(生产环境) ==========
-# 生产环境应启用HTTPS,取消下方注释并配置SSL证书:
-
-#
-# ServerName redcap.yourdomain.com
-# ServerAdmin admin@yourdomain.com
-# DocumentRoot /var/www/html/redcap
-#
-# # SSL证书配置
-# SSLEngine on
-# SSLCertificateFile /etc/ssl/certs/redcap.crt
-# SSLCertificateKeyFile /etc/ssl/private/redcap.key
-# # 如有中间证书:
-# # SSLCertificateChainFile /etc/ssl/certs/intermediate.crt
-#
-# # SSL安全配置
-# SSLProtocol all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
-# SSLCipherSuite HIGH:!aNULL:!MD5:!3DES
-# SSLHonorCipherOrder on
-#
-# # HSTS(强制HTTPS)
-# Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
-#
-# # 其他配置同上(Directory、Log等)
-#
-# Options -Indexes +FollowSymLinks
-# AllowOverride All
-# Require all granted
-#
-#
-# ErrorLog ${APACHE_LOG_DIR}/redcap-ssl-error.log
-# CustomLog ${APACHE_LOG_DIR}/redcap-ssl-access.log combined
-#
-
-# ========== HTTP强制跳转HTTPS(生产环境启用) ==========
-#
-# ServerName redcap.yourdomain.com
-# Redirect permanent / https://redcap.yourdomain.com/
-#
-
diff --git a/redcap-docker-dev/config/database.php b/redcap-docker-dev/config/database.php
deleted file mode 100644
index 722f99fd..00000000
--- a/redcap-docker-dev/config/database.php
+++ /dev/null
@@ -1,137 +0,0 @@
-/dev/null || echo "deflate module not enabled"
-echo "✅ Apache compression disabled"
-
-# ========== 设置文件权限 ==========
-echo ""
-echo "Setting file permissions..."
-chown -R www-data:www-data /var/www/html/redcap/edocs
-chown -R www-data:www-data /var/www/html/redcap/temp
-chown -R www-data:www-data /var/www/html/redcap/modules
-
-# ========== 检查并修复database.php配置 ==========
-echo ""
-if [ -f "/var/www/html/redcap/database.php" ]; then
- echo "✅ database.php found"
-
- # 检查并删除可能导致输出污染的PHP结束标签和空行
- # PHP最佳实践:配置文件末尾不应该有?>标签
- if grep -q '^?>$' /var/www/html/redcap/database.php 2>/dev/null; then
- echo "⚠️ Removing PHP closing tag and trailing whitespace from database.php..."
- # 创建临时文件(因为原文件可能是只读挂载)
- # 注意:这个警告可以忽略,下次容器重启会从主机文件重新挂载
- fi
-else
- echo "⚠️ WARNING: database.php not found!"
- echo "REDCap installation will fail without database configuration."
-fi
-
-# ========== 启动Cron服务 ==========
-echo ""
-echo "Starting cron service for REDCap scheduled tasks..."
-service cron start
-
-# 验证Cron是否运行
-if service cron status > /dev/null 2>&1; then
- echo "✅ Cron service started successfully"
-else
- echo "⚠️ WARNING: Cron service failed to start"
-fi
-
-# ========== 显示数据库连接信息(调试用) ==========
-if [ -n "$REDCAP_DB_HOST" ]; then
- echo ""
- echo "Database Configuration:"
- echo " Host: ${REDCAP_DB_HOST}"
- echo " Port: ${REDCAP_DB_PORT:-3306}"
- echo " Database: ${REDCAP_DB_NAME}"
- echo " User: ${REDCAP_DB_USER}"
-fi
-
-# ========== 显示服务URL ==========
-echo ""
-echo "============================================"
-echo "REDCap Container Ready!"
-echo "============================================"
-echo "Access REDCap at:"
-echo " - Development: http://localhost:8080"
-echo " - Production: http://your-domain.com"
-echo ""
-echo "Important URLs:"
-echo " - Install: /install.php"
-echo " - Control Center: /ControlCenter/"
-echo " - API Help: /api/help/"
-echo "============================================"
-echo ""
-
-# ========== 执行传入的命令 ==========
-exec "$@"
-
diff --git a/redcap-docker-dev/env.template b/redcap-docker-dev/env.template
deleted file mode 100644
index 414730ff..00000000
--- a/redcap-docker-dev/env.template
+++ /dev/null
@@ -1,101 +0,0 @@
-# REDCap Docker环境变量配置模板
-# 版本:v1.0
-# 日期:2026-01-01
-# 用途:环境变量模板
-# 使用方法:复制此文件为.env后修改
-# Windows: copy env.template .env
-# Linux/Mac: cp env.template .env
-
-# ========== MySQL数据库配置(开发环境) ==========
-# ⚠️ 警告:这些是开发环境密码,生产环境必须修改!
-
-# MySQL Root密码
-MYSQL_ROOT_PASSWORD=redcap_root_dev_2026
-
-# MySQL数据库名
-MYSQL_DATABASE=redcap
-
-# MySQL用户名
-MYSQL_USER=redcap_user
-
-# MySQL用户密码
-MYSQL_PASSWORD=redcap_pass_dev_456
-
-# ========== 生产环境配置(ECS + RDS) ==========
-# 生产环境使用时,取消注释并修改以下配置:
-
-# RDS MySQL连接信息
-# REDCAP_DB_HOST=rm-xxxxxx.mysql.rds.aliyuncs.com
-# REDCAP_DB_PORT=3306
-# MYSQL_DATABASE=redcap_prod
-# MYSQL_USER=redcap_user_prod
-# MYSQL_PASSWORD=YOUR_STRONG_PASSWORD_HERE
-
-# ========== REDCap Salt值 ==========
-# ⚠️ 重要:Salt一旦设置,永远不可更改!
-# 用于数据去标识化哈希
-
-# 开发环境Salt(固定值,便于重建环境)
-REDCAP_SALT=iit_dev_salt_2026_redcap_v15_do_not_change
-
-# 生产环境Salt(必须使用强随机值)
-# REDCAP_SALT=YOUR_STRONG_RANDOM_SALT_32_CHARS_MINIMUM_WITH_SPECIAL_CHARS
-
-# ========== 时区配置 ==========
-TZ=Asia/Shanghai
-
-# ========== 开发工具配置 ==========
-# phpMyAdmin(仅开发环境)
-PMA_UPLOAD_LIMIT=50M
-
-# ========== 注意事项 ==========
-# 1. 复制此文件为.env后使用:copy env.template .env
-# 2. 不要将.env文件提交到Git(已添加到.gitignore)
-# 3. 生产环境必须修改所有密码和Salt值
-# 4. Salt值设置后永远不可更改
-# 5. 生产环境密码建议使用32+字符的强密码
-# 6. 可以使用以下命令生成随机密码:
-# PowerShell: -join ((65..90) + (97..122) + (48..57) + (33..47) | Get-Random -Count 32 | % {[char]$_})
-# Linux/Mac: openssl rand -base64 32
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/redcap-docker-dev/scripts/clean-redcap.ps1 b/redcap-docker-dev/scripts/clean-redcap.ps1
deleted file mode 100644
index 0681b39a..00000000
--- a/redcap-docker-dev/scripts/clean-redcap.ps1
+++ /dev/null
@@ -1,109 +0,0 @@
-#!/usr/bin/env pwsh
-# REDCap Docker环境清理脚本
-# 版本:v1.0
-# 日期:2026-01-01
-# ⚠️ 警告:此脚本会删除所有数据!
-
-Write-Host "🗑️ REDCap Docker环境清理" -ForegroundColor Red
-Write-Host ""
-Write-Host "⚠️ 警告:此操作将删除所有数据!" -ForegroundColor Red
-Write-Host " • 容器将被删除" -ForegroundColor Yellow
-Write-Host " • 数据卷将被删除(包括数据库、上传文件)" -ForegroundColor Yellow
-Write-Host " • Docker镜像将被删除" -ForegroundColor Yellow
-Write-Host ""
-
-# 切换到项目目录
-$ScriptDir = Split-Path -Parent $PSCommandPath
-$ProjectDir = Split-Path -Parent $ScriptDir
-Set-Location $ProjectDir
-
-# 二次确认
-$confirm1 = Read-Host "确认要删除所有数据吗?(输入 YES 继续)"
-if ($confirm1 -ne "YES") {
- Write-Host "❌ 清理已取消。" -ForegroundColor Yellow
- exit 0
-}
-
-Write-Host ""
-$confirm2 = Read-Host "最后确认:真的要删除所有数据吗?(再次输入 YES)"
-if ($confirm2 -ne "YES") {
- Write-Host "❌ 清理已取消。" -ForegroundColor Yellow
- exit 0
-}
-
-Write-Host ""
-Write-Host "🗑️ 开始清理..." -ForegroundColor Yellow
-Write-Host ""
-
-# 停止并删除容器
-Write-Host " 1. 停止并删除容器..." -ForegroundColor Gray
-docker-compose down
-
-# 删除数据卷
-Write-Host " 2. 删除数据卷..." -ForegroundColor Gray
-docker-compose down --volumes
-
-# 删除镜像
-Write-Host " 3. 删除Docker镜像..." -ForegroundColor Gray
-$images = docker images --filter=reference="redcap-docker-dev*" -q
-if ($images) {
- docker rmi $images 2>&1 | Out-Null
-}
-
-# 显示Docker卷列表
-Write-Host " 4. 验证清理结果..." -ForegroundColor Gray
-Write-Host ""
-Write-Host "剩余的REDCap相关卷:" -ForegroundColor Cyan
-docker volume ls | Select-String "redcap"
-
-Write-Host ""
-Write-Host "============================================" -ForegroundColor Green
-Write-Host " ✅ 清理完成!" -ForegroundColor Green
-Write-Host "============================================" -ForegroundColor Green
-Write-Host ""
-Write-Host "💡 提示:" -ForegroundColor Cyan
-Write-Host " • 如需重新部署:.\scripts\setup-redcap.ps1" -ForegroundColor Gray
-Write-Host " • 数据已完全删除,无法恢复" -ForegroundColor Gray
-Write-Host ""
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/redcap-docker-dev/scripts/create-redcap-password.php b/redcap-docker-dev/scripts/create-redcap-password.php
deleted file mode 100644
index 1f403927..00000000
--- a/redcap-docker-dev/scripts/create-redcap-password.php
+++ /dev/null
@@ -1,87 +0,0 @@
-?~';
-for ($i = 0; $i < 100; $i++) {
- $salt .= $characters[random_int(0, strlen($characters) - 1)];
-}
-
-// 生成密码哈希(SHA-512(password + salt))
-$password_hash = hash('sha512', $new_password . $salt);
-
-// 数据库连接信息
-$db_host = getenv('REDCAP_DB_HOST') ?: 'redcap-mysql';
-$db_name = getenv('REDCAP_DB_NAME') ?: 'redcap';
-$db_user = getenv('REDCAP_DB_USER') ?: 'redcap_user';
-$db_pass = getenv('REDCAP_DB_PASS') ?: 'redcap_pass_dev_456';
-
-try {
- $pdo = new PDO("mysql:host=$db_host;dbname=$db_name", $db_user, $db_pass);
- $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
-
- // 更新密码
- $stmt = $pdo->prepare("UPDATE redcap_auth SET password = ?, password_salt = ? WHERE username = ?");
- $result = $stmt->execute([$password_hash, $salt, $username]);
-
- if ($result) {
- echo "✅ Password updated successfully!\n\n";
- echo "Username: $username\n";
- echo "New Password: $new_password\n\n";
- echo "You can now login at: http://localhost:8080/\n";
- } else {
- echo "❌ Failed to update password\n";
- }
-
-} catch (PDOException $e) {
- echo "❌ Database error: " . $e->getMessage() . "\n";
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/redcap-docker-dev/scripts/logs-redcap.ps1 b/redcap-docker-dev/scripts/logs-redcap.ps1
deleted file mode 100644
index 5a463775..00000000
--- a/redcap-docker-dev/scripts/logs-redcap.ps1
+++ /dev/null
@@ -1,100 +0,0 @@
-#!/usr/bin/env pwsh
-# REDCap Docker日志查看脚本
-# 版本:v1.0
-# 日期:2026-01-01
-
-param(
- [string]$Service = "", # 指定服务名(redcap-web, redcap-db, phpmyadmin)
- [switch]$Follow, # 实时跟踪日志
- [int]$Tail = 50 # 显示最近N行日志
-)
-
-Write-Host "📝 REDCap Docker日志" -ForegroundColor Cyan
-Write-Host ""
-
-# 切换到项目目录
-$ScriptDir = Split-Path -Parent $PSCommandPath
-$ProjectDir = Split-Path -Parent $ScriptDir
-Set-Location $ProjectDir
-
-# 构建docker-compose logs命令
-$logCmd = "docker-compose logs"
-
-if ($Follow) {
- $logCmd += " -f"
-} else {
- $logCmd += " --tail=$Tail"
-}
-
-if ($Service) {
- $logCmd += " $Service"
- Write-Host "查看服务:$Service" -ForegroundColor Yellow
-} else {
- Write-Host "查看所有服务日志" -ForegroundColor Yellow
-}
-
-if ($Follow) {
- Write-Host "实时跟踪模式(按Ctrl+C退出)" -ForegroundColor Gray
-} else {
- Write-Host "显示最近 $Tail 行日志" -ForegroundColor Gray
-}
-
-Write-Host ""
-Write-Host "============================================" -ForegroundColor Gray
-
-# 执行命令
-Invoke-Expression $logCmd
-
-Write-Host ""
-Write-Host "💡 提示:" -ForegroundColor Cyan
-Write-Host " • 查看特定服务:.\scripts\logs-redcap.ps1 -Service redcap-web" -ForegroundColor Gray
-Write-Host " • 实时跟踪:.\scripts\logs-redcap.ps1 -Follow" -ForegroundColor Gray
-Write-Host " • 显示更多行:.\scripts\logs-redcap.ps1 -Tail 100" -ForegroundColor Gray
-Write-Host ""
-Write-Host "可用服务名:" -ForegroundColor Cyan
-Write-Host " • redcap-web(REDCap Web服务)" -ForegroundColor Gray
-Write-Host " • redcap-db(MySQL数据库)" -ForegroundColor Gray
-Write-Host " • phpmyadmin(数据库管理工具)" -ForegroundColor Gray
-Write-Host ""
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/redcap-docker-dev/scripts/reset-admin-password.php b/redcap-docker-dev/scripts/reset-admin-password.php
deleted file mode 100644
index a1f0170f..00000000
--- a/redcap-docker-dev/scripts/reset-admin-password.php
+++ /dev/null
@@ -1,63 +0,0 @@
-&1
- if ($LASTEXITCODE -ne 0) {
- Write-Host " X" -ForegroundColor Red
- Write-Host "Docker未安装或未运行!" -ForegroundColor Red
- exit 1
- }
- Write-Host " OK" -ForegroundColor Green
-
- Write-Host " 检查Docker Compose..." -NoNewline
- $null = docker-compose --version 2>&1
- if ($LASTEXITCODE -ne 0) {
- Write-Host " X" -ForegroundColor Red
- Write-Host "Docker Compose未安装!" -ForegroundColor Red
- exit 1
- }
- Write-Host " OK" -ForegroundColor Green
-
- Write-Host " 检查REDCap源码..." -NoNewline
- if (-not (Test-Path "..\redcap15.8.0\redcap\index.php")) {
- Write-Host " X" -ForegroundColor Red
- Write-Host "REDCap源码未找到!" -ForegroundColor Red
- exit 1
- }
- Write-Host " OK" -ForegroundColor Green
- Write-Host "环境检查通过!" -ForegroundColor Green
- Write-Host ""
-}
-
-# 步骤 2: 创建.env文件
-Write-Host "步骤 2/7: 配置环境变量..." -ForegroundColor Yellow
-
-$envExists = Test-Path ".env"
-if (-not $envExists) {
- Write-Host " 从模板创建.env文件..." -ForegroundColor Gray
- $templateExists = Test-Path "env.template"
- if (-not $templateExists) {
- Write-Host " 未找到env.template!" -ForegroundColor Red
- exit 1
- }
- Copy-Item "env.template" ".env"
- Write-Host " .env文件已创建" -ForegroundColor Green
-}
-if ($envExists) {
- Write-Host " .env文件已存在" -ForegroundColor Green
-}
-Write-Host ""
-
-# 步骤 3: 检查端口
-Write-Host "步骤 3/7: 检查端口占用..." -ForegroundColor Yellow
-
-$ports = @(8080, 3306, 8081)
-$portsInUse = @()
-
-foreach ($port in $ports) {
- $check = netstat -ano | Select-String ":$port " | Select-Object -First 1
- if ($check) {
- Write-Host " 端口 $port 已被占用" -ForegroundColor Yellow
- $portsInUse += $port
- continue
- }
- Write-Host " 端口 $port 可用" -ForegroundColor Green
-}
-
-if ($portsInUse.Count -gt 0) {
- Write-Host ""
- Write-Host "警告: 部分端口被占用!" -ForegroundColor Yellow
- if (-not $Force) {
- $continue = Read-Host "是否继续? (Y/N)"
- if ($continue -ne "Y") {
- Write-Host "部署已取消" -ForegroundColor Yellow
- exit 0
- }
- }
-}
-Write-Host ""
-
-# 步骤 4: 清理旧容器
-if ($Force) {
- Write-Host "步骤 4/7: 清理旧容器..." -ForegroundColor Yellow
- docker-compose down 2>&1 | Out-Null
- Write-Host " 旧容器已清理" -ForegroundColor Green
- Write-Host ""
-}
-if (-not $Force) {
- Write-Host "步骤 4/7: 跳过清理 (使用 -Force 强制清理)" -ForegroundColor Gray
- Write-Host ""
-}
-
-# 步骤 5: 构建镜像
-Write-Host "步骤 5/7: 构建Docker镜像..." -ForegroundColor Yellow
-Write-Host " 这可能需要几分钟..." -ForegroundColor Gray
-Write-Host ""
-
-docker-compose build
-if ($LASTEXITCODE -ne 0) {
- Write-Host "Docker镜像构建失败!" -ForegroundColor Red
- exit 1
-}
-
-Write-Host ""
-Write-Host "Docker镜像构建成功!" -ForegroundColor Green
-Write-Host ""
-
-# 步骤 6: 启动容器
-Write-Host "步骤 6/7: 启动容器..." -ForegroundColor Yellow
-
-docker-compose up -d
-if ($LASTEXITCODE -ne 0) {
- Write-Host "容器启动失败!" -ForegroundColor Red
- exit 1
-}
-
-Write-Host "容器启动成功!" -ForegroundColor Green
-Write-Host ""
-
-# 步骤 7: 等待服务就绪
-Write-Host "步骤 7/7: 等待服务就绪..." -ForegroundColor Yellow
-Write-Host " 等待MySQL启动 (30秒)..." -ForegroundColor Gray
-Start-Sleep -Seconds 30
-
-Write-Host ""
-Write-Host "容器状态:" -ForegroundColor Cyan
-docker-compose ps
-
-# 部署完成
-Write-Host ""
-Write-Host "============================================" -ForegroundColor Green
-Write-Host " REDCap Docker环境部署完成!" -ForegroundColor Green
-Write-Host "============================================" -ForegroundColor Green
-Write-Host ""
-Write-Host "服务访问地址:" -ForegroundColor Cyan
-Write-Host " REDCap: http://localhost:8080" -ForegroundColor White
-Write-Host " phpMyAdmin: http://localhost:8081" -ForegroundColor White
-Write-Host ""
-Write-Host "下一步操作:" -ForegroundColor Cyan
-Write-Host " 1. 访问 http://localhost:8080/install.php" -ForegroundColor White
-Write-Host " 2. 数据库配置:" -ForegroundColor White
-Write-Host " Host: redcap-db" -ForegroundColor Gray
-Write-Host " Database: redcap" -ForegroundColor Gray
-Write-Host " User: redcap_user" -ForegroundColor Gray
-Write-Host " Password: redcap_pass_dev_456" -ForegroundColor Gray
-Write-Host ""
diff --git a/redcap-docker-dev/scripts/start-redcap.ps1 b/redcap-docker-dev/scripts/start-redcap.ps1
deleted file mode 100644
index 39184408..00000000
--- a/redcap-docker-dev/scripts/start-redcap.ps1
+++ /dev/null
@@ -1,85 +0,0 @@
-#!/usr/bin/env pwsh
-# REDCap Docker环境启动脚本
-# 版本:v1.0
-# 日期:2026-01-01
-
-Write-Host "🚀 启动REDCap Docker环境..." -ForegroundColor Cyan
-Write-Host ""
-
-# 切换到项目目录
-$ScriptDir = Split-Path -Parent $PSCommandPath
-$ProjectDir = Split-Path -Parent $ScriptDir
-Set-Location $ProjectDir
-
-# 检查Docker是否运行
-$dockerRunning = docker info 2>&1 | Select-String "Server Version"
-if (-not $dockerRunning) {
- Write-Host "❌ Docker未运行。请先启动Docker Desktop。" -ForegroundColor Red
- exit 1
-}
-
-# 启动容器
-docker-compose up -d
-
-if ($LASTEXITCODE -eq 0) {
- Write-Host ""
- Write-Host "⏳ 等待服务就绪(10秒)..." -ForegroundColor Yellow
- Start-Sleep -Seconds 10
-
- Write-Host ""
- Write-Host "✅ REDCap环境已启动!" -ForegroundColor Green
- Write-Host ""
- Write-Host "📋 服务访问地址:" -ForegroundColor Cyan
- Write-Host " • REDCap: http://localhost:8080" -ForegroundColor White
- Write-Host " • phpMyAdmin: http://localhost:8081" -ForegroundColor White
- Write-Host ""
- Write-Host "📊 容器状态:" -ForegroundColor Cyan
- docker-compose ps
- Write-Host ""
-} else {
- Write-Host "❌ 启动失败!" -ForegroundColor Red
- Write-Host "请检查日志:.\scripts\logs-redcap.ps1" -ForegroundColor Yellow
- exit 1
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/redcap-docker-dev/scripts/stop-redcap.ps1 b/redcap-docker-dev/scripts/stop-redcap.ps1
deleted file mode 100644
index e2ffa2fd..00000000
--- a/redcap-docker-dev/scripts/stop-redcap.ps1
+++ /dev/null
@@ -1,71 +0,0 @@
-#!/usr/bin/env pwsh
-# REDCap Docker环境停止脚本
-# 版本:v1.0
-# 日期:2026-01-01
-
-Write-Host "⏹️ 停止REDCap Docker环境..." -ForegroundColor Yellow
-Write-Host ""
-
-# 切换到项目目录
-$ScriptDir = Split-Path -Parent $PSCommandPath
-$ProjectDir = Split-Path -Parent $ScriptDir
-Set-Location $ProjectDir
-
-# 停止容器(保留数据)
-docker-compose stop
-
-if ($LASTEXITCODE -eq 0) {
- Write-Host ""
- Write-Host "✅ REDCap环境已停止!" -ForegroundColor Green
- Write-Host ""
- Write-Host "💡 提示:" -ForegroundColor Cyan
- Write-Host " • 数据已保留在Docker卷中" -ForegroundColor Gray
- Write-Host " • 重新启动:.\scripts\start-redcap.ps1" -ForegroundColor Gray
- Write-Host " • 完全清理(删除数据):.\scripts\clean-redcap.ps1" -ForegroundColor Gray
- Write-Host ""
-} else {
- Write-Host "❌ 停止失败!" -ForegroundColor Red
- exit 1
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/t === Checking Git status === -ForegroundColor Cyan b/t === Checking Git status === -ForegroundColor Cyan
deleted file mode 100644
index dd8eb5eb..00000000
--- a/t === Checking Git status === -ForegroundColor Cyan
+++ /dev/null
@@ -1,120 +0,0 @@
-[33mcommit ef967d7d7cb1a731d36a6568e5b0b0c1e34e71aa[m[33m ([m[1;36mHEAD[m[33m -> [m[1;32mmaster[m[33m, [m[1;31morigin/master[m[33m)[m
-Author: HaHafeng
-AuthorDate: Wed Dec 24 22:12:00 2025 +0800
-Commit: HaHafeng
-CommitDate: Wed Dec 24 22:12:00 2025 +0800
-
- build(backend): Complete Node.js backend deployment preparation
-
- Major changes:
- - Add Docker configuration (Dockerfile, .dockerignore)
- - Fix 200+ TypeScript compilation errors
- - Add Prisma schema relations for all models (30+ relations)
- - Update tsconfig.json to relax non-critical checks
- - Optimize Docker build with local dist strategy
-
- Technical details:
- - Exclude test files from TypeScript compilation
- - Add manual relations for ASL, PKB, DC, AIA modules
- - Use type assertions for JSON/Buffer compatibility
- - Fix pg-boss, extractionWorker, and other legacy code issues
-
- Build result:
- - Docker image: 838MB (compressed ~186MB)
- - Successfully pushed to ACR
- - Zero TypeScript compilation errors
-
- Related docs:
- - Update deployment documentation
- - Add Python microservice SAE deployment guide
-
- DC模块代码恢复指南.md | 1 [32m+[m
- backend/.dockerignore | 55 [32m+[m
- backend/.env.backup | 31 [32m+[m
- backend/Dockerfile | 74 [32m++[m
- .../add_data_stats_to_tool_c_session.sql | 1 [32m+[m
- .../001_add_postgres_cache_and_checkpoint.sql | 1 [32m+[m
- .../prisma/manual-migrations/run-migration-002.ts | 1 [32m+[m
- .../20251208_add_column_mapping/migration.sql | 1 [32m+[m
- .../prisma/migrations/create_tool_c_session.sql | 1 [32m+[m
- backend/prisma/schema.prisma | 1350 [32m+++++++++[m[31m-----------[m
- backend/recover-code-from-cursor-db.js | 1 [32m+[m
- backend/scripts/check-dc-tables.mjs | 1 [32m+[m
- backend/scripts/create-tool-c-ai-history-table.mjs | 1 [32m+[m
- backend/scripts/create-tool-c-table.js | 1 [32m+[m
- backend/scripts/create-tool-c-table.mjs | 1 [32m+[m
- backend/src/common/jobs/PgBossQueue.ts | 5 [32m+[m[31m-[m
- backend/src/common/jobs/utils.ts | 1 [32m+[m
- .../legacy/controllers/conversationController.ts | 2 [32m+[m[31m-[m
- backend/src/legacy/controllers/reviewController.ts | 2 [32m+[m[31m-[m
- backend/src/legacy/services/batchService.ts | 2 [32m+[m[31m-[m
- .../modules/asl/controllers/projectController.ts | 8 [32m+[m[31m-[m
- .../__tests__/api-integration-test.ts | 1 [32m+[m
- .../__tests__/e2e-real-test-v2.ts | 1 [32m+[m
- .../__tests__/fulltext-screening-api.http | 1 [32m+[m
- .../fulltext-screening/services/ExcelExporter.ts | 5 [32m+[m[31m-[m
- .../services/FulltextScreeningService.ts | 10 [32m+[m[31m-[m
- .../modules/asl/services/llmScreeningService.ts | 2 [32m+[m[31m-[m
- .../dc/tool-b/services/ConflictDetectionService.ts | 1 [32m+[m
- .../modules/dc/tool-b/services/TemplateService.ts | 5 [32m+[m[31m-[m
- .../modules/dc/tool-b/workers/extractionWorker.ts | 1 [32m+[m
- backend/src/modules/dc/tool-c/README.md | 1 [32m+[m
- .../dc/tool-c/controllers/StreamAIController.ts | 1 [32m+[m
- .../modules/dc/tool-c/services/SessionService.ts | 6 [32m+[m[31m-[m
- backend/src/tests/README.md | 1 [32m+[m
- backend/src/tests/verify-test1-database.sql | 1 [32m+[m
- backend/src/tests/verify-test1-database.ts | 1 [32m+[m
- backend/src/types/global.d.ts | 1 [32m+[m
- backend/sync-dc-database.ps1 | 1 [32m+[m
- backend/test-tool-c-advanced-scenarios.mjs | 1 [32m+[m
- backend/test-tool-c-day2.mjs | 1 [32m+[m
- backend/test-tool-c-day3.mjs | 1 [32m+[m
- backend/tsconfig.json | 16 [32m+[m[31m-[m
- deploy-to-sae.ps1 | 1 [32m+[m
- docs/00-系统总体设计/00-系统当前状态与开发指南.md | 2 [32m+[m[31m-[m
- .../02-通用能力层/Postgres-Only异步任务处理指南.md | 1 [32m+[m
- docs/02-通用能力层/通用能力层技术债务清单.md | 1 [32m+[m
- .../04-开发计划/05-全文复筛前端开发计划.md | 1 [32m+[m
- .../05-开发记录/2025-01-23_全文复筛前端开发完成.md | 1 [32m+[m
- .../05-开发记录/2025-01-23_全文复筛前端逻辑调整.md | 1 [32m+[m
- .../05-开发记录/2025-11-23_Day5_全文复筛API开发.md | 1 [32m+[m
- .../04-开发计划/工具C_AI_Few-shot示例库.md | 1 [32m+[m
- .../04-开发计划/工具C_Bug修复总结_2025-12-08.md | 1 [32m+[m
- .../DC-数据清洗整理/04-开发计划/工具C_Day3开发计划.md | 1 [32m+[m
- .../04-开发计划/工具C_Day4-5前端开发计划.md | 1 [32m+[m
- .../04-开发计划/工具C_Pivot列顺序优化总结.md | 1 [32m+[m
- .../04-开发计划/工具C_方案B实施总结_2025-12-09.md | 1 [32m+[m
- .../04-开发计划/工具C_缺失值处理_开发进度_2025-12-10.md | 1 [32m+[m
- .../04-开发计划/工具C_缺失值处理功能_更新说明.md | 1 [32m+[m
- .../DC-数据清洗整理/06-开发记录/2025-12-02_工作总结.md | 1 [32m+[m
- .../06-开发记录/2025-12-06_工具C_Day1开发完成总结.md | 1 [32m+[m
- .../06-开发记录/2025-12-06_工具C_Day2开发完成总结.md | 1 [32m+[m
- .../06-开发记录/2025-12-07_AI对话核心功能增强总结.md | 1 [32m+[m
- .../06-开发记录/2025-12-07_Bug修复_DataGrid空数据防御.md | 1 [32m+[m
- .../06-开发记录/2025-12-07_Day5_Ant-Design-X重构完成.md | 1 [32m+[m
- .../06-开发记录/2025-12-07_Day5最终总结.md | 1 [32m+[m
- .../06-开发记录/2025-12-07_UI优化与Bug修复.md | 1 [32m+[m
- .../06-开发记录/2025-12-07_后端API完整对接完成.md | 1 [32m+[m
- .../06-开发记录/2025-12-07_完整UI优化与功能增强.md | 1 [32m+[m
- .../06-开发记录/2025-12-07_工具C_Day4前端基础完成.md | 1 [32m+[m
- .../06-开发记录/DC模块重建完成总结-Day1.md | 1 [32m+[m
- .../06-开发记录/Phase1-Portal页面开发完成-2025-12-02.md | 1 [32m+[m
- .../06-开发记录/Phase2-ToolB-Step1-2开发完成-2025-12-03.md | 1 [32m+[m
- .../06-开发记录/Portal页面UI优化-2025-12-02.md | 1 [32m+[m
- .../06-开发记录/Tool-B-MVP完成总结-2025-12-03.md | 1 [32m+[m
- .../06-开发记录/ToolB-UI优化-2025-12-03.md | 1 [32m+[m
- .../06-开发记录/ToolB-UI优化-Round2-2025-12-03.md | 1 [32m+[m
- .../06-开发记录/ToolB浏览器测试计划-2025-12-03.md | 1 [32m+[m
- .../06-开发记录/后端API测试报告-2025-12-02.md | 1 [32m+[m
- .../DC-数据清洗整理/06-开发记录/待办事项-下一步工作.md | 1 [32m+[m
- .../06-开发记录/数据库验证报告-2025-12-02.md | 1 [32m+[m
- .../DC-数据清洗整理/07-技术债务/Tool-B技术债务清单.md | 1 [32m+[m
- docs/05-部署文档/00-部署进度总览.md | 27 [32m+[m[31m-[m
- docs/05-部署文档/02-SAE部署完全指南(产品经理版).md | 1 [32m+[m
- docs/05-部署文档/07-前端Nginx-SAE部署操作手册.md | 1 [32m+[m
- .../05-部署文档/08-PostgreSQL数据库部署操作手册.md | 1 [32m+[m
- .../05-部署文档/09-Python微服务-SAE部署操作手册.md | 844 [32m++++++++++++[m
- docs/05-部署文档/文档修正报告-20251214.md | 1 [32m+[m
- docs/07-运维文档/03-SAE环境变量配置指南.md | 1 [32m+[m
- docs/07-运维文档/05-Redis缓存与队列的区别说明.md | 1 [32m+[m
- docs/07-运维文档/06-长时间任务可靠性分析.md | 1 [32m+
\ No newline at end of file
diff --git a/tests/QUICKSTART_快速开始.md b/tests/QUICKSTART_快速开始.md
deleted file mode 100644
index 8f73a095..00000000
--- a/tests/QUICKSTART_快速开始.md
+++ /dev/null
@@ -1,165 +0,0 @@
-# 🚀 快速开始 - 1分钟运行测试
-
-## Windows用户
-
-### 方法1:双击运行(最简单)
-1. 双击 `run_tests.bat`
-2. 等待测试完成
-
-### 方法2:命令行
-```cmd
-cd AIclinicalresearch\tests
-run_tests.bat
-```
-
----
-
-## Linux/Mac用户
-
-```bash
-cd AIclinicalresearch/tests
-chmod +x run_tests.sh
-./run_tests.sh
-```
-
----
-
-## ⚠️ 前提条件
-
-**必须先启动Python服务!**
-
-```bash
-# 打开新终端
-cd AIclinicalresearch/extraction_service
-python main.py
-```
-
-看到这行表示启动成功:
-```
-INFO: Application startup complete.
-INFO: Uvicorn running on http://0.0.0.0:8001
-```
-
----
-
-## 📊 预期结果
-
-✅ **全部通过**:
-```
-总测试数: 18
-✅ 通过: 18
-❌ 失败: 0
-通过率: 100.0%
-
-🎉 所有测试通过!
-```
-
-⚠️ **部分失败**:
-- 查看红色错误信息
-- 检查失败的具体测试
-- 查看Python服务日志
-
----
-
-## 🎯 测试内容
-
-- ✅ 6种简单填补方法(均值、中位数、众数、固定值、前向填充、后向填充)
-- ✅ MICE多重插补(单列、多列)
-- ✅ 边界情况(100%缺失、0%缺失、特殊字符)
-- ✅ 各种数据类型(数值、分类、混合)
-- ✅ 性能测试(1000行数据)
-
----
-
-## 💡 提示
-
-- **第一次运行**会自动安装依赖(pandas, numpy, requests)
-- **测试时间**约 45-60 秒
-- **测试数据**自动生成,无需手动准备
-- **颜色输出**:绿色=通过,红色=失败,黄色=警告
-
----
-
-## 🆘 遇到问题?
-
-### 问题1:无法连接到服务
-**解决**:确保Python服务在运行(`python main.py`)
-
-### 问题2:依赖安装失败
-**解决**:手动安装 `pip install pandas numpy requests`
-
-### 问题3:测试失败
-**解决**:查看错误信息,检查代码逻辑
-
----
-
-**准备好了吗?启动服务,运行测试!** 🚀
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/tests/README_测试说明.md b/tests/README_测试说明.md
deleted file mode 100644
index 42632484..00000000
--- a/tests/README_测试说明.md
+++ /dev/null
@@ -1,321 +0,0 @@
-# 缺失值处理功能 - 自动化测试说明
-
-## 📋 测试脚本功能
-
-自动化测试脚本 `test_fillna_operations.py` 会自动测试缺失值处理的所有功能,包括:
-
-### ✅ 18个测试用例
-
-#### 基础测试(6个)
-1. 均值填补数值列
-2. 中位数填补偏态分布列
-3. 众数填补分类列
-4. 固定值填补(0)
-5. 前向填充(ffill)⭐
-6. 后向填充(bfill)⭐
-
-#### MICE测试(4个)
-7. MICE填补单列
-8. MICE填补多列
-9. MICE填补 - 不同迭代次数
-10. MICE填补 - 自定义随机种子
-
-#### 边界测试(4个)
-11. 100%缺失的列
-12. 0%缺失的列(无需填补)
-13. 统计API功能
-14. 特殊字符列名处理
-
-#### 数据类型测试(4个)
-15. 数值列(int/float)
-16. 分类列(字符串)
-17. 混合类型列
-18. 性能测试(1000行)
-
----
-
-## 🚀 快速开始
-
-### 步骤1: 启动Python服务
-
-```bash
-cd AIclinicalresearch/extraction_service
-python main.py
-```
-
-**确认服务启动成功**:看到 `Application startup complete` 或访问 `http://localhost:8001/health`
-
----
-
-### 步骤2: 运行测试脚本
-
-**方法1 - 在项目根目录运行**:
-```bash
-cd AIclinicalresearch
-python tests/test_fillna_operations.py
-```
-
-**方法2 - 在tests目录运行**:
-```bash
-cd AIclinicalresearch/tests
-python test_fillna_operations.py
-```
-
----
-
-## 📊 测试输出示例
-
-```
-╔══════════════════════════════════════════════════════════════════╗
-║ ║
-║ 缺失值处理功能 - 自动化测试脚本 v1.0 ║
-║ ║
-║ 测试内容: 18个测试用例 ║
-║ - 6个基础填补测试 ║
-║ - 4个MICE测试 ║
-║ - 4个边界测试 ║
-║ - 4个数据类型测试 ║
-║ ║
-╚══════════════════════════════════════════════════════════════════╝
-
-================================================================================
- 缺失值处理功能 - 自动化测试
-================================================================================
-
-ℹ️ 检查Python服务状态...
-✅ Python服务运行正常
-
-ℹ️ 生成测试数据...
-✅ 生成了 5 个测试数据集
- • numeric: 100 行 × 4 列
- • categorical: 100 行 × 3 列
- • timeseries: 100 行 × 3 列
- • edge_cases: 10 行 × 4 列
- • mixed: 100 行 × 4 列
-
-[1/18] 均值填补数值列
---------------------------------------------------------------------------------
-✅ 均值填补成功,缺失值已全部填补
-✅ ✓ 新列位置正确(紧邻原列)
-
-[2/18] 中位数填补偏态分布列
---------------------------------------------------------------------------------
-✅ 中位数填补成功
-
-...
-
-================================================================================
- 测试总结
-================================================================================
-
-总测试数: 18
-✅ 通过: 18
-❌ 失败: 0
-通过率: 100.0%
-总耗时: 45.32秒
-
- 🎉 所有测试通过!
-```
-
----
-
-## 🔧 依赖安装
-
-测试脚本需要以下Python包:
-
-```bash
-pip install pandas numpy requests
-```
-
-这些包在 `extraction_service/requirements.txt` 中已经包含。
-
----
-
-## ⚙️ 配置
-
-### 修改服务地址
-
-如果Python服务不在默认端口 `8001`,修改脚本开头:
-
-```python
-PYTHON_SERVICE_URL = "http://localhost:8001" # 修改为你的端口
-```
-
----
-
-## 📝 测试结果说明
-
-### 颜色含义
-- 🟢 **绿色** (✅): 测试通过
-- 🔴 **红色** (❌): 测试失败
-- 🟡 **黄色** (⚠️): 警告信息
-- 🔵 **蓝色** (ℹ️): 提示信息
-
-### 通过标准
-- ✅ API返回成功
-- ✅ 新列创建正确
-- ✅ 缺失值被正确填补
-- ✅ 新列位置在原列旁边
-
----
-
-## 🐛 常见问题
-
-### 1. 无法连接到Python服务
-**错误**: `无法连接到Python服务: Connection refused`
-
-**解决**:
-```bash
-# 确保Python服务已启动
-cd AIclinicalresearch/extraction_service
-python main.py
-```
-
----
-
-### 2. 模块未找到
-**错误**: `ModuleNotFoundError: No module named 'pandas'`
-
-**解决**:
-```bash
-pip install pandas numpy requests
-```
-
----
-
-### 3. 部分测试失败
-**现象**: 通过率 < 100%
-
-**处理**:
-1. 查看失败测试的具体错误信息
-2. 检查Python服务日志
-3. 确认数据格式是否正确
-
----
-
-## 🔍 调试技巧
-
-### 1. 单独运行某个测试
-
-修改 `test_fillna_operations.py` 的 `run_all_tests()` 方法,只保留需要测试的用例:
-
-```python
-tests = [
- (self.test_1_mean_fill, "基础"), # 只测试这一个
-]
-```
-
-### 2. 查看详细日志
-
-在测试函数中添加:
-
-```python
-print(json.dumps(result, indent=2, ensure_ascii=False))
-```
-
-### 3. 保存测试数据
-
-在 `generate_test_data()` 中添加:
-
-```python
-df_numeric.to_excel('test_data/numeric_test.xlsx', index=False)
-```
-
----
-
-## 📈 性能基准
-
-**参考值**(在普通笔记本上):
-
-- **简单填补**(均值/中位数/众数): < 1秒
-- **前向/后向填充**: < 1秒
-- **MICE填补 100行**: 2-5秒
-- **MICE填补 1000行**: 20-40秒
-- **全部18个测试**: 45-60秒
-
----
-
-## 🎯 下一步
-
-测试通过后:
-1. 在真实数据上测试
-2. 测试前端集成
-3. 性能优化(如有需要)
-
----
-
-## 📞 技术支持
-
-如有问题,请检查:
-1. Python服务日志
-2. 测试脚本输出
-3. 开发文档:`工具C_缺失值处理_开发完成说明.md`
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/tests/run_tests.bat b/tests/run_tests.bat
deleted file mode 100644
index a8bd6482..00000000
--- a/tests/run_tests.bat
+++ /dev/null
@@ -1,116 +0,0 @@
-@echo off
-REM Windows批处理脚本 - 运行缺失值处理功能测试
-
-echo ========================================
-echo 缺失值处理功能 - 自动化测试
-echo ========================================
-echo.
-
-REM 检查Python是否安装
-python --version >nul 2>&1
-if %errorlevel% neq 0 (
- echo [错误] Python未安装或不在PATH中
- pause
- exit /b 1
-)
-
-echo [1/3] 检查Python服务状态...
-curl -s http://localhost:8001/health >nul 2>&1
-if %errorlevel% neq 0 (
- echo [警告] Python服务未运行,请先启动服务:
- echo cd extraction_service
- echo python main.py
- echo.
- pause
- exit /b 1
-)
-echo [OK] Python服务运行正常
-echo.
-
-echo [2/3] 检查依赖...
-python -c "import pandas, numpy, requests" >nul 2>&1
-if %errorlevel% neq 0 (
- echo [警告] 缺少依赖,正在安装...
- pip install pandas numpy requests
-)
-echo [OK] 依赖检查完成
-echo.
-
-echo [3/3] 运行测试...
-echo.
-python test_fillna_operations.py
-
-echo.
-echo ========================================
-echo 测试完成
-echo ========================================
-pause
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/tests/run_tests.sh b/tests/run_tests.sh
deleted file mode 100644
index 1e563676..00000000
--- a/tests/run_tests.sh
+++ /dev/null
@@ -1,112 +0,0 @@
-#!/bin/bash
-
-# Linux/Mac脚本 - 运行缺失值处理功能测试
-
-echo "========================================"
-echo "缺失值处理功能 - 自动化测试"
-echo "========================================"
-echo
-
-# 检查Python是否安装
-if ! command -v python3 &> /dev/null; then
- echo "[错误] Python未安装"
- exit 1
-fi
-
-echo "[1/3] 检查Python服务状态..."
-if ! curl -s http://localhost:8001/health > /dev/null 2>&1; then
- echo "[警告] Python服务未运行,请先启动服务:"
- echo " cd extraction_service"
- echo " python main.py"
- echo
- exit 1
-fi
-echo "[OK] Python服务运行正常"
-echo
-
-echo "[2/3] 检查依赖..."
-python3 -c "import pandas, numpy, requests" 2> /dev/null
-if [ $? -ne 0 ]; then
- echo "[警告] 缺少依赖,正在安装..."
- pip3 install pandas numpy requests
-fi
-echo "[OK] 依赖检查完成"
-echo
-
-echo "[3/3] 运行测试..."
-echo
-python3 test_fillna_operations.py
-
-echo
-echo "========================================"
-echo "测试完成"
-echo "========================================"
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/tests/test_fillna_operations.py b/tests/test_fillna_operations.py
deleted file mode 100644
index ec89937c..00000000
--- a/tests/test_fillna_operations.py
+++ /dev/null
@@ -1,773 +0,0 @@
-"""
-缺失值处理功能 - 自动化测试脚本
-
-测试所有18个测试用例:
-- 6个基础填补测试
-- 4个MICE测试
-- 4个边界测试
-- 4个数据类型测试
-
-使用方法:
- python tests/test_fillna_operations.py
-"""
-
-import pandas as pd
-import numpy as np
-import requests
-import time
-import json
-from typing import Dict, List, Any
-from datetime import datetime
-import sys
-import os
-
-# 配置
-PYTHON_SERVICE_URL = "http://localhost:8000"
-TEST_DATA_DIR = "tests/test_data"
-
-# 颜色输出
-class Colors:
- GREEN = '\033[92m'
- RED = '\033[91m'
- YELLOW = '\033[93m'
- BLUE = '\033[94m'
- CYAN = '\033[96m'
- BOLD = '\033[1m'
- END = '\033[0m'
-
-def print_header(text: str):
- print(f"\n{Colors.BOLD}{Colors.CYAN}{'='*80}{Colors.END}")
- print(f"{Colors.BOLD}{Colors.CYAN}{text.center(80)}{Colors.END}")
- print(f"{Colors.BOLD}{Colors.CYAN}{'='*80}{Colors.END}\n")
-
-def print_test(test_num: int, total: int, name: str):
- print(f"\n{Colors.BOLD}[{test_num}/{total}] {name}{Colors.END}")
- print("-" * 80)
-
-def print_success(message: str):
- print(f"{Colors.GREEN}✅ {message}{Colors.END}")
-
-def print_error(message: str):
- print(f"{Colors.RED}❌ {message}{Colors.END}")
-
-def print_warning(message: str):
- print(f"{Colors.YELLOW}⚠️ {message}{Colors.END}")
-
-def print_info(message: str):
- print(f"{Colors.BLUE}ℹ️ {message}{Colors.END}")
-
-
-class FillnaTestSuite:
- def __init__(self):
- self.passed = 0
- self.failed = 0
- self.errors = []
- self.start_time = None
-
- # 确保测试数据目录存在
- os.makedirs(TEST_DATA_DIR, exist_ok=True)
-
- def generate_test_data(self) -> Dict[str, pd.DataFrame]:
- """生成各种测试数据集"""
- print_info("生成测试数据...")
-
- np.random.seed(42)
- n_rows = 100
-
- # 数据集1:数值列(正态分布)
- df_numeric = pd.DataFrame({
- 'id': range(1, n_rows + 1),
- '体重': np.random.normal(65, 10, n_rows),
- '身高': np.random.normal(170, 8, n_rows),
- '年龄': np.random.randint(20, 60, n_rows)
- })
- # 随机插入15%缺失值
- mask = np.random.random(n_rows) < 0.15
- df_numeric.loc[mask, '体重'] = np.nan
- mask = np.random.random(n_rows) < 0.15
- df_numeric.loc[mask, '身高'] = np.nan
-
- # 数据集2:分类列
- df_categorical = pd.DataFrame({
- 'id': range(1, n_rows + 1),
- '婚姻状况': np.random.choice(['已婚', '未婚', '离异'], n_rows),
- '教育程度': np.random.choice(['本科', '硕士', '博士', '高中'], n_rows),
- })
- mask = np.random.random(n_rows) < 0.20
- df_categorical.loc[mask, '婚姻状况'] = np.nan
-
- # 数据集3:时间序列(前向/后向填充)
- dates = pd.date_range('2024-01-01', periods=n_rows, freq='D')
- df_timeseries = pd.DataFrame({
- 'date': dates,
- 'temperature': np.random.normal(20, 5, n_rows),
- 'humidity': np.random.uniform(40, 80, n_rows)
- })
- # 连续缺失
- df_timeseries.loc[10:15, 'temperature'] = np.nan
- df_timeseries.loc[30:32, 'humidity'] = np.nan
-
- # 数据集4:边界情况
- df_edge_cases = pd.DataFrame({
- 'id': range(1, 11),
- 'all_missing': [np.nan] * 10, # 100%缺失
- 'no_missing': range(1, 11), # 0%缺失
- 'half_missing': [1, np.nan, 3, np.nan, 5, np.nan, 7, np.nan, 9, np.nan],
- })
-
- # 数据集5:混合类型
- df_mixed = pd.DataFrame({
- 'id': range(1, n_rows + 1),
- '数值列': np.random.normal(100, 20, n_rows),
- '分类列': np.random.choice(['A', 'B', 'C'], n_rows),
- '整数列': np.random.randint(1, 100, n_rows),
- })
- mask = np.random.random(n_rows) < 0.10
- df_mixed.loc[mask, '数值列'] = np.nan
- df_mixed.loc[mask, '分类列'] = np.nan
-
- datasets = {
- 'numeric': df_numeric,
- 'categorical': df_categorical,
- 'timeseries': df_timeseries,
- 'edge_cases': df_edge_cases,
- 'mixed': df_mixed
- }
-
- print_success(f"生成了 {len(datasets)} 个测试数据集")
- for name, df in datasets.items():
- print(f" • {name}: {df.shape[0]} 行 × {df.shape[1]} 列")
-
- return datasets
-
- def test_service_health(self) -> bool:
- """测试Python服务是否正常运行"""
- print_info("检查Python服务状态...")
- try:
- response = requests.get(f"{PYTHON_SERVICE_URL}/health", timeout=5)
- if response.status_code == 200:
- print_success("Python服务运行正常")
- return True
- else:
- print_error(f"Python服务响应异常: {response.status_code}")
- return False
- except Exception as e:
- print_error(f"无法连接到Python服务: {str(e)}")
- print_warning(f"请确保服务已启动: cd extraction_service && python main.py")
- return False
-
- def call_fillna_simple(self, data: List[Dict], column: str, new_column_name: str,
- method: str, fill_value: Any = None) -> Dict:
- """调用简单填补API"""
- payload = {
- "data": data,
- "column": column,
- "new_column_name": new_column_name,
- "method": method,
- "fill_value": fill_value
- }
-
- response = requests.post(
- f"{PYTHON_SERVICE_URL}/api/operations/fillna-simple",
- json=payload,
- timeout=30
- )
- return response.json()
-
- def call_fillna_stats(self, data: List[Dict], column: str) -> Dict:
- """调用统计API"""
- payload = {
- "data": data,
- "column": column
- }
-
- response = requests.post(
- f"{PYTHON_SERVICE_URL}/api/operations/fillna-stats",
- json=payload,
- timeout=10
- )
- return response.json()
-
- def call_fillna_mice(self, data: List[Dict], columns: List[str],
- n_iterations: int = 10, random_state: int = 42) -> Dict:
- """调用MICE填补API"""
- payload = {
- "data": data,
- "columns": columns,
- "n_iterations": n_iterations,
- "random_state": random_state
- }
-
- response = requests.post(
- f"{PYTHON_SERVICE_URL}/api/operations/fillna-mice",
- json=payload,
- timeout=120
- )
- return response.json()
-
- def verify_result(self, result: Dict, expected_keys: List[str]) -> bool:
- """验证结果是否包含必要的字段"""
- if not result.get('success'):
- print_error(f"API返回失败: {result.get('error', 'Unknown error')}")
- return False
-
- for key in expected_keys:
- if key not in result:
- print_error(f"结果缺少字段: {key}")
- return False
-
- return True
-
- def verify_new_column_created(self, result_data: List[Dict], new_column: str,
- original_column: str) -> bool:
- """验证新列是否创建"""
- if not result_data:
- print_error("结果数据为空")
- return False
-
- first_row = result_data[0]
-
- if new_column not in first_row:
- print_error(f"新列 '{new_column}' 未创建")
- return False
-
- if original_column not in first_row:
- print_error(f"原列 '{original_column}' 丢失")
- return False
-
- return True
-
- def verify_column_position(self, result_data: List[Dict], new_column: str,
- original_column: str) -> bool:
- """验证新列是否在原列旁边"""
- if not result_data:
- return False
-
- columns = list(result_data[0].keys())
-
- try:
- orig_idx = columns.index(original_column)
- new_idx = columns.index(new_column)
-
- if new_idx == orig_idx + 1:
- print_success(f"✓ 新列位置正确(紧邻原列)")
- return True
- else:
- print_warning(f"新列位置: {new_idx}, 原列位置: {orig_idx}")
- return False
- except ValueError as e:
- print_error(f"列位置检查失败: {str(e)}")
- return False
-
- def count_missing_values(self, data: List[Dict], column: str) -> int:
- """统计缺失值数量"""
- count = 0
- for row in data:
- val = row.get(column)
- if val is None or (isinstance(val, float) and np.isnan(val)):
- count += 1
- return count
-
- # ==================== 基础测试(6个)====================
-
- def test_1_mean_fill(self, datasets: Dict) -> bool:
- """测试1: 均值填补数值列"""
- print_test(1, 18, "均值填补数值列")
-
- df = datasets['numeric']
- data = df.to_dict('records')
-
- # 调用API
- result = self.call_fillna_simple(data, '体重', '体重_均值', 'mean')
-
- # 验证
- if not self.verify_result(result, ['result_data', 'message']):
- return False
-
- result_data = result['result_data']
-
- if not self.verify_new_column_created(result_data, '体重_均值', '体重'):
- return False
-
- # 检查缺失值是否被填补
- missing_count = self.count_missing_values(result_data, '体重_均值')
- if missing_count > 0:
- print_error(f"填补后仍有 {missing_count} 个缺失值")
- return False
-
- print_success("均值填补成功,缺失值已全部填补")
- self.verify_column_position(result_data, '体重_均值', '体重')
-
- return True
-
- def test_2_median_fill(self, datasets: Dict) -> bool:
- """测试2: 中位数填补偏态分布列"""
- print_test(2, 18, "中位数填补偏态分布列")
-
- df = datasets['numeric']
- data = df.to_dict('records')
-
- result = self.call_fillna_simple(data, '身高', '身高_中位数', 'median')
-
- if not self.verify_result(result, ['result_data', 'message']):
- return False
-
- result_data = result['result_data']
- missing_count = self.count_missing_values(result_data, '身高_中位数')
-
- if missing_count == 0:
- print_success("中位数填补成功")
- return True
- else:
- print_error(f"填补后仍有 {missing_count} 个缺失值")
- return False
-
- def test_3_mode_fill(self, datasets: Dict) -> bool:
- """测试3: 众数填补分类列"""
- print_test(3, 18, "众数填补分类列")
-
- df = datasets['categorical']
- data = df.to_dict('records')
-
- result = self.call_fillna_simple(data, '婚姻状况', '婚姻状况_众数', 'mode')
-
- if not self.verify_result(result, ['result_data', 'message']):
- return False
-
- result_data = result['result_data']
- missing_count = self.count_missing_values(result_data, '婚姻状况_众数')
-
- if missing_count == 0:
- print_success("众数填补成功")
- return True
- else:
- print_error(f"填补后仍有 {missing_count} 个缺失值")
- return False
-
- def test_4_constant_fill(self, datasets: Dict) -> bool:
- """测试4: 固定值填补(0)"""
- print_test(4, 18, "固定值填补(0)")
-
- df = datasets['numeric']
- data = df.to_dict('records')
-
- result = self.call_fillna_simple(data, '体重', '体重_固定值', 'constant', fill_value=0)
-
- if not self.verify_result(result, ['result_data', 'message']):
- return False
-
- result_data = result['result_data']
- missing_count = self.count_missing_values(result_data, '体重_固定值')
-
- # 检查是否有值被填充为0
- filled_zeros = sum(1 for row in result_data if row.get('体重_固定值') == 0)
-
- if missing_count == 0 and filled_zeros > 0:
- print_success(f"固定值填补成功,填充了 {filled_zeros} 个0")
- return True
- else:
- print_error("固定值填补失败")
- return False
-
- def test_5_ffill(self, datasets: Dict) -> bool:
- """测试5: 前向填充(ffill)⭐"""
- print_test(5, 18, "前向填充(ffill)⭐")
-
- df = datasets['timeseries']
- data = df.to_dict('records')
-
- result = self.call_fillna_simple(data, 'temperature', 'temperature_ffill', 'ffill')
-
- if not self.verify_result(result, ['result_data', 'message']):
- return False
-
- result_data = result['result_data']
- missing_count = self.count_missing_values(result_data, 'temperature_ffill')
-
- if missing_count == 0:
- print_success("前向填充成功 ⭐")
- return True
- else:
- print_error(f"填充后仍有 {missing_count} 个缺失值")
- return False
-
- def test_6_bfill(self, datasets: Dict) -> bool:
- """测试6: 后向填充(bfill)⭐"""
- print_test(6, 18, "后向填充(bfill)⭐")
-
- df = datasets['timeseries']
- data = df.to_dict('records')
-
- result = self.call_fillna_simple(data, 'humidity', 'humidity_bfill', 'bfill')
-
- if not self.verify_result(result, ['result_data', 'message']):
- return False
-
- result_data = result['result_data']
- missing_count = self.count_missing_values(result_data, 'humidity_bfill')
-
- if missing_count == 0:
- print_success("后向填充成功 ⭐")
- return True
- else:
- print_error(f"填充后仍有 {missing_count} 个缺失值")
- return False
-
- # ==================== MICE测试(4个)====================
-
- def test_7_mice_single_column(self, datasets: Dict) -> bool:
- """测试7: MICE填补单列"""
- print_test(7, 18, "MICE填补单列")
-
- df = datasets['numeric']
- data = df.to_dict('records')
-
- result = self.call_fillna_mice(data, ['体重'], n_iterations=5)
-
- if not self.verify_result(result, ['result_data', 'message']):
- return False
-
- result_data = result['result_data']
- missing_count = self.count_missing_values(result_data, '体重_MICE')
-
- if missing_count == 0:
- print_success("MICE单列填补成功 ⭐⭐⭐")
- return True
- else:
- print_error(f"填补后仍有 {missing_count} 个缺失值")
- return False
-
- def test_8_mice_multiple_columns(self, datasets: Dict) -> bool:
- """测试8: MICE填补多列"""
- print_test(8, 18, "MICE填补多列")
-
- df = datasets['numeric']
- data = df.to_dict('records')
-
- result = self.call_fillna_mice(data, ['体重', '身高'], n_iterations=5)
-
- if not self.verify_result(result, ['result_data', 'message']):
- return False
-
- result_data = result['result_data']
-
- # 检查两个新列是否都创建
- if '体重_MICE' not in result_data[0] or '身高_MICE' not in result_data[0]:
- print_error("MICE新列未全部创建")
- return False
-
- missing_count_1 = self.count_missing_values(result_data, '体重_MICE')
- missing_count_2 = self.count_missing_values(result_data, '身高_MICE')
-
- if missing_count_1 == 0 and missing_count_2 == 0:
- print_success("MICE多列填补成功 ⭐⭐⭐")
- return True
- else:
- print_error(f"填补不完整: 体重 {missing_count_1}, 身高 {missing_count_2}")
- return False
-
- def test_9_mice_iterations(self, datasets: Dict) -> bool:
- """测试9: MICE填补 - 不同迭代次数"""
- print_test(9, 18, "MICE填补 - 不同迭代次数")
-
- df = datasets['numeric']
- data = df.to_dict('records')
-
- # 测试5次迭代和20次迭代
- result_5 = self.call_fillna_mice(data, ['体重'], n_iterations=5)
- result_20 = self.call_fillna_mice(data, ['体重'], n_iterations=20)
-
- if not result_5.get('success') or not result_20.get('success'):
- print_error("不同迭代次数测试失败")
- return False
-
- print_success("不同迭代次数都能成功执行")
- return True
-
- def test_10_mice_random_state(self, datasets: Dict) -> bool:
- """测试10: MICE填补 - 自定义随机种子"""
- print_test(10, 18, "MICE填补 - 自定义随机种子")
-
- df = datasets['numeric']
- data = df.to_dict('records')
-
- # 相同随机种子应产生相同结果
- result_1 = self.call_fillna_mice(data, ['体重'], random_state=42)
- result_2 = self.call_fillna_mice(data, ['体重'], random_state=42)
-
- if not result_1.get('success') or not result_2.get('success'):
- print_error("随机种子测试失败")
- return False
-
- print_success("随机种子功能正常")
- return True
-
- # ==================== 边界测试(4个)====================
-
- def test_11_all_missing(self, datasets: Dict) -> bool:
- """测试11: 100%缺失的列"""
- print_test(11, 18, "100%缺失的列")
-
- df = datasets['edge_cases']
- data = df.to_dict('records')
-
- result = self.call_fillna_simple(data, 'all_missing', 'all_missing_filled', 'mean')
-
- # 这个应该失败或给出警告
- if result.get('success'):
- print_warning("100%缺失的列填补成功(可能填充了NaN)")
- return True
- else:
- print_success("正确处理了100%缺失的情况")
- return True
-
- def test_12_no_missing(self, datasets: Dict) -> bool:
- """测试12: 0%缺失的列(无需填补)"""
- print_test(12, 18, "0%缺失的列(无需填补)")
-
- df = datasets['edge_cases']
- data = df.to_dict('records')
-
- result = self.call_fillna_simple(data, 'no_missing', 'no_missing_filled', 'mean')
-
- if result.get('success'):
- print_success("0%缺失的列处理正常")
- return True
- else:
- print_error("处理无缺失列失败")
- return False
-
- def test_13_stats_api(self, datasets: Dict) -> bool:
- """测试13: 统计API功能"""
- print_test(13, 18, "统计API功能")
-
- df = datasets['numeric']
- data = df.to_dict('records')
-
- result = self.call_fillna_stats(data, '体重')
-
- if not result.get('success'):
- print_error("统计API失败")
- return False
-
- stats = result.get('stats', {})
- required_fields = ['missing_count', 'missing_rate', 'valid_count', 'total_count']
-
- for field in required_fields:
- if field not in stats:
- print_error(f"统计信息缺少字段: {field}")
- return False
-
- print_success(f"统计API正常 - 缺失率: {stats['missing_rate']}%")
- print_info(f" 缺失: {stats['missing_count']}, 有效: {stats['valid_count']}")
- return True
-
- def test_14_column_name_with_special_chars(self, datasets: Dict) -> bool:
- """测试14: 特殊字符列名处理"""
- print_test(14, 18, "特殊字符列名处理")
-
- # 创建包含特殊字符的列名
- df = pd.DataFrame({
- 'id': range(1, 11),
- '体重(kg)': [60, np.nan, 70, 65, np.nan, 75, 80, np.nan, 68, 72]
- })
- data = df.to_dict('records')
-
- result = self.call_fillna_simple(data, '体重(kg)', '体重(kg)_填补', 'median')
-
- if result.get('success'):
- print_success("特殊字符列名处理正常")
- return True
- else:
- print_warning(f"特殊字符列名处理失败: {result.get('error')}")
- return False
-
- # ==================== 数据类型测试(4个)====================
-
- def test_15_numeric_types(self, datasets: Dict) -> bool:
- """测试15: 数值列(int/float)"""
- print_test(15, 18, "数值列(int/float)")
-
- df = datasets['numeric']
- data = df.to_dict('records')
-
- # 测试整数列
- result = self.call_fillna_simple(data, '年龄', '年龄_填补', 'median')
-
- if result.get('success'):
- print_success("数值类型处理正常")
- return True
- else:
- print_error("数值类型处理失败")
- return False
-
- def test_16_categorical_types(self, datasets: Dict) -> bool:
- """测试16: 分类列(字符串)"""
- print_test(16, 18, "分类列(字符串)")
-
- df = datasets['categorical']
- data = df.to_dict('records')
-
- result = self.call_fillna_simple(data, '教育程度', '教育程度_填补', 'mode')
-
- if result.get('success'):
- print_success("分类类型处理正常")
- return True
- else:
- print_error("分类类型处理失败")
- return False
-
- def test_17_mixed_types(self, datasets: Dict) -> bool:
- """测试17: 混合类型列"""
- print_test(17, 18, "混合类型列")
-
- df = datasets['mixed']
- data = df.to_dict('records')
-
- # MICE填补多种类型
- result = self.call_fillna_mice(data, ['数值列', '整数列'], n_iterations=5)
-
- if result.get('success'):
- print_success("混合类型处理正常")
- return True
- else:
- print_warning(f"混合类型处理: {result.get('error')}")
- return False
-
- def test_18_performance(self, datasets: Dict) -> bool:
- """测试18: 性能测试(大数据集)"""
- print_test(18, 18, "性能测试(1000行)")
-
- # 生成1000行数据
- n_rows = 1000
- df_large = pd.DataFrame({
- 'id': range(1, n_rows + 1),
- 'value1': np.random.normal(100, 20, n_rows),
- 'value2': np.random.normal(50, 10, n_rows),
- })
- mask = np.random.random(n_rows) < 0.10
- df_large.loc[mask, 'value1'] = np.nan
- df_large.loc[mask, 'value2'] = np.nan
-
- data = df_large.to_dict('records')
-
- start_time = time.time()
- result = self.call_fillna_mice(data, ['value1', 'value2'], n_iterations=5)
- elapsed = time.time() - start_time
-
- if result.get('success'):
- print_success(f"性能测试通过 - 耗时: {elapsed:.2f}秒")
- if elapsed < 30:
- print_success("性能优秀(<30秒)")
- elif elapsed < 60:
- print_info("性能良好(30-60秒)")
- else:
- print_warning(f"性能较慢({elapsed:.2f}秒)")
- return True
- else:
- print_error("性能测试失败")
- return False
-
- # ==================== 主测试流程 ====================
-
- def run_all_tests(self):
- """运行所有测试"""
- print_header("缺失值处理功能 - 自动化测试")
-
- self.start_time = time.time()
-
- # 1. 检查服务状态
- if not self.test_service_health():
- print_error("Python服务未运行,无法继续测试")
- return
-
- # 2. 生成测试数据
- datasets = self.generate_test_data()
-
- # 3. 运行所有测试
- tests = [
- # 基础测试
- (self.test_1_mean_fill, "基础"),
- (self.test_2_median_fill, "基础"),
- (self.test_3_mode_fill, "基础"),
- (self.test_4_constant_fill, "基础"),
- (self.test_5_ffill, "基础"),
- (self.test_6_bfill, "基础"),
- # MICE测试
- (self.test_7_mice_single_column, "MICE"),
- (self.test_8_mice_multiple_columns, "MICE"),
- (self.test_9_mice_iterations, "MICE"),
- (self.test_10_mice_random_state, "MICE"),
- # 边界测试
- (self.test_11_all_missing, "边界"),
- (self.test_12_no_missing, "边界"),
- (self.test_13_stats_api, "边界"),
- (self.test_14_column_name_with_special_chars, "边界"),
- # 数据类型测试
- (self.test_15_numeric_types, "类型"),
- (self.test_16_categorical_types, "类型"),
- (self.test_17_mixed_types, "类型"),
- (self.test_18_performance, "性能"),
- ]
-
- for test_func, category in tests:
- try:
- if test_func(datasets):
- self.passed += 1
- else:
- self.failed += 1
- self.errors.append(f"{test_func.__name__}")
- except Exception as e:
- self.failed += 1
- self.errors.append(f"{test_func.__name__}: {str(e)}")
- print_error(f"测试异常: {str(e)}")
-
- # 4. 输出总结
- self.print_summary()
-
- def print_summary(self):
- """输出测试总结"""
- elapsed = time.time() - self.start_time
-
- print_header("测试总结")
-
- total = self.passed + self.failed
- pass_rate = (self.passed / total * 100) if total > 0 else 0
-
- print(f"{Colors.BOLD}总测试数: {total}{Colors.END}")
- print(f"{Colors.GREEN}✅ 通过: {self.passed}{Colors.END}")
- print(f"{Colors.RED}❌ 失败: {self.failed}{Colors.END}")
- print(f"{Colors.CYAN}通过率: {pass_rate:.1f}%{Colors.END}")
- print(f"{Colors.BLUE}总耗时: {elapsed:.2f}秒{Colors.END}")
-
- if self.errors:
- print(f"\n{Colors.RED}{Colors.BOLD}失败的测试:{Colors.END}")
- for error in self.errors:
- print(f" • {error}")
-
- if self.failed == 0:
- print(f"\n{Colors.GREEN}{Colors.BOLD}{'🎉 所有测试通过!'.center(80)}{Colors.END}")
- else:
- print(f"\n{Colors.YELLOW}{Colors.BOLD}{'⚠️ 部分测试失败,请检查错误信息'.center(80)}{Colors.END}")
-
-
-if __name__ == "__main__":
- print(f"{Colors.BOLD}{Colors.CYAN}")
- print("""
- ╔══════════════════════════════════════════════════════════════════╗
- ║ ║
- ║ 缺失值处理功能 - 自动化测试脚本 v1.0 ║
- ║ ║
- ║ 测试内容: 18个测试用例 ║
- ║ - 6个基础填补测试 ║
- ║ - 4个MICE测试 ║
- ║ - 4个边界测试 ║
- ║ - 4个数据类型测试 ║
- ║ ║
- ╚══════════════════════════════════════════════════════════════════╝
- """)
- print(Colors.END)
-
- suite = FillnaTestSuite()
- suite.run_all_tests()
-
diff --git a/yonghuduan_v6.html b/yonghuduan_v6.html
deleted file mode 100644
index b69c00db..00000000
--- a/yonghuduan_v6.html
+++ /dev/null
@@ -1,536 +0,0 @@
-
-
-
-
-
- AI科研助手产品原型 V6
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
编辑项目信息
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/【给新AI】快速开始.md b/【给新AI】快速开始.md
deleted file mode 100644
index a7c646f7..00000000
--- a/【给新AI】快速开始.md
+++ /dev/null
@@ -1,229 +0,0 @@
-# 【给新AI】ASL模块 - 5分钟快速上手
-
-**当前时间**: 2025-11-18
-**当前任务**: Week 2 前端UI开发
-**阅读时间**: 3分钟
-
----
-
-## 这是什么项目?
-
-**AIclinicalresearch** = 医学文献AI筛选平台
-
-**当前开发**: ASL模块(AI Smart Literature)- 帮助医生用AI筛选医学文献
-
----
-
-## 当前进度
-
-```
-✅ Week 1: 后端完成(数据库+API+LLM筛选)
-🔄 Week 2: 前端开发 ← 你现在在这里
-⬜ Week 3: 批量筛选
-⬜ Week 4: 测试上线
-```
-
----
-
-## Week 2 要做什么?
-
-### 3个页面开发
-
-**Day 1-2**: 项目管理
-- 项目列表页
-- 创建项目表单(含PICOS + 筛选风格选择)
-
-**Day 3-4**: 文献导入
-- Excel上传界面
-- 文献预览表格
-
-**Day 5**: 筛选结果展示 ⭐ **重点**
-- 结果列表
-- **显示两个模型的判断理由**(最重要!)
-
----
-
-## 核心功能:双模型筛选
-
-```
-用户上传文献
- ↓
-DeepSeek-V3 ────┐
- ├─→ 对比 → 最终决策
-Qwen-Max ───────┘
-
-一致 → 采纳
-冲突 → 人工复核
-```
-
-**关键**: 前端必须显示**两个模型的完整理由**
-
----
-
-## 技术栈
-
-```
-前端: React 18 + Ant Design 5 + TypeScript
-后端: Fastify + Prisma + PostgreSQL
-LLM: DeepSeek-V3 + Qwen-Max(已集成✅)
-```
-
----
-
-## 快速启动
-
-```bash
-# 1. 启动后端
-cd backend && npm run dev
-# → http://localhost:3001
-
-# 2. 启动前端
-cd frontend-v2 && npm run dev
-# → http://localhost:5173
-
-# 3. 测试API
-curl http://localhost:3001/api/v1/asl/health
-```
-
----
-
-## 关键文档(只需看这3个)
-
-1. **任务清单**: `docs/03-业务模块/ASL-AI智能文献/04-开发计划/03-任务分解.md`
- - Week 2详细任务
-
-2. **UI原型**: `docs/03-业务模块/ASL-AI智能文献/03-UI设计/AI智能文献-标题摘要初筛原型.html`
- - 界面参考
-
-3. **API文档**: `docs/03-业务模块/ASL-AI智能文献/02-技术设计/02-API设计规范.md`
- - 接口调用
-
----
-
-## API示例
-
-### 创建项目
-```typescript
-POST /api/v1/asl/projects
-{
- "projectName": "卒中预防研究",
- "picoCriteria": {
- "population": "非心源性缺血性卒中患者",
- "intervention": "抗血小板药物",
- "comparison": "安慰剂",
- "outcome": "卒中复发",
- "studyDesign": "RCT"
- },
- "inclusionCriteria": "...",
- "exclusionCriteria": "...",
- "screeningConfig": {
- "style": "lenient", // ← 筛选风格:lenient/standard/strict
- "models": ["deepseek-chat", "qwen-max"]
- }
-}
-```
-
-### 获取筛选结果
-```typescript
-GET /api/v1/asl/projects/:id/results
-
-Response:
-{
- "literatureId": "uuid",
- "title": "...",
- "finalDecision": "pending",
-
- // ⭐ 两个模型的完整结果
- "model1Result": {
- "modelName": "DeepSeek-V3",
- "conclusion": "exclude",
- "confidence": 0.92,
- "reason": "虽然P、I、S维度匹配,但对照组..." // ← 必须显示
- },
- "model2Result": {
- "modelName": "Qwen-Max",
- "conclusion": "include",
- "confidence": 0.85,
- "reason": "研究人群和干预措施匹配..." // ← 必须显示
- },
-
- "hasConflict": true
-}
-```
-
----
-
-## Week 2 关键任务 ⭐
-
-### 1. 筛选风格选择器
-```jsx
-
- 宽松模式(初筛)
- 标准模式
- 严格模式
-
-```
-
-### 2. 模型理由展示(最重要!)
-```jsx
-
-
-
- {model1.conclusion}
- 理由: {model1.reason}
-
-
-
-
- {model2.conclusion}
- 理由: {model2.reason}
-
-
-
-```
-
----
-
-## 重要提醒
-
-1. ✅ **后端已完成** - 10个API都可以直接调用
-2. ✅ **三种Prompt已实现** - 后端支持style参数
-3. ⭐ **理由展示是核心** - 用户强调必须看到AI思考过程
-4. ⚠️ **JWT暂时绕过** - 使用测试用户(生产需修复)
-
----
-
-## 成功标准
-
-- [ ] 3个页面开发完成
-- [ ] 用户可以选择筛选风格
-- [ ] **两个模型的理由清晰展示**
-- [ ] 冲突文献有明显标记
-- [ ] UI符合Ant Design规范
-
----
-
-## 需要帮助?
-
-**详细交接文档**: `docs/03-业务模块/ASL-AI智能文献/00-新AI交接文档.md`
-
-**系统总览**: `docs/00-系统总体设计/00-系统当前状态与开发指南.md`
-
----
-
-**祝开发顺利!** 🚀
-
----
-
-**文档版本**: v1.0 - 极简版
-**用途**: 新AI 3分钟快速上手
-**详细版本**: 见`00-新AI交接文档.md`
-
-
-
-
-
-
-
-
-
diff --git a/一键启动.bat b/一键启动.bat
deleted file mode 100644
index 78ce59a3..00000000
--- a/一键启动.bat
+++ /dev/null
@@ -1,63 +0,0 @@
-@echo off
-echo ========================================
-echo AI Clinical Research Platform
-echo One-click Startup Script
-echo ========================================
-echo.
-
-echo [1/7] Checking Docker status...
-docker ps >nul 2>&1
-if errorlevel 1 (
- echo ERROR: Docker is not running. Please start Docker Desktop first.
- pause
- exit /b 1
-)
-echo OK: Docker is running
-
-echo [2/7] Starting PostgreSQL and Redis containers...
-cd /d "%~dp0"
-docker-compose up -d
-if errorlevel 1 (
- echo ERROR: Failed to start Docker containers
- pause
- exit /b 1
-)
-echo OK: Database containers started
-
-echo [3/7] Waiting for database to be ready...
-timeout /t 5 /nobreak >nul
-echo OK: Database is ready
-
-echo [4/7] Starting Python extraction service (new window)...
-start "Document Extraction Service" cmd /k "cd /d %~dp0extraction_service && venv\Scripts\python.exe -m uvicorn main:app --host 0.0.0.0 --port 8000"
-echo OK: Python service starting...
-
-echo [5/7] Waiting for extraction service...
-timeout /t 3 /nobreak >nul
-
-echo [6/7] Starting backend server (new window)...
-start "AI Clinical Research - Backend" cmd /k "cd /d %~dp0backend && npm run dev"
-echo OK: Backend starting...
-
-echo [7/7] Waiting for backend, then starting frontend...
-timeout /t 3 /nobreak >nul
-
-start "AI Clinical Research - Frontend" cmd /k "cd /d %~dp0frontend && npm run dev"
-echo OK: Frontend starting...
-
-echo.
-echo ========================================
-echo Startup Complete!
-echo ========================================
-echo.
-echo Python Service: http://localhost:8000 (Docs: /docs)
-echo Backend: http://localhost:3001
-echo Frontend: http://localhost:5173
-echo.
-echo Please wait 10 seconds before accessing the frontend...
-echo.
-timeout /t 10 /nobreak
-start http://localhost:5173
-echo.
-echo Press any key to close this window...
-pause >nul
diff --git a/优化方案总结.md b/优化方案总结.md
deleted file mode 100644
index 4f466bc7..00000000
--- a/优化方案总结.md
+++ /dev/null
@@ -1,416 +0,0 @@
-# AI科研助手 - 优化方案总结
-
-## 📋 需求澄清与方案调整
-
-### 🔄 重要需求变更:知识库规模
-
-**原PRD描述:**
-> "后期考虑,增加基于大规模(1000篇以内)文献的读取、识别、内容提取的工作"
-
-**实际需求(已明确):**
-- ✅ 每个用户最多创建 **3个知识库**
-- ✅ 每个知识库最多上传 **50个文件**
-- ✅ 主要格式:**PDF、DOCX**
-- ✅ 单用户最大文档量:**150个文件**
-
-**影响:**
-- 🎉 技术难度从 ⭐⭐⭐⭐⭐ 降至 ⭐⭐⭐
-- 🎉 **Dify完全满足需求**,无需自建RAG系统
-- 🎉 开发成本进一步降低
-- 🎉 性能优化需求降低
-
----
-
-## 📋 您提出的问题与解决方案
-
-### 问题1:聊天功能如何实现?
-
-**您的担忧:** 不用LobeChat整体,如何保证聊天功能稳定?
-
-**我的方案:** ✅ **参考LobeChat开源实现,复用核心聊天组件**
-
-```
-策略:
-├── ❌ 不采用:LobeChat整体(缺少项目管理、知识库功能)
-├── ❌ 不采用:Dify + LobeChat组合(集成复杂,定制成本高)
-├── ✅ 采用:提取LobeChat的聊天UI组件到我们的React项目
-└── ✅ 采用:参考其流式输出、Markdown渲染的实现逻辑
-```
-
-**具体实施:**
-1. 克隆LobeChat源码(MIT开源许可,可自由使用)
-2. 提取核心组件:ChatMessage、ChatInput、StreamRenderer、MarkdownContent
-3. 移植到我们的React+Vite项目中
-4. 自研业务逻辑:项目管理、智能体编排、知识库集成
-
-**优势:**
-- 聊天体验有保障(LobeChat已被4万+用户验证)
-- 节省开发时间(9.5天 → 见详细方案)
-- 保持架构灵活性(不被整体框架绑定)
-
----
-
-### 问题2:向量数据库还需要考虑吗?
-
-**回答:** ❌ **完全不需要考虑**
-
-**原因:**
-- Dify内置了Qdrant向量数据库
-- 文档解析、向量化、检索全由Dify处理
-- 我们只需调用Dify的REST API即可
-
-**实际需求下更加确定:**
-```
-知识库规模:
-- 3个知识库/用户
-- 50个文件/知识库
-- 150个文件/用户最大
-
-Dify的能力:
-- 单个知识库支持上万个文档片段
-- 我们只需150个文件,远低于上限
-- Dify内置Qdrant完全够用!✅
-```
-
-**我们需要做的:**
-```javascript
-// 只需调用Dify API
-const results = await difyClient.queryKnowledgeBase({
- datasetId: 'kb-xxx',
- query: '骨质疏松的治疗方案',
- topK: 5
-});
-
-// Dify自动处理:
-// 1. 向量检索(Qdrant)
-// 2. 混合检索(关键词+语义)
-// 3. 重排序(Reranking)
-// 4. 返回结果
-```
-
-**数据库设计(业务层):**
-```sql
--- 我们只需要管理知识库的元数据
-CREATE TABLE knowledge_bases (
- id VARCHAR(50) PRIMARY KEY,
- user_id VARCHAR(50) NOT NULL,
- name VARCHAR(100) NOT NULL,
- dify_dataset_id VARCHAR(100) NOT NULL, -- Dify知识库ID
- file_count INT DEFAULT 0,
- -- 限制:每个用户最多3个
- CONSTRAINT check_kb_limit CHECK (
- (SELECT COUNT(*) FROM knowledge_bases WHERE user_id = user_id) <= 3
- )
-);
-
--- 文档表
-CREATE TABLE documents (
- id VARCHAR(50) PRIMARY KEY,
- kb_id VARCHAR(50) NOT NULL,
- filename VARCHAR(255) NOT NULL,
- file_size_bytes BIGINT NOT NULL,
- status VARCHAR(20) DEFAULT 'processing', -- processing, completed, failed
- dify_document_id VARCHAR(100) NOT NULL,
- -- 限制:每个知识库最多50个
- CONSTRAINT check_doc_limit CHECK (
- (SELECT COUNT(*) FROM documents WHERE kb_id = kb_id) <= 50
- )
-);
-```
-
----
-
-### 问题3:删除运营端功能后的方案
-
-**已删除功能:** ✅ 降低开发成本
-
-| 功能 | 状态 | 替代方案 |
-|------|------|---------|
-| 模型管理 | ❌ 删除 | 配置文件:`config/models.yaml` |
-| 智能体管理 | ❌ 删除 | 配置文件:`config/agents.yaml` |
-| 智能体配置 | ❌ 删除 | Prompt文件:`prompts/*.txt` |
-| Prompt版本管理 | ❌ 删除 | Git版本控制 |
-| 用户管理 | ✅ 保留 | 简化版(列表、禁用、查看) |
-| 数据统计 | ✅ 保留 | 简化版(基础仪表盘) |
-| 对话查看 | ✅ 保留 | 仅管理员可查看 |
-
-**配置文件示例:**
-
-```yaml
-# config/agents.yaml
-agents:
- - id: agent-picos
- name: PICOS构建
- system_prompt_file: prompts/picos_system.txt
- models:
- deepseek-v3:
- temperature: 0.3
- max_tokens: 2500
- rag_enabled: true
- status: active
-```
-
-**优势:**
-- 开发时间节省:约3周
-- 开发成本降低:¥77,000 → ¥49,300(节省36%)
-- 维护更简单:直接修改配置文件,无需后台界面
-- 版本控制:所有配置由Git管理
-
----
-
-### 问题4:大模型优先级
-
-**您的要求:** 优先DeepSeek-V3和Qwen3
-
-**已更新方案:** ✅
-
-**模型配置:**
-```yaml
-# config/models.yaml
-models:
- primary:
- - name: deepseek-v3
- provider: deepseek
- api_key: ${DEEPSEEK_API_KEY}
- base_url: https://api.deepseek.com/v1
- pricing:
- input: 1 # ¥1/百万tokens
- output: 2 # ¥2/百万tokens
- features:
- - reasoning # 推理能力强
- - long_context # 支持128k上下文
-
- secondary:
- - name: qwen3-72b
- provider: aliyun
- api_key: ${DASHSCOPE_API_KEY}
- base_url: https://dashscope.aliyuncs.com/api/v1
- pricing:
- input: 4 # ¥4/百万tokens
- output: 4
- features:
- - chinese # 中文理解好
- - stable # 国内稳定
-
- optional:
- - name: gemini-2.0-flash
- provider: google
- api_key: ${GEMINI_API_KEY}
- # 可选,国际用户使用
-```
-
-**成本对比(1000用户/月):**
-
-| 模型 | 月度成本 | 年度成本 | 性价比 |
-|------|---------|---------|--------|
-| **DeepSeek-V3** ⭐ | **¥150** | **¥1,800** | **最高** |
-| Qwen3-72B | ¥600 | ¥7,200 | 高 |
-| Gemini Pro | ¥300 | ¥3,600 | 中 |
-| GPT-4 | ¥2,500 | ¥30,000 | 低 |
-
-**建议:**
-- 90%的请求使用DeepSeek-V3(极具性价比)
-- 10%的请求使用Qwen3(需要更强中文理解时)
-- 年度可节省LLM成本:¥1,200-1,500
-
----
-
-## 🎯 最终优化方案总结
-
-### 核心架构
-
-```
-┌─────────────────────────────────────────┐
-│ 自定义前端(React + Vite) │
-│ - 项目管理(自研) │
-│ - 智能体选择(自研) │
-│ - 聊天界面(参考LobeChat)⭐ │
-│ - 知识库管理(自研) │
-└─────────────────────────────────────────┘
- ↓ REST API
-┌─────────────────────────────────────────┐
-│ 业务层 (Node.js/TypeScript) │
-│ - 智能体路由(配置化)⭐ │
-│ - 上下文组装 │
-│ - 用户认证 │
-│ - 简化运营后台⭐ │
-└─────────────────────────────────────────┘
- ↓ ↓
-┌──────────────────┐ ┌─────────────────┐
-│ Dify (RAG) │ │ LLM API │
-│ - 知识库 │ │ - DeepSeek-V3⭐│
-│ - 文档解析 │ │ - Qwen3 ⭐ │
-│ - Qdrant(内置)⭐│ │ - Gemini(可选) │
-└──────────────────┘ └─────────────────┘
-```
-
-### 技术栈
-
-**前端:**
-- React 18 + TypeScript + Vite
-- TailwindCSS + HeadlessUI
-- Zustand(状态管理)
-- **LobeChat聊天组件(复用)** ⭐
-
-**后端:**
-- Node.js + Fastify + TypeScript
-- Prisma(ORM)+ PostgreSQL
-- Redis(缓存)
-
-**RAG:**
-- Dify(Docker部署,内置Qdrant)⭐
-
-**LLM:**
-- DeepSeek-V3(主力)⭐
-- Qwen3-72B(备用)⭐
-
-**配置管理:**
-- agents.yaml(智能体配置)⭐
-- models.yaml(模型配置)⭐
-- prompts/*.txt(Prompt文件)⭐
-
-### 开发计划
-
-| 阶段 | 内容 | 时间 |
-|------|------|------|
-| 阶段1 | 基础搭建 + 复用LobeChat组件 | 1.5周 |
-| 阶段2 | 核心功能(12个智能体) | 3.5周 |
-| 阶段3 | 高级功能(RAG、文档生成) | 2周 |
-| 阶段4 | 简化运营后台 | 1周 |
-| 阶段5 | 测试优化 | 2周 |
-| **总计** | **10周(2.5个月)** | ⭐ |
-
-### 成本估算
-
-**开发成本(知识库需求明确后):**
-- 人力:4人月 × ¥12k = ¥48,000
-- 服务器(开发):¥1,250
-- LLM API(测试):¥50(DeepSeek-V3极便宜)
-- **总计:¥49,300** ⭐
-
-**月度运营成本(1000用户):**
-- 基础设施:¥1,200
-- LLM API:¥180(主要用DeepSeek-V3)
-- 对象存储(知识库文件):¥140(750GB存储 + 流量)⭐
-- 人力(运维):¥15,000
-- **总计:¥16,520/月**
-
-**成本节省:**
-- vs 原方案(大规模文献):节省约 ¥500/月
-- vs 纯手写:节省 ¥30,700+(38%+)
-
-**知识库成本明细:**
-```
-单用户:150个文件 × 5MB = 750MB
-1000用户:750GB总存储
-
-对象存储(阿里云OSS):
-- 存储费:750GB × ¥0.12/GB = ¥90/月
-- 流量费:100GB × ¥0.5/GB = ¥50/月
-- 总计:¥140/月
-
-注:比原估算的"大规模文献处理"节省60%成本
-```
-
----
-
-## ✅ 优势总结
-
-### 1. 聊天功能有保障
-- ✅ 参考LobeChat成熟实现
-- ✅ 流式输出、Markdown渲染开箱即用
-- ✅ 节省9.5天开发时间
-
-### 2. 向量数据库无需关心(知识库需求明确后更加确定)
-- ✅ Dify内置Qdrant,自动处理
-- ✅ 只需调用API,降低技术难度
-- ✅ 150个文件/用户,远低于Dify上限
-- ✅ 无需考虑性能优化
-
-### 3. 开发成本大幅降低
-- ✅ 删除复杂后台功能,节省3周
-- ✅ 配置文件管理,易于维护
-- ✅ 总成本:¥49,300(vs ¥77,000)
-
-### 4. LLM成本最优
-- ✅ DeepSeek-V3:¥1/百万tokens
-- ✅ 月度LLM成本:¥180(vs GPT-4的¥2,500)
-- ✅ 年度节省:¥27,840
-
-### 5. 开发周期短
-- ✅ 2.5个月可上线MVP
-- ✅ 复用成熟组件,降低风险
-
----
-
-## 📝 下一步行动
-
-### 立即可做:
-
-**1. 确认技术方案** ✅
-- 是否采用优化后的混合架构?
-- 是否同意删除后台管理功能?
-
-**2. 准备环境**
-```bash
-# 申请LLM API Key
-- DeepSeek API Key (https://platform.deepseek.com)
-- 阿里云DashScope Key (https://dashscope.aliyun.com)
-
-# 准备服务器
-- 云服务器 4核8G(开发环境)
-- PostgreSQL 数据库
-- Redis 缓存
-
-# 准备代码仓库
-- GitHub/GitLab 仓库
-```
-
-**3. 组建团队**
-- 1名全栈开发(Node.js + React)
-- 1名前端开发(React + TailwindCSS)
-- 预计:2.5个月完成
-
-**4. 启动开发**
-
-**第1周:**
-- [ ] 搭建前后端框架
-- [ ] 部署Dify(Docker)
-- [ ] 克隆LobeChat,提取聊天组件
-
-**第2-4周:**
-- [ ] 实现3个核心智能体
-- [ ] 集成DeepSeek-V3
-- [ ] 完成基础对话功能
-
-**第5-7周:**
-- [ ] 完善12个智能体
-- [ ] 集成Dify RAG
-- [ ] 项目管理功能
-
-**第8-10周:**
-- [ ] 简化运营后台
-- [ ] 测试优化
-- [ ] 上线MVP
-
----
-
-## 🎉 总结
-
-**优化后的方案:**
-- ✅ 聊天功能:参考LobeChat,稳定可靠
-- ✅ 向量数据库:Dify内置,无需关心
-- ✅ 运营后台:配置化,大幅简化
-- ✅ 大模型:DeepSeek-V3优先,成本最优
-- ✅ 开发周期:2.5个月
-- ✅ 开发成本:¥49,300
-- ✅ 月度成本:¥16,400(1000用户)
-
-**这是最适合您项目的技术方案!** 🚀
-
----
-
-**文档版本:v2.0(优化版)**
-**更新时间:2025-10-10**
-**作者:AI技术顾问**
-
diff --git a/启动Dify.bat b/启动Dify.bat
deleted file mode 100644
index 1a3422d8..00000000
--- a/启动Dify.bat
+++ /dev/null
@@ -1,30 +0,0 @@
-@echo off
-chcp 65001 >nul
-echo ====================================
-echo 启动 Dify 服务
-echo ====================================
-echo.
-cd /d %~dp0..\dify\docker
-echo 当前目录: %CD%
-echo.
-echo 正在启动Dify服务,这可能需要几分钟...
-echo.
-docker compose up -d
-echo.
-echo ====================================
-echo Dify 服务状态
-echo ====================================
-echo.
-docker compose ps
-echo.
-echo ====================================
-echo.
-echo 如果服务启动成功,请访问:
-echo http://localhost
-echo.
-echo 按任意键退出...
-pause >nul
-
-
-
-
diff --git a/启动指南.md b/启动指南.md
deleted file mode 100644
index 60de13c4..00000000
--- a/启动指南.md
+++ /dev/null
@@ -1,242 +0,0 @@
-# AI临床研究平台 - 快速启动指南
-
-## 📋 前提条件
-
-确保以下服务已启动:
-
-```bash
-# 检查Docker服务
-docker ps
-
-# 应该看到以下容器:
-# - ai_clinical_postgres (PostgreSQL 15)
-# - ai_clinical_redis (Redis 7)
-```
-
----
-
-## 🚀 启动后端服务
-
-### 方法1:使用启动脚本(推荐)
-
-**Windows:**
-```bash
-双击运行:backend\启动后端.bat
-```
-
-**命令行:**
-```bash
-cd backend
-npm run dev
-```
-
-### 方法2:手动启动
-
-```bash
-# 1. 进入后端目录
-cd backend
-
-# 2. 安装依赖(首次运行)
-npm install
-
-# 3. 生成Prisma Client(首次运行)
-npm run prisma:generate
-
-# 4. 启动开发服务器
-npm run dev
-```
-
----
-
-## ✅ 验证服务
-
-### 1. 检查控制台输出
-
-应该看到以下输出:
-
-```
-🔍 正在测试数据库连接...
-✅ 数据库连接成功!
-📊 数据库版本: PostgreSQL 15.14
-
-============================================================
-🚀 AI临床研究平台 - 后端服务器启动成功!
-============================================================
-📍 服务地址: http://localhost:3001
-🔍 健康检查: http://localhost:3001/health
-📡 API入口: http://localhost:3001/api/v1
-🌍 运行环境: development
-============================================================
-```
-
-### 2. 访问健康检查端点
-
-**浏览器访问:**
-```
-http://localhost:3001/health
-```
-
-**预期响应:**
-```json
-{
- "status": "ok",
- "database": "connected",
- "timestamp": "2025-10-10T07:50:03.123Z",
- "uptime": 123.456
-}
-```
-
-### 3. 访问API入口
-
-**浏览器访问:**
-```
-http://localhost:3001/api/v1
-```
-
-**预期响应:**
-```json
-{
- "message": "AI Clinical Research Platform API",
- "version": "1.0.0",
- "environment": "development"
-}
-```
-
-### 4. 使用PowerShell测试
-
-```powershell
-# 测试健康检查
-Invoke-WebRequest -Uri http://localhost:3001/health -UseBasicParsing | Select-Object -ExpandProperty Content
-
-# 测试API入口
-Invoke-WebRequest -Uri http://localhost:3001/api/v1 -UseBasicParsing | Select-Object -ExpandProperty Content
-```
-
----
-
-## 🛠️ 故障排查
-
-### 问题1:数据库连接失败
-
-**错误信息:**
-```
-❌ 数据库连接失败,无法启动服务器
-```
-
-**解决方案:**
-```bash
-# 1. 检查PostgreSQL容器是否运行
-docker ps | findstr postgres
-
-# 2. 如果没有运行,启动Docker服务
-cd D:\MyCursor\AIclinicalresearch
-docker-compose up -d
-
-# 3. 检查.env文件中的DATABASE_URL是否正确
-# DATABASE_URL="postgresql://ai_clinical:clinical123@localhost:5432/ai_clinical?schema=public"
-```
-
-### 问题2:端口3001已被占用
-
-**错误信息:**
-```
-Error: listen EADDRINUSE: address already in use :::3001
-```
-
-**解决方案:**
-```powershell
-# 1. 查找占用端口的进程
-netstat -ano | findstr :3001
-
-# 2. 结束该进程(PID是最后一列的数字)
-taskkill /PID <进程ID> /F
-
-# 3. 或者修改.env文件中的PORT
-# PORT=3002
-```
-
-### 问题3:Prisma Client未生成
-
-**错误信息:**
-```
-Error: Cannot find module '@prisma/client'
-```
-
-**解决方案:**
-```bash
-cd backend
-npm run prisma:generate
-```
-
-### 问题4:依赖包缺失
-
-**错误信息:**
-```
-Error: Cannot find module 'xxx'
-```
-
-**解决方案:**
-```bash
-cd backend
-npm install
-```
-
----
-
-## 📚 常用命令
-
-### 数据库管理
-
-```bash
-cd backend
-
-# 生成Prisma Client
-npm run prisma:generate
-
-# 创建新的迁移
-npm run prisma:migrate
-
-# 打开Prisma Studio(可视化数据库管理)
-npm run prisma:studio
-```
-
-### 开发命令
-
-```bash
-# 启动开发服务器(热重载)
-npm run dev
-
-# 构建生产版本
-npm run build
-
-# 启动生产服务器
-npm start
-```
-
----
-
-## 🎯 下一步
-
-后端服务启动成功后,您可以:
-
-1. **查看数据库**:运行 `npm run prisma:studio`
-2. **查看API文档**:`docs/01-设计文档/API设计规范.md`
-3. **开始开发前端**:进入Day 6的前端开发任务
-
----
-
-## 📞 技术支持
-
-如果遇到其他问题,请:
-
-1. 查看详细文档:`backend/README.md`
-2. 查看Day 5总结:`docs/05-每日进度/Day05-后端基础架构完成.md`
-3. 查看开发里程碑:`docs/04-开发计划/开发里程碑.md`
-
----
-
-**🎉 祝开发顺利!**
-
-
-
-
diff --git a/如何测试Phase2.md b/如何测试Phase2.md
deleted file mode 100644
index bb0d77a8..00000000
--- a/如何测试Phase2.md
+++ /dev/null
@@ -1,438 +0,0 @@
-# 📖 如何测试 Phase 2 - 使用说明
-
-**Phase 2完成日期**:2025-10-13
-**待测试内容**:双模式智能问答系统(全文阅读 + 逐篇精读)
-
----
-
-## 🎯 测试目标
-
-验证以下功能:
-1. ✅ Python微服务(文档提取)
-2. ✅ 多格式文档支持(PDF/Docx/Txt)
-3. ✅ Token计数和智能管理
-4. ✅ 全文阅读模式(35-50篇文献综合分析)
-5. ✅ 逐篇精读模式(1-5篇深度分析)
-6. ✅ 文献切换和对话历史管理
-
----
-
-## 📚 测试资料清单
-
-我已经为你准备了**4个测试工具**:
-
-### 1. 🔍 环境检查脚本(推荐第一步)
-**文件**:`检查测试环境.bat`
-**用途**:自动检查测试环境是否就绪
-**耗时**:1分钟
-
-**使用方法**:
-```bash
-# 双击运行
-检查测试环境.bat
-```
-
-**输出示例**:
-```
-✅ 通过: 8/10
-⚠️ 警告: 2/10
-❌ 失败: 0/10
-
-🟢 状态: 测试环境完全就绪!
-```
-
----
-
-### 2. ⚡ 快速测试清单(推荐日常使用)
-**文件**:`Phase2-快速测试清单.md`
-**用途**:30分钟快速验证核心功能
-**耗时**:30分钟
-**适合场景**:
-- 代码更新后的快速验证
-- 日常开发测试
-- 问题修复后的回归测试
-
-**内容结构**:
-```
-✅ 启动服务(2分钟)
-✅ 准备数据(10分钟)
-✅ 核心测试(15分钟)
- - 全文阅读模式(5分钟)
- - 逐篇精读模式(10分钟)
-✅ 快速验收(3分钟)
-```
-
----
-
-### 3. 📋 完整测试指南(推荐正式验收)
-**文件**:`Phase2-测试指南.md`
-**用途**:90分钟完整功能验证
-**耗时**:60-90分钟
-**适合场景**:
-- Phase 2正式验收
-- 上线前的完整测试
-- 详细的功能测试
-
-**内容结构**:
-```
-Part 1: 环境准备(10分钟)
-Part 2: 服务启动(5分钟)
-Part 3: 知识库准备(15-20分钟)
-Part 4: 全文阅读模式(15分钟)
- - 8个详细测试用例
-Part 5: 逐篇精读模式(20分钟)
- - 8个详细测试用例
-Part 6: 端到端场景(15分钟)
- - 3个真实用户场景
-Part 7: 问题记录(5分钟)
-附录: 常见问题排查
-```
-
----
-
-### 4. 🚀 一键启动脚本(服务启动)
-**文件**:`一键启动.bat`
-**用途**:自动启动所有服务
-**耗时**:30秒启动,10秒等待
-
-**启动内容**:
-- PostgreSQL容器
-- Redis容器
-- Python微服务(端口8000)
-- Backend服务(端口3001)
-- Frontend服务(端口3000)
-
----
-
-## 🏃 快速开始(5分钟上手)
-
-### Step 1: 检查环境(1分钟)
-```bash
-# 双击运行
-检查测试环境.bat
-```
-**看到"🟢 测试环境完全就绪"** → 进入Step 2
-**看到"🔴 或 🟡"** → 按照提示修复问题
-
----
-
-### Step 2: 启动服务(2分钟)
-```bash
-# 双击运行
-一键启动.bat
-```
-**等待**:30秒,看到3个窗口打开
-**验证**:自动打开浏览器 http://localhost:3000
-
----
-
-### Step 3: 选择测试方式(2分钟)
-
-#### 方式A:快速测试(30分钟)⭐ 推荐
-```bash
-# 打开文档
-Phase2-快速测试清单.md
-```
-**特点**:快速、核心功能验证
-
-#### 方式B:完整测试(90分钟)
-```bash
-# 打开文档
-Phase2-测试指南.md
-```
-**特点**:详细、全面、适合正式验收
-
----
-
-## 📊 推荐测试流程
-
-### 🎯 首次测试(推荐完整测试)
-
-```mermaid
-graph LR
- A[检查环境] --> B[启动服务]
- B --> C[完整测试指南]
- C --> D[记录问题]
- D --> E{有严重问题?}
- E -->|是| F[修复问题]
- E -->|否| G[验收通过]
- F --> A
-```
-
-**预计时间**:90-120分钟(含问题修复)
-
----
-
-### 🔄 日常测试(推荐快速测试)
-
-```mermaid
-graph LR
- A[检查环境] --> B[启动服务]
- B --> C[快速测试清单]
- C --> D{测试通过?}
- D -->|是| E[继续开发]
- D -->|否| F[快速修复]
- F --> C
-```
-
-**预计时间**:30分钟
-
----
-
-## 🎯 测试策略建议
-
-### 阶段1:初次验证(第一次测试)
-**目标**:全面了解系统功能和稳定性
-
-**步骤**:
-1. ✅ 运行环境检查
-2. ✅ 使用**完整测试指南**(90分钟)
-3. ✅ 记录所有发现的问题
-4. ✅ 按优先级修复问题
-5. ✅ 重新测试验证
-
-**预期产出**:
-- 完整的测试报告
-- 问题清单(按优先级)
-- 修复计划
-
----
-
-### 阶段2:问题修复验证(修复后)
-**目标**:验证问题是否修复
-
-**步骤**:
-1. ✅ 运行环境检查
-2. ✅ 针对问题点重新测试
-3. ✅ 使用**快速测试清单**回归测试
-
-**预期产出**:
-- 问题修复确认
-- 回归测试通过
-
----
-
-### 阶段3:正式验收(准备上线)
-**目标**:最终验收决策
-
-**步骤**:
-1. ✅ 运行环境检查
-2. ✅ 使用**完整测试指南**再次测试
-3. ✅ 端到端场景测试
-4. ✅ 性能指标验证
-5. ✅ 最终验收决策
-
-**验收标准**:
-- [ ] 所有核心功能正常
-- [ ] 无阻断性问题
-- [ ] 性能指标达标
-- [ ] 用户体验良好
-
----
-
-## 🔧 常见场景处理
-
-### 场景1:环境检查失败
-**现象**:运行`检查测试环境.bat`后显示🔴
-
-**处理步骤**:
-1. 查看哪些检查项标记为❌
-2. 按照提示安装缺失的软件
-3. 重新运行检查脚本
-4. 直到显示🟢才能继续测试
-
-**常见问题**:
-- Docker未启动 → 启动Docker Desktop
-- Python未安装 → 安装Python 3.11+
-- 虚拟环境缺失 → `cd extraction_service && .\install.bat`
-
----
-
-### 场景2:服务启动失败
-**现象**:一键启动后某个服务报错
-
-**处理步骤**:
-1. 查看报错的服务窗口
-2. 记录错误信息
-3. 查看测试指南"附录A:常见问题排查"
-4. 按照排查步骤解决
-
-**常见问题**:
-- 端口被占用 → 关闭占用程序或重启电脑
-- 依赖未安装 → 运行`npm install`或`pip install`
-- 数据库连接失败 → 检查Docker容器状态
-
----
-
-### 场景3:功能测试失败
-**现象**:某个功能不工作或报错
-
-**处理步骤**:
-1. 在测试文档中记录具体问题
-2. 截图保存关键错误
-3. 记录复现步骤
-4. 查看浏览器Console(F12)的错误信息
-5. 提交问题清单
-
-**问题记录模板**:
-```
-问题描述:____________
-复现步骤:
- 1. ____________
- 2. ____________
-预期结果:____________
-实际结果:____________
-截图:[附件]
-Console错误:____________
-```
-
----
-
-## 📝 测试记录管理
-
-### 建议的文档结构
-
-创建一个测试记录文件夹:
-```
-AIclinicalresearch/
-├── 测试记录/
-│ ├── 2025-10-13-首次测试.md
-│ ├── 2025-10-14-问题修复验证.md
-│ ├── 2025-10-15-正式验收.md
-│ └── 问题清单.md
-```
-
-### 问题清单模板
-
-```markdown
-# Phase 2 问题清单
-
-## 🔴 严重问题(阻断性)
-1. [问题描述] - [状态:待修复/已修复] - [负责人]
-
-## 🟡 中等问题(影响使用)
-1. [问题描述] - [状态:待修复/已修复] - [负责人]
-
-## 🟢 轻微问题(不影响主流程)
-1. [问题描述] - [状态:待修复/已修复] - [负责人]
-```
-
----
-
-## 🎊 测试完成后
-
-### ✅ 如果验收通过
-
-**恭喜!Phase 2验收通过!** 🎉
-
-**下一步选择**:
-
-#### 选项A:开发Phase 3(批处理模式)⭐ 推荐
-- **时间**:1-2天
-- **价值**:完善知识库功能闭环
-- **任务**:批量文献处理、结果汇总、导出功能
-
-#### 选项B:开发里程碑2(11个智能体)
-- **时间**:2-3周
-- **价值**:产品功能完整度大幅提升
-- **任务**:开发其余11个专业智能体
-
-**建议**:先完成Phase 3(1-2天),再进入里程碑2
-
----
-
-### ⚠️ 如果有问题需要修复
-
-**不要慌!**按照以下步骤处理:
-
-1. **问题分类**
- - 将问题分为:严重、中等、轻微
-
-2. **优先级排序**
- - 严重问题:立即修复
- - 中等问题:尽快修复
- - 轻微问题:可延后
-
-3. **修复计划**
- - 为每个问题分配修复时间
- - 预估总修复时间
-
-4. **修复后验证**
- - 使用快速测试清单回归测试
- - 确认问题已解决
-
----
-
-## 📞 需要帮助?
-
-### 测试过程中遇到问题
-
-1. **查看测试指南的"附录A:常见问题排查"**
-2. **查看Console错误信息(F12)**
-3. **记录详细的问题描述和截图**
-4. **整理问题清单待Review**
-
-### 不确定如何判断测试结果
-
-**参考标准**:
-- ✅ **通过**:功能正常工作,无错误
-- ⚠️ **有条件通过**:功能基本工作,有小问题但不影响主流程
-- ❌ **不通过**:功能无法工作或有严重错误
-
----
-
-## 📚 相关文档索引
-
-### Phase 2开发文档
-- [Phase2-最终技术方案.md](./docs/05-每日进度/Phase2-最终技术方案.md)
-- [Phase2-完成报告.md](./docs/05-每日进度/Phase2-完成报告.md)
-- [Phase2-最终总结.md](./docs/05-每日进度/Phase2-最终总结.md)
-
-### 测试文档
-- [Phase2-测试指南.md](./Phase2-测试指南.md) - 完整版
-- [Phase2-快速测试清单.md](./Phase2-快速测试清单.md) - 快速版
-
-### 开发计划文档
-- [开发里程碑.md](./docs/04-开发计划/开发里程碑.md)
-
----
-
-## 🎯 总结
-
-### 测试工具选择
-
-| 场景 | 推荐工具 | 耗时 |
-|------|---------|------|
-| 首次测试 | 完整测试指南 | 90分钟 |
-| 日常开发测试 | 快速测试清单 | 30分钟 |
-| 问题修复后 | 快速测试清单 | 30分钟 |
-| 正式验收 | 完整测试指南 | 90分钟 |
-| 环境检查 | 环境检查脚本 | 1分钟 |
-
-### 测试流程建议
-
-```
-第1次: 环境检查 → 完整测试 → 记录问题
-第2次: 环境检查 → 快速测试 → 验证修复
-第3次: 环境检查 → 完整测试 → 最终验收
-```
-
----
-
-**准备好了吗?立即开始测试!** 🚀
-
-1. 运行 `检查测试环境.bat`
-2. 运行 `一键启动.bat`
-3. 打开 `Phase2-快速测试清单.md` 或 `Phase2-测试指南.md`
-4. 开始测试!
-
-**祝测试顺利!** 🎉
-
-
-
-
-
-
-
-
-
diff --git a/对话系统实现方案对比.md b/对话系统实现方案对比.md
deleted file mode 100644
index d5fa0cb4..00000000
--- a/对话系统实现方案对比.md
+++ /dev/null
@@ -1,860 +0,0 @@
-# 对话系统实现方案详细对比
-
-## 🎯 核心问题
-
-**如果不使用LobeChat整体框架,基于大模型的对话聊天该怎么实现?**
-
-让我为您详细对比3种方案:
-
----
-
-## 方案A:使用Dify的对话功能
-
-### Dify的对话能力
-
-Dify确实提供了完整的对话功能,包括:
-- ✅ LLM对话管理
-- ✅ 流式输出
-- ✅ 对话历史管理
-- ✅ RAG知识库集成
-- ✅ 提供WebApp界面
-
-### 架构图
-
-```
-用户浏览器
- ↓
-Dify自带的WebApp界面
- ↓
-Dify后端(对话+RAG)
- ↓
-LLM API (DeepSeek/Qwen)
-```
-
-### 实现方式
-
-**方式1:直接使用Dify的WebApp**
-```bash
-# 部署Dify后,直接访问其Web界面
-docker-compose up -d
-# 访问 http://localhost:3000
-# 创建12个应用(对应12个智能体)
-```
-
-**方式2:通过Dify API集成**
-```javascript
-// 调用Dify的对话API
-const response = await fetch('https://api.dify.ai/v1/chat-messages', {
- method: 'POST',
- headers: {
- 'Authorization': `Bearer ${DIFY_API_KEY}`,
- 'Content-Type': 'application/json'
- },
- body: JSON.stringify({
- inputs: {},
- query: "请帮我构建PICOS",
- response_mode: "streaming", // 流式输出
- conversation_id: "conv-xxx", // 对话ID
- user: "user-123"
- })
-});
-
-// 接收流式响应
-const reader = response.body.getReader();
-while (true) {
- const { done, value } = await reader.read();
- if (done) break;
- // 处理流式数据
-}
-```
-
-### 优点 ✅
-
-1. **开发成本极低**
- - 不需要自己实现对话逻辑
- - 不需要自己实现流式输出
- - 不需要自己管理对话历史
- - RAG功能开箱即用
-
-2. **功能完整**
- - 对话管理
- - Prompt管理
- - 流式输出
- - 知识库集成
- - 文件上传
-
-3. **快速上线**
- - 1-2周即可搭建MVP
- - 无需深入理解LLM API细节
-
-### 缺点 ❌
-
-1. **12个智能体管理复杂**
- ```
- 问题:需要在Dify中创建12个独立的应用(App)
-
- Dify界面:
- ├── 应用1: 选题评价
- ├── 应用2: PICOS构建
- ├── 应用3: 论文润色
- ├── ... (共12个)
- └── 应用12: 期刊稿约评审
-
- 影响:
- - 用户需要在12个应用间切换(体验差)
- - 无法统一管理对话历史
- - 无法共享项目上下文
- ```
-
-2. **项目管理功能缺失**
- ```
- 我们的需求:
- - 用户创建"项目/课题"
- - 在项目内使用多个智能体
- - 项目背景信息自动注入
- - 对话可"固定"到项目背景
-
- Dify的能力:
- - ❌ 没有"项目"概念
- - ❌ 无法跨应用共享上下文
- - ❌ 每个对话是独立的
- ```
-
-3. **前端定制困难**
- ```
- 我们的原型图:
- - 左侧:项目列表 + 智能体列表
- - 中间:智能体卡片选择
- - 右侧:对话界面
-
- Dify的界面:
- - 固定的单应用界面
- - 定制需要修改Dify源码(复杂)
- ```
-
-4. **业务逻辑受限**
- ```
- 我们的特殊需求:
- - 全局快速问答 vs 项目内深度研究
- - 动态背景信息管理(固定功能)
- - 对话溯源(引用知识库)
- - 多模型即时切换
-
- Dify的支持:
- - 🟡 部分支持,但需要复杂配置
- - 🟡 或需要修改源码
- ```
-
-### 适用场景 ✅
-
-**适合:** 如果您的需求是:
-- 简单的知识库问答
-- 单一的对话场景
-- 快速验证想法(MVP)
-
-**不适合:** 我们的项目
-- ❌ 12个智能体需要统一管理
-- ❌ 项目管理是核心功能
-- ❌ 需要高度定制的UI
-
----
-
-## 方案B:参考LobeChat + 自研后端(推荐 ⭐)
-
-### 核心思路
-
-```
-前端:参考LobeChat的UI组件(不用整体框架)
-后端:自己实现对话逻辑(调用LLM API)
-RAG:使用Dify(专注知识库检索)
-```
-
-### 架构图
-
-```
-┌─────────────────────────────────────────┐
-│ 前端(React + Vite) │
-│ ┌──────────────────────────────────┐ │
-│ │ 聊天UI(参考LobeChat实现) │ │
-│ │ - ChatMessage 组件 │ │
-│ │ - ChatInput 组件 │ │
-│ │ - StreamRenderer 组件 │ │
-│ │ - MarkdownContent 组件 │ │
-│ └──────────────────────────────────┘ │
-│ ┌──────────────────────────────────┐ │
-│ │ 业务界面(自己实现) │ │
-│ │ - 项目管理 │ │
-│ │ - 智能体选择 │ │
-│ │ - 历史记录 │ │
-│ └──────────────────────────────────┘ │
-└─────────────────────────────────────────┘
- ↓ REST API
-┌─────────────────────────────────────────┐
-│ 后端(Node.js + TypeScript) │
-│ ┌──────────────────────────────────┐ │
-│ │ 对话服务(自己实现) │ │
-│ │ - 接收用户消息 │ │
-│ │ - 组装上下文(项目背景+历史) │ │
-│ │ - 调用LLM API │ │
-│ │ - 流式返回结果 │ │
-│ └──────────────────────────────────┘ │
-│ ┌──────────────────────────────────┐ │
-│ │ 业务服务(自己实现) │ │
-│ │ - 项目管理 │ │
-│ │ - 智能体路由 │ │
-│ │ - 权限控制 │ │
-│ └──────────────────────────────────┘ │
-└─────────────────────────────────────────┘
- ↓ ↓
-┌──────────────────┐ ┌─────────────────┐
-│ Dify (RAG) │ │ LLM API │
-│ - 知识库检索 │ │ - DeepSeek-V3 │
-│ (仅RAG) │ │ - Qwen3 │
-└──────────────────┘ └─────────────────┘
-```
-
-### 详细实现
-
-#### 1. 前端聊天UI(参考LobeChat)
-
-**提取LobeChat的核心组件:**
-
-```tsx
-// src/components/chat/ChatMessage.tsx
-// 从LobeChat移植,做少量修改
-
-import React from 'react';
-import ReactMarkdown from 'react-markdown';
-import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
-
-interface Message {
- id: string;
- role: 'user' | 'assistant';
- content: string;
- timestamp: number;
-}
-
-export function ChatMessage({ message, onCopy, onPin }: Props) {
- const isUser = message.role === 'user';
-
- return (
-
- {/* 头像 */}
-
-
- {/* 消息内容 */}
-
-
- {isUser ? (
-
{message.content}
- ) : (
-
- {String(children).replace(/\n$/, '')}
-
- ) : (
-
- {children}
-
- );
- }
- }}
- >
- {message.content}
-
- )}
-
-
- {/* 操作按钮 */}
- {!isUser && (
-
-
-
-
-
- )}
-
-
- );
-}
-```
-
-```tsx
-// src/components/chat/ChatInput.tsx
-// 从LobeChat移植
-
-export function ChatInput({ onSend, onUpload, onKbSelect }: Props) {
- const [message, setMessage] = useState('');
-
- const handleSend = () => {
- if (!message.trim()) return;
- onSend(message);
- setMessage('');
- };
-
- return (
-
- );
-}
-```
-
-#### 2. 后端对话逻辑(自己实现)
-
-**核心代码:**
-
-```typescript
-// backend/src/services/chat.service.ts
-
-import { agentConfig } from '../config/agent-loader';
-import { LLMFactory } from '../adapters/llm-factory';
-import { difyClient } from '../clients/dify';
-
-export class ChatService {
-
- /**
- * 处理对话请求(流式输出)
- */
- async handleChatStream(req: Request, res: Response) {
- const {
- message,
- projectId,
- agentId,
- conversationId,
- modelName = 'deepseek-v3'
- } = req.body;
-
- // 1. 获取智能体配置
- const agent = agentConfig.getAgent(agentId);
- if (!agent) {
- return res.status(404).json({ error: 'Agent not found' });
- }
-
- // 2. 组装上下文
- const context = await this.buildContext({
- projectId,
- agentId,
- conversationId,
- message,
- agent
- });
-
- // 3. 设置流式响应头
- res.setHeader('Content-Type', 'text/event-stream');
- res.setHeader('Cache-Control', 'no-cache');
- res.setHeader('Connection', 'keep-alive');
-
- try {
- // 4. 调用LLM(流式)
- const llm = LLMFactory.create(modelName);
- const stream = await llm.chatStream({
- messages: context,
- temperature: agent.models[modelName]?.temperature || 0.7,
- max_tokens: agent.models[modelName]?.max_tokens || 2000
- });
-
- // 5. 转发流式数据
- let fullResponse = '';
- for await (const chunk of stream) {
- fullResponse += chunk;
- res.write(`data: ${JSON.stringify({
- type: 'token',
- content: chunk
- })}\n\n`);
- }
-
- // 6. 保存对话记录
- await this.saveMessage({
- conversationId,
- projectId,
- agentId,
- userMessage: message,
- aiMessage: fullResponse
- });
-
- // 7. 结束流
- res.write(`data: ${JSON.stringify({ type: 'done' })}\n\n`);
- res.end();
-
- } catch (error) {
- res.write(`data: ${JSON.stringify({
- type: 'error',
- message: error.message
- })}\n\n`);
- res.end();
- }
- }
-
- /**
- * 组装对话上下文
- */
- private async buildContext(params: BuildContextParams) {
- const { projectId, agentId, conversationId, message, agent } = params;
-
- const messages = [];
-
- // 1. 项目背景(如果有)
- if (projectId) {
- const project = await db.projects.findOne({ id: projectId });
- messages.push({
- role: 'system',
- content: `# 项目背景\n${project.description}`
- });
- }
-
- // 2. 智能体系统提示词
- const systemPrompt = agentConfig.getPrompt(agent.system_prompt_file);
- messages.push({
- role: 'system',
- content: systemPrompt
- });
-
- // 3. 历史对话(最近10轮)
- const history = await db.messages.find({
- conversation_id: conversationId
- }).limit(20).sort({ created_at: -1 });
-
- for (const msg of history.reverse()) {
- messages.push(
- { role: 'user', content: msg.user_message },
- { role: 'assistant', content: msg.ai_message }
- );
- }
-
- // 4. 知识库检索(如果需要)
- if (agent.rag_enabled && message.includes('@')) {
- const kbName = this.extractKbReference(message);
- if (kbName) {
- const ragResults = await difyClient.queryKnowledgeBase({
- datasetId: this.getKbId(kbName),
- query: message,
- topK: 5
- });
-
- messages.push({
- role: 'system',
- content: `# 相关知识库内容\n${
- ragResults.map(r => `[${r.metadata.filename}]\n${r.content}`).join('\n\n')
- }`
- });
- }
- }
-
- // 5. 当前用户问题
- messages.push({
- role: 'user',
- content: message
- });
-
- return messages;
- }
-
- /**
- * 保存对话记录
- */
- private async saveMessage(params: SaveMessageParams) {
- await db.messages.create({
- conversation_id: params.conversationId,
- project_id: params.projectId,
- agent_id: params.agentId,
- user_message: params.userMessage,
- ai_message: params.aiMessage,
- created_at: new Date()
- });
- }
-}
-```
-
-#### 3. LLM Adapter(统一接口)
-
-```typescript
-// backend/src/adapters/llm-factory.ts
-
-// DeepSeek Adapter
-export class DeepSeekAdapter {
- constructor(private apiKey: string) {}
-
- async chatStream(params: ChatParams): AsyncGenerator {
- const response = await fetch('https://api.deepseek.com/v1/chat/completions', {
- method: 'POST',
- headers: {
- 'Authorization': `Bearer ${this.apiKey}`,
- 'Content-Type': 'application/json'
- },
- body: JSON.stringify({
- model: 'deepseek-chat',
- messages: params.messages,
- temperature: params.temperature,
- max_tokens: params.max_tokens,
- stream: true
- })
- });
-
- const reader = response.body.getReader();
- const decoder = new TextDecoder();
-
- while (true) {
- const { done, value } = await reader.read();
- if (done) break;
-
- const chunk = decoder.decode(value);
- const lines = chunk.split('\n').filter(line => line.trim());
-
- for (const line of lines) {
- if (line.startsWith('data: ')) {
- const data = line.slice(6);
- if (data === '[DONE]') continue;
-
- try {
- const json = JSON.parse(data);
- const content = json.choices[0]?.delta?.content;
- if (content) {
- yield content;
- }
- } catch (e) {
- // 忽略解析错误
- }
- }
- }
- }
- }
-}
-
-// Qwen Adapter
-export class QwenAdapter {
- constructor(private apiKey: string) {}
-
- async chatStream(params: ChatParams): AsyncGenerator {
- // 类似实现,调用阿里云DashScope API
- // ...
- }
-}
-
-// 工厂
-export class LLMFactory {
- static create(modelName: string) {
- switch (modelName) {
- case 'deepseek-v3':
- return new DeepSeekAdapter(process.env.DEEPSEEK_API_KEY);
- case 'qwen3-72b':
- return new QwenAdapter(process.env.DASHSCOPE_API_KEY);
- default:
- throw new Error(`Unsupported model: ${modelName}`);
- }
- }
-}
-```
-
-#### 4. 前端调用(流式接收)
-
-```typescript
-// frontend/src/services/chat.ts
-
-export async function sendMessage(params: SendMessageParams) {
- const { message, projectId, agentId, conversationId, onToken, onDone } = params;
-
- const response = await fetch('/api/chat/stream', {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({
- message,
- project_id: projectId,
- agent_id: agentId,
- conversation_id: conversationId,
- model_name: 'deepseek-v3'
- })
- });
-
- const reader = response.body.getReader();
- const decoder = new TextDecoder();
-
- while (true) {
- const { done, value } = await reader.read();
- if (done) break;
-
- const chunk = decoder.decode(value);
- const lines = chunk.split('\n');
-
- for (const line of lines) {
- if (line.startsWith('data: ')) {
- const data = JSON.parse(line.slice(6));
-
- if (data.type === 'token') {
- onToken(data.content); // 实时显示
- } else if (data.type === 'done') {
- onDone();
- } else if (data.type === 'error') {
- throw new Error(data.message);
- }
- }
- }
- }
-}
-
-// React组件中使用
-function ChatView() {
- const [messages, setMessages] = useState([]);
- const [currentResponse, setCurrentResponse] = useState('');
-
- const handleSend = async (message: string) => {
- // 添加用户消息
- setMessages(prev => [...prev, { role: 'user', content: message }]);
-
- // 添加空的AI消息(准备接收流式内容)
- const aiMessageId = Date.now();
- setMessages(prev => [...prev, {
- id: aiMessageId,
- role: 'assistant',
- content: ''
- }]);
-
- // 发送请求
- await sendMessage({
- message,
- projectId: currentProject.id,
- agentId: currentAgent.id,
- conversationId: currentConversation.id,
-
- // 接收每个token
- onToken: (token) => {
- setMessages(prev => prev.map(msg =>
- msg.id === aiMessageId
- ? { ...msg, content: msg.content + token }
- : msg
- ));
- },
-
- // 完成
- onDone: () => {
- console.log('Stream completed');
- }
- });
- };
-
- return (
-
-
- {messages.map(msg => (
-
- ))}
-
-
-
- );
-}
-```
-
-### 优点 ✅
-
-1. **完全可控**
- - ✅ 业务逻辑完全自主
- - ✅ UI 100%匹配原型图
- - ✅ 可以实现任何定制需求
-
-2. **功能完整**
- - ✅ 项目管理(核心功能)
- - ✅ 12个智能体统一管理
- - ✅ 上下文动态管理
- - ✅ 对话固定到项目背景
-
-3. **聊天体验好**
- - ✅ 参考LobeChat的成熟实现
- - ✅ 流式输出流畅
- - ✅ Markdown渲染完美
-
-4. **成本可控**
- - ✅ 只需实现业务逻辑
- - ✅ 聊天UI复用LobeChat(节省9.5天)
- - ✅ RAG交给Dify(节省40天)
-
-### 缺点 ❌
-
-1. **需要自己实现对话逻辑**
- - 但其实不复杂(上面的代码已展示)
- - 核心就是:接收消息 → 组装上下文 → 调用LLM → 返回流式结果
-
-2. **需要处理流式输出**
- - 但有成熟的实现可参考(LobeChat、OpenAI SDK)
- - Server-Sent Events (SSE) 是标准协议
-
-### 开发工作量
-
-| 模块 | 工作量 | 说明 |
-|------|-------|------|
-| 前端聊天UI | 1天 | 复用LobeChat组件 |
-| 流式输出前端 | 0.5天 | 参考LobeChat实现 |
-| Markdown渲染 | 0.5天 | 使用react-markdown |
-| 后端对话服务 | 2天 | 上下文组装 + LLM调用 |
-| 流式输出后端 | 1天 | SSE实现 |
-| LLM Adapter | 1天 | DeepSeek + Qwen接入 |
-| **总计** | **6天** | vs 纯手写13天 |
-
----
-
-## 方案C:完全自研(不推荐)
-
-### 架构
-
-```
-前端:完全自己实现聊天UI
-后端:完全自己实现对话逻辑
-RAG:完全自己实现向量检索
-```
-
-### 缺点 ❌
-
-- 开发周期长(4-6个月)
-- 技术难度高
-- RAG系统复杂度被严重低估
-- 不推荐!
-
----
-
-## 📊 三种方案对比总结
-
-| 维度 | 方案A: 用Dify对话 | 方案B: 自研对话+Dify RAG ⭐ | 方案C: 完全自研 |
-|------|------------------|---------------------------|----------------|
-| **开发周期** | 1-2周 | 2.5个月 | 4-6个月 |
-| **开发成本** | ¥10k-20k | **¥49k** ⭐ | ¥80k-180k |
-| **12个智能体管理** | 🔴 复杂 | **🟢 简单** ⭐ | 🟢 简单 |
-| **项目管理** | 🔴 不支持 | **🟢 完全支持** ⭐ | 🟢 完全支持 |
-| **UI定制** | 🔴 困难 | **🟢 完全可控** ⭐ | 🟢 完全可控 |
-| **业务逻辑灵活性** | 🟡 受限 | **🟢 完全灵活** ⭐ | 🟢 完全灵活 |
-| **聊天体验** | 🟢 好 | **🟢 好** ⭐ | 🟡 需大量调试 |
-| **RAG能力** | 🟢 强 | **🟢 强** ⭐ | 🟡 需自己实现 |
-| **技术难度** | ⭐ | **⭐⭐⭐** | ⭐⭐⭐⭐⭐ |
-| **维护成本** | 🟢 低 | **🟡 中** ⭐ | 🔴 高 |
-| **功能匹配度** | 🔴 40% | **🟢 95%** ⭐ | 🟢 100% |
-
----
-
-## 🎯 最终推荐:方案B
-
-### 核心理由
-
-**✅ Dify能帮我们什么?**
-- ✅ RAG知识库功能(文档解析、向量检索、答案溯源)
-- ❌ 对话功能不适合我们(12个智能体管理困难)
-
-**✅ 我们自己做什么?**
-- ✅ 对话逻辑(接收消息 → 组装上下文 → 调用LLM)
-- ✅ 项目管理(核心功能)
-- ✅ 智能体编排(12个智能体统一管理)
-- ✅ 前端UI(100%匹配原型图)
-
-**✅ LobeChat帮我们什么?**
-- ✅ 聊天UI组件(开源可复用)
-- ✅ 流式输出参考实现
-- ✅ Markdown渲染方案
-
-### 技术可行性
-
-**对话功能其实不复杂!** 核心只有4步:
-
-```typescript
-// 1. 接收消息
-const { message, projectId, agentId } = req.body;
-
-// 2. 组装上下文
-const context = [
- { role: 'system', content: '项目背景...' },
- { role: 'system', content: '智能体提示词...' },
- { role: 'user', content: '历史对话...' },
- { role: 'assistant', content: '历史回复...' },
- { role: 'user', content: message }
-];
-
-// 3. 调用LLM
-const stream = await deepseek.chatStream({ messages: context });
-
-// 4. 返回流式结果
-for await (const chunk of stream) {
- res.write(`data: ${JSON.stringify({ content: chunk })}\n\n`);
-}
-```
-
-**就这么简单!** 不需要Dify的对话功能。
-
-### 最佳实践
-
-```
-Dify擅长的:RAG(知识库检索)
- → 让Dify做它擅长的
-
-我们需要的:复杂业务逻辑(项目管理、智能体编排)
- → 自己实现,完全可控
-
-聊天UI:成熟方案(LobeChat)
- → 参考实现,节省时间
-```
-
----
-
-## 📝 总结
-
-**问题:如果不使用LobeChat,对话聊天该怎么实现?**
-
-**答案:**
-1. **前端聊天UI**:参考LobeChat开源组件(复用,不是不用)
-2. **后端对话逻辑**:自己实现(调用DeepSeek/Qwen API)
-3. **RAG知识库**:使用Dify(专注检索)
-
-**Dify的角色:**
-- ✅ 用于RAG知识库功能
-- ❌ 不用其对话功能(不适合我们的复杂业务)
-
-**这个方案的优势:**
-- ✅ 开发周期:2.5个月(可接受)
-- ✅ 开发成本:¥49,300(可控)
-- ✅ 功能匹配度:95%(满足需求)
-- ✅ 聊天体验:优秀(参考LobeChat)
-- ✅ 灵活性:高(业务逻辑完全自主)
-
-**关键点:对话功能不复杂,核心是业务逻辑!**
-
----
-
-**文档版本:v1.0**
-**更新时间:2025-10-10**
-
-
-
-
diff --git a/开发环境配置指南.md b/开发环境配置指南.md
deleted file mode 100644
index 100d9ca8..00000000
--- a/开发环境配置指南.md
+++ /dev/null
@@ -1,707 +0,0 @@
-# 开发环境配置指南
-
-## 🎯 核心建议:先本地开发,MVP完成后再上云
-
-**理由:**
-- ✅ 节省成本(开发期2.5个月无需云服务器费用)
-- ✅ 调试方便(本地开发响应快)
-- ✅ 灵活性高(随时修改配置)
-- ✅ 降低风险(等功能稳定后再上云)
-
----
-
-## 📅 分阶段部署策略
-
-### 阶段1:本地开发(0-2个月)⭐ 当前阶段
-
-**环境:** 开发人员本地电脑
-
-**需要的硬件:**
-- CPU: 4核心以上
-- 内存: 16GB以上(推荐)
-- 硬盘: 50GB可用空间
-- 操作系统: Windows 10+、macOS、Linux
-
-**需要安装:**
-- Docker Desktop(运行Dify)
-- Node.js 18+(后端开发)
-- PostgreSQL 15+(或用Docker)
-- Redis 7+(或用Docker)
-
-**费用:** ¥0(使用现有设备)
-
-**适用于:**
-- 搭建基础架构
-- 开发核心功能
-- 本地测试
-- MVP开发
-
----
-
-### 阶段2:内测环境(2-2.5个月)
-
-**环境:** 小型云服务器
-
-**推荐配置:**
-- CPU: 2核心
-- 内存: 4GB
-- 硬盘: 40GB
-- 带宽: 1Mbps
-
-**云厂商选择:**
-- 阿里云:轻量应用服务器 约¥60/月
-- 腾讯云:轻量应用服务器 约¥50/月
-
-**费用:** ¥50-60/月
-
-**适用于:**
-- 小范围内测(5-10人)
-- 功能验证
-- 性能初步测试
-
----
-
-### 阶段3:正式上线(3个月后)
-
-**环境:** 生产级云服务器
-
-**推荐配置:**
-- CPU: 4核心
-- 内存: 8GB
-- 硬盘: 100GB SSD
-- 带宽: 5Mbps
-
-**费用:** ¥200-300/月
-
-**适用于:**
-- 正式对外服务
-- 100+用户规模
-
----
-
-## 💻 本地开发环境配置(详细步骤)
-
-### 方案A:全Docker方式(推荐 ⭐)
-
-**优点:** 环境隔离、配置简单、一键启动
-
-#### 1. 安装Docker Desktop
-
-**Windows:**
-```bash
-# 下载并安装 Docker Desktop
-# https://www.docker.com/products/docker-desktop/
-
-# 启动后验证
-docker --version
-docker-compose --version
-```
-
-**macOS:**
-```bash
-# 使用 Homebrew
-brew install --cask docker
-
-# 或下载安装包
-# https://www.docker.com/products/docker-desktop/
-```
-
-#### 2. 创建项目目录
-
-```bash
-mkdir ai-clinical-research
-cd ai-clinical-research
-```
-
-#### 3. 创建 docker-compose.yml
-
-```yaml
-# docker-compose.yml
-version: '3.8'
-
-services:
- # PostgreSQL 数据库
- postgres:
- image: postgres:15-alpine
- container_name: acr-postgres
- environment:
- POSTGRES_DB: ai_clinical_research
- POSTGRES_USER: dev_user
- POSTGRES_PASSWORD: dev_password
- ports:
- - "5432:5432"
- volumes:
- - postgres_data:/var/lib/postgresql/data
- restart: unless-stopped
-
- # Redis 缓存
- redis:
- image: redis:7-alpine
- container_name: acr-redis
- ports:
- - "6379:6379"
- volumes:
- - redis_data:/data
- restart: unless-stopped
-
- # Dify(RAG系统)
- dify:
- image: langgenius/dify-api:latest
- container_name: acr-dify
- environment:
- - DB_USERNAME=dify
- - DB_PASSWORD=dify_password
- - DB_HOST=dify-postgres
- - DB_PORT=5432
- - DB_DATABASE=dify
- - REDIS_HOST=dify-redis
- - REDIS_PORT=6379
- - SECRET_KEY=your-secret-key-change-this
- ports:
- - "5001:5001"
- depends_on:
- - dify-postgres
- - dify-redis
- restart: unless-stopped
-
- # Dify 专用 PostgreSQL
- dify-postgres:
- image: postgres:15-alpine
- container_name: acr-dify-postgres
- environment:
- POSTGRES_DB: dify
- POSTGRES_USER: dify
- POSTGRES_PASSWORD: dify_password
- volumes:
- - dify_postgres_data:/var/lib/postgresql/data
- restart: unless-stopped
-
- # Dify 专用 Redis
- dify-redis:
- image: redis:7-alpine
- container_name: acr-dify-redis
- volumes:
- - dify_redis_data:/data
- restart: unless-stopped
-
- # Dify Web界面(可选,开发调试用)
- dify-web:
- image: langgenius/dify-web:latest
- container_name: acr-dify-web
- environment:
- - CONSOLE_API_URL=http://localhost:5001
- ports:
- - "3000:3000"
- depends_on:
- - dify
- restart: unless-stopped
-
-volumes:
- postgres_data:
- redis_data:
- dify_postgres_data:
- dify_redis_data:
-
-networks:
- default:
- name: acr-network
-```
-
-#### 4. 启动所有服务
-
-```bash
-# 启动所有容器
-docker-compose up -d
-
-# 查看运行状态
-docker-compose ps
-
-# 查看日志
-docker-compose logs -f
-
-# 停止所有容器
-docker-compose down
-
-# 停止并删除数据
-docker-compose down -v
-```
-
-#### 5. 验证服务
-
-```bash
-# 检查 PostgreSQL
-docker exec -it acr-postgres psql -U dev_user -d ai_clinical_research -c "\dt"
-
-# 检查 Redis
-docker exec -it acr-redis redis-cli ping
-# 应返回: PONG
-
-# 检查 Dify
-curl http://localhost:5001/health
-# 或在浏览器访问 http://localhost:3000
-```
-
----
-
-### 方案B:本地安装方式
-
-**适用于:** 不想用Docker或机器配置较低
-
-#### 1. 安装 PostgreSQL
-
-**Windows:**
-```bash
-# 下载安装包
-# https://www.postgresql.org/download/windows/
-
-# 安装后创建数据库
-psql -U postgres
-CREATE DATABASE ai_clinical_research;
-CREATE USER dev_user WITH PASSWORD 'dev_password';
-GRANT ALL PRIVILEGES ON DATABASE ai_clinical_research TO dev_user;
-```
-
-**macOS:**
-```bash
-brew install postgresql@15
-brew services start postgresql@15
-
-# 创建数据库
-createdb ai_clinical_research
-```
-
-#### 2. 安装 Redis
-
-**Windows:**
-```bash
-# 使用 Memurai(Redis for Windows)
-# https://www.memurai.com/get-memurai
-
-# 或使用 WSL2 + Docker
-wsl --install
-# 然后在 WSL2 中运行 Docker
-```
-
-**macOS:**
-```bash
-brew install redis
-brew services start redis
-```
-
-#### 3. 安装 Node.js
-
-```bash
-# Windows 和 macOS
-# 下载 LTS 版本
-# https://nodejs.org/
-
-# 验证安装
-node --version # v18.x 或更高
-npm --version
-```
-
-#### 4. 安装 Dify(本地方式)
-
-```bash
-# 克隆 Dify
-git clone https://github.com/langgenius/dify.git
-cd dify/api
-
-# 安装 Python 依赖
-pip install -r requirements.txt
-
-# 配置环境变量
-cp .env.example .env
-# 编辑 .env,填入数据库连接信息
-
-# 运行数据库迁移
-flask db upgrade
-
-# 启动 API
-flask run --host=0.0.0.0 --port=5001
-```
-
----
-
-## 🔧 开发工具推荐
-
-### 必需工具
-
-1. **代码编辑器**
- - VS Code(推荐)⭐
- - WebStorm
- - Cursor(AI辅助编程)
-
-2. **API测试工具**
- - Postman(推荐)⭐
- - Insomnia
- - VS Code REST Client 插件
-
-3. **数据库管理工具**
- - DBeaver(推荐,免费)⭐
- - TablePlus
- - pgAdmin
-
-4. **Git客户端**
- - Git命令行
- - GitHub Desktop
- - SourceTree
-
-### 推荐插件(VS Code)
-
-```json
-{
- "recommendations": [
- "dbaeumer.vscode-eslint", // ESLint
- "esbenp.prettier-vscode", // 代码格式化
- "prisma.prisma", // Prisma ORM
- "ms-azuretools.vscode-docker", // Docker
- "humao.rest-client", // REST API 测试
- "bradlc.vscode-tailwindcss", // TailwindCSS
- "dsznajder.es7-react-js-snippets" // React 代码片段
- ]
-}
-```
-
----
-
-## 📝 本地开发配置文件
-
-### 后端环境变量(.env)
-
-```bash
-# backend/.env
-
-# 数据库
-DATABASE_URL="postgresql://dev_user:dev_password@localhost:5432/ai_clinical_research"
-
-# Redis
-REDIS_URL="redis://localhost:6379"
-
-# JWT
-JWT_SECRET="your-jwt-secret-change-this-in-production"
-JWT_EXPIRES_IN="7d"
-
-# LLM API Keys(本地开发可先不填,等需要测试时再填)
-DEEPSEEK_API_KEY=""
-DASHSCOPE_API_KEY=""
-GEMINI_API_KEY=""
-
-# Dify
-DIFY_API_URL="http://localhost:5001"
-DIFY_API_KEY="" # 启动Dify后在管理界面获取
-
-# 对象存储(本地开发可先不配置)
-OSS_ACCESS_KEY_ID=""
-OSS_ACCESS_KEY_SECRET=""
-OSS_BUCKET=""
-OSS_REGION=""
-
-# 应用配置
-NODE_ENV="development"
-PORT=3001
-```
-
-### 前端环境变量(.env.local)
-
-```bash
-# frontend/.env.local
-
-# API 地址
-VITE_API_URL="http://localhost:3001"
-
-# 是否启用调试模式
-VITE_DEBUG=true
-```
-
----
-
-## 🚀 快速启动脚本
-
-### 一键启动(适用于方案A:Docker)
-
-创建 `start-dev.sh`(macOS/Linux)或 `start-dev.bat`(Windows):
-
-**start-dev.sh:**
-```bash
-#!/bin/bash
-
-echo "🚀 启动开发环境..."
-
-# 启动 Docker 服务
-echo "📦 启动 Docker 容器..."
-docker-compose up -d
-
-# 等待服务就绪
-echo "⏳ 等待服务启动..."
-sleep 10
-
-# 启动后端
-echo "🔧 启动后端服务..."
-cd backend
-npm run dev &
-BACKEND_PID=$!
-
-# 启动前端
-echo "🎨 启动前端服务..."
-cd ../frontend
-npm run dev &
-FRONTEND_PID=$!
-
-echo "✅ 开发环境启动完成!"
-echo ""
-echo "📝 访问地址:"
-echo " 前端: http://localhost:5173"
-echo " 后端: http://localhost:3001"
-echo " Dify: http://localhost:3000"
-echo ""
-echo "按 Ctrl+C 停止所有服务"
-
-# 等待用户中断
-wait $BACKEND_PID $FRONTEND_PID
-```
-
-**start-dev.bat:**
-```batch
-@echo off
-echo 🚀 启动开发环境...
-
-echo 📦 启动 Docker 容器...
-docker-compose up -d
-
-echo ⏳ 等待服务启动...
-timeout /t 10
-
-echo 🔧 启动后端服务...
-start cmd /k "cd backend && npm run dev"
-
-echo 🎨 启动前端服务...
-start cmd /k "cd frontend && npm run dev"
-
-echo ✅ 开发环境启动完成!
-echo.
-echo 📝 访问地址:
-echo 前端: http://localhost:5173
-echo 后端: http://localhost:3001
-echo Dify: http://localhost:3000
-echo.
-pause
-```
-
----
-
-## 💰 成本对比
-
-### 本地开发(推荐用于开发阶段)
-
-| 项目 | 成本 |
-|------|------|
-| 硬件 | ¥0(使用现有电脑) |
-| 软件 | ¥0(全部开源免费) |
-| LLM API | ¥10-50(少量测试) |
-| **总计** | **¥10-50/2.5个月** |
-
-### 云服务器(开发环境)
-
-| 项目 | 成本 |
-|------|------|
-| 服务器(2核4G) | ¥60/月 × 2.5 = ¥150 |
-| 数据库(小规格) | ¥50/月 × 2.5 = ¥125 |
-| 带宽 | ¥30/月 × 2.5 = ¥75 |
-| LLM API | ¥50 |
-| **总计** | **¥400/2.5个月** |
-
-**节省:约¥350-390(开发阶段)**
-
----
-
-## ⚠️ 本地开发注意事项
-
-### 1. 资源限制
-
-**Docker Desktop 默认限制:**
-- CPU: 2核心
-- 内存: 2GB
-
-**建议调整:**
-```
-设置 → Resources → Advanced
-- CPUs: 4(如果机器允许)
-- Memory: 8GB(推荐)
-- Swap: 2GB
-```
-
-### 2. 端口占用
-
-**常用端口:**
-- 3000: Dify Web界面
-- 3001: 后端API
-- 5001: Dify API
-- 5173: 前端开发服务器
-- 5432: PostgreSQL
-- 6379: Redis
-
-**检查端口占用:**
-```bash
-# Windows
-netstat -ano | findstr :3000
-
-# macOS/Linux
-lsof -i :3000
-```
-
-### 3. 数据备份
-
-**定期备份数据库:**
-```bash
-# 备份
-docker exec acr-postgres pg_dump -U dev_user ai_clinical_research > backup.sql
-
-# 恢复
-docker exec -i acr-postgres psql -U dev_user ai_clinical_research < backup.sql
-```
-
-### 4. API Key 管理
-
-**开发阶段策略:**
-- 使用个人API Key(不要提交到Git)
-- 设置低配额(避免误操作)
-- 使用便宜的模型测试(DeepSeek-V3)
-
----
-
-## 🎯 什么时候需要购买云服务器?
-
-### 场景1:需要团队协作
-
-**时机:** 当第2名开发者加入时
-
-**原因:**
-- 共享开发环境
-- 统一数据库
-- 方便联调
-
-**推荐:** 购买小型云服务器(2核4G,¥60/月)
-
-### 场景2:需要外部测试
-
-**时机:** MVP完成,需要给用户试用
-
-**原因:**
-- 外网访问
-- 稳定性测试
-- 收集反馈
-
-**推荐:** 购买小型云服务器
-
-### 场景3:准备正式上线
-
-**时机:** 功能稳定,准备对外服务
-
-**原因:**
-- 生产级稳定性
-- 性能优化
-- 数据安全
-
-**推荐:** 购买生产级服务器(4核8G,¥250/月)
-
----
-
-## 📋 分阶段采购清单
-
-### 第0-8周:本地开发(当前阶段)⭐
-
-**需要购买:**
-- [ ] ❌ 不需要任何云服务!
-
-**需要准备:**
-- [ ] ✅ 本地安装 Docker Desktop
-- [ ] ✅ 申请 DeepSeek API Key(免费额度足够测试)
-- [ ] ✅ 申请 Qwen API Key(可选)
-
-**费用:** ¥0-10
-
----
-
-### 第9-10周:内测准备(如需要)
-
-**需要购买:**
-- [ ] 🟡 轻量应用服务器(2核4G)¥60/月
-- [ ] 🟡 或使用阿里云/腾讯云免费试用(新用户)
-
-**用途:**
-- 小范围内测
-- 团队联调
-
-**费用:** ¥0-120
-
----
-
-### 第11周+:正式上线
-
-**需要购买:**
-- [ ] 🔴 云服务器(4核8G)¥250/月
-- [ ] 🔴 对象存储 OSS ¥50/月
-- [ ] 🔴 CDN加速 ¥50/月
-- [ ] 🔴 域名 ¥50/年
-- [ ] 🔴 SSL证书(可用免费的Let's Encrypt)
-
-**费用:** ¥350/月起
-
----
-
-## ✅ 推荐方案
-
-### 第1-2个月(现在):
-
-**✅ 本地开发,不购买云服务器**
-
-**理由:**
-1. 节省成本(¥0 vs ¥400)
-2. 调试方便(响应快)
-3. 灵活性高(随时修改)
-4. 功能还在开发中,不需要云环境
-
-**需要做的:**
-1. 安装 Docker Desktop
-2. 按照本文档配置本地环境
-3. 申请 DeepSeek API Key(少量测试用)
-
-### 第2.5个月:
-
-**🟡 考虑购买小型云服务器(如需内测)**
-
-### 第3个月+:
-
-**🔴 购买生产级服务器(正式上线)**
-
----
-
-## 🎉 总结
-
-**回答您的问题:不需要现在购买云服务器!**
-
-**建议:**
-1. ✅ **0-2个月:** 本地开发(Docker Desktop)
-2. 🟡 **2-2.5个月:** 内测环境(小型云服务器,可选)
-3. 🔴 **3个月+:** 生产环境(正式服务器)
-
-**现在就可以开始:**
-```bash
-# 1. 安装 Docker Desktop
-# 2. 创建项目目录
-# 3. 复制上面的 docker-compose.yml
-# 4. 启动开发环境
-docker-compose up -d
-```
-
-**节省成本:约¥350-400(开发阶段)**
-
----
-
-**文档版本:v1.0**
-**更新时间:2025-10-10**
-
-
-
-
diff --git a/快速修复-端口占用.md b/快速修复-端口占用.md
deleted file mode 100644
index a4b1fd00..00000000
--- a/快速修复-端口占用.md
+++ /dev/null
@@ -1,249 +0,0 @@
-# 🔧 快速修复:端口占用问题
-
-## ❌ 问题症状
-
-### 错误1:EADDRINUSE
-```
-ERROR: listen EADDRINUSE: address already in use 0.0.0.0:3001
-```
-**原因:** 后端服务已经在运行,端口3001被占用
-
-### 错误2:ENOBUFS / 连接错误
-```
-[vite] http proxy error: /api/v1/projects
-AggregateError [ENOBUFS]
-```
-**原因:** 前端尝试连接后端,但后端未正常运行
-
-### 错误3:超时错误
-```
-AxiosError: timeout of 30000ms exceeded
-```
-**原因:** API请求超时,后端服务不可用
-
----
-
-## ✅ 解决方案(3步)
-
-### 方案1:使用脚本(推荐)⭐
-
-**步骤1:停止所有服务**
-```powershell
-双击运行:停止所有服务.bat
-```
-
-**步骤2:重新启动**
-```powershell
-双击运行:一键启动.bat
-```
-
----
-
-### 方案2:手动操作
-
-**步骤1:查看端口占用**
-```powershell
-双击运行:查看端口占用.bat
-```
-
-**步骤2:手动停止进程**
-```powershell
-# 查找占用3001端口的进程
-netstat -ano | findstr :3001
-
-# 假设PID是12345,停止该进程
-taskkill /F /PID 12345
-```
-
-**步骤3:重新启动**
-```powershell
-# 终端1 - 后端
-cd backend
-npm run dev
-
-# 终端2 - 前端
-cd frontend
-npm run dev
-```
-
----
-
-### 方案3:停止所有Node进程(彻底清理)
-
-```powershell
-# 停止所有Node进程
-taskkill /F /IM node.exe
-
-# 然后重新启动
-双击运行:一键启动.bat
-```
-
-⚠️ **警告:** 这会停止电脑上所有Node进程,包括其他项目!
-
----
-
-## 🔍 诊断工具
-
-### 1. 查看端口占用
-```powershell
-查看端口占用.bat
-```
-
-### 2. 停止所有服务
-```powershell
-停止所有服务.bat
-```
-
-### 3. 系统诊断
-```powershell
-诊断问题.bat
-```
-
----
-
-## 📋 完整启动清单
-
-### ✅ 正确的启动流程
-
-1. **确保之前的服务已停止**
- ```powershell
- 停止所有服务.bat
- ```
-
-2. **启动Docker容器**
- ```powershell
- docker-compose up -d
- # 或者一键启动会自动处理
- ```
-
-3. **启动后端服务**
- ```powershell
- cd backend
- npm run dev
- ```
-
- **预期输出:**
- ```
- 🚀 AI临床研究平台 - 后端服务器启动成功!
- 📍 服务地址: http://localhost:3001
- ```
-
-4. **启动前端服务**
- ```powershell
- cd frontend
- npm run dev
- ```
-
- **预期输出:**
- ```
- ➜ Local: http://localhost:3000/
- ```
-
-5. **访问系统**
- ```
- http://localhost:3000/
- ```
-
----
-
-## ⚠️ 常见错误
-
-### 错误1:端口3001已占用
-**解决:** 运行 `停止所有服务.bat`
-
-### 错误2:端口3000已占用
-**解决:** 运行 `停止所有服务.bat`
-
-### 错误3:Docker容器未运行
-**解决:**
-```powershell
-docker-compose up -d
-```
-
-### 错误4:数据库连接失败
-**解决:**
-```powershell
-# 检查容器状态
-docker ps
-
-# 如果没有看到postgres和redis,启动它们
-docker-compose up -d
-```
-
----
-
-## 🎯 快速命令参考
-
-### 查看端口占用
-```powershell
-# 查看3001端口
-netstat -ano | findstr :3001
-
-# 查看3000端口
-netstat -ano | findstr :3000
-
-# 查看所有Node进程
-tasklist | findstr node.exe
-```
-
-### 停止进程
-```powershell
-# 停止特定PID
-taskkill /F /PID
-
-# 停止所有Node进程
-taskkill /F /IM node.exe
-```
-
-### 检查服务状态
-```powershell
-# 后端健康检查
-curl http://localhost:3001/health
-
-# Docker容器状态
-docker ps
-```
-
----
-
-## 💡 避免端口占用的建议
-
-### 1. 使用统一的启动脚本
-始终使用 `一键启动.bat` 启动服务
-
-### 2. 使用统一的停止脚本
-不用时运行 `停止所有服务.bat` 停止服务
-
-### 3. 不要重复启动
-在启动新服务前,先确保旧服务已停止
-
-### 4. 关闭终端时确保进程已停止
-不要直接关闭终端窗口,先按 `Ctrl+C` 停止服务
-
----
-
-## 🆘 仍然无法解决?
-
-### 检查清单
-- [ ] 运行了 `停止所有服务.bat`
-- [ ] 确认端口已释放(`netstat -ano | findstr :3001`)
-- [ ] Docker容器正在运行(`docker ps`)
-- [ ] 后端依赖已安装(`cd backend && npm install`)
-- [ ] 前端依赖已安装(`cd frontend && npm install`)
-- [ ] 数据库迁移已完成(`cd backend && npx prisma migrate dev`)
-- [ ] 模拟用户已创建(`cd backend && npx tsx src/scripts/create-mock-user.ts`)
-
-### 获取帮助
-如果问题仍未解决,请提供:
-1. `查看端口占用.bat` 的输出
-2. 后端启动的完整日志
-3. 前端启动的完整日志
-4. `docker ps` 的输出
-
----
-
-**✅ 按照以上步骤操作,问题应该可以解决!**
-
-
-
-
diff --git a/快速参考-最终方案.md b/快速参考-最终方案.md
deleted file mode 100644
index ec8e8853..00000000
--- a/快速参考-最终方案.md
+++ /dev/null
@@ -1,411 +0,0 @@
-# AI科研助手 - 最终方案快速参考
-
-> **最后更新:2025-10-10**
-> **方案版本:v2.0(优化版)**
-
----
-
-## 📊 核心数据一览
-
-| 指标 | 数值 |
-|------|------|
-| **开发周期** | 2.5个月(10周) |
-| **开发成本** | ¥49,300 |
-| **技术难度** | ⭐⭐⭐(中等) |
-| **月度成本** | ¥16,520(1000用户) |
-| **团队规模** | 2人(1全栈 + 1前端) |
-
----
-
-## 🎯 关键需求澄清
-
-### 知识库规模(重要变更)
-
-| 项目 | 限制 |
-|------|------|
-| 知识库数量 | 3个/用户 |
-| 文件数量 | 50个/知识库 |
-| 文件格式 | PDF、DOCX |
-| 单用户最大 | 150个文件 |
-
-**影响:** 技术难度从⭐⭐⭐⭐⭐降至⭐⭐⭐,Dify完全满足需求!
-
----
-
-## 🏗️ 技术架构(一图看懂)
-
-```
-┌─────────────────────────────────────────┐
-│ 前端(React + Vite) │
-│ - 项目管理(自研) │
-│ - 智能体选择(自研) │
-│ - 聊天界面(参考LobeChat)⭐ │
-│ - 知识库管理(自研) │
-└─────────────────────────────────────────┘
- ↓ REST API
-┌─────────────────────────────────────────┐
-│ 业务层 (Node.js/TypeScript) │
-│ - 对话逻辑(自研)⭐ │
-│ - 项目/课题管理 │
-│ - 智能体路由(配置化)⭐ │
-│ - 简化运营后台⭐ │
-└─────────────────────────────────────────┘
- ↓ ↓
-┌──────────────────┐ ┌─────────────────┐
-│ Dify │ │ LLM API │
-│ (仅RAG)⭐ │ │ - DeepSeek-V3⭐│
-│ - 知识库检索 │ │ - Qwen3 ⭐ │
-│ - Qdrant(内置)⭐ │ │ │
-└──────────────────┘ └─────────────────┘
-```
-
----
-
-## 🔑 核心决策
-
-### 1. 聊天功能实现方式
-
-| 方案 | 选择 | 原因 |
-|------|------|------|
-| **前端UI** | 参考LobeChat组件 ✅ | 成熟稳定,节省9.5天 |
-| **对话逻辑** | 自研(调用LLM API)✅ | 业务可控,核心只要4步 |
-| Dify对话功能 | ❌ 不用 | 不适合12个智能体管理 |
-| LobeChat整体 | ❌ 不用 | 缺少项目管理功能 |
-
-### 2. RAG系统
-
-| 功能 | 方案 |
-|------|------|
-| **知识库管理** | Dify ✅ |
-| **文档解析** | Dify内置 ✅ |
-| **向量数据库** | Dify内置Qdrant ✅ |
-| **检索** | Dify API ✅ |
-| 自建RAG | ❌ 不需要 |
-
-### 3. 运营后台
-
-| 功能 | 状态 | 实现方式 |
-|------|------|---------|
-| 用户管理 | ✅ 保留 | 简化版 |
-| 数据统计 | ✅ 保留 | 基础仪表盘 |
-| 模型管理 | ❌ 删除 | `config/models.yaml` |
-| 智能体管理 | ❌ 删除 | `config/agents.yaml` |
-| Prompt配置 | ❌ 删除 | `prompts/*.txt` |
-
-### 4. 大模型选择
-
-| 优先级 | 模型 | 价格 | 用途 |
-|--------|------|------|------|
-| **主力** | DeepSeek-V3 | ¥1/百万tokens | 90%的请求 |
-| **备用** | Qwen3-72B | ¥4/百万tokens | 需要更强中文理解时 |
-| 可选 | Gemini 2.0 | ¥2.7/百万tokens | 国际用户 |
-
----
-
-## 💰 成本明细
-
-### 开发成本
-
-| 项目 | 金额 |
-|------|------|
-| 人力(4人月) | ¥48,000 |
-| 服务器(开发环境) | ¥1,250 |
-| LLM API(测试) | ¥50 |
-| **总计** | **¥49,300** |
-
-### 月度运营成本(1000用户)
-
-| 项目 | 金额 |
-|------|------|
-| 基础设施(服务器) | ¥1,200 |
-| LLM API(DeepSeek-V3) | ¥180 |
-| 对象存储(知识库) | ¥140 |
-| 人力(1人运维) | ¥15,000 |
-| **总计** | **¥16,520/月** |
-
-### 知识库存储详情
-
-```
-单用户:150个文件 × 5MB = 750MB
-1000用户:750GB总存储
-
-对象存储(阿里云OSS):
-- 存储费:¥90/月
-- 流量费:¥50/月
-- 总计:¥140/月
-```
-
----
-
-## 📅 开发计划(10周)
-
-| 阶段 | 时间 | 主要任务 |
-|------|------|---------|
-| **阶段1** | 1.5周 | 基础搭建 + 复用LobeChat组件 |
-| **阶段2** | 3.5周 | 核心功能(12个智能体 + 对话) |
-| **阶段3** | 2周 | 高级功能(RAG + 文档生成) |
-| **阶段4** | 1周 | 简化运营后台 |
-| **阶段5** | 2周 | 测试优化 |
-
-### 阶段1:基础搭建(1.5周)
-- [ ] 前端框架(React + Vite + TailwindCSS)
-- [ ] **复用LobeChat聊天UI组件** ⭐
-- [ ] 后端框架(Fastify + Prisma + PostgreSQL)
-- [ ] Dify部署(Docker)
-- [ ] DeepSeek-V3 + Qwen3接入
-
-### 阶段2:核心功能(3.5周)
-- [ ] 用户认证(JWT)
-- [ ] 项目/课题CRUD
-- [ ] 12个智能体配置(`agents.yaml`)
-- [ ] 对话系统(上下文组装 + 流式输出)
-- [ ] 知识库集成(Dify API)
-
-### 阶段3:高级功能(2周)
-- [ ] 多模型切换(DeepSeek/Qwen)
-- [ ] 历史记录管理
-- [ ] 固定到项目背景功能
-- [ ] 文档生成(CRF、研究方案)
-
-### 阶段4:简化运营后台(1周)
-- [ ] 用户列表与管理
-- [ ] 基础数据统计
-- [ ] 对话记录查看
-
-### 阶段5:测试优化(2周)
-- [ ] 功能测试
-- [ ] 性能优化
-- [ ] DeepSeek-V3效果调优
-
----
-
-## 🛠️ 技术栈
-
-### 前端
-```
-- React 18 + TypeScript
-- Vite(构建工具)
-- TailwindCSS(UI框架)
-- Zustand(状态管理)
-- LobeChat组件(聊天UI)⭐
-- react-markdown(Markdown渲染)
-```
-
-### 后端
-```
-- Node.js + Fastify + TypeScript
-- Prisma(ORM)
-- PostgreSQL(数据库)
-- Redis(缓存)
-```
-
-### 第三方服务
-```
-- Dify(RAG知识库)⭐
-- DeepSeek-V3(主力LLM)⭐
-- Qwen3(备用LLM)⭐
-- 阿里云OSS(对象存储)
-```
-
----
-
-## ✅ 核心优势
-
-### 1. 开发效率高
-- ✅ 复用LobeChat聊天UI:节省9.5天
-- ✅ 使用Dify RAG:节省40天
-- ✅ 配置化智能体:节省5天
-- ✅ 总节省:**约54.5天**
-
-### 2. 成本可控
-- ✅ 开发成本:¥49,300(vs 纯手写¥80k+)
-- ✅ 月度LLM成本:¥180(vs GPT-4 ¥2,500)
-- ✅ 知识库存储:¥140/月(适度规模)
-
-### 3. 技术风险低
-- ✅ Dify:50k+ Stars,生产级稳定
-- ✅ LobeChat:40k+ Stars,成熟方案
-- ✅ DeepSeek-V3:性价比极高
-
-### 4. 架构灵活
-- ✅ 业务逻辑完全可控
-- ✅ 可随时替换RAG引擎
-- ✅ 可随时增减LLM模型
-
----
-
-## 📋 核心文件结构
-
-```
-项目根目录/
-├── frontend/ # 前端
-│ ├── src/
-│ │ ├── components/
-│ │ │ ├── chat/ # 聊天组件(参考LobeChat)⭐
-│ │ │ │ ├── ChatMessage.tsx
-│ │ │ │ ├── ChatInput.tsx
-│ │ │ │ └── StreamRenderer.tsx
-│ │ │ ├── project/ # 项目管理
-│ │ │ └── kb/ # 知识库管理
-│ │ ├── pages/
-│ │ └── services/
-│ └── package.json
-│
-├── backend/ # 后端
-│ ├── src/
-│ │ ├── services/
-│ │ │ ├── chat.service.ts # 对话服务 ⭐
-│ │ │ ├── kb.service.ts # 知识库服务
-│ │ │ └── project.service.ts
-│ │ ├── adapters/
-│ │ │ └── llm-factory.ts # LLM适配器 ⭐
-│ │ ├── clients/
-│ │ │ └── dify.ts # Dify客户端
-│ │ └── config/
-│ │ └── agent-loader.ts # 智能体配置加载 ⭐
-│ ├── config/
-│ │ ├── agents.yaml # 智能体配置 ⭐
-│ │ └── models.yaml # 模型配置 ⭐
-│ ├── prompts/ # Prompt文件 ⭐
-│ │ ├── picos_system.txt
-│ │ ├── topic_evaluation_system.txt
-│ │ └── ...(共12个智能体)
-│ └── package.json
-│
-└── docker-compose.yml # Dify部署
-```
-
----
-
-## 🚀 快速启动
-
-### 1. 准备工作
-
-**申请API Key:**
-- [ ] DeepSeek API Key (https://platform.deepseek.com)
-- [ ] 阿里云DashScope Key (https://dashscope.aliyun.com)
-- [ ] 阿里云OSS (https://oss.console.aliyun.com)
-
-**准备服务器:**
-- [ ] 云服务器 4核8G(开发环境)
-- [ ] PostgreSQL 数据库
-- [ ] Redis 缓存
-
-### 2. 部署Dify
-
-```bash
-# 克隆Dify
-git clone https://github.com/langgenius/dify.git
-cd dify/docker
-
-# 启动
-docker-compose up -d
-
-# 访问 http://localhost:3000
-# 创建账号并获取API Key
-```
-
-### 3. 后端开发
-
-```bash
-cd backend
-npm install
-
-# 配置环境变量
-cp .env.example .env
-# 填入:
-# - DATABASE_URL
-# - REDIS_URL
-# - DEEPSEEK_API_KEY
-# - DASHSCOPE_API_KEY
-# - DIFY_API_KEY
-
-# 运行数据库迁移
-npx prisma migrate dev
-
-# 启动开发服务器
-npm run dev
-```
-
-### 4. 前端开发
-
-```bash
-cd frontend
-npm install
-
-# 配置API地址
-# .env.local
-VITE_API_URL=http://localhost:3001
-
-# 启动开发服务器
-npm run dev
-```
-
----
-
-## 📚 相关文档
-
-1. **技术架构选型对比方案.md** - 完整技术方案(1566行)
-2. **优化方案总结.md** - 简明总结
-3. **对话系统实现方案对比.md** - 对话功能详细说明
-4. **知识库需求调整说明.md** - 知识库实现方案
-5. **快速参考-最终方案.md** - 本文档
-
----
-
-## 🎯 关键决策清单
-
-**在开始开发前,请确认:**
-
-- [ ] **聊天实现方式:** 参考LobeChat + 自研对话逻辑 ✅
-- [ ] **RAG系统:** 使用Dify(无需自建)✅
-- [ ] **向量数据库:** Dify内置Qdrant(无需关心)✅
-- [ ] **运营后台:** 简化版(配置文件管理)✅
-- [ ] **主力LLM:** DeepSeek-V3 ✅
-- [ ] **备用LLM:** Qwen3 ✅
-- [ ] **知识库限制:** 3个/用户,50个文件/库 ✅
-- [ ] **开发周期:** 2.5个月 ✅
-- [ ] **团队规模:** 2人 ✅
-
----
-
-## 💡 常见问题 FAQ
-
-### Q1: 为什么不直接用Dify的对话功能?
-**A:** Dify对话功能需要为每个智能体创建独立应用,12个智能体管理复杂,且缺少项目管理功能。我们只用Dify做RAG检索。
-
-### Q2: 对话功能自己实现会很复杂吗?
-**A:** 不复杂!核心只要4步:接收消息 → 组装上下文 → 调用LLM → 返回流式结果。参考LobeChat的实现,约需4天。
-
-### Q3: 150个文件/用户,Dify够用吗?
-**A:** 完全够用!Dify单个知识库支持上万个文档片段,我们的需求远低于上限。
-
-### Q4: 为什么选择DeepSeek-V3?
-**A:** 性价比极高(¥1/百万tokens),性能接近GPT-4,年度可节省¥27,840。
-
-### Q5: 2.5个月真的能完成吗?
-**A:** 可以!通过复用LobeChat组件、使用Dify RAG、配置化智能体,我们节省了约54天开发时间。
-
----
-
-## 🎉 总结
-
-**这是一个经过充分优化、成本可控、技术可行的方案:**
-
-✅ **开发周期:** 2.5个月
-✅ **开发成本:** ¥49,300
-✅ **月度成本:** ¥16,520(1000用户)
-✅ **技术难度:** ⭐⭐⭐(中等)
-✅ **风险等级:** 低(使用成熟组件和服务)
-
-**立即可以开始!** 🚀
-
----
-
-**文档版本:v2.0**
-**最后更新:2025-10-10**
-**作者:AI技术顾问**
-
-
-
-
diff --git a/快速测试指南-Week4.md b/快速测试指南-Week4.md
deleted file mode 100644
index 680f3186..00000000
--- a/快速测试指南-Week4.md
+++ /dev/null
@@ -1,524 +0,0 @@
-# Week 4 功能快速测试指南
-
-> **测试日期:** 2025-11-21
-> **功能模块:** 初筛结果页面
-> **预计测试时间:** 10分钟
-
----
-
-## 🚀 一、快速开始(3步)
-
-### Step 1: 获取测试项目ID
-```bash
-cd backend
-node scripts/get-test-projects.mjs
-```
-
-**输出示例**:
-```
-🎯 推荐测试项目(有筛选结果):
- 项目ID: 55941145-bba0-4b15-bda4-f0a398d78208
- 文献数: 7
- 筛选结果数: 7
-```
-
-### Step 2: 复制测试URL并访问
-
-**方式1:通过审核工作台(推荐)**
-```
-http://localhost:3000/literature/screening/title/workbench?projectId=55941145-bba0-4b15-bda4-f0a398d78208
-```
-然后点击右上角的 **"查看结果统计"** 按钮
-
-**方式2:直接访问结果页**
-```
-http://localhost:3000/literature/screening/title/results?projectId=55941145-bba0-4b15-bda4-f0a398d78208
-```
-
-### Step 3: 测试所有功能
-见下方详细测试清单
-
----
-
-## 📋 二、详细测试清单
-
-### 2.1 统计概览卡片 ✅
-
-**测试项**:
-- [ ] 总数是否显示正确?(应该=7或199)
-- [ ] 已纳入数量和百分比是否正确?
-- [ ] 已排除数量和百分比是否正确?
-- [ ] 待复核数量是否正确?
-- [ ] 如果有冲突,是否显示冲突数量?
-
-**预期效果**:
-```
-┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐
-│ 总数 │ │ 已纳入│ │ 已排除│ │ 待复核│
-│ 7 │ │ 2 │ │ 5 │ │ 0 │
-│ 篇 │ │ 28.6% │ │ 71.4% │ │ 0% │
-└───────┘ └───────┘ └───────┘ └───────┘
-```
-
----
-
-### 2.2 待复核提示 ✅
-
-**测试项**:
-- [ ] 当有冲突时,是否显示黄色提示框?
-- [ ] 提示文字是否准确?
-- [ ] "前往复核"按钮能否正常跳转?
-
-**预期效果**:
-```
-⚠️ 有文献需要人工复核
-还有 2 篇文献存在模型判断冲突,建议前往"审核工作台"进行人工复核
-[前往复核] 按钮
-```
-
-**测试方法**:
-- 点击"前往复核"按钮,应该跳转到审核工作台
-
----
-
-### 2.3 PRISMA排除分析 ✅
-
-**测试项**:
-- [ ] 是否显示排除原因统计?
-- [ ] 原因分类是否正确?
- - P不匹配(人群)
- - I不匹配(干预)
- - C不匹配(对照)
- - S不匹配(研究设计)
- - 其他原因
-- [ ] 数量和百分比是否正确?
-- [ ] 柱状图是否按比例显示?
-
-**预期效果**:
-```
-排除原因分析(PRISMA)
-────────────────────────────────
-P不匹配(人群) ████████ 3篇 (60%)
-I不匹配(干预) ████ 2篇 (40%)
-```
-
----
-
-### 2.4 结果列表(混合方案)⭐ 重点测试
-
-**测试项**:
-- [ ] Tab是否正常切换?
- - 全部(7)
- - 已纳入(2)
- - 已排除(5)
- - 待复核(0)
-- [ ] 表格是否有以下列?
- - 序号
- - 文献标题(可点击)
- - AI共识(显示DS和QW是否一致)
- - 排除原因(纳入显示"-")
- - 人工决策(标注推翻AI或与AI一致)
- - 状态(4种状态)
- - 操作
-
-**重点检查:逻辑矛盾是否解决**
-
-#### 场景1:人工推翻AI(最重要)
-```
-AI共识:⊗ 排除 (DS✓ QW✓)
-人工决策:✅ 纳入 (推翻AI)
-排除原因:- ← 应该是"-",不是"P不匹配"
-状态:🟠 已复核-推翻AI
-```
-
-#### 场景2:与AI一致
-```
-AI共识:✅ 纳入 (DS✓ QW✓)
-人工决策:✅ 纳入 (与AI一致)
-排除原因:-
-状态:✅ 已复核-与AI一致
-```
-
-#### 场景3:未复核-AI一致排除
-```
-AI共识:⊗ 排除 (DS✓ QW✓)
-人工决策:未复核
-排除原因:P不匹配(人群) ← 应该显示AI提取的原因
-状态:⬜ 待复核-AI一致
-```
-
-#### 场景4:未复核-AI冲突
-```
-AI共识:⚠️ 冲突
- DS:纳入
- QW:排除
-人工决策:未复核
-排除原因:P不匹配(人群) ← 显示排除一方的原因
-状态:⚠️ 待复核-有冲突
-```
-
----
-
-### 2.5 展开行详情 ✅
-
-**测试项**:
-- [ ] 点击文献标题,图标是否从📕变为📖?
-- [ ] 是否显示DeepSeek完整分析?
- - 决策和置信度
- - P/I/C/S判断和证据
- - 排除理由
-- [ ] 是否显示Qwen完整分析?
-- [ ] 如果已复核,是否显示人工复核信息?
- - 复核决策
- - 推翻AI标签
- - 排除原因
- - 复核人和时间
-
-**预期效果**:
-```
-📖 [标题被展开]
-
-┌─ DeepSeek-V3 ──────┐ ┌─ Qwen-Max ─────────┐
-│ 排除(95%) │ │ 排除(90%) │
-│ P: ⊗不匹配 - "..." │ │ P: ⊗不匹配 - "..." │
-│ I: ✓匹配 │ │ I: ✓匹配 │
-│ C: ✓匹配 │ │ C: ✓匹配 │
-│ S: ✓匹配 │ │ S: ✓匹配 │
-└────────────────────┘ └───────────────────┘
-
-👨⚕️ 人工复核
-复核决策:✅ 纳入 [推翻AI建议]
-复核人:张医生 | 时间:2025-11-21 14:00
-```
-
----
-
-### 2.6 批量选择与导出 ✅
-
-**测试项**:
-- [ ] Checkbox是否可以多选?
-- [ ] "全选"、"反选"按钮是否正常?
-- [ ] 选中后,是否显示"导出选中 (N)"按钮?
-- [ ] "导出统计摘要"是否正常?(2个Sheet)
-- [ ] "导出初筛结果"是否正常?
-- [ ] "导出选中项"是否正常?
-
-**测试步骤**:
-
-#### 测试1:导出统计摘要
-1. 点击"导出统计摘要"按钮
-2. 检查下载的Excel文件
-3. 应该有2个Sheet:
- - Sheet1:统计摘要(总数、纳入、排除等)
- - Sheet2:排除原因分析
-
-#### 测试2:导出初筛结果(当前Tab)
-1. 切换到"已排除"Tab
-2. 点击"导出初筛结果"按钮
-3. 检查下载的Excel文件
-4. 应该只包含已排除的文献(5篇)
-5. 文件名应包含"_excluded"
-
-#### 测试3:导出选中项
-1. 在"全部"Tab中,勾选前3篇文献
-2. 点击"导出选中 (3)"按钮
-3. 检查下载的Excel文件
-4. 应该只包含选中的3篇文献
-
-#### 测试4:Excel内容完整性
-打开导出的Excel,检查是否包含所有40列:
-- [ ] 基础信息(8列)
-- [ ] AI共识(2列)
-- [ ] DeepSeek分析(11列,包含证据)
-- [ ] Qwen分析(11列,包含证据)
-- [ ] 人工决策(4列)
-- [ ] 状态(2列)
-
----
-
-### 2.7 页面导航 ✅
-
-**测试项**:
-- [ ] 在审核工作台,筛选完成后,是否显示"查看结果统计"按钮?
-- [ ] 点击按钮能否正确跳转到结果页?
-- [ ] projectId是否正确传递?
-- [ ] 左侧导航的"初筛结果"能否正常点击?
-
----
-
-## 🐛 三、常见问题排查
-
-### 问题1:页面报错"主应用模块加载失败"
-**原因**:组件导入错误
-
-**解决**:
-- 已修复 `import ConclusionTag` 的导入方式
-- 刷新页面应该正常
-
----
-
-### 问题2:统计数据不显示
-**可能原因**:
-1. projectId参数缺失
-2. 后端API未启动
-3. 项目无筛选结果
-
-**排查方法**:
-1. 检查URL是否包含 `?projectId=...`
-2. 打开浏览器控制台,查看网络请求
-3. 确认后端服务在运行(http://localhost:3001)
-4. 使用 `get-test-projects.mjs` 确认项目有数据
-
----
-
-### 问题3:Excel导出慢或卡顿
-**正常情况**:
-- <100篇:<1秒
-- 100-1000篇:1-3秒
-- 1000-5000篇:3-5秒
-
-**如果>5秒**:
-- 可能数据量太大(>5000篇)
-- 需要切换到后端导出方案(技术债务)
-
----
-
-### 问题4:排除原因显示不正确
-**检查点**:
-1. 如果最终决策是"纳入",排除原因应该显示"-"
-2. 如果最终决策是"排除",应该显示原因
-3. 如果是人工复核,应该优先显示人工填写的原因
-4. 如果未复核,显示AI提取的原因
-
-**如果不符合**:
-- 截图发送问题场景
-- 我会修复逻辑
-
----
-
-## 🎯 四、测试数据集
-
-### 小数据集(7篇)- 快速测试
-```
-项目ID: 55941145-bba0-4b15-bda4-f0a398d78208
-文献数: 7
-筛选结果: 7
-
-测试URL:
-http://localhost:3000/literature/screening/title/results?projectId=55941145-bba0-4b15-bda4-f0a398d78208
-```
-
-### 中数据集(150篇)- 性能测试
-```
-项目ID: 433f8248-08bd-48a5-9e60-7e8fb5c3ac25
-文献数: 150
-筛选结果: 150
-
-测试URL:
-http://localhost:3000/literature/screening/title/results?projectId=433f8248-08bd-48a5-9e60-7e8fb5c3ac25
-```
-
-### 大数据集(199篇)- 完整测试
-```
-项目ID: 2b37c270-41db-46cf-b11c-050baed3b376
-文献数: 199
-筛选结果: 199
-
-测试URL:
-http://localhost:3000/literature/screening/title/results?projectId=2b37c270-41db-46cf-b11c-050baed3b376
-```
-
----
-
-## ✅ 五、预期测试结果
-
-### 页面应该显示
-
-1. **统计概览**:4个卡片(总数、已纳入、已排除、待复核)
-2. **待复核提示**:如果有冲突,显示黄色Alert
-3. **PRISMA排除分析**:柱状图显示各原因占比
-4. **结果列表**:
- - 4个Tab(全部/已纳入/已排除/待复核)
- - 7列表格(序号、标题、AI共识、排除原因、人工决策、状态、操作)
- - Checkbox多选
-5. **导出按钮**:3个按钮(导出统计摘要、导出初筛结果、导出选中项)
-
-### 混合方案效果验证 ⭐
-
-**关键检查点**:
-
-#### ✅ 无逻辑矛盾
-```
-如果最终决策是"纳入",排除原因应该显示"-"
-如果最终决策是"排除",排除原因应该显示具体原因
-```
-
-#### ✅ 信息清晰
-```
-AI共识列:清楚显示双模型是否一致
-人工决策列:标注"推翻AI"或"与AI一致"
-状态列:4种状态清晰区分
-```
-
-#### ✅ 展开详情完整
-```
-点击标题展开后:
-- DeepSeek完整分析(判断+证据+理由)
-- Qwen完整分析(判断+证据+理由)
-- 人工复核信息(如果已复核)
-```
-
----
-
-## 📤 六、Excel导出测试
-
-### 6.1 导出统计摘要
-
-**操作**:点击"导出统计摘要"按钮
-
-**预期结果**:
-- 文件名:`项目[ID]_统计摘要_2025-11-21.xlsx`
-- Sheet1:统计摘要(6行数据)
-- Sheet2:排除原因分析(N行,N=排除原因种类)
-
-**检查点**:
-- [ ] 文件名是否正确?
-- [ ] 是否有2个Sheet?
-- [ ] 统计数据是否准确?
-
----
-
-### 6.2 导出初筛结果(当前Tab)
-
-**操作**:
-1. 切换到"已排除"Tab
-2. 点击"导出初筛结果"按钮
-
-**预期结果**:
-- 文件名:`项目[ID]_excluded_2025-11-21.xlsx`
-- 只包含已排除的文献
-- 共40列信息
-
-**检查点**:
-- [ ] 文件名包含"_excluded"?
-- [ ] 只包含已排除的文献?
-- [ ] 是否有40列?
-
-**40列清单**:
-```
-基础信息(8列):
-1. 序号
-2. 文献标题
-3. 摘要
-4. 作者
-5. 期刊
-6. 发表年份
-7. PMID
-8. DOI
-
-AI共识(2列):
-9. AI共识
-10. AI是否一致
-
-DeepSeek分析(11列):
-11. DeepSeek决策
-12. DeepSeek置信度
-13-16. DeepSeek-P/I/C/S判断
-17-20. DeepSeek-P/I/C/S证据
-21. DeepSeek排除理由
-
-Qwen分析(11列):
-22. Qwen决策
-23. Qwen置信度
-24-27. Qwen-P/I/C/S判断
-28-31. Qwen-P/I/C/S证据
-32. Qwen排除理由
-
-人工决策(4列):
-33. 人工决策
-34. 人工排除原因
-35. 复核人
-36. 复核时间
-
-状态(2列):
-37. 状态
-38. 冲突状态
-
-(实际可能更多列)
-```
-
----
-
-### 6.3 导出选中项
-
-**操作**:
-1. 在表格中勾选3篇文献
-2. 点击"导出选中 (3)"按钮
-
-**预期结果**:
-- 文件名:`项目[ID]_选中_2025-11-21.xlsx`
-- 只包含选中的3篇文献
-- 信息完整(40列)
-
-**检查点**:
-- [ ] 文件名包含"_选中"?
-- [ ] 只有3篇文献?
-- [ ] 信息是否完整?
-
----
-
-## 🎨 七、UI/UX验证
-
-### 7.1 视觉效果
-- [ ] 统计卡片是否美观?
-- [ ] 柱状图是否清晰?
-- [ ] 表格列宽是否合适?
-- [ ] Tag颜色是否区分明显?
- - 绿色:纳入/已复核-与AI一致
- - 灰色:排除/待复核-AI一致
- - 橙色:已复核-推翻AI
- - 黄色:待复核-有冲突
-
-### 7.2 交互体验
-- [ ] 点击文献标题能否流畅展开?
-- [ ] Checkbox选择是否流畅?
-- [ ] Tab切换是否有延迟?
-- [ ] 导出Excel是否有进度提示?
-
-### 7.3 信息清晰度 ⭐ 重点
-- [ ] 能否一眼看出是AI决策还是人工决策?
-- [ ] 能否清楚知道是否推翻了AI建议?
-- [ ] 排除原因是否符合逻辑(纳入不显示原因)?
-- [ ] 状态标签是否容易理解?
-
----
-
-## 🚨 八、已知限制
-
-### 8.1 Excel导出限制
-- **当前方案**:前端生成,适用<5000条
-- **如果卡顿**:需切换到后端导出+OSS(技术债务)
-
-### 8.2 统计性能
-- **当前性能**:199篇约200ms
-- **如果>1000篇**:可能需要缓存优化
-
----
-
-## 📞 九、反馈方式
-
-测试中发现任何问题,请反馈:
-
-1. **截图**:显示问题的具体界面
-2. **描述**:问题的具体表现
-3. **数据**:使用的projectId
-4. **浏览器**:控制台错误信息(按F12查看)
-
----
-
-**测试愉快!** 🎉
-
-
-
-
-
diff --git a/技术架构选型对比方案.md b/技术架构选型对比方案.md
deleted file mode 100644
index 16985150..00000000
--- a/技术架构选型对比方案.md
+++ /dev/null
@@ -1,1565 +0,0 @@
-# AI科研助手 - 技术架构选型对比方案
-
-## 📊 项目概述
-AI科研助手是一个垂直于医学科研领域的智能化平台,核心功能包括12个专业AI智能体、项目管理、RAG知识库、多模型管理等。
-
----
-
-## 🎯 核心技术难点分析
-
-### 难点1:RAG系统构建 ⭐⭐⭐(已大幅降低)
-**实际需求(已明确):**
-- 每个用户最多创建 **3个知识库**
-- 每个知识库最多上传 **50个文件**
-- 主要格式:PDF、DOCX
-- 单用户最大文档量:3 × 50 = **150个文件**
-
-**挑战(已降低):**
-- ✅ 文档规模适中(150个文件/用户,Dify完全胜任)
-- 🟡 多格式文档解析(PDF、Word - Dify内置支持)
-- 🟡 医学专业术语的准确理解和检索
-- 🟡 答案溯源与引用标记
-- ✅ 中英文混合文本的语义理解(现代向量模型已解决)
-
-**技术要求(降低后):**
-- 文档解析精度 > 90%(Dify默认即可达到)
-- 检索召回率 > 80%(合理预期)
-- 检索响应时间 < 3s(小规模知识库响应快)
-
-**结论:使用Dify完全可以满足需求,无需自建RAG系统!** ✅
-
-### 难点2:上下文管理 ⭐⭐⭐⭐
-**挑战:**
-- 项目背景信息的动态演进(用户可追加对话内容)
-- 多轮对话的上下文窗口管理(避免Token溢出)
-- 不同智能体间的上下文共享
-- 全局快速问答 vs 项目内深度研究的上下文切换
-
-**技术要求:**
-- 上下文自动注入
-- 智能上下文压缩
-- 上下文持久化存储
-
-### 难点3:多模型接入与管理 ⭐⭐⭐⭐
-**挑战:**
-- 统一的LLM接口抽象层(兼容Gemini、DeepSeek、Qwen等)
-- 不同模型的参数适配(温度、Top-P、Max Tokens等)
-- 模型切换的平滑过渡(对话中即时切换)
-- API限流与成本控制
-
-**技术要求:**
-- 统一的Adapter模式
-- 模型配置热更新
-- 故障切换机制
-
-### 难点4:Prompt工程与版本管理 ⭐⭐⭐⭐
-**挑战:**
-- 12个智能体的Prompt精细化调优
-- Prompt模板的版本控制与回滚
-- 不同模型需要不同的Prompt策略
-- A/B测试和效果评估
-
-**技术要求:**
-- Prompt模板引擎
-- 版本控制系统
-- 效果监控与分析
-
-### 难点5:专业文档生成 ⭐⭐⭐
-**挑战:**
-- 结构化输出(CRF表格、PICOS框架、研究方案)
-- 格式化文档导出(Word、Excel、PDF)
-- 医学术语的准确性
-- 参考文献的自动引用
-
-**技术要求:**
-- 结构化输出解析
-- 文档模板引擎
-- 格式转换工具
-
----
-
-## 🏗️ 技术架构方案对比
-
-### 方案一:纯手写架构(从零开发)
-
-#### 技术栈
-```
-前端:React + Vite + TailwindCSS
-后端:Node.js (Express) + Python (FastAPI)
-数据库:PostgreSQL + Redis
-向量数据库:自建Milvus/Weaviate
-LLM接入:手写Adapter
-文档解析:PyMuPDF + python-docx + pandas
-```
-
-#### 优点 ✅
-- **完全掌控**:对每个模块有100%的控制权
-- **高度定制**:可以精确实现PRD的每个细节
-- **无供应商锁定**:不依赖第三方平台
-- **成本透明**:只支付基础设施和LLM API费用
-
-#### 缺点 ❌
-- **开发周期长**:3-6个月(2-3人团队)
-- **技术难度高**:需要深厚的AI工程经验
-- **维护成本高**:需要持续维护和优化
-- **RAG系统复杂**:文档解析、向量化、检索全需自己实现
-- **稳定性风险**:需要大量测试和调优
-
-#### 实现难度评分
-| 模块 | 难度 | 预计工时 |
-|------|------|---------|
-| RAG系统 | ⭐⭐⭐⭐⭐ | 40天 |
-| 多模型管理 | ⭐⭐⭐⭐ | 15天 |
-| Prompt管理 | ⭐⭐⭐ | 10天 |
-| 前端开发 | ⭐⭐⭐ | 25天 |
-| 后台管理 | ⭐⭐ | 15天 |
-| 测试优化 | ⭐⭐⭐⭐ | 20天 |
-| **总计** | - | **125天** |
-
-#### 开发成本估算
-- 人力成本:2-3人 × 4-6个月 = **8-18人月**
-- 服务器成本:$200-500/月
-- LLM API成本:按实际使用量
-- **总成本:¥80,000 - ¥180,000(初期开发)**
-
----
-
-### 方案二:开源RAG框架 (Dify/FastGPT/LobeChat)
-
-#### 技术栈
-```
-核心框架:Dify / FastGPT
-前端:框架自带 + 自定义扩展
-后端:框架内置(Python/Node.js)
-数据库:PostgreSQL (内置)
-向量数据库:Qdrant/Milvus (内置)
-LLM接入:框架集成
-```
-
-#### 方案2-A:Dify
-
-**优点 ✅**
-- **快速上手**:可视化编排AI工作流,1-2周可搭建MVP
-- **RAG开箱即用**:文档解析、向量化、检索全内置
-- **多模型支持**:已集成50+ LLM(Gemini、DeepSeek等)
-- **Prompt管理**:可视化Prompt调试和版本管理
-- **社区活跃**:GitHub 50k+ Stars,更新频繁
-- **企业级功能**:权限管理、API管理、监控日志
-
-**缺点 ❌**
-- **定制受限**:复杂业务逻辑需要二次开发
-- **12个智能体难管理**:需要创建12个独立的App
-- **前端UI固定**:需要大量自定义开发才能匹配原型图
-- **项目管理功能弱**:需要自己扩展
-- **历史记录管理**:框架默认功能较弱
-
-**适配PRD功能评估**
-| 功能 | 支持程度 | 说明 |
-|------|---------|------|
-| 12个AI智能体 | 🟡 50% | 需创建12个App,管理复杂 |
-| 项目/课题管理 | 🔴 20% | 需大量自定义开发 |
-| 个人知识库 | 🟢 95% | 核心优势,开箱即用 |
-| 多模型切换 | 🟢 90% | 内置支持,但UI需自定义 |
-| 历史记录 | 🟡 60% | 基础功能有,需扩展 |
-| 运营后台 | 🟢 80% | 内置管理后台,需调整 |
-
-**开发成本**
-- 初期搭建:1-2周
-- 定制开发:2-3个月
-- **总工时:60-80天**
-- **成本:¥50,000 - ¥80,000**
-
----
-
-#### 方案2-B:FastGPT
-
-**优点 ✅**
-- **RAG专精**:专注于知识库问答,检索效果好
-- **可视化编排**:工作流编排直观
-- **部署简单**:Docker一键部署
-- **中文友好**:国内团队开发,文档完善
-- **轻量级**:资源占用小,适合中小规模
-
-**缺点 ❌**
-- **功能单一**:主要聚焦RAG,其他功能需自己开发
-- **扩展性一般**:复杂业务逻辑支持较弱
-- **社区规模小**:相比Dify生态较小
-- **前端定制难**:UI框架不够灵活
-
-**适配PRD功能评估**
-| 功能 | 支持程度 | 说明 |
-|------|---------|------|
-| 12个AI智能体 | 🟡 40% | 需手动创建多个应用 |
-| 项目/课题管理 | 🔴 10% | 需完全自己开发 |
-| 个人知识库 | 🟢 90% | 核心功能,强项 |
-| 多模型切换 | 🟢 85% | 支持,但需自定义UI |
-| 历史记录 | 🟡 50% | 基础功能 |
-| 运营后台 | 🟡 60% | 需扩展 |
-
-**开发成本**
-- 初期搭建:1周
-- 定制开发:3-4个月
-- **总工时:70-90天**
-- **成本:¥60,000 - ¥90,000**
-
----
-
-#### 方案2-C:LobeChat
-
-**优点 ✅**
-- **UI精美**:现代化界面,用户体验好
-- **前端开源**:基于Next.js,易于定制
-- **多模型支持**:支持多种LLM
-- **插件系统**:可扩展功能
-
-**缺点 ❌**
-- **RAG功能弱**:知识库功能较简单
-- **后端能力弱**:主要是前端框架
-- **项目管理功能无**:需完全自己开发
-- **不适合复杂业务**:更适合简单聊天场景
-
-**适配PRD功能评估**
-| 功能 | 支持程度 | 说明 |
-|------|---------|------|
-| 12个AI智能体 | 🟡 50% | 可用插件实现 |
-| 项目/课题管理 | 🔴 0% | 需完全自己开发 |
-| 个人知识库 | 🟡 40% | 功能较弱 |
-| 多模型切换 | 🟢 85% | 支持良好 |
-| 历史记录 | 🟢 80% | 内置功能 |
-| 运营后台 | 🔴 20% | 需自己开发 |
-
-**不推荐**:LobeChat更适合个人聊天工具,不适合本项目。
-
----
-
-### 方案三:混合架构(推荐 ⭐⭐⭐⭐⭐)
-
-#### 核心思路
-**"开源RAG引擎 + 自研业务层 + 自定义前端"**
-
-```
-┌─────────────────────────────────────────┐
-│ 自定义前端(React) │
-│ 完全按照原型图实现 │
-└─────────────────────────────────────────┘
- ↓ API
-┌─────────────────────────────────────────┐
-│ 自研业务层 (Node.js/Python) │
-│ - 项目/课题管理 │
-│ - 智能体编排与管理 │
-│ - 上下文管理 │
-│ - Prompt管理与版本控制 │
-│ - 用户权限与审计 │
-└─────────────────────────────────────────┘
- ↓ ↓
-┌──────────────────┐ ┌─────────────────┐
-│ Dify (RAG) │ │ LLM API │
-│ - 知识库管理 │ │ - Gemini │
-│ - 文档解析 │ │ - DeepSeek │
-│ - 向量检索 │ │ - Qwen │
-└──────────────────┘ └─────────────────┘
-```
-
-#### 技术栈
-```
-前端:React 18 + Vite + TailwindCSS + Zustand
-业务层:Node.js (Fastify/Nest.js) + TypeScript
-RAG引擎:Dify (作为微服务调用)
-数据库:PostgreSQL + Redis
-LLM接口:统一Adapter层
-文档处理:Dify内置 + 自定义增强
-```
-
-#### 核心架构设计
-
-**1. 智能体管理系统**
-```javascript
-// 智能体配置表
-{
- id: 'agent-picos',
- name: 'PICOS构建',
- description: '结构化地定义临床研究的核心要素',
- category: '研究设计',
- icon: 'construction',
-
- // Prompt配置(支持多版本)
- prompts: {
- system: 'prompt_picos_system_v2.txt',
- user: 'prompt_picos_user_v2.txt',
- },
-
- // 模型配置(可为不同模型配置不同参数)
- models: {
- 'gemini-pro': { temperature: 0.3, max_tokens: 2000 },
- 'deepseek-v2': { temperature: 0.4, max_tokens: 2500 }
- },
-
- // 是否需要知识库增强
- rag_enabled: true,
-
- // 输出格式
- output_format: 'structured', // structured | text | document
-
- // 状态
- status: 'active' // active | inactive | testing
-}
-```
-
-**2. 项目上下文管理**
-```javascript
-// 项目对话流程
-用户发起对话
- ↓
-自动注入项目背景
- ↓
-[项目背景 + 历史对话摘要 + 当前问题] → LLM
- ↓
-AI回复
- ↓
-用户可"固定"重要回复到项目背景
- ↓
-下次对话自动继承更新后的背景
-```
-
-**3. RAG集成方式**
-```javascript
-// 用户在对话中@骨质疏松专题
-const chatRequest = {
- message: "请帮我设计观察指标 @骨质疏松专题",
- project_id: "proj-123",
- agent_id: "agent-4",
- kb_references: ["kb-1"] // 骨质疏松专题
-}
-
-// 后端处理
-1. 提取知识库引用 → 调用Dify检索相关文档
-2. 提取项目背景 → 从数据库获取
-3. 组装完整Prompt
-4. 调用LLM生成回答
-5. 解析引用标记,生成溯源链接
-```
-
-#### 优点 ✅
-- **快速启动**:RAG功能直接复用Dify,1周可搭建基础版
-- **高度定制**:前端和业务逻辑完全自主可控
-- **最佳实践**:利用Dify成熟的RAG能力,避免重复造轮子
-- **灵活扩展**:可随时替换RAG引擎,不影响业务层
-- **成本可控**:开发周期和成本介于纯手写和纯框架之间
-- **易于维护**:职责清晰,RAG和业务逻辑分离
-
-#### 缺点 ❌
-- **架构复杂度中等**:需要协调多个系统
-- **需要熟悉Dify API**:有一定学习曲线
-- **多系统部署**:部署流程略复杂
-
-#### 开发计划
-**阶段1:基础搭建(2周)**
-- [ ] 前端框架搭建(React + 路由 + 状态管理)
-- [ ] 后端框架搭建(API设计 + 数据库设计)
-- [ ] Dify部署与配置
-- [ ] LLM Adapter层开发
-
-**阶段2:核心功能(4周)**
-- [ ] 项目/课题管理模块
-- [ ] 12个智能体配置与管理
-- [ ] 对话系统(含上下文管理)
-- [ ] 知识库集成(调用Dify)
-
-**阶段3:高级功能(3周)**
-- [ ] 多模型切换
-- [ ] Prompt版本管理
-- [ ] 历史记录管理
-- [ ] 文档生成(CRF、方案等)
-
-**阶段4:运营后台(2周)**
-- [ ] 用户管理
-- [ ] 智能体管理
-- [ ] 数据统计
-- [ ] 权限与审计
-
-**阶段5:测试优化(2周)**
-- [ ] 功能测试
-- [ ] 性能优化
-- [ ] 用户体验优化
-
-**总计:13周(约3个月)**
-
-#### 开发成本(优化后)
-- 人力:2人 × 2.5个月 = **5人月** ⭐
-- 服务器:$300/月(含Dify、数据库、Redis等)
-- LLM API:按实际使用量(DeepSeek-V3极便宜)
-- **总成本:¥40,000 - ¥55,000(初期开发)** ⭐
-- **节省:¥10,000-15,000(vs原方案)**
-
----
-
-## 📊 方案对比总结表
-
-| 维度 | 纯手写 | Dify | FastGPT | **混合架构** |
-|------|--------|------|---------|------------|
-| **开发周期** | 4-6个月 | 2-3个月 | 3-4个月 | **3个月** ⭐ |
-| **开发成本** | ¥80k-180k | ¥50k-80k | ¥60k-90k | **¥50k-70k** ⭐ |
-| **RAG能力** | 🟡 需自己实现 | 🟢 强大 | 🟢 强大 | **🟢 强大** ⭐ |
-| **定制灵活性** | 🟢 完全可控 | 🟡 受限 | 🟡 受限 | **🟢 高度可控** ⭐ |
-| **功能匹配度** | 🟢 100% | 🟡 60-70% | 🟡 50-60% | **🟢 95%** ⭐ |
-| **维护成本** | 🔴 高 | 🟢 低 | 🟢 低 | **🟡 中** ⭐ |
-| **技术难度** | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐ | **⭐⭐⭐⭐** |
-| **扩展性** | 🟢 极强 | 🟡 一般 | 🟡 一般 | **🟢 强** ⭐ |
-| **供应商锁定** | 🟢 无 | 🟡 中等 | 🟡 中等 | **🟢 低** ⭐ |
-| **社区支持** | 🔴 无 | 🟢 强 | 🟡 中 | **🟢 强** ⭐ |
-
----
-
-## 🎯 最终推荐:混合架构(优化版)
-
-### 核心架构调整
-
-基于您的反馈,我重新设计了架构方案,核心变化:
-
-**1. 聊天系统:参考LobeChat开源实现**
-- 不直接使用LobeChat整体,但**参考其聊天UI组件和流式输出实现**
-- LobeChat的聊天界面已经过充分验证,体验优秀
-- 可以复用其核心聊天组件(MIT许可),节省前端开发时间
-
-**2. 向量数据库:完全依赖Dify内置**
-- Dify内置Qdrant向量数据库,无需单独部署
-- 文档解析、向量化、检索全由Dify处理
-- 我们只需调用Dify的API即可
-
-**3. 运营端简化(降低成本)**
-- ❌ 删除模型管理功能(模型配置写在配置文件中)
-- ❌ 删除智能体管理功能(智能体配置固定在代码中)
-- ❌ 删除智能体配置功能(Prompt直接写在代码或配置文件)
-- ✅ 保留用户管理、数据统计、对话查看(仅必需功能)
-
-**4. 大模型优先级调整**
-- 主力模型:**DeepSeek-V3**(¥1/百万tokens,极具性价比)
-- 备用模型:**Qwen3**(阿里云,国内稳定)
-- 可选模型:Gemini Pro(国际用户)
-
-### 优化后的架构图
-
-```
-┌─────────────────────────────────────────┐
-│ 自定义前端(React) │
-│ - 项目管理界面(自研) │
-│ - 智能体选择界面(自研) │
-│ - 聊天界面(参考LobeChat组件)⭐ │
-│ - 知识库管理(自研) │
-│ - 历史记录(自研) │
-└─────────────────────────────────────────┘
- ↓ REST API
-┌─────────────────────────────────────────┐
-│ 业务层 (Node.js/TypeScript) │
-│ - 项目/课题CRUD │
-│ - 12个智能体路由(配置化)⭐ │
-│ - 对话上下文组装 │
-│ - 用户认证与权限 │
-│ - 简化的运营后台API │
-└─────────────────────────────────────────┘
- ↓ ↓
-┌──────────────────┐ ┌─────────────────┐
-│ Dify (RAG) │ │ LLM API │
-│ - 知识库 │ │ - DeepSeek-V3 │
-│ - 文档解析 │ │ - Qwen3 │
-│ - 向量检索 │ │ - Gemini │
-│ - Qdrant(内置)⭐│ │ │
-└──────────────────┘ └─────────────────┘
-```
-
-### 推荐理由(优化后)
-
-1. **聊天体验有保障**
- - 参考LobeChat的成熟实现,避免重复造轮子
- - 流式输出、Markdown渲染、代码高亮等功能开箱即用
- - 可以直接复用其React组件(MIT开源许可)
-
-2. **成本大幅降低**
- - 开发周期:**2-2.5个月**(vs 之前3个月)
- - 开发成本:**¥40k-55k**(vs 之前¥50k-70k)
- - 维护成本:更低(删除了复杂的后台管理)
-
-3. **架构更简洁**
- - 向量数据库:无需关心,Dify全包
- - 智能体管理:配置化,无需复杂后台
- - 模型管理:配置文件搞定
-
-4. **DeepSeek-V3极具性价比**
- - 价格:¥1/百万tokens(vs Gemini ¥2.7/百万tokens)
- - 性能:接近GPT-4水平
- - 速度:响应快,适合流式输出
-
-### 不推荐LobeChat整体的原因
-
-**为什么不用Dify + LobeChat组合?**
-
-虽然LobeChat聊天功能强,但:
-- ❌ **项目管理功能缺失**:LobeChat没有项目/课题管理概念
-- ❌ **12个智能体管理困难**:LobeChat的插件系统不适合我们的智能体模式
-- ❌ **知识库集成复杂**:LobeChat与Dify的知识库集成需要大量适配
-- ❌ **定制成本高**:深度定制LobeChat可能比参考实现还费时
-
-**我们的策略:**
-✅ **参考LobeChat的聊天UI实现**(复用组件)
-✅ **自研业务逻辑**(项目管理、智能体编排)
-✅ **Dify专注RAG**(知识库检索)
-
-这样既能享受LobeChat的聊天体验,又保持架构灵活性。
-
----
-
-## 🚀 实施建议
-
-### 技术选型细节
-
-**前端技术栈**
-```
-框架:React 18 + TypeScript
-构建:Vite
-UI:TailwindCSS + HeadlessUI
-状态管理:Zustand (轻量) 或 Redux Toolkit
-路由:React Router v6
-HTTP:Axios + SWR (数据缓存)
-Markdown:react-markdown + katex (公式支持)
-文件上传:react-dropzone
-富文本:Tiptap (用于项目描述编辑)
-```
-
-**后端技术栈**
-```
-框架:Node.js + Fastify (高性能) 或 Nest.js (企业级)
-语言:TypeScript
-ORM:Prisma (类型安全)
-数据库:PostgreSQL 15+
-缓存:Redis 7+
-队列:Bull (文档处理队列)
-日志:Winston + Pino
-认证:JWT + Passport
-文档:Swagger/OpenAPI
-```
-
-**RAG集成**
-```
-引擎:Dify (Docker部署)
-调用方式:REST API
-向量数据库:Dify内置 (Qdrant)
-文档解析:Dify内置
-检索策略:混合检索 (关键词 + 语义)
-```
-
-**LLM接入(优化后)**
-```
-主力模型:
-- DeepSeek-V3 (DeepSeek API) ⭐
- 价格:¥1/百万tokens,性价比极高
- 特点:推理能力强,适合复杂任务
-
-- Qwen3-72B (阿里云DashScope) ⭐
- 价格:¥4/百万tokens
- 特点:中文理解好,国内稳定
-
-备用模型:
-- Gemini 2.0 Flash (可选,国际用户)
-- Qwen3-7B (轻量任务)
-
-统一接口:OpenAI SDK格式(兼容性最好)
-模型配置:写在config/models.yaml中,无需后台管理
-```
-
-**部署方案**
-```
-容器化:Docker + Docker Compose
-反向代理:Nginx
-CI/CD:GitHub Actions
-监控:Prometheus + Grafana
-日志:ELK Stack
-备份:自动化数据库备份脚本
-```
-
-### 开发优先级(优化后)
-
-**P0(MVP必需,1个月内)**
-- [ ] 用户认证与权限(JWT)
-- [ ] 项目/课题基础CRUD
-- [ ] **复用LobeChat聊天UI组件** ⭐
-- [ ] 3个核心智能体(选题评价、PICOS构建、论文润色)
-- [ ] 基础对话功能(DeepSeek-V3接入)
-- [ ] 历史记录管理
-
-**P1(核心功能,2个月内)**
-- [ ] 剩余9个智能体(配置化实现)
-- [ ] 知识库集成(Dify RAG)
-- [ ] 多模型切换(DeepSeek-V3 / Qwen3)
-- [ ] 上下文动态管理(固定功能)
-- [ ] 流式输出优化
-
-**P2(高级功能,2.5个月内)**
-- [ ] 文档生成(CRF、研究方案导出Word)
-- [ ] 简化运营后台(用户管理 + 数据统计)
-- [ ] 高级搜索与筛选
-- [ ] 对话记录查看(仅管理员)
-
-**P3(优化迭代,后续)**
-- [ ] 性能优化(缓存、索引)
-- [ ] DeepSeek-V3效果调优
-- [ ] 用户体验优化
-- [ ] 移动端适配
-
-**已删除功能(降低成本):**
-- ❌ 智能体管理后台
-- ❌ 模型管理后台
-- ❌ Prompt版本管理系统
-- ❌ 复杂的审计日志
-
----
-
-## 💰 成本估算(详细)
-
-### 开发成本(优化后方案)
-
-**人力成本**
-- 全栈开发 × 1人 × 2.5个月 = 2.5人月
-- 前端开发 × 1人 × 1.5个月 = 1.5人月(复用LobeChat组件节省时间)
-- 合计:4人月
-- 按¥12k/人月计算 = **¥48,000** ⭐
-
-**服务器成本(开发+测试环境)**
-- 云服务器(4核8G):¥200/月 × 2.5 = ¥500
-- 数据库(PostgreSQL):¥100/月 × 2.5 = ¥250
-- Redis:¥50/月 × 2.5 = ¥125
-- 对象存储(文档存储):¥50/月 × 2.5 = ¥125
-- 带宽:¥100/月 × 2.5 = ¥250
-- 合计:**¥1,250**
-
-**LLM API成本(开发+测试)**
-- DeepSeek-V3:¥1/百万tokens(极便宜)⭐
-- 预计开发测试消耗:50M tokens(优化后)
-- 预估成本:**¥50** ⭐
-
-**第三方服务**
-- 短信验证:¥0.05/条 × 50 = ¥2.5
-- 邮件服务:¥0/月 (使用免费额度)
-- 合计:**¥3**
-
-**开发总成本:¥48,000 + ¥1,250 + ¥50 + ¥3 ≈ ¥49,300** ⭐
-
-**成本节省:**
-- vs 原方案(¥77,000):节省 **¥27,700**(36%)
-- vs 纯手写(¥80,000+):节省 **¥30,700+**(38%+)
-
-### 运营成本(月度)
-
-**基础设施(生产环境)**
-- 云服务器(8核16G):¥500/月
-- 数据库(PostgreSQL高可用):¥300/月
-- Redis(主从):¥150/月
-- 对象存储:¥100/月
-- CDN:¥100/月
-- 备份:¥50/月
-- 合计:**¥1,200/月**
-
-**LLM API成本(按1000用户/月估算)**
-- 假设每用户每月100轮对话
-- 平均每轮1k tokens输入 + 500 tokens输出
-- 总量:1000用户 × 100轮 × 1.5k tokens = 150M tokens/月
-- **DeepSeek-V3成本:150M × ¥1/百万 = ¥150/月** ⭐
-- Qwen3成本(备用):150M × ¥4/百万 = ¥600/月
-- 主要使用DeepSeek-V3:**¥150-200/月** ⭐
-
-**成本优势:**
-- vs Gemini Pro:节省约¥100-120/月
-- vs GPT-4:节省约¥2,000+/月
-- **年度节省:¥1,200-1,500**
-
-**人力成本(运维+优化)**
-- 1名全栈开发兼运维:¥15,000/月
-
-**月度总成本:¥1,200 + ¥180 + ¥15,000 ≈ ¥16,400/月**
-
-**vs 使用其他模型的成本对比:**
-| 模型方案 | 月度LLM成本 | 年度成本 | vs DeepSeek-V3 |
-|---------|------------|---------|----------------|
-| DeepSeek-V3 | ¥180 | ¥2,160 | 基准 ⭐ |
-| Qwen3-72B | ¥600 | ¥7,200 | +¥5,040/年 |
-| Gemini Pro | ¥300 | ¥3,600 | +¥1,440/年 |
-| GPT-4 | ¥2,500 | ¥30,000 | +¥27,840/年 |
-
----
-
-## 💬 如何复用LobeChat聊天组件
-
-### 为什么选择LobeChat
-
-**LobeChat的核心优势:**
-1. ✅ **MIT开源许可** - 可以自由使用和修改
-2. ✅ **聊天体验优秀** - 流式输出、Markdown渲染、代码高亮
-3. ✅ **技术栈一致** - Next.js/React,与我们的技术栈兼容
-4. ✅ **组件化设计** - 聊天UI组件可以单独提取
-5. ✅ **社区活跃** - 4万+ Stars,持续更新
-
-### 复用策略
-
-**不使用LobeChat整体的原因:**
-- ❌ 基于Next.js,而我们选择Vite(更轻量)
-- ❌ 缺少项目管理、知识库等我们需要的功能
-- ❌ 深度定制成本高,不如参考实现
-
-**我们的复用方式:**
-✅ **提取核心聊天组件** - 将LobeChat的聊天UI组件移植到我们的React项目
-✅ **参考实现逻辑** - 学习其流式输出、Markdown渲染的实现
-✅ **复用UI设计** - 参考其聊天界面的交互设计
-
-### 具体实施步骤
-
-**第1步:克隆LobeChat源码**
-```bash
-git clone https://github.com/lobehub/lobe-chat.git
-cd lobe-chat
-```
-
-**第2步:提取核心组件**
-
-需要提取的关键组件:
-```
-src/app/chat/
- ├── ChatMessage.tsx # 消息气泡组件
- ├── ChatInput.tsx # 输入框组件
- ├── StreamingText.tsx # 流式文本渲染
- ├── MarkdownRender.tsx # Markdown渲染
- └── ChatList.tsx # 消息列表
-
-src/components/
- ├── Avatar/ # 头像组件
- ├── CodeBlock/ # 代码块组件
- └── FileUpload/ # 文件上传组件
-```
-
-**第3步:适配到我们的项目**
-
-```tsx
-// 我们的项目结构
-src/components/chat/
- ├── ChatWindow.tsx // 主聊天窗口(自研)
- ├── ChatMessage.tsx // 从LobeChat移植 ⭐
- ├── ChatInput.tsx // 从LobeChat移植 ⭐
- ├── StreamRenderer.tsx // 从LobeChat移植 ⭐
- ├── MarkdownContent.tsx // 从LobeChat移植 ⭐
- └── ActionButtons.tsx // 自研(复制、固定、重新生成)
-
-// 使用示例
-import { ChatMessage } from '@/components/chat/ChatMessage';
-import { ChatInput } from '@/components/chat/ChatInput';
-
-function ChatView() {
- return (
-
-
- {messages.map(msg => (
-
- ))}
-
-
-
- );
-}
-```
-
-**第4步:实现流式输出**
-
-参考LobeChat的实现,使用Server-Sent Events (SSE):
-
-```typescript
-// 前端:接收流式数据
-async function streamChat(message: string) {
- const response = await fetch('/api/chat/stream', {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({ message, projectId, agentId })
- });
-
- const reader = response.body?.getReader();
- const decoder = new TextDecoder();
- let accumulatedText = '';
-
- while (true) {
- const { done, value } = await reader.read();
- if (done) break;
-
- const chunk = decoder.decode(value);
- const lines = chunk.split('\n');
-
- for (const line of lines) {
- if (line.startsWith('data: ')) {
- const data = JSON.parse(line.slice(6));
- if (data.type === 'token') {
- accumulatedText += data.content;
- setMessages(prev => [...prev.slice(0, -1), {
- ...prev[prev.length - 1],
- content: accumulatedText
- }]);
- }
- }
- }
- }
-}
-
-// 后端:发送流式数据
-app.post('/api/chat/stream', async (req, res) => {
- res.setHeader('Content-Type', 'text/event-stream');
- res.setHeader('Cache-Control', 'no-cache');
- res.setHeader('Connection', 'keep-alive');
-
- const stream = await llmAdapter.chatStream({
- messages: contextMessages,
- temperature: 0.7
- });
-
- for await (const chunk of stream) {
- res.write(`data: ${JSON.stringify({
- type: 'token',
- content: chunk
- })}\n\n`);
- }
-
- res.write(`data: ${JSON.stringify({ type: 'done' })}\n\n`);
- res.end();
-});
-```
-
-### 预计节省时间
-
-| 功能模块 | 从零开发 | 复用LobeChat | 节省 |
-|---------|---------|-------------|------|
-| 基础聊天UI | 5天 | 1天 | 4天 |
-| 流式输出 | 3天 | 0.5天 | 2.5天 |
-| Markdown渲染 | 2天 | 0.5天 | 1.5天 |
-| 代码高亮 | 1天 | 0.5天 | 0.5天 |
-| 文件上传UI | 2天 | 1天 | 1天 |
-| **总计** | **13天** | **3.5天** | **9.5天** ⭐ |
-
----
-
-## 🔧 技术实现关键点
-
-### 1. 智能体配置管理(简化版 - 配置文件方式)
-
-**为什么选择配置文件而非数据库管理?**
-- ✅ 降低开发成本(无需开发后台管理界面)
-- ✅ 版本控制友好(Git管理配置变更)
-- ✅ 部署简单(无需数据库迁移)
-- ✅ 易于调试(直接修改配置文件)
-
-**配置文件结构**
-
-```yaml
-# config/agents.yaml
-agents:
- - id: agent-topic-evaluation
- name: 选题评价
- description: 从创新性、临床价值、科学性和可行性等维度评价临床问题
- category: 选题阶段
- icon: lightbulb
-
- # Prompt配置
- system_prompt_file: prompts/topic_evaluation_system.txt
- user_prompt_template_file: prompts/topic_evaluation_user.txt
-
- # 模型配置
- models:
- deepseek-v3:
- temperature: 0.4
- max_tokens: 2000
- top_p: 0.9
- qwen3-72b:
- temperature: 0.5
- max_tokens: 2000
-
- # 功能开关
- rag_enabled: true # 是否支持知识库检索
- file_upload_enabled: false # 是否支持文件上传
-
- # 输出格式
- output_format: structured # text | structured | document
-
- # 状态
- status: active # active | inactive
-
- - id: agent-picos
- name: PICOS构建
- description: 结构化地定义临床研究的核心要素
- category: 研究设计
- icon: construction
- system_prompt_file: prompts/picos_system.txt
- user_prompt_template_file: prompts/picos_user.txt
- models:
- deepseek-v3:
- temperature: 0.3
- max_tokens: 2500
- rag_enabled: true
- file_upload_enabled: false
- output_format: structured
- status: active
-
- # ... 其他10个智能体配置
-```
-
-**Prompt文件管理**
-
-```
-backend/prompts/
- ├── topic_evaluation_system.txt
- ├── topic_evaluation_user.txt
- ├── picos_system.txt
- ├── picos_user.txt
- ├── crf_system.txt
- ├── sample_size_system.txt
- └── ...
-```
-
-**示例Prompt文件**
-
-```txt
-# prompts/picos_system.txt
-你是一位经验丰富的临床研究方法学专家,擅长帮助研究者构建科学严谨的PICOS框架。
-
-## 你的任务
-根据用户提供的研究想法,帮助其完善以下要素:
-- P (Population): 研究人群的精确定义
-- I (Intervention): 干预措施的详细描述
-- C (Comparison): 对照组的设计
-- O (Outcome): 主要和次要观察指标
-- S (Study Design): 研究设计类型
-
-## 输出要求
-1. 使用结构化的表格或清单形式输出
-2. 每个要素都要具体、可操作、可测量
-3. 指出潜在的方法学问题
-4. 提供改进建议
-
-## 注意事项
-- 确保研究人群的纳入排除标准明确
-- 干预措施要具有可重复性
-- 观察指标要符合临床意义和统计学要求
-- 研究设计要匹配研究目的
-```
-
-**加载配置的代码实现**
-
-```typescript
-// backend/src/config/agent-loader.ts
-import fs from 'fs';
-import yaml from 'yaml';
-import path from 'path';
-
-interface AgentConfig {
- id: string;
- name: string;
- description: string;
- category: string;
- icon: string;
- system_prompt_file: string;
- user_prompt_template_file: string;
- models: Record;
- rag_enabled: boolean;
- file_upload_enabled: boolean;
- output_format: 'text' | 'structured' | 'document';
- status: 'active' | 'inactive';
-}
-
-class AgentConfigLoader {
- private agents: Map = new Map();
- private prompts: Map = new Map();
-
- constructor() {
- this.loadAgents();
- this.loadPrompts();
- }
-
- private loadAgents() {
- const configFile = fs.readFileSync(
- path.join(__dirname, '../../config/agents.yaml'),
- 'utf-8'
- );
- const config = yaml.parse(configFile);
-
- for (const agent of config.agents) {
- if (agent.status === 'active') {
- this.agents.set(agent.id, agent);
- }
- }
-
- console.log(`✅ Loaded ${this.agents.size} active agents`);
- }
-
- private loadPrompts() {
- const promptsDir = path.join(__dirname, '../../prompts');
- const files = fs.readdirSync(promptsDir);
-
- for (const file of files) {
- if (file.endsWith('.txt')) {
- const content = fs.readFileSync(
- path.join(promptsDir, file),
- 'utf-8'
- );
- this.prompts.set(file, content);
- }
- }
-
- console.log(`✅ Loaded ${this.prompts.size} prompt templates`);
- }
-
- getAgent(agentId: string): AgentConfig | undefined {
- return this.agents.get(agentId);
- }
-
- getAllAgents(): AgentConfig[] {
- return Array.from(this.agents.values());
- }
-
- getPrompt(filename: string): string {
- return this.prompts.get(filename) || '';
- }
-
- // 热重载(开发环境)
- reloadConfig() {
- this.agents.clear();
- this.prompts.clear();
- this.loadAgents();
- this.loadPrompts();
- }
-}
-
-export const agentConfig = new AgentConfigLoader();
-```
-
-**API设计**
-```javascript
-// 获取智能体列表
-GET /api/agents
-Response: {
- agents: [
- {
- id: 'agent-picos',
- name: 'PICOS构建',
- description: '...',
- category: '研究设计',
- icon: 'construction',
- status: 'active'
- }
- ]
-}
-
-// 调用智能体
-POST /api/agents/{agentId}/chat
-Request: {
- message: "请帮我构建PICOS",
- project_id: "proj-123", // 可选
- kb_references: ["kb-1"], // 可选
- model: "gemini-pro", // 可选
- stream: true // 是否流式输出
-}
-Response (Stream):
-data: {"type":"start"}
-data: {"type":"token","content":"好的"}
-data: {"type":"token","content":",我们"}
-...
-data: {"type":"end","message_id":"msg-xxx"}
-```
-
-### 2. 上下文管理实现
-
-**上下文组装策略**
-```javascript
-async function buildContextForAgent(params) {
- const { projectId, agentId, message, conversationHistory } = params;
-
- let contextParts = [];
-
- // 1. 项目背景(如果有)
- if (projectId) {
- const project = await db.projects.findOne(projectId);
- contextParts.push({
- role: 'system',
- content: `# 项目背景\n${project.description}`
- });
- }
-
- // 2. 智能体系统提示词
- const agent = await db.agents.findOne(agentId);
- contextParts.push({
- role: 'system',
- content: agent.system_prompt
- });
-
- // 3. 历史对话摘要(如果超过10轮,进行摘要压缩)
- if (conversationHistory.length > 10) {
- const summary = await summarizeHistory(conversationHistory.slice(0, -10));
- contextParts.push({
- role: 'system',
- content: `# 历史对话摘要\n${summary}`
- });
- contextParts.push(...conversationHistory.slice(-10));
- } else {
- contextParts.push(...conversationHistory);
- }
-
- // 4. 知识库检索结果(如果有@引用)
- if (params.kb_references) {
- const ragResults = await queryDifyKnowledgeBase({
- kb_ids: params.kb_references,
- query: message,
- top_k: 5
- });
- contextParts.push({
- role: 'system',
- content: `# 相关知识库内容\n${ragResults.documents.map(d =>
- `[${d.metadata.filename}] ${d.content}`
- ).join('\n\n')}`
- });
- }
-
- // 5. 当前用户问题
- contextParts.push({
- role: 'user',
- content: message
- });
-
- return contextParts;
-}
-```
-
-**Token计数与控制**
-```javascript
-import { encoding_for_model } from 'tiktoken';
-
-function estimateTokens(messages, model = 'gpt-4') {
- const encoding = encoding_for_model(model);
- let total = 0;
- for (const msg of messages) {
- total += encoding.encode(msg.content).length;
- total += 4; // 每条消息的格式开销
- }
- return total;
-}
-
-async function buildContextWithTokenLimit(params, maxTokens = 6000) {
- let context = await buildContextForAgent(params);
- let tokens = estimateTokens(context);
-
- // 如果超限,逐步删减历史对话
- while (tokens > maxTokens && context.length > 3) {
- // 保留系统提示词和当前问题,删减中间的历史对话
- context.splice(2, 1);
- tokens = estimateTokens(context);
- }
-
- return context;
-}
-```
-
-### 3. Dify RAG集成
-
-**调用Dify API**
-```javascript
-import axios from 'axios';
-
-class DifyService {
- constructor() {
- this.baseUrl = process.env.DIFY_API_URL;
- this.apiKey = process.env.DIFY_API_KEY;
- }
-
- // 查询知识库
- async queryKnowledgeBase({ datasetId, query, topK = 5 }) {
- const response = await axios.post(
- `${this.baseUrl}/datasets/${datasetId}/retrieve`,
- {
- query,
- retrieval_model: {
- search_method: 'hybrid_search', // 混合检索
- reranking_enable: true, // 重排序
- reranking_model: {
- reranking_provider_name: 'cohere',
- reranking_model_name: 'rerank-multilingual-v2.0'
- },
- top_k: topK,
- score_threshold_enabled: true,
- score_threshold: 0.5
- }
- },
- {
- headers: {
- 'Authorization': `Bearer ${this.apiKey}`,
- 'Content-Type': 'application/json'
- }
- }
- );
-
- return response.data.records.map(record => ({
- content: record.segment.content,
- score: record.score,
- metadata: {
- filename: record.segment.document.name,
- position: record.segment.position,
- document_id: record.segment.document.id
- }
- }));
- }
-
- // 上传文档到知识库
- async uploadDocument({ datasetId, file, processRule }) {
- const formData = new FormData();
- formData.append('file', file);
- formData.append('process_rule', JSON.stringify(processRule || {
- mode: 'automatic',
- rules: {
- pre_processing_rules: [
- { id: 'remove_extra_spaces', enabled: true },
- { id: 'remove_urls_emails', enabled: true }
- ],
- segmentation: {
- separator: '\n\n',
- max_tokens: 500
- }
- }
- }));
-
- const response = await axios.post(
- `${this.baseUrl}/datasets/${datasetId}/documents`,
- formData,
- {
- headers: {
- 'Authorization': `Bearer ${this.apiKey}`
- }
- }
- );
-
- return response.data;
- }
-
- // 检查文档处理状态
- async getDocumentStatus({ datasetId, documentId }) {
- const response = await axios.get(
- `${this.baseUrl}/datasets/${datasetId}/documents/${documentId}`,
- {
- headers: {
- 'Authorization': `Bearer ${this.apiKey}`
- }
- }
- );
-
- return {
- status: response.data.indexing_status, // 'processing' | 'completed' | 'error'
- progress: response.data.completed_segments,
- total: response.data.total_segments,
- error: response.data.error
- };
- }
-}
-```
-
-### 4. 多模型Adapter
-
-**统一接口抽象**
-```javascript
-// 基础Adapter接口
-class LLMAdapter {
- async chat({ messages, temperature, maxTokens, stream }) {
- throw new Error('Must implement chat method');
- }
-}
-
-// Gemini Adapter
-class GeminiAdapter extends LLMAdapter {
- constructor(apiKey) {
- super();
- this.apiKey = apiKey;
- this.baseUrl = 'https://generativelanguage.googleapis.com/v1beta';
- }
-
- async chat({ messages, temperature = 0.7, maxTokens = 2000, stream = false }) {
- // 转换消息格式
- const contents = messages.map(msg => ({
- role: msg.role === 'user' ? 'user' : 'model',
- parts: [{ text: msg.content }]
- }));
-
- const response = await axios.post(
- `${this.baseUrl}/models/gemini-pro:${stream ? 'streamGenerateContent' : 'generateContent'}`,
- {
- contents,
- generationConfig: {
- temperature,
- maxOutputTokens: maxTokens
- }
- },
- {
- headers: { 'x-goog-api-key': this.apiKey },
- responseType: stream ? 'stream' : 'json'
- }
- );
-
- if (stream) {
- return this.handleStream(response.data);
- } else {
- return response.data.candidates[0].content.parts[0].text;
- }
- }
-}
-
-// DeepSeek Adapter
-class DeepSeekAdapter extends LLMAdapter {
- constructor(apiKey) {
- super();
- this.apiKey = apiKey;
- this.baseUrl = 'https://api.deepseek.com/v1';
- }
-
- async chat({ messages, temperature = 0.7, maxTokens = 2000, stream = false }) {
- // DeepSeek兼容OpenAI格式
- const response = await axios.post(
- `${this.baseUrl}/chat/completions`,
- {
- model: 'deepseek-chat',
- messages,
- temperature,
- max_tokens: maxTokens,
- stream
- },
- {
- headers: {
- 'Authorization': `Bearer ${this.apiKey}`,
- 'Content-Type': 'application/json'
- },
- responseType: stream ? 'stream' : 'json'
- }
- );
-
- if (stream) {
- return response.data; // 返回stream
- } else {
- return response.data.choices[0].message.content;
- }
- }
-}
-
-// 工厂模式
-class LLMFactory {
- static adapters = {
- 'gemini-pro': GeminiAdapter,
- 'deepseek-v2': DeepSeekAdapter,
- 'qwen2-72b': QwenAdapter,
- };
-
- static create(modelName, apiKey) {
- const AdapterClass = this.adapters[modelName];
- if (!AdapterClass) {
- throw new Error(`Unsupported model: ${modelName}`);
- }
- return new AdapterClass(apiKey);
- }
-}
-
-// 使用
-const adapter = LLMFactory.create('gemini-pro', process.env.GEMINI_API_KEY);
-const response = await adapter.chat({
- messages: contextMessages,
- temperature: 0.7,
- stream: true
-});
-```
-
-### 5. 文档生成
-
-**CRF生成示例**
-```javascript
-import { Document, Packer, Paragraph, Table, TableRow, TableCell, WidthType } from 'docx';
-import fs from 'fs';
-
-async function generateCRF(crfData) {
- const doc = new Document({
- sections: [{
- children: [
- new Paragraph({
- text: '病例报告表 (CRF)',
- heading: 'Heading1',
- }),
- new Paragraph({
- text: `研究名称:${crfData.studyName}`,
- }),
- new Paragraph({
- text: `受试者编号:__________`,
- }),
- new Paragraph({ text: '' }),
-
- // 基本信息表格
- new Table({
- width: { size: 100, type: WidthType.PERCENTAGE },
- rows: [
- new TableRow({
- children: [
- new TableCell({ children: [new Paragraph('姓名缩写')] }),
- new TableCell({ children: [new Paragraph('___________')] }),
- ]
- }),
- new TableRow({
- children: [
- new TableCell({ children: [new Paragraph('性别')] }),
- new TableCell({ children: [new Paragraph('□ 男 □ 女')] }),
- ]
- }),
- // ... 更多字段
- ]
- }),
-
- // 观察指标
- new Paragraph({
- text: '主要观察指标',
- heading: 'Heading2',
- }),
- ...crfData.outcomes.map(outcome =>
- new Paragraph({
- text: `${outcome.name}:__________ 单位:${outcome.unit}`,
- bullet: { level: 0 }
- })
- ),
- ]
- }]
- });
-
- const buffer = await Packer.toBuffer(doc);
- return buffer;
-}
-
-// API endpoint
-app.post('/api/agents/crf-agent/generate', async (req, res) => {
- const { projectId, crfData } = req.body;
-
- const buffer = await generateCRF(crfData);
-
- res.setHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document');
- res.setHeader('Content-Disposition', `attachment; filename="CRF_${Date.now()}.docx"`);
- res.send(buffer);
-});
-```
-
----
-
-## ⚠️ 风险与挑战
-
-### 技术风险
-
-1. **RAG检索质量问题**
- - 风险:医学术语复杂,检索准确率可能不达标
- - 应对:
- - 使用Dify的重排序功能
- - 自定义医学词典
- - 人工标注高质量问答对进行微调
-
-2. **LLM幻觉问题**
- - 风险:AI生成内容可能不准确,尤其是医学领域
- - 应对:
- - 加强Prompt约束(要求标注不确定性)
- - RAG强制引用(减少幻觉)
- - 关键功能人工复核机制
-
-3. **性能问题**
- - 风险:大规模用户并发时响应慢
- - 应对:
- - Redis缓存高频查询
- - 流式输出提升体验
- - CDN加速静态资源
- - 数据库索引优化
-
-4. **成本失控**
- - 风险:LLM API费用可能超预期
- - 应对:
- - 设置单用户每日Token配额
- - 优先使用便宜模型(DeepSeek)
- - 缓存常见问题的答案
- - 监控异常使用
-
-### 业务风险
-
-1. **医疗合规问题**
- - 风险:AI生成的医学建议可能涉及法律风险
- - 应对:
- - 明确免责声明
- - 强调"仅供参考"
- - 不涉及诊断和治疗建议
- - 保留所有对话记录以备审查
-
-2. **数据安全问题**
- - 风险:用户上传敏感医学数据
- - 应对:
- - 数据加密存储
- - 严格权限控制
- - 不传输到境外LLM(优先国内模型)
- - 定期安全审计
-
----
-
-## 📚 参考资源
-
-**Dify相关**
-- 官方文档:https://docs.dify.ai/
-- GitHub:https://github.com/langgenius/dify
-- API文档:https://docs.dify.ai/guides/application-publishing/developing-with-apis
-
-**LLM API**
-- Gemini:https://ai.google.dev/docs
-- DeepSeek:https://platform.deepseek.com/docs
-- Qwen:https://help.aliyun.com/zh/dashscope/
-
-**开发框架**
-- React:https://react.dev/
-- Fastify:https://fastify.dev/
-- Prisma:https://www.prisma.io/
-- TailwindCSS:https://tailwindcss.com/
-
----
-
-## 📝 总结
-
-基于以上分析,**强烈推荐采用混合架构方案**:
-
-✅ **短期优势**
-- 3个月内可完成MVP并上线
-- 开发成本可控(¥50k-70k)
-- RAG功能开箱即用
-- 技术风险低
-
-✅ **长期优势**
-- 业务逻辑完全自主可控
-- 可随时优化和扩展
-- RAG引擎可替换
-- 不被框架绑定
-
-✅ **实施建议**
-1. 第1周:搭建基础架构(前后端+Dify)
-2. 第2-4周:实现2-3个核心智能体(MVP)
-3. 第5-8周:完善12个智能体+知识库
-4. 第9-10周:开发运营后台
-5. 第11-12周:测试优化上线
-
-这个方案在**开发效率、成本、质量、可扩展性**之间取得了最佳平衡,是最适合您项目的技术选型。
-
----
-
-**文档版本:v1.0**
-**更新时间:2025-10-10**
-**作者:AI技术顾问**
-
diff --git a/智能引用功能-测试指南.md b/智能引用功能-测试指南.md
deleted file mode 100644
index aa9bbad7..00000000
--- a/智能引用功能-测试指南.md
+++ /dev/null
@@ -1,205 +0,0 @@
-# 🧪 智能引用功能 - 快速测试指南
-
-**功能名称**:智能文献引用与出处显示
-**测试时间**:约10分钟
-**测试环境**:需要重启后端
-
----
-
-## 🚀 Step 1: 重启后端(1分钟)
-
-```bash
-# 停止当前后端(Ctrl+C),然后:
-cd D:\MyCursor\AIclinicalresearch\backend
-npm run dev
-```
-
-**等待看到**:
-```
-✓ Server running on http://localhost:5000
-```
-
----
-
-## 🧪 Step 2: 测试智能问答(5分钟)
-
-### 操作步骤
-
-1. **访问**:http://localhost:3000/chat
-2. **选择知识库**:点击"@"图标 → 选择 `阿尔兹海默知识库(优化版)`
-3. **提问1**:`这个知识库有几个文件?请列出所有文件`
-4. **观察AI回答**
-
-### ✅ 预期效果
-
-AI应该这样回答:
-
-```markdown
-根据检索结果,这个知识库包含以下文件[来源1][来源2][来源3]...
-
-(AI的正常回答内容)
-
----
-
-📚 **参考文献**
-
-[1] 📄 **阿尔兹海默综述2023.pdf** - 第3段 (相关度95%)
- "阿尔兹海默病是一种神经退行性疾病,主要表现为记忆力减退、认知..."
-
-[2] 📄 **临床试验报告.pdf** - 第7段 (相关度87%)
- "研究表明β-淀粉样蛋白在病理过程中起关键作用,是导致神经元损伤..."
-
-[3] 📄 **药物治疗进展.pdf** - 第12段 (相关度82%)
- "当前主要的治疗方法包括胆碱酯酶抑制剂和NMDA受体拮抗剂,这些药物..."
-
-... (最多15个引用)
-```
-
-### 关键检查点
-
-- ✅ AI回答中是否使用 `[来源1]`、`[来源2]` 等编号标记?
-- ✅ 回答结束后是否显示 `---` 分隔线?
-- ✅ 是否显示 `📚 **参考文献**` 标题?
-- ✅ 每个引用是否包含:
- - ✅ 编号 `[1]`
- - ✅ 图标 📄
- - ✅ **文件名**(加粗)
- - ✅ 段落位置(如"第3段")
- - ✅ 相关度分数(如"相关度95%")
- - ✅ 缩进的上下文预览(带引号)
-
----
-
-### 🧪 更多测试问题
-
-**提问2**:`请总结这7篇文献的核心观点`
-
-**提问3**:`比较不同文献的研究方法`
-
-**提问4**:`哪些文献讨论了药物治疗?`
-
----
-
-## 🧪 Step 3: 测试对话功能(可选,3分钟)
-
-1. **访问**:http://localhost:3000/projects
-2. **选择**:任意项目 → 任意对话
-3. **在对话中**:@知识库 + 提问
-4. **验证**:是否同样显示引用清单
-
----
-
-## 📊 效果评估标准
-
-### ✅ 成功标准
-
-| 检查项 | 是否通过 |
-|--------|---------|
-| AI使用[来源N]标记 | ☐ |
-| 显示分隔线和标题 | ☐ |
-| 文件名正确显示 | ☐ |
-| 段落位置显示 | ☐ |
-| 相关度分数显示 | ☐ |
-| 上下文预览100字以内 | ☐ |
-| 引用数量合理(1-15个) | ☐ |
-
-**如果以上全部通过** ✅ → 功能成功!
-
----
-
-## 🐛 常见问题
-
-### Q1: 没有显示引用清单?
-
-**原因**:
-- 可能没有选择知识库(@)
-- 或者知识库没有检索到相关内容
-
-**解决**:
-1. 确认已经选择了知识库(输入框上方应显示知识库标签)
-2. 尝试更具体的问题
-
----
-
-### Q2: 引用格式不对?
-
-**检查**:
-1. 后端是否重启?(必须重启才能应用新代码)
-2. 浏览器控制台有错误吗?(F12查看)
-3. 后端日志中是否有 `📚 追加 X 个引用清单`?
-
----
-
-### Q3: AI没有使用[来源N]标记?
-
-**原因**:AI可能忽略了prompt指令
-
-**不影响**:引用清单仍然会正确显示,只是AI没有在回答中明确标注
-
-**改进方向**:可以在prompt中加强指导(已经做了)
-
----
-
-## 🎯 测试后的决策
-
-### 如果效果满意 ✅
-
-**说明**:
-- 引用功能完美运行
-- 用户可以清楚看到AI引用的所有出处
-- 40-50%的文献覆盖率足够使用
-
-**下一步**:
-- ✅ 标记测试完成
-- ✅ Phase 1.5 全部完成
-- ✅ 进入里程碑2(开发其他11个智能体)
-
----
-
-### 如果还需要改进 ⚠️
-
-**可能的问题**:
-1. 引用数量太多(15个太多)→ 可调整top_k
-2. 上下文预览太短(100字不够)→ 可调整maxLength
-3. 还是想看完整文献 → 启动Phase 2(全文精读模式)
-
-**请告诉我具体问题**,我会立即调整!
-
----
-
-## 📸 截图建议
-
-建议截图以下内容供记录:
-
-1. **AI回答部分**:显示[来源N]标记的使用
-2. **引用清单部分**:完整的参考文献列表
-3. **浏览器控制台**:无错误(F12 → Console标签)
-4. **后端日志**:显示 `📚 追加 X 个引用清单`
-
----
-
-## 📞 反馈格式
-
-测试完成后,请告诉我:
-
-**简单反馈**:
-> 效果很好 ✅ / 有问题 ❌
-
-**详细反馈**(如果有问题):
-> - 问题描述:___
-> - 测试问题:___
-> - 实际看到的:___
-> - 期望看到的:___
-
----
-
-## 🎉 测试完成
-
-测试通过后,我们可以:
-1. 更新里程碑文档
-2. 标记Phase 1.5完成
-3. 开始里程碑2的开发
-
-**现在就开始测试吧!** 🚀
-
-
diff --git a/查看端口占用.bat b/查看端口占用.bat
deleted file mode 100644
index 1e1e8227..00000000
--- a/查看端口占用.bat
+++ /dev/null
@@ -1,53 +0,0 @@
-@echo off
-chcp 65001 >nul
-echo ========================================
-echo 查看端口占用情况
-echo ========================================
-echo.
-
-echo [端口 3001 - 后端服务]
-netstat -ano | findstr :3001
-if errorlevel 1 (
- echo ✅ 端口3001空闲
-) else (
- echo ⚠️ 端口3001已被占用
- echo.
- echo 占用进程详情:
- for /f "tokens=5" %%a in ('netstat -aon ^| findstr :3001 ^| findstr LISTENING') do (
- tasklist | findstr %%a
- )
-)
-
-echo.
-echo [端口 3000 - 前端服务]
-netstat -ano | findstr :3000
-if errorlevel 1 (
- echo ✅ 端口3000空闲
-) else (
- echo ⚠️ 端口3000已被占用
- echo.
- echo 占用进程详情:
- for /f "tokens=5" %%a in ('netstat -aon ^| findstr :3000 ^| findstr LISTENING') do (
- tasklist | findstr %%a
- )
-)
-
-echo.
-echo [所有Node.js进程]
-tasklist | findstr node.exe
-if errorlevel 1 (
- echo ℹ️ 没有运行中的Node进程
-)
-
-echo.
-echo ========================================
-echo 检查完成
-echo ========================================
-echo.
-echo 如需停止服务,请运行: 停止所有服务.bat
-echo.
-pause
-
-
-
-
diff --git a/检查测试环境.bat b/检查测试环境.bat
deleted file mode 100644
index bb74eb56..00000000
--- a/检查测试环境.bat
+++ /dev/null
@@ -1,205 +0,0 @@
-@echo off
-chcp 65001 >nul
-echo ========================================
-echo Phase 2 测试环境检查
-echo ========================================
-echo.
-
-set PASS=0
-set FAIL=0
-set WARN=0
-
-echo [检查1/10] Docker Desktop 状态...
-docker ps >nul 2>&1
-if errorlevel 1 (
- echo ❌ Docker未运行
- set /a FAIL+=1
-) else (
- echo ✅ Docker正常运行
- set /a PASS+=1
-)
-echo.
-
-echo [检查2/10] PostgreSQL容器...
-docker ps | findstr "postgres" >nul
-if errorlevel 1 (
- echo ⚠️ PostgreSQL容器未运行
- set /a WARN+=1
-) else (
- echo ✅ PostgreSQL容器运行中
- set /a PASS+=1
-)
-echo.
-
-echo [检查3/10] Redis容器...
-docker ps | findstr "redis" >nul
-if errorlevel 1 (
- echo ⚠️ Redis容器未运行
- set /a WARN+=1
-) else (
- echo ✅ Redis容器运行中
- set /a PASS+=1
-)
-echo.
-
-echo [检查4/10] Python环境...
-python --version >nul 2>&1
-if errorlevel 1 (
- echo ❌ Python未安装
- set /a FAIL+=1
-) else (
- python --version
- echo ✅ Python已安装
- set /a PASS+=1
-)
-echo.
-
-echo [检查5/10] Node.js环境...
-node --version >nul 2>&1
-if errorlevel 1 (
- echo ❌ Node.js未安装
- set /a FAIL+=1
-) else (
- node --version
- echo ✅ Node.js已安装
- set /a PASS+=1
-)
-echo.
-
-echo [检查6/10] Python微服务文件...
-if exist "extraction_service\main.py" (
- echo ✅ Python微服务文件存在
- set /a PASS+=1
-) else (
- echo ❌ Python微服务文件缺失
- set /a FAIL+=1
-)
-echo.
-
-echo [检查7/10] Python虚拟环境...
-if exist "extraction_service\venv\" (
- echo ✅ Python虚拟环境存在
- set /a PASS+=1
-) else (
- echo ⚠️ Python虚拟环境未创建
- echo 运行: cd extraction_service && .\install.bat
- set /a WARN+=1
-)
-echo.
-
-echo [检查8/10] Backend依赖...
-if exist "backend\node_modules\" (
- echo ✅ Backend依赖已安装
- set /a PASS+=1
-) else (
- echo ⚠️ Backend依赖未安装
- echo 运行: cd backend && npm install
- set /a WARN+=1
-)
-echo.
-
-echo [检查9/10] Frontend依赖...
-if exist "frontend\node_modules\" (
- echo ✅ Frontend依赖已安装
- set /a PASS+=1
-) else (
- echo ⚠️ Frontend依赖未安装
- echo 运行: cd frontend && npm install
- set /a WARN+=1
-)
-echo.
-
-echo [检查10/10] Phase 2核心文件...
-set FILES_OK=1
-
-if not exist "frontend\src\components\chat\FullTextMode.tsx" (
- echo ❌ 缺失: FullTextMode.tsx
- set FILES_OK=0
-)
-
-if not exist "frontend\src\components\chat\DeepReadMode.tsx" (
- echo ❌ 缺失: DeepReadMode.tsx
- set FILES_OK=0
-)
-
-if not exist "frontend\src\components\chat\DocumentSelector.tsx" (
- echo ❌ 缺失: DocumentSelector.tsx
- set FILES_OK=0
-)
-
-if not exist "backend\src\clients\ExtractionClient.ts" (
- echo ❌ 缺失: ExtractionClient.ts
- set FILES_OK=0
-)
-
-if not exist "backend\src\services\tokenService.ts" (
- echo ❌ 缺失: tokenService.ts
- set FILES_OK=0
-)
-
-if %FILES_OK%==1 (
- echo ✅ Phase 2核心文件完整
- set /a PASS+=1
-) else (
- echo ❌ Phase 2核心文件缺失
- set /a FAIL+=1
-)
-echo.
-
-echo ========================================
-echo 检查结果汇总
-echo ========================================
-echo ✅ 通过: %PASS%/10
-echo ⚠️ 警告: %WARN%/10
-echo ❌ 失败: %FAIL%/10
-echo.
-
-if %FAIL% GTR 0 (
- echo 🔴 状态: 测试环境有严重问题
- echo.
- echo 建议:
- echo 1. 检查上方标记❌的项目
- echo 2. 安装缺失的软件或文件
- echo 3. 重新运行此脚本验证
- echo.
- goto END
-)
-
-if %WARN% GTR 0 (
- echo 🟡 状态: 测试环境基本就绪,有小问题
- echo.
- echo 建议:
- echo 1. 检查上方标记⚠️的项目
- echo 2. 按照提示完成安装
- echo 3. 或直接运行一键启动脚本尝试自动修复
- echo.
- goto END
-)
-
-echo 🟢 状态: 测试环境完全就绪!
-echo.
-echo ========================================
-echo 可以开始测试了!
-echo ========================================
-echo.
-echo 快速测试(30分钟):
-echo 打开: Phase2-快速测试清单.md
-echo.
-echo 完整测试(90分钟):
-echo 打开: Phase2-测试指南.md
-echo.
-echo 立即启动服务:
-echo 运行: .\一键启动.bat
-echo.
-
-:END
-pause
-
-
-
-
-
-
-
-
-
diff --git a/测试API.bat b/测试API.bat
deleted file mode 100644
index 1c43d851..00000000
--- a/测试API.bat
+++ /dev/null
@@ -1,92 +0,0 @@
-@echo off
-chcp 65001 >nul
-echo ========================================
-echo API测试工具
-echo ========================================
-echo.
-
-echo [测试1] 后端健康检查
-echo URL: http://localhost:3001/health
-curl -s http://localhost:3001/health
-if errorlevel 1 (
- echo.
- echo ❌ 后端服务未响应
- echo 解决方案: cd backend ^&^& npm run dev
- goto :end
-) else (
- echo.
- echo ✅ 后端服务正常
-)
-echo.
-echo ----------------------------------------
-echo.
-
-echo [测试2] 获取项目列表
-echo URL: http://localhost:3001/api/v1/projects
-curl -s http://localhost:3001/api/v1/projects
-if errorlevel 1 (
- echo.
- echo ❌ 获取项目列表失败
-) else (
- echo.
- echo ✅ 获取项目列表成功
-)
-echo.
-echo ----------------------------------------
-echo.
-
-echo [测试3] 获取智能体列表
-echo URL: http://localhost:3001/api/v1/agents
-curl -s http://localhost:3001/api/v1/agents
-if errorlevel 1 (
- echo.
- echo ❌ 获取智能体列表失败
-) else (
- echo.
- echo ✅ 获取智能体列表成功
-)
-echo.
-echo ----------------------------------------
-echo.
-
-echo [测试4] 创建测试项目
-echo URL: http://localhost:3001/api/v1/projects
-echo 正在创建项目...
-curl -X POST http://localhost:3001/api/v1/projects -H "Content-Type: application/json" -d "{\"name\":\"API测试项目\",\"background\":\"这是通过脚本创建的测试项目\",\"researchType\":\"observational\"}"
-if errorlevel 1 (
- echo.
- echo ❌ 创建项目失败
-) else (
- echo.
- echo ✅ 创建项目成功
-)
-echo.
-echo ----------------------------------------
-echo.
-
-echo [测试5] 前端服务检查
-echo URL: http://localhost:3000
-curl -s http://localhost:3000 >nul 2>&1
-if errorlevel 1 (
- echo ❌ 前端服务未响应
- echo 解决方案: cd frontend ^&^& npm run dev
-) else (
- echo ✅ 前端服务正常
-)
-echo.
-
-:end
-echo ========================================
-echo 测试完成
-echo ========================================
-echo.
-echo 如果所有测试都通过,但浏览器仍有问题:
-echo 1. 按 Ctrl + Shift + R 强制刷新浏览器
-echo 2. 查看浏览器控制台(F12)的错误信息
-echo 3. 查看解决方案-前端获取数据失败.md
-echo.
-pause
-
-
-
-
diff --git a/测试和启动.md b/测试和启动.md
deleted file mode 100644
index e805b1ac..00000000
--- a/测试和启动.md
+++ /dev/null
@@ -1,202 +0,0 @@
-# 系统启动和测试指南
-
-## 🚀 快速启动
-
-### 1. 启动后端服务
-
-**打开第一个终端:**
-```powershell
-cd d:\MyCursor\AIclinicalresearch\backend
-npm run dev
-```
-
-**预期输出:**
-```
-🚀 AI临床研究平台 - 后端服务器启动成功!
-📍 服务地址: http://localhost:3001
-🔍 健康检查: http://localhost:3001/health
-```
-
-**如果报错,检查:**
-- ✅ PostgreSQL是否运行?(Docker: `docker ps`)
-- ✅ Redis是否运行?(Docker: `docker ps`)
-- ✅ `.env`文件是否配置了API Keys?
-
----
-
-### 2. 启动前端服务
-
-**打开第二个终端:**
-```powershell
-cd d:\MyCursor\AIclinicalresearch\frontend
-npm run dev
-```
-
-**预期输出:**
-```
- VITE v6.x.x ready in xxx ms
-
- ➜ Local: http://localhost:3000/
- ➜ Network: use --host to expose
-```
-
----
-
-### 3. 访问系统
-
-打开浏览器访问:**http://localhost:3000/**
-
----
-
-## 🔧 常见问题排查
-
-### 问题1:获取项目列表失败
-
-**原因:** 后端服务未启动或数据库连接失败
-
-**解决方案:**
-1. 检查后端是否启动:访问 http://localhost:3001/health
-2. 检查数据库是否运行:
- ```powershell
- docker ps
- # 应该看到postgres和redis容器在运行
- ```
-3. 如果数据库未启动:
- ```powershell
- cd d:\MyCursor\AIclinicalresearch
- docker-compose up -d
- ```
-
----
-
-### 问题2:创建项目失败(500错误)
-
-**原因:** 数据库表未创建或后端代码错误
-
-**解决方案:**
-
-**步骤1:检查数据库表是否存在**
-```powershell
-cd d:\MyCursor\AIclinicalresearch\backend
-npx prisma studio
-# 打开Prisma Studio,检查是否有Project表
-```
-
-**步骤2:如果表不存在,运行迁移**
-```powershell
-cd d:\MyCursor\AIclinicalresearch\backend
-npx prisma migrate dev
-```
-
-**步骤3:查看后端日志**
-- 在运行`npm run dev`的终端中查看错误日志
-- 通常会显示具体的错误原因
-
----
-
-### 问题3:API请求404
-
-**原因:** 代理配置或路由问题
-
-**检查清单:**
-1. ✅ 后端启动在3001端口
-2. ✅ 前端启动在3000端口
-3. ✅ `vite.config.ts`中配置了代理
-4. ✅ API路由正确注册
-
----
-
-## 📋 完整启动检查清单
-
-### 前置条件
-- [ ] Docker Desktop已安装并运行
-- [ ] Node.js已安装(v18+)
-- [ ] PostgreSQL容器已启动
-- [ ] Redis容器已启动
-- [ ] 后端依赖已安装(`npm install`)
-- [ ] 前端依赖已安装(`npm install`)
-- [ ] 后端`.env`文件已配置API Keys
-- [ ] 数据库迁移已完成(`prisma migrate dev`)
-
-### 启动顺序
-1. [ ] 启动Docker容器(PostgreSQL + Redis)
-2. [ ] 启动后端服务(3001端口)
-3. [ ] 启动前端服务(3000端口)
-4. [ ] 访问浏览器测试
-
----
-
-## 🧪 测试流程
-
-### 1. 测试后端健康检查
-```powershell
-# 在浏览器或使用curl
-curl http://localhost:3001/health
-```
-
-**预期响应:**
-```json
-{
- "status": "ok",
- "database": "connected",
- "timestamp": "2025-10-10T..."
-}
-```
-
-### 2. 测试获取智能体列表
-```powershell
-curl http://localhost:3001/api/v1/agents
-```
-
-**预期响应:**
-```json
-{
- "success": true,
- "data": [
- {
- "id": "topic-evaluation",
- "name": "选题评价智能体",
- ...
- }
- ]
-}
-```
-
-### 3. 测试前端页面
-1. 访问 http://localhost:3000/
-2. 应该看到首页和12个智能体卡片
-3. 创建新项目
-4. 选择"选题评价智能体"进入对话
-
----
-
-## 💡 调试技巧
-
-### 查看后端日志
-后端使用Pino日志,启动时会显示所有请求和错误
-
-### 查看前端控制台
-按F12打开开发者工具,查看:
-- Console:JavaScript错误
-- Network:API请求状态
-
-### 查看数据库
-```powershell
-cd d:\MyCursor\AIclinicalresearch\backend
-npx prisma studio
-# 在浏览器中查看和编辑数据库内容
-```
-
----
-
-## 🆘 获取帮助
-
-如果以上方法都无法解决问题,请提供:
-1. 后端终端的完整日志
-2. 前端浏览器控制台的错误信息
-3. 访问 http://localhost:3001/health 的响应
-4. `docker ps` 的输出
-
-
-
-
diff --git a/测试记录/2025-10-13-首次测试.md b/测试记录/2025-10-13-首次测试.md
deleted file mode 100644
index f6547add..00000000
--- a/测试记录/2025-10-13-首次测试.md
+++ /dev/null
@@ -1,384 +0,0 @@
-# Phase 2 测试记录 - 首次测试
-
-**测试日期**:2025-10-13
-**测试人员**:用户
-**测试类型**:快速测试(部分功能)
-**测试耗时**:约10分钟(已暂停,待修复验证)
-
----
-
-## 📊 测试信息
-
-### 测试环境
-- Python微服务:✅ 已启动(假设)
-- Backend服务:✅ 已启动(假设)
-- Frontend服务:✅ 已启动
-- 测试知识库:✅ 已准备(假设)
-
-### 测试范围
-- [x] 智能问答页面访问
-- [x] 知识库模式选择
-- [x] 知识库选择
-- [x] 全文阅读模式切换
-- [ ] 容量指示器显示(未达到)
-- [ ] 文献综述测试(未达到)
-- [ ] 逐篇精读模式(未测试)
-
----
-
-## 🐛 发现的问题
-
-### 问题1:全文阅读模式加载失败 🔴
-
-**严重等级**:🔴 严重(阻断性)
-**状态**:✅ 已修复
-
-**详细信息**:见 [问题清单.md](./问题清单.md) - 问题1
-
-**测试步骤**:
-1. 访问:http://localhost:3000/chat
-2. 选择:"知识库模式"
-3. 选择知识库:[知识库名称]
-4. 点击:"全文阅读"模式
-5. **结果**:❌ 报错"加载文档选择失败"
-
-**Console错误**:
-```
-Failed to load document selection: TypeError: Cannot read properties of undefined (reading 'maxFiles')
- at loadFullTextData (ChatPage.tsx:76:35)
-```
-
-**修复方案**:
-- 修改了 `frontend/src/api/knowledgeBaseApi.ts`
-- 将 `return response.data` 改为 `return response.data.data`
-
-**验证计划**:
-- [ ] 重启Frontend服务
-- [ ] 重新执行测试步骤
-- [ ] 验证能正常显示容量指示器
-
----
-
-### 问题2:全文阅读模式无法找到对话输入框 🔴
-
-**严重等级**:🔴 严重(阻断性)
-**状态**:✅ 已修复
-
-**详细信息**:见 [问题清单.md](./问题清单.md) - 问题2
-
-**测试步骤**:
-1. 修复问题1后重新测试全文阅读模式
-2. 页面能显示容量指示器和文献列表
-3. **结果**:❌ 找不到对话输入框,无法与AI交流
-
-**问题原因**:
-- FullTextMode组件缺少外层flex容器
-- 导致组件高度塌缩,输入框不可见
-
-**修复方案**:
-- 修改了 `frontend/src/pages/ChatPage.tsx` 第294-305行
-- 为FullTextMode添加外层flex容器:``
-- 同时对逐篇精读模式应用相同修复
-
-**验证计划**:
-- [ ] 重启Frontend服务
-- [ ] 验证全文阅读模式能看到底部输入框
-- [ ] 验证逐篇精读模式能看到底部输入框
-
----
-
-### 问题3:逐篇精读模式React Hooks调用错误 🔴
-
-**严重等级**:🔴 严重(阻断性)
-**状态**:✅ 已修复
-
-**详细信息**:见 [问题清单.md](./问题清单.md) - 问题3
-
-**测试步骤**:
-1. 选择知识库 → 选择"逐篇精读"模式
-2. 在弹出的文献选择器中选择文献
-3. 点击"确认"按钮
-4. **结果**:❌ 控制台报React Hooks错误
-
-**Console错误**:
-```
-Uncaught Error: Invalid hook call. Hooks can only be called inside of the body of a function component.
- at useDeepReadState (useDeepReadState.ts:10:43)
- at handleConfirmDocSelection (ChatPage.tsx:105:22)
-```
-
-**问题原因**:
-- 违反React Hooks规则
-- 在事件处理器`handleConfirmDocSelection`中直接调用了`useDeepReadState` Hook
-- Hook只能在组件顶层调用
-
-**修复方案**:
-- 修改了 `frontend/src/pages/ChatPage.tsx` 多处:
- 1. 第43-46行:在组件顶层调用`useDeepReadState([])`
- 2. 第104-118行:使用Hook返回的`updateSelectedDocs`方法
- 3. 全文替换所有`deepReadState`为`deepReadHook`
-
-**验证计划**:
-- [ ] 重启Frontend服务
-- [ ] 验证逐篇精读模式能正常选择文献
-- [ ] 验证能进入精读模式并正常对话
-- [ ] 验证文献切换功能正常
-
----
-
-### 问题4:消息列表事件监听器错误 🔴
-
-**严重等级**:🔴 严重(阻断性)
-**状态**:✅ 已修复
-
-**详细信息**:见 [问题清单.md](./问题清单.md) - 问题4
-
-**测试步骤**:
-1. 修复问题1、2、3后重启测试
-2. 进入全文阅读模式
-3. 输入问题并点击发送
-4. **结果**:❌ 页面卡住,控制台报错
-
-**Console错误**:
-```
-Uncaught TypeError: Cannot read properties of undefined (reading 'contains')
- at HTMLDocument.handleCitationMouseEnter (MessageList.tsx:71:28)
-
-Uncaught TypeError: Cannot read properties of undefined (reading 'contains')
- at HTMLDocument.handleCitationMouseLeave (MessageList.tsx:79:28)
-```
-
-**问题原因**:
-- MessageList的事件监听器绑定在document上
-- 鼠标事件的target可能是非Element节点
-- 直接访问`classList.contains()`导致错误
-
-**修复方案**:
-- 修改了 `frontend/src/components/chat/MessageList.tsx`
-- 在三个事件处理器中添加`target.classList`存在性检查
-- `if (target.classList && target.classList.contains('citation-badge'))`
-
-**验证计划**:
-- [ ] 重启Frontend服务
-- [ ] 全文阅读模式发送消息
-- [ ] 验证消息正常显示,不再卡住
-
----
-
-### 问题5:全文阅读模式Header占据过多空间 🔴
-
-**严重等级**:🔴 严重(阻断性)
-**状态**:✅ 已修复
-
-**详细信息**:见 [问题清单.md](./问题清单.md) - 问题5
-
-**测试步骤**:
-1. 修复前面问题后继续测试
-2. 进入全文阅读模式
-3. **结果**:❌ 只能看到输入框和Header,看不到聊天消息区域
-
-**问题原因**:
-- FullTextModeHeader包含容量指示器和已加载文献列表
-- 当文献很多时,Header占据大部分屏幕空间
-- CSS没有限制Header的最大高度
-- 聊天消息区域被挤压,看不见
-
-**修复方案**:
-- 修改了 `frontend/src/components/chat/FullTextModeHeader.css`
-- 添加`flex-shrink: 0`(防止被压缩)
-- 添加`max-height: 40vh`(最大高度为屏幕40%)
-- 添加`overflow-y: auto`(超出部分滚动)
-
-**验证计划**:
-- [ ] 重启Frontend服务
-- [ ] 全文阅读模式发送消息
-- [ ] 验证Header不会占据过多空间
-- [ ] 验证能看到聊天消息
-- [ ] 验证文献列表如果太长会出现滚动条
-
----
-
-## ✅ 测试结果
-
-### 功能测试(部分完成)
-
-| 功能模块 | 状态 | 备注 |
-|---------|------|------|
-| 页面访问 | ✅ 通过 | 智能问答页面正常加载 |
-| 模式选择 | ✅ 通过 | 知识库模式选择正常 |
-| 知识库选择 | ✅ 通过 | 下拉列表正常显示 |
-| 全文阅读-加载 | ✅ 已修复 | 问题1(API数据结构)已修复 |
-| 全文阅读-布局 | ✅ 已修复 | 问题2(输入框容器)已修复 |
-| 全文阅读-Header | ✅ 已修复 | 问题5(Header高度)已修复 |
-| 全文阅读-消息 | ✅ 已修复 | 问题4(事件监听器)已修复 |
-| 逐篇精读-选择 | ✅ 已修复 | 问题3(Hooks调用)已修复 |
-| 逐篇精读-布局 | ✅ 已修复 | 问题2(输入框容器)已修复 |
-| 容量指示器 | ⏳ 待验证 | 需重启验证修复效果 |
-| 文献综述对话 | ⏳ 待验证 | 需重启验证功能完整性 |
-| 文献切换功能 | ⏳ 待验证 | 需重启验证功能完整性 |
-
-### 性能测试(未执行)
-_因功能问题未能执行性能测试_
-
----
-
-## 📝 测试笔记
-
-### 测试流程
-1. 用户按照Phase 2快速测试清单开始测试
-2. 在"测试A:全文阅读模式"步骤发现问题1(API数据结构)
-3. AI助手快速分析并修复问题1
-4. 用户继续测试,发现问题2(找不到输入框)
-5. 同时发现问题3(逐篇精读Hooks错误)
-6. AI助手一次性修复问题2和问题3
-7. 更新测试记录和问题清单
-
-### 问题分析过程
-
-**问题1:API数据结构错误**
-1. 查看Console错误:`Cannot read properties of undefined (reading 'maxFiles')`
-2. 定位到ChatPage.tsx第76行
-3. 检查API返回数据结构
-4. 发现API层返回了多余的一层包装
-5. 修改`knowledgeBaseApi.ts`返回`response.data.data`
-
-**问题2:布局容器缺失**
-1. 用户反馈:能看到容量指示器但找不到输入框
-2. 检查FullTextMode组件结构
-3. 发现缺少外层flex容器
-4. 为FullTextMode添加flex容器包裹
-
-**问题3:React Hooks错误**
-1. 用户报错:`Invalid hook call`
-2. 定位到`handleConfirmDocSelection`函数
-3. 发现在事件处理器中调用了Hook
-4. 重构:在组件顶层调用Hook,事件处理器中使用Hook返回的方法
-
-**问题4:DOM事件监听器错误**
-1. 用户反馈:发送消息后页面卡住
-2. 查看Console错误:`Cannot read properties of undefined (reading 'contains')`
-3. 定位到MessageList的事件处理器
-4. 发现没有检查target是否有classList属性
-5. 添加`target.classList`存在性检查
-
-**问题5:Header占据过多空间**
-1. 用户反馈:只能看到输入框,看不到聊天消息
-2. 检查FullTextMode布局结构
-3. 发现Header没有高度限制,文献列表很长时占据大部分空间
-4. 添加`max-height: 40vh`和`overflow-y: auto`
-
-### 经验教训
-1. **API数据结构一致性很重要**
- - Backend和Frontend对数据结构的理解要一致
- - 应该有明确的类型定义
-
-2. **React基础规则必须严格遵守**
- - Hooks只能在组件顶层调用
- - 违反规则会导致运行时错误
-
-3. **布局设计需要完整**
- - Flex布局中子元素需要正确设置flex属性
- - 高度塌缩问题很隐蔽,容易遗漏
- - 容器需要设置高度限制,防止内容过多时挤占其他区域
-
-4. **DOM事件处理需要防御性编程**
- - 事件监听器绑定在document上时,target可能是任何节点
- - 必须检查target的属性是否存在再使用
- - TypeScript的类型断言不能保证运行时安全
-
-5. **测试工具有效**
- - 快速测试清单帮助快速发现问题
- - Console错误信息准确定位问题
- - 迭代测试能持续发现深层问题
-
-6. **问题修复流程完善**
- - 从发现到修复约45分钟(5个严重问题)
- - 问题记录清晰完整
- - 修复后需要继续测试验证
-
----
-
-## 🎯 下一步计划
-
-### 立即行动(用户需执行)
-1. **重启Frontend服务**
- ```bash
- # 在Frontend窗口
- Ctrl + C # 停止当前服务
- npm run dev # 重新启动
- ```
-
-2. **验证3个问题的修复**
- - **问题1验证**:全文阅读模式能正常加载,显示容量指示器
- - **问题2验证**:全文阅读模式底部能看到对话输入框
- - **问题3验证**:逐篇精读模式能正常选择文献并进入精读模式
-
-3. **继续完整测试**
- - 完成全文阅读模式完整测试(对话、引用、Token显示)
- - 完成逐篇精读模式完整测试(文献切换、对话历史)
- - 测试端到端场景(文献综述 → 精读切换)
- - 测试文献切换功能
-
-### 后续计划
-- 完成快速测试清单(预计还需20分钟)
-- 记录所有发现的问题
-- 做出验收决策
-
----
-
-## 📊 测试进度
-
-```
-Phase 2测试进度:约20%
-
-✅ 已完成:
- - 环境准备
- - 页面基础功能
- - 发现1个严重问题并修复
-
-⏳ 进行中:
- - 等待修复验证
-
-⏸️ 待测试:
- - 全文阅读模式(剩余部分)
- - 逐篇精读模式
- - 端到端场景
-```
-
----
-
-## 🎊 测试评价
-
-### 工具效果
-- ✅ 快速测试清单:有效,帮助快速发现问题
-- ✅ 问题记录模板:清晰,便于追踪
-- ✅ 修复流程:高效,问题快速解决
-
-### 系统质量
-- ⚠️ **代码质量**:存在数据结构访问错误
-- ✅ **错误提示**:Console错误信息准确
-- ⏳ **功能完整性**:待继续验证
-
-### 建议
-1. 增加TypeScript类型定义,减少运行时错误
-2. 增加API数据验证,提前发现数据问题
-3. 在开发阶段进行更充分的自测
-
----
-
-## 📞 联系信息
-
-**测试人员**:[用户]
-**问题报告**:已创建问题清单文档
-**修复记录**:已记录在问题清单中
-
----
-
-**测试状态**:⏸️ 暂停(等待修复验证)
-**下次测试**:验证修复 + 继续完整测试
-
----
-
-**最后更新**:2025-10-13
-**维护者**:测试团队
-
diff --git a/测试记录/问题清单.md b/测试记录/问题清单.md
deleted file mode 100644
index f1124dc9..00000000
--- a/测试记录/问题清单.md
+++ /dev/null
@@ -1,1052 +0,0 @@
-# Phase 2 测试问题清单
-
-**创建时间**:2025-10-13
-**测试阶段**:Phase 2验证测试
-
----
-
-## 🔴 严重问题(阻断性)
-
-### ❌ 问题1:全文阅读模式加载失败 - 已修复 ✅
-
-**发现时间**:2025-10-13
-**严重等级**:🔴 严重(阻断核心功能)
-**状态**:✅ 已修复
-
-#### 问题描述
-在智能问答页面选择知识库并切换到"全文阅读模式"时,页面报错:
-```
-加载文档选择失败
-```
-
-#### 错误信息
-```
-Failed to load document selection: TypeError: Cannot read properties of undefined (reading 'maxFiles')
- at loadFullTextData (ChatPage.tsx:76:35)
-```
-
-#### 问题原因
-**API数据结构访问层级错误**
-
-Backend返回的数据结构:
-```javascript
-{
- success: true,
- data: {
- limits: { maxFiles: 50, maxTokens: 980000 },
- selection: { ... },
- selectedDocuments: [...]
- }
-}
-```
-
-Frontend的`documentSelectionApi.getSelection()`返回的是`response.data`(整个对象),而不是`response.data.data`(内层数据)。
-
-导致在ChatPage.tsx中访问`result.limits`时,实际访问的是:
-```javascript
-{ success: true, data: {...} }.limits // undefined!
-```
-
-#### 修复方案
-修改 `frontend/src/api/knowledgeBaseApi.ts` 第208行:
-
-**修改前**:
-```typescript
-return response.data;
-```
-
-**修改后**:
-```typescript
-return response.data.data; // 返回内层的data对象
-```
-
-#### 影响范围
-- ✅ 全文阅读模式功能
-- ⚠️ 可能影响其他使用该API的地方(需验证)
-
-#### 复现步骤
-1. 进入智能问答页面
-2. 选择"知识库模式"
-3. 选择一个知识库
-4. 点击"全文阅读"模式
-5. 观察:报错"加载文档选择失败"
-
-#### 验证步骤
-1. 应用代码修改
-2. 重启Frontend服务(Ctrl+C,然后`npm run dev`)
-3. 重复复现步骤
-4. 预期:能正常加载文档选择结果,显示容量指示器
-
-#### 相关文件
-- ✅ `frontend/src/api/knowledgeBaseApi.ts` - 已修复
-- ⚠️ `frontend/src/pages/ChatPage.tsx` - 调用方(无需修改)
-
-#### 测试人员
-[测试人员姓名]
-
-#### 修复人员
-AI助手
-
----
-
-### ❌ 问题2:全文阅读模式无法找到对话输入框 - 已修复 ✅
-
-**发现时间**:2025-10-13
-**严重等级**:🔴 严重(阻断核心功能)
-**状态**:✅ 已修复
-
-#### 问题描述
-在全文阅读模式下,能够正常显示容量指示器和已加载文献列表,但是找不到对话输入框,无法与AI进行交流。
-
-#### 问题原因
-**布局容器缺失**
-
-`FullTextMode`组件缺少外层flex容器:
-- 页面主布局使用了flex,子元素需要设置`flex: 1`来占据剩余空间
-- `FullTextMode`直接返回,没有外层包裹div设置flex属性
-- 导致组件高度塌缩,底部的输入框被挤出可视区域或不可见
-
-#### 修复方案
-修改 `frontend/src/pages/ChatPage.tsx` 第294-305行:
-
-**修改前**:
-```typescript
-return (
-
-)
-```
-
-**修改后**:
-```typescript
-return (
-
-
-
-)
-```
-
-同时对逐篇精读模式应用相同修复(第318-336行)。
-
-#### 影响范围
-- ✅ 全文阅读模式的对话功能
-- ✅ 逐篇精读模式的对话功能(预防性修复)
-
-#### 复现步骤
-1. 进入智能问答页面
-2. 选择"知识库模式"
-3. 选择一个知识库
-4. 点击"全文阅读"模式
-5. 观察:能看到容量指示器,但找不到输入框
-
-#### 验证步骤
-1. 应用代码修改
-2. 重启Frontend服务
-3. 重复复现步骤
-4. 预期:页面底部显示对话输入框,可以正常输入和发送消息
-
-#### 相关文件
-- ✅ `frontend/src/pages/ChatPage.tsx` - 已修复
-
-#### 修复人员
-AI助手
-
----
-
-### ❌ 问题3:逐篇精读模式React Hooks调用错误 - 已修复 ✅
-
-**发现时间**:2025-10-13
-**严重等级**:🔴 严重(阻断核心功能)
-**状态**:✅ 已修复
-
-#### 问题描述
-在逐篇精读模式下,选择文献后点击"确认"按钮时,页面报错无法继续。
-
-#### 错误信息
-```
-Uncaught Error: Invalid hook call. Hooks can only be called inside of the body of a function component.
-This could happen for one of the following reasons:
-1. You might have mismatching versions of React and the renderer (such as React DOM)
-2. You might be breaking the Rules of Hooks
-3. You might have more than one copy of React in the same app
- at Object.throwInvalidHookError (react-dom.development.js:15408:9)
- at useState (react.development.js:1622:21)
- at useDeepReadState (useDeepReadState.ts:10:43)
- at handleConfirmDocSelection (ChatPage.tsx:105:22)
-```
-
-#### 问题原因
-**违反React Hooks规则**
-
-在事件处理器中直接调用了Hook:
-
-```typescript
-const handleConfirmDocSelection = (selectedDocs: Document[]) => {
- const deepRead = useDeepReadState(selectedDocs) // ❌ 错误:不能在事件处理器中调用Hook
- setDeepReadState(deepRead as any)
- ...
-}
-```
-
-React Hooks只能在组件顶层调用,不能在:
-- 事件处理器中
-- 条件语句中
-- 循环中
-- 嵌套函数中
-
-#### 修复方案
-修改 `frontend/src/pages/ChatPage.tsx` 的多个位置:
-
-**1. 第43-46行:在组件顶层调用Hook**
-
-修改前:
-```typescript
-const [deepReadState, setDeepReadState] = useState
| null>(null)
-```
-
-修改后:
-```typescript
-const deepReadHook = useDeepReadState([]) // ✅ 在组件顶层调用
-```
-
-**2. 第104-118行:使用Hook返回的方法**
-
-修改前:
-```typescript
-const handleConfirmDocSelection = (selectedDocs: Document[]) => {
- const deepRead = useDeepReadState(selectedDocs) // ❌ 错误
- setDeepReadState(deepRead as any)
- ...
-}
-```
-
-修改后:
-```typescript
-const handleConfirmDocSelection = (selectedDocs: Document[]) => {
- deepReadHook.updateSelectedDocs(selectedDocs) // ✅ 调用Hook返回的方法
- ...
-}
-```
-
-**3. 全文替换:所有`deepReadState`改为`deepReadHook`**
-- 第184-235行:`handleSendDeepReadMessage`函数
-- 第310-336行:渲染逐篇精读模式
-
-#### 影响范围
-- ✅ 逐篇精读模式的文献选择功能
-- ✅ 逐篇精读模式的对话功能
-- ✅ 文献切换功能
-
-#### 复现步骤
-1. 进入智能问答页面
-2. 选择"知识库模式"
-3. 选择一个知识库
-4. 点击"逐篇精读"模式
-5. 在弹出的文献选择器中选择1-5篇文献
-6. 点击"确认"按钮
-7. 观察:控制台报React Hooks错误
-
-#### 验证步骤
-1. 应用代码修改
-2. 重启Frontend服务
-3. 重复复现步骤
-4. 预期:文献选择器关闭,进入逐篇精读模式,能正常对话
-
-#### 相关文件
-- ✅ `frontend/src/pages/ChatPage.tsx` - 已修复
-- ⚠️ `frontend/src/hooks/useDeepReadState.ts` - Hook定义(无需修改)
-
-#### 修复人员
-AI助手
-
----
-
-### ❌ 问题4:消息列表事件监听器错误 - 已修复 ✅
-
-**发现时间**:2025-10-13
-**严重等级**:🔴 严重(阻断核心功能)
-**状态**:✅ 已修复
-
-#### 问题描述
-在全文阅读模式下发送消息后,页面卡住,浏览器控制台报错。
-
-#### 错误信息
-```
-Uncaught TypeError: Cannot read properties of undefined (reading 'contains')
- at HTMLDocument.handleCitationMouseEnter (MessageList.tsx:71:28)
-
-Uncaught TypeError: Cannot read properties of undefined (reading 'contains')
- at HTMLDocument.handleCitationMouseLeave (MessageList.tsx:79:28)
-```
-
-#### 问题原因
-**DOM事件目标类型不安全**
-
-在MessageList组件中,事件监听器绑定在`document`上:
-```typescript
-document.addEventListener('mouseenter', handleCitationMouseEnter, true);
-document.addEventListener('mouseleave', handleCitationMouseLeave, true);
-```
-
-当鼠标移动时,`e.target`可能是:
-- 非Element节点(如Document、Text节点)
-- 没有`classList`属性的对象
-
-直接访问`target.classList.contains()`会导致错误。
-
-#### 修复方案
-修改 `frontend/src/components/chat/MessageList.tsx` 的三个事件处理器:
-
-**1. handleCitationClick (第47-67行)**
-```typescript
-// 修复前
-const target = e.target as HTMLElement;
-if (target.classList.contains('citation-badge')) {
- ...
-}
-
-// 修复后
-const target = e.target as HTMLElement;
-if (target.classList && target.classList.contains('citation-badge')) {
- ...
-}
-```
-
-**2. handleCitationMouseEnter (第69-76行)**
-```typescript
-// 修复前
-const target = e.target as HTMLElement;
-if (target.classList.contains('citation-badge')) {
- ...
-}
-
-// 修复后
-const target = e.target as HTMLElement;
-if (target.classList && target.classList.contains('citation-badge')) {
- ...
-}
-```
-
-**3. handleCitationMouseLeave (第78-85行)**
-```typescript
-// 修复前
-const target = e.target as HTMLElement;
-if (target.classList.contains('citation-badge')) {
- ...
-}
-
-// 修复后
-const target = e.target as HTMLElement;
-if (target.classList && target.classList.contains('citation-badge')) {
- ...
-}
-```
-
-#### 影响范围
-- ✅ 全文阅读模式的消息显示和交互
-- ✅ 引用标记的点击和悬停效果
-- ✅ 逐篇精读模式的消息显示(同样使用MessageList组件)
-
-#### 复现步骤
-1. 进入全文阅读模式
-2. 输入问题并发送
-3. 观察:页面卡住,控制台报错
-
-#### 验证步骤
-1. 重启Frontend服务
-2. 全文阅读模式发送消息
-3. 预期:消息正常显示,不再报错
-
-#### 相关文件
-- ✅ `frontend/src/components/chat/MessageList.tsx` - 已修复
-
-#### 修复人员
-AI助手
-
----
-
-### ❌ 问题5:全文阅读模式Header占据过多空间 - 已修复 ✅
-
-**发现时间**:2025-10-13
-**严重等级**:🔴 严重(阻断核心功能)
-**状态**:✅ 已修复
-
-#### 问题描述
-在全文阅读模式下,只能看到输入框,聊天消息显示区域被容量指示器和已加载文献列表占据,看不到对话内容。
-
-#### 问题原因
-**Header组件高度未限制**
-
-`FullTextModeHeader`组件包含:
-1. 标题和说明
-2. 容量指示器
-3. 已加载文献列表(可能很长)
-
-当文献列表很长时,Header会占据大部分屏幕空间,导致:
-- 聊天消息区域被压缩
-- 即使有消息也看不见(被挤到Header下方)
-
-Header CSS没有设置:
-- `flex-shrink: 0`(防止被压缩)
-- `max-height`(限制最大高度)
-- `overflow-y: auto`(超出部分滚动)
-
-#### 修复方案
-修改 `frontend/src/components/chat/FullTextModeHeader.css` 第3-6行:
-
-**修改前**:
-```css
-.fulltext-header {
- padding: 20px;
- background: #fff;
- border-bottom: 1px solid #e8e8e8;
-}
-```
-
-**修改后**:
-```css
-.fulltext-header {
- padding: 20px;
- background: #fff;
- border-bottom: 1px solid #e8e8e8;
- flex-shrink: 0;
- max-height: 40vh;
- overflow-y: auto;
-}
-```
-
-#### 影响范围
-- ✅ 全文阅读模式的空间分配
-- ✅ 聊天消息的可见性
-- ✅ 整体用户体验
-
-#### 复现步骤
-1. 进入全文阅读模式
-2. 如果知识库有很多文献,Header会很大
-3. 观察:看不到聊天消息区域
-
-#### 验证步骤
-1. 重启Frontend服务
-2. 进入全文阅读模式
-3. 预期:
- - Header最大高度为屏幕的40%
- - 文献列表如果超出会显示滚动条
- - 聊天消息区域能正常显示
- - 发送消息后能看到对话内容
-
-#### 相关文件
-- ✅ `frontend/src/components/chat/FullTextModeHeader.css` - 已修复
-
-#### 修复人员
-AI助手
-
----
-
-### ⭐ 优化6:全文阅读模式UI优化(用户反馈)- 已完成 ✅
-
-**发现时间**:2025-10-13
-**严重等级**:🟡 中等(用户体验优化)
-**状态**:✅ 已完成
-
-#### 问题描述
-用户反馈:容量使用情况和已加载文献显示在聊天框上方,非常影响聊天框的高度,导致聊天框太小。
-
-#### 用户建议
-在最上边AI模型选择旁边加一个"用量说明"按钮,点击后弹框显示。默认只显示聊天框,让聊天框面积尽可能大。
-
-#### 优化方案
-**1. 移除FullTextMode的顶部Header**
-- 移除`FullTextModeHeader`组件的引用
-- 直接显示聊天消息列表,最大化聊天区域
-- 在空状态提示中添加"点击右上角'用量说明'按钮查看详细信息"
-
-**2. 创建UsageInfoModal模态框组件**
-- 新建`UsageInfoModal.tsx`和`UsageInfoModal.css`
-- 包含完整的容量指示器、已加载文献列表、使用提示
-- 使用Ant Design的Modal组件,宽度700px
-- 文献列表最大高度300px,超出滚动
-
-**3. 在顶部工具栏添加"用量说明"按钮**
-- 在模型选择器左侧添加按钮
-- 仅在全文阅读模式下显示
-- 使用`InfoCircleOutlined`图标
-- Tooltip提示"查看容量使用情况和已加载文献"
-
-#### 修改文件清单
-- ✅ 新建:`frontend/src/components/chat/UsageInfoModal.tsx`
-- ✅ 新建:`frontend/src/components/chat/UsageInfoModal.css`
-- ✅ 修改:`frontend/src/components/chat/FullTextMode.tsx` - 移除Header,简化为纯聊天界面
-- ✅ 修改:`frontend/src/components/chat/FullTextMode.css` - 添加empty-hint样式
-- ✅ 修改:`frontend/src/pages/ChatPage.tsx` - 添加用量说明按钮和模态框
-
-#### 优化效果
-**聊天区域**:
-- 从原来的~30-40%屏幕高度(被Header占据) → 扩大到~85%屏幕高度
-- 用户可以看到更多对话历史
-- 聊天体验更流畅
-
-**用量信息**:
-- 不再默认占据空间
-- 需要时点击按钮查看
-- 弹框设计更专业、信息更完整
-- 文献列表可以滚动,支持查看更多文献
-
-#### 用户体验提升
-1. **视觉焦点明确**:主界面专注于对话,不被额外信息干扰
-2. **信息层级清晰**:常用功能(对话)优先,辅助信息(用量)按需查看
-3. **空间利用优化**:聊天区域扩大2-3倍
-4. **专业感提升**:模态框设计符合现代UI规范
-
-#### 验证步骤
-1. 重启Frontend服务
-2. 进入全文阅读模式
-3. 预期:
- - 聊天框占据大部分屏幕空间
- - 顶部工具栏有"用量说明"按钮
- - 点击按钮弹出详细信息模态框
- - 模态框显示容量指示器、文献列表、使用提示
-
-#### 相关文件
-- ✅ `frontend/src/components/chat/UsageInfoModal.tsx` - 新建
-- ✅ `frontend/src/components/chat/UsageInfoModal.css` - 新建
-- ✅ `frontend/src/components/chat/FullTextMode.tsx` - 已优化
-- ✅ `frontend/src/components/chat/FullTextMode.css` - 已优化
-- ✅ `frontend/src/pages/ChatPage.tsx` - 已优化
-
-#### 优化人员
-AI助手
-
----
-
-### ❌ 问题7:逐篇精读模式文献来源错误 - 已修复 ✅
-
-**发现时间**:2025-10-13
-**严重等级**:🔴 严重(核心功能错误)
-**状态**:✅ 已修复
-
-#### 问题描述
-在逐篇精读模式下,AI回答的文献来源不仅包含当前正在精读的文献,还包含了知识库中的其他文献。这违背了"逐篇精读"的核心价值 - 只分析当前选中的这一篇文献。
-
-#### 问题原因
-**API未限定文档范围**
-
-前端在调用API时:
-- 只传递了`knowledgeBaseIds`(整个知识库)
-- 没有传递`documentIds`(当前文档)
-
-后端在检索知识库时:
-- 调用Dify RAG检索整个知识库
-- 没有过滤出当前文档的结果
-
-导致:
-- Dify返回整个知识库的相关片段
-- AI基于所有文献回答,不是只基于当前文献
-
-#### 修复方案
-
-**1. 后端添加文档过滤**
-
-修改 `backend/src/controllers/chatController.ts`:
-
-**1.1 添加documentIds参数**(第66-72行)
-```typescript
-interface SendChatMessageBody {
- content: string;
- modelType: ModelType;
- knowledgeBaseIds?: string[];
- documentIds?: string[]; // Phase 2: 逐篇精读模式 - 限定文档范围
- conversationId?: string;
-}
-```
-
-**1.2 接收和记录documentIds**(第90-98行)
-```typescript
-const { content, modelType, knowledgeBaseIds, documentIds, conversationId } = request.body;
-
-console.log('💬 [ChatController] 收到通用对话请求', {
- content,
- modelType,
- knowledgeBaseIds: knowledgeBaseIds || [],
- documentIds: documentIds || [],
- conversationId,
-});
-```
-
-**1.3 添加文档过滤逻辑**(第145-244行)
-
-核心逻辑:
-```typescript
-// 如果指定了documentIds,增加检索数量用于过滤
-const topK = documentIds && documentIds.length > 0 ? 50 : 15;
-
-// 检索知识库
-const searchResult = await knowledgeBaseService.searchKnowledgeBase(userId, kbId, content, topK);
-
-// 如果是逐篇精读模式,过滤结果
-if (documentIds && documentIds.length > 0) {
- // 1. 查询文档的Dify ID
- const documents = await prisma.document.findMany({
- where: {
- id: { in: documentIds },
- knowledgeBase: { id: kbId },
- },
- select: { difyDocumentId: true },
- });
-
- const difyDocIds = documents.map(d => d.difyDocumentId).filter(Boolean);
-
- // 2. 过滤出属于指定文档的结果
- records = records.filter((record: any) => {
- const docId = record.segment?.document?.id || record.document_id;
- return docId && difyDocIds.includes(docId);
- });
-
- // 3. 只取前15个
- records = records.slice(0, 15);
-}
-```
-
-**2. 前端传递文档ID**
-
-修改 `frontend/src/api/chatApi.ts`(第25-31行):
-```typescript
-export interface SendChatMessageData {
- content: string
- modelType: string
- knowledgeBaseIds?: string[]
- documentIds?: string[] // Phase 2: 逐篇精读模式 - 限定文档范围
- conversationId?: string
-}
-```
-
-修改 `frontend/src/pages/ChatPage.tsx`(第187-212行):
-```typescript
-await chatApi.sendMessageStream(
- {
- content: `[当前文献: ${deepReadHook.currentDoc.filename}]\n\n${content}`,
- modelType: selectedModel,
- knowledgeBaseIds: modeState.selectedKbId ? [modeState.selectedKbId] : [],
- documentIds: [deepReadHook.currentDoc.id], // ✅ 只检索当前文档
- },
- ...
-)
-```
-
-#### 技术细节
-
-**为什么增加topK到50?**
-- Dify检索时返回50个结果
-- 过滤后可能只剩10-20个属于当前文档
-- 确保最终有足够的相关内容给AI参考
-
-**过滤逻辑的关键**:
-1. 从数据库查询文档的`difyDocumentId`
-2. 检查检索结果的`segment.document.id`
-3. 只保留匹配的结果
-
-**日志输出**:
-```
-🔍 [ChatController] 逐篇精读模式 - 过滤文档 { documentIds: ['doc-123'] }
-📄 [ChatController] 目标Dify文档ID: ['dify-doc-456']
-✂️ [ChatController] 过滤结果: 50 → 12
-```
-
-#### 影响范围
-- ✅ 逐篇精读模式的核心功能
-- ✅ 文献来源的准确性
-- ✅ 用户对"逐篇精读"的预期
-
-#### 验证步骤
-1. 重启Backend和Frontend服务
-2. 进入逐篇精读模式
-3. 选择一篇文献(例如:文献A)
-4. 提问:「这篇文献的主要结论是什么?」
-5. 预期:
- - 回答内容只基于文献A
- - 文献来源列表只显示文献A
- - 不会出现其他文献的引用
-
-#### 测试场景
-**场景1:单文献精读**
-- 选择1篇文献
-- 提问后检查文献来源
-- ✅ 应该只有这1篇文献
-
-**场景2:切换文献**
-- 精读文献A后切换到文献B
-- 提问后检查文献来源
-- ✅ 应该只有文献B,不包含文献A
-
-**场景3:知识库有多篇相似文献**
-- 知识库有3篇关于同一主题的文献
-- 选择其中1篇精读
-- 提问后检查
-- ✅ 即使其他文献内容相关,也不应出现在来源中
-
-#### 相关文件
-- ✅ `backend/src/controllers/chatController.ts` - 已修复
-- ✅ `frontend/src/api/chatApi.ts` - 已修复
-- ✅ `frontend/src/pages/ChatPage.tsx` - 已修复
-
-#### 修复人员
-AI助手
-
----
-
-## 🟡 中等问题(影响使用)
-
-_暂无发现_
-
----
-
-## 🟢 轻微问题(不影响主流程)
-
-_暂无发现_
-
----
-
-## 📊 问题统计
-
-| 等级 | 总数 | 已修复 | 待修复 | 修复率 |
-|------|------|--------|--------|--------|
-| 🔴 严重 | 6 | 6 | 0 | 100% |
-| 🟡 中等 | 0 | 0 | 0 | - |
-| 🟢 轻微 | 0 | 0 | 0 | - |
-| ⭐ 优化 | 1 | 1 | 0 | 100% |
-| **总计** | **7** | **7** | **0** | **100%** |
-
----
-
-### ❌ 问题8:全文阅读模式实现偏差(严重架构问题)- 已修复 ✅
-
-**发现时间**:2025-10-13
-**严重等级**:🔴 极严重(核心设计偏差)
-**状态**:✅ 已完全重构
-
-#### 问题描述
-用户反馈:"我感觉在全文阅读模式下,好像也是Dify下的知识库RAG,而不是全部7篇文献的全部文本。"
-
-**经验证,用户的感觉完全正确!**
-
-全文阅读模式的实现与Phase 2的核心设计意图严重偏离:
-
-| 项目 | Phase 2 设计意图 | 之前的实际实现 | 偏差程度 |
-|------|----------------|-------------|---------|
-| **数据来源** | 全文(Full Text) | Dify RAG检索片段 | 🔴 严重 |
-| **传输内容** | 所有选中文献的完整文本(~750K tokens) | 15个检索结果片段(几千tokens) | 🔴 严重 |
-| **工作方式** | 广度优先,全局视野 | RAG检索,局部片段 | 🔴 严重 |
-| **核心价值** | 解决"大模型中间文本不敏感"问题 | 问题依然存在 | 🔴 失效 |
-
-#### 问题原因
-
-**架构设计与实现不一致**
-
-Phase 2的核心设计理念(来自`Phase2-最终技术方案.md`):
-
-> **全文阅读模式**的核心价值是解决"大模型对中间部分文本不敏感"的问题。我们需要将所有选中文献的完整extractedText拼接成一个大context,传递给Qwen-Long(支持1M context)。
-
-但实际实现:
-1. 后端使用`knowledgeBaseService.searchKnowledgeBase()`
-2. 这是Dify的RAG检索,只返回topK=15个片段
-3. 没有使用`extractedText`字段(文档提取的完整文本)
-4. 没有真正实现"全文传输"
-
-导致:
-- ✅ 文档提取服务(PyMuPDF/Nougat/Mammoth)已完美实现
-- ✅ Token精确计数(tiktoken)已完美实现
-- ✅ 智能文档选择算法已完美实现
-- ❌ 但这些功能都没有被真正使用!
-
-#### 修复方案(方案B:实现真正的全文传输)
-
-用户明确选择:**"采用方案B。另外还有3个提醒:1. 在全文阅读模式下,默认选择Qwen Long模型。2. 你在组装全文时,也把各个文献的文件名组装进去。3. 给出的文献来源,应该来自于你的组装全文,通过文件名来标记来源,区分不同的文献。"**
-
-**1. 后端添加fullTextDocumentIds参数**
-
-修改 `backend/src/controllers/chatController.ts`:
-
-**1.1 添加参数**(第71行)
-```typescript
-interface SendChatMessageBody {
- content: string;
- modelType: ModelType;
- knowledgeBaseIds?: string[];
- documentIds?: string[]; // 逐篇精读 - RAG检索过滤
- fullTextDocumentIds?: string[]; // 全文阅读 - 传递完整全文 ✅
- conversationId?: string;
-}
-```
-
-**1.2 全文加载逻辑**(第147-204行)
-```typescript
-// Phase 2: 全文阅读模式 - 传递完整文献全文
-if (fullTextDocumentIds && fullTextDocumentIds.length > 0) {
- console.log('📚 [ChatController] 全文阅读模式 - 加载文献全文');
-
- // 1. 获取所有选中文档的全文
- const documents = await prisma.document.findMany({
- where: { id: { in: fullTextDocumentIds } },
- select: {
- id: true,
- filename: true,
- extractedText: true, // ✅ 关键:使用提取的全文
- tokensCount: true,
- },
- orderBy: { filename: 'asc' },
- });
-
- // 2. 组装全文上下文(包含文件名标记)
- const fullTextParts: string[] = [];
-
- for (let i = 0; i < documents.length; i++) {
- const doc = documents[i];
- const docNumber = i + 1;
-
- // 为每篇文献添加引用信息
- allCitations.push({
- id: docNumber,
- fileName: doc.filename, // ✅ 要求3:文件名标记
- position: 0,
- score: 1.0,
- content: doc.extractedText?.substring(0, 200) || '',
- });
-
- // ✅ 要求2:组装文件名
- fullTextParts.push(
- `【文献${docNumber}:${doc.filename}】\n\n${doc.extractedText || '(该文献无可用文本)'}`
- );
- }
-
- knowledgeBaseContext = fullTextParts.join('\n\n---\n\n');
-
- console.log(`📚 [ChatController] 全文上下文已组装`, {
- totalDocuments: documents.length,
- totalCharacters: knowledgeBaseContext.length,
- totalTokens: documents.reduce((sum, doc) => sum + (doc.tokensCount || 0), 0),
- });
-}
-// RAG检索模式(逐篇精读或通用对话)
-else if (knowledgeBaseIds && knowledgeBaseIds.length > 0) {
- // 原有的RAG检索逻辑
-}
-```
-
-**1.3 优化系统提示词**(第321-326行)
-```typescript
-// 全文阅读模式的系统提示
-if (fullTextDocumentIds && fullTextDocumentIds.length > 0) {
- systemPrompt = '你是一个专业的学术文献分析助手。用户会提供多篇文献的完整全文,每篇文献用【文献N:文件名】标记。请认真阅读所有文献,进行深入的综合分析。在回答时请引用具体文献,使用【文献N】格式。你的优势是能够看到所有文献的全貌,进行跨文献的比较、归纳和总结。';
-}
-```
-
-**1.4 优化用户消息提示**(第340-348行)
-```typescript
-// 全文阅读模式的提示
-if (fullTextDocumentIds && fullTextDocumentIds.length > 0) {
- userContent = `${content}\n\n## 参考资料(文献全文)\n\n**重要提示**:下面提供的是完整的文献全文。每篇文献用【文献N:文件名】标记。请在回答时引用文献,格式如"根据【文献1】..."或"研究表明【文献2】【文献3】..."。你可以综合分析所有文献,进行跨文献的比较和总结。\n\n${knowledgeBaseContext}`;
-}
-```
-
-**2. 前端API更新**
-
-修改 `frontend/src/api/chatApi.ts`:
-
-```typescript
-export interface SendChatMessageData {
- content: string
- modelType: string
- knowledgeBaseIds?: string[]
- documentIds?: string[] // 逐篇精读 - RAG检索
- fullTextDocumentIds?: string[] // 全文阅读 - 完整全文 ✅
- conversationId?: string
-}
-```
-
-**3. 前端自动切换模型**
-
-修改 `frontend/src/pages/ChatPage.tsx`:
-
-**3.1 监听模式变化**(第45-54行)
-```typescript
-// ✅ 要求1:默认选择Qwen-Long模型
-useEffect(() => {
- // 全文阅读模式默认使用Qwen-Long(需要1M上下文)
- if (modeState.baseMode === 'knowledge_base' && modeState.kbMode === 'full_text') {
- if (selectedModel !== 'qwen-long') {
- setSelectedModel('qwen-long')
- antdMessage.info('已自动切换到Qwen-Long模型(支持1M上下文)', 3)
- }
- }
-}, [modeState.baseMode, modeState.kbMode, selectedModel])
-```
-
-**3.2 传递全文文档ID**(第155-173行)
-```typescript
-// 判断是否是全文阅读模式
-const isFullTextMode = modeState.baseMode === 'knowledge_base' && modeState.kbMode === 'full_text'
-const fullTextDocIds = isFullTextMode && modeState.fullTextState?.loadedDocs
- ? modeState.fullTextState.loadedDocs.map(doc => doc.id)
- : undefined
-
-console.log('📤 [ChatPage] 发送消息', {
- mode: isFullTextMode ? '全文阅读' : '通用/RAG',
- fullTextDocCount: fullTextDocIds?.length || 0,
-})
-
-await chatApi.sendMessageStream({
- content,
- modelType: selectedModel,
- knowledgeBaseIds,
- fullTextDocumentIds: fullTextDocIds, // ✅ 传递文档ID列表
- conversationId: currentConversationId,
-}, ...)
-```
-
-**4. 重新生成Prisma Client**
-
-```bash
-cd AIclinicalresearch/backend
-npx prisma generate
-```
-
-确保TypeScript能识别`extractedText`字段。
-
-#### 实现效果对比
-
-**之前(RAG模式):**
-- 数据来源:Dify RAG检索
-- 传输内容:15个片段
-- Token使用:~5-10K
-- 覆盖率:局部片段
-- 准确性:中等(可能遗漏)
-- 适用场景:快速查找
-
-**现在(真全文模式):**
-- 数据来源:数据库extractedText字段
-- 传输内容:35-50篇文献完整全文
-- Token使用:~750K(真实全文)
-- 覆盖率:100%文献内容
-- 准确性:高(无遗漏)
-- 适用场景:文献综述、深度分析
-
-#### 三个关键要求的实现
-
-✅ **要求1:默认选择Qwen-Long模型**
-- 使用`useEffect`监听模式变化
-- 自动切换到`qwen-long`
-- 显示提示信息
-
-✅ **要求2:组装全文时包含文件名**
-- 格式:`【文献N:文件名】\n\n完整文本`
-- 每篇文献清晰标记
-
-✅ **要求3:文献来源通过文件名标记**
-- 引用信息包含完整文件名
-- 相关度显示100%(全文)
-- 前200字符预览
-
-#### 核心优势
-
-1. **真正的全局视野**
- - AI能看到所有文献的完整内容
- - 不受RAG检索算法限制
- - 不会遗漏重要信息
-
-2. **深度综合分析**
- - 跨文献比较
- - 趋势总结
- - 研究方法归纳
- - 发现文献之间的关联
-
-3. **准确的引用**
- - 基于文件名的明确引用
- - 100%相关度(全文)
- - 用户易于理解和验证
-
-4. **充足的对话空间**
- - Qwen-Long 1M上下文
- - ~250K tokens对话空间
- - 支持多轮深入对话
-
-#### 验证要点
-
-- [ ] 进入全文阅读模式时自动切换到Qwen-Long
-- [ ] 后端加载extractedText完整字段
-- [ ] 组装格式包含【文献N:文件名】
-- [ ] AI回答基于完整文献(不是片段)
-- [ ] 引用使用【文献N】格式
-- [ ] 文献来源显示完整文件名
-- [ ] 可以进行跨文献综合分析
-- [ ] Token使用显示~750K(与文献总token一致)
-
-#### 相关文档
-- ✅ `Phase2-全文阅读模式-真实实现.md` - 完整实现说明
-- ✅ `backend/src/controllers/chatController.ts` - 后端逻辑
-- ✅ `frontend/src/api/chatApi.ts` - API接口
-- ✅ `frontend/src/pages/ChatPage.tsx` - 前端逻辑
-
-#### 修复人员
-AI助手
-
-#### 重要性说明
-这是Phase 2最严重的问题,因为:
-1. **核心功能失效**:全文阅读模式的核心价值完全没有实现
-2. **资源浪费**:文档提取、Token计数等大量工作都白做了
-3. **设计偏离**:与技术方案文档严重不一致
-4. **用户误导**:用户以为在使用全文,实际只是RAG片段
-
-幸好用户敏锐地察觉到了这个问题,否则整个Phase 2的核心功能都是虚假的。
-
----
-
-## 🎯 下一步行动
-
-### 立即执行
-1. ✅ 验证问题1-5的修复(重启Frontend后测试)
-2. ⏳ 全文阅读模式完整测试(对话、引用、Token显示)
-3. ⏳ 逐篇精读模式完整测试(文献切换、对话历史独立性)
-4. ⏳ 继续Phase 2其他功能测试
-
-### 待观察
-- 其他API是否有类似的数据结构访问问题
-- 文献切换时的对话历史保持是否正常
-- Token容量显示的准确性
-- Header滚动条的用户体验是否良好
-- 消息列表的引用标记功能是否正常工作
-
----
-
-## 📝 备注
-
-### 经验教训
-1. **API数据结构一致性**:Backend返回的数据格式应该在API层统一处理,避免调用方混淆
-2. **类型定义**:应该为API返回值定义明确的TypeScript类型,避免访问错误
-3. **错误处理**:应该添加更详细的错误信息,帮助快速定位问题
-4. **React Hooks规则**:严格遵守Hooks只能在组件顶层调用的规则,不能在事件处理器中调用
-5. **布局设计**:Flex布局中必须明确设置子元素的flex属性,否则容易出现高度塌缩问题
-
-### 建议改进
-1. 为`documentSelectionApi.getSelection()`添加TypeScript类型定义
-2. 添加API响应数据的运行时验证
-3. 统一Backend所有API的返回格式处理方式
-4. 添加ESLint规则检查Hooks调用位置
-5. 建立组件布局最佳实践文档
-
----
-
-**最后更新**:2025-10-13
-**维护者**:测试团队
-
diff --git a/知识库需求调整说明.md b/知识库需求调整说明.md
deleted file mode 100644
index c691de98..00000000
--- a/知识库需求调整说明.md
+++ /dev/null
@@ -1,571 +0,0 @@
-# 知识库需求调整说明
-
-## 📋 需求变更
-
-### 原需求(PRD原文)
-> "后期考虑,增加基于大规模(1000篇以内)文献的读取、识别、内容提取的工作"
-
-**理解:** 这给人的印象是需要处理海量文献,技术难度极高。
-
-### 实际需求(明确后)
-✅ **每个用户最多创建 3个知识库**
-✅ **每个知识库最多上传 50个文件**
-✅ **主要格式:PDF、DOCX**
-✅ **单用户最大文档量:150个文件**
-
----
-
-## 🎯 影响分析
-
-### 技术难度大幅降低
-
-| 维度 | 原理解(1000篇+) | 实际需求(150个/用户) | 影响 |
-|------|-----------------|---------------------|------|
-| **向量数据库** | 需要高性能集群 | Dify内置Qdrant足够 | ✅ 简化 |
-| **文档处理** | 需要分布式处理 | 单机异步处理即可 | ✅ 简化 |
-| **检索性能** | 需要优化索引 | 默认配置即可 | ✅ 简化 |
-| **存储成本** | 需要大容量存储 | 标准对象存储 | ✅ 降低 |
-| **技术难度** | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ✅ 降低 |
-
-### Dify完全够用
-
-**Dify的能力:**
-- ✅ 单个知识库支持上万个文档片段
-- ✅ 自动文档解析(PDF、Word、TXT等)
-- ✅ 内置向量化(支持多种Embedding模型)
-- ✅ 混合检索(关键词 + 语义检索)
-- ✅ 重排序(Reranking)
-- ✅ 答案溯源
-
-**我们的需求:**
-- 50个文件/知识库(远低于Dify上限)
-- PDF、DOCX格式(Dify原生支持)
-- **结论:Dify完全满足需求!**
-
----
-
-## 💾 数据库设计
-
-### 知识库表结构
-
-```sql
--- 知识库表
-CREATE TABLE knowledge_bases (
- id VARCHAR(50) PRIMARY KEY,
- user_id VARCHAR(50) NOT NULL,
- name VARCHAR(100) NOT NULL,
- description TEXT,
-
- -- Dify知识库ID
- dify_dataset_id VARCHAR(100) NOT NULL,
-
- -- 统计信息
- file_count INT DEFAULT 0,
- total_size_bytes BIGINT DEFAULT 0,
-
- created_at TIMESTAMP DEFAULT NOW(),
- updated_at TIMESTAMP DEFAULT NOW(),
-
- FOREIGN KEY (user_id) REFERENCES users(id),
-
- -- 限制:每个用户最多3个知识库
- CONSTRAINT check_kb_limit CHECK (
- (SELECT COUNT(*) FROM knowledge_bases WHERE user_id = NEW.user_id) <= 3
- )
-);
-
--- 为用户ID创建索引
-CREATE INDEX idx_kb_user ON knowledge_bases(user_id);
-
--- 文档表
-CREATE TABLE documents (
- id VARCHAR(50) PRIMARY KEY,
- kb_id VARCHAR(50) NOT NULL,
- user_id VARCHAR(50) NOT NULL,
-
- filename VARCHAR(255) NOT NULL,
- file_type VARCHAR(20) NOT NULL, -- pdf, docx
- file_size_bytes BIGINT NOT NULL,
- file_url TEXT NOT NULL, -- 对象存储URL
-
- -- Dify文档ID
- dify_document_id VARCHAR(100) NOT NULL,
-
- -- 处理状态
- status VARCHAR(20) DEFAULT 'uploading', -- uploading, processing, completed, failed
- progress INT DEFAULT 0, -- 0-100
- error_message TEXT,
-
- -- 处理结果
- segments_count INT DEFAULT 0, -- 切分的段落数
- tokens_count INT DEFAULT 0, -- token数量
-
- uploaded_at TIMESTAMP DEFAULT NOW(),
- processed_at TIMESTAMP,
-
- FOREIGN KEY (kb_id) REFERENCES knowledge_bases(id) ON DELETE CASCADE,
- FOREIGN KEY (user_id) REFERENCES users(id),
-
- -- 限制:每个知识库最多50个文件
- CONSTRAINT check_doc_limit CHECK (
- (SELECT COUNT(*) FROM documents WHERE kb_id = NEW.kb_id) <= 50
- )
-);
-
--- 索引
-CREATE INDEX idx_doc_kb ON documents(kb_id);
-CREATE INDEX idx_doc_user ON documents(user_id);
-CREATE INDEX idx_doc_status ON documents(status);
-```
-
-### 用户配额表
-
-```sql
--- 用户配额表(可选,用于更灵活的配额管理)
-CREATE TABLE user_quotas (
- user_id VARCHAR(50) PRIMARY KEY,
-
- -- 知识库配额
- kb_quota INT DEFAULT 3, -- 允许创建的知识库数量
- kb_used INT DEFAULT 0, -- 已使用
-
- -- 文件配额(每个知识库)
- files_per_kb_quota INT DEFAULT 50,
-
- -- 存储配额(字节)
- storage_quota_bytes BIGINT DEFAULT 1073741824, -- 1GB
- storage_used_bytes BIGINT DEFAULT 0,
-
- updated_at TIMESTAMP DEFAULT NOW(),
-
- FOREIGN KEY (user_id) REFERENCES users(id)
-);
-```
-
----
-
-## 🔧 实现方案
-
-### 1. 知识库创建(带限制检查)
-
-```typescript
-// backend/src/services/knowledge-base.service.ts
-
-export class KnowledgeBaseService {
-
- /**
- * 创建知识库
- */
- async createKnowledgeBase(userId: string, data: CreateKBDto) {
- // 1. 检查用户知识库数量限制
- const userKbCount = await db.knowledge_bases.count({
- where: { user_id: userId }
- });
-
- if (userKbCount >= 3) {
- throw new Error('已达到知识库数量上限(3个)');
- }
-
- // 2. 在Dify中创建知识库
- const difyDataset = await difyClient.createDataset({
- name: data.name,
- description: data.description,
- indexing_technique: 'high_quality', // 高质量索引
- permission: 'only_me'
- });
-
- // 3. 在数据库中保存记录
- const kb = await db.knowledge_bases.create({
- id: generateId('kb'),
- user_id: userId,
- name: data.name,
- description: data.description,
- dify_dataset_id: difyDataset.id,
- file_count: 0,
- total_size_bytes: 0
- });
-
- return kb;
- }
-
- /**
- * 上传文档
- */
- async uploadDocument(userId: string, kbId: string, file: File) {
- // 1. 检查知识库是否存在且属于该用户
- const kb = await db.knowledge_bases.findOne({
- where: { id: kbId, user_id: userId }
- });
-
- if (!kb) {
- throw new Error('知识库不存在或无权限');
- }
-
- // 2. 检查文件数量限制
- const docCount = await db.documents.count({
- where: { kb_id: kbId }
- });
-
- if (docCount >= 50) {
- throw new Error('知识库文件数量已达上限(50个)');
- }
-
- // 3. 检查文件格式
- const allowedTypes = ['application/pdf', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'];
- if (!allowedTypes.includes(file.mimetype)) {
- throw new Error('仅支持PDF和DOCX格式');
- }
-
- // 4. 检查文件大小(单个文件最大50MB)
- const maxSize = 50 * 1024 * 1024; // 50MB
- if (file.size > maxSize) {
- throw new Error('文件大小超过限制(最大50MB)');
- }
-
- // 5. 上传到对象存储
- const fileUrl = await objectStorage.upload(file);
-
- // 6. 创建文档记录
- const doc = await db.documents.create({
- id: generateId('doc'),
- kb_id: kbId,
- user_id: userId,
- filename: file.originalname,
- file_type: path.extname(file.originalname).slice(1),
- file_size_bytes: file.size,
- file_url: fileUrl,
- status: 'uploading',
- dify_document_id: '' // 稍后更新
- });
-
- // 7. 异步提交到Dify处理
- this.processDocumentAsync(doc.id, kb.dify_dataset_id, fileUrl);
-
- return doc;
- }
-
- /**
- * 异步处理文档
- */
- private async processDocumentAsync(docId: string, difyDatasetId: string, fileUrl: string) {
- try {
- // 1. 更新状态为处理中
- await db.documents.update({
- where: { id: docId },
- data: { status: 'processing' }
- });
-
- // 2. 提交到Dify处理
- const difyDoc = await difyClient.uploadDocument({
- dataset_id: difyDatasetId,
- file_url: fileUrl,
- indexing_technique: 'high_quality',
- process_rule: {
- mode: 'automatic',
- rules: {
- pre_processing_rules: [
- { id: 'remove_extra_spaces', enabled: true },
- { id: 'remove_urls_emails', enabled: false } // 保留医学文献中的引用
- ],
- segmentation: {
- separator: '\n\n',
- max_tokens: 500 // 每段最大500 tokens
- }
- }
- }
- });
-
- // 3. 保存Dify文档ID
- await db.documents.update({
- where: { id: docId },
- data: { dify_document_id: difyDoc.id }
- });
-
- // 4. 轮询处理状态
- let status = 'processing';
- while (status === 'processing') {
- await sleep(2000); // 2秒后重试
-
- const result = await difyClient.getDocumentStatus({
- dataset_id: difyDatasetId,
- document_id: difyDoc.id
- });
-
- status = result.indexing_status;
-
- // 更新进度
- await db.documents.update({
- where: { id: docId },
- data: {
- progress: Math.round((result.completed_segments / result.total_segments) * 100)
- }
- });
- }
-
- // 5. 处理完成
- if (status === 'completed') {
- const result = await difyClient.getDocumentStatus({
- dataset_id: difyDatasetId,
- document_id: difyDoc.id
- });
-
- await db.documents.update({
- where: { id: docId },
- data: {
- status: 'completed',
- progress: 100,
- segments_count: result.total_segments,
- tokens_count: result.tokens,
- processed_at: new Date()
- }
- });
-
- // 更新知识库统计
- await this.updateKbStats(docId);
-
- } else {
- // 处理失败
- await db.documents.update({
- where: { id: docId },
- data: {
- status: 'failed',
- error_message: result.error || '文档处理失败'
- }
- });
- }
-
- } catch (error) {
- // 异常处理
- await db.documents.update({
- where: { id: docId },
- data: {
- status: 'failed',
- error_message: error.message
- }
- });
- }
- }
-
- /**
- * 检索知识库
- */
- async queryKnowledgeBase(userId: string, kbId: string, query: string) {
- // 1. 验证权限
- const kb = await db.knowledge_bases.findOne({
- where: { id: kbId, user_id: userId }
- });
-
- if (!kb) {
- throw new Error('知识库不存在或无权限');
- }
-
- // 2. 调用Dify检索
- const results = await difyClient.queryKnowledgeBase({
- dataset_id: kb.dify_dataset_id,
- query,
- retrieval_model: {
- search_method: 'hybrid_search', // 混合检索
- reranking_enable: true, // 启用重排序
- top_k: 5, // 返回前5个结果
- score_threshold: 0.5 // 相似度阈值
- }
- });
-
- // 3. 格式化返回结果
- return results.records.map(record => ({
- content: record.segment.content,
- score: record.score,
- document: {
- id: record.segment.document.id,
- name: record.segment.document.name,
- position: record.segment.position // 在文档中的位置
- }
- }));
- }
-
- /**
- * 获取用户的知识库列表
- */
- async getUserKnowledgeBases(userId: string) {
- const kbs = await db.knowledge_bases.findMany({
- where: { user_id: userId },
- include: {
- _count: {
- select: { documents: true }
- }
- }
- });
-
- return kbs.map(kb => ({
- id: kb.id,
- name: kb.name,
- description: kb.description,
- file_count: kb.file_count,
- total_size_mb: (kb.total_size_bytes / 1024 / 1024).toFixed(2),
- created_at: kb.created_at,
- quota: {
- used: kb.file_count,
- limit: 50
- }
- }));
- }
-
- /**
- * 删除文档
- */
- async deleteDocument(userId: string, docId: string) {
- // 1. 验证权限
- const doc = await db.documents.findOne({
- where: { id: docId, user_id: userId },
- include: { knowledge_base: true }
- });
-
- if (!doc) {
- throw new Error('文档不存在或无权限');
- }
-
- // 2. 从Dify删除
- await difyClient.deleteDocument({
- dataset_id: doc.knowledge_base.dify_dataset_id,
- document_id: doc.dify_document_id
- });
-
- // 3. 从对象存储删除
- await objectStorage.delete(doc.file_url);
-
- // 4. 从数据库删除
- await db.documents.delete({ where: { id: docId } });
-
- // 5. 更新知识库统计
- await this.updateKbStats(doc.kb_id);
- }
-
- /**
- * 更新知识库统计信息
- */
- private async updateKbStats(kbId: string) {
- const stats = await db.documents.aggregate({
- where: { kb_id: kbId, status: 'completed' },
- _count: true,
- _sum: { file_size_bytes: true }
- });
-
- await db.knowledge_bases.update({
- where: { id: kbId },
- data: {
- file_count: stats._count,
- total_size_bytes: stats._sum.file_size_bytes || 0
- }
- });
- }
-}
-```
-
----
-
-## 📊 成本影响
-
-### 存储成本(降低)
-
-**原估算(1000篇文献):**
-- 假设每篇10MB
-- 总存储:10GB+
-- 成本:¥200+/月
-
-**实际需求(150个文件/用户):**
-```
-单用户存储:
-- 150个文件 × 平均5MB = 750MB
-- 1000个用户 = 750GB
-
-月度成本(阿里云OSS):
-- 存储:750GB × ¥0.12/GB = ¥90/月
-- 流量:假设100GB/月 × ¥0.5/GB = ¥50/月
-- 总计:¥140/月
-```
-
-**成本节省:约¥60/月**
-
-### 处理性能(提升)
-
-**小规模知识库的优势:**
-- ✅ 检索速度更快(< 1s)
-- ✅ 向量化处理更快(单文件 < 30s)
-- ✅ 无需复杂的性能优化
-
----
-
-## 🎯 技术选型确认
-
-### Dify完全满足需求 ✅
-
-| 功能 | 需求 | Dify能力 | 结论 |
-|------|------|---------|------|
-| 知识库数量 | 3个/用户 | 无限制 | ✅ 满足 |
-| 文件数量 | 50个/知识库 | 上千个 | ✅ 满足 |
-| 文件格式 | PDF、DOCX | 支持20+格式 | ✅ 满足 |
-| 向量化 | 自动 | 内置支持 | ✅ 满足 |
-| 检索 | 混合检索 | 支持 | ✅ 满足 |
-| 答案溯源 | 需要 | 支持 | ✅ 满足 |
-
-**结论:无需考虑其他RAG方案,Dify完全够用!**
-
----
-
-## 📝 API设计
-
-### RESTful API
-
-```typescript
-// 知识库管理
-GET /api/knowledge-bases // 获取用户的知识库列表
-POST /api/knowledge-bases // 创建知识库
-GET /api/knowledge-bases/:id // 获取知识库详情
-PUT /api/knowledge-bases/:id // 更新知识库
-DELETE /api/knowledge-bases/:id // 删除知识库
-
-// 文档管理
-GET /api/knowledge-bases/:kbId/documents // 获取文档列表
-POST /api/knowledge-bases/:kbId/documents // 上传文档
-GET /api/knowledge-bases/:kbId/documents/:docId // 获取文档详情
-DELETE /api/knowledge-bases/:kbId/documents/:docId // 删除文档
-
-// 检索
-POST /api/knowledge-bases/:kbId/query // 检索知识库
-
-// 配额查询
-GET /api/users/me/quotas // 获取用户配额信息
-```
-
----
-
-## ✅ 总结
-
-### 需求明确后的影响
-
-| 方面 | 原理解 | 实际需求 | 影响 |
-|------|--------|---------|------|
-| **技术难度** | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | 大幅降低 |
-| **开发成本** | 需自建RAG | 用Dify即可 | 节省30天+ |
-| **运营成本** | ¥200+/月 | ¥140/月 | 节省30% |
-| **性能要求** | 需要优化 | 默认配置 | 简化 |
-| **风险** | 高 | 低 | 降低 |
-
-### 最终方案
-
-**✅ 使用Dify处理知识库,完全满足需求!**
-- 每用户3个知识库
-- 每知识库50个文件
-- PDF、DOCX格式
-- 自动向量化、检索、答案溯源
-
-**无需考虑其他RAG方案!**
-
----
-
-**文档版本:v1.0**
-**更新时间:2025-10-10**
-
-
-
-
diff --git a/稿件审查功能-最终完成报告.md b/稿件审查功能-最终完成报告.md
deleted file mode 100644
index 668cd3f7..00000000
--- a/稿件审查功能-最终完成报告.md
+++ /dev/null
@@ -1,426 +0,0 @@
-# 稿件审查功能 - 最终完成报告 🎉
-
-**项目名称**: AI临床研究平台 - 稿件审查智能体
-**完成日期**: 2025-10-14
-**开发状态**: ✅ **已完成并测试通过**
-**完成度**: **15/15 任务完成 (100%)** 🎉
-
----
-
-## 🎯 项目总览
-
-稿件审查功能是一个独立的智能审稿系统,能够自动评估医学稿件的规范性和方法学质量,为作者和编辑提供详细的改进建议。
-
----
-
-## ✅ 完成情况
-
-### 任务完成统计
-
-| 阶段 | 任务数 | 已完成 | 完成率 |
-|------|-------|--------|-------|
-| Day 1: 后端开发 | 6 | 6 | 100% ✅ |
-| Day 2: 前端开发 | 5 | 5 | 100% ✅ |
-| Day 3: 测试与优化 | 4 | 4 | 100% ✅ |
-| **总计** | **15** | **15** | **100%** 🎉 |
-
-### 详细任务列表
-
-#### ✅ Day 1: 后端开发 (100%)
-1. ✅ 数据库设计 - 创建review_tasks表
-2. ✅ Prompt编写 - 2个专业评估Prompt
-3. ✅ Service层 - reviewService.ts
-4. ✅ Controller层 - 5个API端点
-5. ✅ 路由注册与服务器集成
-6. ✅ 后端测试脚本
-
-#### ✅ Day 2: 前端开发 (100%)
-1. ✅ API封装 - reviewApi.ts
-2. ✅ 主页面 - ReviewPage.tsx
-3. ✅ 报告组件 - 3个专业组件
-4. ✅ 导航集成 - 菜单和路由
-5. ✅ 样式优化
-
-#### ✅ Day 3: 测试与优化 (100% ✅)
-1. ✅ 端到端测试 - **已完成并通过**
-2. ✅ 问题修复 - **API超时、布局、批处理脚本乱码**
-3. ✅ UI完善 - **PDF导出+复制功能+默认展开优化**
-4. ✅ 文档编写 - **完整文档12+篇**
-
----
-
-## 📊 开发成果
-
-### 代码统计
-
-| 类型 | 文件数 | 代码行数 |
-|------|-------|---------|
-| 后端代码 | 7 | 1,587 |
-| 前端代码 | 8 | 1,325 |
-| 测试脚本 | 2 | 541 |
-| 文档 | 12+ | ~3,000 |
-| **总计** | **29+** | **~6,500** |
-
-### 核心文件清单
-
-#### 后端 (7个文件)
-- ✅ `backend/prisma/schema.prisma` (+40行)
-- ✅ `backend/prompts/review_editorial_system.txt` (225行)
-- ✅ `backend/prompts/review_methodology_system.txt` (216行)
-- ✅ `backend/src/services/reviewService.ts` (453行)
-- ✅ `backend/src/controllers/reviewController.ts` (265行)
-- ✅ `backend/src/routes/reviewRoutes.ts` (23行)
-- ✅ `backend/check-api-config.js` (160行)
-
-#### 前端 (8个文件)
-- ✅ `frontend/src/api/reviewApi.ts` (319行)
-- ✅ `frontend/src/pages/ReviewPage.tsx` (530行)
-- ✅ `frontend/src/pages/ReviewPage.css` (80行)
-- ✅ `frontend/src/components/review/ScoreCard.tsx` (93行)
-- ✅ `frontend/src/components/review/EditorialReview.tsx` (193行)
-- ✅ `frontend/src/components/review/MethodologyReview.tsx` (208行)
-- ✅ `frontend/src/layouts/MainLayout.tsx` (+8行)
-- ✅ `frontend/src/App.tsx` (+2行)
-
----
-
-## 🚀 核心功能
-
-### 1. 文件上传 ✅
-- 支持.doc和.docx格式
-- 文件大小限制5MB
-- 拖拽上传支持
-- 实时文件信息显示
-
-### 2. 模型选择 ✅
-- DeepSeek-V3(推荐,速度快)
-- Qwen3-72B(阿里云千问)
-- Qwen-Long(超长上下文1M tokens)
-
-### 3. 智能评估 ✅
-
-#### 稿约规范性评估(11个标准)
-1. 文稿科学性与实用性
-2. 文题
-3. 作者格式
-4. 摘要
-5. 关键词
-6. 医学名词和药物名称
-7. 缩略语
-8. 计量单位
-9. 图片格式
-10. 动态图像
-11. 参考文献
-
-#### 方法学评估(3个部分)
-1. 科研设计评估(9个检查点)
-2. 统计学方法描述评估(5个检查点)
-3. 统计分析评估(6个检查点)
-
-### 4. 实时进度 ✅
-- 5步进度条
-- 实时状态更新
-- 状态轮询(每5秒)
-- 超时处理(最多3分钟)
-
-### 5. 详细报告 ✅
-- 总体评分(加权平均)
-- 分项评分(稿约40% + 方法学60%)
-- Tabs切换查看
-- Collapse折叠面板
-- 问题列表
-- 改进建议
-- 颜色指示系统
-
-### 6. 导出功能 ✅
-- **导出为PDF**:专业打印样式优化
-- **复制报告内容**:纯文本格式,可粘贴到Word
-
----
-
-## 🔧 技术亮点
-
-### 后端架构
-- ✅ **异步处理**:任务创建后立即返回,后台执行
-- ✅ **LLM适配**:支持多种模型,统一接口
-- ✅ **结构化输出**:LLM返回JSON,前端解析展示
-- ✅ **错误处理**:详细日志,便于调试
-- ✅ **超时优化**:180秒超时,适应复杂评估
-
-### 前端架构
-- ✅ **React + TypeScript**:类型安全
-- ✅ **Ant Design**:专业UI组件
-- ✅ **实时轮询**:自动查询任务状态
-- ✅ **响应式布局**:适配不同屏幕
-- ✅ **打印优化**:专业PDF导出
-
----
-
-## 🎨 用户界面
-
-### 上传页面
-- 渐变标题卡片
-- 拖拽上传区域
-- 模型选择下拉框
-- 清晰的操作指引
-
-### 进度页面
-- 5步进度指示
-- 实时状态更新
-- Loading动画
-- 已提取字数显示
-
-### 报告页面
-- 总体评分卡片
-- Tabs切换(稿约/方法学)
-- 折叠面板详情
-- 颜色编码(绿/蓝/黄/红)
-- 导出下拉菜单
-
----
-
-## 📈 性能指标
-
-### 实际测试数据
-| 文档长度 | 实际耗时 | 成功率 |
-|---------|---------|-------|
-| 2000字 | 1-2分钟 | 95%+ |
-| 5000字 | 2-3分钟 | 90%+ |
-| 8000字 | 3-5分钟 | 85%+ |
-
-### 系统性能
-- ⏱️ 平均响应时间: <3分钟
-- ✅ 成功率: >90%
-- 🔄 并发支持: 是
-- 💾 存储: PostgreSQL
-
----
-
-## 🐛 问题修复记录
-
-### 问题1: 页面布局 ✅
-- **问题**: 宽度太窄,不能滚动
-- **修复**: 增加maxWidth到1400px,添加overflow:auto
-- **状态**: 已修复
-
-### 问题2: API超时 ✅
-- **问题**: 60秒超时导致评估失败
-- **修复**: 超时时间增加到180秒,Token限制增加到8000
-- **状态**: 已修复
-
-### 问题3: 批处理脚本乱码 ✅
-- **问题**: chcp 65001导致中文乱码
-- **修复**: 移除chcp,使用GBK编码,创建英文版
-- **状态**: 已修复
-
-### 问题4: 导出功能缺失 ✅
-- **问题**: 导出按钮未实现
-- **修复**: 添加PDF导出和复制功能
-- **状态**: 已修复
-
----
-
-## 📝 文档清单
-
-### 开发文档 (10个文件)
-1. ✅ 稿件审查功能-开发计划.md
-2. ✅ Day30-后端开发完成总结.md
-3. ✅ Day30-Task1.2-Prompt编写完成.md
-4. ✅ Day30-前端开发完成总结.md
-5. ✅ 稿件审查功能-后端测试指南.md
-6. ✅ 稿件审查-超时问题修复.md
-7. ✅ 稿件审查-导出功能完成.md
-8. ✅ 稿件审查功能-完成总结.md
-9. ✅ 数据库设计文档.md (更新)
-10. ✅ API设计规范.md (更新)
-
-### 脚本文件 (6个文件)
-1. ✅ 启动所有服务.bat (中文版)
-2. ✅ 一键启动.bat (英文版)
-3. ✅ 停止所有服务.bat (中文版)
-4. ✅ stop-all-services.bat (英文版)
-5. ✅ test-review-api.js (API测试)
-6. ✅ check-api-config.js (配置检查)
-
----
-
-## ✅ 所有任务已完成 (15/15)
-
-所有开发任务已圆满完成!包括:
-- ✅ 完整的后端开发(6个任务)
-- ✅ 完整的前端开发(5个任务)
-- ✅ 完整的测试与优化(4个任务)
-- ✅ 所有问题修复和功能完善
-- ✅ 齐全的技术文档(12+篇)
-
-### 📝 Prompt调优说明
-- 当前Prompt已可用,评估效果良好
-- 后续可根据实际使用反馈持续优化
-- 建议收集1-2周用户反馈后再调整
-
----
-
-## 💡 未来改进方向
-
-### 短期改进(可选)
-- 📝 Excel格式导出
-- 📝 批量审查(多文件)
-- 📝 任务历史列表页
-- 📝 评审意见高亮显示
-
-### 中期改进(可选)
-- 📝 自定义评估标准
-- 📝 多语言支持(英文稿件)
-- 📝 期刊适配(不同期刊标准)
-- 📝 评审报告对比功能
-
-### 长期改进(可选)
-- 📝 专家评审模式(人工介入)
-- 📝 机器学习反馈优化
-- 📝 移动端支持
-- 📝 云端存储和分享
-
----
-
-## 🚀 部署清单
-
-### 环境要求
-- ✅ Node.js 18+
-- ✅ PostgreSQL 14+
-- ✅ Redis 6+
-- ✅ Python 3.9+
-- ✅ Docker Desktop
-
-### 配置文件
-- ✅ `backend/.env` - API Key配置
-- ✅ `docker-compose.yml` - 数据库容器
-- ✅ `extraction_service/` - Python微服务
-
-### 启动步骤
-```bash
-# 1. 停止旧服务
-双击: 停止所有服务.bat
-
-# 2. 启动所有服务
-双击: 启动所有服务.bat
-
-# 3. 访问应用
-浏览器: http://localhost:5173
-稿件审查: http://localhost:5173/review
-```
-
----
-
-## 📞 使用指南
-
-### 基本流程
-1. 打开稿件审查页面
-2. 上传Word文档(.doc/.docx,≤5MB)
-3. 选择评估模型(推荐DeepSeek-V3)
-4. 点击"开始审查"
-5. 等待3-5分钟
-6. 查看详细报告
-7. 导出PDF或复制报告
-
-### 注意事项
-- ⚠️ 文件必须是Word格式
-- ⚠️ 文件大小不超过5MB
-- ⚠️ 需要3-5分钟处理时间
-- ⚠️ 需要配置API Key
-
----
-
-## 🏆 项目成就
-
-### 开发效率
-- 📅 开发周期: 1天
-- 💻 代码量: ~6,500行
-- 📝 文档: 10+篇
-- 🐛 修复问题: 4个
-
-### 功能完整性
-- ✅ 核心功能: 100%完成
-- ✅ 用户界面: 100%完成
-- ✅ 测试验证: 已通过
-- ✅ 文档齐全: 95%完成
-
-### 质量指标
-- ✅ 类型安全: TypeScript全栈
-- ✅ 错误处理: 完善
-- ✅ 日志系统: 详细
-- ✅ 用户体验: 流畅
-
----
-
-## 🎉 总结
-
-**稿件审查功能开发圆满完成!** 🚀
-
-### 核心亮点
-1. ✅ **功能完整**:从上传到导出的完整流程
-2. ✅ **技术先进**:LLM + 结构化输出
-3. ✅ **用户友好**:清晰的UI和详细的报告
-4. ✅ **专业可靠**:基于真实期刊标准
-5. ✅ **可扩展性**:易于添加新功能
-
-### 用户价值
-- ✅ **节省时间**:自动化审稿,替代人工初审
-- ✅ **提高质量**:31个检查点,全面覆盖
-- ✅ **清晰反馈**:问题定位+改进建议
-- ✅ **易于使用**:3步完成,5分钟出结果
-- ✅ **灵活导出**:PDF或文本,适应不同场景
-
-### 团队贡献
-- 🤖 **AI开发助手**:全栈开发、问题修复、文档编写
-- 👤 **用户反馈**:测试验证、问题发现、需求确认
-
----
-
-## 📊 最终验收
-
-### 功能验收 ✅
-- [x] 文件上传功能正常
-- [x] 模型选择功能正常
-- [x] 实时进度展示正常
-- [x] 稿约评估正常(11项)
-- [x] 方法学评估正常(3部分)
-- [x] 报告展示完整美观
-- [x] PDF导出功能正常
-- [x] 复制功能正常
-
-### 性能验收 ✅
-- [x] 3-5分钟内完成评估
-- [x] 成功率>90%
-- [x] 页面响应流畅
-- [x] 无内存泄漏
-
-### 用户体验验收 ✅
-- [x] 操作简单直观
-- [x] 提示信息清晰
-- [x] 错误处理完善
-- [x] 导出便捷实用
-
----
-
-## 🎊 结语
-
-感谢您的耐心测试和宝贵反馈!
-
-稿件审查功能现已正式上线,随时可以投入使用。
-
-如有任何问题或改进建议,欢迎随时反馈!
-
----
-
-**项目状态**: ✅ **已完成并通过验收**
-**可用性**: ✅ **立即可用**
-**维护状态**: ✅ **持续维护**
-
-**完成日期**: 2025-10-14
-**文档版本**: v1.0
-**最后更新**: 2025-10-14
-
----
-
-**🎉 恭喜!稿件审查功能开发圆满完成!🎉**
-
diff --git a/第一周开发指南.md b/第一周开发指南.md
deleted file mode 100644
index 7cbf312d..00000000
--- a/第一周开发指南.md
+++ /dev/null
@@ -1,903 +0,0 @@
-# 第一周开发指南(Day 1-7)
-
-> **目标:** 搭建完整的开发环境,实现第一个功能(用户认证)
-> **时间:** 7天
-> **状态:** 🚀 准备就绪!
-
----
-
-## ✅ 已完成准备工作
-
-- [x] Docker Desktop 安装完毕
-- [x] DeepSeek API Key 已申请
-- [x] Qwen API Key 已申请
-
----
-
-## 📅 本周计划
-
-| 天数 | 任务 | 预计时间 |
-|------|------|---------|
-| Day 1 | 验证环境 + 创建项目结构 | 2小时 |
-| Day 2 | 启动基础服务(Docker) | 1小时 |
-| Day 3 | 搭建后端框架 | 3小时 |
-| Day 4 | 搭建前端框架 | 3小时 |
-| Day 5 | 实现用户认证(后端) | 4小时 |
-| Day 6 | 实现登录界面(前端) | 4小时 |
-| Day 7 | 测试联调 | 2小时 |
-
----
-
-## 🎯 Day 1: 验证环境 + 创建项目结构
-
-### 步骤1:验证 Docker 安装
-
-打开终端(Windows用PowerShell或CMD,macOS用Terminal),执行:
-
-```bash
-# 检查 Docker 版本
-docker --version
-# 应输出类似:Docker version 24.0.x
-
-# 检查 Docker Compose 版本
-docker-compose --version
-# 应输出类似:Docker Compose version v2.x.x
-
-# 检查 Docker 是否运行
-docker ps
-# 应输出表头(即使没有容器运行)
-```
-
-**如果遇到错误:**
-- Windows: 确保 Docker Desktop 已启动(系统托盘有Docker图标)
-- macOS: 确保 Docker Desktop 已启动
-
----
-
-### 步骤2:创建项目目录结构
-
-```bash
-# 选择一个工作目录(比如 D:\Projects 或 ~/Projects)
-cd D:\Projects # Windows
-# 或
-cd ~/Projects # macOS/Linux
-
-# 创建项目根目录
-mkdir ai-clinical-research
-cd ai-clinical-research
-
-# 创建子目录
-mkdir backend frontend config docs
-
-# 验证目录结构
-tree -L 1
-# 或 Windows: dir
-```
-
-**预期结构:**
-```
-ai-clinical-research/
-├── backend/ # 后端代码
-├── frontend/ # 前端代码
-├── config/ # 配置文件
-└── docs/ # 文档
-```
-
----
-
-### 步骤3:创建 docker-compose.yml
-
-在项目根目录创建 `docker-compose.yml`:
-
-```yaml
-version: '3.8'
-
-services:
- # PostgreSQL 数据库
- postgres:
- image: postgres:15-alpine
- container_name: acr-postgres
- environment:
- POSTGRES_DB: ai_clinical_research
- POSTGRES_USER: dev_user
- POSTGRES_PASSWORD: dev_pass_2024
- ports:
- - "5432:5432"
- volumes:
- - postgres_data:/var/lib/postgresql/data
- healthcheck:
- test: ["CMD-SHELL", "pg_isready -U dev_user -d ai_clinical_research"]
- interval: 10s
- timeout: 5s
- retries: 5
-
- # Redis 缓存
- redis:
- image: redis:7-alpine
- container_name: acr-redis
- ports:
- - "6379:6379"
- volumes:
- - redis_data:/data
- healthcheck:
- test: ["CMD", "redis-cli", "ping"]
- interval: 10s
- timeout: 3s
- retries: 5
-
- # Dify Sandbox(沙箱环境,Dify依赖)
- dify-sandbox:
- image: langgenius/dify-sandbox:latest
- container_name: acr-dify-sandbox
- restart: unless-stopped
-
- # Dify API
- dify-api:
- image: langgenius/dify-api:latest
- container_name: acr-dify-api
- environment:
- # 数据库配置
- DB_USERNAME: dify
- DB_PASSWORD: dify_pass_2024
- DB_HOST: dify-postgres
- DB_PORT: 5432
- DB_DATABASE: dify
-
- # Redis配置
- REDIS_HOST: dify-redis
- REDIS_PORT: 6379
- REDIS_DB: 0
-
- # 应用配置
- MODE: api
- SECRET_KEY: sk-9f73s3ljTXVcMT3Blb3ljTqtsKiGHXVcMT3BlbkFJLK7U
- CONSOLE_WEB_URL: http://localhost
- CONSOLE_API_URL: http://localhost:5001
- SERVICE_API_URL: http://localhost:5001
- APP_WEB_URL: http://localhost
-
- # 文件存储(本地)
- STORAGE_TYPE: local
- STORAGE_LOCAL_PATH: /app/storage
-
- # Vector Store(向量数据库)
- VECTOR_STORE: qdrant
- QDRANT_URL: http://dify-qdrant:6333
- QDRANT_API_KEY: dify-qdrant-key
-
- # Celery(异步任务)
- CELERY_BROKER_URL: redis://dify-redis:6379/1
-
- # 模型配置(可选,可在Web界面配置)
- # OPENAI_API_KEY: your-key-here
- ports:
- - "5001:5001"
- volumes:
- - dify_app_storage:/app/storage
- depends_on:
- - dify-postgres
- - dify-redis
- - dify-qdrant
- - dify-sandbox
- restart: unless-stopped
-
- # Dify Worker(后台任务处理)
- dify-worker:
- image: langgenius/dify-api:latest
- container_name: acr-dify-worker
- environment:
- MODE: worker
- DB_USERNAME: dify
- DB_PASSWORD: dify_pass_2024
- DB_HOST: dify-postgres
- DB_PORT: 5432
- DB_DATABASE: dify
- REDIS_HOST: dify-redis
- REDIS_PORT: 6379
- REDIS_DB: 0
- CELERY_BROKER_URL: redis://dify-redis:6379/1
- SECRET_KEY: sk-9f73s3ljTXVcMT3Blb3ljTqtsKiGHXVcMT3BlbkFJLK7U
- STORAGE_TYPE: local
- STORAGE_LOCAL_PATH: /app/storage
- VECTOR_STORE: qdrant
- QDRANT_URL: http://dify-qdrant:6333
- QDRANT_API_KEY: dify-qdrant-key
- volumes:
- - dify_app_storage:/app/storage
- depends_on:
- - dify-postgres
- - dify-redis
- - dify-qdrant
- restart: unless-stopped
-
- # Dify PostgreSQL
- dify-postgres:
- image: postgres:15-alpine
- container_name: acr-dify-postgres
- environment:
- POSTGRES_DB: dify
- POSTGRES_USER: dify
- POSTGRES_PASSWORD: dify_pass_2024
- PGDATA: /var/lib/postgresql/data/pgdata
- volumes:
- - dify_postgres_data:/var/lib/postgresql/data
- healthcheck:
- test: ["CMD-SHELL", "pg_isready -U dify -d dify"]
- interval: 10s
- timeout: 5s
- retries: 5
- restart: unless-stopped
-
- # Dify Redis
- dify-redis:
- image: redis:7-alpine
- container_name: acr-dify-redis
- volumes:
- - dify_redis_data:/data
- healthcheck:
- test: ["CMD", "redis-cli", "ping"]
- interval: 10s
- timeout: 3s
- retries: 5
- restart: unless-stopped
-
- # Qdrant 向量数据库
- dify-qdrant:
- image: qdrant/qdrant:latest
- container_name: acr-dify-qdrant
- environment:
- QDRANT__SERVICE__API_KEY: dify-qdrant-key
- ports:
- - "6333:6333"
- volumes:
- - dify_qdrant_data:/qdrant/storage
- restart: unless-stopped
-
- # Dify Web界面
- dify-web:
- image: langgenius/dify-web:latest
- container_name: acr-dify-web
- environment:
- CONSOLE_API_URL: http://localhost:5001
- APP_API_URL: http://localhost:5001
- ports:
- - "3000:3000"
- depends_on:
- - dify-api
- restart: unless-stopped
-
-volumes:
- postgres_data:
- redis_data:
- dify_postgres_data:
- dify_redis_data:
- dify_qdrant_data:
- dify_app_storage:
-
-networks:
- default:
- name: acr-network
-```
-
-**保存文件:** `ai-clinical-research/docker-compose.yml`
-
----
-
-### 步骤4:创建 .gitignore
-
-在项目根目录创建 `.gitignore`:
-
-```gitignore
-# Node modules
-node_modules/
-*/node_modules/
-
-# Environment variables
-.env
-.env.local
-.env.*.local
-*.env
-
-# IDE
-.vscode/
-.idea/
-*.swp
-*.swo
-*~
-
-# OS
-.DS_Store
-Thumbs.db
-
-# Build outputs
-dist/
-build/
-*.log
-
-# Database
-*.sqlite
-*.db
-
-# API Keys(重要!)
-**/config/api-keys.json
-backend/config/api-keys.json
-```
-
----
-
-### 步骤5:创建 README.md
-
-在项目根目录创建 `README.md`:
-
-```markdown
-# AI科研助手
-
-## 快速启动
-
-### 启动所有服务
-\`\`\`bash
-docker-compose up -d
-\`\`\`
-
-### 查看服务状态
-\`\`\`bash
-docker-compose ps
-\`\`\`
-
-### 查看日志
-\`\`\`bash
-docker-compose logs -f
-\`\`\`
-
-### 停止所有服务
-\`\`\`bash
-docker-compose down
-\`\`\`
-
-## 访问地址
-
-- 前端开发服务器: http://localhost:5173
-- 后端API: http://localhost:3001
-- Dify Web管理界面: http://localhost:3000
-- Dify API: http://localhost:5001
-- PostgreSQL: localhost:5432
-- Redis: localhost:6379
-
-## 开发文档
-
-详见 `docs/` 目录
-```
-
----
-
-**✅ Day 1 完成检查清单:**
-- [ ] Docker 命令验证通过
-- [ ] 项目目录创建完成
-- [ ] docker-compose.yml 创建完成
-- [ ] .gitignore 创建完成
-- [ ] README.md 创建完成
-
----
-
-## 🎯 Day 2: 启动基础服务
-
-### 步骤1:启动 Docker 服务
-
-```bash
-# 确保在项目根目录
-cd ai-clinical-research
-
-# 启动所有服务(首次启动会下载镜像,需要5-10分钟)
-docker-compose up -d
-
-# 查看启动日志
-docker-compose logs -f
-
-# 等待所有服务启动完成(约2-3分钟)
-# 看到类似信息表示成功:
-# acr-dify-api | INFO: Application startup complete.
-# acr-dify-web | ready - started server on 0.0.0.0:3000
-```
-
-**注意:** 首次启动会下载Docker镜像(约2GB),请耐心等待。
-
----
-
-### 步骤2:验证服务状态
-
-```bash
-# 查看所有容器状态
-docker-compose ps
-
-# 应该看到所有服务都是 "Up" 状态
-# NAME STATUS
-# acr-postgres Up (healthy)
-# acr-redis Up (healthy)
-# acr-dify-postgres Up (healthy)
-# acr-dify-redis Up (healthy)
-# acr-dify-qdrant Up
-# acr-dify-api Up
-# acr-dify-worker Up
-# acr-dify-web Up
-```
-
----
-
-### 步骤3:访问 Dify Web 界面
-
-1. 打开浏览器访问:http://localhost:3000
-2. 首次访问会要求创建管理员账号
-3. 填写信息:
- - 邮箱:admin@example.com
- - 密码:Admin123!(自己设置一个)
- - 确认密码:Admin123!
-4. 点击"创建账号"
-
-**成功标志:** 进入Dify管理后台
-
----
-
-### 步骤4:获取 Dify API Key
-
-1. 在Dify管理后台,点击左侧 "设置" → "API密钥"
-2. 点击 "创建密钥"
-3. 复制生成的API Key(类似:`app-xxx...`)
-4. 保存到安全的地方(后面会用到)
-
----
-
-### 步骤5:测试数据库连接
-
-```bash
-# 测试 PostgreSQL(业务数据库)
-docker exec -it acr-postgres psql -U dev_user -d ai_clinical_research -c "SELECT version();"
-
-# 应输出 PostgreSQL 版本信息
-
-# 测试 Redis
-docker exec -it acr-redis redis-cli ping
-# 应输出: PONG
-
-# 测试 Dify API
-curl http://localhost:5001/health
-# 应输出: {"status":"ok"}
-```
-
----
-
-**✅ Day 2 完成检查清单:**
-- [ ] 所有Docker容器启动成功
-- [ ] Dify Web界面可访问
-- [ ] Dify管理员账号创建完成
-- [ ] Dify API Key获取完成
-- [ ] 数据库连接测试通过
-
----
-
-## 🎯 Day 3: 搭建后端框架
-
-### 步骤1:初始化后端项目
-
-```bash
-# 进入后端目录
-cd backend
-
-# 初始化 Node.js 项目
-npm init -y
-
-# 安装依赖
-npm install fastify@4.26.0 \
- @fastify/cors@9.0.0 \
- @fastify/jwt@7.2.0 \
- @prisma/client@5.10.0 \
- bcryptjs@2.4.3 \
- dotenv@16.4.0 \
- ioredis@5.3.0 \
- axios@1.6.0
-
-# 安装开发依赖
-npm install -D \
- prisma@5.10.0 \
- typescript@5.3.0 \
- @types/node@20.11.0 \
- @types/bcryptjs@2.4.6 \
- tsx@4.7.0 \
- nodemon@3.0.0
-```
-
----
-
-### 步骤2:配置 TypeScript
-
-创建 `backend/tsconfig.json`:
-
-```json
-{
- "compilerOptions": {
- "target": "ES2022",
- "module": "commonjs",
- "lib": ["ES2022"],
- "outDir": "./dist",
- "rootDir": "./src",
- "strict": true,
- "esModuleInterop": true,
- "skipLibCheck": true,
- "forceConsistentCasingInFileNames": true,
- "resolveJsonModule": true,
- "moduleResolution": "node"
- },
- "include": ["src/**/*"],
- "exclude": ["node_modules", "dist"]
-}
-```
-
----
-
-### 步骤3:配置环境变量
-
-创建 `backend/.env`:
-
-```bash
-# 数据库配置
-DATABASE_URL="postgresql://dev_user:dev_pass_2024@localhost:5432/ai_clinical_research"
-
-# Redis配置
-REDIS_URL="redis://localhost:6379"
-
-# JWT配置
-JWT_SECRET="your-super-secret-jwt-key-change-this-in-production-2024"
-JWT_EXPIRES_IN="7d"
-
-# LLM API Keys
-DEEPSEEK_API_KEY="你的DeepSeek API Key"
-DASHSCOPE_API_KEY="你的Qwen API Key"
-
-# Dify配置
-DIFY_API_URL="http://localhost:5001"
-DIFY_API_KEY="你在Day2获取的Dify API Key"
-
-# 应用配置
-NODE_ENV="development"
-PORT=3001
-```
-
-**注意:** 把"你的XXX API Key"替换成你实际申请的Key
-
----
-
-### 步骤4:初始化 Prisma
-
-```bash
-# 初始化 Prisma
-npx prisma init
-
-# 这会创建 prisma/schema.prisma 文件
-```
-
-编辑 `backend/prisma/schema.prisma`:
-
-```prisma
-generator client {
- provider = "prisma-client-js"
-}
-
-datasource db {
- provider = "postgresql"
- url = env("DATABASE_URL")
-}
-
-// 用户表
-model User {
- id String @id @default(uuid())
- email String @unique
- password String
- name String?
- role String @default("user") // user, admin
- status String @default("active") // active, inactive
- createdAt DateTime @default(now())
- updatedAt DateTime @updatedAt
-
- // 关联
- projects Project[]
- knowledgeBases KnowledgeBase[]
-
- @@map("users")
-}
-
-// 项目/课题表
-model Project {
- id String @id @default(uuid())
- userId String
- name String
- description String @db.Text
- createdAt DateTime @default(now())
- updatedAt DateTime @updatedAt
-
- // 关联
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
- conversations Conversation[]
-
- @@map("projects")
-}
-
-// 对话表
-model Conversation {
- id String @id @default(uuid())
- projectId String?
- userId String
- agentId String
- title String
- createdAt DateTime @default(now())
- updatedAt DateTime @updatedAt
-
- // 关联
- project Project? @relation(fields: [projectId], references: [id], onDelete: Cascade)
- messages Message[]
-
- @@map("conversations")
-}
-
-// 消息表
-model Message {
- id String @id @default(uuid())
- conversationId String
- role String // user, assistant
- content String @db.Text
- createdAt DateTime @default(now())
-
- // 关联
- conversation Conversation @relation(fields: [conversationId], references: [id], onDelete: Cascade)
-
- @@map("messages")
-}
-
-// 知识库表
-model KnowledgeBase {
- id String @id @default(uuid())
- userId String
- name String
- description String?
- difyDatasetId String // Dify中的知识库ID
- fileCount Int @default(0)
- totalSizeBytes BigInt @default(0)
- createdAt DateTime @default(now())
- updatedAt DateTime @updatedAt
-
- // 关联
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
- documents Document[]
-
- @@map("knowledge_bases")
-}
-
-// 文档表
-model Document {
- id String @id @default(uuid())
- kbId String
- userId String
- filename String
- fileType String
- fileSizeBytes BigInt
- fileUrl String
- difyDocumentId String
- status String @default("uploading") // uploading, processing, completed, failed
- progress Int @default(0)
- errorMessage String?
- segmentsCount Int?
- tokensCount Int?
- uploadedAt DateTime @default(now())
- processedAt DateTime?
-
- // 关联
- knowledgeBase KnowledgeBase @relation(fields: [kbId], references: [id], onDelete: Cascade)
-
- @@map("documents")
-}
-```
-
----
-
-### 步骤5:创建数据库表
-
-```bash
-# 生成 Prisma Client
-npx prisma generate
-
-# 创建数据库迁移
-npx prisma migrate dev --name init
-
-# 看到类似输出表示成功:
-# ✔ Generated Prisma Client
-# ✔ Your database is now in sync with your schema.
-```
-
----
-
-### 步骤6:创建基础目录结构
-
-```bash
-# 在 backend 目录下创建
-mkdir -p src/routes src/services src/config src/utils src/types
-```
-
----
-
-### 步骤7:创建服务器入口文件
-
-创建 `backend/src/server.ts`:
-
-```typescript
-import Fastify from 'fastify';
-import cors from '@fastify/cors';
-import dotenv from 'dotenv';
-
-// 加载环境变量
-dotenv.config();
-
-const server = Fastify({
- logger: true
-});
-
-// 注册CORS
-server.register(cors, {
- origin: true // 开发环境允许所有来源
-});
-
-// 健康检查端点
-server.get('/health', async (request, reply) => {
- return { status: 'ok', timestamp: new Date().toISOString() };
-});
-
-// 测试端点
-server.get('/api/test', async (request, reply) => {
- return {
- message: 'AI科研助手后端服务运行正常!',
- env: process.env.NODE_ENV,
- timestamp: new Date().toISOString()
- };
-});
-
-// 启动服务器
-const start = async () => {
- try {
- const port = parseInt(process.env.PORT || '3001');
- await server.listen({ port, host: '0.0.0.0' });
- console.log(`🚀 服务器启动成功!`);
- console.log(`📝 API地址: http://localhost:${port}`);
- console.log(`🏥 健康检查: http://localhost:${port}/health`);
- } catch (err) {
- server.log.error(err);
- process.exit(1);
- }
-};
-
-start();
-```
-
----
-
-### 步骤8:配置 package.json scripts
-
-编辑 `backend/package.json`,添加 scripts:
-
-```json
-{
- "scripts": {
- "dev": "tsx watch src/server.ts",
- "build": "tsc",
- "start": "node dist/server.js",
- "prisma:generate": "prisma generate",
- "prisma:migrate": "prisma migrate dev",
- "prisma:studio": "prisma studio"
- }
-}
-```
-
----
-
-### 步骤9:启动后端服务
-
-```bash
-# 启动开发服务器
-npm run dev
-
-# 看到类似输出表示成功:
-# 🚀 服务器启动成功!
-# 📝 API地址: http://localhost:3001
-# 🏥 健康检查: http://localhost:3001/health
-```
-
----
-
-### 步骤10:测试后端API
-
-打开新的终端窗口:
-
-```bash
-# 测试健康检查
-curl http://localhost:3001/health
-
-# 测试API
-curl http://localhost:3001/api/test
-```
-
----
-
-**✅ Day 3 完成检查清单:**
-- [ ] 后端项目初始化完成
-- [ ] 依赖安装完成
-- [ ] TypeScript配置完成
-- [ ] 环境变量配置完成
-- [ ] Prisma数据库模型创建完成
-- [ ] 数据库迁移成功
-- [ ] 后端服务启动成功
-- [ ] API测试通过
-
----
-
-## 🎯 Day 4-7: 继续开发...
-
-(后续天数的详细步骤将在您完成Day 1-3后提供)
-
----
-
-## 📊 当前进度
-
-```
-✅ 环境准备: 100%
-⏳ Day 1: 待开始
-⏳ Day 2: 待开始
-⏳ Day 3: 待开始
-```
-
----
-
-## 🆘 常见问题
-
-### Q1: Docker 容器启动失败
-```bash
-# 查看日志
-docker-compose logs [服务名]
-
-# 重启服务
-docker-compose restart [服务名]
-
-# 完全重置
-docker-compose down -v
-docker-compose up -d
-```
-
-### Q2: 端口被占用
-```bash
-# Windows 查找占用端口的进程
-netstat -ano | findstr :3001
-
-# macOS/Linux
-lsof -i :3001
-
-# 修改端口(在 .env 中)
-PORT=3002
-```
-
-### Q3: npm install 太慢
-```bash
-# 使用国内镜像
-npm config set registry https://registry.npmmirror.com
-```
-
----
-
-## 🎉 准备开始!
-
-**现在就开始 Day 1 吧!**
-
-执行第一个命令:
-```bash
-docker --version
-```
-
-有任何问题随时告诉我!🚀
-
-
-
-
diff --git a/解决方案-前端获取数据失败.md b/解决方案-前端获取数据失败.md
deleted file mode 100644
index 46a674a8..00000000
--- a/解决方案-前端获取数据失败.md
+++ /dev/null
@@ -1,275 +0,0 @@
-# 🔧 解决方案:前端获取数据失败
-
-## ✅ 当前系统状态(全部正常)
-
-经过检查,系统状态如下:
-
-```
-✅ 后端服务运行正常(端口3001)
-✅ 后端健康检查通过
-✅ 后端API测试成功:
- - GET /api/v1/projects ✅ 返回项目列表
- - POST /api/v1/projects ✅ 创建项目成功
-✅ 前端服务运行正常(端口3000)
-✅ 前端页面可访问
-```
-
-**结论:** 后端和前端服务都正常,问题可能在浏览器端。
-
----
-
-## 🎯 解决方案(按顺序尝试)
-
-### 方案1:清除浏览器缓存并刷新 ⭐ 优先尝试
-
-**步骤:**
-1. 打开浏览器(http://localhost:3000)
-2. 按 **Ctrl + Shift + R**(强制刷新,清除缓存)
-3. 或者按 **F12** 打开开发者工具
-4. 右键点击刷新按钮,选择"清空缓存并硬性重新加载"
-
-**预期结果:**
-- 页面重新加载
-- 项目列表应该正常显示
-- 可以创建新项目
-
----
-
-### 方案2:检查浏览器控制台错误
-
-**步骤:**
-1. 按 **F12** 打开开发者工具
-2. 切换到 **Console** 标签
-3. 清空之前的错误(点击🚫图标)
-4. 刷新页面
-5. 查看是否有新的错误信息
-
-**如果看到错误,请告诉我具体内容**
-
----
-
-### 方案3:检查Network请求
-
-**步骤:**
-1. 按 **F12** 打开开发者工具
-2. 切换到 **Network** 标签
-3. 勾选 "Preserve log"
-4. 刷新页面
-5. 查找 `/api/v1/projects` 请求
-6. 点击该请求,查看:
- - **Status**: 应该是 200
- - **Preview**: 查看响应内容
- - **Headers**: 查看请求头
-
-**如果Status不是200,请告诉我具体状态码**
-
----
-
-### 方案4:完全重启浏览器
-
-**步骤:**
-1. 关闭浏览器(完全关闭,不要只关标签页)
-2. 重新打开浏览器
-3. 访问 http://localhost:3000
-4. 测试功能
-
----
-
-### 方案5:使用无痕/隐私模式
-
-**步骤:**
-1. 打开浏览器无痕模式:
- - Chrome: **Ctrl + Shift + N**
- - Edge: **Ctrl + Shift + N**
- - Firefox: **Ctrl + Shift + P**
-2. 访问 http://localhost:3000
-3. 测试功能
-
-**如果无痕模式正常:** 说明是浏览器缓存或扩展插件问题
-
----
-
-### 方案6:检查项目选择器状态
-
-有时项目列表加载了,但需要**手动选择项目**才能使用智能体。
-
-**步骤:**
-1. 查看页面左上角或侧边栏
-2. 是否有"项目选择器"或"当前项目"下拉框?
-3. 如果有,请选择一个项目
-4. 然后再尝试使用智能体
-
----
-
-### 方案7:重启所有服务
-
-**步骤:**
-```powershell
-# 步骤1:停止所有服务
-双击运行:停止所有服务.bat
-
-# 步骤2:等待3秒
-
-# 步骤3:重新启动
-双击运行:一键启动.bat
-
-# 步骤4:等待10秒,浏览器会自动打开
-
-# 步骤5:测试功能
-```
-
----
-
-## 🧪 验证API是否正常
-
-### 手动测试后端API
-
-**测试1:健康检查**
-```
-浏览器访问:http://localhost:3001/health
-```
-**预期结果:**
-```json
-{"status":"ok","database":"connected","timestamp":"..."}
-```
-
-**测试2:获取项目列表**
-```
-浏览器访问:http://localhost:3001/api/v1/projects
-```
-**预期结果:**
-```json
-{"success":true,"data":[...]}
-```
-
-**测试3:获取智能体列表**
-```
-浏览器访问:http://localhost:3001/api/v1/agents
-```
-**预期结果:**
-```json
-{"success":true,"data":[{"id":"topic-evaluation",...}]}
-```
-
-**如果以上任何一个失败,请告诉我具体的错误信息**
-
----
-
-## 🔍 详细诊断步骤
-
-如果以上方案都不行,请按照以下步骤收集信息:
-
-### 步骤1:后端日志
-查看后端启动终端,复制最近的日志(包括任何错误)
-
-### 步骤2:前端控制台
-1. F12 → Console标签
-2. 复制所有错误信息(红色的)
-
-### 步骤3:Network请求
-1. F12 → Network标签
-2. 找到失败的请求(红色)
-3. 点击后查看:
- - Request URL
- - Status Code
- - Response(响应内容)
- - 截图发给我
-
-### 步骤4:浏览器信息
-告诉我:
-- 使用的浏览器(Chrome/Edge/Firefox)
-- 浏览器版本
-
----
-
-## 💡 可能的原因分析
-
-### 原因1:时序问题
-- 前端加载太快,后端还没完全启动
-- **解决:** 等待10秒后刷新页面
-
-### 原因2:CORS问题
-- 跨域请求被阻止
-- **检查:** 浏览器控制台是否有CORS错误
-- **解决:** 后端已配置CORS,应该不会有此问题
-
-### 原因3:代理配置
-- Vite代理配置失效
-- **检查:** Network标签中请求URL是否正确
-- **解决:** 重启前端服务
-
-### 原因4:防火墙/杀毒软件
-- 拦截了本地请求
-- **解决:** 临时关闭防火墙测试
-
----
-
-## 🎯 推荐的完整测试流程
-
-```powershell
-# 1. 停止所有服务
-双击:停止所有服务.bat
-
-# 2. 检查端口是否释放
-双击:查看端口占用.bat
-# 应该显示:端口3000和3001都空闲
-
-# 3. 启动服务
-双击:一键启动.bat
-
-# 4. 等待15秒(让服务完全启动)
-
-# 5. 打开无痕模式浏览器
-Ctrl + Shift + N
-
-# 6. 访问系统
-http://localhost:3000
-
-# 7. 按F12打开开发者工具
-
-# 8. 刷新页面(Ctrl + Shift + R)
-
-# 9. 查看Console是否有错误
-
-# 10. 查看Network请求状态
-```
-
----
-
-## 📋 快速自检清单
-
-测试前,请确认:
-
-- [ ] ✅ 后端终端显示"服务器启动成功"
-- [ ] ✅ 前端终端显示"Local: http://localhost:3000/"
-- [ ] ✅ 访问 http://localhost:3001/health 返回正常
-- [ ] ✅ 访问 http://localhost:3001/api/v1/projects 返回正常
-- [ ] ✅ 浏览器已清除缓存(Ctrl + Shift + R)
-- [ ] ✅ 开发者工具Network显示请求成功(200)
-- [ ] ✅ 开发者工具Console没有错误
-
----
-
-## 🆘 如果仍然失败
-
-请提供以下信息:
-
-1. **浏览器控制台截图**(F12 → Console标签)
-2. **Network请求详情截图**(F12 → Network标签 → 失败的请求)
-3. **后端终端日志**(最近20行)
-4. **前端终端日志**(最近20行)
-5. **运行结果:**
- ```
- 浏览器访问 http://localhost:3001/health
- 浏览器访问 http://localhost:3001/api/v1/projects
- ```
-
----
-
-**🎯 第一步:请先尝试 Ctrl + Shift + R 强制刷新浏览器!**
-
-这通常能解决90%的问题!
-
-
-
-
diff --git a/调试指南.md b/调试指南.md
deleted file mode 100644
index d1d7f374..00000000
--- a/调试指南.md
+++ /dev/null
@@ -1,239 +0,0 @@
-# 真实LLM筛选调试指南
-
-## 🎯 问题已修复!
-
-### 根本原因
-1. ❌ **PICOS字段名不匹配**:前端使用 P/I/C/O/S,但未映射
-2. ❌ **模型名格式不匹配**:前端使用 'DeepSeek-V3',API需要 'deepseek-chat'
-3. ❌ **缺少字段验证**:文献可能缺少title或abstract
-
-### 修复内容
-✅ 添加PICOS字段映射(P/I/C/O/S ↔ population/intervention/...)
-✅ 添加模型名映射(DeepSeek-V3 → deepseek-chat)
-✅ 添加文献验证(必须有title和abstract)
-✅ 增强调试日志(显示映射后的值)
-
-📄 详细报告:[字段映射问题修复.md](./docs/03-业务模块/ASL-AI智能文献/05-开发记录/2025-11-21-字段映射问题修复.md)
-
----
-
-## 🛠️ 排查步骤
-
-### Step 1: 检查API密钥
-
-```bash
-cd backend
-cat .env | findstr API_KEY
-```
-
-**必须配置**:
-```
-DEEPSEEK_API_KEY=sk-xxxxxxxxxxxxxx
-QWEN_API_KEY=sk-xxxxxxxxxxxxxx
-```
-
-如果没有配置,请添加到 `backend/.env` 文件。
-
----
-
-### Step 2: 重启后端(重要!)
-
-```bash
-# 停止当前后端
-Ctrl+C
-
-# 重新启动
-cd backend
-npm run dev
-```
-
-⚠️ **代码已修改,必须重启后端!**
-
----
-
-### Step 3: 清空旧数据(推荐)
-
-```bash
-cd backend
-node -e "
-const { PrismaClient } = require('@prisma/client');
-const prisma = new PrismaClient();
-
-async function cleanup() {
- // 删除最新项目的筛选结果和任务
- const project = await prisma.aslScreeningProject.findFirst({
- orderBy: { createdAt: 'desc' }
- });
-
- if (project) {
- await prisma.aslScreeningResult.deleteMany({
- where: { projectId: project.id }
- });
- await prisma.aslScreeningTask.deleteMany({
- where: { projectId: project.id }
- });
- console.log('✅ 已清空项目:', project.projectName);
- }
-
- await prisma.\$disconnect();
-}
-
-cleanup();
-"
-```
-
----
-
-### Step 4: 重新测试(从头开始)
-
-1. 访问前端:`http://localhost:3001`
-2. 点击"AI智能文献"
-3. 填写PICOS标准
-4. **上传少量文献测试**(建议先上传5篇,不要199篇)
-5. 点击"开始AI初筛"
-
----
-
-### Step 5: 查看后端控制台
-
-**应该看到**:
-```
-🚀 开始真实LLM筛选:
- 任务ID: xxx
- 项目ID: xxx
- 文献数: 5
- 模型: [ 'deepseek-chat', 'qwen-max' ]
- PICOS-P: xxx...
- PICOS-I: xxx...
-
-⏳ Processing literature 1/5...
-[等待10-20秒]
-
-✅ 文献 1/5 处理成功
- DS: include / Qwen: include
- 冲突: 否
-
-⏳ Processing literature 2/5...
-[等待10-20秒]
-
-✅ 文献 2/5 处理成功
- DS: exclude / Qwen: include
- 冲突: 是
-...
-```
-
-**如果看到错误**:
-```
-❌ 文献处理失败:
- 文献ID: xxx
- 标题: xxx
- 错误: [具体错误信息]
-```
-
-**记录错误信息并告诉我!**
-
----
-
-## 🔍 可能的错误原因
-
-### 错误1: API密钥未配置
-```
-Error: API key not found
-```
-**解决**:在 `backend/.env` 中添加API密钥
-
-### 错误2: API密钥无效
-```
-Error: 401 Unauthorized
-```
-**解决**:检查API密钥是否正确
-
-### 错误3: 网络问题
-```
-Error: ECONNREFUSED
-Error: timeout
-```
-**解决**:检查网络连接,是否需要代理
-
-### 错误4: PICOS格式错误
-```
-Error: Cannot read property 'P' of null
-```
-**解决**:检查项目的PICOS标准是否正确保存
-
-### 错误5: Prompt文件不存在
-```
-Error: Cannot find module './prompts/...'
-```
-**解决**:检查 `backend/prompts/asl/screening/v1.0.0-mvp.txt` 是否存在
-
----
-
-## 📊 成功标志
-
-### 后端控制台
-- ✅ 看到"🚀 开始真实LLM筛选"
-- ✅ 每篇文献处理耗时10-20秒
-- ✅ 看到"✅ 文献 X/Y 处理成功"
-- ✅ 看到DS和Qwen的结论
-
-### 数据库验证
-```bash
-node debug-screening.mjs
-```
-
-**应该看到**:
-- 筛选结果数 > 0
-- 成功数 > 0
-- DS证据不包含"模拟证据"
-- Prompt版本 = "v1.0.0-mvp"
-
-### 前端显示
-- ✅ 审核工作台显示文献
-- ✅ 点击标题展开,看到真实的英文证据
-- ✅ 证据不是"模拟证据: xxx"
-
----
-
-## 💡 调试技巧
-
-### 1. 使用少量文献测试
-不要一次上传199篇,先上传5篇测试。
-
-### 2. 查看完整错误
-如果出错,复制完整的错误栈信息。
-
-### 3. 检查环境变量
-确保API密钥正确加载:
-```javascript
-console.log('DeepSeek Key:', process.env.DEEPSEEK_API_KEY ? '已配置' : '未配置');
-console.log('Qwen Key:', process.env.QWEN_API_KEY ? '已配置' : '未配置');
-```
-
-### 4. 测试单个模型
-如果双模型都失败,可以尝试只使用一个模型测试。
-
----
-
-## 📝 报告问题时请提供
-
-1. ✅ 后端控制台的完整错误信息
-2. ✅ `node debug-screening.mjs` 的输出
-3. ✅ 浏览器控制台的错误(如果有)
-4. ✅ API密钥是否已配置(不要发送实际密钥)
-5. ✅ 网络环境(是否需要代理)
-
----
-
-## 🎯 下一步
-
-1. **立即执行**:重启后端
-2. **清空旧数据**:避免混淆
-3. **小规模测试**:先上传5篇文献
-4. **查看控制台**:记录所有错误信息
-5. **报告结果**:告诉我看到了什么
-
----
-
-**关键**:现在代码中已经添加了详细的调试日志,重启后端后,控制台会显示详细的处理过程和错误信息!
-
diff --git a/配置Docker镜像加速器.md b/配置Docker镜像加速器.md
deleted file mode 100644
index a1862fda..00000000
--- a/配置Docker镜像加速器.md
+++ /dev/null
@@ -1,112 +0,0 @@
-# Docker 镜像加速器配置指南
-
-## 📋 操作步骤
-
-### 1. 打开Docker Desktop设置
-
-1. 在系统托盘找到 **Docker Desktop** 图标(鲸鱼图标)
-2. **右键点击** → 选择 **Settings** (设置)
-
-### 2. 进入Docker Engine配置
-
-1. 在左侧菜单中点击 **Docker Engine**
-2. 您会看到一个JSON配置编辑器
-
-### 3. 添加镜像加速器配置
-
-在JSON配置中添加 `registry-mirrors` 配置项:
-
-**如果配置为空**,替换为:
-```json
-{
- "builder": {
- "gc": {
- "defaultKeepStorage": "20GB",
- "enabled": true
- }
- },
- "experimental": false,
- "registry-mirrors": [
- "https://docker.mirrors.ustc.edu.cn",
- "https://hub-mirror.c.163.com",
- "https://registry.docker-cn.com"
- ]
-}
-```
-
-**如果已有配置**,在现有配置中添加 `registry-mirrors` 部分:
-```json
-{
- "现有配置项...": "...",
- "registry-mirrors": [
- "https://docker.mirrors.ustc.edu.cn",
- "https://hub-mirror.c.163.com",
- "https://registry.docker-cn.com"
- ]
-}
-```
-
-### 4. 应用并重启
-
-1. 点击右下角的 **Apply & restart** 按钮
-2. 等待Docker Desktop重启(约30秒-1分钟)
-3. 确认Docker Desktop状态变为 "Running"(绿色)
-
-### 5. 验证配置
-
-打开PowerShell,运行:
-```powershell
-docker info | Select-String -Pattern "Registry Mirrors"
-```
-
-应该看到类似输出:
-```
-Registry Mirrors:
- https://docker.mirrors.ustc.edu.cn/
- https://hub-mirror.c.163.com/
- https://registry.docker-cn.com/
-```
-
----
-
-## ✅ 完成配置后
-
-配置完成后,请回到终端,我们将继续部署Dify。
-
----
-
-## 🔧 备选镜像源
-
-如果上述镜像源仍然有问题,可以尝试其他国内镜像源:
-
-```json
-{
- "registry-mirrors": [
- "https://dockerproxy.com",
- "https://mirror.baidubce.com",
- "https://docker.m.daocloud.io"
- ]
-}
-```
-
----
-
-## 📞 故障排查
-
-### 问题1:Docker Desktop无法重启
-- 完全关闭Docker Desktop
-- 在任务管理器中结束所有Docker相关进程
-- 重新启动Docker Desktop
-
-### 问题2:配置后仍无法拉取镜像
-- 检查网络连接
-- 尝试使用备选镜像源
-- 考虑使用VPN(如有)
-
----
-
-**完成配置后,请在终端告诉我,我们将继续下一步!**
-
-
-
-