relax-mj
Version:
Node.js client for the unofficial MidJourney API.
372 lines • 13.2 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MidjourneyApi = void 0;
const tslib_1 = require("tslib");
const queue_1 = require("./queue");
const utls_1 = require("./utls");
const node_fetch_1 = tslib_1.__importDefault(require("node-fetch"));
const https_proxy_agent_1 = require("https-proxy-agent");
const fs = tslib_1.__importStar(require("fs"));
const path_1 = tslib_1.__importDefault(require("path"));
const mime = tslib_1.__importStar(require("mime"));
class MidjourneyApi {
config;
apiQueue = (0, queue_1.CreateQueue)(1);
Agent;
UpId = Date.now() % 10; // upload id
constructor(config) {
this.config = config;
if (this.config.ProxyUrl && this.config.ProxyUrl !== "") {
this.Agent = new https_proxy_agent_1.HttpsProxyAgent(this.config.ProxyUrl);
}
}
// limit the number of concurrent interactions
async safeIteractions(payload) {
return this.apiQueue.addTask(() => new Promise((resolve) => {
this.interactions(payload, (res) => {
resolve(res);
});
}));
}
async interactions(payload, callback) {
try {
const headers = {
"Content-Type": "application/json",
Authorization: this.config.SalaiToken,
};
const agent = this.Agent;
const response = await (0, node_fetch_1.default)(`${this.config.DiscordBaseUrl}/api/v9/interactions`, {
method: "POST",
body: JSON.stringify(payload),
headers: headers,
agent,
});
callback && callback(response.status);
//discord api rate limit
await (0, utls_1.sleep)(950);
if (response.status >= 400) {
console.error("api.error.config", { config: this.config });
}
return response.status;
}
catch (error) {
console.error(error);
callback && callback(500);
}
}
async ImagineApi(prompt, nonce = (0, utls_1.nextNonce)()) {
const guild_id = this.config.ServerId;
const payload = {
type: 2,
application_id: "936929561302675456",
guild_id,
channel_id: this.config.ChannelId,
session_id: this.config.SessionId,
data: {
version: "1166847114203123795",
id: "938956540159881230",
name: "imagine",
type: 1,
options: [
{
type: 3,
name: "prompt",
value: prompt,
},
],
application_command: {
id: "938956540159881230",
application_id: "936929561302675456",
version: "1166847114203123795",
default_permission: true,
default_member_permissions: null,
type: 1,
nsfw: false,
name: "imagine",
description: "Create images with Midjourney",
dm_permission: true,
options: [
{
type: 3,
name: "prompt",
description: "The prompt to imagine",
required: true,
},
],
},
attachments: [],
},
nonce,
};
return this.safeIteractions(payload);
}
async VariationApi(index, messageId, messageHash, nonce) {
const payload = {
type: 3,
guild_id: this.config.ServerId,
channel_id: this.config.ChannelId,
message_flags: 0,
message_id: messageId,
application_id: "936929561302675456",
session_id: this.config.SessionId,
data: {
component_type: 2,
custom_id: `MJ::JOB::variation::${index}::${messageHash}`,
},
nonce,
};
return this.safeIteractions(payload);
}
async UpscaleApi(index, messageId, messageHash, nonce) {
const guild_id = this.config.ServerId;
const payload = {
type: 3,
guild_id,
channel_id: this.config.ChannelId,
message_flags: 0,
message_id: messageId,
application_id: "936929561302675456",
session_id: this.config.SessionId,
data: {
component_type: 2,
custom_id: `MJ::JOB::upsample::${index}::${messageHash}`,
},
nonce,
};
return this.safeIteractions(payload);
}
async ClickBtnApi(messageId, customId, nonce) {
const guild_id = this.config.ServerId;
const payload = {
type: 3,
nonce,
guild_id,
channel_id: this.config.ChannelId,
message_flags: 0,
message_id: messageId,
application_id: "936929561302675456",
session_id: this.config.SessionId,
data: {
component_type: 2,
custom_id: customId,
},
};
return this.safeIteractions(payload);
}
async InfoApi(nonce) {
const guild_id = this.config.ServerId;
const payload = {
type: 2,
application_id: "936929561302675456",
guild_id,
channel_id: this.config.ChannelId,
session_id: this.config.SessionId,
data: {
version: "987795925764280356",
id: "972289487818334209",
name: "info",
type: 1,
options: [],
application_command: {
id: "972289487818334209",
application_id: "936929561302675456",
version: "987795925764280356",
default_member_permissions: null,
type: 1,
nsfw: false,
name: "info",
description: "View information about your profile.",
dm_permission: true,
contexts: null,
},
attachments: [],
},
nonce,
};
return this.safeIteractions(payload);
}
async FastApi(nonce) {
const guild_id = this.config.ServerId;
const payload = {
type: 2,
application_id: "936929561302675456",
guild_id,
channel_id: this.config.ChannelId,
session_id: this.config.SessionId,
data: {
version: "987795926183731231",
id: "972289487818334212",
name: "fast",
type: 1,
options: [],
application_command: {
id: "972289487818334212",
application_id: "936929561302675456",
version: "987795926183731231",
default_member_permissions: null,
type: 1,
nsfw: false,
name: "fast",
description: "Switch to fast mode",
dm_permission: true,
contexts: null,
},
attachments: [],
},
nonce,
};
return this.safeIteractions(payload);
}
async RelaxApi(nonce) {
const guild_id = this.config.ServerId;
const channel_id = this.config.ChannelId;
const payload = {
type: 2,
application_id: "936929561302675456",
guild_id,
channel_id,
session_id: this.config.SessionId,
data: {
version: "987795926183731232",
id: "972289487818334213",
name: "relax",
type: 1,
options: [],
application_command: {
id: "972289487818334213",
application_id: "936929561302675456",
version: "987795926183731232",
default_member_permissions: null,
type: 1,
nsfw: false,
name: "relax",
description: "Switch to relax mode",
dm_permission: true,
contexts: null,
},
attachments: [],
},
nonce,
};
return this.safeIteractions(payload);
}
/**
*
* @param fileUrl http or local file path
* @returns
*/
async UploadImage(fileUrl) {
let fileData;
let mimeType;
let filename;
let file_size;
if (fileUrl.startsWith("http")) {
const response = await (0, node_fetch_1.default)(fileUrl);
fileData = await response.arrayBuffer();
mimeType = response.headers.get("content-type");
filename = path_1.default.basename(fileUrl) || "image.png";
file_size = fileData.byteLength;
}
else {
fileData = await fs.promises.readFile(fileUrl);
mimeType = mime.getType(fileUrl);
filename = path_1.default.basename(fileUrl);
file_size = (await fs.promises.stat(fileUrl)).size;
}
if (!mimeType) {
throw new Error("Unknown mime type");
}
const { attachments } = await this.attachments({
filename,
file_size,
id: this.UpId++,
});
const UploadSlot = attachments[0];
await this.uploadImage(UploadSlot, fileData, mimeType);
const response = {
id: UploadSlot.id,
filename: path_1.default.basename(UploadSlot.upload_filename),
upload_filename: UploadSlot.upload_filename,
};
return response;
}
/**
* prepare an attachement to upload an image.
*/
async attachments(...files) {
const headers = {
Authorization: this.config.SalaiToken,
"content-type": "application/json",
};
const url = new URL(`${this.config.DiscordBaseUrl}/api/v9/channels/${this.config.ChannelId}/attachments`);
const body = { files };
const response = await (0, node_fetch_1.default)(url.toString(), {
headers,
method: "POST",
body: JSON.stringify(body),
});
if (response.status === 200) {
return (await response.json());
}
throw new Error(`Attachments return ${response.status} ${response.statusText} ${await response.text()}`);
}
async uploadImage(slot, data, contentType) {
const body = new Uint8Array(data);
const headers = { "content-type": contentType };
const response = await (0, node_fetch_1.default)(slot.upload_url, {
method: "PUT",
headers,
body,
});
if (!response.ok) {
throw new Error(`uploadImage return ${response.status} ${response.statusText} ${await response.text()}`);
}
}
async DescribeApi(data, nonce) {
const payload = {
type: 2,
application_id: "936929561302675456",
guild_id: this.config.ServerId,
channel_id: this.config.ChannelId,
session_id: this.config.SessionId,
data: {
version: "1092492867185950853",
id: "1092492867185950852",
name: "describe",
type: 1,
options: [{ type: 11, name: "image", value: data.id }],
application_command: {
id: "1092492867185950852",
application_id: "936929561302675456",
version: "1092492867185950853",
default_member_permissions: null,
type: 1,
nsfw: false,
name: "describe",
description: "Writes a prompt based on your image.",
dm_permission: true,
contexts: null,
options: [
{
type: 11,
name: "image",
description: "The image to describe",
required: true,
},
],
},
attachments: [
{
id: data.id,
filename: data.filename,
uploaded_filename: data.upload_filename,
},
],
},
nonce,
};
return this.safeIteractions(payload);
}
}
exports.MidjourneyApi = MidjourneyApi;
//# sourceMappingURL=midjourne.api.js.map