Android程序员怎么从零到一开发一个自己的AI小程序并上线

引言

一个android端的程序员,经常会冒出一些好玩的点子,特别是现在AI技术发展的那么快,想过把自己的一些好玩的idea做成app,但是目前国内app上线的流程非常麻烦,需要申请软件著作,还有一大堆审核。所以我想先做小程序吧,既能承载我需要的功能,也不需要非常麻烦的审核。(其实后面微信小程序上线也碰到一些问题)

源起

一直以来对中国传统文化感兴趣,特别是对汉服挺感兴趣的,但是又舍不得钱自己去买汉服穿,想着要是能结合AI能力,让自己或者朋友能很方便的体验到穿汉服的乐趣那该多好。怎么才能让别人很方便的体验到汉服呢?首先想到的是用AI的换脸技术,先找到一批/生成一批中国各个朝代的底图,然后一键换上自己的脸。

简单流程

流程比较简单,但是这样的话可玩性太差了,最好对底图进行分类,让用户有可以有不同的选择,比如性别分类:小孩,男子,女子。社会地位分类:帝王、公主、皇后、文臣、武将、平民等,还有朝代分类。根据这种想法给了三个不同的分类方式,方便用户选择不同的角色进行体验。

朝代 角色 性别
商周 神话 孩童
帝后 女子
皇室 男子
三国 文臣
隋唐 武将
... 平民
民国 妖魔

除了上面的三种分类之外,对于每一个角色,也可能有不同的服装,简单的例子:古代官员 有朝服 有便服。并且对于同一个角色应该设置不同镜头的底图,比如远景 近景 中景 方便用户选择。

梳理之后的流程图如下:

设计和实现

源起里面已经把想要的主要功能梳理清楚了,可以提供给用户选择不同朝代、不同地位、不同性别的底图进行换脸然后生成自己想要的图片。根据上面的主要功能给出数据结构设计和技术选型。

  1. 技术选型

由于之前一直做的客户端开发,熟悉的语言是java/kotlin没有接触过微信小程序相关的,所以在网上搜了一波,最后选择uniapp来做小程序,选择uniapp的原因:

  • 使用vue语法比较简单,大概看了一两晚 基本上能够动手写。
  • uniapp提供了多端能力,后面要做抖音小程序或者原生的app方便。
  • 最重要的是可以使用unicloud能力,使用云函数,(不熟悉后台开发的福音)而且每月的费用比较低,我选的是5/月最低的。

明确使用uniapp来开发小程序后,前端/后端一个人就可以搞定了,使用unicloud云,不用自己部署服务器,对之前客户端开发的人来说也很容易上手。

  1. 数据库设计

由于换脸是依赖底图的,并且还有朝代、性别、社会地位等区别。

  1. 角色数据表
字段 类型 描述
name string 姓名(花木兰)
dynasty string 朝代(隋唐/宋朝等)
role string 角色(皇帝/平民等)
gender int 性别(男/女/儿童)
image_list string[] 底图列表
intro string 角色介绍
use_count int 用户使用次数
  1. 分类数据表

因为要对角色进行通过朝代、性别、地位分类,所以需要抽出一个分类表

字段 类型 描述
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、实现
  1. 弹框管理器
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;
}
  1. 弹框类
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、随机推荐算法

用户已经使用过,如何推荐,用户未使用过,如何推荐。

  1. 根据选择偏好比例推荐

    1. 根据用户选择历史人物的性别和朝代比例,结合用户的选择偏好,给出推荐列表。
  2. 避免重复推荐

    1. 确保推荐的历史人物不与用户已选择过的历史人物角色重复。

广告接入

广告接入采用尽量少打扰用户的方式,用户进入时不会看到广告,只有其他操作时才让用户看广告。

场景 场景截图 广告类型 广告样式 时机 频控 对应代码
列表页 原生广告-横幅 用户下滑获取更多时,插入广告,首页默认展示3个底图,上滑时 是否可以在第5个位置放广告?其他页面类似。
合成中 原生广告-格子 合成时放在合成文案的下面 每次合成时都展示 // wxml文件
开始合成 激励广告 用户点击开始穿越的时候展示只有看完广告之后才可以开始穿越,不然不可以穿越 看一次广告可以穿越几次?

小程序上线碰到的问题

1、小程序备案

由于没有公司,也不想做个人小程序,所以弄了个人工商的小程序,按照微信的收费工商的一年300元。万能淘宝可以解决,懂的都懂。

2、算法备案

由于小程序涉及到换脸功能,需要AI算法备案,这个当时愁死了,但是最后还是解决了,也没花啥钱,在淘宝上问了一家开口5888元,最后不到100元搞定。

最后

喜欢的同学可以扫码体验一下,有想交流的也可以留言。

相关推荐
呵呵哒( ̄▽ ̄)"8 分钟前
vue.js 展示树状结构数据,动态生成 HTML 内容
开发语言·前端·javascript·vue.js
安冬的码畜日常9 分钟前
【CSS in Depth 2 精译_035】5.5 Grid 网格布局中的子网格布局(全新内容)
前端·css·css3·网格布局·css布局·子网格·subgrid
JuneTT11 分钟前
uniapp 常用高度状态栏,导航栏,tab栏,底部安全高度
前端·javascript·uni-app
i801338 分钟前
delphi制作漂亮的农历窗体(IntraWeb+Layui的完美结合)
前端·javascript·layui
南瓜啊38 分钟前
【VUE】状态管理:Pinia组件、Cookie组件
前端·javascript·vue.js
@月落1 小时前
获取douyin商品详情:API接口的力量
java·前端·数据库
大青虫1 小时前
关于uniapp wifi调用走过的坑
前端·uni-app
媛媛要加油呀1 小时前
web功能测试总结(自用分享)
运维·服务器·前端·功能测试
hakesashou1 小时前
python命令行怎么换行
java·前端·python
**之火2 小时前
前端项目package.json文件对象属性介绍
前端·配置