import { useState, useRef, useEffect } from 'react';
import {
Box,
Paper,
Typography,
Button,
LinearProgress,
CircularProgress,
Alert,
Chip,
Collapse,
IconButton,
Tooltip,
Fade,
Avatar
} from '@mui/material';
import { useTheme, alpha } from '@mui/material/styles';
import ThumbUpIcon from '@mui/icons-material/ThumbUp';
import ThumbDownIcon from '@mui/icons-material/ThumbDown';
import ThumbsUpDownIcon from '@mui/icons-material/ThumbsUpDown';
import RefreshIcon from '@mui/icons-material/Refresh';
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import ExpandLessIcon from '@mui/icons-material/ExpandLess';
import PsychologyIcon from '@mui/icons-material/Psychology';
import AutoFixHighIcon from '@mui/icons-material/AutoFixHigh';
import InfoOutlinedIcon from '@mui/icons-material/InfoOutlined';
import AssignmentIcon from '@mui/icons-material/Assignment';
import SmartToyIcon from '@mui/icons-material/SmartToy';
import { useTranslation } from 'react-i18next';
import ReactMarkdown from 'react-markdown';
import 'github-markdown-css/github-markdown-light.css';
import { blindTestStyles } from '@/styles/blindTest';
function AnswerBox({ title, modelLabel, answer, streaming, showThinking, setShowThinking, scrollRef, styles, theme }) {
const { t } = useTranslation();
const isLeft = modelLabel === 'A';
const avatarColor = isLeft ? 'primary.main' : 'secondary.main';
return (
{modelLabel}
{title}
{streaming && }
{answer?.duration > 0 && !streaming && (
)}
{answer?.error ? (
{answer.error}
) : (
{/* 思维链渲染 */}
{answer?.thinking && (
setShowThinking(!showThinking)}
>
{answer.isThinking ? (
) : (
)}
{t('playground.reasoningProcess', '推理过程')}
{showThinking ? : }
{answer.thinking}
)}
{answer?.content ? (
{answer.content}
) : streaming ? (
{t('blindTest.generatingAnswers', '正在生成回答...')}
) : null}
)}
);
}
export default function BlindTestInProgress({
task,
currentQuestion,
leftAnswer,
rightAnswer,
streamingA,
streamingB,
answersLoading,
voting,
onVote,
onReload
}) {
const { t } = useTranslation();
const theme = useTheme();
const styles = blindTestStyles(theme);
const [showThinkingLeft, setShowThinkingLeft] = useState(true);
const [showThinkingRight, setShowThinkingRight] = useState(true);
// 自动滚动引用
const leftScrollRef = useRef(null);
const rightScrollRef = useRef(null);
// 处理自动滚动
useEffect(() => {
if (streamingA && leftScrollRef.current) {
leftScrollRef.current.scrollTop = leftScrollRef.current.scrollHeight;
}
}, [leftAnswer?.content, leftAnswer?.thinking, streamingA]);
useEffect(() => {
if (streamingB && rightScrollRef.current) {
rightScrollRef.current.scrollTop = rightScrollRef.current.scrollHeight;
}
}, [rightAnswer?.content, rightAnswer?.thinking, streamingB]);
const progress = task ? (task.completedCount / task.totalCount) * 100 : 0;
if (answersLoading && !currentQuestion) {
return (
{t('blindTest.generatingAnswers', '正在准备题目...')}
);
}
if (!currentQuestion) {
return (
}
onClick={onReload}
sx={{ borderRadius: 3, px: 4, py: 1.5, boxShadow: 4 }}
>
{t('blindTest.loadQuestion', '加载题目')}
);
}
return (
{/* 顶部进度和问题 */}
{t('blindTest.progress', '进度')} {task.completedCount + 1}/{task.totalCount}
{currentQuestion.question}
{/* 回答区域 */}
{/* 底部投票区域 */}
}
onClick={() => onVote('left')}
disabled={voting || streamingA || streamingB}
sx={{ ...styles.voteBtn, bgcolor: 'primary.main', '&:hover': { bgcolor: 'primary.dark' } }}
>
{t('blindTest.leftBetter', '左边更好')}
}
onClick={() => onVote('both_good')}
disabled={voting || streamingA || streamingB}
sx={{ ...styles.voteBtn, borderWidth: 2, '&:hover': { borderWidth: 2 } }}
>
{t('blindTest.bothGood', '都好')}
{t('blindTest.referenceAnswer', '参考答案')}
{currentQuestion.answer}
) : (
t('blindTest.noReferenceAnswer', '暂无参考答案')
)
}
arrow
placement="top"
TransitionComponent={Fade}
TransitionProps={{ timeout: 600 }}
componentsProps={{
tooltip: {
sx: {
bgcolor: theme.palette.mode === 'dark' ? 'grey.900' : 'background.paper',
color: 'text.primary',
boxShadow: theme.shadows[8],
border: `1px solid ${theme.palette.divider}`,
p: 0,
'& .MuiTooltip-arrow': {
color: theme.palette.mode === 'dark' ? 'grey.900' : 'background.paper',
'&::before': {
border: `1px solid ${theme.palette.divider}`
}
}
}
}
}}
>
}
sx={{
...styles.voteBtn,
color: 'text.secondary',
minWidth: 'auto',
px: 2
}}
>
{t('blindTest.referenceAnswer', '参考答案')}
}
onClick={() => onVote('both_bad')}
disabled={voting || streamingA || streamingB}
sx={{ ...styles.voteBtn, borderWidth: 2, '&:hover': { borderWidth: 2 } }}
>
{t('blindTest.bothBad', '都不好')}
}
onClick={() => onVote('right')}
disabled={voting || streamingA || streamingB}
sx={{ ...styles.voteBtn, bgcolor: 'secondary.main', '&:hover': { bgcolor: 'secondary.dark' } }}
>
{t('blindTest.rightBetter', '右边更好')}
);
}