LiuJuan20260223Zimage代码实例WebSocket长连接推送LiuJuan生成进度与结果1. 引言从静态页面到动态交互想象一下你正在使用一个AI文生图工具输入了描述词“LiuJuan”点击了生成按钮。接下来你只能盯着一个静止的页面或者一个不断旋转的加载图标心里默默猜测“图片生成到哪一步了是卡住了吗还要等多久”这种等待是令人焦虑的尤其是在处理需要一定计算时间的AI生成任务时。传统的HTTP请求-响应模式在这里显得力不从心因为它无法让服务器主动、持续地向客户端推送任务进度。本文将带你解决这个问题。我们将基于LiuJuan20260223Zimage这个文生图模型服务构建一个完整的WebSocket长连接应用。这个应用不仅能让你生成LiuJuan的图片还能实时地将生成过程中的每一步进度——从模型加载、提示词解析到图像生成、后期处理——推送到你的网页前端让你对整个生成过程了如指掌。你将学到如何将Gradio的简易界面与强大的WebSocket实时通信能力结合打造一个用户体验更佳、信息更透明的AI图像生成应用。无论你是前端开发者想了解实时通信还是AI应用开发者想提升产品体验这篇文章都能给你带来实用的代码和清晰的思路。2. 项目与环境准备在开始编写代码之前我们需要确保有一个可以工作的LiuJuan20260223Zimage模型服务作为后端。这个服务是我们整个实时生成系统的核心。2.1 确认模型服务状态假设你已经通过Xinference成功部署了LiuJuan20260223Zimage镜像。首先我们需要检查服务是否正常运行。打开终端执行以下命令查看服务日志# 查看Xinference服务日志确认模型加载成功 cat /root/workspace/xinference.log如果服务启动成功你应该能在日志中看到模型加载完毕的相关信息。通常你会看到类似“Model loaded successfully”或“Inference server is running on port...”的提示。2.2 获取模型API端点模型服务启动后会提供一个HTTP API端点供我们调用。对于Xinference部署的服务其文生图接口通常遵循标准的路径。在我们的代码中我们将假设模型服务的文生图API地址为http://localhost:9997/v1/images/generations这个地址是Xinference默认的文生图端点。如果你的服务部署在不同的主机或端口请相应修改这个地址。2.3 技术栈概览我们的实时生成系统将使用以下技术后端Python使用FastAPI构建Web服务器和WebSocket服务器同时调用Xinference的模型API。前端HTML/JS一个简单的网页通过WebSocket与后端通信实时接收生成进度。通信协议WebSocket用于实现全双工、低延迟的实时通信。现在让我们开始构建这个系统。3. 构建后端WebSocket服务后端服务是整个应用的大脑它需要做三件事提供网页、处理WebSocket连接、调用AI模型并推送进度。3.1 创建FastAPI应用与WebSocket端点首先我们创建一个FastAPI应用并设置一个WebSocket端点。# backend.py import asyncio import json import aiohttp from fastapi import FastAPI, WebSocket, WebSocketDisconnect from fastapi.responses import HTMLResponse from fastapi.staticfiles import StaticFiles import uuid from typing import Dict # 创建FastAPI应用 app FastAPI(titleLiuJuan实时文生图进度推送服务) # 存储活跃的WebSocket连接 active_connections: Dict[str, WebSocket] {} # 模型API配置 MODEL_API_URL http://localhost:9997/v1/images/generations # 模拟生成步骤在实际应用中这些步骤来自模型的实际处理阶段 GENERATION_STEPS [ 正在解析提示词..., 正在加载模型权重..., 正在初始化图像生成参数..., 正在生成潜在表示..., 正在解码图像..., 正在执行后期处理..., 生成完成 ] async def call_model_api(prompt: str, connection_id: str): 调用Xinference文生图API并模拟进度推送 try: # 第一步解析提示词 await send_progress(connection_id, GENERATION_STEPS[0], 10) await asyncio.sleep(0.5) # 第二步准备模型 await send_progress(connection_id, GENERATION_STEPS[1], 20) await asyncio.sleep(1) # 第三步设置参数 await send_progress(connection_id, GENERATION_STEPS[2], 30) # 实际调用模型API async with aiohttp.ClientSession() as session: payload { prompt: prompt, n: 1, # 生成1张图片 size: 512x512, # 图片尺寸 response_format: url # 返回图片URL } await send_progress(connection_id, GENERATION_STEPS[3], 50) await asyncio.sleep(1) async with session.post(MODEL_API_URL, jsonpayload) as response: if response.status 200: result await response.json() await send_progress(connection_id, GENERATION_STEPS[4], 70) await asyncio.sleep(0.5) await send_progress(connection_id, GENERATION_STEPS[5], 90) await asyncio.sleep(0.3) # 最后一步完成 await send_progress(connection_id, GENERATION_STEPS[6], 100) # 发送最终结果 if connection_id in active_connections: websocket active_connections[connection_id] await websocket.send_json({ type: result, data: result, progress: 100, status: completed }) else: error_msg await response.text() await send_error(connection_id, f模型API调用失败: {error_msg}) except Exception as e: await send_error(connection_id, f生成过程中发生错误: {str(e)}) async def send_progress(connection_id: str, message: str, progress: int): 向指定连接发送进度更新 if connection_id in active_connections: websocket active_connections[connection_id] try: await websocket.send_json({ type: progress, message: message, progress: progress, timestamp: asyncio.get_event_loop().time() }) except: # 连接可能已关闭清理 if connection_id in active_connections: del active_connections[connection_id] async def send_error(connection_id: str, error_message: str): 向指定连接发送错误信息 if connection_id in active_connections: websocket active_connections[connection_id] try: await websocket.send_json({ type: error, message: error_message, timestamp: asyncio.get_event_loop().time() }) except: if connection_id in active_connections: del active_connections[connection_id] app.websocket(/ws/generate) async def websocket_generate(websocket: WebSocket): WebSocket端点处理图片生成请求 await websocket.accept() connection_id str(uuid.uuid4()) active_connections[connection_id] websocket try: while True: # 等待客户端发送生成请求 data await websocket.receive_text() request_data json.loads(data) if request_data.get(action) generate: prompt request_data.get(prompt, LiuJuan) # 启动生成任务不阻塞WebSocket连接 asyncio.create_task(call_model_api(prompt, connection_id)) # 立即确认请求已接收 await websocket.send_json({ type: ack, message: 已开始生成图片请等待进度更新..., connection_id: connection_id }) except WebSocketDisconnect: # 客户端断开连接清理资源 if connection_id in active_connections: del active_connections[connection_id] print(f连接 {connection_id} 已断开) except Exception as e: print(fWebSocket错误: {str(e)}) if connection_id in active_connections: del active_connections[connection_id] # 提供前端页面 app.get(/) async def get(): with open(templates/index.html, r, encodingutf-8) as f: html_content f.read() return HTMLResponse(contenthtml_content) # 挂载静态文件目录如果有CSS/JS文件 app.mount(/static, StaticFiles(directorystatic), namestatic) if __name__ __main__: import uvicorn uvicorn.run(app, host0.0.0.0, port8000)这个后端服务做了以下几件关键事情创建了一个WebSocket端点/ws/generate用于处理实时生成请求模拟了图片生成的各个步骤并实时推送进度实际调用了Xinference的模型API来生成图片管理了多个并发的WebSocket连接3.2 安装依赖创建一个requirements.txt文件fastapi0.104.1 uvicorn[standard]0.24.0 websockets12.0 aiohttp3.9.1 python-multipart0.0.6然后安装依赖pip install -r requirements.txt4. 创建前端实时进度页面前端页面需要与WebSocket服务器建立连接发送生成请求并实时显示进度更新。4.1 创建HTML页面创建templates/index.html文件!DOCTYPE html html langzh-CN head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 titleLiuJuan实时文生图进度演示/title style * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, sans-serif; line-height: 1.6; color: #333; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); min-height: 100vh; padding: 20px; } .container { max-width: 800px; margin: 0 auto; background: white; border-radius: 20px; box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3); overflow: hidden; } .header { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 40px; text-align: center; } .header h1 { font-size: 2.5rem; margin-bottom: 10px; font-weight: 700; } .header p { font-size: 1.1rem; opacity: 0.9; max-width: 600px; margin: 0 auto; } .content { padding: 40px; } .input-section { margin-bottom: 30px; } .input-group { margin-bottom: 20px; } label { display: block; margin-bottom: 8px; font-weight: 600; color: #555; } textarea { width: 100%; padding: 15px; border: 2px solid #e0e0e0; border-radius: 10px; font-size: 16px; font-family: inherit; resize: vertical; min-height: 100px; transition: border-color 0.3s; } textarea:focus { outline: none; border-color: #667eea; } .btn { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; border: none; padding: 15px 30px; font-size: 16px; font-weight: 600; border-radius: 10px; cursor: pointer; transition: transform 0.2s, box-shadow 0.2s; display: inline-flex; align-items: center; gap: 10px; } .btn:hover { transform: translateY(-2px); box-shadow: 0 10px 20px rgba(102, 126, 234, 0.3); } .btn:disabled { opacity: 0.6; cursor: not-allowed; transform: none; box-shadow: none; } .progress-section { margin: 30px 0; display: none; } .progress-section.active { display: block; animation: fadeIn 0.5s ease; } .progress-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px; } .progress-bar { height: 20px; background: #f0f0f0; border-radius: 10px; overflow: hidden; margin-bottom: 20px; } .progress-fill { height: 100%; background: linear-gradient(90deg, #667eea 0%, #764ba2 100%); width: 0%; transition: width 0.3s ease; border-radius: 10px; } .progress-steps { margin-top: 30px; } .step { padding: 15px; margin-bottom: 10px; background: #f8f9fa; border-radius: 10px; border-left: 4px solid #e0e0e0; transition: all 0.3s; display: flex; align-items: center; gap: 15px; } .step.active { border-left-color: #667eea; background: #f0f4ff; } .step.completed { border-left-color: #10b981; background: #f0fdf4; } .step-icon { width: 24px; height: 24px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-weight: bold; color: white; flex-shrink: 0; } .step.active .step-icon { background: #667eea; } .step.completed .step-icon { background: #10b981; } .result-section { margin-top: 40px; display: none; } .result-section.active { display: block; animation: fadeIn 0.5s ease; } .image-container { text-align: center; margin: 20px 0; } .generated-image { max-width: 100%; border-radius: 10px; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1); } .status { padding: 12px 20px; border-radius: 10px; margin-bottom: 20px; font-weight: 500; display: flex; align-items: center; gap: 10px; } .status.connecting { background: #fff3cd; color: #856404; border: 1px solid #ffeaa7; } .status.connected { background: #d1ecf1; color: #0c5460; border: 1px solid #bee5eb; } .status.error { background: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; } .connection-info { font-size: 14px; color: #666; margin-top: 10px; padding: 10px; background: #f8f9fa; border-radius: 5px; } keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } .spinner { width: 20px; height: 20px; border: 3px solid rgba(255, 255, 255, 0.3); border-radius: 50%; border-top-color: white; animation: spin 1s ease-in-out infinite; } keyframes spin { to { transform: rotate(360deg); } } media (max-width: 768px) { .container { margin: 10px; border-radius: 15px; } .header, .content { padding: 20px; } .header h1 { font-size: 2rem; } } /style /head body div classcontainer div classheader h1LiuJuan实时文生图进度演示/h1 p通过WebSocket长连接实时获取图片生成进度告别盲目等待/p /div div classcontent !-- 连接状态显示 -- div classstatus connecting idconnectionStatus div classspinner/div span正在连接WebSocket服务器.../span /div !-- 输入区域 -- div classinput-section div classinput-group label forpromptInput图片描述提示词/label textarea idpromptInput placeholder请输入图片描述例如LiuJuan, 高清, 艺术风格...LiuJuan/textarea /div button classbtn idgenerateBtn onclickgenerateImage() span开始生成图片/span /button div classconnection-info idconnectionInfo 连接ID: span idconnectionId未连接/span /div /div !-- 进度显示区域 -- div classprogress-section idprogressSection div classprogress-header h3生成进度/h3 span idprogressText0%/span /div div classprogress-bar div classprogress-fill idprogressFill/div /div div classprogress-steps idprogressSteps !-- 进度步骤将通过JavaScript动态添加 -- /div /div !-- 结果展示区域 -- div classresult-section idresultSection h3生成结果/h3 div classimage-container img idgeneratedImage classgenerated-image alt生成的图片 /div div idresultInfo/div /div /div /div script // WebSocket连接和状态管理 let socket null; let connectionId null; let isGenerating false; // 预定义的生成步骤 const generationSteps [ 正在解析提示词..., 正在加载模型权重..., 正在初始化图像生成参数..., 正在生成潜在表示..., 正在解码图像..., 正在执行后期处理..., 生成完成 ]; // 初始化页面 document.addEventListener(DOMContentLoaded, function() { initializeWebSocket(); initializeProgressSteps(); }); // 初始化WebSocket连接 function initializeWebSocket() { // 获取当前页面的协议和主机 const protocol window.location.protocol https: ? wss: : ws:; const host window.location.host; const wsUrl ${protocol}//${host}/ws/generate; socket new WebSocket(wsUrl); socket.onopen function(event) { console.log(WebSocket连接已建立); updateConnectionStatus(connected, WebSocket连接成功); document.getElementById(connectionId).textContent 等待分配...; }; socket.onmessage function(event) { const data JSON.parse(event.data); handleWebSocketMessage(data); }; socket.onerror function(error) { console.error(WebSocket错误:, error); updateConnectionStatus(error, 连接发生错误); }; socket.onclose function(event) { console.log(WebSocket连接已关闭); updateConnectionStatus(connecting, 连接已断开正在重连...); // 3秒后尝试重连 setTimeout(initializeWebSocket, 3000); }; } // 初始化进度步骤显示 function initializeProgressSteps() { const stepsContainer document.getElementById(progressSteps); stepsContainer.innerHTML ; generationSteps.forEach((step, index) { const stepElement document.createElement(div); stepElement.className step; stepElement.id step-${index}; stepElement.innerHTML div classstep-icon${index 1}/div div classstep-text${step}/div ; stepsContainer.appendChild(stepElement); }); } // 处理WebSocket消息 function handleWebSocketMessage(data) { console.log(收到消息:, data); switch(data.type) { case ack: // 收到确认消息显示连接ID connectionId data.connection_id; document.getElementById(connectionId).textContent connectionId; break; case progress: // 更新进度 updateProgress(data.message, data.progress); break; case result: // 显示生成结果 showResult(data.data); break; case error: // 显示错误信息 showError(data.message); break; } } // 更新连接状态显示 function updateConnectionStatus(status, message) { const statusElement document.getElementById(connectionStatus); statusElement.className status ${status}; statusElement.innerHTML status connected ? span✅ ${message}/span : status error ? span❌ ${message}/span : div classspinner/divspan${message}/span; } // 开始生成图片 function generateImage() { if (isGenerating) { alert(当前正在生成中请稍候...); return; } if (!socket || socket.readyState ! WebSocket.OPEN) { alert(WebSocket连接未就绪请稍后再试); return; } const promptInput document.getElementById(promptInput); const prompt promptInput.value.trim(); if (!prompt) { alert(请输入图片描述); return; } // 重置状态 resetProgress(); isGenerating true; // 显示进度区域 document.getElementById(progressSection).classList.add(active); document.getElementById(resultSection).classList.remove(active); // 禁用生成按钮 const generateBtn document.getElementById(generateBtn); generateBtn.disabled true; generateBtn.innerHTML div classspinner/divspan生成中.../span; // 发送生成请求 const requestData { action: generate, prompt: prompt }; socket.send(JSON.stringify(requestData)); } // 重置进度显示 function resetProgress() { // 重置进度条 document.getElementById(progressFill).style.width 0%; document.getElementById(progressText).textContent 0%; // 重置所有步骤 generationSteps.forEach((_, index) { const stepElement document.getElementById(step-${index}); stepElement.className step; }); } // 更新进度 function updateProgress(message, progress) { // 更新进度条 const progressFill document.getElementById(progressFill); const progressText document.getElementById(progressText); progressFill.style.width ${progress}%; progressText.textContent ${progress}%; // 根据进度更新步骤状态 const stepIndex Math.floor(progress / (100 / generationSteps.length)); for (let i 0; i generationSteps.length; i) { const stepElement document.getElementById(step-${i}); if (i stepIndex) { stepElement.className step completed; } else if (i stepIndex) { stepElement.className step active; } else { stepElement.className step; } } // 更新当前步骤的文字如果有具体消息 if (message stepIndex generationSteps.length) { const currentStep document.getElementById(step-${stepIndex}); if (currentStep) { const stepText currentStep.querySelector(.step-text); if (stepText) { stepText.textContent message; } } } } // 显示生成结果 function showResult(resultData) { isGenerating false; // 启用生成按钮 const generateBtn document.getElementById(generateBtn); generateBtn.disabled false; generateBtn.innerHTML span开始生成图片/span; // 显示结果区域 document.getElementById(resultSection).classList.add(active); // 显示生成的图片 const imageElement document.getElementById(generatedImage); const resultInfo document.getElementById(resultInfo); if (resultData.data resultData.data.length 0) { const imageUrl resultData.data[0].url; imageElement.src imageUrl; imageElement.style.display block; resultInfo.innerHTML div stylemargin-top: 20px; padding: 15px; background: #f8f9fa; border-radius: 10px; h4生成信息/h4 p✅ 图片生成成功/p p 生成时间${new Date().toLocaleTimeString()}/p p 图片尺寸512x512像素/p pa href${imageUrl} target_blank stylecolor: #667eea; text-decoration: none;点击查看原图/a/p /div ; } else { imageElement.style.display none; resultInfo.innerHTML div stylemargin-top: 20px; padding: 15px; background: #f8f9fa; border-radius: 10px; color: #dc3545; h4生成信息/h4 p❌ 未收到有效的图片数据/p /div ; } } // 显示错误信息 function showError(errorMessage) { isGenerating false; // 启用生成按钮 const generateBtn document.getElementById(generateBtn); generateBtn.disabled false; generateBtn.innerHTML span开始生成图片/span; // 显示错误信息 const resultInfo document.getElementById(resultInfo); resultInfo.innerHTML div stylemargin-top: 20px; padding: 15px; background: #f8d7da; border-radius: 10px; color: #721c24; h4生成失败/h4 p❌ ${errorMessage}/p p请检查模型服务是否正常运行然后重试。/p /div ; document.getElementById(resultSection).classList.add(active); } /script /body /html4.2 前端功能详解这个前端页面实现了以下核心功能自动WebSocket连接页面加载时自动连接后端WebSocket服务器实时状态显示显示连接状态、连接ID等信息进度可视化使用进度条和步骤列表实时显示生成进度结果展示生成完成后显示图片和相关信息错误处理友好的错误提示和重连机制响应式设计适配不同屏幕尺寸5. 运行与测试完整系统现在我们已经有了完整的后端和前端代码让我们来运行并测试这个实时生成系统。5.1 启动后端服务首先确保你的LiuJuan20260223Zimage模型服务正在运行。然后启动我们的WebSocket后端服务# 启动后端服务 python backend.py你应该看到类似这样的输出INFO: Started server process [12345] INFO: Waiting for application startup. INFO: Application startup complete. INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRLC to quit)5.2 访问前端页面打开浏览器访问http://localhost:8000你会看到我们的实时生成界面。5.3 测试实时生成功能连接状态页面加载后顶部会显示WebSocket连接状态。成功连接后会显示WebSocket连接成功。输入提示词在文本框中输入图片描述默认是LiuJuan你也可以尝试其他描述。开始生成点击开始生成图片按钮。观察实时进度进度条会从0%开始逐渐增加下面的步骤列表会实时高亮显示当前正在进行的步骤每个步骤都有详细的描述查看生成结果生成完成后页面会显示生成的图片以及相关的生成信息。5.4 完整测试流程让我们通过一个完整的测试来验证系统功能# test_websocket_client.py import asyncio import websockets import json async def test_websocket_client(): 测试WebSocket客户端模拟前端行为 uri ws://localhost:8000/ws/generate try: async with websockets.connect(uri) as websocket: print(✅ 已连接到WebSocket服务器) # 发送生成请求 request { action: generate, prompt: LiuJuan, 高清, 艺术风格 } print(f 发送请求: {request}) await websocket.send(json.dumps(request)) # 接收并处理消息 print( 等待服务器响应...) while True: try: message await websocket.recv() data json.loads(message) if data[type] ack: print(f✅ 收到确认: {data[message]}) print(f 连接ID: {data[connection_id]}) elif data[type] progress: print(f 进度更新: {data[progress]}% - {data[message]}) elif data[type] result: print(f 生成完成!) print(f 结果数据: {data[data]}) break elif data[type] error: print(f❌ 错误: {data[message]}) break except websockets.exceptions.ConnectionClosed: print(❌ 连接已关闭) break except Exception as e: print(f❌ 连接失败: {str(e)}) if __name__ __main__: asyncio.run(test_websocket_client())运行测试客户端python test_websocket_client.py你应该能看到实时的进度更新从0%到100%每一步都有相应的状态信息。6. 总结与扩展建议通过本文的实践我们成功构建了一个基于WebSocket的LiuJuan文生图实时进度推送系统。这个系统不仅解决了传统HTTP轮询的效率问题还大大提升了用户体验。6.1 核心收获回顾让我们回顾一下这个项目中的关键技术点WebSocket实时通信我们使用WebSocket实现了服务器到客户端的主动推送让进度更新变得实时而高效。进度状态管理通过定义清晰的生成步骤和进度百分比让用户对生成过程有清晰的预期。前后端分离架构前端专注于用户体验和界面交互后端处理AI模型调用和进度管理职责清晰。错误处理与重连完善的错误处理机制和自动重连功能保证了系统的稳定性。用户体验优化进度条、步骤列表、状态提示等设计让等待过程不再焦虑。6.2 实际应用价值这个实时进度推送系统在实际应用中有多重价值提升用户体验用户不再需要盲目等待可以实时了解生成进度提高系统透明度让用户了解AI生成的具体步骤增加信任感便于问题排查当生成失败时可以准确知道是在哪个步骤出了问题支持批量处理可以同时监控多个生成任务的进度6.3 扩展与优化建议如果你想让这个系统更加强大可以考虑以下扩展方向多任务并发支持# 在后端添加多任务管理 class GenerationTaskManager: def __init__(self): self.tasks {} # task_id - task_info self.progress {} # task_id - progress async def start_generation(self, prompt, connection_id): task_id str(uuid.uuid4()) # 创建新任务 self.tasks[task_id] { prompt: prompt, connection_id: connection_id, status: running } # 启动生成任务 asyncio.create_task(self.run_generation(task_id, prompt)) return task_id进度持久化# 将进度保存到数据库支持页面刷新后恢复 import sqlite3 class ProgressDatabase: def __init__(self): self.conn sqlite3.connect(progress.db) self.create_table() def create_table(self): self.conn.execute( CREATE TABLE IF NOT EXISTS generation_progress ( task_id TEXT PRIMARY KEY, connection_id TEXT, prompt TEXT, progress INTEGER, current_step TEXT, created_at TIMESTAMP, updated_at TIMESTAMP ) )更详细的进度信息# 提供更详细的进度信息 async def send_detailed_progress(connection_id, step_info): 发送详细的进度信息 await websocket.send_json({ type: detailed_progress, step: step_info[name], progress: step_info[progress], estimated_time: step_info[eta], details: step_info.get(details, {}), timestamp: time.time() })支持进度取消// 在前端添加取消按钮 function cancelGeneration() { if (socket socket.readyState WebSocket.OPEN currentTaskId) { socket.send(JSON.stringify({ action: cancel, task_id: currentTaskId })); } }移动端适配优化针对手机和平板优化界面布局和交互。6.4 部署建议在实际部署时你还需要考虑WebSocket连接管理使用连接池管理大量并发连接负载均衡当用户量增加时需要考虑多服务器部署安全性添加身份验证和授权机制监控告警监控WebSocket连接状态和生成任务状态6.5 最后的话实时进度推送不仅仅是技术上的优化更是用户体验的重要提升。在AI应用越来越普及的今天让用户了解后台发生了什么变得越来越重要。通过本文的示例你已经掌握了构建实时AI应用的核心技术。无论是文生图、文生视频还是其他需要长时间处理的AI任务都可以使用类似的架构来提供更好的用户体验。记住好的技术应该是看不见的——它应该默默工作同时给用户带来顺畅和安心的体验。WebSocket实时通信就是这样一种看不见但至关重要的技术。现在去创建你自己的实时AI应用吧从简单的进度推送开始逐步添加更多功能你会发现用户对你的产品会有完全不同的感受。获取更多AI镜像想探索更多AI镜像和应用场景访问 CSDN星图镜像广场提供丰富的预置镜像覆盖大模型推理、图像生成、视频生成、模型微调等多个领域支持一键部署。