言映AI视频生成(前端+后端)智能体实现(手把手讲解)
言映 AI 视频生成” V1.0 项目已圆满完成需求文档既定目标,实现从文本到视频的全流程自动化,技术架构稳定、功能覆盖全面、用户体验良好,为不同场景用户提供了低门槛、高效率的视频生成解决方案。后续将基于现存不足与用户反馈持续迭代,进一步提升功能完整性、审核精度与用户体验,推动产品向更成熟、更贴合市场需求的方向发展。
一、言映AI视频生成项目页面展示
1.1言映视频展示首页
2.1言映视频生成页面展示
2.3历史视频页面展示
二、项目介绍
本项目包括三个页面视频首页展示,视频生成页面,历史视频页面。实现的功能有,文字生成视频,图片生成视频,以及基于文字生成视频的首尾帧生成视频,本项目核心功能实现使用智谱清言的cogrevidio3模型实现视频功能,所以在完成本项目之前需要在智谱清言官网申请api密钥。
三、项目实现的基本流程
-
视频任务创建:用户填写任务表单,包含视频标题(必填)、文本脚本或主题描述(支持富文本编辑器),选择视频模板(支持分类筛选),并设置视频时长、分辨率、语言、语音性别等参数,还可上传参考素材(图片、音频)。提交后生成唯一任务 ID,任务状态设为 “待处理” 并加入异步任务队列。
-
CogreVideo3集成:后端通过 API 调用 智谱清言 平台工作流,传递任务参数。大模型自动完成脚本优化与分镜生成、AI 语音合成(TTS)、关键帧图像生成、视频片段合成与剪辑、后期处理(添加字幕、背景音乐、转场效果)等步骤,工作流状态实时同步至系统数据库。
-
任务进度监控:用户在 “我的任务” 页面可查看所有任务状态(待处理→处理中→生成成功→可预览 / 下载,失败时显示失败原因),支持手动刷新、取消任务(仅限 “处理中” 前)、重新生成(失败任务可修改后重试),进度通过 WebSocket 实时推送。
-
视频预览与下载:视频生成成功后,提供 H5 视频播放器在线预览,支持 MP4(高清 / 标清)、MOV、GIF(可选片段导出)等多种格式下载,下载前提示文件大小与网络建议,且支持断点续传(通过对象存储签名 URL 实现)。
四、项目使用的技术栈
系统采用前后端分离架构,各层级技术选型精心搭配,保障系统稳定高效运行:
层级 | 技术选型 | 作用 |
---|---|---|
前端 | Vue.js + Element Plus + WebSocket | 为用户提供流畅、直观的操作界面,通过 WebSocket 实现任务进度实时推送,提升用户体验 |
后端 | Python + Django + Django REST Framework | 构建稳定、高效的后端服务,处理业务逻辑、用户请求等 |
数据库 | MySQL 8.0(元数据) + Redis(缓存 / 会话) | MySQL 存储系统元数据,Redis 用于缓存数据和管理用户会话,提高数据访问效率 |
存储 | 对象存储(如 AWS S3 / 阿里云 OSS) | 安全、可靠地存储大量视频文件,支持视频的预览与下载 |
异步任务 | Celery + RabbitMQ/Redis | 负责处理视频生成等耗时任务,避免阻塞主线程,提升系统并发处理能力 |
AI 引擎 | Cogrevideo3(调用文生图、TTS、视频合成等模型) | 集成多种 AI 能力,实现从文本到视频的全流程自动化生成 |
实时通信 | WebSocket | 实时推送任务进度,让用户及时了解视频生成状态 |
五、项目实现
5.1后端实现
后端使用Django框架开发增加项目的稳定性。
实现流程:
①首先在pychram当中创建一个Django项目。
②创建一个Videoyanying的应用。
③在主项目文件夹下urls.py文件当中注册应用的域名。
④在videoyanying项目的视图层文件当中创建视频生成类。
⑤在创建的视频生成类当中去实现视频生成的函数。
⑥调用api实现功能。
基本的实现流程如下现在我将采取代码加文字的形式解释这个项目。
1. start_video_generation
def start_video_generation(request):
try:
data = json.loads(request.body)
prompt = data.get('prompt')
quality = data.get('quality', 'quality') # 默认为 'quality'
fps = data.get('fps', 30) # 默认为 30
if not prompt:
return JsonResponse({'error': '提示词为必填项'}, status=400)
task = generate_video.delay(request.user.id, prompt, mode='text', image_url=None, confirmed=False,
quality=quality, fps=fps)
logger.info(f"任务 {task.id} 已提交,状态为 WAITING,用户 {request.user.id}")
return JsonResponse({'task_id': task.id, 'status': 'WAITING'})
except json.JSONDecodeError:
logger.error("start_video_generation 中的 JSON 无效")
return JsonResponse({'error': '无效的 JSON'}, status=400)
except Exception as e:
logger.error(f"任务提交失败: {str(e)}")
return JsonResponse({'error': f'任务提交失败: {str(e)}'}, status=500)
-
功能:接收文本提示词,提交文本生成视频的异步任务,返回任务 ID 和状态。
-
验证请求中是否包含
prompt
(提示词),缺失则返回 400 错误。 -
调用 Celery 任务
generate_video
,参数为用户 ID、提示词、生成模式(text
)等。 -
记录任务日志并返回任务 ID 和初始状态(
WAITING
)。
-
-
技术点:
-
Django REST Framework 装饰器:
@api_view(['POST'])
(指定 POST 请求)、@permission_classes([IsAuthenticated])
(需登录验证)。 -
CSRF 豁免:
@csrf_exempt
(允许跨域请求)。 -
JSON 解析:
json.loads(request.body)
解析请求体。 -
异步任务:Celery 的
delay()
方法提交异步任务,返回任务 ID。 -
日志记录:
logger.info
记录任务提交信息。 -
错误处理:捕获 JSON 解析错误和通用异常,返回对应错误信息。
-
2. start_image_video_generation
def start_image_video_generation(request):
try:
data = json.loads(request.body)
prompt = data.get('prompt')
image_url = data.get('image_url')
quality = data.get('quality', 'quality') # 默认为 'quality'
fps = data.get('fps', 30) # 默认为 30
if not prompt or not image_url:
return JsonResponse({'error': '提示词和图片 URL 为必填项'}, status=400)
task = generate_video.delay(request.user.id, prompt, mode='image', image_url=image_url, confirmed=False,
quality=quality, fps=fps)
logger.info(f"任务 {task.id} 已提交,状态为 WAITING,图片视频,用户 {request.user.id}")
return JsonResponse({'task_id': task.id, 'status': 'WAITING'})
except json.JSONDecodeError:
logger.error("start_image_video_generation 中的 JSON 无效")
return JsonResponse({'error': '无效的 JSON'}, status=400)
except Exception as e:
logger.error(f"任务提交失败: {str(e)}")
return JsonResponse({'error': f'任务提交失败: {str(e)}'}, status=500)
-
功能:接收文本提示词和图片 URL,提交图片生成视频的异步任务,返回任务 ID 和状态。
-
验证
prompt
和image_url
是否存在,缺失则返回 400 错误。 -
调用 Celery 任务
generate_video
,生成模式为image
。 -
记录日志并返回任务 ID 和状态。
-
-
技术点:
-
同
start_video_generation
的装饰器(@api_view
、@permission_classes
、@csrf_exempt
)。 -
JSON 解析与参数验证:检查图片 URL 是否存在。
-
Celery 异步任务:提交带图片参数的生成任务。
-
日志与错误处理:同上。
-
3. start_frames_video_generation
def start_frames_video_generation(request):
try:
data = json.loads(request.body)
prompt = data.get('prompt')
image_url = data.get('image_url')
quality = data.get('quality', 'quality') # 默认为 'quality'
fps = data.get('fps', 30) # 默认为 30
if not prompt or not image_url or not isinstance(image_url, list) or len(image_url) != 2:
return JsonResponse({'error': '提示词和图片 URL(包含2个URL的列表)为必填项'}, status=400)
task = generate_video.delay(request.user.id, prompt, mode='frames', image_url=image_url, confirmed=False,
quality=quality, fps=fps)
logger.info(f"任务 {task.id} 已提交,状态为 WAITING,首尾帧视频,用户 {request.user.id}")
return JsonResponse({'task_id': task.id, 'status': 'WAITING'})
except json.JSONDecodeError:
logger.error("start_frames_video_generation 中的 JSON 无效")
return JsonResponse({'error': '无效的 JSON'}, status=400)
except Exception as e:
logger.error(f"任务提交失败: {str(e)}")
return JsonResponse({'error': f'任务提交失败: {str(e)}'}, status=500)
-
功能:接收文本提示词和两个图片 URL(首尾帧),提交首尾帧生成视频的异步任务,返回任务 ID 和状态。
-
验证
prompt
、image_url
(必须是包含 2 个 URL 的列表)是否符合要求。 -
调用 Celery 任务
generate_video
,生成模式为frames
。 -
记录日志并返回任务 ID 和状态。
-
-
技术点:
-
同前两个生成接口的装饰器和请求处理方式。
-
参数类型验证:检查
image_url
是否为列表且长度为 2。 -
Celery 异步任务:支持多图片输入的视频生成。
-
5. get_task_status
def get_task_status(request, task_id):
try:
task = AsyncResult(task_id)
logger.info(f"检查任务 {task_id} 的状态: 状态={task.state}, 结果={task.result}")
if task.state in ['PENDING', 'PROCESSING', 'WAITING', 'SUCCESS']:
return JsonResponse({'status': task.state, 'result': task.result, 'error': None})
elif task.state == 'FAILURE':
return JsonResponse({'status': task.state, 'result': None, 'error': str(task.result)})
else:
logger.warning(f"任务 {task_id} 的状态未知: {task.state}")
return JsonResponse({'status': task.state, 'result': None, 'error': '未知任务状态'})
except Exception as e:
logger.error(f"任务状态检查失败,任务 {task_id}: {str(e)}")
return JsonResponse({'error': f'任务状态检查失败: {str(e)}'}, status=500)
-
功能:确认待处理的视频生成任务,重新提交带确认状态的异步任务。
-
验证请求中是否包含
task_id
,通过AsyncResult
获取原任务状态。 -
检查原任务是否处于
WAITING
状态,否则返回错误。 -
从原任务结果中提取参数,调用
generate_video
并标记confirmed=True
,返回新任务 ID。
-
-
技术点:
-
Celery 任务状态查询:
AsyncResult(task_id)
获取任务状态和结果。 -
状态校验:确保原任务处于可确认状态。
-
异步任务二次提交:基于原任务参数生成新的确认任务。
-
6. proxy_video
def proxy_video(request):
if request.method == 'GET':
video_url = request.GET.get('url')
is_download = request.GET.get('download', 'false').lower() == 'true'
if not video_url:
logger.error(f"用户 {request.user.id} 请求代理视频失败: 缺少视频 URL")
return JsonResponse({'error': '视频 URL 为必填项'}, status=400)
# 验证 URL 格式
if not re.match(r'^https?://', video_url):
logger.error(f"用户 {request.user.id} 请求代理视频失败: 无效的视频 URL {video_url}")
return JsonResponse({'error': '无效的视频 URL'}, status=400)
try:
# 查询 VideoHistory 获取视频元数据(用于动态文件名)
video_history = VideoHistory.objects.filter(user=request.user, video_url=video_url).first()
filename = 'generated_video.mp4'
if video_history:
# 使用 prompt 和时间戳生成文件名
prompt_snippet = video_history.prompt[:30].replace(' ', '_') if video_history.prompt else 'video'
timestamp = video_history.created_at.strftime('%Y%m%d_%H%M%S')
filename = f"{prompt_snippet}_{timestamp}.mp4"
# 转发 Range 头(用于播放时的流式传输)
headers = {}
if 'Range' in request.headers and not is_download:
headers['Range'] = request.headers['Range']
response = requests.get(video_url, stream=True, headers=headers, timeout=10)
response.raise_for_status()
content_type = response.headers.get('Content-Type', 'video/mp4')
headers = {
'Content-Type': content_type,
}
# 如果是下载请求,添加 Content-Disposition 头
if is_download:
headers['Content-Disposition'] = f'attachment; filename="{quote(filename)}"'
# 处理范围请求(用于播放)
if response.status_code == 206 and not is_download:
headers['Content-Range'] = response.headers.get('Content-Range')
headers['Accept-Ranges'] = 'bytes'
-
功能:代理视频文件的流式传输或下载,支持断点续传。
-
接收视频 URL 和下载标识(
download
),验证 URL 合法性。 -
从
VideoHistory
模型查询视频元数据,生成动态文件名。 -
转发 HTTP 请求头(如
Range
用于断点续传),流式返回视频内容。 -
支持播放(流式传输)和下载(添加
Content-Disposition
头)。
-
-
技术点:
-
流式响应:
StreamingHttpResponse
实现大文件分块传输。 -
HTTP 头处理:转发
Range
头支持断点续传,设置Content-Disposition
控制下载。 -
第三方请求:
requests.get(stream=True)
流式获取远程视频。 -
数据库查询:
VideoHistory.objects.filter
获取视频关联的用户数据。 -
URL 验证:正则表达式
re.match
检查 URL 格式(http://
或https://
)。
-
7. video_history
def video_history(request):
try:
histories = VideoHistory.objects.filter(user=request.user)
serializer = VideoHistorySerializer(histories, many=True)
return JsonResponse({'code': 200, 'data': serializer.data})
except Exception as e:
logger.error(f"获取视频历史记录失败: {str(e)}")
return JsonResponse({'error': f'获取视频历史记录失败: {str(e)}'}, status=500)
-
功能:获取当前登录用户的视频生成历史记录。
-
查询
VideoHistory
模型中当前用户的所有记录。 -
使用
VideoHistorySerializer
序列化数据并返回。
-
-
技术点:
-
数据库查询:
filter(user=request.user)
筛选当前用户数据。 -
序列化:
VideoHistorySerializer
将模型实例转换为 JSON 格式。 -
权限控制:
@permission_classes([IsAuthenticated])
确保仅登录用户可访问。
-
5.2通用技术点
-
权限控制:通过
IsAuthenticated
限制接口仅登录用户可访问。 -
日志系统:
logging.getLogger
记录接口调用、错误等信息。 -
错误处理:捕获 JSON 解析错误、数据库异常、网络请求异常等,返回结构化错误响应。
-
异步任务:基于 Celery 实现视频生成任务的异步处理,避免阻塞主线程。
-
HTTP 响应:使用
JsonResponse
返回 JSON 数据,StreamingHttpResponse
处理流式内容。
6、前端实现
前端使用Vue3实现,实现界面美观及稳定
实现的关键点:
①使用轮询解决超时问题
②使用scss实现界面样式美观
③Element_plus实现界面的稳定性
<script setup lang="ts">
import { ref } from 'vue';
import axios from 'axios';
import { ElTabs, ElTabPane, ElInput, ElButton, ElUpload, ElIcon, ElMessage } from 'element-plus';
import { Plus, Download } from '@element-plus/icons-vue';
// 配置axios认证头
const token = localStorage.getItem('token');
if (token) {
axios.defaults.headers.common['Authorization'] = `Bearer ${token}`;
}
// 生成模式
const mode = ref('text'); // text, image, frames, config
// 表单数据
const formData = ref({
content: '' // 提示词
});
// 视频配置数据
const videoConfig = ref({
frameRate: 30, // 帧率
quality: 'speed' // 质量
});
// 图片相关
const imageUrl = ref('');
const firstFrameBase64 = ref('');
const lastFrameBase64 = ref('');
// 生成相关
const videoUrl = ref('');
const loading = ref(false);
const polling = ref(false);
const waiting = ref(false);
const error = ref('');
const attempts = ref(0);
const maxAttempts = 120;
const taskId = ref('');
// 处理图片上传
const handleImageUpload = (file: File | undefined, type: 'image' | 'first' | 'last') => {
if (!file) return false;
const reader = new FileReader();
reader.onload = (e) => {
const base64 = e.target?.result as string;
if (type === 'image') {
imageUrl.value = base64;
} else if (type === 'first') {
firstFrameBase64.value = base64;
} else if (type === 'last') {
lastFrameBase64.value = base64;
}
};
reader.readAsDataURL(file);
return false;
};
// 移除图片
const removeImage = (type: 'image' | 'first' | 'last') => {
if (type === 'image') {
imageUrl.value = '';
} else if (type === 'first') {
firstFrameBase64.value = '';
} else if (type === 'last') {
lastFrameBase64.value = '';
}
};
// 生成视频
const generate = async () => {
if (!token) {
error.value = '请先登录';
ElMessage.error(error.value);
return;
}
if (!formData.value.content) {
error.value = '提示词不能为空';
ElMessage.error(error.value);
return;
}
loading.value = true;
error.value = '';
videoUrl.value = '';
waiting.value = false;
polling.value = false;
attempts.value = 0;
taskId.value = '';
let endpoint = 'start-video-generation/';
let payload: any = {
prompt: formData.value.content,
quality: videoConfig.value.quality,
fps: videoConfig.value.frameRate
};
// 图生视频模式
if (mode.value === 'image') {
if (!imageUrl.value) {
error.value = '图片不能为空';
ElMessage.error(error.value);
loading.value = false;
return;
}
endpoint = 'start-image-video-generation/';
payload = {
prompt: formData.value.content,
image_url: imageUrl.value,
quality: videoConfig.value.quality,
fps: videoConfig.value.frameRate
};
}
// 首尾帧生视频模式
else if (mode.value === 'frames') {
if (!firstFrameBase64.value || !lastFrameBase64.value) {
error.value = '首帧和尾帧不能为空';
ElMessage.error(error.value);
loading.value = false;
return;
}
endpoint = 'start-frames-video-generation/';
payload = {
prompt: formData.value.content,
image_url: [firstFrameBase64.value, lastFrameBase64.value],
quality: videoConfig.value.quality,
fps: videoConfig.value.frameRate
};
}
try {
const submitRes = await axios.post(`http://127.0.0.1:8000/api/videotest/${endpoint}`, payload, { timeout: 60000 });
console.log('start response:', submitRes.data);
taskId.value = submitRes.data.task_id;
if (!taskId.value) {
error.value = submitRes.data.error || '任务提交失败:无任务 ID';
ElMessage.error(error.value);
return;
}
if (submitRes.data.status === 'WAITING') {
waiting.value = true;
} else {
error.value = `任务状态异常: ${submitRes.data.status}`;
ElMessage.error(error.value);
console.warn('Unexpected status, attempting to poll:', submitRes.data.status);
polling.value = true;
pollForResult(taskId.value);
}
} catch (err: any) {
error.value = `任务提交失败: ${err.response?.data?.error || err.message || '未知错误'}`;
ElMessage.error(error.value);
console.error('start error:', err, 'Response data:', err.response?.data);
} finally {
loading.value = false;
}
};
// 确认生成
const confirm = async () => {
if (!taskId.value) {
error.value = '无有效任务 ID';
ElMessage.error(error.value);
console.error('No valid taskId for confirm');
return;
}
loading.value = true;
error.value = '';
try {
const confirmRes = await axios.post('http://127.0.0.1:8000/api/videotest/confirm-video-generation/', {
task_id: taskId.value,
}, { timeout: 60000 });
console.log('confirm-video-generation response:', confirmRes.data);
taskId.value = confirmRes.data.task_id;
if (!taskId.value || confirmRes.data.status !== 'PROCESSING') {
error.value = confirmRes.data.error || '任务确认失败';
ElMessage.error(error.value);
console.error('Confirm failed:', confirmRes.data);
return;
}
polling.value = true;
waiting.value = false;
pollForResult(taskId.value);
} catch (err: any) {
error.value = `任务确认失败: ${err.response?.data?.error || err.message || '未知错误'}`;
ElMessage.error(error.value);
console.error('confirm-video-generation error:', err, 'Response data:', err.response?.data);
} finally {
loading.value = false;
}
};
// 新增: 加载视频 Blob 的辅助函数(修复播放问题)
const loadVideoBlob = async (proxyUrl: string) => {
try {
const response = await fetch(proxyUrl, {
headers: {
Authorization: `Bearer ${token}` // 添加认证头
}
});
if (!response.ok) {
throw new Error(`获取视频失败: ${response.statusText}`);
}
const blob = await response.blob();
videoUrl.value = URL.createObjectURL(blob); // 转换为 Blob URL
ElMessage.success('视频加载成功');
} catch (err: any) {
error.value = `加载视频失败: ${err.message}`;
ElMessage.error(error.value);
console.error('加载视频错误:', err);
}
};
// 轮询任务状态(修改成功分支,使用 Blob URL 播放)
const pollForResult = async (taskId: string) => {
attempts.value = 0;
const baseDelay = 10000;
const maxDelay = 30000;
const poll = async () => {
try {
const res = await axios.get(`http://127.0.0.1:8000/api/videotest/get-task-status/${taskId}/`, {
timeout: 20000,
});
console.log('get-task-status response:', res.data);
const { status, result, error: taskError } = res.data;
if (status === 'SUCCESS' && result && result.url) {
const proxyUrl = `http://127.0.0.1:8000/api/videotest/proxy-video/?url=${encodeURIComponent(result.url)}`;
await loadVideoBlob(proxyUrl); // 使用 Blob 加载视频
polling.value = false;
ElMessage.success('视频生成成功!');
} else if (status === 'FAILURE') {
error.value = taskError || '视频生成失败';
ElMessage.error(error.value);
polling.value = false;
} else if (status === 'PENDING' || status === 'PROCESSING') {
if (attempts.value < maxAttempts) {
const delay = Math.min(baseDelay * Math.pow(2, attempts.value / 2), maxDelay);
attempts.value++;
setTimeout(poll, delay);
} else {
error.value = '任务超时,请检查后端任务状态';
ElMessage.error(error.value);
polling.value = false;
}
} else if (status === 'WAITING') {
error.value = '任务仍未确认,请点击确认生成';
ElMessage.error(error.value);
polling.value = false;
waiting.value = true;
} else {
error.value = `未知任务状态: ${status}`;
ElMessage.error(error.value);
polling.value = false;
}
} catch (err: any) {
console.error('get-task-status error:', err, 'Response data:', err.response?.data);
if (err.code === 'ECONNABORTED' || err.response?.status === 504) {
if (attempts.value < maxAttempts) {
const delay = Math.min(baseDelay * Math.pow(2, attempts.value / 2), maxDelay);
attempts.value++;
setTimeout(poll, delay);
} else {
error.value = '任务超时,请检查后端任务状态';
ElMessage.error(error.value);
polling.value = false;
}
} else {
error.value = `查询结果失败: ${err.response?.data?.error || err.message || '未知错误'}`;
ElMessage.error(error.value);
polling.value = false;
}
}
};
poll();
};
// 处理视频播放错误
const handleVideoError = (event: Event) => {
console.error('Video playback error:', event);
error.value = '视频播放失败,请检查链接或网络';
ElMessage.error(error.value);
};
// 重试功能
const retry = () => {
error.value = '';
attempts.value = 0;
videoUrl.value = '';
waiting.value = false;
polling.value = false;
taskId.value = '';
generate();
};
const downloading = ref(false);
// 下载视频(假按钮)
const downloadVideo = async (url: string) => {
if (downloading.value) return;
downloading.value = true;
try {
ElMessage.info('正在准备下载,请稍候...');
const downloadUrl = `${url}${url.includes('?') ? '&' : '?'}download=true`;
const response = await fetch(downloadUrl, {
headers: {
Authorization: `Bearer ${token}`
}
});
if (!response.ok) {
throw new Error(`下载失败: ${response.statusText}`);
}
const blob = await response.blob();
const downloadUrlObj = window.URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = downloadUrlObj;
link.download = 'generated_video.mp4';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
window.URL.revokeObjectURL(downloadUrlObj);
ElMessage.success('视频下载已开始!');
} catch (err: any) {
error.value = `下载失败: ${err.message || '未知错误'}`;
ElMessage.error(error.value);
console.error('Download error:', err);
} finally {
downloading.value = false;
}
};
</script>
一、整体功能实现
该代码实现了一个 AI 视频生成平台的前端页面,核心功能是允许用户通过不同模式(文生视频、图生视频、首尾帧生视频)生成视频,并支持视频预览和下载。整个平台整体流程包括:用户输入配置 → 提交生成任务 → 实时监控任务进度 → 预览生成结果 → 下载视频文件。
二、关键功能模块
-
用户认证与请求配置
- 从 localStorage 获取 token 并配置 axios 请求头,实现身份验证
- 所有 API 请求自动携带 Authorization 令牌,确保接口安全访问
-
多模式视频生成
- 文生视频:通过文本提示词生成视频
- 图生视频:基于单张图片和提示词生成视频
- 首尾帧生视频:根据首帧和尾帧图片及提示词生成过渡视频
- 视频配置:可设置帧率(30fps/60fps)和质量模式(速度优先 / 质量优先)
-
任务管理流程
- 任务提交:根据不同模式向后端发送相应参数
- 任务确认:支持待处理任务的确认机制
- 进度监控:通过轮询机制实时获取任务状态
- 结果处理:视频生成成功后加载并展示视频
-
媒体处理功能
- 图片上传:支持首帧、尾帧等图片上传并预览
- 视频预览:使用 HTML5 video 标签实现视频播放
- 视频下载:通过 Blob 对象和 URL.createObjectURL 实现视频下载
-
用户交互反馈
- 加载状态显示:任务提交和处理过程中的动画提示
- 错误处理:各类操作错误的提示和重试机制
- 状态指示:清晰展示视频生成各阶段状态
三、关键技术点解析
-
Vue 3 + TypeScript 组合式 API
- 使用
<script setup lang="ts">
实现组件逻辑,提升类型安全性 - 通过
ref
创建响应式数据,管理表单状态、媒体资源和任务信息
- 使用
-
Axios 网络请求
- 配置全局请求头实现身份验证
- 处理不同类型的 HTTP 请求(POST 提交任务、GET 查询状态)
- 设置超时处理和错误捕获机制
-
文件处理技术
- FileReader API:将上传的图片转换为 Base64 格式预览
- Blob 与 Object URL:处理视频流,实现前端视频预览和下载
- 断点续传支持:通过 Range 请求头实现大视频文件的断点续传
-
任务轮询机制
- 指数退避策略:随着尝试次数增加,逐步延长轮询间隔(10s 到 30s)
- 最大尝试限制:最多 120 次尝试,防止无限轮询
- 状态分支处理:根据不同任务状态(SUCCESS/FAILURE/PENDING 等)执行相应逻辑
-
Element Plus 组件集成
- 表单组件:ElInput、ElSelect 处理用户输入
- 上传组件:ElUpload 实现图片上传功能
- 导航组件:ElTabs 实现不同生成模式的切换
- 反馈组件:ElMessage 提供操作结果提示
-
动画与交互效果
- CSS 动画:实现标题浮动、加载动画、状态指示等视觉效果
- 过渡效果:按钮悬停、点击反馈等微交互
- 响应式设计:适配不同屏幕尺寸的布局调整
-
错误处理机制
- 输入验证:检查必填项和格式合法性
- 网络错误处理:捕获请求失败、超时等异常
- 播放错误处理:视频加载和播放失败的提示
-
安全措施
- 权限控制:未登录用户无法提交生成任务
- URL 验证:检查图片和视频 URL 的合法性
- 认证保护:所有敏感操作都需要有效的 token
该代码通过组合现代前端技术,实现了一个功能完整、用户体验良好的 AI 视频生成平台界面,同时兼顾了代码的可维护性和扩展性。
7、项目总结
“言映 AI 视频生成” V1.0 项目已圆满完成需求文档既定目标,实现从文本到视频的全流程自动化,技术架构稳定、功能覆盖全面、用户体验良好,为不同场景用户提供了低门槛、高效率的视频生成解决方案。后续将基于现存不足与用户反馈持续迭代,进一步提升功能完整性、审核精度与用户体验,推动产品向更成熟、更贴合市场需求的方向发展。
更多推荐
所有评论(0)