引言
一个android端的程序员,经常会冒出一些好玩的点子,特别是现在AI技术发展的那么快,想过把自己的一些好玩的idea做成app,但是目前国内app上线的流程非常麻烦,需要申请软件著作,还有一大堆审核。所以我想先做小程序吧,既能承载我需要的功能,也不需要非常麻烦的审核。(其实后面微信小程序上线也碰到一些问题)
源起
一直以来对中国传统文化感兴趣,特别是对汉服挺感兴趣的,但是又舍不得钱自己去买汉服穿,想着要是能结合AI能力,让自己或者朋友能很方便的体验到穿汉服的乐趣那该多好。怎么才能让别人很方便的体验到汉服呢?首先想到的是用AI的换脸技术,先找到一批/生成一批中国各个朝代的底图,然后一键换上自己的脸。
简单流程
流程比较简单,但是这样的话可玩性太差了,最好对底图进行分类,让用户有可以有不同的选择,比如性别分类:小孩,男子,女子。社会地位分类:帝王、公主、皇后、文臣、武将、平民等,还有朝代分类。根据这种想法给了三个不同的分类方式,方便用户选择不同的角色进行体验。
朝代 | 角色 | 性别 |
---|---|---|
商周 | 神话 | 孩童 |
秦 | 帝后 | 女子 |
汉 | 皇室 | 男子 |
三国 | 文臣 | |
隋唐 | 武将 | |
... | 平民 | |
民国 | 妖魔 |
除了上面的三种分类之外,对于每一个角色,也可能有不同的服装,简单的例子:古代官员 有朝服 有便服。并且对于同一个角色应该设置不同镜头的底图,比如远景 近景 中景 方便用户选择。
梳理之后的流程图如下:
设计和实现
源起里面已经把想要的主要功能梳理清楚了,可以提供给用户选择不同朝代、不同地位、不同性别的底图进行换脸然后生成自己想要的图片。根据上面的主要功能给出数据结构设计和技术选型。
- 技术选型
由于之前一直做的客户端开发,熟悉的语言是java/kotlin没有接触过微信小程序相关的,所以在网上搜了一波,最后选择uniapp来做小程序,选择uniapp的原因:
- 使用vue语法比较简单,大概看了一两晚 基本上能够动手写。
- uniapp提供了多端能力,后面要做抖音小程序或者原生的app方便。
- 最重要的是可以使用unicloud能力,使用云函数,(不熟悉后台开发的福音)而且每月的费用比较低,我选的是5/月最低的。
明确使用uniapp来开发小程序后,前端/后端一个人就可以搞定了,使用unicloud云,不用自己部署服务器,对之前客户端开发的人来说也很容易上手。
- 数据库设计
由于换脸是依赖底图的,并且还有朝代、性别、社会地位等区别。
- 角色数据表
字段 | 类型 | 描述 |
---|---|---|
name | string | 姓名(花木兰) |
dynasty | string | 朝代(隋唐/宋朝等) |
role | string | 角色(皇帝/平民等) |
gender | int | 性别(男/女/儿童) |
image_list | string[] | 底图列表 |
intro | string | 角色介绍 |
use_count | int | 用户使用次数 |
- 分类数据表
因为要对角色进行通过朝代、性别、地位分类,所以需要抽出一个分类表
字段 | 类型 | 描述 |
---|---|---|
category | string | dynasty/gender/social用来区分大类 |
image | string | 分类的封面图片 |
title | string | 隋唐 |
3、换脸能力接入
如何接入换脸能力呢?可以参考这个图像流,具体的如何接入,可以私聊我。
实现效果
1、首页
2、详情页
3、生成结果页
4、生成海报
引导弹框
上新角色时如何让用户快速的看到角色,或者上新功能时如何让用户快速的体验新功能,这块做了一个引导弹框管理类,用来管理弹框。
1、引导弹框
2、引导弹框管理设计
当有新功能/新角色上线时 引导用户去体验,如果要做成可配置化,就需要解藕,当不同活动上线的时候也可以使用。
活动弹框包含两个部分,第一个是活动图片,第二个是关闭按钮,图片可以通过下发来配置,但是图片的点击跳转,最好也能够通过配置下发,关闭按钮的逻辑是统一的,点击之后就关闭当前弹框。
-
弹框展示逻辑
- 对每个用户同一个弹框只展示一次,用户点击/包括关闭/跳转之后都不再展示。
- 弹框是否展示逻辑保存在本地,如果用户移除了小程序,下次打开小程序时还是会展示。(不放服务端)
-
弹框数据结构
id image type routerUrl times priority 弹框的唯一标识 活动图片 1:功能dialog2:新角色dialog 跳转详情页的路径 弹框频次默认1次 弹框展示的优先级/优先级越高,越先展示 -
弹框列表
- dialog_list,当配置了多个弹框时,会根据优先级从前往后遍历弹框,找到未使用的弹框进行弹出。(频控逻辑:一天只弹一个弹框)
dialog1 | dialog2 | dialog3 | ... | dialogn |
---|
3、实现
- 弹框管理器
javascript
//用于弹框的频控管理类
export function canShowDialogById(id) {
//判断弹框是否可以展示
const list = uni.getStorageSync('dialog_id_list') || [];
// 判断 list 中是否包含 id
const isIdInList = list.includes(id);
// 如果 id 存在于 list 中,则返回 false;否则返回 true
return !isIdInList;
}
//保存弹框展示
export function saveDialogTimeById(id) {
uni.setStorageSync('dialog_id_list', id);
}
export function getDialogItem(list) {
if (!list) {
return null;
}
// 使用 find 方法查找符合条件的 item
const foundItem = list.find(item => {
return item && item._id && canShowDialogById(item._id);
});
console.log("get dialog item", foundItem);
return foundItem || null;
}
- 弹框类
xml
<template>
<view class="mask"></view>
<view class="modal">
<image class="modal-image" :src="dialogItem.image" mode="widthFix" @click="gotoDetail"></image>
<image class="close-button" src="/static/images/icon_close.png" @click="closeModal"></image>
</view>
</template>
<script>
export default {
name: "custom-dialog",
props: {
dialogItem: {
type: Object,
required: true
}
},
data() {
return {
};
},
methods: {
closeModal() {
console.log("close modal");
this.$emit('closeModal');
},
gotoDetail() {
this.$emit('gotoDetail');
},
}
}
</script>
<style>
.mask {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
z-index: 9999;
}
.modal {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 80vw;
/* 宽度为屏幕宽度的80% */
text-align: center;
z-index: 19999;
}
.modal-image {
width: 100%;
height: auto;
/* 图片高度自适应 */
z-index: 19999;
}
.close-button {
margin-top: 20px;
/* 调整关闭按钮与图片间距 */
width: 40px;
/* 调整关闭按钮的大小 */
height: 40px;
/* 调整关闭按钮的大小 */
display: block;
margin: 0 auto;
z-index: 19999;
/* 将关闭按钮水平居中 */
}
</style>
推荐角色
当用户生成当前角色后,给用户推荐其他角色,让整个流程更加完善,提高用户体验,不然用户生成一个角色之后又要返回去选其他角色
1、通过算法推荐,可以动态调整。
2、直接指定,方便配置下发。
1、推荐算法
1、活动角色
如果是活动角色,从活动列表中获取同性别角色。如果没有同性别角色,获取其他性别角色。
2、其他角色
优先找同朝代,同身份、同性别的角色,如果没有同身份的角色、找同性别不同身份的角色,如果没有同性别、不同身份的角色 查找其他朝代同性别、同身份的角色。
暂时无法在飞书文档外展示此内容
3、朝代关联关系
朝代 | 关联 |
---|---|
清朝 | 民国 |
明朝 | 宋朝 |
... | ... |
4、推荐角色剔除
对用户已经生成过的角色不再推荐,从推荐列表中进行剔除,不然达不到让用户体验多个角色的目标。
2、手动配置推荐角色
直接在数据库中关联下发推荐的角色,下发的推荐角色不可以更改,但是可以定制化推荐。
perl
{
"dynasty": "商周",
"dynasty_label": "商周",
"gender": "male",
"image_list": [
"https://env-00jxh1m2drwc.normal.cloudstatic.cn/hot-style/%E5%95%86/%E5%95%86%E5%91%A8-%E5%A7%AC%E5%8F%9101.png",
"https://env-00jxh1m2drwc.normal.cloudstatic.cn/hot-style/%E5%95%86/%E5%95%86%E5%91%A8-%E5%A7%AC%E5%8F%9102.png"
],
"recommend_list": [
"1",
"2"
],
"intro": "姬发",
"name": "姬发",
"role": "武将"
"count":0
}
3、新增角色生成次数数据
每个角色生成时,上报一条生成数据,用于推荐算法的使用,推荐时可以从其他用户使用最多的角色里面进行选择。新增count字段。用于统计角色生成次数
perl
{
"dynasty": "商周",
"dynasty_label": "商周",
"gender": "male",
"image_list": [
"https://env-00jxh1m2drwc.normal.cloudstatic.cn/hot-style/%E5%95%86/%E5%95%86%E5%91%A8-%E5%A7%AC%E5%8F%9101.png",
"https://env-00jxh1m2drwc.normal.cloudstatic.cn/hot-style/%E5%95%86/%E5%95%86%E5%91%A8-%E5%A7%AC%E5%8F%9102.png"
],
"intro": "姬发",
"name": "姬发",
"role": "武将"
"count":0
}
4、随机推荐算法
用户已经使用过,如何推荐,用户未使用过,如何推荐。
-
根据选择偏好比例推荐:
- 根据用户选择历史人物的性别和朝代比例,结合用户的选择偏好,给出推荐列表。
-
避免重复推荐:
- 确保推荐的历史人物不与用户已选择过的历史人物角色重复。
广告接入
广告接入采用尽量少打扰用户的方式,用户进入时不会看到广告,只有其他操作时才让用户看广告。
场景 | 场景截图 | 广告类型 | 广告样式 | 时机 | 频控 | 对应代码 |
---|---|---|---|---|---|---|
列表页 | 原生广告-横幅 | 用户下滑获取更多时,插入广告,首页默认展示3个底图,上滑时 是否可以在第5个位置放广告?其他页面类似。 | ||||
合成中 | 原生广告-格子 | 合成时放在合成文案的下面 | 每次合成时都展示 | // wxml文件 | ||
开始合成 | 激励广告 | 用户点击开始穿越的时候展示只有看完广告之后才可以开始穿越,不然不可以穿越 | 看一次广告可以穿越几次? |
小程序上线碰到的问题
1、小程序备案
由于没有公司,也不想做个人小程序,所以弄了个人工商的小程序,按照微信的收费工商的一年300元。万能淘宝可以解决,懂的都懂。
2、算法备案
由于小程序涉及到换脸功能,需要AI算法备案,这个当时愁死了,但是最后还是解决了,也没花啥钱,在淘宝上问了一家开口5888元,最后不到100元搞定。
最后
喜欢的同学可以扫码体验一下,有想交流的也可以留言。