From 82ad5f6a81a2d273f854cc9b9b7d741849a7d2d2 Mon Sep 17 00:00:00 2001 From: HuangHai <10402852@qq.com> Date: Thu, 28 Aug 2025 08:20:31 +0800 Subject: [PATCH] 'commit' --- dsLightRag/static/YunXiao/physics_quiz.html | 943 ++++---------------- dsLightRag/static/YunXiao/physics_quiz.js | 505 +++++++++++ 2 files changed, 661 insertions(+), 787 deletions(-) create mode 100644 dsLightRag/static/YunXiao/physics_quiz.js diff --git a/dsLightRag/static/YunXiao/physics_quiz.html b/dsLightRag/static/YunXiao/physics_quiz.html index 62f8525a..7bde6225 100644 --- a/dsLightRag/static/YunXiao/physics_quiz.html +++ b/dsLightRag/static/YunXiao/physics_quiz.html @@ -13,32 +13,37 @@ } body { - background-color: #f5f7fa; + background-color: #f0f2f5; color: #333; line-height: 1.6; - padding: 20px; } .container { - max-width: 1000px; + max-width: 1200px; margin: 0 auto; - background-color: white; - border-radius: 12px; - box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08); - padding: 30px; + padding: 20px; } header { text-align: center; margin-bottom: 30px; - padding-bottom: 20px; - border-bottom: 1px solid #eee; + padding: 20px 0; + background-color: #1a5276; + color: white; + border-radius: 10px; + box-shadow: 0 4px 12px rgba(0,0,0,0.1); } h1 { - color: #2c3e50; + font-size: 2.2rem; margin-bottom: 10px; - font-size: 28px; + font-weight: 700; + } + + .quiz-info { + font-size: 1.1rem; + margin-bottom: 20px; + color: #ecf0f1; } .difficulty-indicator { @@ -64,30 +69,24 @@ color: #c62828; } - .quiz-info { - color: #666; - font-size: 16px; - margin-bottom: 20px; - } - .question-section { + background-color: white; + border-radius: 12px; + padding: 30px; + box-shadow: 0 4px 20px rgba(0,0,0,0.08); margin-bottom: 30px; } .question { - background-color: #f9f9f9; - border-radius: 8px; - padding: 20px; - margin-bottom: 20px; - transition: all 0.3s ease; + margin-bottom: 30px; + padding-bottom: 20px; + border-bottom: 1px solid #eee; } - .question.hidden { - display: none; - } - - .question:hover { - box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05); + .question:last-child { + border-bottom: none; + margin-bottom: 0; + padding-bottom: 0; } .question-header { @@ -99,29 +98,28 @@ .question-number { font-weight: bold; - color: #2980b9; - font-size: 18px; + font-size: 1.1rem; + color: #1a5276; } .question-points { - background-color: #e3f2fd; - color: #2980b9; - padding: 3px 10px; + background-color: #3498db; + color: white; + padding: 4px 10px; border-radius: 12px; - font-size: 14px; + font-size: 0.9rem; } .question-text { - margin-bottom: 15px; - font-size: 16px; + margin-bottom: 20px; + font-size: 1.1rem; line-height: 1.7; } .options { display: grid; grid-template-columns: 1fr 1fr; - gap: 12px; - margin-bottom: 15px; + gap: 15px; } @media (max-width: 768px) { @@ -131,39 +129,104 @@ } .option { - background-color: white; + background-color: #f8f9fa; border: 1px solid #ddd; - border-radius: 6px; - padding: 12px 15px; + border-radius: 8px; + padding: 15px; cursor: pointer; - transition: all 0.2s ease; - display: flex; - align-items: center; + transition: all 0.3s ease; } .option:hover { - border-color: #2980b9; - background-color: #f0f7ff; + background-color: #e3f2fd; + border-color: #90caf9; } .option input { margin-right: 10px; } - .option label { - cursor: pointer; - flex: 1; + .btn-section { + text-align: center; + margin-top: 40px; } - .question-explanation { + .submit-btn { + background-color: #27ae60; + color: white; + border: none; + padding: 12px 30px; + border-radius: 8px; + font-size: 1rem; + cursor: pointer; + transition: background-color 0.3s ease; + } + + .submit-btn:hover { + background-color: #219653; + } + + .result-section { + background-color: white; + border-radius: 12px; + padding: 30px; + box-shadow: 0 4px 20px rgba(0,0,0,0.08); + margin-top: 30px; + display: none; + } + + .result-header { + text-align: center; + margin-bottom: 20px; + color: #1a5276; + } + + .result-stats { + display: flex; + justify-content: space-around; + margin-bottom: 30px; + flex-wrap: wrap; + } + + .stat-item { + text-align: center; + padding: 15px; + } + + .stat-value { + font-size: 2rem; + font-weight: bold; + color: #2c3e50; + } + + .stat-label { + color: #7f8c8d; + font-size: 0.9rem; + } + + .explanation { margin-top: 15px; padding: 15px; - background-color: #e8f5e9; - border-left: 4px solid #4caf50; + background-color: #f8f9fa; + border-left: 4px solid #3498db; border-radius: 4px; display: none; } + .explanation.show { + display: block; + } + + .correct { + background-color: #e8f5e9; + border-color: #81c784; + } + + .incorrect { + background-color: #ffebee; + border-color: #e57373; + } + .navigation-section { text-align: center; margin: 20px 0; @@ -173,62 +236,29 @@ display: none; } - .submit-section { - text-align: center; - margin-top: 40px; - } - - #submit-btn { - background-color: #2980b9; + .next-btn { + background-color: #3498db; color: white; border: none; - padding: 12px 30px; - border-radius: 6px; - cursor: pointer; - font-size: 16px; - transition: all 0.2s ease; - } - - #submit-btn:hover { - background-color: #1e6fa5; - transform: translateY(-2px); - } - - #result { - margin-top: 30px; - padding: 20px; + padding: 10px 25px; border-radius: 8px; - display: none; + font-size: 0.9rem; + cursor: pointer; + transition: background-color 0.3s ease; + margin-top: 15px; } - .result-header { - font-size: 22px; - font-weight: bold; - margin-bottom: 15px; - color: #2c3e50; + .next-btn:hover { + background-color: #2980b9; } - - .score { - font-size: 18px; - margin-bottom: 20px; - color: #333; - } - - .correct-answers { - background-color: #e8f5e9; - color: #2e7d32; - padding: 10px 15px; - border-radius: 6px; - margin-bottom: 10px; - } - - .incorrect-answers { - background-color: #ffebee; - color: #c62828; - padding: 10px 15px; - border-radius: 6px; - } - + /* 在现有样式中添加 */ + .ask-xueban-btn.hidden { + display: none; + } + .explanation.show + .ask-xueban-btn { + margin-top: 15px; + } +
@@ -240,702 +270,41 @@
-
- -
-
-
中等难度 - 问题 1
-
20分
-
-
- 下列关于万有引力定律的说法中,正确的是: -
-
-
- - -
-
- - -
-
- - -
-
- - -
-
-
- 正确答案:B
- 解析:万有引力定律适用于宇宙中任何两个有质量的物体之间的相互作用,不仅限于天体,故A错误;根据万有引力公式F=G(m₁m₂)/r²,两个物体之间的万有引力大小与它们距离的平方成反比,故B正确;万有引力的方向总是沿着两个物体的连线方向,故C错误;万有引力常量G是卡文迪许通过扭秤实验测量得出的,故D错误。 -
-
+
+ +
-
-
-
中等难度 - 问题 2
-
20分
-
-
- 地球表面的重力加速度为g,若地球的质量不变,但半径变为原来的一半,则地球表面的重力加速度变为: -
-
-
- - -
-
- - -
-
- - -
-
- - -
-
-
- 正确答案:D
- 解析:根据重力加速度公式g=GM/R²,其中G为万有引力常量,M为地球质量,R为地球半径。当地球质量M不变,半径R变为原来的一半时,新的重力加速度g'=GM/(R/2)²=4GM/R²=4g,故答案为D。 -
-
+
+ +
-
-
-
中等难度 - 问题 3
-
20分
-
-
- 人造地球卫星绕地球做匀速圆周运动,若轨道半径增大到原来的2倍,则卫星的线速度大小变为原来的: -
-
-
- - -
-
- - -
-
- - -
-
- - -
-
-
- 正确答案:B
- 解析:根据万有引力提供向心力的公式GMm/r²=mv²/r,可得卫星线速度v=√(GM/r)。当轨道半径r增大到原来的2倍时,新的线速度v'=√(GM/(2r))=v/√2,故答案为B。 -
+
+
+

测验结果

- -
-
-
中等难度 - 问题 4
-
20分
+
+
+
0
+
总分
-
- 两个质量分别为m和M的物体相距为r,它们之间的万有引力大小为F。若将它们的距离变为2r,质量分别变为2m和3M,则它们之间的万有引力大小变为: +
+
0
+
正确题数
-
-
- - -
-
- - -
-
- - -
-
- - -
-
-
- 正确答案:A
- 解析:根据万有引力公式F=G(mM)/r²,变化后的万有引力F'=G(2m·3M)/(2r)²=6GMm/4r²=3GMm/2r²=3F/2,故答案为A。 -
-
- -
-
-
中等难度 - 问题 5
-
20分
-
-
- 关于开普勒行星运动定律,下列说法正确的是: -
-
-
- - -
-
- - -
-
- - -
-
- - -
-
-
- 正确答案:C
- 解析:开普勒第一定律指出所有行星绕太阳运动的轨道都是椭圆,太阳处在椭圆的一个焦点上,故A错误;根据开普勒第二定律,行星与太阳的连线在相等时间内扫过相等的面积,因此行星在近日点的速率大于在远日点的速率,故B错误;开普勒第三定律表明所有行星的轨道半长轴的三次方与公转周期的二次方的比值都相等,故C正确;开普勒定律不仅适用于行星绕太阳的运动,也适用于卫星绕行星的运动,只是比值不同,故D错误。 -
-
- - - - - - - - - - - - - - - - - - - - - - - - -
- -
-
测验结果
-
您的得分:0/100分
-
正确题数:0
-
错误题数:0
-
+
- + + \ No newline at end of file diff --git a/dsLightRag/static/YunXiao/physics_quiz.js b/dsLightRag/static/YunXiao/physics_quiz.js new file mode 100644 index 00000000..eb753e5d --- /dev/null +++ b/dsLightRag/static/YunXiao/physics_quiz.js @@ -0,0 +1,505 @@ +// 题目数据数组 +const questions = [ + // 简单难度题目 (5道) + { + difficulty: 'easy', + text: '下列哪个物理量是矢量?', + options: ['A. 质量', 'B. 时间', 'C. 位移', 'D. 路程'], + answer: 'C', + explanation: '矢量具有大小和方向,位移是矢量,其他选项均为标量。' + }, + { + difficulty: 'easy', + text: '下列哪个物理量是矢量?', + options: ['A. 质量', 'B. 时间', 'C. 位移', 'D. 路程'], + answer: 'C', + explanation: '矢量具有大小和方向,位移是矢量,其他选项均为标量。' + }, + { + difficulty: 'easy', + text: '下列哪个物理量是矢量?', + options: ['A. 质量', 'B. 时间', 'C. 位移', 'D. 路程'], + answer: 'C', + explanation: '矢量具有大小和方向,位移是矢量,其他选项均为标量。' + }, + { + difficulty: 'easy', + text: '下列哪个物理量是矢量?', + options: ['A. 质量', 'B. 时间', 'C. 位移', 'D. 路程'], + answer: 'C', + explanation: '矢量具有大小和方向,位移是矢量,其他选项均为标量。' + }, + { + difficulty: 'easy', + text: '下列哪个物理量是矢量?', + options: ['A. 质量', 'B. 时间', 'C. 位移', 'D. 路程'], + answer: 'C', + explanation: '矢量具有大小和方向,位移是矢量,其他选项均为标量。' + }, + // 中等难度题目 (5道) + { + difficulty: 'medium', + text: '关于万有引力定律,下列说法正确的是?', + options: [ + 'A. 万有引力只存在于天体之间', + 'B. 万有引力与物体质量成正比,与距离成反比', + 'C. 万有引力的发现者是牛顿', + 'D. 地球对苹果的引力大于苹果对地球的引力' + ], + answer: 'C', + explanation: '万有引力存在于任何有质量的物体之间,A错误;万有引力与距离的平方成反比,B错误;牛顿发现了万有引力定律,C正确;物体间的引力是相互的,大小相等,D错误。' + }, + { + difficulty: 'medium', + text: '关于万有引力定律,下列说法正确的是?', + options: [ + 'A. 万有引力只存在于天体之间', + 'B. 万有引力与物体质量成正比,与距离成反比', + 'C. 万有引力的发现者是牛顿', + 'D. 地球对苹果的引力大于苹果对地球的引力' + ], + answer: 'C', + explanation: '万有引力存在于任何有质量的物体之间,A错误;万有引力与距离的平方成反比,B错误;牛顿发现了万有引力定律,C正确;物体间的引力是相互的,大小相等,D错误。' + }, + { + difficulty: 'medium', + text: '关于万有引力定律,下列说法正确的是?', + options: [ + 'A. 万有引力只存在于天体之间', + 'B. 万有引力与物体质量成正比,与距离成反比', + 'C. 万有引力的发现者是牛顿', + 'D. 地球对苹果的引力大于苹果对地球的引力' + ], + answer: 'C', + explanation: '万有引力存在于任何有质量的物体之间,A错误;万有引力与距离的平方成反比,B错误;牛顿发现了万有引力定律,C正确;物体间的引力是相互的,大小相等,D错误。' + }, + { + difficulty: 'medium', + text: '关于万有引力定律,下列说法正确的是?', + options: [ + 'A. 万有引力只存在于天体之间', + 'B. 万有引力与物体质量成正比,与距离成反比', + 'C. 万有引力的发现者是牛顿', + 'D. 地球对苹果的引力大于苹果对地球的引力' + ], + answer: 'C', + explanation: '万有引力存在于任何有质量的物体之间,A错误;万有引力与距离的平方成反比,B错误;牛顿发现了万有引力定律,C正确;物体间的引力是相互的,大小相等,D错误。' + }, + { + difficulty: 'medium', + text: '关于万有引力定律,下列说法正确的是?', + options: [ + 'A. 万有引力只存在于天体之间', + 'B. 万有引力与物体质量成正比,与距离成反比', + 'C. 万有引力的发现者是牛顿', + 'D. 地球对苹果的引力大于苹果对地球的引力' + ], + answer: 'C', + explanation: '万有引力存在于任何有质量的物体之间,A错误;万有引力与距离的平方成反比,B错误;牛顿发现了万有引力定律,C正确;物体间的引力是相互的,大小相等,D错误。' + }, + // 困难难度题目 (5道) + { + difficulty: 'hard', + text: '相对论中质量与能量的关系表达式是?', + options: ['A. E=mc²', 'B. F=ma', 'C. E=hv', 'D. P=mv'], + answer: 'A', + explanation: '爱因斯坦的质能方程E=mc²表明质量和能量可以相互转换。' + }, + { + difficulty: 'hard', + text: '相对论中质量与能量的关系表达式是?', + options: ['A. E=mc²', 'B. F=ma', 'C. E=hv', 'D. P=mv'], + answer: 'A', + explanation: '爱因斯坦的质能方程E=mc²表明质量和能量可以相互转换。' + }, + { + difficulty: 'hard', + text: '相对论中质量与能量的关系表达式是?', + options: ['A. E=mc²', 'B. F=ma', 'C. E=hv', 'D. P=mv'], + answer: 'A', + explanation: '爱因斯坦的质能方程E=mc²表明质量和能量可以相互转换。' + }, + { + difficulty: 'hard', + text: '相对论中质量与能量的关系表达式是?', + options: ['A. E=mc²', 'B. F=ma', 'C. E=hv', 'D. P=mv'], + answer: 'A', + explanation: '爱因斯坦的质能方程E=mc²表明质量和能量可以相互转换。' + }, + { + difficulty: 'hard', + text: '相对论中质量与能量的关系表达式是?', + options: ['A. E=mc²', 'B. F=ma', 'C. E=hv', 'D. P=mv'], + answer: 'A', + explanation: '爱因斯坦的质能方程E=mc²表明质量和能量可以相互转换。' + }, +]; + +// 当前难度级别,初始为中等 +let currentDifficulty = 'medium'; +// 已完成的难度 +const completedDifficulties = []; +// 各难度得分情况 +const scores = { + easy: { score: 0, correct: 0, incorrect: 0 }, + medium: { score: 0, correct: 0, incorrect: 0 }, + hard: { score: 0, correct: 0, incorrect: 0 } +}; + +// 学伴功能相关变量 +let mediaRecorder; let audioChunks = []; let isRecording = false; +let audioElement = null; let isPlaying = false; +let currentQuestion = null; + +// DOM元素 +const questionContainer = document.getElementById('question-container'); +const submitBtn = document.getElementById('submit-btn'); +const resultSection = document.getElementById('result-section'); +const totalScoreElement = document.getElementById('total-score'); +const correctCountElement = document.getElementById('correct-count'); +const incorrectCountElement = document.getElementById('incorrect-count'); +const navigationSection = document.getElementById('navigation-section'); +const navigationMessage = document.getElementById('navigation-message'); +const nextBtn = document.getElementById('next-btn'); +const difficultyIndicator = document.querySelector('.difficulty-indicator'); +// 学伴功能DOM元素 +const recordingIndicator = document.getElementById('recordingIndicator'); +const thinkingIndicator = document.getElementById('thinkingIndicator'); +const resultContainer = document.getElementById('resultContainer'); +const asrResultText = document.getElementById('asrResultText'); +const feedbackResultText = document.getElementById('feedbackResultText'); +const playAudioBtn = document.getElementById('playAudioBtn'); +const audioProgress = document.getElementById('audioProgress'); +const progressBar = document.getElementById('progressBar'); +const audioTime = document.getElementById('audioTime'); + +// 初始化页面 +document.addEventListener('DOMContentLoaded', () => { + renderQuestions(currentDifficulty); + // 绑定学伴答疑按钮事件 + document.addEventListener('click', function(e) { + if (e.target && e.target.classList.contains('ask-xueban-btn')) { + currentQuestion = { + number: e.target.dataset.question, + difficulty: e.target.dataset.difficulty + }; + startRecording(); + } + }); +}); + +// 渲染指定难度的题目 +function renderQuestions(difficulty) { + questionContainer.innerHTML = ''; + + // 筛选当前难度的题目 + const filteredQuestions = questions.filter(q => q.difficulty === difficulty); + + // 生成题目HTML + filteredQuestions.forEach((q, index) => { + const questionNumber = index + 1; + const questionElement = document.createElement('div'); + questionElement.className = 'question'; + questionElement.dataset.difficulty = q.difficulty; + questionElement.dataset.question = questionNumber; + + questionElement.innerHTML = ` +
+
${getDifficultyName(q.difficulty)}难度 - 问题 ${questionNumber}
+
20分
+
+

${q.text}

+
+ ${q.options.map((option, optIndex) => { + const optionLetter = String.fromCharCode(65 + optIndex); + return ` +
+ + +
+ `; + }).join('')} +
+
${q.explanation}
+ + `; + + questionContainer.appendChild(questionElement); + }); +} + +// 获取难度名称 +function getDifficultyName(difficulty) { + const names = { + easy: '简单', + medium: '中等', + hard: '高级' + }; + return names[difficulty] || difficulty; +} + +// 提交答案 +submitBtn.addEventListener('click', () => { + checkAnswers(); + submitBtn.disabled = true; + submitBtn.textContent = '已提交'; +}); + +// 检查答案 +function checkAnswers() { + let correctCount = 0; + let incorrectCount = 0; + let totalScore = 0; + + // 获取当前难度的题目 + const currentQuestions = questions.filter(q => q.difficulty === currentDifficulty); + + // 检查每道题的答案 + currentQuestions.forEach((q, index) => { + const questionNumber = index + 1; + const selectedOption = document.querySelector(`input[name="q${q.difficulty}-${questionNumber}"]:checked`); + const explanationElement = document.getElementById(`explanation-${q.difficulty}-${questionNumber}`); + const optionsContainer = document.querySelector(`div[data-difficulty="${q.difficulty}"][data-question="${questionNumber}"] .options`); + const allOptions = optionsContainer.querySelectorAll('.option'); + + // 显示解析 + explanationElement.classList.add('show'); + + if (!selectedOption) { + // 未答题 + optionsContainer.style.border = '2px solid #f39c12'; + return; + } + + // 标记正确或错误 + const selectedValue = selectedOption.value; + if (selectedValue === q.answer) { + // 正确 + selectedOption.closest('.option').classList.add('correct'); + correctCount++; + totalScore += 20; + } else { + // 错误 + selectedOption.closest('.option').classList.add('incorrect'); + // 标记正确答案 + allOptions.forEach(option => { + if (option.querySelector(`input[value="${q.answer}"]`)) { + option.classList.add('correct'); + } + }); + incorrectCount++; + } + }); + + // 更新当前难度得分 + scores[currentDifficulty] = { + score: totalScore, + correct: correctCount, + incorrect: incorrectCount + }; + + // 添加到已完成难度 + if (!completedDifficulties.includes(currentDifficulty)) { + completedDifficulties.push(currentDifficulty); + } + + // 显示结果 + showResults(); + + // 显示下一步建议 + showNextRecommendation(); +} + +// 显示结果 +function showResults() { + resultSection.style.display = 'block'; + + // 计算总得分 + let totalScore = 0; + let totalCorrect = 0; + let totalIncorrect = 0; + + completedDifficulties.forEach(difficulty => { + totalScore += scores[difficulty].score; + totalCorrect += scores[difficulty].correct; + totalIncorrect += scores[difficulty].incorrect; + }); + + // 更新结果显示 + totalScoreElement.textContent = totalScore; + correctCountElement.textContent = totalCorrect; + incorrectCountElement.textContent = totalIncorrect; + + // 滚动到结果区域 + resultSection.scrollIntoView({ behavior: 'smooth' }); +} + +// 显示下一步建议 +function showNextRecommendation() { + navigationSection.style.display = 'block'; + const currentScore = scores[currentDifficulty]; + + if (currentDifficulty === 'medium') { + if (currentScore.correct >= 3) { + navigationMessage.textContent = `恭喜!您在${getDifficultyName(currentDifficulty)}难度中答对了${currentScore.correct}题,表现优秀,建议挑战高级难度。`; + nextBtn.onclick = () => switchDifficulty('hard'); + } else { + navigationMessage.textContent = `您在${getDifficultyName(currentDifficulty)}难度中答对了${currentScore.correct}题,建议先尝试简单难度巩固基础。`; + nextBtn.onclick = () => switchDifficulty('easy'); + } + } else if (currentDifficulty === 'easy') { + navigationMessage.textContent = `您已完成${getDifficultyName(currentDifficulty)}难度,建议继续挑战中等难度。`; + nextBtn.onclick = () => switchDifficulty('medium'); + } else if (currentDifficulty === 'hard') { + navigationMessage.textContent = `恭喜您完成了所有难度级别!您的总分为${scores.easy.score + scores.medium.score + scores.hard.score}分。`; + nextBtn.style.display = 'none'; + } + + navigationSection.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); +} + +// 切换难度 +function switchDifficulty(nextDifficulty) { + currentDifficulty = nextDifficulty; + difficultyIndicator.textContent = `当前难度:${getDifficultyName(nextDifficulty)}`; + difficultyIndicator.className = `difficulty-indicator difficulty-${nextDifficulty}`; + + // 重置按钮状态 + submitBtn.disabled = false; + submitBtn.textContent = '提交答案'; + + // 隐藏结果和导航区域 + resultSection.style.display = 'none'; + navigationSection.style.display = 'none'; + + // 渲染新难度题目 + renderQuestions(nextDifficulty); + + // 滚动到页面顶部 + window.scrollTo({ top: 0, behavior: 'smooth' }); +} + +// 学伴功能 - 开始录音 +function startRecording() { + if (isRecording) return; + + navigator.mediaDevices.getUserMedia({ audio: true }) + .then(stream => { + mediaRecorder = new MediaRecorder(stream); + audioChunks = []; + + mediaRecorder.ondataavailable = event => { + if (event.data.size > 0) audioChunks.push(event.data); + }; + + mediaRecorder.onstop = () => { + const audioBlob = new Blob(audioChunks, { type: 'audio/wav' }); + uploadAudioToServer(audioBlob); + }; + + mediaRecorder.start(); + isRecording = true; + recordingIndicator.style.display = 'flex'; + + // 设置最长录音时间为60秒 + setTimeout(stopRecording, 60000); + }) + .catch(error => { + console.error("获取麦克风权限失败:", error); + alert("请授权麦克风权限以使用录音功能"); + }); +} + +// 学伴功能 - 停止录音 +function stopRecording() { + if (!isRecording || !mediaRecorder) return; + + mediaRecorder.stop(); + isRecording = false; + recordingIndicator.style.display = 'none'; + + if (mediaRecorder.stream) { + mediaRecorder.stream.getTracks().forEach(track => track.stop()); + } +} + +// 学伴功能 - 上传音频到服务器 +function uploadAudioToServer(audioBlob) { + thinkingIndicator.style.display = 'flex'; + resultContainer.style.display = 'none'; + + const formData = new FormData(); + formData.append('file', audioBlob, 'recording.wav'); + if (currentQuestion) { + formData.append('question_number', currentQuestion.number); + formData.append('difficulty', currentQuestion.difficulty); + } + + fetch('/api/xueban/upload-audio', { method: 'POST', body: formData }) + .then(response => response.json()) + .then(data => { + thinkingIndicator.style.display = 'none'; + if (data.success) { + asrResultText.textContent = data.asr_text || '未识别到内容'; + feedbackResultText.textContent = data.feedback_text || '无反馈内容'; + resultContainer.style.display = 'flex'; + + if (data.audio_url) { + audioElement = new Audio(data.audio_url); + audioElement.onloadedmetadata = function() { updateAudioTimeDisplay(); }; + audioElement.ontimeupdate = function() { updateAudioProgress(); updateAudioTimeDisplay(); }; + audioElement.onended = function() { isPlaying = false; updatePlayButton(); }; + playAudioBtn.onclick = togglePlayAudio; + audioProgress.onclick = function(e) { + const rect = audioProgress.getBoundingClientRect(); + const clickPosition = (e.clientX - rect.left) / rect.width; + audioElement.currentTime = clickPosition * audioElement.duration; + }; + } + } else { + alert('音频处理失败: ' + data.message); + } + }) + .catch(error => { + thinkingIndicator.style.display = 'none'; + alert('上传音频失败: ' + error.message); + }); +} + +// 学伴功能 - 切换音频播放/暂停 +function togglePlayAudio() { + if (!audioElement) return; + isPlaying ? audioElement.pause() : audioElement.play(); + isPlaying = !isPlaying; + updatePlayButton(); +} + +// 学伴功能 - 更新播放按钮状态 +function updatePlayButton() { + playAudioBtn.innerHTML = isPlaying ? + `` : + ``; +} + +// 学伴功能 - 更新音频进度条 +function updateAudioProgress() { + if (audioElement && audioElement.duration) { + progressBar.style.width = `${(audioElement.currentTime / audioElement.duration) * 100}%`; + } +} + +// 学伴功能 - 更新音频时间显示 +function updateAudioTimeDisplay() { + if (audioElement && audioElement.duration) { + const currentTime = formatTime(audioElement.currentTime); + const duration = formatTime(audioElement.duration); + audioTime.textContent = `${currentTime} / ${duration}`; + } +} + +// 学伴功能 - 格式化时间为 MM:SS +function formatTime(seconds) { + const mins = Math.floor(seconds / 60); + const secs = Math.floor(seconds % 60); + return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`; +} \ No newline at end of file