Electron 桌面应用接入通义万相:文生图从 0 到 1 实战
2026/9/12 2:11:25 网站建设 项目流程

🎨 Electron 桌面应用接入通义万相:文生图从 0 到 1 实战

💡 想在 Electron 应用里一键「画」出小说封面、海报、插画?阿里云通义万相(文生图)是个不错的选择。本文以 51mazi 小说写作软件的 AI 封面功能为例,手把手讲清:主进程如何安全调用 API、图片如何落盘到书籍目录、以及渲染进程如何优雅对接。看完你就能在自己的 Electron 项目里接好通义万相,实现「提示词 → 图片 → 本地文件」全链路。

📋 目录

  • 🎨 Electron 桌面应用接入通义万相:文生图从 0 到 1 实战
    • 📋 目录
    • 🎯 为什么选通义万相
    • 🏗️ 整体架构:主进程干活,渲染进程展示
    • 🔧 核心实现:服务层 + IPC + 落盘
      • 1. 服务层:通义万相文生图
      • 2. IPC:生成封面 + 确认使用 + 丢弃
      • 3. Preload:统一暴露,避免「is not a function」
    • 🛡️ 安全与体验:Key 存储、错误码、提示语
    • 📝 完整代码在哪看
    • 🎉 小结与 GitHub
      • 🏷️ 标签

🎯 为什么选通义万相

通义万相是阿里云百炼平台提供的文生图能力,适合在桌面应用里做「根据文字生成图片」的功能:

  • 国内服务:延迟低、无需科学上网
  • REST APIPOST+ JSON,和 Electron 主进程里的fetch天然契合
  • 模型能力:支持中文提示词、多种尺寸、正向/反向提示词,适合小说封面、插画等场景
  • 按量计费:个人或小团队可控成本

在 51mazi 里,我们用它做「AI 生成小说封面」:用户输入书名、笔名、风格描述,由通义万相生成图片,再保存到书籍根目录(如ai_cover1.png、确认后复制为cover.png)。

🏗️ 整体架构:主进程干活,渲染进程展示

原则和接入 DeepSeek 时一致:API Key 和网络请求只在主进程,渲染进程只发 IPC、不碰 Key

┌─────────────────────┐ │ Vue 组件 │ 渲染进程:填写提示词、选尺寸、点「生成」 │ (AICoverDrawer) │ └──────────┬──────────┘ │ IPC: tongyiwanxiang:generate-cover ▼ ┌─────────────────────┐ │ Preload │ contextBridge 暴露 generateAICover、confirmAICover 等 └──────────┬──────────┘ │ ▼ ┌─────────────────────┐ │ 主进程 │ 调用 tongyiwanxiang 服务 → 拿到图片 URL → 下载 → 写入书籍目录 │ tongyiwanxiang.js │ └──────────┬──────────┘ │ HTTPS ▼ ┌─────────────────────┐ │ 阿里云 通义万相 API │ dashscope.aliyuncs.com └─────────────────────┘

这样做的直接好处:

  1. 安全:API Key 存在 electron-store(用户目录),渲染进程拿不到。
  2. 可控:限流、重试、错误码解析都可以在主进程统一处理。
  3. 可维护:换模型或换接口时只改主进程服务层即可。

🔧 核心实现:服务层 + IPC + 落盘

1. 服务层:通义万相文生图

在主进程里单独建一个服务类(如src/main/services/tongyiwanxiang.js),只做三件事:组请求体 → 发 HTTP → 解析返回里的图片 URL

接口形式(以当前使用的多模态生成接口为例):

  • URLhttps://dashscope.aliyuncs.com/api/v1/services/aigc/multimodal-generation/generation
  • 鉴权:HeaderAuthorization: Bearer <API Key>
  • Bodymodelinput.messages[].content[].text(提示词)、parameters(尺寸、负向提示词、是否扩展提示词等)

核心代码示例:

// src/main/services/tongyiwanxiang.jsconstDASHSCOPE_API_BASE='https://dashscope.aliyuncs.com/api/v1/services/aigc/multimodal-generation/generation'constMODEL='wan2.6-t2i'classTongyiwanxiangService{asyncgenerateCover(options={}){const{prompt,size='1280*1280',negativePrompt=''}=optionsconstbody={model:MODEL,input:{messages:[{role:'user',content:[{text:prompt.trim()}]}]},parameters:{prompt_extend:true,watermark:false,n:1,negative_prompt:negativePrompt||'',size:String(size)}}constresponse=awaitfetch(DASHSCOPE_API_BASE,{method:'POST',headers:{'Content-Type':'application/json',Authorization:`Bearer${this.apiKey}`},body:JSON.stringify(body)})constdata=awaitresponse.json().catch(()=>({}))if(data.code){thrownewError(this._formatErrorMessage(data.code,data.message))}constimageUrl=data.output?.choices?.[0]?.message?.content?.[0]?.imageif(!imageUrl)thrownewError('接口未返回有效图片地址')returnimageUrl}}

返回的imageUrl是临时可访问的地址,需在有效期内(通常 24 小时内)下载到本地,否则会失效。所以下一步就是在主进程里「下载 → 落盘」。

2. IPC:生成封面 + 确认使用 + 丢弃

主进程注册三个 IPC Handler,对应前端三个操作:

操作IPC Channel作用
生成封面tongyiwanxiang:generate-cover调服务 → 拿 URL → 下载 → 保存到书籍目录ai_cover1.pngai_cover2.png
确认使用tongyiwanxiang:confirm-cover把用户选中的那张复制为cover.png
取消/关闭tongyiwanxiang:discard-ai-covers当前实现不删文件,仅关闭弹框

生成封面的主流程示例(逻辑在主进程):

// 1. 调通义万相拿到图片 URLconstimageUrl=awaittongyiwanxiangService.generateCover({prompt,size,negativePrompt})// 2. 下载图片constres=awaitfetch(imageUrl)constbuf=Buffer.from(awaitres.arrayBuffer())// 3. 保存到书籍根目录:ai_cover1.png, ai_cover2.png ...constexisting=fs.readdirSync(bookPath).filter((f)=>/^ai_cover\d+\.png$/i.test(f))constnextNum=existing.length===0?1:Math.max(...existing.map(解析数字))+1constfileName=`ai_cover${nextNum}.png`constcoverPath=join(bookPath,fileName)fs.writeFileSync(coverPath,buf)return{success:true,localPath:coverPath}

这样渲染进程拿到的就是本地路径,可以直接用file://做预览;确认使用时再根据chosenPath复制为cover.png即可。

3. Preload:统一暴露,避免「is not a function」

渲染进程通过window.electron.generateAICoverconfirmAICover等调用。若只在contextIsolated === true时通过contextBridge暴露了这些方法,而在contextIsolated === false时只挂了electronAPI,就会出现「confirmAICover is not a function」。

做法:把「自定义 API」抽成一份(如customElectronAPI),两种情况下都挂到window.electron上:

constcustomElectronAPI={// ... 其他 APIgenerateAICover:(options)=>ipcRenderer.invoke('tongyiwanxiang:generate-cover',options),confirmAICover:(options)=>ipcRenderer.invoke('tongyiwanxiang:confirm-cover',options),discardAICovers:(options)=>ipcRenderer.invoke('tongyiwanxiang:discard-ai-covers',options)}if(process.contextIsolated){contextBridge.exposeInMainWorld('electron',{...electronAPI,...customElectronAPI})}else{window.electron={...electronAPI,...customElectronAPI}}

这样无论是否开启上下文隔离,前端都能稳定调到这些方法。

🛡️ 安全与体验:Key 存储、错误码、提示语

  • API Key:从 electron-store 读(如tongyiwanxiang.apiKey),只在主进程使用,不通过 IPC 把 Key 本身传给渲染进程。
  • 错误码:通义万相会返回code(如InvalidApiKeyDataInspectionFailedThrottling),在主进程里用_formatErrorMessage转成中文提示,再通过 IPC 返回给前端展示。
  • 体验:生成时前端可提示「正在努力生图中,不要关闭弹框」,并禁用关闭或二次点击,避免中途关掉导致状态错乱。

📝 完整代码在哪看

实现涉及的文件:

  • src/main/services/tongyiwanxiang.js:通义万相服务层
  • src/main/index.jstongyiwanxiang:generate-cover/confirm-cover/discard-ai-covers的 IPC 实现
  • src/preload/index.jscustomElectronAPIwindow.electron的挂载
  • src/renderer/src/service/tongyiwanxiang.js:前端对generateAICoverconfirmAICover的封装
  • src/renderer/src/components/AICoverDrawer.vue:封面生成弹框 UI 与提示词拼接(书名、笔名、风格)

可直接在仓库里按文件名搜索,每个模块都有注释,便于对照本文捋清链路。

🎉 小结与 GitHub

在 Electron 里接入通义万相文生图,核心就是三件事:

  1. 主进程服务层:组好请求、调 API、拿图片 URL,并做好错误码与异常处理。
  2. 主进程 IPC + 落盘:下载图片、按规则命名(如ai_cover1.png)、确认后复制为cover.png,所有写盘都在主进程完成。
  3. Preload 统一暴露:自定义 API 与 electronAPI 合并后一起挂到window.electron,避免上下文隔离开关导致的方法缺失。

按这个思路,你可以把「通义万相 + Electron」复用到任何需要文生图的桌面功能上(海报、插画、配图等)。若你想直接看完整工程和交互细节,欢迎到 51mazi 仓库里翻代码、提 Issue 或 Star。

  • GitHub 仓库:https://github.com/xiaoshengxianjun/51mazi ⭐ 给个 Star 支持一下!
  • 通义万相 API 文档:阿里云百炼 - 文生图

🏷️ 标签

#Electron#通义万相#文生图#阿里云#桌面应用#Vue3#IPC#51mazi


💡如果这篇文章对你有帮助,请在GitHub上给个 ⭐️ 支持一下!

本文基于 51mazi 开源项目,通义万相文生图接入方案

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询