我把AI绘图工具搬到自有App中,并且开源免费

网友投稿 575 2023-08-23

前言

和大家一样我也在思考如何通过现有 Ai 工具去有效的提升 App 的活跃度,并让里面的服务多元化起来,ChatGPT 大家都尝试的挺多了,我就计划用 Ai 绘图工具下手。

我把AI绘图工具搬到自有App中,并且开源免费

但现在 Midjourney 开始收费,每个月30刀还是挺贵的,于是放弃(毕竟穷)。于是想起之前使用的 Scribble Diffusion ,只需要画两笔草图就能生成高质量图片,体验不错还能免费。

Scribble Diffusion 是一个简单的在线服务,它使用 AI 将粗略的草图转换为精致的图像,每一张图像都是不同的(而且没有版权困扰)。简单来说,我们只需要「用画笔描绘一张草图,在输入描述后稍等片刻」,随后就会为你生成一幅画。这幅画可以多次生成,每次生成的结果也都大不相同。

Scribble Diffusion 的能力大概是这样的(左边是我画的,右边是 TA 画的)

a photo of grassland with cloud(有云朵的草地)

the sun setting behind the mountains(山后落日)

A lovely kitten(小猫咪呀)

我发现 Scribble Diffusion 作画的能力非常出乎意料,而且可以根据你的描述来定义不同的照片风格(比如照片,油画,素描等等),于是就产生了做成小程序通过小程序容器搬运到 App 的想法(毕竟开箱即用,也不需要做什么配置,不了解小程序容器技术的小伙伴可以关注 FinClip、mPaaS 等产品)。

调研官网之后发现官网中的元素非常简单,正因如此,我觉得把「Scribble Diffusion」搬运到 FinClip 小程序里大概要分这样几步:

使用 canvas 实现画板,能够在小程序中进行绘画; 提供输入框与生成按钮,能够补充图片的描述和生成的按钮; 获取生成的图片链接进行展示

使用小程序实现画板

我们可以使用小程序来实现一个画板,使用 canvas 标签实现画笔功能。用户可以在画板上绘制画作,也可以选择清空画板操作。

下面是一个示例代码

xml
复制代码
<!--画布区域--> <view class="canvas_area"> <canvas id="myCanvas" canvas-id="myCanvas" class="myCanvas" disable-scroll="false" bindtouchstart="touchStart" bindtouchmove="touchMove" bindtouchend="touchEnd"> </canvas> </view> <view class="clearBtn" bindtap="reset"> 清空画板 </view>
kotlin
复制代码
Page({ data: { isProcessing: false, prompt: , scribble: null, pen : 2, //画笔粗细默认值 color : #000000, // 画笔颜色默认值 result: null, text: }, startX: 0, //保存X坐标轴变量 startY: 0, //保存X坐标轴变量 onLoad(params) { wx.createSelectorQuery().select(#myCanvas).context((res) => { this.context = res.context }).exec() }, //手指触摸动作开始 touchStart: function (e) { //得到触摸点的坐标 this.startX = e.changedTouches[0].x this.startY = e.changedTouches[0].y // this.context = wx.createContext() this.context.setStrokeStyle(this.data.color) this.context.setLineWidth(this.data.pen) this.context.setLineCap(round) // 让线条圆润 this.context.beginPath() }, //手指触摸后移动 touchMove: function (e) { var startX1 = e.changedTouches[0].x var startY1 = e.changedTouches[0].y this.context.moveTo(this.startX, this.startY) this.context.lineTo(startX1, startY1) this.context.stroke() this.startX = startX1; this.startY = startY1; //只是一个记录方法调用的容器,用于生成记录绘制行为的actions数组。context跟<canvas/>不存在对应关系,一个context生成画布的绘制动作数组可以应用于多个<canvas/> wx.drawCanvas({ canvasId: myCanvas, reserve: true, actions: this.context.getActions() // 获取绘图动作数组 }) }, //手指触摸动作结束 touchEnd: function () { var imageData = wx.canvasGetImageData({ canvasId: myCanvas, height: 250, width: 250, x: 0, y: 0, success(res){ return res.data } }) }, //清除画板 reset: function(){ this.context.clearRect(0, 0, 400, 400); this.context.draw(true) } })

提供输入框和生成按钮

我们需要提供一个 input 输入框,供用户输入 prompt;同时,我们需要提供一个按钮,点击时会触发响应事件,将 canvas 内容生成图片,同时将 prompt 输入作为参数,提交给服务端进行图片生成。

这里是示例代码:

xml
复制代码
<!-- 输入框 --> <view class="imageDes"> <view class="formInput"> <input class="input" type="text" name="go" placeholder="用关键词描述画的内容" bindinput="update"/> </view> </view>
javascript
复制代码
Page({ ... 省略上述代码 // 更新表单提交按钮状态 update(e){ this.setData({ prompt : e.detail.value }) }, })

获取生成的图片链接并展示

当用户点击生成图片按钮后,我们会将 canvas 内容和用户输入的 prompt 作为参数提交给服务端进行图片生成。服务端会返回生成的图片链接,我们需要将它展示给用户。

在下面的示例代码中,我们服务端发送 POST 请求,然后解析返回的 jsON 数据,获取图片链接,并将其添加到页面中。用户就可以看到生成的图片了。

xml
复制代码
<!-- 绘图结果 --> <view class="result" wx:if="{{result}}"> <view class="resultBox"> <view class="content"> <image class="content" src="{{result}}" mode="aspectFit" /> </view> <view class="download"> <view class="btn" bindtap="download"> - </view> </view> </view> </view>
javascript
复制代码
Page({ ... 省略上述代码 async getCanvasImage() { return new Promise((resolve, reject) => { wx.canvasToTempFilePath({ x: 0, y: 0, width: 250, height: 250, destWidth: 250, destHeight: 250, canvasId: myCanvas, success(res) { console.log(res.tempFilePath) resolve(res.tempFilePath) }, fail(err) { console.log(err) } }) }) }, async upload(image) { return new Promise((resolve) => { wx.uploadFile({ url: xxxxxx, filePath: image, name: file, success (res){ const data = JSON.parse(res.data) resolve(data.url) }, fail(err){ console.log(上传失败) console.log(err) } }) }) }, async sleep(time) { return new Promise((resolve) => { setTimeout(() => { resolve() }, time) }) }, async handleSubmit(e) { if (!this.data.prompt) { return } wx.showLoading({ title: 生成中, }) try { const prompt = this.data.prompt const image = await this.getCanvasImage() this.setData({ error: null, isProcessing: true }); const url = await this.upload(image) console.log(图片, url) const body = { prompt: prompt, image: url, }; const response = await my_fetch.fetch( { url: "https://scribblediffusion.com/api/predictions", method: "POST", headers: { "Content-Type": "application/json", }, params: JSON.stringify(body), }); let prediction = response.data; console.log(预测, prediction) if (response.statusCode !== 201) { wx.showToast({ title: 生成失败, duration: 2000 }) this.setData({ error: 生成失败 }); return; } while ( prediction.status !== "succeeded" && prediction.status !== "failed" ) { console.log(prediction.status) await this.sleep(500); const response = await my_fetch.fetch({ url:"https://scribblediffusion.com/api/predictions/" + prediction.id, }); prediction = response.data; if (response.statusCode !== 200) { this.setData({ error: prediction.detail }); return; } } if (Array.isArray(prediction.output) && prediction.output.length > 1) { wx.hideLoading() this.setData({ isProcessing: false, result: prediction.output[1] }); } else { wx.hideLoading() wx.showToast({ title: 生成失败, duration: 2000 }) this.setData({ isProcessing: false, error: 生成失败 }) } } catch (error) { wx.hideLoading() console.log(error) wx.showToast({ title: 生成失败, duration: 2000 }) } }, })

生成完小程序之后,再通过管理后台上传小程序就可以在 App 获得 ai 绘图工具啦!

当然,如果你对 Scribble Diffusion 有更多奇怪的想法想付诸实践,开发者也已经将项目文件进行了开源,可以直接尝试~

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:整理一波 React Native 好用的工具
下一篇:Hybrid App 模式的几大前端框架比较
相关文章

 发表评论

暂时没有评论,来抢沙发吧~