当前位置: 首页 > news >正文

使用 Laf 一周内上线美术狮 AI 绘画小程序

“美术狮 AI 绘画”(以下简称“美术狮”),是我们小团队的一次尝试,定位是人人都可以上手的,充满创意的,理解中文和中国文化的图片生成工具。

在完善图像模型和论证核心问题之后,我们开始构建 MVP(最小化可行产品)。MVP 的构建需要:

  • 实现快,开发周期较短
  • 模式轻,产品重点突出
  • 成本低,只投入较少的人力、物力

这些目标,对于我们而言都是不小的挑战。得益于 Laf 的使用,从开发到第一个版本上线,只用了一周时间小程序功能精简、目标清晰;主体服务成本(杭州+新加坡)在 100 元 / 月以内(含有优化空间)。

下面会结合“美术狮”MVP 构建的全过程,和大家交流使用 Laf 这个平台(技术)的思考。

原文链接:https://forum.laf.run/d/984

技术选型过程

函数即服务,是目前我们对 Laf范式的思考和理解。也是“美术狮”选择 Laf 作为服务端的主要因素。

我在 2015 年就接触了“类似”的 BaaS 平台 LeanCloud,并做过两次实践。第一次是对爬取的小红书内容做维护,第二次是给一个中科院的朋友做化学试剂编号的管理。

LeanCloud,偏向于数据库即服务这种范式,对数据增删改查,提供基于数据的丰富的查询、聚合运算方法是这个范式的核心。

范式无优劣之分,取决于需要解决的问题场景、复杂度和规模。对于以数据库为中心的,包含简单鉴权的系统比如 CRM、甚至是 ERP,LeanCloud 都可以很好地适应和匹配。

我们还尝试和了解过主打实时性的野狗云(已下线),以及后来上线一段时间又被字节跳动下线的轻服务(已下线)。也尝试过跟着教程使用 Firebase

“美术狮”或者其他的 AI 应用的实际使用场景中,数据库的操作只是一个部分,复杂的内容生成逻辑、多平台资源调度、相对密集的计算是这类场景中的重心

小程序本身,虽然运行在客户端内拥有一定的计算能力,但是把它看作一个增强的 BS 结构通用性会更好,我们需要把大量地生成逻辑和计算处理流程剥离出来放在服务端由多平台协同完成;同时为了减小分发包的大小,当需要包含其他 SDK 文件时,我们也会格外谨慎

因此,数据库即服务,并不能很好地解决我们所面临的问题,可能并不是 AICG 应用优先会选择的范式。

腾讯云函数(Serverless)

接下来尝试了使用腾讯云函数,能满足了我们的一部分需求。

但是对于单次计算相对密集,调用资源繁多,访问量不稳定的应用而言。冷启动是可怕的,服务被冷却后,再一次被拉起来需要较长地等待时间。在并发和访问量不大时,云函数被频繁地冷却,对用户体验伤害较大,较为致命。这个对于每一个从 0 到 1 的独立开发者可能都是个头疼的问题。

对存储桶、数据库,腾讯云函数并没有做深度地整合,单独配置云数据库、存储桶,会在 MVP 阶段增加不必要的时间和费用的开销。

微信云开发

微信云开发可以通过微信开发者工具一键开通。在“美术狮”迁移的 Laf 之前,我们在微信云开发中做了大量的尝试。

放弃使用微信云开发,主要是下面一些原因:

  1. 基础库 Node 版本过低,对第三方包支持不好;
  2. IDE 开发体验不好,写代码像是看 PPT,本地调试不够方便直观;
  3. 计费系统诡异,虽然我们是腾讯云的老用户,小程序无法在原有账户中开通服务,必须以小程序的维度新开通账户,付费和管理维护不方便;
  4. 对跨区域、跨服务支持不佳;
  5. 冷启动延迟依然明显。

通过内置的鉴权机制快速获取 openid,是微信云开发宣称的优势。

在“美术狮”产品迁移后到 Laf 后,结合社区教程,也可以在“3 分钟”内,实现实现这些功能。

从 0 写一个微信小程序对接 Laf 云开发获取用户 openid - Sealos 开发者社区

Supabase、Vercel、Cloudflare

Verce、Cloudflare 是我特别喜欢的两个平台,这里一笔带过。主要原因是无法整合到国内的网络环境中。

最终我们选择了 Laf。在使用 Laf 的过程中,我们获得几乎等同于 Woker、EdgeFunction 的使用体验和开发效率。

为什么选择 Laf?

函数即服务

Laf 最吸引我们的,是通过云函数的构建应用的方式。

函数即服务在一定程度上,是可以包容(包含)数据库即服务这个范式的。

传统的 Server 端开发,通过 RouterController 去组织代码,利于管理和维护。但是,从另一个层面看,会在一定程度上,降低了 MVP 产品的开发效率,阻碍了创新的落地。

“美术狮”在第一个版本上线前半个小时,决定添加一个每日签到的功能。

通过云函数,我们更聚焦新特性、新功能,而不是困在这个签到功能应该放在哪个 Router 下,哪个 Controller 下这些工程管理的思考中。通过定义一个 task_user_daily_check_in,我们很快地实现了这个功能。

云函数调用云函数,是另外一个我喜欢的特性,我们定义了若干个“内部”云函数(同时关闭了所有 HTTP 方法),来为其他云函数服务。比如获取第三方服务的 access token 并在本地持久化。一方面,代码能够解耦和复用,另一方,安全性也大大提升。

例如这段代码,获取百度云服务的 access token ,关闭请求方法后,仅能被内部调用。

import cloud from '@lafjs/cloud'export default async function (ctx: FunctionContext) {const ret = await cloud.fetch({url: "https://aip.baidubce.com//oauth/2.0/token?",method: "get",params: {'grant_type': 'client_credentials','client_id': process.env.BAE_CLIENT_ID,'client_secret': process.env.BAE_CLIENT_SECRET},});cloud.shared.set('bae_access_tooen', ret.data.access_token)
}

当然,云函数过多后,仅能通过修改函数名去人为地调整云函数的排序,目录结构会显得凌乱,如果能按照 Tag(虚拟文件夹)去聚合、管理云函数,对我而言,会更清晰和直观。

技术栈友好

Laf 使用 TypescriptJavascript )进行开发,与 web 端、小程序开发属于同一技术栈。大大降低了全栈开发的难度,同时绝大多数代码可以在两端进行复用

在避免讨论“谁是世界上最好的编程语言”的前提下,仅从团队、成本、开发效率几个方面讨论,一致的技术栈是 MVP 开发的一个好选择。

良好地第三方支持

Laf 对 第三方 NPM 包的支持很好。我尝试过引用 moment 等这些第三方库处理时间数据,七牛等第三方服务处理图片资源,同时内置了大量常用的第三方库。

如同乐高拼图,云函数可以不断地、从不同维度地整合和丰富。存在大量第三方依赖的项目,迁移时成本较低。

实测,秒下各类第三方 NPM 包,精准版本控制,不需要“魔法”。

开箱即用的数据库

Laf 内置了对 Mongodb 的良好支持,提供了一个开箱即用的数据库。够用,好用

Laf 除了提供大量封装后的查询、聚合方法外,也提供了与原生 Mongo 交互的接口。

例如:通过与原生数据库交互创建索引。

import cloud from "@lafjs/cloud";
const db = cloud.database()export async function main(ctx: FunctionContext) {let res = await cloud.mongo.db.collection('users').createIndex({ "openid": 1})const resIndexs = await cloud.mongo.db.collection("users").indexes()return resIndexs
};

便利、直观的在线调试

在 Laf 中通过控制台、日志,可以完成绝大部分的调试工作。复杂一点的操作可以通过内置的极简的 Postman(接口调试)去完成。

这种极简、干练的风格贯穿 Laf 的功能(也包括上面提到的数据库设计)、UI,是我们 fancy Laf 的另一个重要原因。

实际的使用过程中,除了“存储”这个功能,其他所有的功能区,面板都能被我们高频地使用到。聚焦目标,专注效率,冗余度低

杭州、新加坡两地部署

在“美术狮”的开发过程中,我们在 laf.run(杭州)、laf.dev(新加坡)分别购买和部署了 Laf。多服务交融、跨区域的开发是一种奇妙的体验。

“美术狮”在图片的生成过程中,利用了腾讯云在新加坡的 GPU,图片的存储、优化又在国内完成,最终由七牛提供持久化和 CDN 服务。

Laf 在杭州与新加坡之间通信通畅,可用性高,与其他第三方平台能够完美地整合。

一键弹性伸缩

得益于同门的 Sealos 等项目和 Laf 在云计算方面的深耕,Laf 可以一键配置应用规格和弹性伸缩。

虽然,无数的产品默默地消失了,除非被 DDOS,很多产品很难触发弹性伸缩的条件(比如“美术狮”),但是梦想总是要有的。

短时间的高平发需要专业的运维,极快地做出水平拓展,对于小团队而言,在技术、资金方面都很难做到。Laf 很好地解决了这个后顾之忧,给我们提供了莫大的安全感,这个方面,我会在后面的部分继续补充。

开源、开放

Laf 与我使用过的其他 BaaS 不同,是一个开源项目。

之前有幸和 @ 马斯洛 有过一次对话,马老板是一个深邃、有远见的 Leader。

如果一个项目只隶属于一个公司,那么这个项目的命运大致会捆绑在这个公司的命运上。而一个项目属于社群,哪怕公司没有了,项目仍然能发展、完善。

开源的决定让 Laf 拥有了更长的生命周期和可靠性。用户再也不用担心像“轻服务”突然下线这种事情的发生,可以更放心地实践和使用平台和技术。

另外,不到万不得已,我不会去尝试部署 Laf 的服务。我有一堆自己的理由:

  1. 可靠和稳定能够节省更多的成本,自部署相当于自己承担服务的可靠性,很多人的专业性和运维能力并不足以完成这个工作;
  2. 项目的维护者们更了解项目,也能更好、更快地解决突发问题;
  3. Laf 的部分特性,是靠集群发挥的,购买和维护集群的成本会更高;
  4. 向开源项目付费、贡献代码,是对开发者很好地鼓励和支持。

良好用户运营和收费

在使用了 Laf 的过程中,曾遇到一个无法为文档创建索引的故障。@ 白夜 帮忙联系了 @ 马斯洛 后,很快解决了我的问题。绝大多数问题可以在文档和社区找到解答和代码片段

我们反馈过希望有一个“回收站”的功能。Laf 迭代更新后,回收站如期而至,作为用户,想法被倾听、尊重并实现真是一件开心的事情。

之前对 Laf 的配置缺乏了解,在后台调整了过高的配置。马老板 会把实际资源消耗情况和建议调整值告诉我,每一次沟通都能让我们感受到技术大牛的魅力和一颗为用户着想的心。

合计下来,价廉物美,比一台中等配置的云服务器性价比高很多,同时,我也不用担心可能会到来的流量高峰,我相信 Laf 专业的运维一定会解决“美术狮”未来会遇到的问题。

番外篇

我们是 Midjourney 和 SD 的忠实粉丝。“美术狮”这个名称是 GPT-4 出谋划策的,小程序 Logo 和部分图片资源也是由“美术狮”生成的。

在使用 Mid 和 SD 的过程中,我们发现两个问题:

  1. 准确的 Prompts 需要使用英文书写,特定的英文词汇需要记忆、积累(比如风格、镜头、视角等);
  2. Prompts 需要通过结构化排列,关键词的顺序也会影响出图质量,同时创作者需要具备一定的美术、摄影方面的专业素养。

身边能把 Mid 或者 SD 用好的人少之又少;一个是语言问题,一个是专业问题。

我们以 Dalle2 模型,作为训练起点,没错,就是画面惨不忍睹的 Dalle2,虽然如此,Dalle 是目前绘画模型中最懂自然语言的

Prompts 是文字,由图片 describe 出的 Tag 也是文字,语言文字是信息沟通最重要的媒介,大语言模型更是这次 AI 浪潮的基石。

我们通过 3 个多月,提升了“美术狮”对自然语言特别是中文的理解,让它更灵动、更懂你,尽管还有诸多不完美,过程中仍然带给我们许多惊喜。

我们团队在以后的实践中,会继续使用 Laf,使用 Laf 是快乐的事情。希望越来越多的人能够感受到 Laf 的魅力。也希望 Laf 明天会更好。

相关文章:

使用 Laf 一周内上线美术狮 AI 绘画小程序

“美术狮 AI 绘画”(以下简称“美术狮”),是我们小团队的一次尝试,定位是人人都可以上手的,充满创意的,理解中文和中国文化的图片生成工具。 在完善图像模型和论证核心问题之后,我们开始构建 MV…...

Kubernetes(k8s)当中安装并使用ingress暴露应用

Kubernetes当中安装并使用ingress暴露应用 为什么需要Ingress前期准备集群准备LoadBalancer准备 安装Ingress-Nginx下载地址v1.3.1v1.8.1 修改文件v1.3.1v1.8.1修改ingress服务类型配置 执行安装 部署应用通过ingress-nginx暴露应用部署ingress的yaml文件v1.3.1v1.8.1 为什么需…...

03-Flask-工程配置加载方式

工程配置加载方式 前言配置对象中加载配置文件中加载环境变量中加载三种配置方式优缺点工厂模式创建Flask app 前言 本篇来学习下Flake工程配置加载方式 配置对象中加载 应用场景:作为默认配置写在代码中 # -*- coding: utf-8 -*- # Time : 2023/9/2 # Autho…...

Orangepi安装外设库 wiringPi

注意:mobaXterm传送文件要在SSH登陆环境下才可以。 同时电脑和orangepi都在同一个wifi下。...

[dasctf]misc3 chrchrchr.pcapng

webshell 流量分析 php代码部分没啥看的,主要在标黄的部分,裁剪掉前面的字符可base解码 能看到在向a.txt中写入数据 wp # tshark.exe -r chrchrchr.pcapng -T fields -e urlencoded-form.value -Y "urlencoded-form.keyzd2ebbfb26dd" >…...

微服务--Sentinel(实现:服务高可用)

内存溢出:OOM 服务器挂掉的原因: 1.激增流量打垮: 1.流量突然飙升,导致CPU上升,出现挂机 2.负载不均:比如一个实例长期未重启,导致磁盘写满降低响应时间等。 3.线程池满,单点故障&…...

【MySQL】4、MySQL备份与恢复

备份的主要目的是灾难恢复,备份还可以测试应用、回滚数据修改、查询历史数据、审计等 MySQL日志管理 MySQL 的日志默认保存位置为 /usr/local/mysql/data #配置文件 vim /etc/my.cnf 日志的分类 常见日志有: 错误日志,一般查询日志&…...

python后端,一个账户,多设备登录管理

一个账号,多台设备同时登陆的问题,设计以及实现 参考这篇文章: https://www.alibabacloud.com/help/zh/tair/use-cases/manage-multi-device-logon-from-a-single-user-by-using-tairhash1.0 设计思路 利用的是Redis,主设备的保…...

Django实现音乐网站 ⒁

使用Python Django框架制作一个音乐网站, 本篇主要是歌手页-全部歌手页功能开发。 目录 分出首页样式内容 创建首页样式文件 首页引入样式文件 全部歌手列表 创建路由 显示视图 引入分页实现库 视图方法 创建歌手首页 增加歌手跳转 导航条改活 首页增加…...

服务器监控可视化

IT监控可视化是一种将IT监控数据以图形化的方式呈现给用户的技术,可以帮助用户更直观、更易懂地了解IT系统的运行状况。服务器监控可视化是其中的一个重要应用场景,可以将服务器的各种性能指标以图表、仪表盘等形式展示,以便管理员更好地了解…...

Redis网络模型

目录 Redis网络模型 用户空间和内核态空间 阻塞IO(BIO) 非阻塞IO(NIO) IO多路复用 信号驱动IO 异步IO(AIO) Redis到底是单线程还是多线程? 为什么要使用单线程? Redis网络模型 进程的寻址空间会划分为两部分:内核空间、用户空间 用…...

Super Resolve Dynamic Scene from Continuous Spike Streams论文笔记

摘要 近期,脉冲相机在记录高动态场景中展示了其优越的潜力。不像传统相机将一个曝光时间内的视觉信息进行压缩成像,脉冲相机连续地输出二的脉冲流来记录动态场景,因此拥有极高的时间分辨率。而现有的脉冲相机重建方法主要集中在重建和脉冲相…...

操作视频的开始与暂停

调用 ref.current.play() 方法来播放视频; 如果视频需要暂停,我们调用 ref.current.pause() 方法来暂停视频。 通过 useRef 创建的 ref 操作视频的开始与暂停 当用户点击按钮时,根据当前视频的状态,我们会开始或暂停视频&…...

使用Docker配置深度学习的运行环境

文章目录 推荐实验环境前言docker安装docker操作docker配置常见方法(安装包、联网、程序管理器)安装驱动的前提要求传统方法安装驱动程序程序管理器安装联网安装deb包安装 安装完成后的设置非传统方法安装-通过容器安装驱动的前提要求安装NVIDIA-Contain…...

三相PMSM的坐标变换

三相PMSM的坐标变换 三相PMSM的数学模型具有复杂性和耦合性的多变量系统。因此需要对其进行降阶和解耦变换。 Vα,Vb,Vc是自然坐标系。 Vα,Vβ是静止坐标系。 Vd,Vq是同步旋转坐标系。 自然坐标系 三相永磁同步电机的驱动电路…...

8.(Python数模)(预测模型一)马尔科夫链预测

Python实现马尔科夫链预测 马尔科夫链原理 马尔科夫链是一种进行预测的方法,常用于系统未来时刻情况只和现在有关,而与过去无关。 用下面这个例子来讲述马尔科夫链。 如何预测下一时刻计算机发生故障的概率? 当前状态只存在0(故…...

Leetcode1006笨阶乘

思路:以4为一个分组分别进行处理 class Solution:def clumsy(self, n: int) -> int:answer_dict {0:0,1: 1, 2: 2, 3: 6, 4: 7}if n > 4:answer n * (n - 1) // (n - 2) n - 3n - 4else:print(answer_dict[n])return answer_dict[n]print(answer)while n …...

阻塞非阻塞IO(BIO和NIO),IO多路复用

1.概念 NIO(New Input/Output)和BIO(Blocking Input/Output)是Java中用于处理输入输出的两种不同的模型。 BIO 会阻塞,等有了消息,立刻返回,一个线程处理一个recv(需要很多线程&…...

HTTP协议初识·中篇

加上目录,会出现导向不正确的情况,可能是bug,目录一长就容易出错? 本篇主要讲解了: 网页分离(网页代码和.c文件分离) html链接跳转 网页添加图片 确认并返回资源类型 填写正文长度属性 添加表单 临时重定向 补充知识&a…...

数学建模:拟合算法

🔆 文章首发于我的个人博客:欢迎大佬们来逛逛 数学建模:拟合算法 文章目录 数学建模:拟合算法拟合算法多项式拟合非线性拟合cftool工具箱的使用 拟合算法 根据1到12点间的温度数据求出温度与时间之间的近似函数关系 F ( t ) F(…...

计算机网络-笔记-汇总

目录 📚 前言 🌸章节汇总 🚀 学习心得 ⌛2023年8月31日 星期四 📚 前言 在学习了【操作系统】、【计算机组成原理】之后 再来学习【计算机网络】,对计算机之间如何通信,有了一个大致的认识。 可以想象…...

STM32定时器定时及其应用

STM32定时器定时及其应用 定时器概述☆定时器相关配置CubeMX工程配置及程序实现固件库程序设计及实现 定时器概述 1. 工作原理 使用精准的时基,通过硬件的方式,实现定时功能。定时器核心就是计数器 2. 定时器分类   基本定时器(TIM6~TIM7…...

(牛客) 游游的字符重排(next_permutation的使用)

题目描述 游游定义一个字符串是“好串”,当且仅当该字符串相邻的字符不相等。例如"arcaea"是好串,而"food"不是好串。 游游拿到了一个字符串,她可以将该字符串的各个字符顺序随意打乱。她想知道一共可以生产多少种不同的…...

RTPEngine 通过 HTTP 获取指标的方式

文章目录 1.背景介绍2.RTPEngine 支持的 HTTP 请求3.通过 HTTP 请求获取指标的方法3.1 脚本配置3.2 请求方式 1.背景介绍 RTPEngine 是常用的媒体代理服务器,通常被集成到 SIP 代理服务器中以减小代理服务器媒体传输的压力,其架构如下图所示。这种使用方…...

聚鑫数藏平台——引领数字资产管理新风向

随着数字经济的飞速发展,新金融生态应运而生。区块链技术的崭新突破,使数字资产的重要性日益凸显,为投资者带来了前所未有的机遇和挑战。在此背景下,聚鑫数藏平台横空出世,引领着数字资产管理的新风向。 聚鑫数藏平台&…...

web3j solidity 转java

需要使用的环境 web3j,nodejs 安装编译sol工具 1 $ npm install -g solc 保存为hello.sol文件到本地 1 2 3 4 5 6 7 8 pragma solidity 0.4.19; contract hello { function main(uint a) constant returns (uint b) { uint result a * 8; …...

uniapp项目实战系列(3):底部导航栏与头部导航栏的配置

目录 系列往期文章(点击跳转)uniapp项目实战系列(1):导入数据库,启动后端服务,开启代码托管(点击跳转)uniapp项目实战系列(2):新建项目,项目搭建,微信开发工具…...

Jwt工具类

导入依赖 <dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version> </dependency> <dependency><groupId>javax.xml.bind</groupId><artifactId>jax…...

计算机网络-笔记-第五章-运输层

&#x1f338;章节汇总 一、第一章——计算机网络概述 二、第二章——物理层 三、第三章——数据链路层 四、第四章——网络层 五、第五章——运输层 六、第六章——应用层 目录 五、第五章——运输层 1、运输层概述 2、运输层端口号、复用、分用 &#xff08;1&#xff0…...

java-参数传递机制

java参数传递机制都是值传递。 基本类型参数传输都是数据值。 传递到方法中的值是拷贝后的值。 引用类型参数传输的都是地址值。 如果是数组的参数传递&#xff0c;那么是引用传递&#xff08;本质上还是值传递&#xff0c;但是由于数组的值传递是传递数组的内存地址&#xf…...