Files
dsProject/dsLightRag/static/XiaoZhi.html

200 lines
8.7 KiB
HTML
Raw Normal View History

2025-08-22 08:01:36 +08:00
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>学伴切换示例</title>
<style>
.model-selector {
2025-08-22 08:06:17 +08:00
position: fixed; top: 20px; left: 20px; z-index: 1000;
padding: 10px; background-color: rgba(255, 255, 255, 0.8);
border-radius: 5px; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
2025-08-22 08:01:36 +08:00
}
2025-08-22 08:06:17 +08:00
select { padding: 8px 12px; border: 1px solid #ccc; border-radius: 4px; background-color: white; font-size: 14px; }
.recording-controls {
position: fixed; bottom: 20px; right: 20px; z-index: 1000;
display: flex; flex-direction: column; gap: 10px;
2025-08-22 08:01:36 +08:00
}
2025-08-22 08:06:17 +08:00
.record-button {
width: 70px; height: 70px; border-radius: 50%;
background-color: #dc3545; border: none; color: white;
font-size: 16px; cursor: pointer; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
display: flex; align-items: center; justify-content: center;
2025-08-22 08:18:29 +08:00
/* 确保按钮始终可见 */
opacity: 1 !important;
visibility: visible !important;
2025-08-22 08:01:36 +08:00
}
2025-08-22 08:06:17 +08:00
.record-button:hover { background-color: #c82333; }
.stop-button {
width: 70px; height: 70px; border-radius: 50%;
background-color: #6c757d; border: none; color: white;
font-size: 16px; cursor: pointer; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
display: flex; align-items: center; justify-content: center;
2025-08-22 08:01:36 +08:00
display: none;
2025-08-22 08:18:29 +08:00
/* 确保按钮始终可见 */
opacity: 1 !important;
visibility: visible !important;
2025-08-22 08:01:36 +08:00
}
2025-08-22 08:06:17 +08:00
.stop-button:hover { background-color: #5a6268; }
.recording-indicator {
position: fixed; bottom: 20px; left: 20px; z-index: 1000;
padding: 10px 15px; background-color: rgba(220, 53, 69, 0.9);
color: white; border-radius: 20px; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
display: none; align-items: center;
2025-08-22 08:01:36 +08:00
}
2025-08-22 08:06:17 +08:00
.recording-dot {
width: 10px; height: 10px; background-color: white;
border-radius: 50%; margin-right: 8px; animation: pulse 1.5s infinite;
2025-08-22 08:01:36 +08:00
}
2025-08-22 08:06:17 +08:00
@keyframes pulse { 0% { opacity: 1; } 50% { opacity: 0.5; } 100% { opacity: 1; } }
2025-08-22 08:01:36 +08:00
</style>
</head>
<body>
<div class="model-selector">
<label for="model-select">选择学伴:</label>
<select id="model-select">
<option value="shizuku">小智</option>
<option value="koharu">小荷</option>
<option value="wanko">汪喵</option>
</select>
</div>
<div class="recording-indicator" id="recordingIndicator">
<div class="recording-dot"></div>
<span>正在录音...</span>
</div>
2025-08-22 08:06:17 +08:00
<div class="recording-controls">
<button class="record-button" id="startRecordBtn">开始录音</button>
<button class="stop-button" id="stopRecordBtn">停止录音</button>
2025-08-22 08:01:36 +08:00
</div>
<script src="https://l2dwidget.js.org/lib/L2Dwidget.min.js"></script>
<script>
2025-08-22 08:18:29 +08:00
// 模型配置 - 使用与Sample.html相同的CDN链接
2025-08-22 08:01:36 +08:00
const models = {
2025-08-22 08:18:29 +08:00
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: "小荷" },
2025-08-22 08:06:17 +08:00
wanko: { jsonPath: "https://unpkg.com/live2d-widget-model-wanko@1.0.5/assets/wanko.model.json", name: "汪喵" }
2025-08-22 08:01:36 +08:00
};
// 录音相关变量
2025-08-22 08:06:17 +08:00
let mediaRecorder; let audioChunks = []; let isRecording = false;
2025-08-22 08:01:36 +08:00
// 获取URL参数
function getUrlParam(name) {
const reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)');
const r = window.location.search.substr(1).match(reg);
2025-08-22 08:06:17 +08:00
return r ? unescape(r[2]) : null;
2025-08-22 08:01:36 +08:00
}
// 开始录音
function startRecording() {
if (isRecording) return;
2025-08-22 08:06:17 +08:00
console.log("尝试开始录音");
2025-08-22 08:01:36 +08:00
navigator.mediaDevices.getUserMedia({ audio: true })
.then(stream => {
mediaRecorder = new MediaRecorder(stream);
audioChunks = [];
mediaRecorder.ondataavailable = event => {
2025-08-22 08:06:17 +08:00
if (event.data.size > 0) audioChunks.push(event.data);
2025-08-22 08:01:36 +08:00
};
mediaRecorder.onstop = () => {
const audioBlob = new Blob(audioChunks, { type: 'audio/wav' });
console.log("录音完成,音频数据大小:", audioBlob.size);
const audioUrl = URL.createObjectURL(audioBlob);
console.log("录音URL:", audioUrl);
2025-08-22 08:06:17 +08:00
// 这里可以调用ASR服务
2025-08-22 08:01:36 +08:00
};
mediaRecorder.start();
isRecording = true;
document.getElementById('recordingIndicator').style.display = 'flex';
2025-08-22 08:06:17 +08:00
document.getElementById('startRecordBtn').style.display = 'none';
document.getElementById('stopRecordBtn').style.display = 'flex';
console.log("开始录音成功");
2025-08-22 08:01:36 +08:00
// 设置最长录音时间为60秒
setTimeout(stopRecording, 60000);
})
.catch(error => {
console.error("获取麦克风权限失败:", error);
alert("请授权麦克风权限以使用录音功能");
});
}
// 停止录音
function stopRecording() {
if (!isRecording || !mediaRecorder) return;
mediaRecorder.stop();
isRecording = false;
document.getElementById('recordingIndicator').style.display = 'none';
2025-08-22 08:06:17 +08:00
document.getElementById('startRecordBtn').style.display = 'flex';
document.getElementById('stopRecordBtn').style.display = 'none';
2025-08-22 08:01:36 +08:00
console.log("停止录音");
if (mediaRecorder.stream) {
mediaRecorder.stream.getTracks().forEach(track => track.stop());
}
}
2025-08-22 08:18:29 +08:00
// 初始化看板娘 - 简化为Sample.html的工作版本
2025-08-22 08:01:36 +08:00
function initL2Dwidget() {
const modelId = getUrlParam('id') || 'shizuku';
const model = models[modelId] || models.shizuku;
document.getElementById('model-select').value = modelId;
console.log('加载模型:', model.name, model.jsonPath);
2025-08-22 08:18:29 +08:00
// 初始化模型 - 与Sample.html相同的配置
2025-08-22 08:01:36 +08:00
L2Dwidget.init({
2025-08-22 08:06:17 +08:00
"model": { "jsonPath": model.jsonPath, "scale": 1 },
2025-08-22 08:18:29 +08:00
"display": {
"position": "right",
"width": 150,
"height": 300,
"hOffset": 0,
"vOffset": -20
},
2025-08-22 08:06:17 +08:00
"mobile": { "show": true, "scale": 0.5 },
"react": { "opacityDefault": 0.8, "opacityOnHover": 1 },
"dialog": { "enable": true, "script": {
'tap body': `你好啊,我是${model.name}。`,
'tap face': '有什么问题或者烦心事都可以和我聊聊~'
}}
2025-08-22 08:01:36 +08:00
});
}
// 页面加载完成后初始化
window.onload = function() {
2025-08-22 08:18:29 +08:00
// 直接初始化看板娘,不添加额外延迟
2025-08-22 08:01:36 +08:00
initL2Dwidget();
2025-08-22 08:18:29 +08:00
// 监听下拉框变化
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);
2025-08-22 08:06:17 +08:00
// 页面加载时请求麦克风权限
navigator.mediaDevices.getUserMedia({ audio: true })
.then(stream => {
console.log("麦克风权限已授予");
// 立即停止流,只获取权限
stream.getTracks().forEach(track => track.stop());
})
.catch(error => {
console.error("获取麦克风权限失败:", error);
alert("请授权麦克风权限以使用录音功能");
});
2025-08-22 08:01:36 +08:00
};
</script>
</body>
</html>