midjourney
Version:
Node.js client for the unofficial MidJourney API.
313 lines • 10.8 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MidjourneyApi = void 0;
const tslib_1 = require("tslib");
const interfaces_1 = require("./interfaces");
const utils_1 = require("./utils");
const command_1 = require("./command");
const async_1 = tslib_1.__importDefault(require("async"));
class MidjourneyApi extends command_1.Command {
config;
UpId = Date.now() % 10; // upload id
constructor(config) {
super(config);
this.config = config;
}
safeIteractions = (request) => {
return new Promise((resolve, reject) => {
this.queue.push({
request,
callback: (any) => {
resolve(any);
},
}, (error, result) => {
if (error) {
reject(error);
}
else {
resolve(result);
}
});
});
};
processRequest = async ({ request, callback, }) => {
const httpStatus = await this.interactions(request);
callback(httpStatus);
await (0, utils_1.sleep)(this.config.ApiInterval);
};
queue = async_1.default.queue(this.processRequest, 1);
interactions = async (payload) => {
try {
const headers = {
"Content-Type": "application/json",
Authorization: this.config.SalaiToken,
};
const response = await this.config.fetch(`${this.config.DiscordBaseUrl}/api/v9/interactions`, {
method: "POST",
body: JSON.stringify(payload),
headers: headers,
});
if (response.status >= 400) {
console.error("api.error.config", {
payload: JSON.stringify(payload),
config: this.config,
});
}
return response.status;
}
catch (error) {
console.error(error);
return 500;
}
};
async ImagineApi(prompt, nonce = (0, utils_1.nextNonce)()) {
const payload = await this.imaginePayload(prompt, nonce);
return this.safeIteractions(payload);
}
async SwitchRemixApi(nonce = (0, utils_1.nextNonce)()) {
const payload = await this.PreferPayload(nonce);
return this.safeIteractions(payload);
}
async ShortenApi(prompt, nonce = (0, utils_1.nextNonce)()) {
const payload = await this.shortenPayload(prompt, nonce);
return this.safeIteractions(payload);
}
async VariationApi({ index, msgId, hash, nonce = (0, utils_1.nextNonce)(), flags = 0, }) {
return this.CustomApi({
msgId,
customId: `MJ::JOB::variation::${index}::${hash}`,
flags,
nonce,
});
}
async UpscaleApi({ index, msgId, hash, nonce = (0, utils_1.nextNonce)(), flags, }) {
return this.CustomApi({
msgId,
customId: `MJ::JOB::upsample::${index}::${hash}`,
flags,
nonce,
});
}
async RerollApi({ msgId, hash, nonce = (0, utils_1.nextNonce)(), flags, }) {
return this.CustomApi({
msgId,
customId: `MJ::JOB::reroll::0::${hash}::SOLO`,
flags,
nonce,
});
}
async CustomApi({ msgId, customId, flags, nonce = (0, utils_1.nextNonce)(), }) {
if (!msgId)
throw new Error("msgId is empty");
if (flags === undefined)
throw new Error("flags is undefined");
const payload = {
type: 3,
nonce,
guild_id: this.config.ServerId,
channel_id: this.config.ChannelId,
message_flags: flags,
message_id: msgId,
application_id: this.config.BotId,
session_id: this.config.SessionId,
data: {
component_type: 2,
custom_id: customId,
},
};
return this.safeIteractions(payload);
}
//FIXME: get SubmitCustomId from discord api
async ModalSubmitApi({ nonce, msgId, customId, prompt, submitCustomId, }) {
var payload = {
type: 5,
application_id: this.config.BotId,
channel_id: this.config.ChannelId,
guild_id: this.config.ServerId,
data: {
id: msgId,
custom_id: customId,
components: [
{
type: 1,
components: [
{
type: 4,
custom_id: submitCustomId,
value: prompt,
},
],
},
],
},
session_id: this.config.SessionId,
nonce,
};
console.log("submitCustomId", JSON.stringify(payload));
return this.safeIteractions(payload);
}
async RemixApi({ nonce, msgId, customId, prompt, }) {
return this.ModalSubmitApi({
nonce,
msgId,
customId,
prompt,
submitCustomId: interfaces_1.RemixModalSubmitID,
});
}
async ShortenImagineApi({ nonce, msgId, customId, prompt, }) {
return this.ModalSubmitApi({
nonce,
msgId,
customId,
prompt,
submitCustomId: interfaces_1.ShortenModalSubmitID,
});
}
async DescribeImagineApi({ nonce, msgId, customId, prompt, }) {
return this.ModalSubmitApi({
nonce,
msgId,
customId,
prompt,
submitCustomId: interfaces_1.DescribeModalSubmitID,
});
}
async CustomZoomImagineApi({ nonce, msgId, customId, prompt, }) {
customId = customId.replace("MJ::CustomZoom", "MJ::OutpaintCustomZoomModal");
return this.ModalSubmitApi({
nonce,
msgId,
customId,
prompt,
submitCustomId: interfaces_1.CustomZoomModalSubmitID,
});
}
async InfoApi(nonce) {
const payload = await this.infoPayload(nonce);
return this.safeIteractions(payload);
}
async SettingsApi(nonce) {
const payload = await this.settingsPayload(nonce);
return this.safeIteractions(payload);
}
async FastApi(nonce) {
const payload = await this.fastPayload(nonce);
return this.safeIteractions(payload);
}
async RelaxApi(nonce) {
const payload = await this.relaxPayload(nonce);
return this.safeIteractions(payload);
}
/**
*
* @param fileUrl http file path
* @returns
*/
async UploadImageByUri(fileUrl) {
const response = await this.config.fetch(fileUrl);
const fileData = await response.arrayBuffer();
const mimeType = response.headers.get("content-type");
const filename = fileUrl.split("/").pop() || "image.png";
const file_size = fileData.byteLength;
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 resp = {
id: UploadSlot.id,
filename: UploadSlot.upload_filename.split("/").pop() || "image.png",
upload_filename: UploadSlot.upload_filename,
};
return resp;
}
async UploadImageByBole(blob, filename = (0, utils_1.nextNonce)() + ".png") {
const fileData = await blob.arrayBuffer();
const mimeType = blob.type;
const file_size = fileData.byteLength;
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 resp = {
id: UploadSlot.id,
filename: UploadSlot.upload_filename.split("/").pop() || "image.png",
upload_filename: UploadSlot.upload_filename,
};
return resp;
}
/**
* prepare an attachement to upload an image.
*/
async attachments(...files) {
const { SalaiToken, DiscordBaseUrl, ChannelId, fetch } = this.config;
const headers = {
Authorization: SalaiToken,
"content-type": "application/json",
};
const url = new URL(`${DiscordBaseUrl}/api/v9/channels/${ChannelId}/attachments`);
const body = { files };
const response = await this.config.fetch(url, {
headers,
method: "POST",
body: JSON.stringify(body),
});
if (response.status === 200) {
return (await response.json());
}
const error = `Attachments return ${response.status} ${response.statusText} ${await response.text()}`;
throw new Error(error);
}
async uploadImage(slot, data, contentType) {
const body = new Uint8Array(data);
const headers = { "content-type": contentType };
const response = await this.config.fetch(slot.upload_url, {
method: "PUT",
headers,
body,
});
if (!response.ok) {
throw new Error(`uploadImage return ${response.status} ${response.statusText} ${await response.text()}`);
}
}
async DescribeApi(image, nonce) {
const payload = await this.describePayload(image, nonce);
return this.safeIteractions(payload);
}
async upImageApi(image, nonce) {
const { SalaiToken, DiscordBaseUrl, ChannelId, fetch } = this.config;
const payload = {
content: "",
nonce,
channel_id: ChannelId,
type: 0,
sticker_ids: [],
attachments: [image],
};
const url = new URL(`${DiscordBaseUrl}/api/v9/channels/${ChannelId}/messages`);
const headers = {
Authorization: SalaiToken,
"content-type": "application/json",
};
const response = await fetch(url, {
headers,
method: "POST",
body: JSON.stringify(payload),
});
return response.status;
}
}
exports.MidjourneyApi = MidjourneyApi;
//# sourceMappingURL=midjourney.api.js.map