⤴️如何使用 Nest.js 构建 Midjourney API🚀
TL;DR
在这篇文章中,我将向您展示使用 Typescript 和 Nest.js 构建非官方 Midjourney API 的架构。
DeepEval——LLM 应用程序的开源评估框架
DeepEval 根据事实一致性、准确性、答案相关性等指标来评估性能
我们才刚刚起步。
能帮我们加个星吗?😽
https://github.com/confident-ai/deepeval
➡️ 请点赞、关注并加星标这篇文章
我们要建造什么?
首先,让我们了解一下 Mindjourney 在 Discord 上的工作原理。人们使用简单的命令与人工智能机器人对话。机器人会接收这些命令,并根据用户的描述创建图片。
为了模拟这种行为,我们需要创建一个与 Discord 机器人交互的 API。该机器人能够与 Discord 交互,从而向 Midjourney 发送命令。命令流的高级设计如下:
重要提示:本教程仅用于教育目的,旨在帮助您了解 Discord 与 Midjourney 的交互方式。不建议将其用作生产服务或任何官方项目。
我选择 Nest.js 的原因是,市面上有很多 Python 示例教你如何为 Midjourney 构建 API,但却没有一个像样的案例能完整地展示如何使用 JavaScript 或 Node.js 完成整个流程。我更喜欢使用 Nest.js,因为它的组织结构清晰,并且易于引导项目启动。
连接 Midjourney 的 Discord 机器人
由于缺乏正式的 API,可以通过 Discord 机器人连接到 Midjourney。该过程包括以下步骤。
重要提示:为了使此功能正常工作,您必须拥有 Midjourney 订阅。
步骤 1:创建 Discord 机器人。
请花点时间帮我一下。我正在努力打造最好的LLM评估开源项目。
请给我一颗星 - 我会非常感激。
构建完整的 Midjourney API 的第一步是创建我们的 Discord 机器人。Discord 提供了一个界面,可用于创建不同用途的机器人。现在就创建你的 MJ 机器人吧。
这是一篇关于创建 Discord 机器人的很棒的文章。
创建机器人后,您将收到一个邀请链接。使用它来邀请机器人加入您的 Discord 服务器——稍后我们将使用它来生成和接收图像。
步骤 2:执行 /Imagine 命令
创建Nest.js应用后,请继续创建discord
模块。该模块将与我们的 Discord 服务器和 MidJourney 进行交互。
让我们从我们的控制器开始,它应该看起来像这样:
@Controller('discord')
export class DiscordController {
constructor(private discordService: DiscordService) {}
@Post('imagine')
async imagine(@Body('prompt') prompt: string): Promise<any> {
return this.discordService.sendImagineCommand(prompt);
}
}
如你所见,我创建了一个包含单个POST
请求的 Discord 模块。我们将向请求传递一个prompt
参数discord/imagine
。
接下来,让我们创建我们的 discord 服务:
@Injectable()
export class DiscordService {
constructor(private readonly httpService: HttpService) {}
async sendImagineCommand(prompt: string): Promise<any> {
const postUrl = "https://discord.com/api/v9/interactions";
const uniqueId = this.generateId();
const postPayload = {
type: 2,
application_id: <APPLICATION_ID>,
guild_id: <GUILD_ID>,
channel_id: <CHANNEL_ID>,
session_id: <SESSION_ID>,
data: {
version: <COMMAND_VERSION>,
id: <IMAGINE_COMMAND_ID>,
name: "imagine",
type: 1,
options: [
{
type: 3,
name: "prompt",
value: `${prompt} --no ${uniqueId}`
}
],
application_command: {
id: <IMAGINE_COMMAND_ID>,
application_id: <APPLICATION_ID>,
version: <COMMAND_VERSION>,
default_member_permissions: null,
type: 1,
nsfw: false,
name: "imagine",
description: "Create images with Midjourney",
dm_permission: true,
contexts: [0, 1, 2],
options: [
{
type: 3,
name: "prompt",
description: "The prompt to imagine",
required: true
}
]
},
attachments: []
}
};
const postHeaders = {
authorization: <your auth token>,
"Content-Type": "application/json"
};
this.httpService
.post(postUrl, postPayload, { headers: postHeaders })
.toPromise()
.then(console.log);
return uniqueId;
}
generateId(): number {
return Math.floor(Math.random() * 1000);
}
}
您会注意到以下几点:
-
我们使用
https://discord.com/api/v9/interactions
Discord 端点与 Discord 服务器交互并发送命令。这是处理 Midjourney 请求的主要入口点。 -
我们模拟了网页浏览器向 Discord 发出的请求,真正的“魔法”来了——
/imagine
登录 Midjourney 网页后,从 Discord 网页界面向 Midjourney 发送命令。
发送请求后,您会注意到Network
tab 中也发送了 imagine 命令,这与上面的非常相似。 -
复制相关字段:
IMAGINE_COMMAND_ID
、、、和。这些字段将在我们的服务中使用。我们还需要复制作为请求一部分发送的字段COMMAND_VERSION
。SESSION_ID
GUILD_ID
CHANNEL_ID
APPLICATION_ID
MIDJOURNEY_TOKEN
-
从我们之前创建的机器人应用程序页面复制
BOT_TOKEN
。这对于与我们的机器人进行通信非常重要。 -
您还会注意到
uniqueId
我们使用generateId()
函数生成的。这是使用 Midjourney 的--no
命令,以便我们稍后可以追溯发送到 Discord 的唯一请求并获取生成的图像。
完成此步骤后,您现在可以使用/imagine
命令调用 Discord 并使用 Midjourney 生成图像。
提醒:这只是一篇描述此流程如何工作的技术文章,不建议用于任何项目。
步骤 3:获取生成的图像。
让我们创建一个新的控制器来获取图像:
@Get('mj/results/:id')
async getMidjourneyResults(@Param('id') id: string) {
const image = await this.discordService.getResultFromMidjourney(id);
const attachmentUrl = get(image[0].attachments[0], 'url');
if (attachmentUrl) {
const urls = await this.discordService.processAndUpload(attachmentUrl);
return urls;
}
return image;
}
我们将使用id
创建/imagine
请求时生成的唯一信息来从 Discord 获取结果。
async getResultFromMidjourney(id: string): Promise<any> {
const headers = {
"Authorization": MIDJOURNEY_TOKEN,
"Content-Type": "application/json"
};
const channelUrl = `https://discord.com/api/v9/channels/${CHANNEL_ID}/messages?limit=50`;
try {
const response = await this.httpService.get(channelUrl, { headers: headers }).toPromise();
const data = response.data;
const matchingMessage = data.filter(message =>
message.content.includes(id) &&
message
.components
.some(component => component.components.some(c => c.label === "U1") ) // means that we can upscale results
) || [];
if (!matchingMessage.length) {
return null;
}
if (matchingMessage.attachments && matchingMessage.attachments.length > 0) {
for (const attachment of matchingMessage.attachments) {
attachment.url = await this.fetchAndEncodeImage(attachment.url);
}
}
return matchingMessage;
} catch (error) {
// do something
}
}
async fetchAndEncodeImage(url: string): Promise<string> {
const response: AxiosResponse<any> = await this.httpService.get(url, {
responseType: 'arraybuffer',
}).toPromise();
const base64 = Buffer.from(response.data, 'binary').toString('base64');
return `data:${response.headers['content-type']};base64,${base64}`;
}
https://discord.com/api/v9/channels/${CHANNEL_ID}/messages?limit=50
端点用于获取我们的 Discord 频道并获取响应以检索我们的图像。
由于 Midjourney 生成大约需要 60 秒或更长时间,我们需要每 x 秒轮询一次该通道以检查结果。
让我们尝试一下{ prompt: "a cat" }
:
就这样!现在你应该拥有一个功能齐全的 Midjourney API,可以用于测试和娱乐,并且你也了解了 Discord 机器人架构的工作原理。
最后的想法
现在,您已经拥有一个引导项目,它演示了 Discord 如何与 MidJourney 通信,从而生成令人惊叹的 AI 图像。
您可以构建一个美观的 UI,并拥有自己的生成式 AI 平台。祝您好运!