尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Stable Yogi 模型JavaScript交互全实现:从网页调用到动态效果展示

Stable Yogi 模型JavaScript交互全实现:从网页调用到动态效果展示 Stable Yogi 模型JavaScript交互全实现从网页调用到动态效果展示你是不是也好奇那些炫酷的AI图片生成网站背后是怎么把模型能力搬到浏览器里的今天咱们就来亲手实现一个。不用复杂的后端就用你熟悉的JavaScript从零开始在网页上调用Stable Yoji模型生成图片还能玩点动态效果。这篇文章会带你走完整个流程怎么用几行代码发起请求怎么处理返回的图片数据怎么把它漂亮地展示在页面上最后再加点加载动画和简单的图片编辑功能让整个交互体验更丝滑。我会提供可以直接复制粘贴的代码块你跟着做很快就能看到效果。1. 环境准备与项目搭建在开始写代码之前我们得先把“舞台”搭好。这里不需要安装复杂的Python环境或深度学习框架一切都在前端完成。1.1 理解基本原理简单来说我们的目标是在浏览器里通过JavaScript代码向一个提供了Stable Yoji模型服务的API地址发送请求。这个请求里包含了我们想要生成图片的文字描述Prompt。API服务器收到请求后调用模型生成图片并把图片数据通常是Base64编码的字符串返回给浏览器。最后我们用JavaScript把这个字符串转换成图片显示在网页上。整个过程是异步的因为生成图片需要时间所以我们会用到Promise、async/await这些来处理等待和响应。1.2 创建基础HTML结构我们先创建一个最简单的HTML文件作为我们所有功能的容器。!DOCTYPE html html langzh-CN head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 titleStable Yoji 前端交互实验室/title style * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, sans-serif; line-height: 1.6; padding: 20px; background-color: #f5f7fa; color: #333; } .container { max-width: 1200px; margin: 0 auto; } header { text-align: center; margin-bottom: 40px; } h1 { color: #2c3e50; margin-bottom: 10px; } .subtitle { color: #7f8c8d; font-size: 1.1em; } main { display: grid; grid-template-columns: 1fr 1fr; gap: 30px; } media (max-width: 768px) { main { grid-template-columns: 1fr; } } .control-panel, .display-panel { background: white; padding: 25px; border-radius: 12px; box-shadow: 0 5px 15px rgba(0,0,0,0.08); } .loading { display: none; /* 默认隐藏 */ text-align: center; padding: 20px; color: #3498db; } .spinner { border: 4px solid rgba(0,0,0,0.1); border-radius: 50%; border-top: 4px solid #3498db; width: 40px; height: 40px; animation: spin 1s linear infinite; margin: 10px auto; } keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } .error-message { display: none; background-color: #fee; color: #c33; padding: 15px; border-radius: 6px; margin-top: 15px; border-left: 4px solid #c33; } /style /head body div classcontainer header h1Stable Yoji 前端交互实验室/h1 p classsubtitle用JavaScript调用AI模型实时生成与编辑图像/p /header main !-- 左侧控制面板 -- section classcontrol-panel h2生成控制台/h2 !-- 输入区域和按钮将由JavaScript动态生成或操作 -- div idinputArea/div div idbuttonArea/div div classloading idloadingIndicator div classspinner/div pAI正在创作中请稍候.../p /div div classerror-message iderrorDisplay/div /section !-- 右侧展示面板 -- section classdisplay-panel h2作品展示区/h2 div idimageContainer p idplaceholderText生成的图片将在这里显示/p !-- Canvas和Img元素将由JavaScript动态创建 -- /div div ideditorControls stylemargin-top: 20px; display: none; h3简易编辑器/h3 !-- 编辑按钮将由JavaScript动态生成 -- /div /section /main /div !-- 引入我们即将编写的JavaScript文件 -- script srcapp.js/script /body /html这个HTML文件搭建了一个双栏布局的基本页面左边是控制区右边是展示区。我们还预先定义好了加载动画和错误提示的样式它们默认是隐藏的。2. 核心用JavaScript调用模型API现在进入最核心的部分——写JavaScript代码来和AI模型“对话”。我们将创建一个单独的app.js文件。2.1 初始化与API配置首先我们在app.js里设置一些初始变量和API的配置信息。这里假设你已经有一个可用的Stable Yoji模型API端点。在实际项目中你需要替换成你自己的服务地址。// app.js // 1. API配置 const API_CONFIG { // 替换为你的Stable Yoji模型API端点 baseURL: https://your-stable-yoji-api.com/v1, generatePath: /generate, // 生成图片的路径 // 一些默认的生成参数可以根据模型要求调整 defaultParams: { prompt: a cute cat, // 默认提示词 negative_prompt: , // 负面提示词 steps: 20, // 迭代步数 cfg_scale: 7.5, // 提示词相关性 width: 512, height: 512, samples: 1, // 生成数量 // 注意不同API返回的数据格式可能不同常见的是直接返回Base64或包含Base64的JSON response_format: base64_json // 明确要求返回Base64格式 } }; // 2. 获取页面上的关键DOM元素 const inputArea document.getElementById(inputArea); const buttonArea document.getElementById(buttonArea); const loadingIndicator document.getElementById(loadingIndicator); const errorDisplay document.getElementById(errorDisplay); const imageContainer document.getElementById(imageContainer); const placeholderText document.getElementById(placeholderText); const editorControls document.getElementById(editorControls); // 3. 当前生成的图片数据Base64格式 let currentImageData null; // 用于引用当前展示的Canvas或Img元素 let currentImageElement null;2.2 构建用户输入界面接下来我们用JavaScript动态创建输入框和按钮这样比直接在HTML里写更灵活。// 4. 创建用户交互界面 function initUI() { // 创建提示词输入框 const promptLabel document.createElement(label); promptLabel.textContent 描述你想生成的画面; promptLabel.style.display block; promptLabel.style.marginBottom 8px; promptLabel.style.fontWeight bold; const promptTextarea document.createElement(textarea); promptTextarea.id promptInput; promptTextarea.rows 4; promptTextarea.style.width 100%; promptTextarea.style.padding 12px; promptTextarea.style.border 1px solid #ddd; promptTextarea.style.borderRadius 6px; promptTextarea.style.fontSize 16px; promptTextarea.style.resize vertical; promptTextarea.value API_CONFIG.defaultParams.prompt; // 设置默认值 promptTextarea.placeholder 例如一只戴着宇航员头盔的柯基犬在火星上赛博朋克风格...; inputArea.appendChild(promptLabel); inputArea.appendChild(promptTextarea); // 创建生成按钮 const generateButton document.createElement(button); generateButton.id generateBtn; generateButton.textContent 生成图像; generateButton.style.marginTop 20px; generateButton.style.padding 12px 30px; generateButton.style.backgroundColor #3498db; generateButton.style.color white; generateButton.style.border none; generateButton.style.borderRadius 6px; generateButton.style.fontSize 16px; generateButton.style.cursor pointer; generateButton.style.transition background-color 0.3s; generateButton.onmouseover () generateButton.style.backgroundColor #2980b9; generateButton.onmouseout () generateButton.style.backgroundColor #3498db; buttonArea.appendChild(generateButton); // 为按钮绑定点击事件 generateButton.addEventListener(click, handleGenerateClick); } // 初始化UI initUI();2.3 实现API请求函数这是最关键的一步我们使用浏览器原生的fetchAPI来发送请求。注意处理异步和错误。// 5. 核心调用生成API的函数 async function callGenerateAPI(promptText) { // 显示加载动画 loadingIndicator.style.display block; // 隐藏之前的错误信息 errorDisplay.style.display none; // 准备请求参数合并默认参数和用户输入 const requestBody { ...API_CONFIG.defaultParams, prompt: promptText }; const apiUrl ${API_CONFIG.baseURL}${API_CONFIG.generatePath}; try { console.log(正在向API发送请求..., apiUrl); const response await fetch(apiUrl, { method: POST, headers: { Content-Type: application/json, // 如果需要API密钥在这里添加 // Authorization: Bearer YOUR_API_KEY }, body: JSON.stringify(requestBody) }); if (!response.ok) { // 如果HTTP状态码不是2xx抛出错误 const errorText await response.text(); throw new Error(API请求失败 (${response.status}): ${errorText}); } const data await response.json(); console.log(API响应数据:, data); // 处理响应不同API返回的数据结构可能不同 // 情况1: 直接返回Base64字符串 // 情况2: 返回一个对象其中某个字段是Base64字符串如 data.images[0] let base64ImageString; if (typeof data string data.startsWith(data:image)) { // 已经是完整的Data URL base64ImageString data; } else if (data.images Array.isArray(data.images) data.images[0]) { // 常见格式{ images: [base64编码的图片字符串] } // 注意API返回的可能只是纯Base64没有data:image/png;base64,前缀 const rawBase64 data.images[0]; base64ImageString rawBase64.startsWith(data:image) ? rawBase64 : data:image/png;base64,${rawBase64}; } else if (data.image) { // 格式{ image: base64... } const rawBase64 data.image; base64ImageString rawBase64.startsWith(data:image) ? rawBase64 : data:image/png;base64,${rawBase64}; } else { throw new Error(无法从API响应中解析出图片数据); } return base64ImageString; } catch (error) { console.error(调用API时发生错误:, error); // 显示错误信息给用户 showError(生成失败${error.message}); throw error; // 重新抛出错误让调用者知道 } finally { // 无论成功失败都隐藏加载动画 loadingIndicator.style.display none; } }2.4 处理图片展示与用户交互拿到Base64数据后我们需要把它变成图片显示出来并处理整个交互流程。// 6. 处理生成按钮点击事件 async function handleGenerateClick() { const promptInput document.getElementById(promptInput); const userPrompt promptInput.value.trim(); if (!userPrompt) { showError(请输入图片描述); return; } try { const imageDataUrl await callGenerateAPI(userPrompt); // 保存当前图片数据供后续编辑使用 currentImageData imageDataUrl; // 在页面上展示图片 displayGeneratedImage(imageDataUrl); // 显示编辑控制面板 editorControls.style.display block; } catch (error) { // 错误已在callGenerateAPI中处理这里可以记录日志或做其他处理 console.log(生成流程被取消或失败。); } } // 7. 将Base64图片显示在页面上 function displayGeneratedImage(dataUrl) { // 移除之前的占位文本和图片 placeholderText.style.display none; if (currentImageElement) { currentImageElement.remove(); } // 创建新的图片元素 const img document.createElement(img); img.src dataUrl; img.alt AI生成的图像; img.style.maxWidth 100%; img.style.height auto; img.style.borderRadius 8px; img.style.boxShadow 0 4px 12px rgba(0,0,0,0.15); img.style.display block; img.style.margin 0 auto; // 图片加载完成后的回调可选用于获取原始尺寸等 img.onload function() { console.log(图片加载成功尺寸: ${this.naturalWidth} x ${this.naturalHeight}); // 可以在这里触发一些依赖于图片尺寸的操作 initEditorControls(this); // 初始化编辑器传入图片DOM元素 }; imageContainer.appendChild(img); currentImageElement img; // 保存引用 } // 8. 显示错误信息 function showError(message) { errorDisplay.textContent message; errorDisplay.style.display block; // 5秒后自动隐藏错误信息 setTimeout(() { errorDisplay.style.display none; }, 5000); }到这一步一个最基础的“输入描述 - 生成图片 - 显示图片”的流程就完成了。你可以打开HTML文件输入描述点击按钮应该就能看到图片生成并显示出来前提是你的API地址配置正确且可访问。3. 进阶实现动态效果与图片编辑光是生成和显示还不够酷我们再加点料让页面互动性更强。3.1 添加图片编辑器控制面板我们来实现几个简单的图片后处理功能灰度滤镜、裁剪、旋转。这些操作我们将使用HTML5的Canvas API来完成这样更灵活也能直接在浏览器里处理不依赖服务器。// 9. 初始化图片编辑器控制面板 function initEditorControls(imageElement) { // 清空之前的控制按钮 editorControls.innerHTML h3简易编辑器/h3; const buttonContainer document.createElement(div); buttonContainer.style.display flex; buttonContainer.style.gap 10px; buttonContainer.style.flexWrap wrap; buttonContainer.style.marginTop 10px; // 创建各种编辑按钮 const editFunctions [ { name: 应用灰度滤镜, action: applyGrayscaleFilter }, { name: 裁剪中心区域, action: applyCenterCrop }, { name: 顺时针旋转90°, action: rotateImage }, { name: 重置为原图, action: resetToOriginal } ]; editFunctions.forEach(func { const btn document.createElement(button); btn.textContent func.name; btn.style.padding 8px 16px; btn.style.backgroundColor #2ecc71; btn.style.color white; btn.style.border none; btn.style.borderRadius 4px; btn.style.cursor pointer; btn.style.fontSize 14px; btn.onclick () func.action(imageElement); buttonContainer.appendChild(btn); }); // 下载按钮 const downloadBtn document.createElement(button); downloadBtn.textContent 下载图片; downloadBtn.style.padding 8px 16px; downloadBtn.style.backgroundColor #9b59b6; downloadBtn.style.color white; downloadBtn.style.border none; downloadBtn.style.borderRadius 4px; downloadBtn.style.cursor pointer; downloadBtn.style.fontSize 14px; downloadBtn.onclick () downloadImage(imageElement); buttonContainer.appendChild(downloadBtn); editorControls.appendChild(buttonContainer); } // 10. 使用Canvas应用灰度滤镜 function applyGrayscaleFilter(imgElement) { const canvas document.createElement(canvas); const ctx canvas.getContext(2d); const width imgElement.naturalWidth; const height imgElement.naturalHeight; canvas.width width; canvas.height height; // 将原图绘制到Canvas ctx.drawImage(imgElement, 0, 0); // 获取图像数据 const imageData ctx.getImageData(0, 0, width, height); const data imageData.data; // 遍历每个像素计算灰度值 for (let i 0; i data.length; i 4) { const r data[i]; const g data[i 1]; const b data[i 2]; // 使用加权平均法计算灰度 const gray 0.299 * r 0.587 * g 0.114 * b; data[i] data[i 1] data[i 2] gray; } // 将处理后的数据放回Canvas ctx.putImageData(imageData, 0, 0); // 用处理后的Canvas数据替换原图 replaceImageWithCanvas(canvas, imgElement); } // 11. 裁剪图片中心区域裁剪为原图的70% function applyCenterCrop(imgElement) { const canvas document.createElement(canvas); const ctx canvas.getContext(2d); const originalWidth imgElement.naturalWidth; const originalHeight imgElement.naturalHeight; // 定义裁剪区域为原图中心的70% const cropRatio 0.7; const cropWidth originalWidth * cropRatio; const cropHeight originalHeight * cropRatio; const cropX (originalWidth - cropWidth) / 2; const cropY (originalHeight - cropHeight) / 2; canvas.width cropWidth; canvas.height cropHeight; // 从原图指定区域裁剪并绘制到Canvas ctx.drawImage( imgElement, cropX, cropY, cropWidth, cropHeight, // 源图像裁剪区域 0, 0, cropWidth, cropHeight // 在Canvas上的绘制区域 ); replaceImageWithCanvas(canvas, imgElement); } // 12. 旋转图片90度 function rotateImage(imgElement) { const canvas document.createElement(canvas); const ctx canvas.getContext(2d); const width imgElement.naturalWidth; const height imgElement.naturalHeight; // 旋转后宽高互换 canvas.width height; canvas.height width; // 平移并旋转画布 ctx.translate(height / 2, width / 2); ctx.rotate(Math.PI / 2); // 90度 ctx.translate(-width / 2, -height / 2); // 绘制图片 ctx.drawImage(imgElement, 0, 0); replaceImageWithCanvas(canvas, imgElement); } // 13. 重置为原始图片 function resetToOriginal(imgElement) { if (currentImageData) { imgElement.src currentImageData; } } // 14. 用Canvas内容替换原Img元素 function replaceImageWithCanvas(canvas, originalImgElement) { // 将Canvas转换为Data URL const newDataUrl canvas.toDataURL(image/png); // 更新图片源 originalImgElement.src newDataUrl; // 注意这里我们没有更新currentImageData所以“重置”功能仍然有效 } // 15. 下载图片 function downloadImage(imgElement) { // 创建一个临时的链接元素 const link document.createElement(a); link.href imgElement.src; link.download stable-yoji-${Date.now()}.png; // 生成一个带时间戳的文件名 document.body.appendChild(link); link.click(); document.body.removeChild(link); }3.2 添加更友好的交互反馈为了让等待过程不那么枯燥我们可以优化一下加载状态比如添加一个进度模拟因为大多数API不返回实时进度或者更丰富的动画。// 16. 可选增强加载状态体验 function enhanceLoadingExperience() { const loadingText loadingIndicator.querySelector(p); const dots [., .., ...]; let dotIndex 0; // 模拟一个动态的等待文本 const intervalId setInterval(() { if (loadingIndicator.style.display block) { loadingText.textContent AI正在创作中请稍候${dots[dotIndex]}; dotIndex (dotIndex 1) % dots.length; } else { clearInterval(intervalId); loadingText.textContent AI正在创作中请稍候...; // 重置 } }, 500); // 注意这个interval需要在加载结束时被清理我们在callGenerateAPI的finally块中隐藏loadingIndicator // 隐藏后上面的判断会失败interval自动停止。这是一种简单的处理方式。 } // 在callGenerateAPI函数中显示loadingIndicator后调用它 // 修改callGenerateAPI函数开头部分 // loadingIndicator.style.display block; // enhanceLoadingExperience(); // 添加这一行4. 完整代码整合与运行现在我们把所有代码片段按逻辑顺序整合到app.js文件中。确保你的HTML文件正确引用了它。最终app.js文件的结构建议如下API配置和DOM元素获取initUI()函数定义与调用callGenerateAPI()函数定义handleGenerateClick()函数定义displayGeneratedImage()和showError()函数定义编辑器相关函数定义 (initEditorControls,applyGrayscaleFilter等)可选enhanceLoadingExperience()函数定义把代码按这个顺序放好保存。然后用浏览器打开你的HTML文件。第一次运行可能会遇到的问题CORS错误如果你的API服务器没有正确配置CORS跨域资源共享浏览器会阻止请求。解决方法最佳实践在后端API服务中配置允许你的前端域名。开发测试可以使用浏览器插件临时禁用CORS不推荐用于生产或者将前端和后端部署在同一个域名下。API地址或参数错误检查API_CONFIG中的baseURL和defaultParams是否与你的模型服务要求一致。查看浏览器开发者工具F12的“网络(Network)”标签查看请求详情和错误响应。图片显示问题检查API返回的数据格式。我们的代码处理了两种常见格式但如果你的API返回的结构不同需要调整callGenerateAPI函数中解析base64ImageString的逻辑。5. 总结与后续探索跟着上面的步骤走一遍你应该已经拥有了一个功能相当完整的Stable Yoji模型前端交互界面。它不仅能根据文字描述生成图片还能在浏览器里直接进行简单的编辑和下载。整个过程只用到了HTML、CSS和原生JavaScript没有依赖任何前端框架理解起来很直接。用下来感觉前端调用AI模型API其实比想象中要简单核心就是处理好异步请求和数据格式转换。Canvas API给了我们很大的发挥空间今天做的滤镜、裁剪只是冰山一角你完全可以在此基础上增加更多效果比如调整亮度对比度、添加艺术滤镜甚至结合其他JavaScript库做更复杂的处理。遇到问题别怕多看看浏览器控制台的报错信息那是最好的调试工具。下一步你可以尝试把这段代码封装成一个可复用的JavaScript模块或者用Vue、React这些框架来重构让代码组织更清晰。也可以探索一下模型的其他参数比如换一种采样器、调整引导系数看看生成的图片会有什么变化。获取更多AI镜像想探索更多AI镜像和应用场景访问 CSDN星图镜像广场提供丰富的预置镜像覆盖大模型推理、图像生成、视频生成、模型微调等多个领域支持一键部署。
返回列表