简介: 当一个程序员想要个漫画风的头像时...
前言我一直都想要有一个漫画版的头像,奈何手太笨,用了很多软件 “捏不出来”,所以就在想着,是否可以基于 AI 实现这样一个功能,并部署到 Serverless 架构上让更多人来尝试使用呢?
后端项目后端项目采用业界鼎鼎有名的动漫风格转化滤镜库 AnimeGAN 的 v2 版本,效果大概如下:
关于这个模型的具体的信息,在这里不做详细的介绍和说明。通过与 Python Web 框架结合,将 AI 模型通过接口对外暴露:
from PIL import Image import io import torch import base64 import bottle import random import json cacheDir = '/tmp/' modelDir = './model/bryandlee_animegan2-pytorch_main' getModel = lambda modelName: torch.hub.load(modelDir, "generator", pretrained=modelName, source='local') models = { 'celeba_distill': getModel('celeba_distill'), 'face_paint_512_v1': getModel('face_paint_512_v1'), 'face_paint_512_v2': getModel('face_paint_512_v2'), 'paprika': getModel('paprika') } randomStr = lambda num=5: "".join(random.sample('abcdefghijklmnopqrstuvwxyz', num)) face2paint = torch.hub.load(modelDir, "face2paint", size=512, source='local') @bottle.route('/images/comic_style', method='POST') def getComicStyle(): result = {} try: postData = json.loads(bottle.request.body.read().decode("utf-8")) style = postData.get("style", 'celeba_distill') image = postData.get("image") localName = randomStr(10) # 图片获取 imagePath = cacheDir + localName with open(imagePath, 'wb') as f: f.write(base64.b64decode(image)) # 内容预测 model = models[style] imgAttr = Image.open(imagePath).convert("RGB") outAttr = face2paint(model, imgAttr) img_buffer = io.BytesIO() outAttr.save(img_buffer, format='JPEG') byte_data = img_buffer.getvalue() img_buffer.close() result["photo"] = 'data:image/jpg;base64, %s' % base64.b64encode(byte_data).decode() except Exception as e: print("ERROR: ", e) result["error"] = True return result app = bottle.default_app() if __name__ == "__main__": bottle.run(host='localhost', port=8099)
整个代码是基于 Serverless 架构进行了部分改良的:
- 实例初始化的时候,进行模型的加载,已经可能的减少频繁的冷启动带来的影响情况;
- 在函数模式下,往往只有/tmp目录是可写的,所以图片会被缓存到/tmp目录下;
- 虽然说函数计算是“无状态”的,但是实际上也有复用的情况,所有数据在存储到tmp的时候进行了随机命名;
- 虽然部分云厂商支持二进制的文件上传,但是大部分的 Serverless 架构对二进制上传支持的并不友好,所以这里依旧采用 Base64 上传的方案;
上面的代码,更多是和 AI 相关的,除此之外,还需要有一个获取模型列表,以及模型路径等相关信息的接口:
import bottle @bottle.route('/system/styles', method='GET') def styles(): return { "AI动漫风": { 'color': 'red', 'detailList': { "风格1": { 'uri': "images/comic_style", 'name': 'celeba_distill', 'color': 'orange', 'preview': 'https://serverless-article-picture.oss-cn-hangzhou.aliyuncs.com/1647773808708_20220320105649389392.png' }, "风格2": { 'uri': "images/comic_style", 'name': 'face_paint_512_v1', 'color': 'blue', 'preview': 'https://serverless-article-picture.oss-cn-hangzhou.aliyuncs.com/1647773875279_20220320105756071508.png' }, "风格3": { 'uri': "images/comic_style", 'name': 'face_paint_512_v2', 'color': 'pink', 'preview': 'https://serverless-article-picture.oss-cn-hangzhou.aliyuncs.com/1647773926924_20220320105847286510.png' }, "风格4": { 'uri': "images/comic_style", 'name': 'paprika', 'color': 'cyan', 'preview': 'https://serverless-article-picture.oss-cn-hangzhou.aliyuncs.com/1647773976277_20220320105936594662.png' }, } }, } app = bottle.default_app() if __name__ == "__main__": bottle.run(host='localhost', port=8099)
可以看到,此时我的做法是,新增了一个函数作为新接口对外暴露,那么为什么不在刚刚的项目中,增加这样的一个接口呢?而是要多维护一个函数呢?
- AI 模型加载速度慢,如果把获取AI处理列表的接口集成进去,势必会影响该接口的性能;
- AI 模型所需配置的内存会比较多,而获取 AI 处理列表的接口所需要的内存非常少,而内存会和计费有一定的关系,所以分开有助于成本的降低;
关于第二个接口(获取 AI 处理列表的接口),相对来说是比较简单的,没什么问题,但是针对第一个 AI 模型的接口,就有比较头疼的点:
- 模型所需要的依赖,可能涉及到一些二进制编译的过程,所以导致无法直接跨平台使用;
- 模型文件比较大 (单纯的 Pytorch 就超过 800M),函数计算的上传代码最多才 100M,所以这个项目无法直接上传;
所以这里需要借助 Serverless Devs 项目来进行处理:
参考 Yaml规范 - Serverless Devs
完成 s.yaml 的编写:
edition: 1.0.0 name: start-ai access: "default" vars: # 全局变量 region: cn-hangzhou service: name: ai nasConfig: # NAS配置, 配置后function可以访问指定NAS userId: 10003 # userID, 默认为10003 groupId: 10003 # groupID, 默认为10003 mountPoints: # 目录配置 - serverAddr: 0fe764bf9d-kci94.cn-hangzhou.nas.aliyuncs.com # NAS 服务器地址 nasDir: /python3 fcDir: /mnt/python3 vpcConfig: vpcId: vpc-bp1rmyncqxoagiyqnbcxk securityGroupId: sg-bp1dpxwusntfryekord6 vswitchIds: - vsw-bp1wqgi5lptlmk8nk5yi0 services: image: component: fc props: # 组件的属性值 region: ${vars.region} service: ${vars.service} function: name: image_server description: 图片处理服务 runtime: python3 codeUri: ./ ossBucket: temp-code-cn-hangzhou handler: index.app memorySize: 3072 timeout: 300 environmentVariables: PYTHONUSERBASE: /mnt/python3/python triggers: - name: httpTrigger type: http config: authType: anonymous methods: - GET - POST - PUT customDomains: - domainName: avatar.aialbum.net protocol: HTTP routeConfigs: - path: /*
然后进行:
1、依赖的安装:s build --use-docker
2、项目的部署:s deploy
3、在 NAS 中创建目录,上传依赖:
s nas command mkdir /mnt/python3/python s nas upload -r 本地依赖路径 /mnt/python3/python
完成之后可以通过接口对项目进行测试。
另外,微信小程序需要 https 的后台接口,所以这里还需要配置 https 相关的证书信息,此处不做展开。
小程序项目小程序项目依旧采用 colorUi,整个项目就只有一个页面:
页面相关布局:
第一步:选择图片 本地上传图片 获取当前头像关注打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?