feat: 提取常量配置

This commit is contained in:
zdl
2025-11-24 14:31:50 +08:00
parent 9b068fd69f
commit 13040b5df8
7 changed files with 569 additions and 288 deletions

View File

@@ -0,0 +1,101 @@
// src/views/AgentChat/constants/animations.ts
// Framer Motion 动画变体配置
import { Variants } from 'framer-motion';
/**
* Framer Motion 动画变体配置
* 用于 AgentChat 组件的各种动画效果
*/
export const animations: Record<string, Variants> = {
/**
* 左侧栏滑入动画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 },
},
};

View File

@@ -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';

View File

@@ -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;

View File

@@ -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);
};

View File

@@ -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: '📊' },
];

View File

@@ -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, MCPTool[]> = {
[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] || [];
};

View File

@@ -92,281 +92,22 @@ import {
Users, Users,
} from 'lucide-react'; } from 'lucide-react';
/** // 常量配置 - 从 TypeScript 模块导入
* Framer Motion 动画变体配置 import { animations } from './constants/animations';
*/ import { MessageTypes } from './constants/messageTypes';
const animations = { import { AVAILABLE_MODELS, DEFAULT_MODEL_ID } from './constants/models';
slideInLeft: { import { MCP_TOOLS, TOOL_CATEGORIES, DEFAULT_SELECTED_TOOLS } from './constants/tools';
initial: { x: -320, opacity: 0 }, import { quickQuestions } from './constants/quickQuestions';
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: <Brain className="w-5 h-5" />,
color: 'purple',
},
{
id: 'kimi-k2',
name: 'Kimi K2',
description: '快速响应模型,适合简单查询',
icon: <Zap className="w-5 h-5" />,
color: 'blue',
},
{
id: 'deepmoney',
name: 'DeepMoney',
description: '金融专业模型',
icon: <TrendingUp className="w-5 h-5" />,
color: 'green',
},
];
/**
* MCP 工具配置(完整列表)
*/
const MCP_TOOLS = [
// 新闻搜索类
{
id: 'search_news',
name: '全球新闻搜索',
icon: <Globe className="w-4 h-4" />,
category: '新闻资讯',
description: '搜索全球新闻,支持关键词和日期过滤'
},
{
id: 'search_china_news',
name: '中国新闻搜索',
icon: <Newspaper className="w-4 h-4" />,
category: '新闻资讯',
description: 'KNN语义搜索中国新闻'
},
{
id: 'search_medical_news',
name: '医疗健康新闻',
icon: <Activity className="w-4 h-4" />,
category: '新闻资讯',
description: '医药、医疗设备、生物技术新闻'
},
// 概念板块类
{
id: 'search_concepts',
name: '概念板块搜索',
icon: <PieChart className="w-4 h-4" />,
category: '概念板块',
description: '搜索股票概念板块及相关股票'
},
{
id: 'get_concept_details',
name: '概念详情',
icon: <FileText className="w-4 h-4" />,
category: '概念板块',
description: '获取概念板块详细信息'
},
{
id: 'get_stock_concepts',
name: '股票概念',
icon: <BarChart3 className="w-4 h-4" />,
category: '概念板块',
description: '查询股票相关概念板块'
},
{
id: 'get_concept_statistics',
name: '概念统计',
icon: <LineChart className="w-4 h-4" />,
category: '概念板块',
description: '涨幅榜、跌幅榜、活跃榜等'
},
// 涨停分析类
{
id: 'search_limit_up_stocks',
name: '涨停股票搜索',
icon: <TrendingUp className="w-4 h-4" />,
category: '涨停分析',
description: '搜索涨停股票,支持多条件筛选'
},
{
id: 'get_daily_stock_analysis',
name: '涨停日报',
icon: <Calendar className="w-4 h-4" />,
category: '涨停分析',
description: '每日涨停股票分析报告'
},
// 研报路演类
{
id: 'search_research_reports',
name: '研报搜索',
icon: <BookOpen className="w-4 h-4" />,
category: '研报路演',
description: '搜索研究报告,支持语义搜索'
},
{
id: 'search_roadshows',
name: '路演活动',
icon: <Briefcase className="w-4 h-4" />,
category: '研报路演',
description: '上市公司路演、投资者交流活动'
},
// 股票数据类
{
id: 'get_stock_basic_info',
name: '股票基本信息',
icon: <FileText className="w-4 h-4" />,
category: '股票数据',
description: '公司名称、行业、主营业务等'
},
{
id: 'get_stock_financial_index',
name: '财务指标',
icon: <DollarSign className="w-4 h-4" />,
category: '股票数据',
description: 'EPS、ROE、营收增长率等'
},
{
id: 'get_stock_trade_data',
name: '交易数据',
icon: <BarChart3 className="w-4 h-4" />,
category: '股票数据',
description: '价格、成交量、涨跌幅等'
},
{
id: 'get_stock_balance_sheet',
name: '资产负债表',
icon: <PieChart className="w-4 h-4" />,
category: '股票数据',
description: '资产、负债、所有者权益'
},
{
id: 'get_stock_cashflow',
name: '现金流量表',
icon: <LineChart className="w-4 h-4" />,
category: '股票数据',
description: '经营、投资、筹资现金流'
},
{
id: 'search_stocks_by_criteria',
name: '条件选股',
icon: <Search className="w-4 h-4" />,
category: '股票数据',
description: '按行业、地区、市值筛选'
},
{
id: 'get_stock_comparison',
name: '股票对比',
icon: <BarChart3 className="w-4 h-4" />,
category: '股票数据',
description: '多只股票财务指标对比'
},
// 用户数据类
{
id: 'get_user_watchlist',
name: '自选股列表',
icon: <Users className="w-4 h-4" />,
category: '用户数据',
description: '用户关注的股票及行情'
},
{
id: 'get_user_following_events',
name: '关注事件',
icon: <Activity className="w-4 h-4" />,
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 === '用户数据'),
};
/** /**
* Agent Chat - 主组件HeroUI v3 深色主题) * 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 AgentChat = () => {
const { user } = useAuth(); const { user } = useAuth();
@@ -385,14 +126,8 @@ const AgentChat = () => {
// UI 状态 // UI 状态
const [searchQuery, setSearchQuery] = useState(''); const [searchQuery, setSearchQuery] = useState('');
const [selectedModel, setSelectedModel] = useState('kimi-k2-thinking'); const [selectedModel, setSelectedModel] = useState(DEFAULT_MODEL_ID);
const [selectedTools, setSelectedTools] = useState([ const [selectedTools, setSelectedTools] = useState(DEFAULT_SELECTED_TOOLS);
'search_news',
'search_china_news',
'search_concepts',
'search_limit_up_stocks',
'search_research_reports',
]);
const [isLeftSidebarOpen, setIsLeftSidebarOpen] = useState(true); const [isLeftSidebarOpen, setIsLeftSidebarOpen] = useState(true);
const [isRightSidebarOpen, setIsRightSidebarOpen] = useState(true); const [isRightSidebarOpen, setIsRightSidebarOpen] = useState(true);
@@ -666,16 +401,11 @@ const AgentChat = () => {
) )
: sessions; : sessions;
const quickQuestions = [ // quickQuestions 已移动到 constants/quickQuestions.ts
{ text: '今日涨停板块分析', emoji: '🔥' },
{ text: '新能源概念机会', emoji: '⚡' },
{ text: '半导体行业动态', emoji: '💾' },
{ text: '本周热门研报', emoji: '📊' },
];
return ( return (
<Box minH="100vh" bg="gray.900"> <Box flex={1} bg="gray.900">
<Flex h="calc(100vh - 72px)" overflow="hidden" position="relative"> <Flex h="100%" overflow="hidden" position="relative">
{/* 背景渐变层 - 移到 Flex 内部 */} {/* 背景渐变层 - 移到 Flex 内部 */}
<Box <Box
position="absolute" position="absolute"