update pay function

This commit is contained in:
2025-11-28 16:32:27 +08:00
parent 250d585b87
commit ec2978026a
7 changed files with 212 additions and 73 deletions

View File

@@ -28,14 +28,63 @@ import {
Copy,
ThumbsUp,
ChevronRight,
ChevronDown,
Database,
Check,
Wrench,
AlertCircle,
Brain,
} from 'lucide-react';
import { getRoleConfig, MEETING_ROLES } from '../../constants/meetingRoles';
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 - 会议消息气泡组件
*
@@ -326,6 +436,7 @@ const MeetingMessageBubble = ({ message, isLatest }) => {
>
<Avatar
size="sm"
src={roleConfig.avatar}
icon={getRoleIcon(roleConfig.roleType)}
bg={roleConfig.color}
boxShadow={`0 0 12px ${roleConfig.color}40`}
@@ -444,51 +555,65 @@ const MeetingMessageBubble = ({ message, isLatest }) => {
/>
)}
{/* 消息内容 */}
<Box
fontSize="sm"
color="gray.100"
lineHeight="tall"
sx={{
'& p': { mb: 2 },
'& h1, & h2, & h3': { color: 'gray.50', fontWeight: 'bold' },
'& ul, & ol': { pl: 4 },
'& li': { mb: 1 },
'& code': {
bg: 'rgba(255,255,255,0.1)',
px: 1,
borderRadius: 'sm',
},
'& blockquote': {
borderLeftWidth: '3px',
borderLeftColor: roleConfig.color,
pl: 3,
color: 'gray.300',
fontStyle: 'italic',
},
'& strong': { color: roleConfig.color },
}}
>
{message.content ? (
<MarkdownWithCharts content={message.content} variant="dark" />
) : isStreaming ? (
<HStack spacing={2} color="gray.500">
<Spinner size="sm" />
<Text>正在思考...</Text>
</HStack>
) : null}
{/* 解析 deepmoney 格式的内容 */}
{(() => {
const parsedContent = parseDeepmoneyContent(message.content);
return (
<>
{/* 思考过程(可折叠) */}
<ThinkingBlock
thinking={parsedContent.thinking}
roleColor={roleConfig.color}
/>
{/* 流式输出时的光标 */}
{isStreaming && message.content && (
<motion.span
animate={{ opacity: [1, 0, 1] }}
transition={{ duration: 0.8, repeat: Infinity }}
style={{ color: roleConfig.color }}
>
</motion.span>
)}
</Box>
{/* 消息内容 */}
<Box
fontSize="sm"
color="gray.100"
lineHeight="tall"
sx={{
'& p': { mb: 2 },
'& h1, & h2, & h3': { color: 'gray.50', fontWeight: 'bold' },
'& ul, & ol': { pl: 4 },
'& li': { mb: 1 },
'& code': {
bg: 'rgba(255,255,255,0.1)',
px: 1,
borderRadius: 'sm',
},
'& blockquote': {
borderLeftWidth: '3px',
borderLeftColor: roleConfig.color,
pl: 3,
color: 'gray.300',
fontStyle: 'italic',
},
'& strong': { color: roleConfig.color },
}}
>
{parsedContent.answer ? (
<MarkdownWithCharts content={parsedContent.answer} variant="dark" />
) : isStreaming ? (
<HStack spacing={2} color="gray.500">
<Spinner size="sm" />
<Text>正在思考...</Text>
</HStack>
) : null}
{/* 流式输出时的光标 */}
{isStreaming && parsedContent.answer && (
<motion.span
animate={{ opacity: [1, 0, 1] }}
transition={{ duration: 0.8, repeat: Infinity }}
style={{ color: roleConfig.color }}
>
</motion.span>
)}
</Box>
</>
);
})()}
{/* 操作按钮 */}
<Flex mt={3} pt={3} borderTop="1px solid" borderColor="whiteAlpha.100">