Node.js全栈项目集成Wan2.1-UMT5:实时视频生成进度推送
Node.js全栈项目集成Wan2.1-UMT5实时视频生成进度推送最近在做一个挺有意思的项目需要把Wan2.1-UMT5这个视频生成模型集成到我们自己的系统里。用户上传一段文字描述系统就能生成一段短视频。听起来挺酷对吧但问题来了视频生成是个挺耗时的活儿用户提交任务后总不能让他干等着看着一个空白的页面发呆。想象一下你点了杯咖啡店员告诉你“等着吧好了叫你”然后你就只能傻站着。但如果店员告诉你“正在磨豆子…正在萃取…正在打奶泡…”你是不是感觉好多了我们做的就是这个——给用户一个实时的进度条让他知道后台到底在忙活啥。这篇文章我就来聊聊怎么用Node.js搭一个前后端分离的应用把Wan2.1-UMT5接进来并且用WebSocket实现那个“正在磨豆子”的实时进度推送。整个过程会涉及到Node.js环境搭建、Express后端、Vue前端以及最核心的WebSocket通信。我会尽量用大白话讲清楚保证你看完就能动手试试。1. 项目目标与核心价值这个项目想解决的核心问题就一个消除用户等待的焦虑感。视频生成尤其是质量高一点的动辄需要几十秒甚至几分钟。在这段时间里如果前端页面没有任何反馈用户很容易以为程序卡死了、任务失败了甚至可能直接关掉页面。这不仅体验差还可能造成服务器资源的浪费因为后台任务还在跑。我们的解决方案是引入实时进度推送。具体来说当用户在后端提交一个视频生成任务后后端会启动Wan2.1-UMT5模型进行逐帧生成。每生成完一帧或者完成一个关键步骤如下载模型、编码、渲染等后端就通过WebSocket向前端发送一条消息。前端Vue页面接收到消息后实时更新进度条、百分比或者文字提示例如“正在初始化模型…”、“正在生成第15帧/共60帧…”。这样一来用户就能清晰地看到任务正在稳步推进心里有底体验自然就好了很多。这对于需要处理长耗时任务的AI应用来说是一个提升用户满意度的关键设计。2. 技术栈与环境准备工欲善其事必先利其器。我们先来看看需要准备哪些东西。2.1 核心技术组件后端 (Backend):Node.js: 我们的JavaScript运行环境也是整个后端服务的基础。建议使用最新的LTS版本稳定性有保障。Express: 一个极简的Node.js Web框架用来快速搭建RESTful API接口处理用户的任务提交、查询等HTTP请求。WebSocket (ws库): 为了实现全双工、低延迟的实时通信我们选择WebSocket协议。Node.js端我们使用ws这个非常流行的库来创建WebSocket服务器。Wan2.1-UMT5: 这是我们的“大厨”负责根据文字描述烹饪出视频。我们需要将其Python脚本或API集成到Node.js环境中通常可以通过Child Process子进程或者HTTP调用如果模型单独部署的方式。前端 (Frontend):Vue 3: 我们选择Vue来构建用户界面因为它简单、灵活生态丰富。我们将用Vue来创建任务提交表单、展示进度条和最终生成的视频。WebSocket API (原生或库): 浏览器原生支持WebSocket客户端API我们直接使用它来连接后端的WebSocket服务接收实时进度消息。UI库 (可选): 为了快速搭建美观的界面你可以选择像Element Plus、Ant Design Vue这样的UI组件库里面自带了进度条、按钮等组件。通信桥梁:WebSocket: 它是本项目实时功能的灵魂。不同于HTTP的“一问一答”WebSocket建立连接后服务器可以随时主动给客户端推送消息完美契合进度推送的需求。2.2 开发环境搭建首先确保你的电脑上已经安装了Node.js和npmNode.js的包管理器。打开终端或命令提示符输入以下命令检查node --version npm --version如果能看到版本号说明已经安装。如果没有你需要去Node.js官网下载并安装最新的LTS版本。安装过程很简单基本上就是一路“下一步”。安装好Node.js后我们可以开始创建项目了。为了清晰我建议将前端和后端的代码放在两个独立的文件夹里比如video-gen-backend和video-gen-frontend。后端项目初始化# 创建一个后端项目文件夹并进入 mkdir video-gen-backend cd video-gen-backend # 初始化一个新的Node.js项目生成package.json文件 npm init -y # 安装我们需要的依赖包 npm install express ws cors # express: web框架 # ws: WebSocket服务器库 # cors: 处理跨域请求因为前端和后端可能运行在不同端口前端项目初始化我们使用Vue官方脚手架Vite来快速创建项目它比传统的Vue CLI更轻更快。# 回到上级目录创建前端项目 cd .. npm create vuelatest video-gen-frontend # 按照提示操作通常只需要选择默认选项即可。 # 创建完成后进入项目并安装依赖 cd video-gen-frontend npm install # 如果需要UI库例如安装Element Plus npm install element-plus环境准备好之后我们的项目骨架就有了。接下来我们开始搭建后端的“厨房”。3. 后端搭建Express与WebSocket服务后端要干两件主要的事一是提供HTTP API接口让前端提交任务二是运行一个WebSocket服务器用来推送进度。3.1 创建基础的Express服务器在后端项目文件夹 (video-gen-backend) 里创建一个server.js文件。// server.js const express require(express); const http require(http); const WebSocket require(ws); const cors require(cors); const app express(); const port 3000; // 后端服务端口 // 使用CORS中间件允许前端跨域访问 app.use(cors()); // 解析JSON格式的请求体 app.use(express.json()); // 创建一个简单的HTTP接口用于健康检查或提交任务示例 app.get(/, (req, res) { res.send(视频生成后端服务正在运行); }); // 假设的任务提交接口后续会完善 app.post(/api/generate, (req, res) { const { prompt } req.body; // 从请求体中获取用户输入的文字描述 if (!prompt) { return res.status(400).json({ error: 请输入视频描述 }); } // 这里先返回一个模拟的响应 res.json({ message: 任务已接收, taskId: task_${Date.now()} }); }); // 创建HTTP服务器并将Express app作为请求处理器 const server http.createServer(app); // 创建WebSocket服务器将其绑定到同一个HTTP服务器上 const wss new WebSocket.Server({ server }); // 存储所有连接的WebSocket客户端简单示例生产环境需要更复杂的管理 const clients new Set(); wss.on(connection, (ws) { console.log(新的WebSocket客户端已连接); clients.add(ws); // 当客户端断开连接时从集合中移除 ws.on(close, () { console.log(WebSocket客户端已断开连接); clients.delete(ws); }); // 可以在这里处理客户端发来的消息如果需要双向通信 ws.on(message, (message) { console.log(收到客户端消息:, message.toString()); }); }); // 一个模拟的进度推送函数后续会替换为真实的Wan2.1-UMT5调用 function broadcastProgress(taskId, progress, message) { const progressData { taskId, progress, // 进度百分比0-100 message // 进度描述如“正在生成第X帧” }; const dataStr JSON.stringify(progressData); clients.forEach(client { if (client.readyState WebSocket.OPEN) { client.send(dataStr); } }); } // 启动服务器 server.listen(port, () { console.log(后端服务已启动运行在 http://localhost:${port}); console.log(WebSocket服务已启动运行在 ws://localhost:${port}); });现在运行node server.js你的后端服务就启动了。它既可以通过http://localhost:3000访问HTTP接口也支持WebSocket连接。3.2 集成Wan2.1-UMT5与模拟进度真实集成Wan2.1-UMT5需要根据其具体的部署方式本地Python脚本、Docker容器、HTTP服务等来调用。这里为了演示进度推送的核心逻辑我们用一个模拟函数来替代。我们修改/api/generate接口让它启动一个模拟的“视频生成”长任务并在这个过程中通过broadcastProgress函数向所有连接的WebSocket客户端推送进度。// 在server.js中修改 /api/generate 接口 app.post(/api/generate, async (req, res) { const { prompt } req.body; if (!prompt) { return res.status(400).json({ error: 请输入视频描述 }); } const taskId task_${Date.now()}; // 立即响应告诉前端任务已开始并返回任务ID res.json({ message: 视频生成任务已开始, taskId }); // 在后台异步执行耗时的生成任务不阻塞HTTP响应 simulateVideoGeneration(taskId, prompt); }); // 模拟视频生成过程的函数 async function simulateVideoGeneration(taskId, prompt) { console.log(开始处理任务 ${taskId}: ${prompt}); const totalFrames 60; // 假设总共生成60帧 const steps [ { progress: 5, message: 正在初始化模型和加载参数... }, { progress: 10, message: 正在解析文本描述... }, // ... 其他准备步骤 ]; // 模拟准备阶段 for (const step of steps) { await delay(500); // 模拟耗时 broadcastProgress(taskId, step.progress, step.message); } // 模拟逐帧生成阶段 for (let frame 1; frame totalFrames; frame) { await delay(100); // 模拟每帧生成耗时 const progress 10 (frame / totalFrames) * 80; // 从10%到90% broadcastProgress(taskId, Math.floor(progress), 正在生成第 ${frame} / ${totalFrames} 帧...); } // 模拟后期处理阶段 await delay(800); broadcastProgress(taskId, 95, 视频帧合成与编码中...); await delay(500); broadcastProgress(taskId, 100, 视频生成完成); console.log(任务 ${taskId} 处理完毕); } // 一个简单的延迟函数 function delay(ms) { return new Promise(resolve setTimeout(resolve, ms)); }关键点在于HTTP接口 (/api/generate)立即返回响应而不是等待任务完成。真正的生成任务在后台异步执行。这样前端就不会因为等待而超时。任务执行过程中通过WebSocket将进度“推”给前端。后端“厨房”准备好了现在我们来打造前端的“取餐窗口”。4. 前端实现Vue与实时进度展示前端的工作是提供一个界面让用户输入描述提交任务并最直观地展示从后端推送过来的实时进度。4.1 创建任务提交与展示组件我们创建一个简单的Vue组件VideoGenerator.vue。!-- video-gen-frontend/src/components/VideoGenerator.vue -- template div classvideo-generator h2Wan2.1-UMT5 视频生成体验/h2 div classinput-section el-input v-modelprompt typetextarea :rows4 placeholder请输入你想要生成的视频描述例如一只小猫在草地上追逐蝴蝶阳光明媚风格卡通 clearable / el-button typeprimary clickhandleSubmit :loadingisSubmitting :disabled!prompt.trim() {{ isSubmitting ? 生成中... : 开始生成视频 }} /el-button /div !-- 任务状态与进度展示区域 -- div classtask-status v-ifcurrentTaskId h3任务状态: {{ currentTaskId }}/h3 div classprogress-info pstrong进度描述:/strong {{ progressMessage || 等待开始... }}/p el-progress :percentageprogressPercentage :statusprogressStatus :stroke-width16 :text-insidetrue / p classprogress-text{{ progressPercentage }}%/p /div !-- 视频展示区域生成完成后显示 -- div classvideo-result v-ifvideoUrl h4生成结果/h4 video :srcvideoUrl controls width600/video p el-button typesuccess clickdownloadVideo下载视频/el-button /p /div /div p classtip提示视频生成需要一些时间请耐心等待。下方会实时显示进度。/p /div /template script setup import { ref, onMounted, onUnmounted } from vue; import { ElMessage } from element-plus; // 响应式数据 const prompt ref(); // 用户输入的描述 const isSubmitting ref(false); // 提交按钮加载状态 const currentTaskId ref(); // 当前任务ID const progressPercentage ref(0); // 进度百分比 const progressMessage ref(); // 进度描述文字 const videoUrl ref(); // 生成完成的视频URL const ws ref(null); // WebSocket连接实例 // 计算进度条状态用于改变颜色 const progressStatus computed(() { if (progressPercentage.value 100) return success; if (progressPercentage.value 0) return ; return exception; }); // 提交生成任务 const handleSubmit async () { if (!prompt.value.trim()) { ElMessage.warning(请输入视频描述); return; } isSubmitting.value true; progressPercentage.value 0; progressMessage.value 正在提交任务...; videoUrl.value ; try { const response await fetch(http://localhost:3000/api/generate, { method: POST, headers: { Content-Type: application/json }, body: JSON.stringify({ prompt: prompt.value }) }); const data await response.json(); if (response.ok) { currentTaskId.value data.taskId; ElMessage.success(任务已提交ID: ${data.taskId}); // 进度将由WebSocket推送更新 } else { ElMessage.error(data.error || 任务提交失败); resetTaskState(); } } catch (error) { console.error(提交任务出错:, error); ElMessage.error(网络错误请检查后端服务); resetTaskState(); } finally { isSubmitting.value false; } }; // 初始化WebSocket连接 const initWebSocket () { // 确保只建立一个连接 if (ws.value ws.value.readyState WebSocket.OPEN) { return; } const socketUrl ws://localhost:3000; // 与后端server.js中定义的端口一致 ws.value new WebSocket(socketUrl); ws.value.onopen () { console.log(WebSocket连接已建立); }; ws.value.onmessage (event) { try { const data JSON.parse(event.data); // 假设后端推送的数据格式为 { taskId, progress, message } // 这里简单处理只更新与当前任务ID匹配的进度 // 实际项目中可能需要更复杂的任务状态管理 if (!currentTaskId.value || data.taskId currentTaskId.value) { progressPercentage.value data.progress; progressMessage.value data.message; // 如果进度达到100%可以模拟获取视频结果 if (data.progress 100) { // 这里假设视频生成完成后可以通过另一个API获取视频文件 // 例如fetch(/api/video/${currentTaskId.value}).then(...) // 为了演示我们用一个假的URL setTimeout(() { videoUrl.value https://example.com/demo-video.mp4; // 替换为真实URL ElMessage.success(视频生成完成); }, 1000); } } } catch (e) { console.error(解析WebSocket消息失败:, e); } }; ws.value.onerror (error) { console.error(WebSocket连接错误:, error); ElMessage.error(实时连接异常进度可能无法更新); }; ws.value.onclose () { console.log(WebSocket连接已关闭); }; }; // 重置任务状态 const resetTaskState () { progressPercentage.value 0; progressMessage.value ; // 注意不重置currentTaskId以便WebSocket能继续匹配消息 }; // 模拟下载视频 const downloadVideo () { if (videoUrl.value) { const link document.createElement(a); link.href videoUrl.value; link.download generated_video_${currentTaskId.value}.mp4; document.body.appendChild(link); link.click(); document.body.removeChild(link); } }; // 组件挂载时建立WebSocket连接 onMounted(() { initWebSocket(); }); // 组件卸载时关闭WebSocket连接 onUnmounted(() { if (ws.value) { ws.value.close(); } }); /script style scoped .video-generator { max-width: 800px; margin: 0 auto; padding: 20px; } .input-section { margin-bottom: 30px; } .input-section .el-button { margin-top: 15px; display: block; } .task-status { margin-top: 30px; padding: 20px; border: 1px solid #e4e7ed; border-radius: 8px; background-color: #fafafa; } .progress-info { margin: 20px 0; } .progress-text { text-align: center; margin-top: 10px; font-size: 18px; font-weight: bold; } .video-result { margin-top: 30px; text-align: center; } .tip { margin-top: 20px; color: #909399; font-size: 14px; } /style这个组件做了以下几件事提供了一个文本输入框和提交按钮。提交任务到后端API (/api/generate)。在页面加载时建立WebSocket连接监听后端推送的进度消息。实时更新进度条和进度描述文字。当进度达到100%时展示一个模拟的视频播放器。4.2 运行前端项目在video-gen-frontend目录下运行npm run devVite会启动一个开发服务器通常运行在http://localhost:5173。打开浏览器访问这个地址你应该能看到我们的视频生成界面了。确保后端服务 (node server.js) 也在运行然后在前端输入描述并点击提交。你会看到进度条开始动起来并且文字提示会不断变化就像后台真的在生成视频一样。5. 核心机制WebSocket实时通信详解现在让我们深入看看让这一切“动起来”的核心——WebSocket通信流程。连接建立前端Vue组件在onMounted生命周期中使用new WebSocket(ws://localhost:3000)与后端建立WebSocket连接。这个连接是持久化的。任务触发用户点击提交按钮前端通过普通的HTTP POST请求将任务描述发送到后端的/api/generate接口。异步处理与推送后端Express接口立即返回一个响应包含taskId然后在后台异步启动模拟的视频生成函数simulateVideoGeneration。这个函数在执行过程中的各个节点如初始化、生成第X帧、合成完成都会调用broadcastProgress函数。广播进度broadcastProgress函数将进度信息taskId,progress,message构造成JSON字符串然后遍历所有已连接的WebSocket客户端 (clients)通过client.send()方法将消息推送给每一个前端。前端响应更新前端的WebSocket对象通过onmessage事件监听器接收到消息。解析出JSON数据后Vue的响应式系统会立刻更新progressPercentage和progressMessage这两个变量的值。由于它们被用在了模板中进度条和文本显示界面就会自动、实时地更新。整个流程形成了一个高效的“推送”模型而不是前端不断地“轮询”询问后端“好了没”。这大大减少了不必要的网络请求降低了服务器压力并且实现了真正的实时反馈。6. 总结与展望走完这一趟你会发现在一个Node.js全栈应用里实现实时进度推送并没有想象中那么复杂。核心就是利用WebSocket这座桥把后端长任务执行的“心跳”一声声地传向前端。我们这套方案的优势很明显用户体验大幅提升。用户不再面对一个“静止”的页面而是能亲眼看到自己的工作正在被处理每一步都清晰可见。这对于AI生成这类耗时操作来说几乎是必备的功能。当然我们演示的是一个简化版本。在实际项目中你可能还需要考虑更多任务队列与管理当多个用户同时提交任务时需要引入任务队列如Bull、Agenda来管理避免服务器过载。WebSocket连接管理我们的例子简单地将所有客户端存在一个Set里。真实场景需要将连接与用户或会话关联确保进度只推送给提交任务的那个浏览器标签页。错误处理与重连网络可能不稳定前端需要实现WebSocket断线重连机制。安全性需要对WebSocket连接进行认证和授权防止未授权的访问。Wan2.1-UMT5的真实集成用child_process或python-shell调用Python脚本或者通过HTTP请求调用单独部署的模型API并解析其真实输出。不过无论后端的具体生成逻辑多么复杂“HTTP接口触发任务WebSocket推送进度”这个模式都是通用的。你可以把本文中的模拟生成函数替换成任何耗时的AI模型调用、文件处理、数据计算等任务。希望这个从零开始的例子能给你带来一些启发。下次当你需要让用户等待时别忘了给他们一个“进度条”。获取更多AI镜像想探索更多AI镜像和应用场景访问 CSDN星图镜像广场提供丰富的预置镜像覆盖大模型推理、图像生成、视频生成、模型微调等多个领域支持一键部署。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2464523.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!