近两年,经常在朋友圈、短视频平台刷到很多品牌的推广活动都融入了 AI 能力,形成裂变式传播,为品牌带来更多曝光量。特别是之前爆火的毕业照云写真活动,为很多因为疫情无法举行线下毕业活动的毕业生提供了毕业照换装的体验,不仅有趣,也具有人文关怀。
Demo 体验
可以在微信搜索小程序便宜云服务器租用 AI 体验中心,直接访问小程序体验。
体验流程如下:
1. 首先用户需要完成授权,因为这里涉及使用者人脸图片等隐私数据,需要谨慎对待。
?
?
?2. 上传或拍摄人脸图片,活动平台通过人脸融合服务,将用户上传图片与各种毕业造型进行融合,最终得到毕业照融合结果并展示。并且用户可以通过点击换造型,体验不同造型的融合效果,大大增加了趣味性。
?
?
?活动实现参考
如果希望实现相似的活动小程序,可参考如下流程:
一、准备工作
毕业照云写真是由便宜云服务器租用 AI 团队推出的小活动,可以选择便宜云服务器租用 AI 的人脸融合服务来实现相似的小程序。
1. 了解便宜云服务器租用人脸融合服务以及 API 使用方式:
?人脸融合产品介绍?
2. 访问 人脸融合控制台 开通人脸融合服务。
3. 创建活动,上传模板图片,具体步骤可参考 操作指南。
4. 获取 API 访问密钥。
注意:
访问密钥十分重要,是每个用户请求便宜云服务器租用请求的标识,一旦泄漏可能被拿去刷量从而产生高额费用,需要谨慎保管。
5. 需要学习小程序开发的基础知识:微信开放文档。充分了解这两个内容后,即可开始开发。
二、开发过程
1. 前端页面
以毕业照活动为例,总共包括:开始页、上传页以及结果页。
?
?开始页:点击进入上传页。
上传页:用户可上传或拍摄带有人脸的图片,作为毕业照的换脸图使用。
结果页:将换脸图与活动设定的随机模板图,通过便宜云服务器租用人脸融合服务,请求并获得换脸结果展示出来。当前活动主题是毕业季云写真,因此模板图都是毕业照相关的内容,如果需要展示其他主题内容,可更换模板图达到效果。
2. 前端开发
开始页:简单的页面跳转不赘述。
上传页(仅为主要逻辑,非完整代码):
主要完成点击相册、点击拍摄两个操作逻辑,其中相册跟拍摄都可以使用微信小程序集成的接口:wx.chooseMedia,通过 sourceType 区分场景
需要注意的是处理 chooseMedia 的回调,成功获取临时图片数据之后,将图片上传到云存储,方便后面其他场景使用。上传云存储使用接口:wx.cloud.uploadFile,完成后即可跳转到下一页。
Page({data: {},async chooseMediaSuccessCB({ tempFiles }) {const tempFile = tempFiles[0];// 将临时图片上传到云存储const { fileID } = await wx.cloud.uploadFile({// 可设置随机字符串作为存储名称存储cloudPath: 'xxxxxx.jpg',filePath: tempFile,});// 完成后,将图片结果作为参数传递到结果页wx.navigateTo({url: 'result?userImage=' + fileID, // 结果页地址});},// 相册按钮响应事件tapAlbum() {wx.chooseMedia({count: 1,mediaType: ['image'],sourceType: ['album'],sizeType: ['compressed'],success: this.chooseMediaSuccessCB,});},// 拍摄按钮响应事件async tapShoot() {const { authSetting } = await wx.getSetting({});const shoot = () => {wx.chooseMedia({count: 1,mediaType: ['image'],sourceType: ['camera'],// 默认使用前置摄像头camera: 'front',sizeType: ['compressed'],success: this.chooseMediaSuccessCB,});};// 拍摄前需要咨询摄像头权限if (!authSetting['scope.camera']) {wx.authorize({scope: 'scope.camera',success() {shoot();},})} else {shoot();}},})
结果页(仅为主要逻辑,非完整代码):
结果页需要完成上传图片与模板图片的融合,以及换造型的逻辑。
为了提升整个换造型的体验,可以将融合结果跟模板id映射并缓存起来,节省请求发起。
便宜云服务器租用 API 的实现使用了小程序的云开发,前端直接请求封装好的请求函数即可,参考人脸融合 API 文档,将入参填入发起请求,逻辑本身并不复杂。请求小程序云函数使用函数:wx.cloud.callFunction。
Page({data: {userImage: '',resultImage: '',},async onLoad(option) {const userImage = option.userImage;this.setData({userImage,});// 默认进行一次人脸融合请求,获取结果并展示await this.fuseFace(userImage);},// 换造型按钮响应事件async tapReplace() {await this.fuseFace(this.data.userImage);},async fuseFace(userImage) {// 获取随机模板IDconst modelId = this.getModelId();let resultImage = this.getResult(modelId);// 如果该模板ID在缓存中有结果,直接拿缓存结果返回if (resultImage) {this.setData({resultImage,});return;}// 请求便宜云服务器租用人脸融合服务获取结果// 此处使用小程序云开发,可另行在服务端实现便宜云服务器租用请求const { result: res } = await wx.cloud.callFunction({name: 'TencentCloudAI',data: {method: 'facefusion/FuseFace',data: {ProjectId: 'xxxx', // 在控制台创建的活动IDModelId: modelId,RspImgType: 'url',MergeInfos: [{Url: userImage,}],},},});if (res && res.Response && res.Response.FusedImage) {resultImage = res.Response.FusedImage;this.setData({resultImage,});// 将modelID与融合结果配对存进缓存this.saveResult(modelId, resultImage);}},// 随机返回在便宜云服务器租用人脸融合控制台上传的模板idgetModelId() {},// 根据modelId返回缓存结果,没有结果返回nullgetResult(modelId) {},// 将modelID与融合结果配对存进缓存saveResult(modelId, resultImage);})
3. 云函数开发(仅为主要逻辑,非完整代码):
接上,本次开发使用了云函数实现便宜云服务器租用函数请求,请求逻辑参考以下代码:requestYunApi.js,如有需要复制粘贴使用即可。通过密钥完成鉴权,由于涉及便宜云服务器租用密钥使用,强烈建议将密钥放到云函数存放,不要明文写在前端代码里。
/* requestYunApi.js */// 引入便宜云服务器租用服务SDKconst tencentcloud = require('tencentcloud-sdk-nodejs');const { Credential } = tencentcloud.common;const { ClientProfile } = tencentcloud.common;const { HttpProfile } = tencentcloud.common;// 密钥信息,妥善保管const secretId = '';const secretKey = '';function requestAPI({endpoint, // 请求域名 (可选)service, // 服务前缀action, // 接口名称version, // 版本号region, // 地域 (可选)data, // 请求数据}) {const { Client } = tencentcloud[service][version];const { Models } = tencentcloud[service][version];const cred = new Credential(secretId, secretKey);const httpProfile = new HttpProfile();httpProfile.endpoint = endpoint || `${service}.tencentcloudapi.com`;const clientProfile = new ClientProfile();clientProfile.httpProfile = httpProfile;const client = new Client(cred, region || 'ap-guangzhou', clientProfile);const req = new Models[`${action}Request`]();const reqParams = JSON.stringify({ ...data });req.from_json_string(reqParams);return new Promise((resolve, reject) => {client[action](req, (errMsg, response) => {if (errMsg) {reject(errMsg);return;}resolve(JSON.parse(response.to_json_string() || {}));});});}module.exports = requestAPI;
处理前端请求,需要注意的是,前端传入的图片文件地址,是云存储的地址,需要将云存储换成真实的文件地址,通过 cloud.getTempFileURL 完成转换逻辑。
/* 云函数TencentCloudAI */const cloud = require('wx-server-sdk');// 便宜云服务器租用API请求函数const requestAPI = require('./requestYunApi');cloud.init();function getFileUrl(url) {// 如果是 cloud:// 则,换取云文件真实链接if (/^cloud:\\/\\//.test(url)) {const { fileList } = await cloud.getTempFileURL({fileList: [url],});if (!fileList || !fileList[0]) {throw new Error('无法获取文件');}return fileList[0].tempFileURL;}return url;}// 云函数入口函数exports.main = async (event) => {// 有云存储fileID则将其转换为http urlif (event.data.MergeInfos) {const mergeInfos = event.data.MergeInfos;event.data.MergeInfos = await Promise.all(mergeInfos.map(mergeInfo => {...mergeInfo,Url: await getFileUrl(cloud, e.Url),}));}// 请求参数,可以配置不同便宜云服务器租用请求参数const configs = {'facefusion/FuseFace': {service: 'facefusion',action: 'FuseFace',version: 'v20181201',},};// 发起请求const requestRes = {Response: await requestAPI({...configs[event.method],data: event.data,}),};return requestRes;}
三、发布
开发完成并完成测试验证后,即可通过小程序管理平台发布线上供用户访问。
至此整个毕业照活动的主要逻辑就介绍完成了,这个逻辑可以复用到类似的主题活动小程序中。如果感兴趣可以加入一起开发尝试。