随着 AI 技术的快速发展,前端开发者可以轻松地将强大的人工智能能力集成到 Web 应用中,打造出富有创意和互动性的产品。本文分享一个有趣的 AI 应用:用户上传宠物(或人物)照片,选择队服颜色、编号、位置、持杆手和风格等参数,即可生成一张该照片主角化身为冰球运动员的形象图。
这个应用的核心在于前端使用 Vue3 实现用户交互和数据处理,后端能力则完全依赖 Coze(扣子)平台的 Workflow API。Coze 提供了可视化工作流编排和强大的图像生成能力,我们只需通过 API 调用即可完成复杂 AI 任务,无需自己训练模型或部署服务。
整个应用代码简洁,核心逻辑不到 200 行,却实现了完整的上传、预览、参数配置和生成流程。下面我们一步步拆解实现细节。
应用功能概述
- 上传照片:支持本地图片选择,并立即显示预览。
- 参数配置:队服编号、颜色、位置(守门员/前锋/后卫)、持杆手(左手/右手)、生成风格(写实、乐高、国漫等)。
- 生成图像:点击“生成”按钮,上传图片到 Coze,调用预配置的工作流,返回生成的冰球运动员形象。
- 状态反馈:实时显示“上传中”“生成中”等状态,提升用户体验。
这个应用特别适合分享到社交圈,上传自家宠物照片生成冰球选手形象,趣味性十足。
技术栈与准备工作
-
前端框架:Vue3 + Composition API +
-
AI 能力:Coze 平台(国内版 api.coze.cn)
-
关键 API:
- 文件上传:api.coze.cn/v1/files/up…
- 工作流运行:api.coze.cn/v1/workflow…
准备步骤:
- 在 Coze 平台创建并发布一个工作流,输入参数包括图片(文件类型)和文本参数(如 style、position 等),输出为生成的图像 URL。
- 创建 Personal Access Token (PAT),用于 API 认证。
- 在 Vue 项目中通过环境变量存储 PAT(推荐使用 .env 文件)。
核心实现:图片本地预览
图片上传前立即预览是优秀用户体验的关键。用户选择大文件时,上传需要时间,预览能让用户确认选对了图片。
Vue3 中,我们使用原生 FileReader API 将文件读取为 Base64 DataURL,直接绑定到 的 src。
关键代码:
vue
const uploadImage = ref(null); // 绑定 <input type="file">
const imgPreview = ref(''); // 预览 URL
const updateImageData = () => {
const input = uploadImage.value;
if (!input.files || input.files.length === 0) return;
const file = input.files[0];
const reader = new FileReader();
reader.readAsDataURL(file); // 异步读取为 Base64
reader.onload = (e) => {
imgPreview.value = e.target.result; // data:image/jpeg;base64,...
};
};
模板部分:
vue
<input type="file" ref="uploadImage" accept="image/*" @change="updateImageData" />
<img :src="imgPreview" alt="预览" v-if="imgPreview" />
这样,用户选择图片后立即看到预览,无需等待上传。
小贴士:Base64 编码会增加约 33% 的数据体积,仅适合预览和小图传输。大文件上传仍推荐原文件。
文件上传到 Coze
Coze 的图像生成工作流通常需要文件类型输入。我们不能直接传 Base64,而需先上传文件到 Coze 服务器,获取 file_id。
上传接口使用 FormData + fetch:
JavaScript
const uploadUrl = 'https://api.coze.cn/v1/files/upload';
const patToken = import.meta.env.VITE_PAT_TOKEN;
const uploadFile = async () => {
const formData = new FormData();
const input = uploadImage.value;
if (!input.files || input.files.length === 0) return;
formData.append('file', input.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
};
注意:Header 只需 Authorization,无需 Content-Type(浏览器会自动设置 multipart/form-data)。
调用 Coze Workflow 生成图像
上传成功后,获取 file_id,将其作为参数传入工作流。
工作流运行接口:
JavaScript
const workflowUrl = 'https://api.coze.cn/v1/workflow/run';
const workflow_id = '你的workflowID';
const parameters = {
picture: file_id, // Coze 会自动识别 file_id 为文件
style: style.value,
position: position.value,
shooting_hand: shooting_hand.value,
uniform_color: uniform_color.value,
uniform_number: uniform_number.value,
};
const res = await fetch(workflowUrl, {
method: 'POST',
headers: {
'Authorization': `Bearer ${patToken}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
workflow_id,
parameters
}),
});
const ret = await res.json();
if (ret.code !== 0) {
status.value = ret.msg;
return;
}
const data = JSON.parse(ret.data); // Coze 返回 data 为字符串 JSON
imgUrl.value = data.data;
注意:如果工作流输入参数为文件类型,直接传 file_id(字符串)即可,Coze 会自动转换为内部 URL。有些情况下需传对象 { file_id: xxx },请根据你的工作流输入参数类型调整。
完整模板与状态管理
模板中我们使用响应式变量管理状态:
vue
const status = ref(''); // 状态提示
const imgUrl = ref(''); // 生成结果 URL
const generate = async () => {
status.value = "图片上传中...";
const file_id = await uploadFile();
if (!file_id) return;
status.value = "图片上传成功,正在生成中...";
// ... 调用 workflow
};
输出区域:
vue
<div class="output" v-if="imgUrl">
<img :src="imgUrl" alt="生成的冰球运动员形象" />
</div>
<div v-if="status">{{ status }}</div>
样式与布局优化
使用 Flex 布局实现左右结构:左侧输入区(上传 + 参数),右侧输出区。样式使用 scoped,避免污染全局。
部分关键样式:
CSS
.container { display: flex; height: 100vh; }
.input { min-width: 330px; display: flex; flex-direction: column; }
.output { width: 100%; display: flex; justify-content: center; align-items: center; }
.generated { width: 400px; height: 400px; border: 1px solid black; }
完整代码示例
以下是完整的 App.vue
vue
<template>
<div class="container">
<div class="input">
<div class="file-input">
<input type="file" ref="uploadImage" accept="image/*" @change="updateImageData" />
</div>
<img :src="imgPreview" alt="预览" v-if="imgPreview" />
<div class="generate">
<button @click="generate">生成</button>
</div>
</div>
<div class="output">
<div class="generated">
<img :src="imgUrl" alt="结果" v-if="imgUrl" />
<div v-if="status">{{ status }}</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue';
const uploadUrl = 'https://api.coze.cn/v1/files/upload';
const workflowUrl = 'https://api.coze.cn/v1/workflow/run';
const workflow_id = '你的workflowID';
const patToken = import.meta.env.VITE_PAT_TOKEN;
// 响应式数据(参数、状态、URL)省略,与原代码一致
const generate = async () => { /* 如上实现 */ };
const uploadFile = async () => { /* 如上实现 */ };
const updateImageData = () => { /* 如上实现 */ };
const uploadImage = ref(null);
const imgPreview = ref('');
</script>
<style scoped>
/* 样式代码与原一致 */
</style>
安全与优化建议
- Token 安全:PAT 放在环境变量中,生产环境使用后端代理,避免暴露。
- 错误处理:完善网络错误、超时等异常捕获。
- 加载状态:生成过程中可添加 loading 动画。
- 图片大小限制:前端可校验文件大小,避免上传超大文件。
- 流式响应:如果工作流支持流式,可改为 stream 模式实时显示进度。
结语
通过 Vue3 + Coze API,我们仅用前端代码就实现了一个完整、有趣的 AI 图像生成应用。这充分展示了无服务器 AI 开发的便利性:前端负责交互,Coze 负责复杂 AI 逻辑。
感兴趣的同学可以基于此扩展更多功能,比如支持多人照片、批量生成,或集成分享到微信/微博。AI 时代,前端开发者大有可为,赶紧试试吧!