| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| import React, { useEffect, useRef } from 'react'; |
| import { Typography } from '@douyinfe/semi-ui'; |
| import MarkdownRenderer from '../common/markdown/MarkdownRenderer'; |
| import { ChevronRight, ChevronUp, Brain, Loader2 } from 'lucide-react'; |
| import { useTranslation } from 'react-i18next'; |
|
|
| const ThinkingContent = ({ |
| message, |
| finalExtractedThinkingContent, |
| thinkingSource, |
| styleState, |
| onToggleReasoningExpansion, |
| }) => { |
| const { t } = useTranslation(); |
| const scrollRef = useRef(null); |
| const lastContentRef = useRef(''); |
|
|
| const isThinkingStatus = |
| message.status === 'loading' || message.status === 'incomplete'; |
| const headerText = |
| isThinkingStatus && !message.isThinkingComplete |
| ? t('思考中...') |
| : t('思考过程'); |
|
|
| useEffect(() => { |
| if ( |
| scrollRef.current && |
| finalExtractedThinkingContent && |
| message.isReasoningExpanded |
| ) { |
| scrollRef.current.scrollTop = scrollRef.current.scrollHeight; |
| } |
| }, [finalExtractedThinkingContent, message.isReasoningExpanded]); |
|
|
| useEffect(() => { |
| if (!isThinkingStatus) { |
| lastContentRef.current = ''; |
| } |
| }, [isThinkingStatus]); |
|
|
| if (!finalExtractedThinkingContent) return null; |
|
|
| let prevLength = 0; |
| if (isThinkingStatus && lastContentRef.current) { |
| if (finalExtractedThinkingContent.startsWith(lastContentRef.current)) { |
| prevLength = lastContentRef.current.length; |
| } |
| } |
|
|
| if (isThinkingStatus) { |
| lastContentRef.current = finalExtractedThinkingContent; |
| } |
|
|
| return ( |
| <div className='rounded-xl sm:rounded-2xl mb-2 sm:mb-4 overflow-hidden shadow-sm backdrop-blur-sm'> |
| <div |
| className='flex items-center justify-between p-3 cursor-pointer hover:bg-gradient-to-r hover:from-white/20 hover:to-purple-50/30 transition-all' |
| style={{ |
| background: |
| 'linear-gradient(135deg, #4c1d95 0%, #6d28d9 50%, #7c3aed 100%)', |
| position: 'relative', |
| }} |
| onClick={() => onToggleReasoningExpansion(message.id)} |
| > |
| <div className='absolute inset-0 overflow-hidden'> |
| <div className='absolute -top-10 -right-10 w-40 h-40 bg-white opacity-5 rounded-full'></div> |
| <div className='absolute -bottom-8 -left-8 w-24 h-24 bg-white opacity-10 rounded-full'></div> |
| </div> |
| <div className='flex items-center gap-2 sm:gap-4 relative'> |
| <div className='w-6 h-6 sm:w-8 sm:h-8 rounded-full bg-white/20 flex items-center justify-center shadow-lg'> |
| <Brain |
| style={{ color: 'white' }} |
| size={styleState.isMobile ? 12 : 16} |
| /> |
| </div> |
| <div className='flex flex-col'> |
| <Typography.Text |
| strong |
| style={{ color: 'white' }} |
| className='text-sm sm:text-base' |
| > |
| {headerText} |
| </Typography.Text> |
| {thinkingSource && ( |
| <Typography.Text |
| style={{ color: 'white' }} |
| className='text-xs mt-0.5 opacity-80 hidden sm:block' |
| > |
| 来源: {thinkingSource} |
| </Typography.Text> |
| )} |
| </div> |
| </div> |
| <div className='flex items-center gap-2 sm:gap-3 relative'> |
| {isThinkingStatus && !message.isThinkingComplete && ( |
| <div className='flex items-center gap-1 sm:gap-2'> |
| <Loader2 |
| style={{ color: 'white' }} |
| className='animate-spin' |
| size={styleState.isMobile ? 14 : 18} |
| /> |
| <Typography.Text |
| style={{ color: 'white' }} |
| className='text-xs sm:text-sm font-medium opacity-90' |
| > |
| 思考中 |
| </Typography.Text> |
| </div> |
| )} |
| {(!isThinkingStatus || message.isThinkingComplete) && ( |
| <div className='w-5 h-5 sm:w-6 sm:h-6 rounded-full bg-white/20 flex items-center justify-center'> |
| {message.isReasoningExpanded ? ( |
| <ChevronUp |
| size={styleState.isMobile ? 12 : 16} |
| style={{ color: 'white' }} |
| /> |
| ) : ( |
| <ChevronRight |
| size={styleState.isMobile ? 12 : 16} |
| style={{ color: 'white' }} |
| /> |
| )} |
| </div> |
| )} |
| </div> |
| </div> |
| <div |
| className={`transition-all duration-500 ease-out ${ |
| message.isReasoningExpanded |
| ? 'max-h-96 opacity-100' |
| : 'max-h-0 opacity-0' |
| } overflow-hidden bg-gradient-to-br from-purple-50 via-indigo-50 to-violet-50`} |
| > |
| {message.isReasoningExpanded && ( |
| <div className='p-3 sm:p-5 pt-2 sm:pt-4'> |
| <div |
| ref={scrollRef} |
| className='bg-white/70 backdrop-blur-sm rounded-lg sm:rounded-xl p-2 shadow-inner overflow-x-auto overflow-y-auto thinking-content-scroll' |
| style={{ |
| maxHeight: '200px', |
| scrollbarWidth: 'thin', |
| scrollbarColor: 'rgba(0, 0, 0, 0.3) transparent', |
| }} |
| > |
| <div className='prose prose-xs sm:prose-sm prose-purple max-w-none text-xs sm:text-sm'> |
| <MarkdownRenderer |
| content={finalExtractedThinkingContent} |
| className='' |
| animated={isThinkingStatus} |
| previousContentLength={prevLength} |
| /> |
| </div> |
| </div> |
| </div> |
| )} |
| </div> |
| </div> |
| ); |
| }; |
|
|
| export default ThinkingContent; |
|
|