10行代码做一个AI创意画室:Vue3 + Coze 免费搭,零后端零服务器

0 阅读9分钟

你有没有想过,做一个能上传图片→AI自动生成创意图像的应用,需要多少代码?

答案是:前端核心代码 10 行,后端 0 行,服务器 0 台,花费 0 元。

哈哈,听起来够不够爽?

今天我们要做的东西长这样:

  • 用户上传一张照片(产品图、自拍、宠物照……都行)

  • AI "看懂" 这张图,提取关键特征

  • 根据你选的风格,生成一张全新的创意图像

  • 全程可视化,生成结果直接展示在页面上

听起来很复杂?其实 Coze(扣子)的工作流已经把最难的 AI 部分封装好了,咱要做的只是:搭一个工作流 + 写 10 行前端代码。

这篇和之前那篇"竞品监控系统"完全不同——那篇走的是企业级深度教程,这篇走的是极简+视觉冲击路线。10 分钟搭完,发朋友圈刚好。

Let`s go!

整体架构:简单到离谱

整个应用就 3 层:

用户上传图片 → Coze 工作流(AI大脑)→ 返回生成的图片 URL → 前端展示

没有后端,没有数据库,没有服务器。Coze 工作流部署后自动变成一个 API,前端直接调。

┌──────────┐    API     ┌──────────────────┐
│  Vue3    │ ──────────→ │  Coze 工作流      │
│  前端    │ ←────────── │  (图片理解→LLM→  │
│          │  图片URL    │   图像生成)       │
└──────────┘            └──────────────────┘

需要准备的东西:

  • ✅ 一个 Coze 账号(coze.cn 免费注册)

  • ✅ Node.js 环境(装过 Vue 开发环境就有)

  • ✅ 10 分钟时间

Coze 工作流搭建(核心部分)

这是整篇文章的重点。打开 coze.cn,创建一个新工作流。

工作流节点全景

一共 5 个节点,像搭积木一样连起来:

开始节点 → 图片理解(LLM) → 提示词生成(LLM) → 图像生成 → 结束节点

第 1 步:开始节点 — 定义输入

创建开始节点,添加两个输入参数:

| 参数名 | 类型 | 说明 | | --- | --- | --- | | image | Image | 用户上传的图片 | | style | String | 风格选择(如:赛博朋克/水彩/像素风/油画/动漫) |

第 2 步:图片理解节点 — 让 AI "看懂" 图片

拖一个大模型节点,选择豆包·视觉理解模型(注意:必须选带"视觉理解"后缀的,否则看不懂图片)。

配置:

  • 输入

    image 引用开始节点的 image 参数

  • 系统提示词

    你是一个图片分析专家。请仔细观察用户上传的图片,提取以下信息并用JSON格式输出:
    {
      "subject""图片主体(如:一只橘猫/一个人/一个产品)",
      "colors": ["主色调1""主色调2"],
      "features""关键特征描述(如:毛发蓬松、表情呆萌)",
      "background""背景描述"
    }
    只输出JSON,不要其他内容。
    

第 3 步:提示词生成节点 — 组合创意指令

再拖一个大模型节点,这次用普通文本模型就行(如豆包·1.8)。

配置:

  • 输入

    image_analysis 引用上一步的输出,style 引用开始节点的 style

  • 系统提示词

    你是一个创意图像提示词专家。根据图片分析结果和用户选择的风格,生成一段英文图像生成提示词。
    
    规则:
    1. 保留原图主体的核心特征(颜色、形状、表情等不能变)
    2. 将画面转换为{{style}}风格
    3. 提示词控制在50词以内
    4. 只输出提示词文本,不要其他内容
    
    示例输出:
    A fluffy orange cat sitting on a windowsill, cyberpunk style, neon lights, dark background with purple and blue tones, highly detailed, 4k
    

第 4 步:图像生成节点

拖一个图像生成节点(在 Coze 插件市场搜索"图像生成"即可找到)。

  • 输入

    prompt 引用上一步生成的提示词

  • 尺寸

    1024×1024(或根据需求调整)

第 5 步:结束节点 — 输出结果

把图像生成节点的输出(图片 URL)连接到结束节点的输出参数。

工作流搭建完成!点「试运行」测试一下,上传一张图,选个风格,看看效果。

💡 工作流发布后会自动获得一个 API 地址,记下这个地址,前端要用。这些之前在竞品监控那篇有详细介绍,不清楚的可以翻看前一篇。

Vue3 前端代码(核心只有 10 行)

先快速创建一个 Vue3 项目:

npm create vite@latest ai-image-studio -- --template vue
cd ai-image-studio
npm install
npm run dev

打开 src/App.vue,替换为以下内容:

<script setup>
import { ref } from 'vue'

// ⬇️ 替换成你自己的 Coze 工作流 API 地址和 Token
const WORKFLOW_URL = 'https://api.coze.cn/v1/workflow/run'
const WORKFLOW_ID = '你的工作流ID'
const PAT_TOKEN = '你的个人访问令牌'

const selectedFile = ref(null)
const previewUrl = ref('')
const resultUrl = ref('')
const loading = ref(false)
const selectedStyle = ref('赛博朋克')

// 核心函数:上传 + 生成,就这么简单
const generate = async () => {
  if (!selectedFile.valuereturn
  loading.value = true
  resultUrl.value = ''

  // 第1步:上传图片获取 file_id
  const formData = new FormData()
  formData.append('file', selectedFile.value)
  const uploadRes = await fetch('https://api.coze.cn/v1/files/upload', {
    method'POST',
    headers: { 'Authorization'`Bearer ${PAT_TOKEN}` },
    body: formData
  })
  const { data: { id: file_id } } = await uploadRes.json()

  // 第2步:调用工作流,传入图片ID和风格
  const runRes = await fetch(WORKFLOW_URL, {
    method'POST',
    headers: {
      'Authorization'`Bearer ${PAT_TOKEN}`,
      'Content-Type''application/json'
    },
    bodyJSON.stringify({
      workflow_idWORKFLOW_ID,
      parameters: {
        imageJSON.stringify({ file_id }),
        style: selectedStyle.value
      }
    })
  })
  const { data } = await runRes.json()
  resultUrl.value = JSON.parse(data).data  // 生成的图片 URL
  loading.value = false
}

const onFileChange = (e) => {
  selectedFile.value = e.target.files[0]
  previewUrl.value = URL.createObjectURL(e.target.files[0])
}
</script>

<template>
  <div class="studio">
    <h1>🎨 AI 创意画室</h1>

    <!-- 上传区域 -->
    <div class="upload-area">
      <input type="file" accept="image/*" @change="onFileChange" />
      <img src="previewUrl" />
    </div>

    <!-- 风格选择 -->
    <div class="styles">
      <button v-for="s in ['赛博朋克', '水彩', '像素风', '油画', '动漫']"
        :key="s"
        :class="{ active: selectedStyle === s }"
        @click="selectedStyle = s">
        {{ s }}
      </button>
    </div>

    <!-- 生成按钮 -->
    <button class="generate-btn" @click="generate" :disabled="loading">
      {{ loading ? '生成中...' : '✨ 开始生成' }}
    </button>

    <!-- 结果展示 -->
    <div v-if="resultUrl" class="result">
      <h3>生成结果</h3>
      <img src="resultUrl" />
    </div>
  </div>
</template>

<style scoped>
.studio {
  max-width600px;
  margin0 auto;
  padding2rem;
  font-family: system-ui, sans-serif;
}
.upload-area {
  border2px dashed #ccc;
  border-radius12px;
  padding2rem;
  text-align: center;
  margin1rem 0;
}
.preview.result-img {
  max-width100%;
  border-radius8px;
  margin-top1rem;
}
.styles {
  display: flex;
  gap0.5rem;
  flex-wrap: wrap;
  margin1rem 0;
}
.styles button {
  padding0.5rem 1rem;
  border2px solid #e0e0e0;
  border-radius20px;
  background: white;
  cursor: pointer;
  transition: all 0.2s;
}
.styles button.active {
  border-color#6366f1;
  background#6366f1;
  color: white;
}
.generate-btn {
  width100%;
  padding1rem;
  backgroundlinear-gradient(135deg#6366f1#8b5cf6);
  color: white;
  border: none;
  border-radius12px;
  font-size1.1rem;
  cursor: pointer;
}
.generate-btn:disabled {
  opacity0.6;
  cursor: not-allowed;
}
.result {
  margin-top2rem;
  text-align: center;
}
</style>

没错,核心逻辑就两个 fetch 调用:上传文件 → 调用工作流。加起来不到 30 行(含 UI 模板和样式),纯业务逻辑不到 10 行。

代码要点解释

为什么分两步?

Coze 工作流不能直接接收图片文件流。所以要先调用文件上传 API,拿到 file_id,再把 file_id 传给工作流。这是 Coze 的标准用法。

PAT Token 从哪来?

登录 coze.cn → 右上角头像 → 「个人设置」→ 「API 令牌」→ 创建个人访问令牌(PAT)。

工作流 ID 从哪来?

打开你的工作流页面,URL 里就有。或者在工作流详情页点击右上角「API」按钮,会直接给你完整的调用地址和参数格式。

跑起来看效果

浏览器打开 http://localhost:5173

图片

操作演示:

图片

图片

呃,确实是朋克风,但咋猫变成狗狗了?可能是大模型的解析图片的能力不行吧?

大家的呢?你还满意否?

试试同一张图切换不同风格——水彩风的猫、像素风的猫、油画风的猫……每种都是完全不同的视觉效果,非常适合发朋友圈。

如果报如下错误:

图片

去coze把上传图片的权限打开

3 个进阶玩法

基础版跑通了,来点有意思的。

玩法 1:加入"随机风格"

在风格按钮里加一个"🎲 随机",点击后随机选一个风格:

const randomStyle = () => {
  const styles = ['赛博朋克''水彩''像素风''油画''动漫''素描''浮世绘']
  selectedStyle.value = styles[Math.floor(Math.random() * styles.length)]
}

玩法 2:批量生成对比图

把 5 个风格同时发请求,一次性出 5 张图,做成对比效果:

const generateAll = async () => {
  const styles = ['赛博朋克''水彩''像素风''油画''动漫']
  loading.value = true
  results.value = []

  const file_id = await uploadFile()  // 上传一次,复用 file_id

  // 5个风格并发请求
  const promises = styles.map(async (style) => {
    const res = await callWorkflow(file_id, style)
    return { style, url: res }
  })
  results.value = await Promise.all(promises)
  loading.value = false
}

一张原图,5 种风格同时出图,做一张"风格对比九宫格"——这个效果在社交媒体上传播力极强。

玩法 3:加上"提示词微调"

在页面上加一个文本框,允许用户在 AI 生成的提示词基础上追加自己的描述:

<
textarea
 
v-model
=
"customPrompt"
 
placeholder
=
"追加描述(可选):比如 加上月亮背景"
></
textarea
>

工作流里增加一个参数 extra_prompt,在提示词生成节点里拼接到 AI 输出后面。这样用户就有了更精细的控制。

和直接调 Stable Diffusion / DALL-E 有什么区别?

你可能会问:我直接调 OpenAI 的 DALL-E API 或者 Stable Diffusion 不就行了?

区别在于工作流的编排能力

| 维度 | 直接调图像生成 API | Coze 工作流 + Vue3 | | --- | --- | --- | | 图片理解 | 需要额外接一个视觉模型 | 工作流内置图片理解节点 | | 提示词工程 | 你自己写或额外调 LLM | LLM 节点自动优化 | | 修改逻辑 | 改代码重新部署 | 改工作流节点,秒级生效 | | 加新风格 | 改代码 | 工作流加个条件分支 | | 成本 | 两个 API 分别付费 | Coze 免费额度 + 图像生成费用 | | 部署 | 需要后端服务 | 纯前端,零后端 |

核心优势:Coze 工作流把"理解图片→生成提示词→生成图像"这个链路封装成了一个可视化的流水线。你想改任何环节,拖拽节点就行,不用改前端代码。

常见问题

Q:生成很慢怎么办?

A:Coze 工作流跑完整个链路(图片理解→提示词→图像生成)大约需要 5-15 秒。如果嫌慢,可以在工作流里换用更快的模型(如豆包·Lite),或者把图像尺寸调小到 512×512。

Q:PAT Token 安全吗?放前端不会泄露?

A:严格来说,PAT Token 放在前端确实有泄露风险。个人项目/演示用没问题,生产环境建议加一层后端代理(参考我之前那篇"竞品监控"文章的方案)。本文追求的是极简,先把功能跑通。

Q:图片生成有数量限制吗?

A:Coze 平台有免费额度,超出后按调用量计费。具体价格看 coze.cn 定价页。个人玩一玩,免费额度完全够用。

Q:能部署到线上让别人用吗?

A:可以。npm run build 生成静态文件,扔到 Vercel / Netlify / GitHub Pages 就行,纯前端零后端。但记得把 PAT Token 换成后端代理,不然你的 Token 会被白嫖。

总结

整个项目从搭建到出效果,不到 30 分钟。这才是"前端 + AI"最有趣的样子——不是复杂的架构图,不是晦涩的概念,而是上传一张图,看到 AI 给你变出一个全新的画面

如果你做了有意思的效果,欢迎在评论区晒图。

📎 上一篇教程回顾:Coze 工作流 + Vue3 搭建企业级竞品监控系统

那篇走的是深度路线(后端代理、流式响应、条件分支),和这篇形成互补,建议都看看。


感谢看到这里!

如果本文对你有所帮助,欢迎点赞支持。

前端实战笔记、踩坑总结会持续更新,更多干货首发于公众号【前端晨话】,欢迎关注 ~