@brojs/kandinsky
Version:
JavaScript library for Kandinsky AI image generation
187 lines (186 loc) • 7.77 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.KandinskyAPI = exports.AspectRatio = void 0;
const axios_1 = __importDefault(require("axios"));
const form_data_1 = __importDefault(require("form-data"));
/**
* Популярные соотношения сторон для генерации изображений.
* Используется для удобного указания стандартных пропорций изображения.
*
* @example
* // Квадратное изображение
* const params = {
* query: 'кот',
* aspectRatio: AspectRatio.Square_1_1
* };
*
* @example
* // Вертикальное изображение для Instagram
* const params = {
* query: 'портрет',
* aspectRatio: AspectRatio.Vertical_2_3
* };
*
* @example
* // Широкоформатное изображение для видео
* const params = {
* query: 'пейзаж',
* aspectRatio: AspectRatio.Horizontal_16_9
* };
*/
var AspectRatio;
(function (AspectRatio) {
/**
* Квадратное изображение (1:1)
* Идеально подходит для аватарок, миниатюр и социальных сетей
* @example
* aspectRatio: AspectRatio.Square_1_1 // 1024x1024
*/
AspectRatio[AspectRatio["Square_1_1"] = 1] = "Square_1_1";
/**
* Вертикальное изображение (2:3)
* Стандартное соотношение для портретов и вертикальных фотографий
* @example
* aspectRatio: AspectRatio.Vertical_2_3 // 682x1024
*/
AspectRatio[AspectRatio["Vertical_2_3"] = 0.6666666666666666] = "Vertical_2_3";
/**
* Горизонтальное изображение (3:2)
* Классическое соотношение для пейзажей и горизонтальных фотографий
* @example
* aspectRatio: AspectRatio.Horizontal_3_2 // 1024x682
*/
AspectRatio[AspectRatio["Horizontal_3_2"] = 1.5] = "Horizontal_3_2";
/**
* Вертикальное изображение (9:16)
* Соотношение для мобильных устройств и сторис
* @example
* aspectRatio: AspectRatio.Vertical_9_16 // 576x1024
*/
AspectRatio[AspectRatio["Vertical_9_16"] = 0.5625] = "Vertical_9_16";
/**
* Широкоформатное изображение (16:9)
* Стандартное соотношение для видео и широкоформатных дисплеев
* @example
* aspectRatio: AspectRatio.Horizontal_16_9 // 1024x576
*/
AspectRatio[AspectRatio["Horizontal_16_9"] = 1.7777777777777777] = "Horizontal_16_9";
})(AspectRatio || (exports.AspectRatio = AspectRatio = {}));
class KandinskyAPI {
constructor({ apiKey, secretKey } = {}) {
this.pipelineId = null;
this.apiKey = apiKey || process.env.KANDINSKY_API_KEY || '';
this.secretKey = secretKey || process.env.KANDINSKY_SECRET_KEY || '';
if (!this.apiKey || !this.secretKey) {
throw new Error('API key and Secret key are required');
}
this.client = axios_1.default.create({
baseURL: 'https://api-key.fusionbrain.ai/',
headers: {
'X-Key': `Key ${this.apiKey}`,
'X-Secret': `Secret ${this.secretKey}`,
},
});
}
async getPipeline() {
if (this.pipelineId !== null) {
return this.pipelineId;
}
const response = await this.client.get('key/api/v1/pipelines');
const id = response.data[0].id;
if (typeof id !== 'string') {
throw new Error('Invalid pipeline ID received');
}
this.pipelineId = id;
return id;
}
calculateDimensions(params) {
const MAX_SIZE = 1024;
const MIN_SIZE = 256;
// Если указаны и width, и height, используем их
if (params.width && params.height) {
return {
width: Math.min(Math.max(params.width, MIN_SIZE), MAX_SIZE),
height: Math.min(Math.max(params.height, MIN_SIZE), MAX_SIZE)
};
}
// Если указан aspectRatio
if (params.aspectRatio) {
let width = params.width || MAX_SIZE;
let height = params.height || MAX_SIZE;
if (params.width) {
// Если указана только ширина, вычисляем высоту
height = Math.round(width / params.aspectRatio);
}
else if (params.height) {
// Если указана только высота, вычисляем ширину
width = Math.round(height * params.aspectRatio);
}
else {
// Если не указаны ни ширина, ни высота, используем максимальный размер
if (params.aspectRatio > 1) {
width = MAX_SIZE;
height = Math.round(MAX_SIZE / params.aspectRatio);
}
else {
height = MAX_SIZE;
width = Math.round(MAX_SIZE * params.aspectRatio);
}
}
// Проверяем ограничения
width = Math.min(Math.max(width, MIN_SIZE), MAX_SIZE);
height = Math.min(Math.max(height, MIN_SIZE), MAX_SIZE);
return { width, height };
}
// Если не указаны ни размеры, ни aspectRatio, используем значения по умолчанию
return {
width: MAX_SIZE,
height: MAX_SIZE
};
}
async generate(params) {
const pipelineId = await this.getPipeline();
const dimensions = this.calculateDimensions(params);
const requestParams = {
type: 'GENERATE',
numImages: params.numImages || 1,
width: dimensions.width,
height: dimensions.height,
style: params.style || undefined,
negativePromptDecoder: params.negativePromptDecoder || undefined,
generateParams: {
query: params.query,
},
};
const formData = new form_data_1.default();
formData.append('pipeline_id', pipelineId);
formData.append('params', JSON.stringify(requestParams), {
contentType: 'application/json'
});
const response = await this.client.post('key/api/v1/pipeline/run', formData, {
headers: {
...formData.getHeaders(),
},
});
const uuid = response.data.uuid;
return this.waitForGeneration(uuid, params.attempts, params.delay);
}
async waitForGeneration(uuid, attempts = 10, delay = 2000) {
for (let i = 0; i < attempts; i++) {
const response = await this.client.get(`key/api/v1/pipeline/status/${uuid}`);
const data = response.data;
if (data.status === 'DONE' && data.result) {
return data.result.files;
}
if (data.status === 'FAIL') {
throw new Error(data.errorDescription || 'Generation failed');
}
await new Promise(resolve => setTimeout(resolve, delay));
}
throw new Error('Generation timeout');
}
}
exports.KandinskyAPI = KandinskyAPI;