Major Updates: - Add StreamingService with OpenAI Compatible format (backend/common/streaming) - Upgrade Chat component V2 with Ant Design X integration - Implement AIA module with 12 intelligent agents - Create AgentHub with 100% prototype V11 restoration - Create ChatWorkspace with streaming response support - Add ThinkingBlock for deep thinking display - Add useAIStream Hook for OpenAI Compatible stream handling Backend Common Capabilities (~400 lines): - OpenAIStreamAdapter: SSE adapter with OpenAI format - StreamingService: unified streaming service - Support content and reasoning_content dual streams - Deep thinking tag processing (<think>...</think>) Frontend Common Capabilities (~2000 lines): - AIStreamChat: modern streaming chat component - ThinkingBlock: collapsible deep thinking display - ConversationList: conversation management with grouping - useAIStream: OpenAI Compatible stream handler Hook - useConversations: conversation state management Hook - Modern design styles (Ultramodern theme) AIA Module Frontend (~1500 lines): - AgentHub: 12 agent cards with timeline design - ChatWorkspace: fullscreen immersive chat interface - AgentCard: theme-colored cards (blue/yellow/teal/purple) - 5 phases, 12 agents configuration - Responsive layout (desktop + mobile) AIA Module Backend (~900 lines): - agentService: 12 agents config with system prompts - conversationService: refactored with StreamingService - attachmentService: file upload skeleton (30k token limit) - 12 API endpoints with authentication - Full CRUD for conversations and messages Documentation: - AIA module status and development guide - Universal capabilities catalog (11 services) - Quick reference card for developers - System overview updates Testing: - Stream response verified (HTTP 200) - Authentication working correctly - Auto conversation creation working - Deep thinking display working - Message input and send working Status: Core features completed (85%), attachment and history loading pending
144 lines
4.4 KiB
TypeScript
144 lines
4.4 KiB
TypeScript
/**
|
||
* AgentHub - 智能体大厅主界面
|
||
*
|
||
* 100%还原原型图V11:
|
||
* - 最大宽度 760px,居中
|
||
* - 头部搜索框
|
||
* - 时间轴设计(左侧序号圆点+连接线)
|
||
* - 5个阶段,12个智能体卡片
|
||
*/
|
||
|
||
import React, { useState, useMemo } from 'react';
|
||
import { BrainCircuit, Search } from 'lucide-react';
|
||
import { AgentCard } from './AgentCard';
|
||
import { AGENTS, PHASES } from '../constants';
|
||
import type { AgentConfig } from '../types';
|
||
import '../styles/agent-hub.css';
|
||
|
||
interface AgentHubProps {
|
||
onAgentSelect: (agent: AgentConfig) => void;
|
||
}
|
||
|
||
export const AgentHub: React.FC<AgentHubProps> = ({ onAgentSelect }) => {
|
||
const [searchValue, setSearchValue] = useState('');
|
||
|
||
// 按阶段分组智能体
|
||
const agentsByPhase = useMemo(() => {
|
||
const grouped: Record<number, AgentConfig[]> = {};
|
||
AGENTS.forEach(agent => {
|
||
if (!grouped[agent.phase]) {
|
||
grouped[agent.phase] = [];
|
||
}
|
||
grouped[agent.phase].push(agent);
|
||
});
|
||
return grouped;
|
||
}, []);
|
||
|
||
// 搜索提交
|
||
const handleSearch = () => {
|
||
if (searchValue.trim()) {
|
||
// 默认进入第一个智能体并携带搜索内容
|
||
const firstAgent = AGENTS[0];
|
||
onAgentSelect({ ...firstAgent, initialQuery: searchValue } as any);
|
||
}
|
||
};
|
||
|
||
const handleKeyDown = (e: React.KeyboardEvent) => {
|
||
if (e.key === 'Enter') {
|
||
handleSearch();
|
||
}
|
||
};
|
||
|
||
return (
|
||
<div className="agent-hub">
|
||
{/* 主体内容 */}
|
||
<main className="hub-main">
|
||
{/* 头部搜索区 */}
|
||
<div className="hub-header">
|
||
<div className="header-title">
|
||
<div className="title-icon">
|
||
<BrainCircuit size={24} />
|
||
</div>
|
||
<h1 className="title-text">
|
||
医学研究专属大模型
|
||
<span className="title-badge">已接入DeepSeek</span>
|
||
</h1>
|
||
</div>
|
||
|
||
<div className="search-box">
|
||
<input
|
||
type="text"
|
||
placeholder="输入研究想法,例如:SGLT2抑制剂对心衰患者预后的影响..."
|
||
value={searchValue}
|
||
onChange={(e) => setSearchValue(e.target.value)}
|
||
onKeyDown={handleKeyDown}
|
||
className="search-input"
|
||
/>
|
||
<button className="search-btn" onClick={handleSearch}>
|
||
<Search size={20} />
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
{/* 流水线模块 */}
|
||
<div className="pipeline-container">
|
||
{PHASES.map((phase, phaseIndex) => {
|
||
const isLast = phaseIndex === PHASES.length - 1;
|
||
const agents = agentsByPhase[phase.phase] || [];
|
||
|
||
// 根据阶段确定列数
|
||
let gridCols = 'grid-cols-3';
|
||
if (phase.phase === 2) gridCols = 'grid-cols-3'; // 4个卡片,每行3个
|
||
if (phase.phase === 3) gridCols = 'grid-cols-3'; // 1个卡片
|
||
if (phase.phase === 4) gridCols = 'grid-cols-3'; // 2个卡片
|
||
if (phase.phase === 5) gridCols = 'grid-cols-3'; // 2个卡片
|
||
|
||
return (
|
||
<div
|
||
key={phase.phase}
|
||
className={`pipeline-stage ${isLast ? 'last-stage' : ''}`}
|
||
>
|
||
{/* 左侧时间轴 */}
|
||
<div className="timeline-marker">
|
||
<div className={`timeline-dot theme-${phase.theme}`}>
|
||
{phase.phase}
|
||
</div>
|
||
{!isLast && <div className="timeline-line" />}
|
||
</div>
|
||
|
||
{/* 阶段内容 */}
|
||
<div className="stage-content">
|
||
<h2 className="stage-title">
|
||
{phase.name}
|
||
{phase.isTool && (
|
||
<span className="tool-badge">工具</span>
|
||
)}
|
||
</h2>
|
||
|
||
<div className={`agents-grid ${gridCols}`}>
|
||
{agents.map(agent => (
|
||
<AgentCard
|
||
key={agent.id}
|
||
agent={agent}
|
||
onClick={onAgentSelect}
|
||
/>
|
||
))}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
);
|
||
})}
|
||
</div>
|
||
</main>
|
||
|
||
{/* 底部 */}
|
||
<footer className="hub-footer">
|
||
<p>© 2025 临床研究平台 - 医学研究专属大模型</p>
|
||
</footer>
|
||
</div>
|
||
);
|
||
};
|
||
|
||
export default AgentHub;
|
||
|