Files
dsProject/dsLightRag/static/JiMeng/video_preview.html
2025-08-21 11:08:47 +08:00

340 lines
14 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!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>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif;
}
body {
background-color: #f5f7fa;
color: #333;
line-height: 1.6;
padding: 20px;
}
.container {
max-width: 900px;
margin: 0 auto;
background: white;
border-radius: 10px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
padding: 30px;
}
h1 {
text-align: center;
margin-bottom: 20px;
color: #2c3e50;
}
.video-container {
display: flex;
flex-direction: column;
align-items: center;
margin: 30px 0;
min-height: 400px;
justify-content: center;
background-color: #f8f9fa;
border-radius: 6px;
padding: 20px;
}
.loading {
text-align: center;
font-size: 18px;
color: #666;
}
.video-player {
max-width: 100%;
max-height: 800px; /* 增加最大高度 */
width: 100%; /* 宽度充满容器 */
border-radius: 6px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
display: none;
}
.btn-group {
display: flex;
justify-content: center;
margin-top: 30px;
gap: 20px;
}
.btn {
padding: 12px 25px;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 16px;
transition: background 0.3s;
}
.btn-primary {
background-color: #3498db;
color: white;
}
.btn-primary:hover {
background-color: #2980b9;
}
.btn-secondary {
background-color: #95a5a6;
color: white;
}
.btn-secondary:hover {
background-color: #7f8c8d;
}
.progress-container {
width: 100%;
max-width: 600px;
margin: 20px 0;
}
.progress-bar {
width: 100%;
height: 20px;
background-color: #e9ecef;
border-radius: 10px;
overflow: hidden;
}
.progress {
height: 100%;
background-color: #3498db;
width: 0%;
transition: width 0.3s;
}
.progress-text {
text-align: center;
margin-top: 10px;
color: #666;
}
</style>
</head>
<body>
<div class="container">
<h1>三、视频预览</h1>
<div class="video-container">
<div class="loading" id="loading">视频生成中,请稍候...</div>
<div class="progress-container">
<div class="progress-bar">
<div class="progress" id="progress"></div>
</div>
<div class="progress-text" id="progressText">正在准备...</div>
</div>
<video id="videoPlayer" class="video-player" controls preload="metadata"></video>
</div>
<div class="btn-group">
<button class="btn btn-secondary" id="backBtn">返回修改</button>
<button class="btn btn-primary" id="downloadBtn" style="display: none;">下载视频</button>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
const taskId = sessionStorage.getItem('videoTaskId');
const loading = document.getElementById('loading');
const progress = document.getElementById('progress');
const progressText = document.getElementById('progressText');
const videoPlayer = document.getElementById('videoPlayer');
const backBtn = document.getElementById('backBtn');
const downloadBtn = document.getElementById('downloadBtn');
if (!taskId) {
alert('没有找到视频任务ID请返回重新生成');
window.location.href = 'image_preview.html';
return;
}
// 定义查询间隔(毫秒)
const queryInterval = 3000; // 3秒查询一次
// 最大查询次数(防止无限循环)- 改为200次延长到10分钟
const maxQueries = 200; // 最多查询200次
// 当前查询次数
let queryCount = 0;
// 模拟进度0-100
let simulatedProgress = 0;
// 开始时间
const startTime = new Date().getTime();
// 查询视频任务状态
function queryVideoTask() {
if (queryCount >= maxQueries) {
const elapsedTime = Math.round((new Date().getTime() - startTime) / 1000);
loading.textContent = `视频生成超时(已等待${elapsedTime}秒),您可以稍后在历史记录中查看,或重新生成。`;
progressText.textContent = '生成超时';
return;
}
fetch('/api/jimeng/query_video_task', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ task_id: taskId })
})
.then(response => {
if (!response.ok) {
throw new Error('网络响应异常');
}
return response.json();
})
.then(data => {
queryCount++;
if (data.code === 200) {
const statusInfo = data.data;
if (statusInfo.status === 'completed') {
// 视频生成完成
loading.style.display = 'none';
progress.style.width = '100%';
progressText.textContent = '生成完成正在保存到OBS...';
// 调用接口将视频保存到OBS
fetch('/api/jimeng/upload_url_to_obs', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
url: statusInfo.video_url,
object_key_prefix: 'jimeng_videos/'
})
})
.then(response => {
if (!response.ok) {
throw new Error('保存到OBS失败');
}
return response.json();
})
.then(obsData => {
if (obsData.code === 200) {
// 获取OBS下载URL
const obsVideoUrl = obsData.data.obs_url;
progressText.textContent = '已保存到OBS';
// 设置视频源为OBS URL
videoPlayer.src = obsVideoUrl;
videoPlayer.style.display = 'block';
downloadBtn.style.display = 'inline-block';
} else {
progressText.textContent = '保存到OBS失败: ' + obsData.message;
// 仍然使用原始URL播放
videoPlayer.src = statusInfo.video_url;
videoPlayer.style.display = 'block';
downloadBtn.style.display = 'inline-block';
}
})
.catch(error => {
console.error('保存到OBS时出错:', error);
progressText.textContent = '保存到OBS出错: ' + error.message;
// 仍然使用原始URL播放
videoPlayer.src = statusInfo.video_url;
videoPlayer.style.display = 'block';
downloadBtn.style.display = 'inline-block';
});
} else if (statusInfo.status === 'failed') {
// 视频生成失败
loading.textContent = '视频生成失败: ' + statusInfo.error_msg;
progressText.textContent = '生成失败';
} else {
// 视频生成中
// 计算已等待时间
const elapsedTime = Math.round((new Date().getTime() - startTime) / 1000);
// 更新进度(更平滑的进度更新)
const progressPercentage = Math.min(95, (queryCount / maxQueries) * 100);
progress.style.width = progressPercentage + '%';
progressText.textContent = `正在生成中... (已等待${elapsedTime}秒,${Math.round(progressPercentage)}%)`;
// 继续查询
setTimeout(queryVideoTask, queryInterval);
}
} else {
loading.textContent = '查询失败: ' + data.message;
progressText.textContent = '查询失败';
// 继续查询
setTimeout(queryVideoTask, queryInterval);
}
})
.catch(error => {
console.error('查询视频任务时出错:', error);
loading.textContent = '查询出错: ' + error.message;
progressText.textContent = '查询出错';
// 继续查询
setTimeout(queryVideoTask, queryInterval);
});
}
// 开始查询
queryVideoTask();
// 返回按钮
backBtn.addEventListener('click', function() {
window.location.href = 'image_preview.html';
});
// 下载按钮
downloadBtn.addEventListener('click', function() {
if (videoPlayer.src) {
// 使用fetch API获取视频blob
fetch(videoPlayer.src)
.then(response => {
if (!response.ok) {
throw new Error('下载失败: ' + response.statusText);
}
return response.blob();
})
.then(blob => {
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'generated_video.mp4';
document.body.appendChild(a);
a.click();
// 释放URL对象
setTimeout(() => {
URL.revokeObjectURL(url);
document.body.removeChild(a);
}, 100);
})
.catch(error => {
console.error('下载视频时出错:', error);
alert('下载失败: ' + error.message);
});
}
});
// 视频错误处理
videoPlayer.addEventListener('error', function(e) {
console.error('视频播放错误:', e);
let errorMsg = '视频播放失败';
switch(videoPlayer.error.code) {
case 1:
errorMsg += ': 视频加载中断';
break;
case 2:
errorMsg += ': 视频格式不支持';
break;
case 3:
errorMsg += ': 视频解码失败';
break;
case 4:
errorMsg += ': 视频无法加载';
break;
}
alert(errorMsg);
});
// 添加取消按钮
const cancelBtn = document.createElement('button');
cancelBtn.className = 'btn btn-secondary';
cancelBtn.textContent = '取消等待';
cancelBtn.addEventListener('click', function() {
if (confirm('确定要取消等待吗?视频仍在后台生成,您可以稍后在历史记录中查看。')) {
window.location.href = 'image_preview.html';
}
});
document.querySelector('.btn-group').appendChild(cancelBtn);
});
</script>
</body>
</html>