你有没有想过,做一个能上传图片→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.value) return
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'
},
body: JSON.stringify({
workflow_id: WORKFLOW_ID,
parameters: {
image: JSON.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-width: 600px;
margin: 0 auto;
padding: 2rem;
font-family: system-ui, sans-serif;
}
.upload-area {
border: 2px dashed #ccc;
border-radius: 12px;
padding: 2rem;
text-align: center;
margin: 1rem 0;
}
.preview, .result-img {
max-width: 100%;
border-radius: 8px;
margin-top: 1rem;
}
.styles {
display: flex;
gap: 0.5rem;
flex-wrap: wrap;
margin: 1rem 0;
}
.styles button {
padding: 0.5rem 1rem;
border: 2px solid #e0e0e0;
border-radius: 20px;
background: white;
cursor: pointer;
transition: all 0.2s;
}
.styles button.active {
border-color: #6366f1;
background: #6366f1;
color: white;
}
.generate-btn {
width: 100%;
padding: 1rem;
background: linear-gradient(135deg, #6366f1, #8b5cf6);
color: white;
border: none;
border-radius: 12px;
font-size: 1.1rem;
cursor: pointer;
}
.generate-btn:disabled {
opacity: 0.6;
cursor: not-allowed;
}
.result {
margin-top: 2rem;
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 搭建企业级竞品监控系统
那篇走的是深度路线(后端代理、流式响应、条件分支),和这篇形成互补,建议都看看。
感谢看到这里!
如果本文对你有所帮助,欢迎点赞支持。
前端实战笔记、踩坑总结会持续更新,更多干货首发于公众号【前端晨话】,欢迎关注 ~