UNPKG

@brojs/kandinsky

Version:

JavaScript library for Kandinsky AI image generation

187 lines (186 loc) 7.77 kB
"use strict"; 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;