From eb035d6d351083f5a3d95159ee7b07ba11be69df Mon Sep 17 00:00:00 2001 From: "mula.liu" Date: Tue, 9 Sep 2025 11:36:26 +0800 Subject: [PATCH] 1.0.3 --- src/pages/MeetingDetails.css | 141 ++++++++++++++++++++++++++++ src/pages/MeetingDetails.jsx | 173 ++++++++++++++++++++++++++++++++--- 2 files changed, 302 insertions(+), 12 deletions(-) diff --git a/src/pages/MeetingDetails.css b/src/pages/MeetingDetails.css index ef5f0a5..9d45e8a 100644 --- a/src/pages/MeetingDetails.css +++ b/src/pages/MeetingDetails.css @@ -1676,3 +1676,144 @@ font-style: italic; text-align: center; } + + +/* AI总结进度条样式 */ +.summary-progress-section { + margin: 20px 0; + padding: 20px; + background: #f8fafc; + border-radius: 12px; + border: 1px solid #e5e7eb; +} + +.progress-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 12px; +} + +.progress-title { + font-size: 14px; + font-weight: 500; + color: #374151; +} + +.progress-percentage { + font-size: 14px; + font-weight: 600; + color: #2563eb; +} + +.progress-bar-container { + height: 8px; + background: #e5e7eb; + border-radius: 4px; + overflow: hidden; + position: relative; +} + +.progress-bar-fill { + height: 100%; + background: linear-gradient(90deg, #3b82f6 0%, #2563eb 100%); + border-radius: 4px; + transition: width 0.3s ease; + position: relative; + overflow: hidden; +} + +.progress-bar-animate { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: linear-gradient( + 90deg, + rgba(255, 255, 255, 0) 0%, + rgba(255, 255, 255, 0.3) 50%, + rgba(255, 255, 255, 0) 100% + ); + animation: progress-shine 1.5s linear infinite; +} + +@keyframes progress-shine { + 0% { + transform: translateX(-100%); + } + 100% { + transform: translateX(100%); + } +} + +.progress-message { + display: flex; + align-items: center; + gap: 8px; + margin-top: 12px; + font-size: 13px; + color: #6b7280; +} + +.progress-message .status-indicator { + width: 8px; + height: 8px; + border-radius: 50%; + animation: pulse 1.5s ease-in-out infinite; +} + +.progress-message .status-indicator.processing { + background: #3b82f6; +} + +.success-message { + display: flex; + align-items: center; + gap: 8px; + margin: 20px 0; + padding: 12px 16px; + background: linear-gradient(135deg, #f0f9ff 0%, #e0f2fe 100%); + border-left: 4px solid #3b82f6; + border-radius: 8px; + font-size: 14px; + color: #1e40af; + animation: slideInFromTop 0.3s ease-out; +} + +.success-message svg { + color: #3b82f6; + animation: sparkle 0.5s ease-in-out; +} + +@keyframes slideInFromTop { + 0% { + opacity: 0; + transform: translateY(-10px); + } + 100% { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes sparkle { + 0%, 100% { + transform: scale(1) rotate(0deg); + } + 50% { + transform: scale(1.2) rotate(180deg); + } +} + +/* 更新生成按钮在加载时的样式 */ +.generate-summary-btn:disabled { + opacity: 0.7; + cursor: not-allowed; + background: #94a3b8; +} + +.generate-summary-btn:disabled:hover { + transform: none; + box-shadow: none; +} diff --git a/src/pages/MeetingDetails.jsx b/src/pages/MeetingDetails.jsx index fde6e1f..c65bf0f 100644 --- a/src/pages/MeetingDetails.jsx +++ b/src/pages/MeetingDetails.jsx @@ -42,6 +42,11 @@ const MeetingDetails = ({ user }) => { const [userPrompt, setUserPrompt] = useState(''); const [summaryHistory, setSummaryHistory] = useState([]); const [currentHighlightIndex, setCurrentHighlightIndex] = useState(-1); + const [summaryTaskId, setSummaryTaskId] = useState(null); + const [summaryTaskStatus, setSummaryTaskStatus] = useState(null); + const [summaryTaskProgress, setSummaryTaskProgress] = useState(0); + const [summaryTaskMessage, setSummaryTaskMessage] = useState(''); + const [summaryPollInterval, setSummaryPollInterval] = useState(null); const audioRef = useRef(null); const transcriptRefs = useRef([]); @@ -55,6 +60,11 @@ const MeetingDetails = ({ user }) => { clearInterval(statusCheckInterval); setStatusCheckInterval(null); } + if (summaryPollInterval) { + console.log('组件卸载,清理总结任务轮询定时器'); + clearInterval(summaryPollInterval); + setSummaryPollInterval(null); + } }; }, [meeting_id]); @@ -544,40 +554,147 @@ const MeetingDetails = ({ user }) => { } }; - // AI总结相关函数 + // AI总结相关函数 - 使用异步API const generateSummary = async () => { if (summaryLoading) return; setSummaryLoading(true); + setSummaryTaskProgress(0); + setSummaryTaskMessage('正在启动AI分析...'); + setSummaryTaskStatus('pending'); + try { const baseUrl = ""; - const response = await apiClient.post(`${baseUrl}/api/meetings/${meeting_id}/generate-summary`, { + // 使用异步API + const response = await apiClient.post(`${baseUrl}/api/meetings/${meeting_id}/generate-summary-async`, { user_prompt: userPrompt }); - setSummaryResult(response.data); + const taskId = response.data.task_id; + setSummaryTaskId(taskId); - // 刷新总结历史 - await fetchSummaryHistory(); + // 开始轮询任务状态 + const interval = setInterval(async () => { + try { + const statusResponse = await apiClient.get(`${baseUrl}/api/llm-tasks/${taskId}/status`); + const status = statusResponse.data; + + setSummaryTaskStatus(status.status); + setSummaryTaskProgress(status.progress || 0); + setSummaryTaskMessage(status.message || '处理中...'); + + if (status.status === 'completed') { + clearInterval(interval); + setSummaryPollInterval(null); + + // 设置结果 + setSummaryResult({ + content: status.result, + task_id: taskId + }); + + // 刷新总结历史(包含所有任务) + await fetchSummaryHistory(); + + // 刷新会议摘要 + await refreshMeetingSummary(); + + setSummaryLoading(false); + setSummaryTaskMessage('AI总结生成成功!'); + + // 3秒后清除成功消息 + setTimeout(() => { + setSummaryTaskMessage(''); + setSummaryTaskProgress(0); + }, 3000); + + } else if (status.status === 'failed') { + clearInterval(interval); + setSummaryPollInterval(null); + setSummaryLoading(false); + setError(status.error_message || '生成AI总结失败'); + setSummaryTaskMessage('生成失败:' + (status.error_message || '未知错误')); + } + } catch (err) { + console.error('Error polling task status:', err); + // 继续轮询,不中断 + } + }, 3000); // 每3秒查询一次 - // 只刷新会议摘要部分,避免整页刷新 - await refreshMeetingSummary(); + setSummaryPollInterval(interval); } catch (err) { - console.error('Error generating summary:', err); - setError('生成AI总结失败,请重试'); - } finally { + console.error('Error starting summary generation:', err); + setError('启动AI总结失败,请重试'); setSummaryLoading(false); + setSummaryTaskMessage(''); + setSummaryTaskProgress(0); } }; const fetchSummaryHistory = async () => { try { const baseUrl = ""; - const response = await apiClient.get(`${baseUrl}/api/meetings/${meeting_id}/summaries`); - setSummaryHistory(response.data.summaries); + // 获取所有LLM任务历史(包含进度和状态) + const tasksResponse = await apiClient.get(`${baseUrl}/api/meetings/${meeting_id}/llm-tasks`); + const tasks = tasksResponse.data.tasks || []; + + // 转换为历史记录格式,包含任务信息 + const summaries = tasks + .filter(task => task.status === 'completed' && task.result) + .map(task => ({ + id: task.task_id, + content: task.result, + user_prompt: task.user_prompt, + created_at: task.created_at, + task_info: { + task_id: task.task_id, + status: task.status, + progress: task.progress + } + })); + + setSummaryHistory(summaries); + + // 如果有进行中的任务,恢复轮询 + const runningTask = tasks.find(task => ['pending', 'processing'].includes(task.status)); + if (runningTask && !summaryPollInterval) { + setSummaryTaskId(runningTask.task_id); + setSummaryTaskStatus(runningTask.status); + setSummaryTaskProgress(runningTask.progress || 0); + setSummaryLoading(true); + + // 恢复轮询 + const interval = setInterval(async () => { + try { + const statusResponse = await apiClient.get(`${baseUrl}/api/llm-tasks/${runningTask.task_id}/status`); + const status = statusResponse.data; + + setSummaryTaskStatus(status.status); + setSummaryTaskProgress(status.progress || 0); + setSummaryTaskMessage(status.message || '处理中...'); + + if (['completed', 'failed'].includes(status.status)) { + clearInterval(interval); + setSummaryPollInterval(null); + setSummaryLoading(false); + + if (status.status === 'completed') { + await fetchSummaryHistory(); + await refreshMeetingSummary(); + } + } + } catch (err) { + console.error('Error polling task status:', err); + } + }, 3000); + + setSummaryPollInterval(interval); + } + } catch (err) { console.error('Error fetching summary history:', err); + setSummaryHistory([]); } }; @@ -1317,6 +1434,38 @@ ${renderedHTML} + {/* 任务进度显示 */} + {summaryLoading && ( +
+
+ 生成进度 + {summaryTaskProgress}% +
+
+
+
+
+
+ {summaryTaskMessage && ( +
+
+ {summaryTaskMessage} +
+ )} +
+ )} + + {/* 成功消息 */} + {!summaryLoading && summaryTaskMessage && summaryTaskStatus === 'completed' && ( +
+ + {summaryTaskMessage} +
+ )} + {summaryResult && (