白日梦AI绘画app开发碎碎念

7.3k 词

演示视频如下:

日志(一) 记于8.1

本博客系列主要记载ai绘画安卓app开发过程,预计将使用uni-app开发前端,后端使用python提供接口,链接数据库
开个头,明天再努力

安装HBuilderX

在官网下载压缩包解压即可

创建项目

创建uni-app项目,选择默认,文件格式如下

  • pages存储图形界面
  • static存静态资源
  • pages.json注册页面以及跳转,全局样式

运行

对于浏览器点击运行即可

手机运行

  • 最初尝试真机运行,本人使用meizu18,在启用开发者模式,并允许usb调试的情况下,电脑与手机接入相同网络,但仍无法检测到设备
  • 后来发现还要下载adb,于是完成下载并在HBuilder X指定路径后检测到了设备
  • 连接设备后,在手机上允许通过usb安装软件,自动安装HBuilder后即可正常调试

一想到那么多问题我就头大,大创开摆

上午

uni-app的基础语法

  • 在非uni块中不能使用网页标签,因为在真实环境中不生效
  • pages文件最靠前的为index页面,即首个页面
  • 将div、span换成view、text使用,以免跨平台不生效,view是div的效果,text是span的效果
    • text具有多种属性,如selectable控制该文本是否可选
  • 块的长宽单位可使用rpx,默认宽最大750rpx,高为1314rpx;使用rpx能使得相应块随屏幕自动变化
  • scroll-view用以封装需要滑动的块,指定属性scroll-x或者scroll-y即可
  • swiper:走马灯,swiper-item为走马灯的一个元素
  • image是img的替代品,提供多种图片显示模式
  • 对于诸如button之类的组件,原生组件样式较少,可以使用uView组件库

下午

uni-app的基础语法

  • navigator当跳转用,有多种跳转模式,例如navigate将保留上一级页面,而redirect不会保留
  • tabBar用以表示app底部菜单栏,在pages中配置,每一个item均可以设置图标、文本、跳转页面等
    • 需注意设置tabBar页面后,naviagte只能跳转到非tabBar的page去
    • reLaunch可以跳转,其本质是进入全新的页面,原有页面栈清空
  • form表单提交多使用submit更方便
  • 自定义组件在components文件夹下创建a文件夹并创建a.vue即可自动使用相应组件
    • 利用props实现组件的变化

完成了底部导航栏的配置

日志(二)丢失

日志(三) 记于8.2

上午

使用uView样式不生效

结果发现他的样式用的scss,在app.vue的style引用时应该给style加上lang=“scss”

u-botton未生效

最初配置pages中的easycom时,配置错误,修改正确后,由于HX为了保证调试的性能,未及时更新该配置,重启即可。

卡片效果绘制

由于自己的uView不知道为什么缺失了u-card,干脆就自己画了,设置背景、边框圆角、边框颜色即可

mmd画了一上午,就一个登录页面

下午

mmd,被py的各种包折磨麻了

后端

考虑到后端要使用神经网络,故采取python作为后端语言

  • 安装flask,提供接口
  • 安装pymysql、flask-sqlalchemy对数据库进行操纵
  • 考虑到最后要部署在服务器上,索性在已有环境安装,结果包老是报错,将部分包删除或修改版本后最终配置成功

flask

  • @app.route指定路由,函数紧跟
  • request.args.get获取相应请求携带的数据
  • 直接return就可返回结果

db

  • 创建db对象,SQLAlchemy(利用app.config完成配置)
  • 创建与表映射的对象便于操作
  • 添加操作
    • 拿到数据用对应对象包裹
    • 将该对象添加到db.session中
    • 将该改变同步到数据库中
    • 返回相应结果resp
  • 查询操作
    • get查找:根据主键查找
      • Object.query.get返回相应对象结果
    • filter_by查找:查询多条数据
      • Object.query.filter_by(column=condition)返回类数组
  • 更新操作
    • 先获取到相应的对象
    • 直接拿属性一改就完事
    • 然后提交
  • 删除操作
    • 查询获取相应对象
    • db.session.delete对象
    • 提交
  • 多表操作,昏!

晚上

我突然发现,原来学校的实验室的服务器不能直接对外网建立接口!!!
于是我开始尝试各种方法使得手机能够访问相应接口

电脑访问服务器local的基本原理是端口转发:服务器->电脑

思路一:直接把服务器端口转发至手机端口

  • 下载JuiceSSH,连接服务器
  • 启动相应程序
  • curl对应网址成功
  • 但是浏览器及app请求失败
  • 可能是安卓的网络配置导致的

思路二:服务器->电脑->手机

  • 在服务器启动端口转发
  • 电脑确认可以访问
  • adb reverse相应端口
  • 但手机还是不行!!!

解决不了问题,就消除问题,先采用安卓模拟器去进行开发

卧槽,老子成功了

思路二是正确的

  • 之前失败的原因是在HXadb之前调用adb命令,启动HX导致之前的adb配置消失
  • 在启动HX后在使用adb reverse即可使用手机浏览器访问
  • 之前我跟傻子一样用axios,结果nm真机不适配,然后一看uni.request简单的一批,这下请求也没问题了

日志(四) 记于8.3

上午

卡拉比丘去了

下午

傻逼uView,tm按着官网装的文件到处缺组件,安上之后样式又上一堆,真有你的哦
画图一分钟,报错两小时,HX和uView混合双打

关于uView的uToast

title无法显示

关于HBuilder的编译

  • 1个小时前,utoast的show可以正常运行
  • 一个小时后就找不到了
  • 在这期间没有对uView及相关配件做任何操作

关于HBuilder真机运行

  • uni-app自带的navigationbar在写了两小时后,奇迹般的消失了

垃圾uView

高情商:一统江湖

低情商:一捅江湖

全部改成uv-ui

日志(五) 记于8.7

对前端进行优化

  • 更换了组件库
  • 完成了用户本人信息的基本展示

后端flask学习

  • 了解了基础的数据库操作方式
  • 了解了基础的文件管理方式

stable-diffusion了解应用

  • 最初想自己写api
  • 发现网上已经有api开源代码,但是未与数据库进行联动
  • 目前的主要任务是改写api与数据库联动

日志(六) 记于8.9

基本实现了绘画功能

  • 能够实现参数的配置
  • 能够实现多模型加载与选择
  • 能够将传回的base64图像展示与保存

base64图像的保存

  • 首先利用bitmap将base64保存到指定路径
  • 由于在真机中无法直接查阅到相应文件(似乎是被隐藏了),在前端利用uniapp的图像保存到相册的功能,进行二次保存
  • 清楚第一次保存的数据

参数的展示

  • 由于扩散模型参数众多,故作了一定的简化
  • 为了能够使用Hire.fix,对多个相关参数进行了固定设置使得用户能一键得到高清优化的图像

接下来的主要任务

  • 数据库表的设计
  • 社区版面的渲染

日志(七) 记于?

增添了一些绘画可调参数

  • 引入不同风格的模型参数
  • 可启用自主训练的textual_inversion模型

完成了所有表格设计

预计将实现图像分享社区的核心功能

完成了图像的发表功能

完成了预览页面的绘制

  • 实现了分页分类查询
  • 以触底方式实现分页查询
  • 以头部tab实现分类查询
    遇到的主要问题与本博客制作时条件查询的问题一致,不同功能的查询相互转换时容易出现错误

今后主要工作

  • 详情页绘制及后端接口的书写
  • 在绘画部分引入img2img功能
  • 完善个人空间的内容布置
  • 调整色彩风格

感觉一个人做这个东西力不从心啊

日志(八) 记于?

完成了详情页面的绘制

  • 实现了基本信息的展示
    • 图像、作者、词条、发表时间
    • 点赞功能的引入与显示
    • 下载图像
    • 评论
  • 主要问题在于分页查询评论
    • 与网页端不同,评论是以触底方式分页查询的,用户并行时会出现问题
      • 当我已进入图片详情查询了评论后,若其他用户在此刻对同一图片发表评论,将导致原分页起点向后挪动
      • 此刻我触底查询后,分页查询结果将得到重复的评论,例如原评论编号1,2,3,4,现插入评论5,每页2个结果,插入前首次查询得到3,4,插入后触底查询得到3,2
      • 为解决该问题,每一次触底查询,都将额外携带参数cid,作为分页查询的起点,其范围规定在cid评论及其以前的评论
    • 与网页端不同,插入评论不能简单重新获取评论以显示新评论
      • 在已查询多页情况下,进行评论,如果选择直接查询,将导致目前页面高度减小(相关组件信息先消失,后出现),但是由于触底查询仍然存在,目前所在位置远远低于页面高度,将重复触发触底查询
      • 故将接口设置为返回该新评论的信息,并将其插入评论列表
  • 待解决的问题
    • 对评论进行回复的前端
      • 高情商:难以正确展示
      • 低情商:丑

丰富广场页面

  • 为走马灯添加按点赞、时间排序的前三图像
  • 添加条件搜索功能,为用户提供对标题的模糊搜索

添加搜索结果页面

  • 该走的分页查询都走了一遍

主要在于我不会css

qwq

日志(九) 记于?

重新更换了前端的风格

以绿色为主题,对多个页面进行重新绘制

引入图生图模块

  • 简化了一定参数
  • 当用户已完成文生图模块后,进入图生图模块将使其生成的图像作为图生图的原始图像

按点赞数查询

  • 引入了两种模式切换:时间顺序与点赞数顺序
  • 分页查询的规则做了更改
    • 由于之前只考虑了按时间顺序排列图像,故第一次获取得到的图像列表中第一个图像的iid为本次分页查询的起点,并作为条件在后续多页查询中传回接口
    • 但是当使用喜好排序时,第一次获得的图像列表很有可能不含有本次分页查询起点的iid
      • 这将导致分页查询可能遗失掉部分图像信息,例如:第一次查询时,最大iid为20,但是由于iid为20的图像可能并不能在点赞数中排第一页,故未出现在图像列表,若保持原逻辑不变,再次查询,则将永远查不到20
      • 总结:原逻辑将导致比点赞数最多图像发表时间晚的图像无法查询
    • 故修改了接口逻辑,在查询页数为1时,将额外返回本次查询得到的最大iid,该iid将作为后续页数查询的起点
    • 前端接受该iid,并在查询页数大于1时将该iid作为消息返回给接口

日志(十) 记于?

对热门模块修改

即按喜好排序

  • 问题 图片喜好排序与时间顺序排序特点不同:
    • 时间顺序排序的图片只要记录每次排序的图片编号最大值,则分页查询可通过规定iid的范围稳定进行多次查询
    • 喜好排序乱序,除了可能存在新的图片突然出现导致乱序,还存在某原图片在查询过程中喜好数量发生巨大改变导致分页已有顺序改变
      • 对于前者,我们仍可采用同时间顺序一样的解决方案
      • 对于后者,我们不得不思考变化的喜好导致变化的顺序,在不乱序的情况下,如何在前端进行信息呈现
  • 方案一 每一次查询逐步扩大per_page,相当于只查一页查得更多,以此保证前后喜好顺序不变
    • 从理论上讲,该方法从api得到的信息总是准确实时的
    • 但是不利于前端信息的呈现,因为每一次都会经历图像全部消失再出现的过程,容易误触发触底函数

    例如,我已查询两页,试图查询第三页,此时我触底发出请求,页面中的图像在接受新信息时先消失,导致视口高度降低,但我仍位于最底端,所以会反复触发触底查询

  • 方案二 每一次查询保证不重复查询已有例子,以维持图像不重复
    • 但违背了我想要按喜好排序的想法
  • 方案三 最后不得已,选择放弃分页查询,固定查询前10个获得收藏最多的图像

    我个人认为,绝对的喜好排序与分页查询本身是矛盾的,喜好是用户随机决定的,会随时间改变,而手机端的触底触发分页查询天然要求已出现的内容不可改变

    • 由于之前均为分页查询,导致之前的分支是先判断是否为第一页(第一页查询时必须返回分页起点编号)在判断排序标准
    • 现改为,首先判断排序标准,若按时间顺序排序在进行分页查询应有的判断
    • 为了使热门模块信息更为饱满,额外增加了收藏数量、图像风格、作者的信息,使得页面呈现足够丰富
    • 对于前端,依据某粉色app排行榜排版,进行重构,展现前10图像

个人空间

  • 个人空间模块展示个人信息包括:姓名、签名、作品数、收藏数、被收藏数
  • 个人空间模块内含两个分页查询:
    • 我的作品:集中我所发表的作品,逻辑同时间顺序分页查询的逻辑
    • 我的收藏:集中我所喜爱的作品,逻辑同时间顺序分页查询的逻辑
  • 但考虑到强调个人信息的展示,于是不再采用触底查询,而是使用指定块内进行分页查询,保证个人信息出现在视口内

日志(十一) 记于9.3

引入他人空间模块

基于我的空间模块渲染别人的相关消息

修改信息显示页

  • 修改整体前端风格
  • 引入绘图按钮,将页面重置于绘图界面,并保留浏览图像的生成关键词,方便用户快速使用别人的词语绘图

为所有表单增加健壮性

修改绘图api

  • 用户绘图时需上传uid和secret,检查通过后才可绘图
  • 尝试使用内存管理,使得多人同时请求,进行排队等待,但是似乎会影响使用服务器的其他人

日志(十二) 记于9.4

inpaiting

开发目标

用户通过简单的触摸涂抹,对原图部分内容进行覆盖,覆盖部分将重绘,而其余部分不变

前端图形界面展示

主要难点

  • canvas前端样式设置
    • uniapp未能提供有效的获取canvas的宽高方法,所以第一步需要手动设置参数,调整canvas的高度,宽度统一为750rpx,高度根据实际要求设置
    1
    2
    3
    4
    <canvas class="mycanvas" canvas-id="mycanvas"
    @touchstart="touchstart" @touchmove="touchmove"
    @touchend="touchend" ref='canvas'
    :style="{'height':c_height+'rpx'}"></canvas>
    • 高度的设置主要依据图像的高度,uniapp的组件image不支持本地图片,故只能使用img标签,但是img与uniapp许多api并不兼容,例如最重要的获取样式,uniapp获取样式无法得到img,返回的对象值是null
    • 所以放弃直接获取img的高度,干脆自己算,得到正确的高度,保证从视图上用户的画板和图像大小一致
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    uni.getImageInfo({
    src:_this.img_file,
    success(image){
    let hole_wh = image.width+image.height
    let imgWidth = (image.width/hole_wh)
    let imgHeight = (image.height/hole_wh)
    let img_bl = Math.ceil(750/imgWidth)
    _this.c_height = img_bl*imgHeight
    }
    })
    • 设置canvas的position固定置顶,且z-index更大,自此完成了画布和图像前端样式的重合

    该阶段主要问题在于画布随任意图像变化,保持大小一致、位置重合

  • canvas绘画函数
    • 设置初始化函数
    • 设置三个阶段的函数,touchstart、touchmove、touchend,代表起笔、运笔、收笔
      • 起笔函数,获取起点坐标并置入points数组中
      • 运笔函数,再次获取坐标并置入数组,判断数组长度,若大于2则绘画
      • 收笔函数,清空points数组
    • 设置存储函数,以jpg形式存储并转为base64编码,置入存储区

      jpg存储将保留白色背景与黑色笔画,便于后续操作

  • 后端图像处理
    • 得到base64原图与mask
    • 利用PIL获取原图宽高
    • 对mask进行resize

    原因在于,前端绘制时,对图像统一进行了宽为750rpx、高度自动的设置,图像本身进行了缩放,虽然画布与缩放后的图像完全匹配,但是,保存时,画布的图像未缩放,往往比原图像更大,故需进行比例缩放,该行为不会导致重绘相对位置发生改变,因为之前计算画布宽高用的是同样的方法,只是逆向罢了

    • 对mask进行invert

    原因在于模型要求mask在重绘部分为白色,非重绘部分为黑色,但前端为了方便用户,选择以黑色作为重绘部分的颜色,故在此需要反色

    • 最终得到的mask再输入原有模型

日志(十三) 记于9.10

完善inpainting

  • 实现图像可以自如的在多功能中相互流通
    • 将文生图图像转入图生图
    • 将图生图图像转入局部重绘
  • 修改了绘画图像的显示逻辑,统一改为base64图像,以避免app端使用文件路径显示图像可能时,图像开裂的情况
  • 修改了inpainting引入后,不同模式转换的逻辑

引入词条选择

  • 将频繁使用的词条分类归纳(通用、场景、人物)
  • 用户点击词条,可便捷加入相应提示语

修改广场图像显示

扩大图像高度,突出图像本身作为主体

密码加密

  • 前端向后端传递,进行对称加密
  • 后端向数据库载入,先解密,再哈希加密

未来主要工作

  • 图像生成过程的操作:如中断、进程显示
  • 大量用户同时申请无法排队等待问题
  • 界面太丑不够好看

日志(十四) 记于9.11

后端区分绘画任务

  • 对所有绘画任务绑定task_id
  • 不同绘画任务排队等待
  • 基于该id,可对绘画完成情况查询或强制中断

前端优化

  • 颜色主体更换为红色
  • 引入采样方法多选项
  • 对绘画部分逻辑进行修改
    • 绘画开始时,每隔一段时间向后端接口询问绘画进度
      • 若id不一致,显示排队等待
      • 若id一致,显示绘画完成情况
    • 绘画结束,释放该查询任务
    • 绘画过程中,可以根据task_id进行中断,中断完成将返回临时图像并销毁进度查询
  • 对绘画页面显示作优化
    • 引入进度条,显示进度
    • 中止按钮与创作按钮相互转换
    • 无图像时,下载、发表、分享按钮消失

日志(十五) 记于9.16

预览图像

  • 对所有上传图像降低分辨率后,存储在另一个文件夹中
  • 数据库增加属性,保存预览图像的url
  • 不进入图像详情页时,均使用预览图像的url进行渲染

回复评论

  • 前端多级回复写的太丑了
  • 干脆压缩至一级回复,允许用户对现有评论进行回复
  • 回复评论的展示同某粉色软件的样式,点击原评论,将在下方打开回复评论的内容,并可以对点击的评论进行回复

消息提醒

  • 消息由新的评论产生
  • 在浏览页将在左上角显示消息的数量
  • 进入消息详情页,将显示消息的主体信息,包括:用户名、头像、内容、评论所在图像的标题
  • 可以左滑以删除消息
  • 可以点击评论进入对应的图像详情页

图像删除

  • 允许作者删除自己的图像
  • 同步删除文件服务器中的原图与预览图
  • 相关信息级联删除
留言