diff --git a/src/views/AgentChat/constants/animations.ts b/src/views/AgentChat/constants/animations.ts new file mode 100644 index 00000000..5cd5e77a --- /dev/null +++ b/src/views/AgentChat/constants/animations.ts @@ -0,0 +1,101 @@ +// src/views/AgentChat/constants/animations.ts +// Framer Motion 动画变体配置 + +import { Variants } from 'framer-motion'; + +/** + * Framer Motion 动画变体配置 + * 用于 AgentChat 组件的各种动画效果 + */ +export const animations: Record = { + /** + * 左侧栏滑入动画(Spring 物理引擎) + * 从左侧滑入,使用弹性动画 + */ + slideInLeft: { + initial: { x: -320, opacity: 0 }, + animate: { + x: 0, + opacity: 1, + transition: { + type: 'spring', + stiffness: 300, + damping: 30, + }, + }, + exit: { + x: -320, + opacity: 0, + transition: { duration: 0.2 }, + }, + }, + + /** + * 右侧栏滑入动画(Spring 物理引擎) + * 从右侧滑入,使用弹性动画 + */ + slideInRight: { + initial: { x: 320, opacity: 0 }, + animate: { + x: 0, + opacity: 1, + transition: { + type: 'spring', + stiffness: 300, + damping: 30, + }, + }, + exit: { + x: 320, + opacity: 0, + transition: { duration: 0.2 }, + }, + }, + + /** + * 消息淡入上移动画 + * 用于新消息出现时的动画效果 + */ + fadeInUp: { + initial: { opacity: 0, y: 20 }, + animate: { + opacity: 1, + y: 0, + transition: { + type: 'spring', + stiffness: 400, + damping: 25, + }, + }, + }, + + /** + * 错开动画项 + * 用于列表项的错开出现效果 + */ + staggerItem: { + initial: { opacity: 0, y: 10 }, + animate: { opacity: 1, y: 0 }, + }, + + /** + * 错开动画容器 + * 用于包含多个子项的容器,使子项依次出现 + */ + staggerContainer: { + animate: { + transition: { + staggerChildren: 0.05, + }, + }, + }, + + /** + * 按压缩放动画 + * 用于按钮等交互元素的点击/悬停效果 + */ + pressScale: { + whileTap: { scale: 0.95 }, + whileHover: { scale: 1.05 }, + }, +}; diff --git a/src/views/AgentChat/constants/index.ts b/src/views/AgentChat/constants/index.ts new file mode 100644 index 00000000..35c32e62 --- /dev/null +++ b/src/views/AgentChat/constants/index.ts @@ -0,0 +1,22 @@ +// src/views/AgentChat/constants/index.ts +// 常量配置统一导出 + +/** + * 统一导出所有常量配置模块 + * + * 使用示例: + * ```typescript + * // 方式 1: 从子模块导入(推荐,按需引入) + * import { animations } from './constants/animations'; + * import { MessageTypes } from './constants/messageTypes'; + * + * // 方式 2: 从统一入口导入 + * import { animations, MessageTypes, AVAILABLE_MODELS } from './constants'; + * ``` + */ + +export * from './animations'; +export * from './messageTypes'; +export * from './models'; +export * from './tools'; +export * from './quickQuestions'; diff --git a/src/views/AgentChat/constants/messageTypes.ts b/src/views/AgentChat/constants/messageTypes.ts new file mode 100644 index 00000000..1d5de3c6 --- /dev/null +++ b/src/views/AgentChat/constants/messageTypes.ts @@ -0,0 +1,93 @@ +// src/views/AgentChat/constants/messageTypes.ts +// 消息类型定义 + +/** + * 消息类型枚举 + * 定义 Agent Chat 中所有可能的消息类型 + */ +export enum MessageTypes { + /** 用户消息 */ + USER = 'user', + /** Agent 思考中状态 */ + AGENT_THINKING = 'agent_thinking', + /** Agent 执行计划 */ + AGENT_PLAN = 'agent_plan', + /** Agent 执行步骤中 */ + AGENT_EXECUTING = 'agent_executing', + /** Agent 最终回复 */ + AGENT_RESPONSE = 'agent_response', + /** 错误消息 */ + ERROR = 'error', +} + +/** + * 文件附件接口 + */ +export interface MessageFile { + /** 文件名称 */ + name: string; + /** 文件大小(字节)*/ + size: number; + /** MIME 类型 */ + type: string; + /** 文件 URL(本地或远程)*/ + url: string; +} + +/** + * 消息基础接口 + */ +export interface BaseMessage { + /** 消息唯一标识 */ + id: string | number; + /** 消息类型 */ + type: MessageTypes; + /** 消息内容 */ + content: string; + /** 时间戳(ISO 8601 格式)*/ + timestamp: string; +} + +/** + * 用户消息接口 + */ +export interface UserMessage extends BaseMessage { + type: MessageTypes.USER; + /** 上传的文件附件 */ + files?: MessageFile[]; +} + +/** + * Agent 消息接口 + */ +export interface AgentMessage extends BaseMessage { + type: + | MessageTypes.AGENT_RESPONSE + | MessageTypes.AGENT_THINKING + | MessageTypes.AGENT_PLAN + | MessageTypes.AGENT_EXECUTING; + /** 执行计划(JSON 对象)*/ + plan?: any; + /** 执行步骤结果 */ + stepResults?: Array<{ + tool_name: string; + status: 'success' | 'error'; + execution_time?: number; + error?: string; + }>; + /** 额外元数据 */ + metadata?: any; +} + +/** + * 错误消息接口 + */ +export interface ErrorMessage extends BaseMessage { + type: MessageTypes.ERROR; +} + +/** + * 消息联合类型 + * 用于表示任意类型的消息 + */ +export type Message = UserMessage | AgentMessage | ErrorMessage; diff --git a/src/views/AgentChat/constants/models.ts b/src/views/AgentChat/constants/models.ts new file mode 100644 index 00000000..1e81adf3 --- /dev/null +++ b/src/views/AgentChat/constants/models.ts @@ -0,0 +1,63 @@ +// src/views/AgentChat/constants/models.ts +// 可用模型配置 + +import React from 'react'; +import { Brain, Zap, TrendingUp } from 'lucide-react'; + +/** + * 模型配置接口 + */ +export interface ModelConfig { + /** 模型唯一标识 */ + id: string; + /** 模型显示名称 */ + name: string; + /** 模型描述 */ + description: string; + /** 模型图标(React 元素)*/ + icon: React.ReactNode; + /** 颜色主题 */ + color: string; +} + +/** + * 可用模型配置列表 + * 包含所有可供用户选择的 AI 模型 + */ +export const AVAILABLE_MODELS: ModelConfig[] = [ + { + id: 'kimi-k2-thinking', + name: 'Kimi K2 Thinking', + description: '深度思考模型,适合复杂分析', + icon: React.createElement(Brain, { className: 'w-5 h-5' }), + color: 'purple', + }, + { + id: 'kimi-k2', + name: 'Kimi K2', + description: '快速响应模型,适合简单查询', + icon: React.createElement(Zap, { className: 'w-5 h-5' }), + color: 'blue', + }, + { + id: 'deepmoney', + name: 'DeepMoney', + description: '金融专业模型', + icon: React.createElement(TrendingUp, { className: 'w-5 h-5' }), + color: 'green', + }, +]; + +/** + * 默认选中的模型 ID + */ +export const DEFAULT_MODEL_ID = 'kimi-k2-thinking'; + +/** + * 根据 ID 查找模型配置 + * @param modelId 模型 ID + * @returns 模型配置对象,未找到则返回 undefined + */ +export const findModelById = (modelId: string): ModelConfig | undefined => { + return AVAILABLE_MODELS.find((model) => model.id === modelId); +}; diff --git a/src/views/AgentChat/constants/quickQuestions.ts b/src/views/AgentChat/constants/quickQuestions.ts new file mode 100644 index 00000000..e275051e --- /dev/null +++ b/src/views/AgentChat/constants/quickQuestions.ts @@ -0,0 +1,23 @@ +// src/views/AgentChat/constants/quickQuestions.ts +// 快捷问题配置 + +/** + * 快捷问题配置接口 + */ +export interface QuickQuestion { + /** 问题文本 */ + text: string; + /** 表情符号 */ + emoji: string; +} + +/** + * 预设快捷问题列表 + * 用于在聊天界面初始状态显示,帮助用户快速开始对话 + */ +export const quickQuestions: QuickQuestion[] = [ + { text: '今日涨停板块分析', emoji: '🔥' }, + { text: '新能源概念机会', emoji: '⚡' }, + { text: '半导体行业动态', emoji: '💾' }, + { text: '本周热门研报', emoji: '📊' }, +]; diff --git a/src/views/AgentChat/constants/tools.ts b/src/views/AgentChat/constants/tools.ts new file mode 100644 index 00000000..45390fb5 --- /dev/null +++ b/src/views/AgentChat/constants/tools.ts @@ -0,0 +1,249 @@ +// src/views/AgentChat/constants/tools.ts +// MCP 工具配置 + +import React from 'react'; +import { + Globe, + Newspaper, + Activity, + PieChart, + FileText, + BarChart3, + LineChart, + TrendingUp, + Calendar, + BookOpen, + Briefcase, + DollarSign, + Search, + Users, +} from 'lucide-react'; + +/** + * 工具类别枚举 + */ +export enum ToolCategory { + NEWS = '新闻资讯', + CONCEPT = '概念板块', + LIMIT_UP = '涨停分析', + RESEARCH = '研报路演', + STOCK_DATA = '股票数据', + USER_DATA = '用户数据', +} + +/** + * MCP 工具配置接口 + */ +export interface MCPTool { + /** 工具唯一标识 */ + id: string; + /** 工具显示名称 */ + name: string; + /** 工具图标(React 元素)*/ + icon: React.ReactNode; + /** 工具类别 */ + category: ToolCategory; + /** 工具描述 */ + description: string; +} + +/** + * MCP 工具完整配置列表 + * 包含所有可供 Agent 调用的工具 + */ +export const MCP_TOOLS: MCPTool[] = [ + // ==================== 新闻搜索类 ==================== + { + id: 'search_news', + name: '全球新闻搜索', + icon: React.createElement(Globe, { className: 'w-4 h-4' }), + category: ToolCategory.NEWS, + description: '搜索全球新闻,支持关键词和日期过滤', + }, + { + id: 'search_china_news', + name: '中国新闻搜索', + icon: React.createElement(Newspaper, { className: 'w-4 h-4' }), + category: ToolCategory.NEWS, + description: 'KNN语义搜索中国新闻', + }, + { + id: 'search_medical_news', + name: '医疗健康新闻', + icon: React.createElement(Activity, { className: 'w-4 h-4' }), + category: ToolCategory.NEWS, + description: '医药、医疗设备、生物技术新闻', + }, + + // ==================== 概念板块类 ==================== + { + id: 'search_concepts', + name: '概念板块搜索', + icon: React.createElement(PieChart, { className: 'w-4 h-4' }), + category: ToolCategory.CONCEPT, + description: '搜索股票概念板块及相关股票', + }, + { + id: 'get_concept_details', + name: '概念详情', + icon: React.createElement(FileText, { className: 'w-4 h-4' }), + category: ToolCategory.CONCEPT, + description: '获取概念板块详细信息', + }, + { + id: 'get_stock_concepts', + name: '股票概念', + icon: React.createElement(BarChart3, { className: 'w-4 h-4' }), + category: ToolCategory.CONCEPT, + description: '查询股票相关概念板块', + }, + { + id: 'get_concept_statistics', + name: '概念统计', + icon: React.createElement(LineChart, { className: 'w-4 h-4' }), + category: ToolCategory.CONCEPT, + description: '涨幅榜、跌幅榜、活跃榜等', + }, + + // ==================== 涨停分析类 ==================== + { + id: 'search_limit_up_stocks', + name: '涨停股票搜索', + icon: React.createElement(TrendingUp, { className: 'w-4 h-4' }), + category: ToolCategory.LIMIT_UP, + description: '搜索涨停股票,支持多条件筛选', + }, + { + id: 'get_daily_stock_analysis', + name: '涨停日报', + icon: React.createElement(Calendar, { className: 'w-4 h-4' }), + category: ToolCategory.LIMIT_UP, + description: '每日涨停股票分析报告', + }, + + // ==================== 研报路演类 ==================== + { + id: 'search_research_reports', + name: '研报搜索', + icon: React.createElement(BookOpen, { className: 'w-4 h-4' }), + category: ToolCategory.RESEARCH, + description: '搜索研究报告,支持语义搜索', + }, + { + id: 'search_roadshows', + name: '路演活动', + icon: React.createElement(Briefcase, { className: 'w-4 h-4' }), + category: ToolCategory.RESEARCH, + description: '上市公司路演、投资者交流活动', + }, + + // ==================== 股票数据类 ==================== + { + id: 'get_stock_basic_info', + name: '股票基本信息', + icon: React.createElement(FileText, { className: 'w-4 h-4' }), + category: ToolCategory.STOCK_DATA, + description: '公司名称、行业、主营业务等', + }, + { + id: 'get_stock_financial_index', + name: '财务指标', + icon: React.createElement(DollarSign, { className: 'w-4 h-4' }), + category: ToolCategory.STOCK_DATA, + description: 'EPS、ROE、营收增长率等', + }, + { + id: 'get_stock_trade_data', + name: '交易数据', + icon: React.createElement(BarChart3, { className: 'w-4 h-4' }), + category: ToolCategory.STOCK_DATA, + description: '价格、成交量、涨跌幅等', + }, + { + id: 'get_stock_balance_sheet', + name: '资产负债表', + icon: React.createElement(PieChart, { className: 'w-4 h-4' }), + category: ToolCategory.STOCK_DATA, + description: '资产、负债、所有者权益', + }, + { + id: 'get_stock_cashflow', + name: '现金流量表', + icon: React.createElement(LineChart, { className: 'w-4 h-4' }), + category: ToolCategory.STOCK_DATA, + description: '经营、投资、筹资现金流', + }, + { + id: 'search_stocks_by_criteria', + name: '条件选股', + icon: React.createElement(Search, { className: 'w-4 h-4' }), + category: ToolCategory.STOCK_DATA, + description: '按行业、地区、市值筛选', + }, + { + id: 'get_stock_comparison', + name: '股票对比', + icon: React.createElement(BarChart3, { className: 'w-4 h-4' }), + category: ToolCategory.STOCK_DATA, + description: '多只股票财务指标对比', + }, + + // ==================== 用户数据类 ==================== + { + id: 'get_user_watchlist', + name: '自选股列表', + icon: React.createElement(Users, { className: 'w-4 h-4' }), + category: ToolCategory.USER_DATA, + description: '用户关注的股票及行情', + }, + { + id: 'get_user_following_events', + name: '关注事件', + icon: React.createElement(Activity, { className: 'w-4 h-4' }), + category: ToolCategory.USER_DATA, + description: '用户关注的重大事件', + }, +]; + +/** + * 按类别分组的工具配置 + * 用于在 UI 中按类别展示工具 + */ +export const TOOL_CATEGORIES: Record = { + [ToolCategory.NEWS]: MCP_TOOLS.filter((t) => t.category === ToolCategory.NEWS), + [ToolCategory.CONCEPT]: MCP_TOOLS.filter((t) => t.category === ToolCategory.CONCEPT), + [ToolCategory.LIMIT_UP]: MCP_TOOLS.filter((t) => t.category === ToolCategory.LIMIT_UP), + [ToolCategory.RESEARCH]: MCP_TOOLS.filter((t) => t.category === ToolCategory.RESEARCH), + [ToolCategory.STOCK_DATA]: MCP_TOOLS.filter((t) => t.category === ToolCategory.STOCK_DATA), + [ToolCategory.USER_DATA]: MCP_TOOLS.filter((t) => t.category === ToolCategory.USER_DATA), +}; + +/** + * 默认选中的工具 ID 列表 + * 这些工具在页面初始化时自动选中 + */ +export const DEFAULT_SELECTED_TOOLS: string[] = [ + 'search_news', + 'search_china_news', + 'search_concepts', + 'search_limit_up_stocks', + 'search_research_reports', +]; + +/** + * 根据 ID 查找工具配置 + * @param toolId 工具 ID + * @returns 工具配置对象,未找到则返回 undefined + */ +export const findToolById = (toolId: string): MCPTool | undefined => { + return MCP_TOOLS.find((tool) => tool.id === toolId); +}; + +/** + * 根据类别获取工具列表 + * @param category 工具类别 + * @returns 该类别下的所有工具 + */ +export const getToolsByCategory = (category: ToolCategory): MCPTool[] => { + return TOOL_CATEGORIES[category] || []; +}; diff --git a/src/views/AgentChat/index.js b/src/views/AgentChat/index.js index 9a89bf5b..7446357f 100644 --- a/src/views/AgentChat/index.js +++ b/src/views/AgentChat/index.js @@ -92,281 +92,22 @@ import { Users, } from 'lucide-react'; -/** - * Framer Motion 动画变体配置 - */ -const animations = { - slideInLeft: { - initial: { x: -320, opacity: 0 }, - animate: { - x: 0, - opacity: 1, - transition: { - type: 'spring', - stiffness: 300, - damping: 30, - }, - }, - exit: { - x: -320, - opacity: 0, - transition: { duration: 0.2 }, - }, - }, - slideInRight: { - initial: { x: 320, opacity: 0 }, - animate: { - x: 0, - opacity: 1, - transition: { - type: 'spring', - stiffness: 300, - damping: 30, - }, - }, - exit: { - x: 320, - opacity: 0, - transition: { duration: 0.2 }, - }, - }, - fadeInUp: { - initial: { opacity: 0, y: 20 }, - animate: { - opacity: 1, - y: 0, - transition: { - type: 'spring', - stiffness: 400, - damping: 25, - }, - }, - }, - staggerItem: { - initial: { opacity: 0, y: 10 }, - animate: { opacity: 1, y: 0 }, - }, - staggerContainer: { - animate: { - transition: { - staggerChildren: 0.05, - }, - }, - }, - pressScale: { - whileTap: { scale: 0.95 }, - whileHover: { scale: 1.05 }, - }, -}; - -/** - * 消息类型 - */ -const MessageTypes = { - USER: 'user', - AGENT_THINKING: 'agent_thinking', - AGENT_PLAN: 'agent_plan', - AGENT_EXECUTING: 'agent_executing', - AGENT_RESPONSE: 'agent_response', - ERROR: 'error', -}; - -/** - * 可用模型配置 - */ -const AVAILABLE_MODELS = [ - { - id: 'kimi-k2-thinking', - name: 'Kimi K2 Thinking', - description: '深度思考模型,适合复杂分析', - icon: , - color: 'purple', - }, - { - id: 'kimi-k2', - name: 'Kimi K2', - description: '快速响应模型,适合简单查询', - icon: , - color: 'blue', - }, - { - id: 'deepmoney', - name: 'DeepMoney', - description: '金融专业模型', - icon: , - color: 'green', - }, -]; - -/** - * MCP 工具配置(完整列表) - */ -const MCP_TOOLS = [ - // 新闻搜索类 - { - id: 'search_news', - name: '全球新闻搜索', - icon: , - category: '新闻资讯', - description: '搜索全球新闻,支持关键词和日期过滤' - }, - { - id: 'search_china_news', - name: '中国新闻搜索', - icon: , - category: '新闻资讯', - description: 'KNN语义搜索中国新闻' - }, - { - id: 'search_medical_news', - name: '医疗健康新闻', - icon: , - category: '新闻资讯', - description: '医药、医疗设备、生物技术新闻' - }, - - // 概念板块类 - { - id: 'search_concepts', - name: '概念板块搜索', - icon: , - category: '概念板块', - description: '搜索股票概念板块及相关股票' - }, - { - id: 'get_concept_details', - name: '概念详情', - icon: , - category: '概念板块', - description: '获取概念板块详细信息' - }, - { - id: 'get_stock_concepts', - name: '股票概念', - icon: , - category: '概念板块', - description: '查询股票相关概念板块' - }, - { - id: 'get_concept_statistics', - name: '概念统计', - icon: , - category: '概念板块', - description: '涨幅榜、跌幅榜、活跃榜等' - }, - - // 涨停分析类 - { - id: 'search_limit_up_stocks', - name: '涨停股票搜索', - icon: , - category: '涨停分析', - description: '搜索涨停股票,支持多条件筛选' - }, - { - id: 'get_daily_stock_analysis', - name: '涨停日报', - icon: , - category: '涨停分析', - description: '每日涨停股票分析报告' - }, - - // 研报路演类 - { - id: 'search_research_reports', - name: '研报搜索', - icon: , - category: '研报路演', - description: '搜索研究报告,支持语义搜索' - }, - { - id: 'search_roadshows', - name: '路演活动', - icon: , - category: '研报路演', - description: '上市公司路演、投资者交流活动' - }, - - // 股票数据类 - { - id: 'get_stock_basic_info', - name: '股票基本信息', - icon: , - category: '股票数据', - description: '公司名称、行业、主营业务等' - }, - { - id: 'get_stock_financial_index', - name: '财务指标', - icon: , - category: '股票数据', - description: 'EPS、ROE、营收增长率等' - }, - { - id: 'get_stock_trade_data', - name: '交易数据', - icon: , - category: '股票数据', - description: '价格、成交量、涨跌幅等' - }, - { - id: 'get_stock_balance_sheet', - name: '资产负债表', - icon: , - category: '股票数据', - description: '资产、负债、所有者权益' - }, - { - id: 'get_stock_cashflow', - name: '现金流量表', - icon: , - category: '股票数据', - description: '经营、投资、筹资现金流' - }, - { - id: 'search_stocks_by_criteria', - name: '条件选股', - icon: , - category: '股票数据', - description: '按行业、地区、市值筛选' - }, - { - id: 'get_stock_comparison', - name: '股票对比', - icon: , - category: '股票数据', - description: '多只股票财务指标对比' - }, - - // 用户数据类 - { - id: 'get_user_watchlist', - name: '自选股列表', - icon: , - category: '用户数据', - description: '用户关注的股票及行情' - }, - { - id: 'get_user_following_events', - name: '关注事件', - icon: , - category: '用户数据', - description: '用户关注的重大事件' - }, -]; - -// 按类别分组工具 -const TOOL_CATEGORIES = { - '新闻资讯': MCP_TOOLS.filter(t => t.category === '新闻资讯'), - '概念板块': MCP_TOOLS.filter(t => t.category === '概念板块'), - '涨停分析': MCP_TOOLS.filter(t => t.category === '涨停分析'), - '研报路演': MCP_TOOLS.filter(t => t.category === '研报路演'), - '股票数据': MCP_TOOLS.filter(t => t.category === '股票数据'), - '用户数据': MCP_TOOLS.filter(t => t.category === '用户数据'), -}; +// 常量配置 - 从 TypeScript 模块导入 +import { animations } from './constants/animations'; +import { MessageTypes } from './constants/messageTypes'; +import { AVAILABLE_MODELS, DEFAULT_MODEL_ID } from './constants/models'; +import { MCP_TOOLS, TOOL_CATEGORIES, DEFAULT_SELECTED_TOOLS } from './constants/tools'; +import { quickQuestions } from './constants/quickQuestions'; /** * Agent Chat - 主组件(HeroUI v3 深色主题) + * + * 注意:所有常量配置已提取到 constants/ 目录: + * - animations: constants/animations.ts + * - MessageTypes: constants/messageTypes.ts + * - AVAILABLE_MODELS: constants/models.ts + * - MCP_TOOLS, TOOL_CATEGORIES: constants/tools.ts + * - quickQuestions: constants/quickQuestions.ts */ const AgentChat = () => { const { user } = useAuth(); @@ -385,14 +126,8 @@ const AgentChat = () => { // UI 状态 const [searchQuery, setSearchQuery] = useState(''); - const [selectedModel, setSelectedModel] = useState('kimi-k2-thinking'); - const [selectedTools, setSelectedTools] = useState([ - 'search_news', - 'search_china_news', - 'search_concepts', - 'search_limit_up_stocks', - 'search_research_reports', - ]); + const [selectedModel, setSelectedModel] = useState(DEFAULT_MODEL_ID); + const [selectedTools, setSelectedTools] = useState(DEFAULT_SELECTED_TOOLS); const [isLeftSidebarOpen, setIsLeftSidebarOpen] = useState(true); const [isRightSidebarOpen, setIsRightSidebarOpen] = useState(true); @@ -666,16 +401,11 @@ const AgentChat = () => { ) : sessions; - const quickQuestions = [ - { text: '今日涨停板块分析', emoji: '🔥' }, - { text: '新能源概念机会', emoji: '⚡' }, - { text: '半导体行业动态', emoji: '💾' }, - { text: '本周热门研报', emoji: '📊' }, - ]; + // quickQuestions 已移动到 constants/quickQuestions.ts return ( - - + + {/* 背景渐变层 - 移到 Flex 内部 */}