感谢laf提供云资源赞助,小伙伴可白piao用来做测试。
感谢laf团队、白夜、米开朗基杨@sealos.io的热心布道 ,life is short, u need laf : )
欢迎你也来加入laf开发。
正好现在laf在做一个活动,一起搞起来吧人人都能接入 Midjourney
目标
由于Midjourney官方并没有提供api接口,有大佬开封装了通过discord间接操作使用midjourney的nodejs包,我们通过在自己的程序中集成这个三方库来完成midjourney的使用,这是代码层面的核心事情。另外就是大家都懂的原因没办法访问midjourney,我们通过https://laf.dev 的新加坡节点Serverless来运行我们的程序,我们再通过访问在laf部署的程序来连接midjourney服务。
注册laf账号
Laf是环界云开发的一个Serverless框架,它可以帮助开发者快速构建具有AI能力的分布式应用。使用Laf,你可以像写博客一样轻松地编写代码,并随时随地快速发布上线应用。
现在Laf提供免费资源供开发者测试使用,这里我们直接用免费的就足够跑程序了。
laf服务区分杭州和新加坡,从不同域名进入注册不同区域的账号。
新加坡:新加坡地址 (今天的midjourney我们要用新加坡的服务)
杭州:杭州地址
手机号码短信注册,过程太简单,这里不多说了。
编写函数
先在云开发面板添加一个函数,取个自己喜欢的函数名,我这里取名:midjourney
添加函数代码
import cloud from '@lafjs/cloud'
import { Midjourney, MidjourneyMessage } from 'midjourney'
const SERVER_ID = '' // Midjourney 服务 ID
const CHANNEL_ID = '' // Midjourney 频道 ID
const SALAI_TOKEN = '' // Midjourney 服务 Token
const 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
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)
}
}
// 查询最近消息
async function RetrieveMessages(param) {
console.log("RetrieveMessages")
const client = new MidjourneyMessage({
ChannelId: CHANNEL_ID,
SalaiToken: SALAI_TOKEN,
});
const msg = await client.RetrieveMessages();
console.log("RetrieveMessages success ", msg)
return msg
}
// 创建生图任务
async function imagine(param) {
console.log("imagine", param)
const { question, msg_Id } = param
const msg = await client.Imagine(
`[${msg_Id}] ${question}`,
(uri: string, progress: string) => {
console.log("loading", uri, "progress", progress);
}
);
console.log("imagine success ", msg)
return true
}
// upscale 放大图片
async function upscale(param) {
console.log("upscale", param)
const { question, index, id, url } = param
const hash = url.split("_").pop()?.split(".")[0] ?? ""
console.log(hash)
const msg = await client.Upscale(
question,
index,
id,
hash,
(uri: string, progress: string) => {
console.log("loading", uri, "progress", progress);
}
);
console.log("upscale success ", msg)
return msg
}
// variation 变换图片
async function variation(param) {
console.log("variation", param)
const client = new Midjourney({
ServerId: SERVER_ID,
ChannelId: CHANNEL_ID,
SalaiToken: SALAI_TOKEN,
Debug: true,
SessionId: SALAI_TOKEN,
Limit: Limit,
MaxWait: 100
});
const { question, index, id, url } = param
const hash = url.split("_").pop()?.split(".")[0] ?? ""
const msg = await client.Variation(
question,
index,
id,
hash,
(uri: string, progress: string) => {
console.log("loading", uri, "progress", progress);
}
);
console.log("variation success ", msg)
return msg
}
添加相关函数所需的依赖:
填写关键配置信息,用于初始化一个midjourney客户端:
const SERVER_ID = '' // Midjourney 服务 ID
const CHANNEL_ID = '' // Midjourney 频道 ID
const SALAI_TOKEN = '' // Midjourney 服务 Token
这三项配置信息可以白piao @米开朗基杨@sealos.io 提供的满级账号用来测试够了,仔细看前文的活动帖即可获得。
如果有自己的账号,可以登录discord在频道发一条信息,F12在请求中找到。
完成以上操作步骤,点击laf云开发节点的发布,即可测试midjourney api接口调用。
接口调试:
先点击发布左侧的链接,复制。这就是我们写好的midjourney服务api链接了。
我这里用postman调试api接口:
先来调用生成图片
查询历史任务:
从历史任务中获得我们发送的生图任务和结果。
查询接口一次返回多条数据,返回的是这个频道中的数据,目前这个测试配置信息是多人共享的,所以能查到其他人生成的图片任务。
查询到结果后,记得提取出:id、content、url这几个字段,后面放大和重新绘制会用到。
来看看生成的图片效果吧。
一次生图任务会返回四张预览图供你选择,选择一张你喜欢的,执行放大即可获得高清大图。
这里我们把第二张图放大看看:
看看放大的图片效果:
非常高清,很有质感。midjourney 杠杆滴。
小伙伴可能会遇到生成图片结果的url链接无法访问的情况,是因为大家都懂的原因。
这里我们仍然可以继续使用laf提供的云存储能力来转存图片,示例代码如下:
import cloud from '@lafjs/cloud'
import axios from 'axios'
import { S3 } from "@aws-sdk/client-s3";
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,
})
export default async function (ctx: FunctionContext) {
console.log('storage image')
const { url } = ctx.body
if (!url) {
return { err: "url is empty" }
}
let key = ''
if (url.indexOf('https://cdn.discordapp.com/') == 0) {
key = url.replace('https://cdn.discordapp.com/', '')
}
if (url.indexOf('https://media.discordapp.net/') == 0) {
key = url.replace('https://media.discordapp.net/', '')
}
await uploadImgToMinio(url, key);
return { data: 'https://<你的云存储bucket>.site.laf.dev/' + key }
}
async function uploadImgToMinio(imgurl, key) {
const { data } = await axios.get(imgurl, { responseType: 'arraybuffer' });
const buffer = Buffer.from(data, 'binary');
await s3Client.putObject({
Bucket: <你的云存储bucket>,
Key: key,
Body: buffer,
ContentType: 'application/octet-stream'
});
}
这里将原始的图片路径完全一致的转存到laf云存储中保存,保存成功后我们就可以通过laf云存储的bucket链接地址来访问图片了。
更多玩法等你来挖掘,就讲到这里。
下面是我用laf做的样例,不要在意页面美感,主要做接口实验使用。
示例:传送门