diff --git a/dsLightRag/static/XueBan.html b/dsLightRag/static/XueBan.html
index aee173a3..c0021cc6 100644
--- a/dsLightRag/static/XueBan.html
+++ b/dsLightRag/static/XueBan.html
@@ -179,287 +179,298 @@
有权限问题的话,请点击这里
-
+
+
+
+
+
+
- // 录音相关变量
- let mediaRecorder; let audioChunks = []; let isRecording = false;
- // 音频播放相关变量
- let audioElement = null; let isPlaying = false;
+ // 模型配置 - 使用与Sample.html相同的CDN链接
+ const models = {
+ shizuku: { jsonPath: "https://unpkg.com/live2d-widget-model-shizuku@1.0.5/assets/shizuku.model.json", name: "小智" },
+ koharu: { jsonPath: "https://unpkg.com/live2d-widget-model-koharu@1.0.5/assets/koharu.model.json", name: "小荷" },
+ wanko: { jsonPath: "https://unpkg.com/live2d-widget-model-wanko@1.0.5/assets/wanko.model.json", name: "汪喵" }
+ };
- // 获取URL参数
- function getUrlParam(name) {
- const reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)');
- const r = window.location.search.substr(1).match(reg);
- return r ? unescape(r[2]) : null;
- }
+ // 录音相关变量
+ let mediaRecorder; let audioChunks = []; let isRecording = false;
+ // 音频播放相关变量
+ let audioElement = null; let isPlaying = false;
- // 开始录音
- function startRecording() {
- if (isRecording) return;
+ // 获取URL参数
+ function getUrlParam(name) {
+ const reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)');
+ const r = window.location.search.substr(1).match(reg);
+ return r ? unescape(r[2]) : null;
+ }
- console.log("尝试开始录音");
- navigator.mediaDevices.getUserMedia({ audio: true })
- .then(stream => {
- mediaRecorder = new MediaRecorder(stream);
- audioChunks = [];
+ // 开始录音
+ function startRecording() {
+ if (isRecording) return;
- mediaRecorder.ondataavailable = event => {
- if (event.data.size > 0) audioChunks.push(event.data);
- };
+ console.log("尝试开始录音");
+ navigator.mediaDevices.getUserMedia({ audio: true })
+ .then(stream => {
+ mediaRecorder = new MediaRecorder(stream);
+ audioChunks = [];
- mediaRecorder.onstop = () => {
- const audioBlob = new Blob(audioChunks, { type: 'audio/wav' });
- console.log("录音完成,音频数据大小:", audioBlob.size);
- const audioUrl = URL.createObjectURL(audioBlob);
- console.log("录音URL:", audioUrl);
- // 这里可以调用ASR服务
- uploadAudioToServer(audioBlob);
- };
+ mediaRecorder.ondataavailable = event => {
+ if (event.data.size > 0) audioChunks.push(event.data);
+ };
- mediaRecorder.start();
- isRecording = true;
- document.getElementById('recordingIndicator').style.display = 'flex';
- document.getElementById('startRecordBtn').style.display = 'none';
- document.getElementById('stopRecordBtn').style.display = 'flex';
- console.log("开始录音成功");
+ mediaRecorder.onstop = () => {
+ const audioBlob = new Blob(audioChunks, { type: 'audio/wav' });
+ console.log("录音完成,音频数据大小:", audioBlob.size);
+ const audioUrl = URL.createObjectURL(audioBlob);
+ console.log("录音URL:", audioUrl);
+ // 这里可以调用ASR服务
+ uploadAudioToServer(audioBlob);
+ };
- // 设置最长录音时间为60秒
- setTimeout(stopRecording, 60000);
- })
- .catch(error => {
- console.error("获取麦克风权限失败:", error);
- alert("请授权麦克风权限以使用录音功能");
- });
- }
+ mediaRecorder.start();
+ isRecording = true;
+ document.getElementById('recordingIndicator').style.display = 'flex';
+ document.getElementById('startRecordBtn').style.display = 'none';
+ document.getElementById('stopRecordBtn').style.display = 'flex';
+ console.log("开始录音成功");
- // 停止录音
- function stopRecording() {
- if (!isRecording || !mediaRecorder) return;
-
- mediaRecorder.stop();
- isRecording = false;
- document.getElementById('recordingIndicator').style.display = 'none';
- document.getElementById('startRecordBtn').style.display = 'flex';
- document.getElementById('stopRecordBtn').style.display = 'none';
- console.log("停止录音");
-
- if (mediaRecorder.stream) {
- mediaRecorder.stream.getTracks().forEach(track => track.stop());
- }
- }
-
- // 上传音频到服务器
- function uploadAudioToServer(audioBlob) {
- console.log("开始上传音频到服务器");
- // 显示思考中动画
- document.getElementById('thinkingIndicator').style.display = 'flex';
-
- const formData = new FormData();
- formData.append('file', audioBlob, 'recording.wav');
-
- fetch('/api/xueban/upload-audio', {
- method: 'POST',
- body: formData
- })
- .then(response => {
- if (!response.ok) {
- throw new Error('服务器响应错误');
- }
- return response.json();
- })
- .then(data => {
- console.log("处理结果:", data);
- // 隐藏思考中动画
- document.getElementById('thinkingIndicator').style.display = 'none';
-
- if (data.success) {
- showResults(data.data);
- } else {
- alert('音频处理失败: ' + data.message);
- }
+ // 设置最长录音时间为60秒
+ setTimeout(stopRecording, 60000);
})
.catch(error => {
- console.error("上传音频失败:", error);
- // 隐藏思考中动画
- document.getElementById('thinkingIndicator').style.display = 'none';
-
- alert('上传音频失败: ' + error.message);
+ console.error("获取麦克风权限失败:", error);
+ alert("请授权麦克风权限以使用录音功能");
});
+ }
+
+ // 停止录音
+ function stopRecording() {
+ if (!isRecording || !mediaRecorder) return;
+
+ mediaRecorder.stop();
+ isRecording = false;
+ document.getElementById('recordingIndicator').style.display = 'none';
+ document.getElementById('startRecordBtn').style.display = 'flex';
+ document.getElementById('stopRecordBtn').style.display = 'none';
+ console.log("停止录音");
+
+ if (mediaRecorder.stream) {
+ mediaRecorder.stream.getTracks().forEach(track => track.stop());
}
+ }
- // 显示ASR识别结果和反馈
- function showResults(data) {
- // 更新结果显示容器
- const resultContainer = document.getElementById('resultContainer');
- resultContainer.style.display = 'flex';
+ // 上传音频到服务器
+ function uploadAudioToServer(audioBlob) {
+ console.log("开始上传音频到服务器");
+ // 显示思考中动画
+ document.getElementById('thinkingIndicator').style.display = 'flex';
+
+ const formData = new FormData();
+ formData.append('file', audioBlob, 'recording.wav');
- // 显示ASR结果
- document.getElementById('asrResultText').textContent = data.asr_text || '未识别到内容';
-
- // 显示反馈文本
- document.getElementById('feedbackResultText').textContent = data.feedback_text || '无反馈内容';
-
- // 准备音频播放
- if (data.audio_url) {
- if (audioElement) {
- audioElement.pause();
- audioElement = null;
- }
-
- audioElement = new Audio(data.audio_url);
- audioElement.onloadedmetadata = function() {
- updateAudioTimeDisplay();
- // 音频加载完成后自动播放
- try {
- audioElement.play();
- isPlaying = true;
- updatePlayButton();
- } catch (e) {
- console.error("自动播放失败:", e);
- }
- // 无论自动播放是否成功,都显示播放按钮
- document.getElementById('playAudioBtn').style.display = 'flex';
- };
-
- audioElement.ontimeupdate = function() {
- updateAudioProgress();
- updateAudioTimeDisplay();
- };
-
- audioElement.onended = function() {
- isPlaying = false;
- updatePlayButton();
- };
-
- // 绑定播放按钮事件
- document.getElementById('playAudioBtn').onclick = togglePlayAudio;
-
- // 绑定进度条点击事件
- document.getElementById('audioProgress').onclick = function(e) {
- if (!audioElement) return;
-
- const progressBar = document.getElementById('audioProgress');
- const rect = progressBar.getBoundingClientRect();
- const clickPosition = (e.clientX - rect.left) / rect.width;
- audioElement.currentTime = clickPosition * audioElement.duration;
- };
+ fetch('/api/xueban/upload-audio', {
+ method: 'POST',
+ body: formData
+ })
+ .then(response => {
+ if (!response.ok) {
+ throw new Error('服务器响应错误');
}
- }
+ return response.json();
+ })
+ .then(data => {
+ console.log("处理结果:", data);
+ // 隐藏思考中动画
+ document.getElementById('thinkingIndicator').style.display = 'none';
+
+ if (data.success) {
+ showResults(data.data);
+ } else {
+ alert('音频处理失败: ' + data.message);
+ }
+ })
+ .catch(error => {
+ console.error("上传音频失败:", error);
+ // 隐藏思考中动画
+ document.getElementById('thinkingIndicator').style.display = 'none';
+
+ alert('上传音频失败: ' + error.message);
+ });
+ }
- // 切换音频播放/暂停
- function togglePlayAudio() {
- if (!audioElement) return;
+ // 显示ASR识别结果和反馈
+ function showResults(data) {
+ // 更新结果显示容器
+ const resultContainer = document.getElementById('resultContainer');
+ resultContainer.style.display = 'flex';
- if (isPlaying) {
+ // 显示ASR结果
+ document.getElementById('asrResultText').textContent = data.asr_text || '未识别到内容';
+
+ // 显示反馈文本
+ document.getElementById('feedbackResultText').textContent = data.feedback_text || '无反馈内容';
+
+ // 准备音频播放
+ if (data.audio_url) {
+ if (audioElement) {
audioElement.pause();
- } else {
- audioElement.play();
+ audioElement = null;
}
- isPlaying = !isPlaying;
- updatePlayButton();
+
+ audioElement = new Audio(data.audio_url);
+ audioElement.onloadedmetadata = function() {
+ updateAudioTimeDisplay();
+ // 音频加载完成后自动播放
+ try {
+ audioElement.play();
+ isPlaying = true;
+ updatePlayButton();
+ } catch (e) {
+ console.error("自动播放失败:", e);
+ }
+ // 无论自动播放是否成功,都显示播放按钮
+ document.getElementById('playAudioBtn').style.display = 'flex';
+ };
+
+ audioElement.ontimeupdate = function() {
+ updateAudioProgress();
+ updateAudioTimeDisplay();
+ };
+
+ audioElement.onended = function() {
+ isPlaying = false;
+ updatePlayButton();
+ };
+
+ // 绑定播放按钮事件
+ document.getElementById('playAudioBtn').onclick = togglePlayAudio;
+
+ // 绑定进度条点击事件
+ document.getElementById('audioProgress').onclick = function(e) {
+ if (!audioElement) return;
+
+ const progressBar = document.getElementById('audioProgress');
+ const rect = progressBar.getBoundingClientRect();
+ const clickPosition = (e.clientX - rect.left) / rect.width;
+ audioElement.currentTime = clickPosition * audioElement.duration;
+ };
}
+ }
- // 更新播放按钮状态
- function updatePlayButton() {
- const playButton = document.getElementById('playAudioBtn');
- if (isPlaying) {
- playButton.innerHTML = `
-
- `;
- } else {
- playButton.innerHTML = `
-
- `;
- }
+ // 切换音频播放/暂停
+ function togglePlayAudio() {
+ if (!audioElement) return;
+
+ if (isPlaying) {
+ audioElement.pause();
+ } else {
+ audioElement.play();
}
+ isPlaying = !isPlaying;
+ updatePlayButton();
+ }
- // 更新音频进度条
- function updateAudioProgress() {
- if (!audioElement || !audioElement.duration) return;
-
- const progress = (audioElement.currentTime / audioElement.duration) * 100;
- document.getElementById('progressBar').style.width = `${progress}%`;
+ // 更新播放按钮状态
+ function updatePlayButton() {
+ const playButton = document.getElementById('playAudioBtn');
+ if (isPlaying) {
+ playButton.innerHTML = `
+
+ `;
+ } else {
+ playButton.innerHTML = `
+
+ `;
}
+ }
- // 更新音频时间显示
- function updateAudioTimeDisplay() {
- if (!audioElement || !audioElement.duration) return;
+ // 更新音频进度条
+ function updateAudioProgress() {
+ if (!audioElement || !audioElement.duration) return;
- const currentTime = formatTime(audioElement.currentTime);
- const duration = formatTime(audioElement.duration);
- document.getElementById('audioTime').textContent = `${currentTime} / ${duration}`;
- }
+ const progress = (audioElement.currentTime / audioElement.duration) * 100;
+ document.getElementById('progressBar').style.width = `${progress}%`;
+ }
- // 格式化时间为 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')}`;
- }
+ // 更新音频时间显示
+ function updateAudioTimeDisplay() {
+ if (!audioElement || !audioElement.duration) return;
- // 初始化看板娘 - 简化为Sample.html的工作版本
- function initL2Dwidget() {
- const modelId = getUrlParam('id') || 'koharu';
- const model = models[modelId] || models.koharu;
+ const currentTime = formatTime(audioElement.currentTime);
+ const duration = formatTime(audioElement.duration);
+ document.getElementById('audioTime').textContent = `${currentTime} / ${duration}`;
+ }
- document.getElementById('model-select').value = modelId;
- console.log('加载模型:', model.name, model.jsonPath);
+ // 格式化时间为 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')}`;
+ }
- // 初始化模型 - 与Sample.html相同的配置
- L2Dwidget.init({
- "model": { "jsonPath": model.jsonPath, "scale": 1 },
- "display": {
- "position": "right",
- "width": 150,
- "height": 300,
- "hOffset": 0, // 重置水平偏移
- "vOffset": -20 // 重置垂直偏移
- },
- "mobile": { "show": true, "scale": 0.5 },
- "react": { "opacityDefault": 0.8, "opacityOnHover": 1 },
- "dialog": { "enable": true, "script": {
- 'tap body': `你好啊,我是${model.name}。`,
- 'tap face': '有什么问题或者烦心事都可以和我聊聊~'
- }}
+ // 初始化看板娘 - 简化为Sample.html的工作版本
+ function initL2Dwidget() {
+ const modelId = getUrlParam('id') || 'koharu';
+ const model = models[modelId] || models.koharu;
+
+ document.getElementById('model-select').value = modelId;
+ console.log('加载模型:', model.name, model.jsonPath);
+
+ // 初始化模型 - 与Sample.html相同的配置
+ L2Dwidget.init({
+ "model": { "jsonPath": model.jsonPath, "scale": 1 },
+ "display": {
+ "position": "right",
+ "width": 150,
+ "height": 300,
+ "hOffset": 0, // 重置水平偏移
+ "vOffset": -20 // 重置垂直偏移
+ },
+ "mobile": { "show": true, "scale": 0.5 },
+ "react": { "opacityDefault": 0.8, "opacityOnHover": 1 },
+ "dialog": { "enable": true, "script": {
+ 'tap body': `你好啊,我是${model.name}。`,
+ 'tap face': '有什么问题或者烦心事都可以和我聊聊~'
+ }}
+ });
+ }
+
+ // 页面加载完成后初始化
+ window.onload = function() {
+ // 直接初始化看板娘,不添加额外延迟
+ initL2Dwidget();
+
+ // 监听下拉框变化(使用独立JS暴露的接口)
+ document.getElementById('model-select').addEventListener('change', function() {
+ window.switchL2DModel(this.value);
+ });
+
+ // 绑定录音按钮事件
+ document.getElementById('startRecordBtn').addEventListener('click', startRecording);
+ document.getElementById('stopRecordBtn').addEventListener('click', stopRecording);
+
+ // 页面加载时请求麦克风权限
+ navigator.mediaDevices.getUserMedia({ audio: true })
+ .then(stream => {
+ console.log("麦克风权限已授予");
+ // 立即停止流,只获取权限
+ stream.getTracks().forEach(track => track.stop());
+ })
+ .catch(error => {
+ console.error("获取麦克风权限失败:", error);
+ alert("请授权麦克风权限以使用录音功能");
});
- }
-
- // 页面加载完成后初始化
- window.onload = function() {
- // 直接初始化看板娘,不添加额外延迟
- initL2Dwidget();
-
- // 监听下拉框变化
- document.getElementById('model-select').addEventListener('change', function() {
- window.location.search = '?id=' + this.value;
- });
-
- // 绑定录音按钮事件
- document.getElementById('startRecordBtn').addEventListener('click', startRecording);
- document.getElementById('stopRecordBtn').addEventListener('click', stopRecording);
-
- // 页面加载时请求麦克风权限
- navigator.mediaDevices.getUserMedia({ audio: true })
- .then(stream => {
- console.log("麦克风权限已授予");
- // 立即停止流,只获取权限
- stream.getTracks().forEach(track => track.stop());
- })
- .catch(error => {
- console.error("获取麦克风权限失败:", error);
- alert("请授权麦克风权限以使用录音功能");
- });
- };
-
+ };