零基础手把手教你如何使用Laf免费玩转Midjourney

一、什么是Laf?

Laf 是一个 Serverless 框架,提供开箱即用的云函数,云数据库,对象存储等能力,是一个非常干净清爽的开发平台,不仅入门简单,还能像写博客一样写代码!最重要的是,敲重点,三分钟即可上线 ChatGPT 应用

若想深入了解可点击 介绍 | laf 云开发https://doc.laf.run/guide/

二、入门Laf开发应用前的准备

在正式开发应用前需要先进行账号注册和新建应用,具体操作方法可访问Web IDE | laf 云开发https://doc.laf.run/guide/web-ide/

说明:下面讲解的Midjourney需要访问 laf.dev 域名进行注册

三、正式接入Midjourney

在应用列表点击「开发」按钮即可进入 Laf 应用开发 IDE

直接Web IDE在线开发,连安装软件的工作都省了,不得不说,十分亲民

 1.添加NPM依赖

点击左下角【NPM依赖】处的“+”按钮,在弹框中搜索“midjourney”,选中第一个后再点击“保存并重启”,等待3秒左右依赖会添加完成

 2.添加函数

点击左上角【函数列表】处的“+”按钮,在弹框中输入函数名(比如:mj-func),其他默认,完成后点击“确认”按钮,等待3秒左右函数会添加完成

408a392b3eda4244bc18f5f475cdbec2.png

说明:关于云函数的入门,可点击下面链接了解详情云函数入门 | laf 云开发https://doc.laf.run/guide/function/

3.初始化Midjourney

上面已经添加了midjourney的依赖,接着需要在刚刚添加的函数中引入midjourney,并进行初始化

import { Midjourney, MidjourneyMessage } from 'midjourney'
const SERVER_ID = '' // Midjourney 服务 ID
const CHANNEL_ID = '' // Midjourney 频道 ID
const SALAI_TOKEN = '' // Midjourney 服务 Tokenconst Limit = 100
const MaxWait = 3//初始化
const client = new Midjourney({ServerId: SERVER_ID,ChannelId: CHANNEL_ID,SalaiToken: SALAI_TOKEN,Debug: true,SessionId: SALAI_TOKEN,Limit: Limit,MaxWait: MaxWait
});

其中服务ID、频道ID和服务Token可在 人人都能接入 Midjourney,赚取自己的第一桶金 中找大佬单独获取

4.生成图片

“export default async function”可以理解成函数的主入口,在其方法内我们可以根据传入的参数去实现不同的业务逻辑

//主入口
export default async function (ctx: FunctionContext) {const { type, param } = ctx.body//参数校验if (!type) {return resultData(0, '参数type不能为空!')}switch (type) {case 'imagine'://生成图片return await imagine(param)}
}

下面为【生成图片】的具体实现,需要question和msg_Id两个参数

question:其实就是prompt(提示),需要输入英文

msg_Id:可以理解成会话ID

// 创建生图任务
async function imagine(param) {console.log("imagine", param)const { question, msg_Id } = param//参数校验if (!question || !msg_Id) {return resultData(0, '参数question或msg_Id不能为空!')}try {const obj = await client.Imagine(`[${msg_Id}] ${question}`,(uri: string, progress: string) => {console.log("loading", uri, "progress", progress);});console.log("imagine success ", obj)return resultData(200, 'imagine success', obj)}catch (e) {return resultData(0, '参数错误!', e)}
}

 为了让前端在调用接口时接收到的数据风格统一化,故这里在返回数据时进行了统一的封装处理

//返回结果数据
async function resultData(code = 0, msg = '', data = null) {return { code, msg, data }
}

以上完成后可点击上方的“发布”按钮,等待3秒左右,复制“发布”按钮旁的链接,即可在apipost或者前端中进行调用,如下图:

{"type": "imagine","param": {"question": "a beautiful girl","msg_Id": "20230523_G001"}
}

说明:在返回的结果数据中code为200时表示请求成功,data为null不用理会,请求成功后大约等待30秒到一分钟左右的时间, Midjourney会自动在后台生成我们想要的图片,届时我们再调用【查询最近消息】的接口获取生成的图片。

另外,除了通过apipost或postman调用接口,我们还可以使用Web IDE自带的接口调试进行调用,不仅可以清晰的看到运行的结果,还能在控制台打印出我们想要的日志信息,十分的便利,如下图:

5.查询最近消息

在主入口方法中增加【查询最近消息】的业务逻辑

//主入口
export default async function (ctx: FunctionContext) {const { type, param } = ctx.body//参数校验if (!type) {return resultData(0, '参数type不能为空!')}switch (type) {case 'retrieveMessages'://查询最近消息return await retrieveMessages(param)case 'imagine'://生成图片return await imagine(param)}
}

下面为【查询最近消息】的具体实现,由于默认查询的是所有用户最近50条的消息,所以这里根据msg_Id进行了数据筛选(若想查询所有的可以去掉这个限制)

msg_Id:会话ID(需与生成图片时传的msg_Id一致)

// 查询消息(最近50条)
async function retrieveMessages(param) {console.log("retrieveMessages", param)const { msg_Id } = param//参数校验if (!msg_Id) {return resultData(0, '参数msg_Id不能为空!')}try {const client = new MidjourneyMessage({ChannelId: CHANNEL_ID,SalaiToken: SALAI_TOKEN,});const obj = await client.RetrieveMessages();console.log("retrieveMessages success ", obj)//解析返回的list数据,获取图片信息if (obj) {//查找满足当前会话的消息let info = obj.find(x => x.content.indexOf(msg_Id) > -1);//校验是否完成了图片的生成,条件:attachments节点下的第一个子对象,且width大于512if (info && info.attachments && info.attachments.length > 0 && info.attachments[0].width > 512) {let d = info.attachments[0];//调用云函数获取网络图片并存储const res = await cloud.invoke('store-func', {body: {type: 'fetchImg',param: {fileName: d.filename,fileUrl: d.url,contentType: d.content_type}}});if (res.code == 200) {d.pic = res.datares.data = d}return res;}}return resultData(0, '未获取到数据!')}catch (e) {return resultData(0, '参数错误!', e)}
}

其中,这里“调用云函数获取网络图片并存储”是写在另一个云函数中,所以需要另外再创建一个云函数“store-func”,具体实现如下:

import cloud from "@lafjs/cloud";
import { GetObjectCommand, S3 } from "@aws-sdk/client-s3";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";//初始化
const s3Client = new S3({endpoint: process.env.OSS_EXTERNAL_ENDPOINT,region: process.env.OSS_REGION,credentials: {accessKeyId: process.env.OSS_ACCESS_KEY,secretAccessKey: process.env.OSS_ACCESS_SECRET},forcePathStyle: true,
})
//存储空间名称,不带 Laf 应用 appid
const bucketName = 'store-file'//主入口
export default async function (ctx: FunctionContext) {const { type, param } = ctx.body//参数校验if (!type) {return resultData(0, '参数type不能为空!')}switch (type) {case 'fetchImg'://存储网络图片return await fetchImgToStore(param)}
}//获取网络图片并存储
async function fetchImgToStore(param) {console.log("fetchImgToStore", param);const { fileName, fileUrl, contentType } = param//参数校验if (!fileName || !fileUrl || !contentType) {return resultData(0, '参数fileName、fileUrl或contentType不能为空!')}try {//下载url图片二进制数据const ret = await cloud.fetch({url: fileUrl,method: "get",responseType: "arraybuffer"});// console.log(ret.data);if (ret.data) {//图片存储const res = await uploadAppFile(fileName, ret.data, contentType);console.log('文件存储结果:', res)if (res && res.$metadata && res.$metadata.httpStatusCode == 200) {//获取图片存储的绝对路径const fileUrl = await getAppFileUrl(fileName);return resultData(200, '成功', fileUrl)}return resultData(0, '文件存储失败!')}return resultData(0, '获取网络图片失败!')}catch (e) {return resultData(0, '出现异常!', e)}
}//拼接文件桶名字
function getInternalBucketName() {const appid = process.env.APP_ID;return `${appid}-${bucketName}`;
}//上传文件
async function uploadAppFile(key, body, contentType) {const bucket = getInternalBucketName();const res = await s3Client.putObject({Bucket: bucket,Key: key,ContentType: contentType,Body: body,})return res;
}//获取文件 url
async function getAppFileUrl(key) {const bucket = getInternalBucketName();const res = await getSignedUrl(s3Client, new GetObjectCommand({Bucket: bucket,Key: key,}));return res;
}//返回结果数据
async function resultData(code = 0, msg = '', data = null) {return { code, msg, data }
}

这里涉及到了云函数的调用,以及云存储,详细资料可在下面链接中进行查阅云存储简介 | laf 云开发https://doc.laf.run/guide/oss/

以上完成后可点击上方的“发布”按钮,等待3秒左右,复制“发布”按钮旁的链接,即可在apipost或者前端中进行调用,如下图:

{"type": "retrieveMessages","param": {"msg_Id": "20230523_G001"}
}

 返回的data中pic的链接即为生成的图片

 

 6.放大图片

在主入口方法中增加【放大图片】的业务逻辑

//主入口
export default async function (ctx: FunctionContext) {const { type, param } = ctx.body//参数校验if (!type) {return resultData(0, '参数type不能为空!')}switch (type) {case 'retrieveMessages'://查询最近消息return await retrieveMessages(param)case 'imagine'://生成图片return await imagine(param)case 'upscale'://放大图片return await upscale(param)}
}

下面为【放大图片】的具体实现,需要question、index、id和url四个参数

question:与生成图片时的参数,需要输入英文

index:你想要的第几张图(默认生成的4张图,按1234的顺序)

id:查询最近消息接口返回的数据体中的id

url:查询最近消息接口返回的数据体中attachments节点下的url

// upscale 放大图片
async function upscale(param) {console.log("upscale", param)const { question, index, id, url } = param//参数校验if (!question || !index || !id || !url) {return resultData(0, '参数question、index、id或url不能为空!')}try {const hash = url.split("_").pop()?.split(".")[0] ?? ""const obj = await client.Upscale(question,index,id,hash,(uri: string, progress: string) => {console.log("loading", uri, "progress", progress);});console.log("upscale success ", obj)return resultData(200, 'upscale success', obj)}catch (e) {return resultData(0, '参数错误!', e)}
}

以上完成后可点击上方的“发布”按钮,等待3秒左右,复制“发布”按钮旁的链接,即可在apipost或者前端中进行调用,如下图:

{"type": "upscale","param": {"question": "a beautiful girl","index": 2,"id": "1110429562023723048","url": "https://cdn.discordapp.com/attachments/1110206663958466611/1110429561428135976/johnsonmaureen_20230523_G001_a_beautiful_girl_1925266c-7937-4b8d-8150-c16f013d0dca.png"}
}

成功后,大约等待30秒到一分钟,重新再调用一下【查询最近消息】的接口,获取可访问的放大后的图片

或者,也可以在【放大图片】的接口中将新生成的图片进行云存储后再返回给前端,两种方式都可以

7.变换图片

在主入口方法中增加【变换图片】的业务逻辑

//主入口
export default async function (ctx: FunctionContext) {const { type, param } = ctx.body//参数校验if (!type) {return resultData(0, '参数type不能为空!')}switch (type) {case 'retrieveMessages'://查询最近消息return await retrieveMessages(param)case 'imagine'://生成图片return await imagine(param)case 'upscale'://放大图片return await upscale(param)case 'variation'://变换图片return await variation(param)}
}

下面为【变换图片】的具体实现,需要question、index、id和url四个参数

question:与生成图片时的参数,需要输入英文

index:你想要的第几张图(默认生成的4张图,按1234的顺序)

id:查询最近消息接口返回的数据体中的id

url:查询最近消息接口返回的数据体中attachments节点下的url

// variation 变换图片
async function variation(param) {console.log("variation", param)const { question, index, id, url } = param//参数校验if (!question || !index || !id || !url) {return resultData(0, '参数question、index、id或url不能为空!')}try {const hash = url.split("_").pop()?.split(".")[0] ?? ""const obj = await client.Variation(question,index,id,hash,(uri: string, progress: string) => {console.log("loading", uri, "progress", progress);});console.log("variation success ", obj)return resultData(200, 'variation success', obj)}catch (e) {return resultData(0, '参数错误!', e)}
}

以上完成后可点击上方的“发布”按钮,等待3秒左右,复制“发布”按钮旁的链接,即可在apipost或者前端中进行调用,如下图:

{"type": "variation","param": {"question": "a beautiful girl","index": 3,"id": "1110429562023723048","url": "https://cdn.discordapp.com/attachments/1110206663958466611/1110429561428135976/johnsonmaureen_20230523_G001_a_beautiful_girl_1925266c-7937-4b8d-8150-c16f013d0dca.png"}
}

 说明:在返回的结果数据中code为200时表示请求成功,data为null不用理会,请求成功后大约等待30秒到一分钟左右的时间, Midjourney会自动在后台重新生成我们想要的图片,届时我们再调用【查询最近消息】的接口获取变换后的图片。

8.关于云存储

如使用云存储,需在云存储中新建Bucket,如下图:

d6b83fef597d4fd48986461d61b24a41.png

下面为云函数mj-func的完整代码:

import cloud from '@lafjs/cloud'
import { Midjourney, MidjourneyMessage } from 'midjourney'
const SERVER_ID = '' // Midjourney 服务 ID
const CHANNEL_ID = '' // Midjourney 频道 ID
const SALAI_TOKEN = '' // Midjourney 服务 Tokenconst Limit = 100
const MaxWait = 3//初始化
const client = new Midjourney({ServerId: SERVER_ID,ChannelId: CHANNEL_ID,SalaiToken: SALAI_TOKEN,Debug: true,SessionId: SALAI_TOKEN,Limit: Limit,MaxWait: MaxWait
});//主入口
export default async function (ctx: FunctionContext) {const { type, param } = ctx.body//参数校验if (!type) {return resultData(0, '参数type不能为空!')}switch (type) {case 'retrieveMessages'://查询最近消息return await retrieveMessages(param)case 'imagine'://生成图片return await imagine(param)case 'upscale'://放大图片return await upscale(param)case 'variation'://变换图片return await variation(param)}
}// 查询消息(最近50条)
async function retrieveMessages(param) {console.log("retrieveMessages", param)const { msg_Id } = param//参数校验if (!msg_Id) {return resultData(0, '参数msg_Id不能为空!')}try {const client = new MidjourneyMessage({ChannelId: CHANNEL_ID,SalaiToken: SALAI_TOKEN,});const obj = await client.RetrieveMessages();console.log("retrieveMessages success ", obj)//解析返回的list数据,获取图片信息if (obj) {//查找满足当前会话的消息let info = obj.find(x => x.content.indexOf(msg_Id) > -1);//校验是否完成了图片的生成,条件:attachments节点下的第一个子对象,且width大于512if (info && info.attachments && info.attachments.length > 0 && info.attachments[0].width > 512) {let d = info.attachments[0];//调用云函数获取网络图片并存储const res = await cloud.invoke('store-func', {body: {type: 'fetchImg',param: {fileName: d.filename,fileUrl: d.url,contentType: d.content_type}}});if (res.code == 200) {info.pic = res.datares.data = info}return res;}}return resultData(0, '未获取到数据!')}catch (e) {return resultData(0, '参数错误!', e)}
}// 创建生图任务
async function imagine(param) {console.log("imagine", param)const { question, msg_Id } = param//参数校验if (!question || !msg_Id) {return resultData(0, '参数question或msg_Id不能为空!')}try {const obj = await client.Imagine(`[${msg_Id}] ${question}`,(uri: string, progress: string) => {console.log("loading", uri, "progress", progress);});console.log("imagine success ", obj)return resultData(200, 'imagine success', obj)}catch (e) {return resultData(0, '参数错误!', e)}
}// upscale 放大图片
async function upscale(param) {console.log("upscale", param)const { question, index, id, url } = param//参数校验if (!question || !index || !id || !url) {return resultData(0, '参数question、index、id或url不能为空!')}try {const hash = url.split("_").pop()?.split(".")[0] ?? ""const obj = await client.Upscale(question,index,id,hash,(uri: string, progress: string) => {console.log("loading", uri, "progress", progress);});console.log("upscale success ", obj)return resultData(200, 'upscale success', obj)}catch (e) {return resultData(0, '参数错误!', e)}
}// variation 变换图片
async function variation(param) {console.log("variation", param)const { question, index, id, url } = param//参数校验if (!question || !index || !id || !url) {return resultData(0, '参数question、index、id或url不能为空!')}try {const hash = url.split("_").pop()?.split(".")[0] ?? ""const obj = await client.Variation(question,index,id,hash,(uri: string, progress: string) => {console.log("loading", uri, "progress", progress);});console.log("variation success ", obj)return resultData(200, 'variation success', obj)}catch (e) {return resultData(0, '参数错误!', e)}
}//返回结果数据
async function resultData(code = 0, msg = '', data = null) {return { code, msg, data }
}

 以上即为使用Laf接入Midjourney的完整演示,如有疑问,欢迎提出!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/62009.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

.net配置nacos,手把手教你分布式配置中心

.net配置nacos,手把手教你分布式配置中心 个人博客地址:note.raokun.top 拥抱ChatGPT,国内访问网站:https://www.playchat.top Nacos是一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。 这么优秀的分布式服务…

《商标与商号法律制度冲突问题研究报告》发布

2022年4月11日,北京阳光知识产权与法律发展基金会正式发布《商标与商号法律制度冲突问题研究报告》。报告历时一年半,是目前针对商标与字号法律制度冲突问题进行的比较系统、全面的研究成果,具有极高的实践价值。   在我国目前的法律制度体…

为什么之前CSDN上免费用的chatgpt不见了

chatgpt刚上线时候,管理风控上是比较松的,基本上通过一些简单的技术手段就能获取大量的账号,并能在限制地区稳定访问使用,甚至单号同时访问也是可以轻松应对;但后面,风控发生了本质上的改变。 ​ 编辑切换…

人工神经网络文献综述,人工神经网络论文文献

BP神经网络方法 。 人工神经网络是近几年来发展起来的新兴学科,它是一种大规模并行分布处理的非线性系统,适用解决难以用数学模型描述的系统,逼近任何非线性的特性,具有很强的自适应、自学习、联想记忆、高度容错和并行处理能力…

美国DARPA204页可解释人工智能文献综述论文《Explanation in Human-AI Systems》

来源:专知 摘要:本文介绍Arxiv上的《Explanation in Human-AI Systems》,一篇关于可解释机器学习的综述,介绍了可解释机器学习的多学科观点、历史研究、模型、关键点等。 可解释AI是现在正火热的科研和工程问题。Arxiv上一篇《Exp…

Python | 电影Top250 + 数据可视化

文章目录 1. 代码2. 数据可视化2.1 读取数据2.2 各年份上映电影数量柱状图(纵向)2.3 各地区上映电影数量前十柱状图(横向)2.4 电影评价人数前二十柱状图(横向) 可视化项目源码数据 大家好,我是 …

或颠覆广告格局,FGMNT的VR工具亮相戛纳国际创意节

Situ或重新定义广告客户可视化其广告系列的方式。 在戛纳国际创意节上,墨尔本虚拟现实初创公司FGMNT展示了他们的新的VR网络工具——Situ,或重新定义广告客户可视化其广告系列的方式。 据悉,Situ是一种基于网页的沉浸式工具,使客…

html form提交heard,德普前妻Amber Heard戛纳合辑

0 德普前妻Amber Heard戛纳合辑 2018-05-14 10:56 德普前妻Amber Heard出席戛纳电影节,不论是简约的黑白配还是拍摄广告时撩人的红色衬衫,或是走红毯时性感十足的深V礼服裙,她都能穿出属于自己的味道。在外媒24小时跟拍、豪不修图的渣画质里&…

数据分析(一)豆瓣华语电影分析

在之前,我们已经用通过爬虫获取了豆瓣华语电影共33133部电影的数据,具体爬虫介绍请见之前的博文,爬虫实战(一)利用scrapy爬取豆瓣华语电影。本文对爬虫过程进行简要概述后,对这部分数据进行分析。 1. 前言…

Python猫眼电影数据采集与可视化分析实战

在国内比较知名的电影数据平台应该就是豆瓣、猫眼了,别的使用的不是很多,这两个平台就我们来说,平时的实践依赖还是比较多的,今天主要是想基于猫眼电影数据做一点分析性的工作,在我之前的文章中,基于豆瓣影评数据的采集、处理、存储、分析、可视化整个流程已经做了详细的…

践行社会责任的路上,中概股们看到了怎样的风景?

谈起社会责任,你会想到什么?绿色经济、“双碳”目标、共同富裕、乡村振兴、慈善活动、ESG(环境、社会和公司治理)这些名词肯定少不了。 当下,全球企业正越发强调社会责任,这或许是商业发展到一定阶段的必然结果,但也离…

第九届北京国际电影节海报,对你发起邀请

文丨夏莎莎 你看>丨创意视觉设计(ID:fvatm0525) 第九届北京国际电影节海报,你肿么了? 来自官方的海报文案 敲重点,好好学习昂 强行乱入的文案 四月的北京 水绿 云淡 风轻 天坛女神 屹立苍穹 脚踏大地 播…

遇见·戛纳--张全欣《遇见·环市路》

遇见戛纳--张全欣《遇见环市路》 今年的第71届戛纳电影节,不仅仅是西方电影的专属舞台,以中国为代表的亚洲电影以及种种正式参与或蹭热度的新闻层出不穷。 提起法国,大家想到的是:浪漫、时尚、奢华。 而提起法国戛纳,必…