首先来一波感谢:
感谢laf提供赞助,目前可以免费使用Midjourney进行开发和测试。
感谢白夜、米开朗基杨@sealos.io的耐心解答,让我对laf有了更多的使用与了解。
什么是laf?来了解下。
文末有【示例】
开始
废话不多说,进入正题。
laf在做一个活动,可以使用快速上手Midjourney《人人都能接入 Midjourney》。具体活动,可以查看论坛。
原理
原理部分不涉及代码,涉及背景介绍,熟悉的同学可以略过。因为midjourney
官方没有提供API功能,所以有国外大神将开源了一款模拟请求工具,来请求midjourney,laf将这代码集成到内部的npm包中。如果需要github地址,欢迎留言,我私信给您。
所以laf平台,加上下面的实例代码可以很好的快速接入到系统中。
开始
要现有个laf账号,会有免费1月的试用,本次调用mj(以下代指midjourney),所以要在laf.dev
上注册使用,这是运行在新加坡环境上。
代码逻辑
我的核心思想是这样的:先要有个核心与midjourney
交互的代码,上层的我们想做的业务逻辑可以自己定义。
代码
laf 是一个云开发平台,可以将代码暴露成api形式,进行调用,一些其他鉴权等,可以在之前我写的文章中找到灵感:腾讯云开发迁移实录
- 要做一个云函数,处理与midjourney交互,我这里起名云函数
mj-send
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 = 3const 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.bodyswitch (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 } = paramconst 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 } = paramconst 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 } = paramconst 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付费账号,没有key?大佬我们做朋友,留言我来告诉你。
发布即可调用,怎么调用?我把curl给你,你看看结构就懂了,该替换的替换。
- 画图
画图需要一些时间,这里默认使用的fast,但也是会花时间的,所以成图我们要在之后调用查询接口查看。
question
:就是prompt,这里要输入英文。- 关注下参数
msg_Id
,后面有用
curl --location --request POST 'https://<你的发布地址服务>' \
--header 'User-Agent: apifox/1.0.0 (https://www.apifox.cn)' \
--header 'Content-Type: application/json' \
--data-raw '{"type": "imagine","param": {"question": "a dog","msg_Id": 1684585158}
}'
- 查询
curl --location --request POST 'https://<你的发布地址服务>' \
--header 'User-Agent: apifox/1.0.0 (https://www.apifox.cn)' \
--header 'Content-Type: application/json' \
--data-raw '{"type":"RetrieveMessages"
}'
如何获取到我刚创建的图呢?先看一下返回的结果。
[{"id": "1109565864640008202","type": 0,"content": "**[1684582132] a dog --seed 8925 --v 5** - <@1013684342851117146> (fast)","channel_id": "1109368983364313204","author": {"id": "936929561302675456","username": "Midjourney Bot","global_name": null,"avatar": "4a79ea7cd151474ff9f6e08339d69380","discriminator": "9282","public_flags": 589824,"bot": true,"avatar_decoration": null},"attachments": [{"id": "1109565863994077215","filename": "johnsonmaureen_1684582132_a_dog_a062b5e2-ab39-40b0-b281-1365695529d5.png","size": 4275948,"url": "https://cdn.discordapp.com/attachments/1109368983364313204/1109565863994077215/johnsonmaureen_1684582132_a_dog_a062b5e2-ab39-40b0-b281-1365695529d5.png","proxy_url": "https://media.discordapp.net/attachments/1109368983364313204/1109565863994077215/johnsonmaureen_1684582132_a_dog_a062b5e2-ab39-40b0-b281-1365695529d5.png","width": 2048,"height": 2048,"content_type": "image/png"}]}**省略其他数据**
]
返回结果为数组,还记得上面的msg_Id
吗,在JSON结构中查看content
部分,就可以看到
"content": "**[1684582132] a dog --seed 8925 --v 5** - <@1013684342851117146> (fast)",
所以,我们可以用这个字段来进行筛选。$.attachments[0].url
就是成图了。
- 选取生成大图
如果再返回的四张图有一张看得不错,怎么生成大图呢?先给你个表格,告诉你哪是1,哪是3
1 | 2 |
---|---|
3 | 4 |
然后来看如何传参
curl --location --request POST 'https://<你的发布地址服务>' \
--header 'User-Agent: apifox/1.0.0 (https://www.apifox.cn)' \
--header 'Content-Type: application/json' \
--data-raw '{"type": "upscale","param": {"id": "1109460470152319086","question":"a dog","index": 3,
"url":"https://cdn.discordapp.com/attachments/1109368983364313204/1109460469628022915/johnsonmaureen_1684585158_a_dog_d5b7e35c-0fce-4f7d-b440-35f5602d2f25.png"}
}'
解释下参数:
- id: 是查询返回结果体里的id
- question,是最开始输入进去的
prompt
- index: 你想要的第几张图
- url:是查询返回结果体里的url,四张图拼一起的那个。
别问我怎么知道的,我都是翻代码看得。
- 重绘
当看上这4张图中某一个的风格或者样式之后,可以根据这个风格重绘。
curl --location --request POST 'https://<你的发布地址服务>' \
--header 'User-Agent: apifox/1.0.0 (https://www.apifox.cn)' \
--header 'Content-Type: application/json' \
--data-raw '{"type": "variation","param": {"id": "1109460470152319086","question": "a dog","index": 3,"url": "https://cdn.discordapp.com/attachments/1109368983364313204/1109460469628022915/johnsonmaureen_1684585158_a_dog_d5b7e35c-0fce-4f7d-b440-35f5602d2f25.png"}
}'
参数解释不说了,跟上面类似。
至此教程结束了
赶紧去上手做点什么吧,实践出真知~
作品展示
这次其实是laf在组织活动,想我这种平台级别思考大佬的人,不会去钻到某个应用当中,我来看看大家都画了什么图,所以我做了个简陋的页面,本人前端能力有限,代码实现全靠ChatGPT。
上链接:
laf比赛作品大赏
如果觉得不错打个赏吧,后面是答疑环节
问题
- 我怎么知道mj的图画完没有呢?
可以根据$.attachments[0].width
的尺寸大小来看,如果小于2048,则没有生成完,没生成完其实应该是512。 - 怎么让图片结果与请求msg_Id绑定?
正如上文所说要自己实现一个逻辑去匹配结果,另外还有一个就是用好触发器,他会定时执行你的服务,这样你就可以将数据进行增量处理。
`