Files
AIclinicalresearch/frontend-v2/src/modules/aia/components/AgentHub.tsx
HaHafeng 3d35e9c58b feat(aia): Complete AIA V2.0 with universal streaming capabilities
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
2026-01-14 19:09:28 +08:00

144 lines
4.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 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>&copy; 2025 - </p>
</footer>
</div>
);
};
export default AgentHub;