一句话简介:用户上传一张宠物照片,选择队服颜色、号码、位置等参数,AI 自动生成一张“穿冰球服的宠物”图片,并实时展示——这一切,仅靠前端 + Coze API 就能实现!
🔮 前言:为什么做这个项目?
在 AIGC(AI 生成内容)爆发的今天,普通人也能通过低代码平台快速构建 AI 应用。
Coze 作为字节推出的智能体开发平台,提供了强大的 工作流(Workflow)能力,允许我们将图像理解、提示词工程、Stable Diffusion 等能力封装成一个 API。
于是,我突发奇想:能不能让我的猫穿上冰球服?
于是就有了这个小而美的项目——IceBall AI:上传任意宠物/人像照片,AI 自动将其“换装”为冰球运动员形象,支持自定义队服颜色、号码、持杆手、风格等,结果可直接分享朋友圈!
本文将带你从 0 到 1 拆解这个应用的前端实现,重点讲解:
- 如何用 Vue3 实现图片预览
- 如何调用 Coze 文件上传接口
- 如何安全传递
file_id给工作流 - 如何解析并展示生成的图片 URL
最后还会附上 大厂高频面试题,助你举一反三!
🧠 Coze 工作流做了什么?
在深入代码前,先理解后端逻辑:
✅ 工作流设计(在 Coze 平台配置)
-
输入参数:
picture:文件 ID(由前端上传后返回)style:生成风格(如“乐高”、“油画”)uniform_color/uniform_number/position/shooting_hand:业务参数
-
内部流程:
-
使用 图像理解 Bot 分析原始图中主体(宠物/人)
-
构造动态提示词(Prompt),例如:
“一只穿着红色冰球服、号码10、左手持杆的猫咪,站在冰球场上,写实风格”
-
调用 文生图模型(如 SDXL)生成新图
-
-
输出:
-
返回生成图片的 临时 URL,格式为:
{ "answer": "https://s.coze.cn/t/xxx" }
-
💡 关键点:前端只需上传文件 → 获取 file_id → 调用 workflow → 展示 answer,无需关心 AI 内部细节。
🖼️ Template:简洁直观的交互界面
设计亮点:
- 响应式布局:左右分栏,适配桌面端
- 即时反馈:上传即显示预览图,提升用户体验
- 状态驱动:
status控制“上传中”、“生成中”等文案 - 条件渲染:
v-if="imgUrl"避免空图占位
⚙️ Script Setup:Vue3 Composition API 核心逻辑
我们使用 <script setup> 语法,代码更简洁、逻辑更聚焦。
1️⃣ 响应式状态管理
js
编辑
const uniform_number = ref(10);
const uniform_color = ref('红');
// ... 其他表单项
const status = ref(''); // 操作状态
const imgUrl = ref(''); // 生成图 URL
const imgPreview = ref(''); // 本地预览图(base64)
const uploadImage = ref(null); // DOM 引用
✅ 所有 UI 状态均由
ref管理,自动触发视图更新。
2️⃣ 图片预览:FileReader + Base64
const updateImageData = () => {
const file = uploadImage.value.files[0];
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = (e) => {
imgPreview.value = e.target.result; // base64 字符串
};
};
- 原理:
FileReader.readAsDataURL()将文件转为data:image/jpeg;base64,...格式 - 优势:无需上传即可本地预览,用户体验流畅
3️⃣ 上传文件到 Coze
js
编辑
const uploadFile = async () => {
const formData = new FormData();
formData.append('file', uploadImage.value.files[0]);
const res = await fetch(uploadUrl, {
method: 'POST',
headers: { Authorization: `Bearer ${patToken}` },
body: formData
});
const ret = await res.json();
if (ret.code !== 0) {
status.value = ret.msg;
return;
}
return ret.data.id; // 关键!返回 file_id
};
🔒 安全提示:使用
.env存储VITE_PAT_TOKEN,避免泄露 PAT(Personal Access Token)
4️⃣ 调用 Coze 工作流(核心!)
js
编辑
const generate = async () => {
status.value = "图片上传中...";
const file_id = await uploadFile();
if (!file_id) return;
status.value = "正在生成中...";
const parameters = {
picture: JSON.stringify({ file_id }), // Coze 要求传 JSON 字符串
style: style.value,
uniform_color: uniform_color.value,
// ... 其他参数
};
const res = await fetch(workflowUrl, {
method: 'POST',
headers: {
Authorization: `Bearer ${patToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
workflow_id: workflowId,
parameters
})
});
const ret = await res.json();
if (ret.code !== 0) {
status.value = ret.msg;
return;
}
// ✅ 正确解析:ret.answer 就是图片 URL!
imgUrl.value = ret.answer;
status.value = '';
};
⚠️ 重点纠正一个误区!
很多同学会写:
imgUrl.value = ret.answer;
但根据你 console.log(ret) 的实际输出:
console.log(ret);
→ ret.data里面的数据还没有反序列化
所以正确做法是:
const data=JSON.parse(ret.data);
imgUrl.value = data.answer; // 直接取!
💡 经验法则:先检查
console.log(ret),再决定如何取值!
🎯 项目亮点总结
| 功能 | 技术实现 |
|---|---|
| 本地图片预览 | FileReader + readAsDataURL |
| 安全上传 | FormData + Bearer Token |
| 参数传递 | 将 file_id 封装为 JSON 字符串 |
| 状态管理 | ref + 条件渲染 |
| 错误处理 | 检查 ret.code !== 0 |
💼 大厂面试题延伸
-
Q:为什么上传文件要用
FormData,而不是直接JSON.stringify(file)?
A:因为文件是二进制数据,FormData支持multipart/form-data编码,可携带二进制流;而 JSON 只能传字符串。 -
Q:
FileReader.readAsDataURL()的原理是什么?有什么缺点?
A:它将文件读取为 Base64 字符串,优点是可直接用于<img src>;缺点是体积膨胀约 33%,且大文件会阻塞主线程。 -
Q:如何防止 PAT Token 泄露?
A:前端无法完全隐藏 Token,因此应:- 在 Coze 后台限制 Token 权限(仅允许特定 workflow)
- 设置 Referer 白名单
- 考虑通过自己的后端代理请求(更安全)
-
Q:Coze 返回的图片 URL 有效期多久?如何长期保存?
A:临时链接通常 10~30 分钟失效。如需持久化,应在前端或后端下载图片并存储到 OSS。
🌟 结语
这个小项目虽简单,却完整覆盖了 现代 Web AI 应用的核心链路:
用户交互 → 数据上传 → AI 调用 → 结果展示。
借助 Coze 这样的平台,前端工程师也能轻松集成强大 AI 能力,不再只是“切图仔”。
GitHub 开源地址:欢迎 Star!(可自行补充)
在线体验:部署后可提供 demo 链接
希望这篇文章对你有启发!如果你也有有趣的 AI 小应用,欢迎在评论区分享 😊
作者:饶世豪 标签:#Vue3 #Coze #AIGC #前端工程化 #低代码AI