update pay function
This commit is contained in:
@@ -2377,7 +2377,7 @@ MEETING_ROLES = {
|
|||||||
"name": "巴菲特",
|
"name": "巴菲特",
|
||||||
"nickname": "唱多者",
|
"nickname": "唱多者",
|
||||||
"role_type": "bull",
|
"role_type": "bull",
|
||||||
"avatar": "/avatars/buffett.png",
|
"avatar": "/images/agent/巴菲特.png",
|
||||||
"model": "kimi-k2-thinking",
|
"model": "kimi-k2-thinking",
|
||||||
"color": "#10B981",
|
"color": "#10B981",
|
||||||
"description": "主观多头,善于分析事件的潜在利好和长期价值",
|
"description": "主观多头,善于分析事件的潜在利好和长期价值",
|
||||||
@@ -2403,7 +2403,7 @@ MEETING_ROLES = {
|
|||||||
"name": "大空头",
|
"name": "大空头",
|
||||||
"nickname": "大空头",
|
"nickname": "大空头",
|
||||||
"role_type": "bear",
|
"role_type": "bear",
|
||||||
"avatar": "/avatars/big_short.png",
|
"avatar": "/images/agent/大空头.png",
|
||||||
"model": "kimi-k2-thinking",
|
"model": "kimi-k2-thinking",
|
||||||
"color": "#EF4444",
|
"color": "#EF4444",
|
||||||
"description": "善于分析事件和财报中的风险因素",
|
"description": "善于分析事件和财报中的风险因素",
|
||||||
@@ -2429,7 +2429,7 @@ MEETING_ROLES = {
|
|||||||
"name": "量化分析员",
|
"name": "量化分析员",
|
||||||
"nickname": "西蒙斯",
|
"nickname": "西蒙斯",
|
||||||
"role_type": "quant",
|
"role_type": "quant",
|
||||||
"avatar": "/avatars/simons.png",
|
"avatar": "/images/agent/simons.png",
|
||||||
"model": "deepseek",
|
"model": "deepseek",
|
||||||
"color": "#3B82F6",
|
"color": "#3B82F6",
|
||||||
"description": "中性立场,使用量化工具分析技术指标",
|
"description": "中性立场,使用量化工具分析技术指标",
|
||||||
@@ -2454,7 +2454,7 @@ MEETING_ROLES = {
|
|||||||
"name": "韭菜",
|
"name": "韭菜",
|
||||||
"nickname": "牢大",
|
"nickname": "牢大",
|
||||||
"role_type": "retail",
|
"role_type": "retail",
|
||||||
"avatar": "/avatars/leek.png",
|
"avatar": "/images/agent/牢大.png",
|
||||||
"model": "deepmoney",
|
"model": "deepmoney",
|
||||||
"color": "#F59E0B",
|
"color": "#F59E0B",
|
||||||
"description": "贪婪又讨厌亏损,热爱追涨杀跌",
|
"description": "贪婪又讨厌亏损,热爱追涨杀跌",
|
||||||
@@ -2474,7 +2474,7 @@ MEETING_ROLES = {
|
|||||||
"name": "基金经理",
|
"name": "基金经理",
|
||||||
"nickname": "决策者",
|
"nickname": "决策者",
|
||||||
"role_type": "manager",
|
"role_type": "manager",
|
||||||
"avatar": "/avatars/fund_manager.png",
|
"avatar": "/images/agent/基金经理.png",
|
||||||
"model": "deepseek",
|
"model": "deepseek",
|
||||||
"color": "#8B5CF6",
|
"color": "#8B5CF6",
|
||||||
"description": "综合分析做出最终决策",
|
"description": "综合分析做出最终决策",
|
||||||
@@ -2650,7 +2650,7 @@ async def stream_role_response(
|
|||||||
messages=messages,
|
messages=messages,
|
||||||
stream=True,
|
stream=True,
|
||||||
temperature=0.7,
|
temperature=0.7,
|
||||||
max_tokens=500,
|
max_tokens=2000, # 增加 token 限制以避免输出被截断
|
||||||
)
|
)
|
||||||
|
|
||||||
full_content = ""
|
full_content = ""
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 134 KiB |
@@ -84,6 +84,7 @@ const MessageRenderer = ({ message, userAvatar }) => {
|
|||||||
<Flex justify="flex-start">
|
<Flex justify="flex-start">
|
||||||
<HStack align="start" spacing={3} maxW="75%">
|
<HStack align="start" spacing={3} maxW="75%">
|
||||||
<Avatar
|
<Avatar
|
||||||
|
src="/images/agent/基金经理.png"
|
||||||
icon={<Cpu className="w-4 h-4" />}
|
icon={<Cpu className="w-4 h-4" />}
|
||||||
size="sm"
|
size="sm"
|
||||||
bgGradient="linear(to-br, purple.500, pink.500)"
|
bgGradient="linear(to-br, purple.500, pink.500)"
|
||||||
@@ -122,6 +123,7 @@ const MessageRenderer = ({ message, userAvatar }) => {
|
|||||||
<Flex justify="flex-start">
|
<Flex justify="flex-start">
|
||||||
<HStack align="start" spacing={3} maxW="75%">
|
<HStack align="start" spacing={3} maxW="75%">
|
||||||
<Avatar
|
<Avatar
|
||||||
|
src="/images/agent/基金经理.png"
|
||||||
icon={<Cpu className="w-4 h-4" />}
|
icon={<Cpu className="w-4 h-4" />}
|
||||||
size="sm"
|
size="sm"
|
||||||
bgGradient="linear(to-br, purple.500, pink.500)"
|
bgGradient="linear(to-br, purple.500, pink.500)"
|
||||||
|
|||||||
@@ -28,14 +28,63 @@ import {
|
|||||||
Copy,
|
Copy,
|
||||||
ThumbsUp,
|
ThumbsUp,
|
||||||
ChevronRight,
|
ChevronRight,
|
||||||
|
ChevronDown,
|
||||||
Database,
|
Database,
|
||||||
Check,
|
Check,
|
||||||
Wrench,
|
Wrench,
|
||||||
AlertCircle,
|
AlertCircle,
|
||||||
|
Brain,
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
import { getRoleConfig, MEETING_ROLES } from '../../constants/meetingRoles';
|
import { getRoleConfig, MEETING_ROLES } from '../../constants/meetingRoles';
|
||||||
import { MarkdownWithCharts } from '@components/ChatBot/MarkdownWithCharts';
|
import { MarkdownWithCharts } from '@components/ChatBot/MarkdownWithCharts';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析 deepmoney 格式的内容
|
||||||
|
* 格式: <think>思考过程</think><answer>回答内容</answer>
|
||||||
|
*
|
||||||
|
* @param {string} content - 原始内容
|
||||||
|
* @returns {{ thinking: string | null, answer: string }} 解析后的内容
|
||||||
|
*/
|
||||||
|
const parseDeepmoneyContent = (content) => {
|
||||||
|
if (!content) return { thinking: null, answer: '' };
|
||||||
|
|
||||||
|
// 匹配 <think>...</think> 标签
|
||||||
|
const thinkMatch = content.match(/<think>([\s\S]*?)<\/think>/i);
|
||||||
|
// 匹配 <answer>...</answer> 标签
|
||||||
|
const answerMatch = content.match(/<answer>([\s\S]*?)<\/answer>/i);
|
||||||
|
|
||||||
|
// 如果有 answer 标签,提取内容
|
||||||
|
if (answerMatch) {
|
||||||
|
return {
|
||||||
|
thinking: thinkMatch ? thinkMatch[1].trim() : null,
|
||||||
|
answer: answerMatch[1].trim(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果只有 think 标签但没有 answer 标签,可能正在流式输出中
|
||||||
|
if (thinkMatch && !answerMatch) {
|
||||||
|
// 检查 think 后面是否有其他内容
|
||||||
|
const afterThink = content.replace(/<think>[\s\S]*?<\/think>/i, '').trim();
|
||||||
|
// 如果 think 后面有内容但不是 answer 标签包裹的,可能是部分输出
|
||||||
|
if (afterThink && !afterThink.startsWith('<answer>')) {
|
||||||
|
return {
|
||||||
|
thinking: thinkMatch[1].trim(),
|
||||||
|
answer: afterThink.replace(/<\/?answer>/gi, '').trim(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
thinking: thinkMatch[1].trim(),
|
||||||
|
answer: '',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果没有特殊标签,返回原内容
|
||||||
|
return {
|
||||||
|
thinking: null,
|
||||||
|
answer: content,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取角色图标
|
* 获取角色图标
|
||||||
*/
|
*/
|
||||||
@@ -281,6 +330,67 @@ const ToolCallsList = ({ toolCalls, roleColor }) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 思考过程展示组件
|
||||||
|
* 用于显示 deepmoney 等模型的思考过程,默认折叠
|
||||||
|
*/
|
||||||
|
const ThinkingBlock = ({ thinking, roleColor }) => {
|
||||||
|
const [isExpanded, setIsExpanded] = useState(false);
|
||||||
|
|
||||||
|
if (!thinking) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box mb={3}>
|
||||||
|
<HStack
|
||||||
|
spacing={2}
|
||||||
|
cursor="pointer"
|
||||||
|
onClick={() => setIsExpanded(!isExpanded)}
|
||||||
|
p={2}
|
||||||
|
bg="rgba(255, 255, 255, 0.03)"
|
||||||
|
borderRadius="md"
|
||||||
|
border="1px solid"
|
||||||
|
borderColor="rgba(255, 255, 255, 0.1)"
|
||||||
|
_hover={{ borderColor: `${roleColor}30` }}
|
||||||
|
transition="all 0.2s"
|
||||||
|
>
|
||||||
|
<Brain className="w-3 h-3" style={{ color: roleColor }} />
|
||||||
|
<Text fontSize="xs" color="gray.400" flex={1}>
|
||||||
|
AI 思考过程
|
||||||
|
</Text>
|
||||||
|
<Box
|
||||||
|
color="gray.500"
|
||||||
|
transition="transform 0.2s"
|
||||||
|
transform={isExpanded ? 'rotate(180deg)' : 'rotate(0deg)'}
|
||||||
|
>
|
||||||
|
<ChevronDown className="w-3 h-3" />
|
||||||
|
</Box>
|
||||||
|
</HStack>
|
||||||
|
|
||||||
|
<Collapse in={isExpanded} animateOpacity>
|
||||||
|
<Box
|
||||||
|
mt={2}
|
||||||
|
p={3}
|
||||||
|
bg="rgba(0, 0, 0, 0.2)"
|
||||||
|
borderRadius="md"
|
||||||
|
borderLeft="2px solid"
|
||||||
|
borderColor={`${roleColor}50`}
|
||||||
|
maxH="200px"
|
||||||
|
overflowY="auto"
|
||||||
|
sx={{
|
||||||
|
'&::-webkit-scrollbar': { width: '4px' },
|
||||||
|
'&::-webkit-scrollbar-track': { bg: 'transparent' },
|
||||||
|
'&::-webkit-scrollbar-thumb': { bg: 'gray.600', borderRadius: 'full' },
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Text fontSize="xs" color="gray.400" whiteSpace="pre-wrap" lineHeight="tall">
|
||||||
|
{thinking}
|
||||||
|
</Text>
|
||||||
|
</Box>
|
||||||
|
</Collapse>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MeetingMessageBubble - 会议消息气泡组件
|
* MeetingMessageBubble - 会议消息气泡组件
|
||||||
*
|
*
|
||||||
@@ -326,6 +436,7 @@ const MeetingMessageBubble = ({ message, isLatest }) => {
|
|||||||
>
|
>
|
||||||
<Avatar
|
<Avatar
|
||||||
size="sm"
|
size="sm"
|
||||||
|
src={roleConfig.avatar}
|
||||||
icon={getRoleIcon(roleConfig.roleType)}
|
icon={getRoleIcon(roleConfig.roleType)}
|
||||||
bg={roleConfig.color}
|
bg={roleConfig.color}
|
||||||
boxShadow={`0 0 12px ${roleConfig.color}40`}
|
boxShadow={`0 0 12px ${roleConfig.color}40`}
|
||||||
@@ -444,6 +555,17 @@ const MeetingMessageBubble = ({ message, isLatest }) => {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{/* 解析 deepmoney 格式的内容 */}
|
||||||
|
{(() => {
|
||||||
|
const parsedContent = parseDeepmoneyContent(message.content);
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{/* 思考过程(可折叠) */}
|
||||||
|
<ThinkingBlock
|
||||||
|
thinking={parsedContent.thinking}
|
||||||
|
roleColor={roleConfig.color}
|
||||||
|
/>
|
||||||
|
|
||||||
{/* 消息内容 */}
|
{/* 消息内容 */}
|
||||||
<Box
|
<Box
|
||||||
fontSize="sm"
|
fontSize="sm"
|
||||||
@@ -469,8 +591,8 @@ const MeetingMessageBubble = ({ message, isLatest }) => {
|
|||||||
'& strong': { color: roleConfig.color },
|
'& strong': { color: roleConfig.color },
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{message.content ? (
|
{parsedContent.answer ? (
|
||||||
<MarkdownWithCharts content={message.content} variant="dark" />
|
<MarkdownWithCharts content={parsedContent.answer} variant="dark" />
|
||||||
) : isStreaming ? (
|
) : isStreaming ? (
|
||||||
<HStack spacing={2} color="gray.500">
|
<HStack spacing={2} color="gray.500">
|
||||||
<Spinner size="sm" />
|
<Spinner size="sm" />
|
||||||
@@ -479,7 +601,7 @@ const MeetingMessageBubble = ({ message, isLatest }) => {
|
|||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
{/* 流式输出时的光标 */}
|
{/* 流式输出时的光标 */}
|
||||||
{isStreaming && message.content && (
|
{isStreaming && parsedContent.answer && (
|
||||||
<motion.span
|
<motion.span
|
||||||
animate={{ opacity: [1, 0, 1] }}
|
animate={{ opacity: [1, 0, 1] }}
|
||||||
transition={{ duration: 0.8, repeat: Infinity }}
|
transition={{ duration: 0.8, repeat: Infinity }}
|
||||||
@@ -489,6 +611,9 @@ const MeetingMessageBubble = ({ message, isLatest }) => {
|
|||||||
</motion.span>
|
</motion.span>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
})()}
|
||||||
|
|
||||||
{/* 操作按钮 */}
|
{/* 操作按钮 */}
|
||||||
<Flex mt={3} pt={3} borderTop="1px solid" borderColor="whiteAlpha.100">
|
<Flex mt={3} pt={3} borderTop="1px solid" borderColor="whiteAlpha.100">
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ export const MEETING_ROLES: Record<string, MeetingRoleConfig> = {
|
|||||||
name: '巴菲特',
|
name: '巴菲特',
|
||||||
nickname: '唱多者',
|
nickname: '唱多者',
|
||||||
roleType: 'bull',
|
roleType: 'bull',
|
||||||
avatar: '/avatars/buffett.png',
|
avatar: '/images/agent/巴菲特.png',
|
||||||
color: '#10B981',
|
color: '#10B981',
|
||||||
gradient: 'linear(to-br, green.400, emerald.600)',
|
gradient: 'linear(to-br, green.400, emerald.600)',
|
||||||
description: '主观多头,善于分析事件的潜在利好和长期价值',
|
description: '主观多头,善于分析事件的潜在利好和长期价值',
|
||||||
@@ -133,7 +133,7 @@ export const MEETING_ROLES: Record<string, MeetingRoleConfig> = {
|
|||||||
name: '大空头',
|
name: '大空头',
|
||||||
nickname: '大空头',
|
nickname: '大空头',
|
||||||
roleType: 'bear',
|
roleType: 'bear',
|
||||||
avatar: '/avatars/big_short.png',
|
avatar: '/images/agent/大空头.png',
|
||||||
color: '#EF4444',
|
color: '#EF4444',
|
||||||
gradient: 'linear(to-br, red.400, rose.600)',
|
gradient: 'linear(to-br, red.400, rose.600)',
|
||||||
description: '善于分析事件和财报中的风险因素,帮助投资者避雷',
|
description: '善于分析事件和财报中的风险因素,帮助投资者避雷',
|
||||||
@@ -144,7 +144,7 @@ export const MEETING_ROLES: Record<string, MeetingRoleConfig> = {
|
|||||||
name: '量化分析员',
|
name: '量化分析员',
|
||||||
nickname: '西蒙斯',
|
nickname: '西蒙斯',
|
||||||
roleType: 'quant',
|
roleType: 'quant',
|
||||||
avatar: '/avatars/simons.png',
|
avatar: '/images/agent/simons.png',
|
||||||
color: '#3B82F6',
|
color: '#3B82F6',
|
||||||
gradient: 'linear(to-br, blue.400, cyan.600)',
|
gradient: 'linear(to-br, blue.400, cyan.600)',
|
||||||
description: '中性立场,使用量化分析工具分析技术指标',
|
description: '中性立场,使用量化分析工具分析技术指标',
|
||||||
@@ -155,7 +155,7 @@ export const MEETING_ROLES: Record<string, MeetingRoleConfig> = {
|
|||||||
name: '韭菜',
|
name: '韭菜',
|
||||||
nickname: '牢大',
|
nickname: '牢大',
|
||||||
roleType: 'retail',
|
roleType: 'retail',
|
||||||
avatar: '/avatars/leek.png',
|
avatar: '/images/agent/牢大.png',
|
||||||
color: '#F59E0B',
|
color: '#F59E0B',
|
||||||
gradient: 'linear(to-br, amber.400, yellow.600)',
|
gradient: 'linear(to-br, amber.400, yellow.600)',
|
||||||
description: '贪婪又讨厌亏损,热爱追涨杀跌的典型散户',
|
description: '贪婪又讨厌亏损,热爱追涨杀跌的典型散户',
|
||||||
@@ -166,7 +166,7 @@ export const MEETING_ROLES: Record<string, MeetingRoleConfig> = {
|
|||||||
name: '基金经理',
|
name: '基金经理',
|
||||||
nickname: '决策者',
|
nickname: '决策者',
|
||||||
roleType: 'manager',
|
roleType: 'manager',
|
||||||
avatar: '/avatars/fund_manager.png',
|
avatar: '/images/agent/基金经理.png',
|
||||||
color: '#8B5CF6',
|
color: '#8B5CF6',
|
||||||
gradient: 'linear(to-br, purple.400, violet.600)',
|
gradient: 'linear(to-br, purple.400, violet.600)',
|
||||||
description: '总结其他人的发言做出最终决策',
|
description: '总结其他人的发言做出最终决策',
|
||||||
|
|||||||
@@ -220,15 +220,9 @@ export const TOOL_CATEGORIES: Record<ToolCategory, MCPTool[]> = {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 默认选中的工具 ID 列表
|
* 默认选中的工具 ID 列表
|
||||||
* 这些工具在页面初始化时自动选中
|
* 所有工具在页面初始化时自动选中
|
||||||
*/
|
*/
|
||||||
export const DEFAULT_SELECTED_TOOLS: string[] = [
|
export const DEFAULT_SELECTED_TOOLS: string[] = MCP_TOOLS.map((tool) => tool.id);
|
||||||
'search_news',
|
|
||||||
'search_china_news',
|
|
||||||
'search_concepts',
|
|
||||||
'search_limit_up_stocks',
|
|
||||||
'search_research_reports',
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据 ID 查找工具配置
|
* 根据 ID 查找工具配置
|
||||||
|
|||||||
@@ -357,11 +357,20 @@ export const useInvestmentMeeting = ({
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'message_complete':
|
case 'message_complete':
|
||||||
if (data.role_id) {
|
{
|
||||||
|
// 后端发送的是 message 对象,role_id 在 message 里
|
||||||
|
const roleId = data.role_id || data.message?.role_id;
|
||||||
|
if (roleId) {
|
||||||
// 后端可能发送 message 对象或直接 content
|
// 后端可能发送 message 对象或直接 content
|
||||||
const finalContent = data.message?.content || data.content;
|
const finalContent = data.message?.content || data.content;
|
||||||
finishStreamingMessage(data.role_id, finalContent);
|
finishStreamingMessage(roleId, finalContent);
|
||||||
setSpeakingRoleId(null);
|
setSpeakingRoleId(null);
|
||||||
|
|
||||||
|
// 如果是结论消息,记录下来
|
||||||
|
if (data.message?.is_conclusion) {
|
||||||
|
setConclusion(data.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -562,11 +571,20 @@ export const useInvestmentMeeting = ({
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'message_complete':
|
case 'message_complete':
|
||||||
if (data.role_id) {
|
{
|
||||||
|
// 后端发送的是 message 对象,role_id 在 message 里
|
||||||
|
const roleId = data.role_id || data.message?.role_id;
|
||||||
|
if (roleId) {
|
||||||
// 后端可能发送 message 对象或直接 content
|
// 后端可能发送 message 对象或直接 content
|
||||||
const finalContent = data.message?.content || data.content;
|
const finalContent = data.message?.content || data.content;
|
||||||
finishStreamingMessage(data.role_id, finalContent);
|
finishStreamingMessage(roleId, finalContent);
|
||||||
setSpeakingRoleId(null);
|
setSpeakingRoleId(null);
|
||||||
|
|
||||||
|
// 如果是结论消息,记录下来
|
||||||
|
if (data.message?.is_conclusion) {
|
||||||
|
setConclusion(data.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user