API Документация v2.0
🚀 Ключевые возможности
- ✨ Text-to-Image - генерация изображений по текстовому описанию
- 🎨 Image-to-Image - трансформация и стилизация изображений
- 🔍 Upscaling - увеличение разрешения с улучшением качества
- 🎭 LoRA модели - специализированные стили и эффекты
- 📊 Детальная аналитика - статистика использования
- 🔄 Real-time обновления - WebSocket поддержка
- 📦 Batch обработка - массовая генерация
- 🔔 Webhooks - автоматические уведомления
- 🎯 Smart Upscale - интеллектуальное масштабирование
📍 Базовая информация
| Базовый URL | https://image.nalitek.com |
| Версия API | 2.0 |
| Формат данных | JSON |
| Аутентификация | API Key в заголовке X-API-Key |
Быстрый старт
Шаг 1: Получите API ключ
Зарегистрируйтесь на сайте и получите API ключ в личном кабинете.
Шаг 2: Сделайте первый запрос
import requests
api_key = "your-api-key"
url = "https://image.nalitek.com/api/generate"
response = requests.post(url,
json={
"prompt": "beautiful sunset over mountains, professional photography",
"width": 512, # Быстрая генерация в низком разрешении
"height": 512,
"smart_upscale": True, # Автоматическое увеличение до HD
"target_width": 2048,
"target_height": 2048,
"model": "flux-dev"
},
headers={"X-API-Key": api_key}
)
data = response.json()
print(f"Image ID: {data['image_id']}")
print(f"Generation ID: {data['generation_id']}")
print(f"Progress URL: {data['progress_url']}")
const apiKey = 'your-api-key';
const url = 'https://image.nalitek.com/api/generate';
fetch(url, {
method: 'POST',
headers: {
'X-API-Key': apiKey,
'Content-Type': 'application/json'
},
body: JSON.stringify({
prompt: 'beautiful sunset over mountains, professional photography',
width: 512, // Быстрая генерация в низком разрешении
height: 512,
smart_upscale: true, // Автоматическое увеличение до HD
target_width: 2048,
target_height: 2048,
model: 'flux-dev'
})
})
.then(res => res.json())
.then(data => {
console.log(`Image ID: ${data.image_id}`);
console.log(`Generation ID: ${data.generation_id}`);
});
$apiKey = 'your-api-key';
$url = 'https://image.nalitek.com/api/generate';
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
'prompt' => 'beautiful sunset over mountains, professional photography',
'width' => 512, // Быстрая генерация в низком разрешении
'height' => 512,
'smart_upscale' => true, // Автоматическое увеличение до HD
'target_width' => 2048,
'target_height' => 2048,
'model' => 'flux-dev'
]));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'X-API-Key: ' . $apiKey,
'Content-Type: application/json'
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
$data = json_decode($response, true);
echo "Image ID: " . $data['image_id'];
curl -X POST https://image.nalitek.com/api/generate \
-H "X-API-Key: your-api-key" \
-H "Content-Type: application/json" \
-d '{
"prompt": "beautiful sunset over mountains, professional photography",
"width": 512,
"height": 512,
"smart_upscale": true,
"target_width": 2048,
"target_height": 2048,
"model": "flux-dev"
}'
Аутентификация
🔐 Использование API ключа
Передавайте ключ в заголовке X-API-Key каждого запроса:
X-API-Key: your-api-key-here
🛡️ Рекомендации по безопасности
- 🔒 Никогда не передавайте API ключ в URL параметрах
- 🔐 Не храните ключ в публичных репозиториях
- 🔑 Используйте переменные окружения для хранения
- 🔄 Регулярно обновляйте ключи
- 📊 Мониторьте использование API в личном кабинете
- 🚫 Ограничивайте доступ по IP для production ключей
Генерация изображений
/api/generate
Создание изображения по текстовому описанию с поддержкой различных моделей и стилей.
Параметры запроса
| Параметр | Тип | Описание | По умолчанию |
|---|---|---|---|
| prompt required | string | Текстовое описание желаемого изображения | - |
| negative_prompt optional | string | Что исключить из генерации | "" |
| width optional | integer | Ширина изображения (512-2048, кратно 64) | 1024 |
| height optional | integer | Высота изображения (512-2048, кратно 64) | 1024 |
| steps optional | integer | Количество шагов генерации (10-100) | 30 |
| guidance_scale optional | float | Сила следования промпту (1.0-20.0) | 7.5 |
| seed optional | integer | Seed для воспроизводимости (-1 = random) | -1 |
| lora_ids optional | array | Массив ID LoRA моделей для стилизации | [] |
| format optional | string | Формат изображения (png/jpeg/webp) | png |
| model optional | string | Модель генерации (flux-dev/flux-schnell) | flux-dev |
| smart_upscale optional | boolean | Автоматическое увеличение с коэффициентом 2x. При запросе размера >512px генерирует в половинном размере и масштабирует до целевого | true |
Ответ успешной генерации
{
"image_id": 4738,
"status": "generating",
"generation_id": "gen_17368567894738",
"url": null,
"thumbnail_url": null,
"prompt": "beautiful sunset over mountains, professional photography, golden hour lighting",
"seed": 8472659,
"dimensions": "1024x1024",
"estimated_time": 28,
"progress_url": "/api/images/4738",
"websocket_channel": "generation_4738"
}
Примеры использования
# Простая генерация
curl -X POST https://image.nalitek.com/api/generate \
-H "X-API-Key: your-api-key" \
-H "Content-Type: application/json" \
-d '{
"prompt": "beautiful sunset over mountains",
"width": 1024,
"height": 1024,
"steps": 30
}'
# С дополнительными параметрами
curl -X POST https://image.nalitek.com/api/generate \
-H "X-API-Key: your-api-key" \
-H "Content-Type: application/json" \
-d '{
"prompt": "futuristic city at night, neon lights, cyberpunk style",
"negative_prompt": "blurry, low quality, distorted",
"width": 1920,
"height": 1080,
"steps": 50,
"guidance_scale": 8.5,
"seed": 42,
"model": "flux-dev",
"format": "png"
}'
# С Smart Upscale
curl -X POST https://image.nalitek.com/api/generate \
-H "X-API-Key: your-api-key" \
-H "Content-Type: application/json" \
-d '{
"prompt": "ultra detailed portrait of a woman",
"width": 512,
"height": 512,
"steps": 30,
"smart_upscale": true,
"target_width": 2048,
"target_height": 2048
}'
# С LoRA моделью
curl -X POST https://image.nalitek.com/api/generate \
-H "X-API-Key: your-api-key" \
-H "Content-Type: application/json" \
-d '{
"prompt": "anime character, detailed eyes",
"width": 1024,
"height": 1024,
"lora_id": "anime-style-v2",
"steps": 30
}'
# Проверка статуса генерации
curl -X GET https://image.nalitek.com/api/images/4738 \
-H "X-API-Key: your-api-key"
import requests
import time
class FluxAPI:
def __init__(self, api_key):
self.api_key = api_key
self.base_url = "https://image.nalitek.com"
self.headers = {"X-API-Key": api_key, "Content-Type": "application/json"}
def generate_image(self, prompt, **kwargs):
"""Генерация изображения по промпту"""
url = f"{self.base_url}/api/generate"
data = {
"prompt": prompt,
"negative_prompt": kwargs.get("negative_prompt", ""),
"width": kwargs.get("width", 1024),
"height": kwargs.get("height", 1024),
"steps": kwargs.get("steps", 30),
"guidance_scale": kwargs.get("guidance_scale", 7.5),
"seed": kwargs.get("seed", -1),
"model": kwargs.get("model", "flux-dev"),
"format": kwargs.get("format", "png")
}
if "lora_id" in kwargs:
data["lora_id"] = kwargs["lora_id"]
# Добавляем параметры smart_upscale если указаны
if kwargs.get("smart_upscale"):
data["smart_upscale"] = kwargs.get("smart_upscale")
if "target_width" in kwargs:
data["target_width"] = kwargs["target_width"]
if "target_height" in kwargs:
data["target_height"] = kwargs["target_height"]
response = requests.post(url, json=data, headers=self.headers)
if response.status_code == 201:
result = response.json()
print(f"✅ Success! Generation ID: {result['generation_id']}")
print(f"📍 Progress URL: {result['progress_url']}")
print(f"🌱 Seed: {result['seed']}")
return result
else:
print(f"❌ Error: {response.status_code}")
print(response.json())
return None
def check_status(self, image_id):
"""Проверка статуса генерации"""
url = f"{self.base_url}/api/images/{image_id}"
response = requests.get(url, headers=self.headers)
return response.json()
def wait_for_completion(self, image_id, timeout=120):
"""Ожидание завершения генерации"""
start_time = time.time()
while time.time() - start_time < timeout:
status = self.check_status(image_id)
if status['status'] == 'completed':
print(f"✅ Completed! URL: {status['url']}")
return status
elif status['status'] == 'failed':
print(f"❌ Failed: {status.get('error_message')}")
return status
time.sleep(2)
print(f"⏱️ Timeout after {timeout} seconds")
return None
# Использование
api = FluxAPI("your-api-key")
# Пример 1: Простая генерация (smart upscale включен по умолчанию)
# При запросе 1024x1024, сгенерирует в 512x512 и масштабирует до 1024x1024
image = api.generate_image(
prompt="cyberpunk city at night, neon lights",
width=1024, # Целевой размер 1024x1024
height=1024, # Автоматически генерирует в 512x512 и масштабирует
steps=30,
guidance_scale=7.5
)
# Пример 2: Отключение smart upscale для прямой генерации
image = api.generate_image(
prompt="detailed portrait",
width=512,
height=512,
smart_upscale=False, # Генерировать напрямую в 512x512
steps=30
)
if image:
result = api.wait_for_completion(image['image_id'])
print(f"Generated and upscaled to {result['dimensions']}")
# Расширенная генерация с LoRA
image = api.generate_image(
prompt="beautiful japanese garden, cherry blossoms, koi pond",
negative_prompt="blurry, low quality, distorted",
width=1024,
height=1024,
steps=50,
guidance_scale=8.0,
model="flux-dev",
lora_id="anime-style-v2"
)
# Генерация с автоматическим upscale
# Генерируем в низком разрешении для скорости, затем автоматически увеличиваем
image = api.generate_image(
prompt="ultra realistic portrait, 8k quality, professional photography",
width=512, # Генерируем в низком разрешении
height=512,
smart_upscale=True, # Включаем автоматический upscale
target_width=2048, # Целевой размер после upscale
target_height=2048,
steps=30,
model="flux-dev"
)
if image:
result = api.wait_for_completion(image['image_id'])
print(f"Image automatically upscaled to {result['dimensions']}")
class FluxAPI {
constructor(apiKey) {
this.apiKey = apiKey;
this.baseUrl = 'https://image.nalitek.com';
}
async generateImage(prompt, options = {}) {
const url = `${this.baseUrl}/api/generate`;
const data = {
prompt: prompt,
negative_prompt: options.negative_prompt || '',
width: options.width || 1024,
height: options.height || 1024,
steps: options.steps || 30,
guidance_scale: options.guidance_scale || 7.5,
seed: options.seed || -1,
model: options.model || 'flux-dev',
format: options.format || 'png'
};
if (options.lora_id) {
data.lora_id = options.lora_id;
}
// Добавляем параметры smart_upscale если указаны
if (options.smart_upscale) {
data.smart_upscale = true;
if (options.target_width) {
data.target_width = options.target_width;
}
if (options.target_height) {
data.target_height = options.target_height;
}
}
try {
const response = await fetch(url, {
method: 'POST',
headers: {
'X-API-Key': this.apiKey,
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
if (response.status === 201) {
const result = await response.json();
console.log(`✅ Success! Generation ID: ${result.generation_id}`);
console.log(`📍 Progress URL: ${result.progress_url}`);
return result;
} else {
const error = await response.json();
console.error(`❌ Error: ${response.status}`, error);
return null;
}
} catch (error) {
console.error('Request failed:', error);
return null;
}
}
async checkStatus(imageId) {
const url = `${this.baseUrl}/api/images/${imageId}`;
const response = await fetch(url, {
headers: { 'X-API-Key': this.apiKey }
});
return response.json();
}
async waitForCompletion(imageId, timeout = 120000) {
const startTime = Date.now();
while (Date.now() - startTime < timeout) {
const status = await this.checkStatus(imageId);
if (status.status === 'completed') {
console.log(`✅ Completed! URL: ${status.url}`);
return status;
} else if (status.status === 'failed') {
console.error(`❌ Failed: ${status.error_message}`);
return status;
}
await new Promise(resolve => setTimeout(resolve, 2000));
}
console.error(`⏱️ Timeout after ${timeout}ms`);
return null;
}
}
// Использование
const api = new FluxAPI('your-api-key');
// Простая генерация с автоматическим upscale
async function generateSimple() {
const image = await api.generateImage('cyberpunk city at night, neon lights', {
width: 512, // Генерируем быстро в низком разрешении
height: 512,
smart_upscale: true, // Автоматически увеличиваем после генерации
target_width: 2048, // Финальный размер
target_height: 2048
});
if (image) {
const result = await api.waitForCompletion(image.image_id);
console.log(`Generated and upscaled to ${result.dimensions}`);
}
}
// Расширенная генерация
async function generateAdvanced() {
const image = await api.generateImage('beautiful japanese garden', {
negative_prompt: 'blurry, low quality',
width: 1024,
height: 1024,
steps: 50,
guidance_scale: 8.0,
model: 'flux-dev',
lora_id: 'anime-style-v2'
});
if (image) {
const result = await api.waitForCompletion(image.image_id);
}
}
// Генерация с автоматическим upscale
async function generateWithSmartUpscale() {
const image = await api.generateImage('ultra realistic portrait, 8k quality', {
width: 512, // Генерируем в низком разрешении для скорости
height: 512,
smart_upscale: true, // Включаем автоматический upscale
target_width: 2048, // Целевой размер после upscale
target_height: 2048,
steps: 30,
model: 'flux-dev'
});
if (image) {
const result = await api.waitForCompletion(image.image_id);
console.log(`Image automatically upscaled to ${result.dimensions}`);
}
}
generateSimple();
generateAdvanced();
generateWithSmartUpscale();
<?php
class FluxAPI {
private $apiKey;
private $baseUrl = 'https://image.nalitek.com';
public function __construct($apiKey) {
$this->apiKey = $apiKey;
}
public function generateImage($prompt, $options = []) {
$url = $this->baseUrl . '/api/generate';
$data = array_merge([
'prompt' => $prompt,
'negative_prompt' => '',
'width' => 1024,
'height' => 1024,
'steps' => 30,
'guidance_scale' => 7.5,
'seed' => -1,
'model' => 'flux-dev',
'format' => 'png'
], $options);
// Добавляем параметры smart_upscale если указаны
if (isset($options['smart_upscale']) && $options['smart_upscale']) {
$data['smart_upscale'] = true;
if (isset($options['target_width'])) {
$data['target_width'] = $options['target_width'];
}
if (isset($options['target_height'])) {
$data['target_height'] = $options['target_height'];
}
}
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'X-API-Key: ' . $this->apiKey,
'Content-Type: application/json'
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode === 201) {
$result = json_decode($response, true);
echo "✅ Success! Generation ID: " . $result['generation_id'] . "\n";
echo "📍 Progress URL: " . $result['progress_url'] . "\n";
return $result;
} else {
echo "❌ Error: HTTP $httpCode\n";
echo $response . "\n";
return null;
}
}
public function checkStatus($imageId) {
$url = $this->baseUrl . '/api/images/' . $imageId;
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-API-Key: ' . $this->apiKey]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
return json_decode($response, true);
}
public function waitForCompletion($imageId, $timeout = 120) {
$startTime = time();
while (time() - $startTime < $timeout) {
$status = $this->checkStatus($imageId);
if ($status['status'] === 'completed') {
echo "✅ Completed! URL: " . $status['url'] . "\n";
return $status;
} elseif ($status['status'] === 'failed') {
echo "❌ Failed: " . $status['error_message'] . "\n";
return $status;
}
sleep(2);
}
echo "⏱️ Timeout after $timeout seconds\n";
return null;
}
}
// Использование
$api = new FluxAPI('your-api-key');
// Простая генерация с автоматическим upscale
$image = $api->generateImage('cyberpunk city at night, neon lights', [
'width' => 512, // Генерируем быстро в низком разрешении
'height' => 512,
'smart_upscale' => true, // Автоматически увеличиваем после генерации
'target_width' => 2048, // Финальный размер
'target_height' => 2048
]);
if ($image) {
$result = $api->waitForCompletion($image['image_id']);
echo "Generated and upscaled to " . $result['dimensions'] . "\n";
}
// Расширенная генерация
$image = $api->generateImage('beautiful japanese garden', [
'negative_prompt' => 'blurry, low quality',
'width' => 1024,
'height' => 1024,
'steps' => 50,
'guidance_scale' => 8.0,
'model' => 'flux-dev',
'lora_id' => 'anime-style-v2'
]);
if ($image) {
$result = $api->waitForCompletion($image['image_id']);
}
// Генерация с автоматическим upscale
$image = $api->generateImage('ultra realistic portrait, 8k quality', [
'width' => 512, // Генерируем в низком разрешении
'height' => 512,
'smart_upscale' => true, // Включаем автоматический upscale
'target_width' => 2048, // Целевой размер после upscale
'target_height' => 2048,
'steps' => 30,
'model' => 'flux-dev'
]);
if ($image) {
$result = $api->waitForCompletion($image['image_id']);
echo "Image automatically upscaled to " . $result['dimensions'] . "\n";
}
Трансформация изображений
/api/img2img
Трансформация существующего изображения на основе текстового описания.
Параметры запроса (multipart/form-data)
| Параметр | Тип | Описание | По умолчанию |
|---|---|---|---|
| image required | file | Файл изображения (max 10MB, formats: png/jpg/webp) | - |
| prompt required | string | Описание желаемой трансформации | - |
| negative_prompt optional | string | Что исключить из генерации | "" |
| strength optional | float | Сила изменения (0.0-1.0) | 0.75 |
| seed optional | integer | Seed для воспроизводимости | -1 |
| steps optional | integer | Количество шагов (10-100) | 30 |
| guidance_scale optional | float | Сила следования промпту (1.0-20.0) | 7.5 |
| width optional | integer | Ширина результата (512-2048) | 1024 |
| height optional | integer | Высота результата (512-2048) | 1024 |
| format optional | string | Формат результата (png/jpeg/webp) | png |
| model optional | string | Модель (flux-dev/flux-schnell) | flux-dev |
| lora_models optional | array | Список ID LoRA моделей | [] |
| smart_upscale optional | boolean | Автоматический upscale после трансформации | false |
| target_width optional | integer | Целевая ширина для smart_upscale | null |
| target_height optional | integer | Целевая высота для smart_upscale | null |
Примеры использования
# Простая трансформация изображения
curl -X POST https://image.nalitek.com/api/img2img \
-H "X-API-Key: your-api-key" \
-F "image=@/path/to/image.jpg" \
-F "prompt=transform to cyberpunk style" \
-F "strength=0.75" \
-F "steps=30"
# С дополнительными параметрами
curl -X POST https://image.nalitek.com/api/img2img \
-H "X-API-Key: your-api-key" \
-F "image=@/path/to/portrait.png" \
-F "prompt=make it look like an oil painting, artistic, brush strokes visible" \
-F "negative_prompt=digital, photo, realistic" \
-F "strength=0.8" \
-F "steps=50" \
-F "guidance_scale=8.5" \
-F "width=1920" \
-F "height=1080" \
-F "seed=42" \
-F "model=flux-dev" \
-F "format=png"
# С Smart Upscale
curl -X POST https://image.nalitek.com/api/img2img \
-H "X-API-Key: your-api-key" \
-F "image=@/path/to/small_image.jpg" \
-F "prompt=enhance details, make it sharper" \
-F "strength=0.5" \
-F "width=512" \
-F "height=512" \
-F "smart_upscale=true" \
-F "target_width=2048" \
-F "target_height=2048"
# С несколькими LoRA моделями
curl -X POST https://image.nalitek.com/api/img2img \
-H "X-API-Key: your-api-key" \
-F "image=@/path/to/photo.jpg" \
-F "prompt=anime style character" \
-F "strength=0.7" \
-F "lora_models[]=anime-style-v2" \
-F "lora_models[]=detailed-eyes-v1" \
-F "steps=30"
# Сохранение результата в файл
curl -X POST https://image.nalitek.com/api/img2img \
-H "X-API-Key: your-api-key" \
-F "image=@input.jpg" \
-F "prompt=futuristic version" \
-F "strength=0.75" \
-o output.json
# Затем получить изображение по URL из ответа
curl -o result.png "https://image.nalitek.com/uploads/images/flux_20250115_123456_abc123.png"
import requests
def transform_image(api_key, image_path, prompt, **kwargs):
"""Трансформация изображения с img2img"""
url = "https://image.nalitek.com/api/img2img"
headers = {"X-API-Key": api_key}
# Подготовка файла
with open(image_path, 'rb') as f:
files = {'image': (image_path, f, 'image/png')}
# Подготовка данных
data = {
'prompt': prompt,
'negative_prompt': kwargs.get('negative_prompt', ''),
'strength': kwargs.get('strength', 0.75),
'steps': kwargs.get('steps', 30),
'seed': kwargs.get('seed', -1),
'width': kwargs.get('width', 1024),
'height': kwargs.get('height', 1024),
'guidance_scale': kwargs.get('guidance_scale', 7.5),
'format': kwargs.get('format', 'png'),
'model': kwargs.get('model', 'flux-dev')
}
# Добавляем параметры smart_upscale если указаны
if kwargs.get('smart_upscale'):
data['smart_upscale'] = 'true'
if kwargs.get('target_width'):
data['target_width'] = kwargs.get('target_width')
if kwargs.get('target_height'):
data['target_height'] = kwargs.get('target_height')
# Добавляем lora_models если указаны
if kwargs.get('lora_models'):
data['lora_models[]'] = kwargs.get('lora_models')
# Отправка запроса
response = requests.post(url, headers=headers, files=files, data=data)
if response.status_code == 201:
result = response.json()
print(f"✅ Success! Image URL: {result['url']}")
print(f"📐 Dimensions: {result['dimensions']}")
print(f"🌱 Seed: {result['seed']}")
return result
else:
print(f"❌ Error: {response.status_code}")
print(response.json())
return None
# Использование с автоматическим upscale
result = transform_image(
api_key="your-api-key",
image_path="input.png",
prompt="transform to cyberpunk style, neon lights, ultra HD",
negative_prompt="blurry, low quality",
width=512, # Трансформируем в низком разрешении для скорости
height=512,
smart_upscale=True, # Автоматически увеличиваем после трансформации
target_width=2048, # Финальный размер
target_height=2048,
strength=0.8,
steps=40
)
# Загрузка результата
if result:
image_url = result['url']
response = requests.get(image_url)
with open('output.png', 'wb') as f:
f.write(response.content)
print("✅ Image saved as output.png")
# Трансформация с автоматическим upscale
result = transform_image(
api_key="your-api-key",
image_path="input.png",
prompt="ultra HD quality, 8k resolution",
smart_upscale=True, # Включаем автоматический upscale
target_width=2048, # Целевой размер
target_height=2048,
strength=0.7,
steps=30
)
if result:
print(f"Image transformed and upscaled to {result['dimensions']}")
async function transformImage(apiKey, imageFile, prompt, options = {}) {
const url = 'https://image.nalitek.com/api/img2img';
// Создание FormData
const formData = new FormData();
formData.append('image', imageFile);
formData.append('prompt', prompt);
formData.append('negative_prompt', options.negative_prompt || '');
formData.append('strength', options.strength || 0.75);
formData.append('steps', options.steps || 30);
formData.append('seed', options.seed || -1);
formData.append('width', options.width || 1024);
formData.append('height', options.height || 1024);
formData.append('guidance_scale', options.guidance_scale || 7.5);
formData.append('format', options.format || 'png');
formData.append('model', options.model || 'flux-dev');
// Добавляем параметры smart_upscale если указаны
if (options.smart_upscale) {
formData.append('smart_upscale', 'true');
if (options.target_width) {
formData.append('target_width', options.target_width);
}
if (options.target_height) {
formData.append('target_height', options.target_height);
}
}
// Добавляем lora_models если указаны
if (options.lora_models && options.lora_models.length > 0) {
options.lora_models.forEach(lora => {
formData.append('lora_models[]', lora);
});
}
try {
const response = await fetch(url, {
method: 'POST',
headers: {
'X-API-Key': apiKey
},
body: formData
});
if (response.status === 201) {
const result = await response.json();
console.log(`✅ Success! Image URL: ${result.url}`);
console.log(`📐 Dimensions: ${result.dimensions}`);
console.log(`🌱 Seed: ${result.seed}`);
return result;
} else {
const error = await response.json();
console.error(`❌ Error: ${response.status}`, error);
return null;
}
} catch (error) {
console.error('Request failed:', error);
return null;
}
}
// Использование с input элементом
document.getElementById('fileInput').addEventListener('change', async (event) => {
const file = event.target.files[0];
if (file) {
// Пример с автоматическим upscale
const result = await transformImage(
'your-api-key',
file,
'transform to cyberpunk style, neon lights, ultra HD',
{
width: 512, // Трансформируем в низком разрешении
height: 512,
smart_upscale: true, // Автоматически увеличиваем после
target_width: 2048, // Финальный размер
target_height: 2048,
negative_prompt: 'blurry, low quality',
strength: 0.8,
steps: 40
}
);
// Пример с автоматическим upscale
const resultWithUpscale = await transformImage(
'your-api-key',
file,
'ultra HD quality, 8k resolution',
{
width: 512, // Трансформируем в низком разрешении
height: 512,
smart_upscale: true, // Включаем автоматический upscale
target_width: 2048, // Целевой размер
target_height: 2048,
strength: 0.7,
steps: 30
}
);
if (result) {
// Отобразить результат
document.getElementById('resultImage').src = result.url;
}
}
});
// Использование с URL изображения
async function transformFromUrl(imageUrl) {
const response = await fetch(imageUrl);
const blob = await response.blob();
const file = new File([blob], 'image.png', { type: 'image/png' });
return await transformImage(
'your-api-key',
file,
'make it artistic painting style'
);
}
<?php
function transformImage($apiKey, $imagePath, $prompt, $options = []) {
$url = 'https://image.nalitek.com/api/img2img';
// Подготовка файла
$cFile = new CURLFile($imagePath, mime_content_type($imagePath), basename($imagePath));
// Подготовка данных
$data = array_merge([
'image' => $cFile,
'prompt' => $prompt,
'negative_prompt' => '',
'strength' => 0.75,
'steps' => 30,
'seed' => -1,
'width' => 1024,
'height' => 1024,
'guidance_scale' => 7.5,
'format' => 'png',
'model' => 'flux-dev'
], $options);
// Добавляем параметры smart_upscale если указаны
if (isset($options['smart_upscale']) && $options['smart_upscale']) {
$data['smart_upscale'] = 'true';
if (isset($options['target_width'])) {
$data['target_width'] = $options['target_width'];
}
if (isset($options['target_height'])) {
$data['target_height'] = $options['target_height'];
}
}
// Добавляем lora_models если указаны
if (isset($options['lora_models']) && is_array($options['lora_models'])) {
foreach ($options['lora_models'] as $index => $lora) {
$data["lora_models[$index]"] = $lora;
}
}
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-API-Key: ' . $apiKey]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode === 201) {
$result = json_decode($response, true);
echo "✅ Success! Image URL: " . $result['url'] . "\n";
echo "📐 Dimensions: " . $result['dimensions'] . "\n";
echo "🌱 Seed: " . $result['seed'] . "\n";
return $result;
} else {
echo "❌ Error: HTTP $httpCode\n";
echo $response . "\n";
return null;
}
}
// Использование с автоматическим upscale
$result = transformImage(
'your-api-key',
'input.png',
'transform to cyberpunk style, neon lights, ultra HD',
[
'width' => 512, // Трансформируем в низком разрешении
'height' => 512,
'smart_upscale' => true, // Автоматически увеличиваем после
'target_width' => 2048, // Финальный размер
'target_height' => 2048,
'negative_prompt' => 'blurry, low quality',
'strength' => 0.8,
'steps' => 40
]
);
// Загрузка результата
if ($result) {
$imageContent = file_get_contents($result['url']);
file_put_contents('output.png', $imageContent);
echo "✅ Image saved as output.png\n";
}
// Пример с автоматическим upscale
$resultWithUpscale = transformImage(
'your-api-key',
'input.png',
'ultra HD quality, 8k resolution',
[
'width' => 512, // Трансформируем в низком разрешении
'height' => 512,
'smart_upscale' => true, // Включаем автоматический upscale
'target_width' => 2048, // Целевой размер
'target_height' => 2048,
'strength' => 0.7,
'steps' => 30
]
);
if ($resultWithUpscale) {
echo "Image transformed and upscaled to " . $resultWithUpscale['dimensions'] . "\n";
}
// Пример с загрузкой через форму
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['image'])) {
$uploadedFile = $_FILES['image']['tmp_name'];
$prompt = $_POST['prompt'] ?? 'transform to artistic style';
$result = transformImage(
'your-api-key',
$uploadedFile,
$prompt,
[
'strength' => floatval($_POST['strength'] ?? 0.75),
'steps' => intval($_POST['steps'] ?? 30)
]
);
if ($result) {
header('Content-Type: application/json');
echo json_encode($result);
}
}
Увеличение разрешения
/api/upscale/{image_id}
Увеличение разрешения существующего изображения с улучшением качества.
Параметры запроса
| Параметр | Тип | Описание | По умолчанию |
|---|---|---|---|
| scale optional | integer | Коэффициент увеличения (2 или 4) | 2 |
| face_enhance optional | boolean | Улучшение лиц с GFPGAN | false |
| denoise optional | float | Уровень удаления шума (0.0-1.0) | 0.5 |
Примеры использования
# Простое увеличение в 2 раза
curl -X POST https://image.nalitek.com/api/upscale/4738 \
-H "X-API-Key: your-api-key" \
-H "Content-Type: application/json" \
-d '{
"scale": 2
}'
# Увеличение в 4 раза
curl -X POST https://image.nalitek.com/api/upscale/4738 \
-H "X-API-Key: your-api-key" \
-H "Content-Type: application/json" \
-d '{
"scale": 4,
"denoise": 0.5
}'
# С улучшением лиц (для портретов)
curl -X POST https://image.nalitek.com/api/upscale/4738 \
-H "X-API-Key: your-api-key" \
-H "Content-Type: application/json" \
-d '{
"scale": 4,
"face_enhance": true,
"denoise": 0.7
}'
# Проверка статуса upscale
curl -X GET https://image.nalitek.com/api/images/4739 \
-H "X-API-Key: your-api-key"
# Скачивание результата
curl -X GET https://image.nalitek.com/api/images/4739 \
-H "X-API-Key: your-api-key" \
| jq -r '.url' \
| xargs curl -o upscaled_image.png
import requests
def upscale_image(api_key, image_id, scale=2, face_enhance=False, denoise=0.5):
"""Увеличение разрешения изображения"""
url = f"https://image.nalitek.com/api/upscale/{image_id}"
headers = {
"X-API-Key": api_key,
"Content-Type": "application/json"
}
data = {
"scale": scale,
"face_enhance": face_enhance,
"denoise": denoise
}
response = requests.post(url, json=data, headers=headers)
if response.status_code == 201:
result = response.json()
print(f"✅ Success! Upscaled URL: {result['url']}")
print(f"📐 New dimensions: {result['dimensions']}")
print(f"🔍 Scale: {result['scale']}x")
return result
else:
print(f"❌ Error: {response.status_code}")
print(response.json())
return None
# Простое увеличение в 2 раза
result = upscale_image(
api_key="your-api-key",
image_id=4738,
scale=2
)
# Увеличение в 4 раза с улучшением лиц
result = upscale_image(
api_key="your-api-key",
image_id=4738,
scale=4,
face_enhance=True,
denoise=0.7
)
async function upscaleImage(apiKey, imageId, options = {}) {
const url = `https://image.nalitek.com/api/upscale/${imageId}`;
const data = {
scale: options.scale || 2,
face_enhance: options.face_enhance || false,
denoise: options.denoise || 0.5
};
try {
const response = await fetch(url, {
method: 'POST',
headers: {
'X-API-Key': apiKey,
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
if (response.status === 201) {
const result = await response.json();
console.log(`✅ Success! Upscaled URL: ${result.url}`);
console.log(`📐 New dimensions: ${result.dimensions}`);
console.log(`🔍 Scale: ${result.scale}x`);
return result;
} else {
const error = await response.json();
console.error(`❌ Error: ${response.status}`, error);
return null;
}
} catch (error) {
console.error('Request failed:', error);
return null;
}
}
// Простое увеличение в 2 раза
upscaleImage('your-api-key', 123);
// Увеличение в 4 раза с улучшением лиц
upscaleImage('your-api-key', 123, {
scale: 4,
face_enhance: true,
denoise: 0.7
});
<?php
function upscaleImage($apiKey, $imageId, $options = []) {
$url = "https://image.nalitek.com/api/upscale/$imageId";
$data = array_merge([
'scale' => 2,
'face_enhance' => false,
'denoise' => 0.5
], $options);
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'X-API-Key: ' . $apiKey,
'Content-Type: application/json'
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode === 201) {
$result = json_decode($response, true);
echo "✅ Success! Upscaled URL: " . $result['url'] . "\n";
echo "📐 New dimensions: " . $result['dimensions'] . "\n";
echo "🔍 Scale: " . $result['scale'] . "x\n";
return $result;
} else {
echo "❌ Error: HTTP $httpCode\n";
echo $response . "\n";
return null;
}
}
// Простое увеличение в 2 раза
$result = upscaleImage('your-api-key', 123);
// Увеличение в 4 раза с улучшением лиц
$result = upscaleImage('your-api-key', 123, [
'scale' => 4,
'face_enhance' => true,
'denoise' => 0.7
]);
Smart Upscale - Умное увеличение
🚀 Преимущества Smart Upscale
- ⚡ Скорость - генерация в низком разрешении происходит в 2-4 раза быстрее
- 💰 Экономия ресурсов - меньше потребление VRAM и вычислительных ресурсов
- 🎯 Качество - финальное изображение получается высокого качества благодаря RealESRGAN
- 🔄 Автоматизация - весь процесс происходит автоматически в одном запросе
Как работает Smart Upscale
🔄 Автоматическое поведение (по умолчанию включено)
// Запрос размера 1024x1024 - автоматически применится smart upscale
{
"prompt": "ultra realistic portrait, 8k quality",
"width": 1024, // Целевой размер
"height": 1024, // Автоматически: генерация 512x512 → upscale до 1024x1024
"steps": 30
// smart_upscale: true по умолчанию
}
// Для размеров ≤512px smart upscale автоматически отключается
{
"prompt": "icon design",
"width": 256, // Маленький размер
"height": 256, // Генерируется напрямую без upscale
"steps": 20
}
// Явное отключение smart upscale
{
"prompt": "detailed artwork",
"width": 1024,
"height": 1024,
"smart_upscale": false, // Генерировать напрямую в 1024x1024 (медленнее)
"steps": 30
}
🖼️ В эндпоинте /api/img2img
const formData = new FormData();
formData.append('image', imageFile);
formData.append('prompt', 'enhance quality, ultra HD');
formData.append('width', '512'); // Трансформируем в низком разрешении
formData.append('height', '512');
formData.append('smart_upscale', 'true'); // Включаем Smart Upscale
formData.append('target_width', '2048'); // Целевой размер
formData.append('target_height', '2048');
Рекомендации по использованию
✅ Когда использовать Smart Upscale
- Нужны изображения высокого разрешения (2K, 4K)
- Важна скорость генерации
- Ограничены ресурсы GPU
- Генерация сложных сцен с множеством деталей
⚠️ Ограничения
- Не рекомендуется для изображений с текстом - может исказить буквы
- Максимальный коэффициент увеличения - 4x
- Требует дополнительное время на upscale (5-15 секунд)
- Занимает больше места на диске (финальное изображение больше)
Примеры оптимальных настроек
| Сценарий | Исходный размер | Целевой размер | Рекомендации |
|---|---|---|---|
| Портреты | 512×512 | 2048×2048 | Включить face_enhance для лучшего качества лиц |
| Пейзажи | 768×512 | 3072×2048 | Использовать denoise=0.3 для сохранения деталей |
| Архитектура | 512×768 | 2048×3072 | Увеличить steps до 40-50 для лучшей детализации |
| Быстрые превью | 256×256 | 1024×1024 | Использовать model="flux-schnell" для скорости |
Получение статуса изображения
/api/get/<id>
Быстрая проверка статуса генерации изображения по ID. Упрощенный эндпоинт для получения основной информации.
Параметры
| Параметр | Тип | Описание |
|---|---|---|
| id required | integer | ID изображения, полученный при создании запроса на генерацию |
Ответ
{
"status": "completed", // "generating", "completed", "failed", "queued"
"url": "/uploads/images/flux_20250902_193838_c5dcc7ee.png", // URL готового изображения (если completed)
"message": "Изображение успешно сгенерировано" // Сообщение о статусе
}
Статусы генерации
| Статус | Описание | Действие |
|---|---|---|
queued |
Запрос в очереди на обработку | Продолжайте проверять статус |
generating |
Изображение генерируется | Продолжайте проверять статус |
completed |
Генерация завершена успешно | Используйте URL для получения изображения |
failed |
Ошибка при генерации | Проверьте сообщение об ошибке |
Примеры использования
import requests
import time
# Запуск генерации
response = requests.post(
"https://image.nalitek.com/api/generate",
headers={"X-API-Key": "your_api_key"},
json={"prompt": "Beautiful sunset", "width": 512, "height": 512}
)
image_id = response.json()["id"]
# Проверка статуса
while True:
status = requests.get(
f"https://image.nalitek.com/api/get/{image_id}",
headers={"X-API-Key": "your_api_key"}
).json()
print(f"Status: {status['status']}")
if status["status"] == "completed":
print(f"Image URL: {status['url']}")
break
elif status["status"] == "failed":
print(f"Error: {status['message']}")
break
time.sleep(2) # Ждем 2 секунды перед следующей проверкой
async function checkImageStatus(imageId) {
const response = await fetch(
`https://image.nalitek.com/api/get/${imageId}`,
{
headers: {
'X-API-Key': 'your_api_key'
}
}
);
const status = await response.json();
console.log(`Status: ${status.status}`);
if (status.status === 'completed') {
console.log(`Image URL: ${status.url}`);
return status.url;
} else if (status.status === 'failed') {
throw new Error(status.message);
}
// Повторить через 2 секунды
await new Promise(resolve => setTimeout(resolve, 2000));
return checkImageStatus(imageId);
}
# Проверка статуса изображения с ID 123
curl -X GET \
https://image.nalitek.com/api/get/123 \
-H "X-API-Key: your_api_key"
# Ответ для завершенной генерации:
# {
# "status": "completed",
# "url": "/uploads/images/flux_20250902_193838_c5dcc7ee.png",
# "message": "Изображение успешно сгенерировано"
# }
/api/images/{id}.
Проверка статуса
/api/status
Получение общего статуса API и доступности сервисов.
Ответ
{
"status": "operational",
"version": "2.0",
"services": {
"generation": "operational",
"img2img": "operational",
"upscale": "operational",
"storage": "operational",
"websocket": "operational"
},
"models": {
"flux-dev": {
"status": "available",
"queue_size": 5,
"avg_generation_time": 28.5
},
"flux-schnell": {
"status": "available",
"queue_size": 2,
"avg_generation_time": 15.3
}
},
"timestamp": "2025-01-15T10:30:00Z"
}
Примеры использования
import requests
def check_api_status():
"""Проверка статуса API"""
url = "https://image.nalitek.com/api/status"
try:
response = requests.get(url, timeout=5)
if response.status_code == 200:
status = response.json()
print(f"✅ API Status: {status['status']}")
print(f"📦 Version: {status['version']}")
# Проверка сервисов
for service, state in status['services'].items():
icon = "✅" if state == "operational" else "❌"
print(f"{icon} {service}: {state}")
# Проверка моделей
print("\n📊 Models:")
for model, info in status['models'].items():
print(f" {model}:")
print(f" Status: {info['status']}")
print(f" Queue: {info['queue_size']} tasks")
print(f" Avg time: {info['avg_generation_time']}s")
return status
else:
print(f"❌ API returned status code: {response.status_code}")
return None
except requests.exceptions.RequestException as e:
print(f"❌ Failed to reach API: {e}")
return None
# Использование
status = check_api_status()
# Проверка перед началом работы
if status and status['status'] == 'operational':
print("\n✅ API is ready for requests!")
else:
print("\n⚠️ API may be experiencing issues")
async function checkApiStatus() {
const url = 'https://image.nalitek.com/api/status';
try {
const response = await fetch(url);
if (response.status === 200) {
const status = await response.json();
console.log(`✅ API Status: ${status.status}`);
console.log(`📦 Version: ${status.version}`);
// Проверка сервисов
for (const [service, state] of Object.entries(status.services)) {
const icon = state === 'operational' ? '✅' : '❌';
console.log(`${icon} ${service}: ${state}`);
}
// Проверка моделей
console.log('\n📊 Models:');
for (const [model, info] of Object.entries(status.models)) {
console.log(` ${model}:`);
console.log(` Status: ${info.status}`);
console.log(` Queue: ${info.queue_size} tasks`);
console.log(` Avg time: ${info.avg_generation_time}s`);
}
return status;
} else {
console.error(`❌ API returned status code: ${response.status}`);
return null;
}
} catch (error) {
console.error(`❌ Failed to reach API: ${error}`);
return null;
}
}
// Использование
checkApiStatus().then(status => {
if (status && status.status === 'operational') {
console.log('\n✅ API is ready for requests!');
} else {
console.log('\n⚠️ API may be experiencing issues');
}
});
<?php
function checkApiStatus() {
$url = 'https://image.nalitek.com/api/status';
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode === 200) {
$status = json_decode($response, true);
echo "✅ API Status: " . $status['status'] . "\n";
echo "📦 Version: " . $status['version'] . "\n";
// Проверка сервисов
foreach ($status['services'] as $service => $state) {
$icon = $state === 'operational' ? '✅' : '❌';
echo "$icon $service: $state\n";
}
// Проверка моделей
echo "\n📊 Models:\n";
foreach ($status['models'] as $model => $info) {
echo " $model:\n";
echo " Status: " . $info['status'] . "\n";
echo " Queue: " . $info['queue_size'] . " tasks\n";
echo " Avg time: " . $info['avg_generation_time'] . "s\n";
}
return $status;
} else {
echo "❌ API returned status code: $httpCode\n";
return null;
}
}
// Использование
$status = checkApiStatus();
// Проверка перед началом работы
if ($status && $status['status'] === 'operational') {
echo "\n✅ API is ready for requests!\n";
} else {
echo "\n⚠️ API may be experiencing issues\n";
}
Управление изображениями
/api/images
Получение списка изображений пользователя с пагинацией и фильтрами.
Параметры запроса
| Параметр | Тип | Описание | По умолчанию |
|---|---|---|---|
| page | integer | Номер страницы | 1 |
| per_page | integer | Элементов на странице (1-100) | 20 |
| status | string | Фильтр по статусу (generating/completed/failed) | - |
| is_upscaled | boolean | Фильтр по upscale статусу | - |
| sort | string | Сортировка (date_desc/date_asc) | date_desc |
Примеры использования
# Получить список изображений
curl -X GET "https://image.nalitek.com/api/images?page=1&per_page=20" \
-H "X-API-Key: your-api-key"
# С фильтрами
curl -X GET "https://image.nalitek.com/api/images?status=completed&sort=date_desc&per_page=50" \
-H "X-API-Key: your-api-key"
# Только upscaled изображения
curl -X GET "https://image.nalitek.com/api/images?is_upscaled=true" \
-H "X-API-Key: your-api-key"
# Получить детали изображения
curl -X GET https://image.nalitek.com/api/images/4738 \
-H "X-API-Key: your-api-key"
# Удалить изображение
curl -X DELETE https://image.nalitek.com/api/images/4738 \
-H "X-API-Key: your-api-key"
# Скачать изображение
curl -X GET https://image.nalitek.com/api/images/4738 \
-H "X-API-Key: your-api-key" \
| jq -r '.url' \
| xargs curl -o image.png
# Получить все изображения с пагинацией (bash скрипт)
#!/bin/bash
API_KEY="your-api-key"
PAGE=1
while true; do
RESPONSE=$(curl -s -X GET "https://image.nalitek.com/api/images?page=$PAGE&per_page=100" \
-H "X-API-Key: $API_KEY")
# Извлечь изображения
echo "$RESPONSE" | jq '.images[]'
# Проверить, есть ли еще страницы
TOTAL_PAGES=$(echo "$RESPONSE" | jq '.pages')
if [ "$PAGE" -ge "$TOTAL_PAGES" ]; then
break
fi
PAGE=$((PAGE + 1))
done
import requests
class ImageManager:
def __init__(self, api_key):
self.api_key = api_key
self.base_url = "https://image.nalitek.com"
self.headers = {"X-API-Key": api_key}
def get_images(self, page=1, per_page=20, **filters):
"""Получение списка изображений"""
url = f"{self.base_url}/api/images"
params = {
'page': page,
'per_page': per_page
}
# Добавление фильтров
if 'status' in filters:
params['status'] = filters['status']
if 'is_upscaled' in filters:
params['is_upscaled'] = filters['is_upscaled']
if 'sort' in filters:
params['sort'] = filters['sort']
response = requests.get(url, params=params, headers=self.headers)
if response.status_code == 200:
data = response.json()
print(f"📸 Found {data['total']} images")
print(f"📄 Page {data['current_page']} of {data['total_pages']}")
for image in data['images']:
print(f"\n🆔 ID: {image['id']}")
print(f"📝 Prompt: {image['prompt'][:50]}...")
print(f"📐 Size: {image['width']}x{image['height']}")
print(f"✅ Status: {image['status']}")
return data
else:
print(f"❌ Error: {response.status_code}")
return None
def get_image_details(self, image_id):
"""Получение деталей изображения"""
url = f"{self.base_url}/api/images/{image_id}"
response = requests.get(url, headers=self.headers)
if response.status_code == 200:
image = response.json()
print(f"🆔 Image ID: {image['id']}")
print(f"📝 Prompt: {image['prompt']}")
print(f"🔗 URL: {image['url']}")
print(f"📐 Dimensions: {image['width']}x{image['height']}")
print(f"🌱 Seed: {image['seed']}")
print(f"⏱️ Generation time: {image['generation_time']}s")
return image
else:
print(f"❌ Error: {response.status_code}")
return None
def delete_image(self, image_id):
"""Удаление изображения"""
url = f"{self.base_url}/api/images/{image_id}"
response = requests.delete(url, headers=self.headers)
if response.status_code == 204:
print(f"✅ Image {image_id} deleted successfully")
return True
else:
print(f"❌ Error: {response.status_code}")
return False
def get_all_images(self):
"""Получение всех изображений (с пагинацией)"""
all_images = []
page = 1
while True:
data = self.get_images(page=page, per_page=100)
if not data:
break
all_images.extend(data['images'])
if page >= data['total_pages']:
break
page += 1
print(f"\n📊 Total images collected: {len(all_images)}")
return all_images
# Использование
manager = ImageManager("your-api-key")
# Получить последние изображения
manager.get_images(page=1, per_page=10)
# Получить только завершенные изображения
manager.get_images(status='completed', sort='date_desc')
# Получить детали конкретного изображения
manager.get_image_details(4738)
# Удалить изображение
manager.delete_image(4739)
# Получить все изображения
all_images = manager.get_all_images()
class ImageManager {
constructor(apiKey) {
this.apiKey = apiKey;
this.baseUrl = 'https://image.nalitek.com';
}
async getImages(page = 1, perPage = 20, filters = {}) {
const url = new URL(`${this.baseUrl}/api/images`);
// Добавление параметров
url.searchParams.append('page', page);
url.searchParams.append('per_page', perPage);
// Добавление фильтров
if (filters.status) url.searchParams.append('status', filters.status);
if (filters.is_upscaled !== undefined) {
url.searchParams.append('is_upscaled', filters.is_upscaled);
}
if (filters.sort) url.searchParams.append('sort', filters.sort);
try {
const response = await fetch(url, {
headers: { 'X-API-Key': this.apiKey }
});
if (response.status === 200) {
const data = await response.json();
console.log(`📸 Found ${data.total} images`);
console.log(`📄 Page ${data.current_page} of ${data.total_pages}`);
data.images.forEach(image => {
console.log(`\n🆔 ID: ${image.id}`);
console.log(`📝 Prompt: ${image.prompt.substring(0, 50)}...`);
console.log(`📐 Size: ${image.width}x${image.height}`);
console.log(`✅ Status: ${image.status}`);
});
return data;
} else {
console.error(`❌ Error: ${response.status}`);
return null;
}
} catch (error) {
console.error('Request failed:', error);
return null;
}
}
async getImageDetails(imageId) {
const url = `${this.baseUrl}/api/images/${imageId}`;
try {
const response = await fetch(url, {
headers: { 'X-API-Key': this.apiKey }
});
if (response.status === 200) {
const image = await response.json();
console.log(`🆔 Image ID: ${image.id}`);
console.log(`📝 Prompt: ${image.prompt}`);
console.log(`🔗 URL: ${image.url}`);
console.log(`📐 Dimensions: ${image.width}x${image.height}`);
console.log(`🌱 Seed: ${image.seed}`);
console.log(`⏱️ Generation time: ${image.generation_time}s`);
return image;
} else {
console.error(`❌ Error: ${response.status}`);
return null;
}
} catch (error) {
console.error('Request failed:', error);
return null;
}
}
async deleteImage(imageId) {
const url = `${this.baseUrl}/api/images/${imageId}`;
try {
const response = await fetch(url, {
method: 'DELETE',
headers: { 'X-API-Key': this.apiKey }
});
if (response.status === 204) {
console.log(`✅ Image ${imageId} deleted successfully`);
return true;
} else {
console.error(`❌ Error: ${response.status}`);
return false;
}
} catch (error) {
console.error('Request failed:', error);
return false;
}
}
async getAllImages() {
const allImages = [];
let page = 1;
let totalPages = 1;
while (page <= totalPages) {
const data = await this.getImages(page, 100);
if (!data) break;
allImages.push(...data.images);
totalPages = data.total_pages;
page++;
}
console.log(`\n📊 Total images collected: ${allImages.length}`);
return allImages;
}
}
// Использование
const manager = new ImageManager('your-api-key');
// Получить последние изображения
manager.getImages(1, 10);
// Получить только завершенные изображения
manager.getImages(1, 20, { status: 'completed', sort: 'date_desc' });
// Получить детали конкретного изображения
manager.getImageDetails(123);
// Удалить изображение
manager.deleteImage(456);
// Получить все изображения
manager.getAllImages();
<?php
class ImageManager {
private $apiKey;
private $baseUrl = 'https://image.nalitek.com';
public function __construct($apiKey) {
$this->apiKey = $apiKey;
}
public function getImages($page = 1, $perPage = 20, $filters = []) {
$url = $this->baseUrl . '/api/images';
$params = [
'page' => $page,
'per_page' => $perPage
];
// Добавление фильтров
if (isset($filters['status'])) {
$params['status'] = $filters['status'];
}
if (isset($filters['is_upscaled'])) {
$params['is_upscaled'] = $filters['is_upscaled'];
}
if (isset($filters['sort'])) {
$params['sort'] = $filters['sort'];
}
$url .= '?' . http_build_query($params);
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-API-Key: ' . $this->apiKey]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode === 200) {
$data = json_decode($response, true);
echo "📸 Found {$data['total']} images\n";
echo "📄 Page {$data['current_page']} of {$data['total_pages']}\n";
foreach ($data['images'] as $image) {
echo "\n🆔 ID: {$image['id']}\n";
echo "📝 Prompt: " . substr($image['prompt'], 0, 50) . "...\n";
echo "📐 Size: {$image['width']}x{$image['height']}\n";
echo "✅ Status: {$image['status']}\n";
}
return $data;
} else {
echo "❌ Error: HTTP $httpCode\n";
return null;
}
}
public function getImageDetails($imageId) {
$url = $this->baseUrl . "/api/images/$imageId";
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-API-Key: ' . $this->apiKey]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode === 200) {
$image = json_decode($response, true);
echo "🆔 Image ID: {$image['id']}\n";
echo "📝 Prompt: {$image['prompt']}\n";
echo "🔗 URL: {$image['url']}\n";
echo "📐 Dimensions: {$image['width']}x{$image['height']}\n";
echo "🌱 Seed: {$image['seed']}\n";
echo "⏱️ Generation time: {$image['generation_time']}s\n";
return $image;
} else {
echo "❌ Error: HTTP $httpCode\n";
return null;
}
}
public function deleteImage($imageId) {
$url = $this->baseUrl . "/api/images/$imageId";
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-API-Key: ' . $this->apiKey]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode === 204) {
echo "✅ Image $imageId deleted successfully\n";
return true;
} else {
echo "❌ Error: HTTP $httpCode\n";
return false;
}
}
}
// Использование
$manager = new ImageManager('your-api-key');
// Получить последние изображения
$manager->getImages(1, 10);
// Получить только завершенные изображения
$manager->getImages(1, 20, ['status' => 'completed', 'sort' => 'date_desc']);
// Получить детали конкретного изображения
$manager->getImageDetails(123);
// Удалить изображение
$manager->deleteImage(456);
User Endpoints
/api/user/profile
Получение профиля текущего пользователя.
Ответ
{
"id": 347,
"username": "alex_petrov",
"email": "alex.petrov@gmail.com",
"role": "user",
"plan": "pro",
"created_at": "2024-11-15T14:22:18Z",
"avatar_url": "https://image.nalitek.com/uploads/avatars/avatar_347_1731678138.jpg",
"settings": {
"default_model": "flux-dev",
"default_quality": "high",
"email_notifications": true,
"webhook_enabled": false
}
}
/api/user/profile
Обновление профиля пользователя.
Примеры использования
import requests
class UserAPI:
def __init__(self, api_key):
self.api_key = api_key
self.base_url = "https://image.nalitek.com"
self.headers = {"X-API-Key": api_key, "Content-Type": "application/json"}
def get_profile(self):
"""Получить профиль пользователя"""
url = f"{self.base_url}/api/user/profile"
response = requests.get(url, headers=self.headers)
if response.status_code == 200:
profile = response.json()
print(f"👤 User: {profile['username']}")
print(f"📧 Email: {profile['email']}")
print(f"🎯 Plan: {profile['plan']}")
print(f"🎨 Default model: {profile['settings']['default_model']}")
return profile
else:
print(f"❌ Error: {response.status_code}")
return None
def update_profile(self, updates):
"""Обновить профиль пользователя"""
url = f"{self.base_url}/api/user/profile"
response = requests.put(url, json=updates, headers=self.headers)
if response.status_code == 200:
profile = response.json()
print("✅ Profile updated successfully")
return profile
else:
print(f"❌ Error: {response.status_code}")
return None
def update_settings(self, settings):
"""Обновить настройки пользователя"""
return self.update_profile({"settings": settings})
def change_password(self, current_password, new_password):
"""Изменить пароль"""
url = f"{self.base_url}/api/user/password"
data = {
"current_password": current_password,
"new_password": new_password
}
response = requests.post(url, json=data, headers=self.headers)
if response.status_code == 200:
print("✅ Password changed successfully")
return True
else:
print(f"❌ Error: {response.status_code}")
return False
# Использование
user_api = UserAPI("your-api-key")
# Получить профиль
profile = user_api.get_profile()
# Обновить настройки
user_api.update_settings({
"default_model": "flux-schnell",
"default_quality": "ultra",
"email_notifications": False
})
# Изменить пароль
user_api.change_password("old_password", "new_secure_password")
class UserAPI {
constructor(apiKey) {
this.apiKey = apiKey;
this.baseUrl = 'https://image.nalitek.com';
}
async getProfile() {
const url = `${this.baseUrl}/api/user/profile`;
try {
const response = await fetch(url, {
headers: { 'X-API-Key': this.apiKey }
});
if (response.status === 200) {
const profile = await response.json();
console.log(`👤 User: ${profile.username}`);
console.log(`📧 Email: ${profile.email}`);
console.log(`🎯 Plan: ${profile.plan}`);
console.log(`🎨 Default model: ${profile.settings.default_model}`);
return profile;
} else {
console.error(`❌ Error: ${response.status}`);
return null;
}
} catch (error) {
console.error('Request failed:', error);
return null;
}
}
async updateProfile(updates) {
const url = `${this.baseUrl}/api/user/profile`;
try {
const response = await fetch(url, {
method: 'PUT',
headers: {
'X-API-Key': this.apiKey,
'Content-Type': 'application/json'
},
body: JSON.stringify(updates)
});
if (response.status === 200) {
const profile = await response.json();
console.log('✅ Profile updated successfully');
return profile;
} else {
console.error(`❌ Error: ${response.status}`);
return null;
}
} catch (error) {
console.error('Request failed:', error);
return null;
}
}
async updateSettings(settings) {
return this.updateProfile({ settings });
}
async changePassword(currentPassword, newPassword) {
const url = `${this.baseUrl}/api/user/password`;
try {
const response = await fetch(url, {
method: 'POST',
headers: {
'X-API-Key': this.apiKey,
'Content-Type': 'application/json'
},
body: JSON.stringify({
current_password: currentPassword,
new_password: newPassword
})
});
if (response.status === 200) {
console.log('✅ Password changed successfully');
return true;
} else {
console.error(`❌ Error: ${response.status}`);
return false;
}
} catch (error) {
console.error('Request failed:', error);
return false;
}
}
}
// Использование
const userApi = new UserAPI('your-api-key');
// Получить профиль
userApi.getProfile();
// Обновить настройки
userApi.updateSettings({
default_model: 'flux-schnell',
default_quality: 'ultra',
email_notifications: false
});
// Изменить пароль
userApi.changePassword('old_password', 'new_secure_password');
<?php
class UserAPI {
private $apiKey;
private $baseUrl = 'https://image.nalitek.com';
public function __construct($apiKey) {
$this->apiKey = $apiKey;
}
public function getProfile() {
$url = $this->baseUrl . '/api/user/profile';
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-API-Key: ' . $this->apiKey]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode === 200) {
$profile = json_decode($response, true);
echo "👤 User: {$profile['username']}\n";
echo "📧 Email: {$profile['email']}\n";
echo "🎯 Plan: {$profile['plan']}\n";
echo "🎨 Default model: {$profile['settings']['default_model']}\n";
return $profile;
} else {
echo "❌ Error: HTTP $httpCode\n";
return null;
}
}
public function updateProfile($updates) {
$url = $this->baseUrl . '/api/user/profile';
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($updates));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'X-API-Key: ' . $this->apiKey,
'Content-Type: application/json'
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode === 200) {
echo "✅ Profile updated successfully\n";
return json_decode($response, true);
} else {
echo "❌ Error: HTTP $httpCode\n";
return null;
}
}
public function updateSettings($settings) {
return $this->updateProfile(['settings' => $settings]);
}
public function changePassword($currentPassword, $newPassword) {
$url = $this->baseUrl . '/api/user/password';
$data = [
'current_password' => $currentPassword,
'new_password' => $newPassword
];
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'X-API-Key: ' . $this->apiKey,
'Content-Type: application/json'
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode === 200) {
echo "✅ Password changed successfully\n";
return true;
} else {
echo "❌ Error: HTTP $httpCode\n";
return false;
}
}
}
// Использование
$userApi = new UserAPI('your-api-key');
// Получить профиль
$profile = $userApi->getProfile();
// Обновить настройки
$userApi->updateSettings([
'default_model' => 'flux-schnell',
'default_quality' => 'ultra',
'email_notifications' => false
]);
// Изменить пароль
$userApi->changePassword('old_password', 'new_secure_password');
Управление API ключами
/api/user/api-keys
Получение списка API ключей пользователя.
/api/user/api-keys
Создание нового API ключа.
/api/user/api-keys/{key_id}
Удаление API ключа.
Примеры использования
import requests
class APIKeyManager:
def __init__(self, api_key):
self.api_key = api_key
self.base_url = "https://image.nalitek.com"
self.headers = {"X-API-Key": api_key, "Content-Type": "application/json"}
def list_keys(self):
"""Получить список API ключей"""
url = f"{self.base_url}/api/user/api-keys"
response = requests.get(url, headers=self.headers)
if response.status_code == 200:
keys = response.json()
print(f"🔑 Total API keys: {len(keys['api_keys'])}")
for key in keys['api_keys']:
print(f"\n🆔 ID: {key['id']}")
print(f"📝 Name: {key['name']}")
print(f"🔑 Prefix: {key['prefix']}")
print(f"📅 Created: {key['created_at']}")
print(f"⏰ Last used: {key['last_used_at']}")
print(f"📊 Usage: {key['usage']['total_requests']} requests")
return keys
else:
print(f"❌ Error: {response.status_code}")
return None
def create_key(self, name, ip_whitelist=None, rate_limit=None):
"""Создать новый API ключ"""
url = f"{self.base_url}/api/user/api-keys"
data = {"name": name}
if ip_whitelist:
data["ip_whitelist"] = ip_whitelist
if rate_limit:
data["rate_limit"] = rate_limit
response = requests.post(url, json=data, headers=self.headers)
if response.status_code == 201:
key_data = response.json()
print(f"✅ API key created successfully")
print(f"🔑 Key: {key_data['key']}")
print(f"⚠️ Save this key! It won't be shown again.")
return key_data
else:
print(f"❌ Error: {response.status_code}")
return None
def delete_key(self, key_id):
"""Удалить API ключ"""
url = f"{self.base_url}/api/user/api-keys/{key_id}"
response = requests.delete(url, headers=self.headers)
if response.status_code == 204:
print(f"✅ API key {key_id} deleted successfully")
return True
else:
print(f"❌ Error: {response.status_code}")
return False
def rotate_key(self, key_id, name=None):
"""Ротация API ключа (удаление старого и создание нового)"""
# Удаляем старый ключ
if self.delete_key(key_id):
# Создаем новый ключ
new_name = name or f"Rotated key (from {key_id})"
return self.create_key(new_name)
return None
# Использование
manager = APIKeyManager("your-api-key")
# Список ключей
manager.list_keys()
# Создать новый ключ
new_key = manager.create_key(
name="Production API Key",
ip_whitelist=["192.168.1.1", "10.0.0.1"],
rate_limit=1000
)
# Удалить ключ
manager.delete_key(123)
# Ротация ключа
manager.rotate_key(456, "New Production Key")
class APIKeyManager {
constructor(apiKey) {
this.apiKey = apiKey;
this.baseUrl = 'https://image.nalitek.com';
}
async listKeys() {
const url = `${this.baseUrl}/api/user/api-keys`;
try {
const response = await fetch(url, {
headers: { 'X-API-Key': this.apiKey }
});
if (response.status === 200) {
const keys = await response.json();
console.log(`🔑 Total API keys: ${keys.api_keys.length}`);
keys.api_keys.forEach(key => {
console.log(`\n🆔 ID: ${key.id}`);
console.log(`📝 Name: ${key.name}`);
console.log(`🔑 Prefix: ${key.prefix}`);
console.log(`📅 Created: ${key.created_at}`);
console.log(`⏰ Last used: ${key.last_used_at}`);
console.log(`📊 Usage: ${key.usage.total_requests} requests`);
});
return keys;
} else {
console.error(`❌ Error: ${response.status}`);
return null;
}
} catch (error) {
console.error('Request failed:', error);
return null;
}
}
async createKey(name, ipWhitelist = null, rateLimit = null) {
const url = `${this.baseUrl}/api/user/api-keys`;
const data = { name };
if (ipWhitelist) data.ip_whitelist = ipWhitelist;
if (rateLimit) data.rate_limit = rateLimit;
try {
const response = await fetch(url, {
method: 'POST',
headers: {
'X-API-Key': this.apiKey,
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
if (response.status === 201) {
const keyData = await response.json();
console.log('✅ API key created successfully');
console.log(`🔑 Key: ${keyData.key}`);
console.log('⚠️ Save this key! It won\'t be shown again.');
return keyData;
} else {
console.error(`❌ Error: ${response.status}`);
return null;
}
} catch (error) {
console.error('Request failed:', error);
return null;
}
}
async deleteKey(keyId) {
const url = `${this.baseUrl}/api/user/api-keys/${keyId}`;
try {
const response = await fetch(url, {
method: 'DELETE',
headers: { 'X-API-Key': this.apiKey }
});
if (response.status === 204) {
console.log(`✅ API key ${keyId} deleted successfully`);
return true;
} else {
console.error(`❌ Error: ${response.status}`);
return false;
}
} catch (error) {
console.error('Request failed:', error);
return false;
}
}
}
// Использование
const manager = new APIKeyManager('your-api-key');
// Список ключей
manager.listKeys();
// Создать новый ключ
manager.createKey(
'Production API Key',
['192.168.1.1', '10.0.0.1'],
1000
);
// Удалить ключ
manager.deleteKey(123);
<?php
class APIKeyManager {
private $apiKey;
private $baseUrl = 'https://image.nalitek.com';
public function __construct($apiKey) {
$this->apiKey = $apiKey;
}
public function listKeys() {
$url = $this->baseUrl . '/api/user/api-keys';
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-API-Key: ' . $this->apiKey]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode === 200) {
$keys = json_decode($response, true);
echo "🔑 Total API keys: " . count($keys['api_keys']) . "\n";
foreach ($keys['api_keys'] as $key) {
echo "\n🆔 ID: {$key['id']}\n";
echo "📝 Name: {$key['name']}\n";
echo "🔑 Prefix: {$key['prefix']}\n";
echo "📅 Created: {$key['created_at']}\n";
echo "⏰ Last used: {$key['last_used_at']}\n";
echo "📊 Usage: {$key['usage']['total_requests']} requests\n";
}
return $keys;
} else {
echo "❌ Error: HTTP $httpCode\n";
return null;
}
}
public function createKey($name, $ipWhitelist = null, $rateLimit = null) {
$url = $this->baseUrl . '/api/user/api-keys';
$data = ['name' => $name];
if ($ipWhitelist) $data['ip_whitelist'] = $ipWhitelist;
if ($rateLimit) $data['rate_limit'] = $rateLimit;
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'X-API-Key: ' . $this->apiKey,
'Content-Type: application/json'
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode === 201) {
$keyData = json_decode($response, true);
echo "✅ API key created successfully\n";
echo "🔑 Key: {$keyData['key']}\n";
echo "⚠️ Save this key! It won't be shown again.\n";
return $keyData;
} else {
echo "❌ Error: HTTP $httpCode\n";
return null;
}
}
public function deleteKey($keyId) {
$url = $this->baseUrl . "/api/user/api-keys/$keyId";
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-API-Key: ' . $this->apiKey]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode === 204) {
echo "✅ API key $keyId deleted successfully\n";
return true;
} else {
echo "❌ Error: HTTP $httpCode\n";
return false;
}
}
}
// Использование
$manager = new APIKeyManager('your-api-key');
// Список ключей
$manager->listKeys();
// Создать новый ключ
$manager->createKey(
'Production API Key',
['192.168.1.1', '10.0.0.1'],
1000
);
// Удалить ключ
$manager->deleteKey(123);
Batch Processing
/api/batch/generate
Массовая генерация изображений (до 10 за раз).
Параметры запроса
| Параметр | Тип | Описание |
|---|---|---|
| batch required | array | Массив объектов с параметрами генерации (max 10) |
| webhook_url optional | string | URL для уведомлений о завершении |
Примеры использования
import requests
import time
class BatchProcessor:
def __init__(self, api_key):
self.api_key = api_key
self.base_url = "https://image.nalitek.com"
self.headers = {"X-API-Key": api_key, "Content-Type": "application/json"}
def batch_generate(self, prompts, common_params=None):
"""Массовая генерация изображений"""
url = f"{self.base_url}/api/batch/generate"
# Подготовка batch данных
batch = []
for prompt in prompts:
item = {"prompt": prompt}
if common_params:
item.update(common_params)
batch.append(item)
data = {
"batch": batch,
"webhook_url": "https://your-webhook.com/batch-complete"
}
response = requests.post(url, json=data, headers=self.headers)
if response.status_code == 201:
result = response.json()
print(f"✅ Batch created: {result['batch_id']}")
print(f"📊 Total jobs: {result['total_jobs']}")
print(f"⏱️ Estimated time: {result['estimated_time']}s")
return result
else:
print(f"❌ Error: {response.status_code}")
return None
def check_batch_status(self, batch_id):
"""Проверка статуса batch"""
url = f"{self.base_url}/api/batch/{batch_id}"
response = requests.get(url, headers=self.headers)
if response.status_code == 200:
status = response.json()
print(f"📊 Batch {batch_id}:")
print(f" Completed: {status['completed']}/{status['total']}")
print(f" Failed: {status['failed']}")
print(f" Status: {status['status']}")
return status
return None
def wait_for_batch(self, batch_id, timeout=600):
"""Ожидание завершения batch"""
start_time = time.time()
while time.time() - start_time < timeout:
status = self.check_batch_status(batch_id)
if status and status['status'] == 'completed':
print("✅ Batch completed!")
return status
elif status and status['status'] == 'failed':
print("❌ Batch failed!")
return status
time.sleep(5)
print(f"⏱️ Timeout after {timeout}s")
return None
# Использование
processor = BatchProcessor("your-api-key")
# Создание batch с разными промптами
prompts = [
"cyberpunk city at night",
"beautiful japanese garden",
"abstract art with vibrant colors",
"portrait of a robot",
"underwater coral reef"
]
batch = processor.batch_generate(
prompts=prompts,
common_params={
"width": 1024,
"height": 1024,
"steps": 30,
"model": "flux-dev"
}
)
if batch:
# Ожидание завершения
result = processor.wait_for_batch(batch['batch_id'])
if result:
# Получение результатов
for job in result['jobs']:
print(f"\n🖼️ Image {job['id']}: {job['url']}")
class BatchProcessor {
constructor(apiKey) {
this.apiKey = apiKey;
this.baseUrl = 'https://image.nalitek.com';
}
async batchGenerate(prompts, commonParams = {}) {
const url = `${this.baseUrl}/api/batch/generate`;
// Подготовка batch данных
const batch = prompts.map(prompt => ({
prompt,
...commonParams
}));
const data = {
batch,
webhook_url: 'https://your-webhook.com/batch-complete'
};
try {
const response = await fetch(url, {
method: 'POST',
headers: {
'X-API-Key': this.apiKey,
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
if (response.status === 201) {
const result = await response.json();
console.log(`✅ Batch created: ${result.batch_id}`);
console.log(`📊 Total jobs: ${result.total_jobs}`);
console.log(`⏱️ Estimated time: ${result.estimated_time}s`);
return result;
} else {
console.error(`❌ Error: ${response.status}`);
return null;
}
} catch (error) {
console.error('Request failed:', error);
return null;
}
}
async checkBatchStatus(batchId) {
const url = `${this.baseUrl}/api/batch/${batchId}`;
try {
const response = await fetch(url, {
headers: { 'X-API-Key': this.apiKey }
});
if (response.status === 200) {
const status = await response.json();
console.log(`📊 Batch ${batchId}:`);
console.log(` Completed: ${status.completed}/${status.total}`);
console.log(` Failed: ${status.failed}`);
console.log(` Status: ${status.status}`);
return status;
}
return null;
} catch (error) {
console.error('Request failed:', error);
return null;
}
}
async waitForBatch(batchId, timeout = 600000) {
const startTime = Date.now();
while (Date.now() - startTime < timeout) {
const status = await this.checkBatchStatus(batchId);
if (status && status.status === 'completed') {
console.log('✅ Batch completed!');
return status;
} else if (status && status.status === 'failed') {
console.log('❌ Batch failed!');
return status;
}
await new Promise(resolve => setTimeout(resolve, 5000));
}
console.log(`⏱️ Timeout after ${timeout}ms`);
return null;
}
}
// Использование
const processor = new BatchProcessor('your-api-key');
// Создание batch с разными промптами
const prompts = [
'cyberpunk city at night',
'beautiful japanese garden',
'abstract art with vibrant colors',
'portrait of a robot',
'underwater coral reef'
];
async function runBatch() {
const batch = await processor.batchGenerate(prompts, {
width: 1024,
height: 1024,
steps: 30,
model: 'flux-dev'
});
if (batch) {
const result = await processor.waitForBatch(batch.batch_id);
if (result) {
result.jobs.forEach(job => {
console.log(`\n🖼️ Image ${job.id}: ${job.url}`);
});
}
}
}
runBatch();
<?php
class BatchProcessor {
private $apiKey;
private $baseUrl = 'https://image.nalitek.com';
public function __construct($apiKey) {
$this->apiKey = $apiKey;
}
public function batchGenerate($prompts, $commonParams = []) {
$url = $this->baseUrl . '/api/batch/generate';
// Подготовка batch данных
$batch = [];
foreach ($prompts as $prompt) {
$item = array_merge(['prompt' => $prompt], $commonParams);
$batch[] = $item;
}
$data = [
'batch' => $batch,
'webhook_url' => 'https://your-webhook.com/batch-complete'
];
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'X-API-Key: ' . $this->apiKey,
'Content-Type: application/json'
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode === 201) {
$result = json_decode($response, true);
echo "✅ Batch created: {$result['batch_id']}\n";
echo "📊 Total jobs: {$result['total_jobs']}\n";
echo "⏱️ Estimated time: {$result['estimated_time']}s\n";
return $result;
} else {
echo "❌ Error: HTTP $httpCode\n";
return null;
}
}
public function checkBatchStatus($batchId) {
$url = $this->baseUrl . "/api/batch/$batchId";
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-API-Key: ' . $this->apiKey]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode === 200) {
$status = json_decode($response, true);
echo "📊 Batch $batchId:\n";
echo " Completed: {$status['completed']}/{$status['total']}\n";
echo " Failed: {$status['failed']}\n";
echo " Status: {$status['status']}\n";
return $status;
}
return null;
}
public function waitForBatch($batchId, $timeout = 600) {
$startTime = time();
while (time() - $startTime < $timeout) {
$status = $this->checkBatchStatus($batchId);
if ($status && $status['status'] === 'completed') {
echo "✅ Batch completed!\n";
return $status;
} elseif ($status && $status['status'] === 'failed') {
echo "❌ Batch failed!\n";
return $status;
}
sleep(5);
}
echo "⏱️ Timeout after {$timeout}s\n";
return null;
}
}
// Использование
$processor = new BatchProcessor('your-api-key');
// Создание batch с разными промптами
$prompts = [
'cyberpunk city at night',
'beautiful japanese garden',
'abstract art with vibrant colors',
'portrait of a robot',
'underwater coral reef'
];
$batch = $processor->batchGenerate($prompts, [
'width' => 1024,
'height' => 1024,
'steps' => 30,
'model' => 'flux-dev'
]);
if ($batch) {
$result = $processor->waitForBatch($batch['batch_id']);
if ($result) {
foreach ($result['jobs'] as $job) {
echo "\n🖼️ Image {$job['id']}: {$job['url']}\n";
}
}
}
Admin Panel
/api/admin/users
Получение списка всех пользователей.
/api/admin/statistics
Общая статистика системы.
/api/admin/user/{user_id}/quota
Изменение квот пользователя.
Примеры использования
import requests
class AdminAPI:
def __init__(self, admin_api_key):
self.api_key = admin_api_key
self.base_url = "https://image.nalitek.com"
self.headers = {"X-API-Key": admin_api_key, "Content-Type": "application/json"}
def get_users(self, page=1, per_page=50):
"""Получить список пользователей"""
url = f"{self.base_url}/api/admin/users"
params = {"page": page, "per_page": per_page}
response = requests.get(url, params=params, headers=self.headers)
if response.status_code == 200:
data = response.json()
print(f"👥 Total users: {data['total']}")
for user in data['users']:
print(f"\n👤 {user['username']} ({user['email']})")
print(f" Plan: {user['plan']}")
print(f" Quota: {user['quota']['daily_generations']}/day")
print(f" Created: {user['created_at']}")
return data
else:
print(f"❌ Error: {response.status_code}")
return None
def get_statistics(self):
"""Получить общую статистику"""
url = f"{self.base_url}/api/admin/statistics"
response = requests.get(url, headers=self.headers)
if response.status_code == 200:
stats = response.json()
print("📊 System Statistics:")
print(f" Total users: {stats['total_users']}")
print(f" Active users (24h): {stats['active_users_24h']}")
print(f" Total generations: {stats['total_generations']}")
print(f" Generations today: {stats['generations_today']}")
print(f" Storage used: {stats['storage_used_gb']} GB")
print(f" Revenue this month: ${stats['revenue_month']}")
return stats
else:
print(f"❌ Error: {response.status_code}")
return None
def update_user_quota(self, user_id, daily_generations, daily_upscales):
"""Обновить квоты пользователя"""
url = f"{self.base_url}/api/admin/user/{user_id}/quota"
data = {
"daily_generations": daily_generations,
"daily_upscales": daily_upscales
}
response = requests.post(url, json=data, headers=self.headers)
if response.status_code == 200:
print(f"✅ Quota updated for user {user_id}")
return True
else:
print(f"❌ Error: {response.status_code}")
return False
def ban_user(self, user_id, reason):
"""Заблокировать пользователя"""
url = f"{self.base_url}/api/admin/user/{user_id}/ban"
data = {"reason": reason}
response = requests.post(url, json=data, headers=self.headers)
if response.status_code == 200:
print(f"✅ User {user_id} banned")
return True
else:
print(f"❌ Error: {response.status_code}")
return False
# Использование
admin = AdminAPI("admin-api-key")
# Получить пользователей
admin.get_users(page=1)
# Получить статистику
admin.get_statistics()
# Обновить квоты
admin.update_user_quota(
user_id=123,
daily_generations=500,
daily_upscales=100
)
# Заблокировать пользователя
admin.ban_user(456, "Violation of terms of service")
class AdminAPI {
constructor(adminApiKey) {
this.apiKey = adminApiKey;
this.baseUrl = 'https://image.nalitek.com';
}
async getUsers(page = 1, perPage = 50) {
const url = new URL(`${this.baseUrl}/api/admin/users`);
url.searchParams.append('page', page);
url.searchParams.append('per_page', perPage);
try {
const response = await fetch(url, {
headers: { 'X-API-Key': this.apiKey }
});
if (response.status === 200) {
const data = await response.json();
console.log(`👥 Total users: ${data.total}`);
data.users.forEach(user => {
console.log(`\n👤 ${user.username} (${user.email})`);
console.log(` Plan: ${user.plan}`);
console.log(` Quota: ${user.quota.daily_generations}/day`);
console.log(` Created: ${user.created_at}`);
});
return data;
} else {
console.error(`❌ Error: ${response.status}`);
return null;
}
} catch (error) {
console.error('Request failed:', error);
return null;
}
}
async getStatistics() {
const url = `${this.baseUrl}/api/admin/statistics`;
try {
const response = await fetch(url, {
headers: { 'X-API-Key': this.apiKey }
});
if (response.status === 200) {
const stats = await response.json();
console.log('📊 System Statistics:');
console.log(` Total users: ${stats.total_users}`);
console.log(` Active users (24h): ${stats.active_users_24h}`);
console.log(` Total generations: ${stats.total_generations}`);
console.log(` Generations today: ${stats.generations_today}`);
console.log(` Storage used: ${stats.storage_used_gb} GB`);
console.log(` Revenue this month: ${stats.revenue_month}`);
return stats;
} else {
console.error(`❌ Error: ${response.status}`);
return null;
}
} catch (error) {
console.error('Request failed:', error);
return null;
}
}
async updateUserQuota(userId, dailyGenerations, dailyUpscales) {
const url = `${this.baseUrl}/api/admin/user/${userId}/quota`;
try {
const response = await fetch(url, {
method: 'POST',
headers: {
'X-API-Key': this.apiKey,
'Content-Type': 'application/json'
},
body: JSON.stringify({
daily_generations: dailyGenerations,
daily_upscales: dailyUpscales
})
});
if (response.status === 200) {
console.log(`✅ Quota updated for user ${userId}`);
return true;
} else {
console.error(`❌ Error: ${response.status}`);
return false;
}
} catch (error) {
console.error('Request failed:', error);
return false;
}
}
}
// Использование
const admin = new AdminAPI('admin-api-key');
// Получить пользователей
admin.getUsers(1);
// Получить статистику
admin.getStatistics();
// Обновить квоты
admin.updateUserQuota(123, 500, 100);
<?php
class AdminAPI {
private $apiKey;
private $baseUrl = 'https://image.nalitek.com';
public function __construct($adminApiKey) {
$this->apiKey = $adminApiKey;
}
public function getUsers($page = 1, $perPage = 50) {
$url = $this->baseUrl . '/api/admin/users';
$url .= '?' . http_build_query(['page' => $page, 'per_page' => $perPage]);
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-API-Key: ' . $this->apiKey]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode === 200) {
$data = json_decode($response, true);
echo "👥 Total users: {$data['total']}\n";
foreach ($data['users'] as $user) {
echo "\n👤 {$user['username']} ({$user['email']})\n";
echo " Plan: {$user['plan']}\n";
echo " Quota: {$user['quota']['daily_generations']}/day\n";
echo " Created: {$user['created_at']}\n";
}
return $data;
} else {
echo "❌ Error: HTTP $httpCode\n";
return null;
}
}
public function getStatistics() {
$url = $this->baseUrl . '/api/admin/statistics';
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-API-Key: ' . $this->apiKey]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode === 200) {
$stats = json_decode($response, true);
echo "📊 System Statistics:\n";
echo " Total users: {$stats['total_users']}\n";
echo " Active users (24h): {$stats['active_users_24h']}\n";
echo " Total generations: {$stats['total_generations']}\n";
echo " Generations today: {$stats['generations_today']}\n";
echo " Storage used: {$stats['storage_used_gb']} GB\n";
echo " Revenue this month: \${$stats['revenue_month']}\n";
return $stats;
} else {
echo "❌ Error: HTTP $httpCode\n";
return null;
}
}
public function updateUserQuota($userId, $dailyGenerations, $dailyUpscales) {
$url = $this->baseUrl . "/api/admin/user/$userId/quota";
$data = [
'daily_generations' => $dailyGenerations,
'daily_upscales' => $dailyUpscales
];
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'X-API-Key: ' . $this->apiKey,
'Content-Type: application/json'
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode === 200) {
echo "✅ Quota updated for user $userId\n";
return true;
} else {
echo "❌ Error: HTTP $httpCode\n";
return false;
}
}
}
// Использование
$admin = new AdminAPI('admin-api-key');
// Получить пользователей
$admin->getUsers(1);
// Получить статистику
$admin->getStatistics();
// Обновить квоты
$admin->updateUserQuota(123, 500, 100);
LoRA Модели
/api/loras
Получение списка доступных LoRA моделей для стилизации.
Примеры использования
# Получить список всех доступных LoRA моделей
curl -X GET https://image.nalitek.com/api/loras \
-H "X-API-Key: your-api-key"
# Использование LoRA при генерации
curl -X POST https://image.nalitek.com/api/generate \
-H "X-API-Key: your-api-key" \
-H "Content-Type: application/json" \
-d '{
"prompt": "anime character with detailed eyes, manga style",
"lora_id": "anime-style-v2",
"width": 1024,
"height": 1024
}'
# Использование нескольких LoRA в img2img
curl -X POST https://image.nalitek.com/api/img2img \
-H "X-API-Key: your-api-key" \
-F "image=@photo.jpg" \
-F "prompt=detailed portrait" \
-F "lora_models[]=anime-style-v2" \
-F "lora_models[]=detailed-eyes-v1" \
-F "strength=0.7"
Успешный ответ
{
"loras": [
{
"id": "anime-style-v2",
"name": "Anime Style v2",
"description": "Стиль аниме для персонажей",
"trigger_words": ["anime", "manga"],
"example_prompt": "anime character, detailed eyes",
"thumbnail_url": "https://image.nalitek.com/uploads/loras/previews/anime-v2_preview.jpg",
"is_active": true,
"is_public": true,
"created_at": "2025-01-10T08:00:00Z",
"category": "style",
"weight_recommended": 0.8
}
]
}
Категории LoRA моделей
- style - Художественные стили (аниме, комикс, живопись)
- character - Персонажи и типажи
- concept - Концепции и тематики
- architecture - Архитектурные стили
- nature - Природа и пейзажи
Статистика пользователя
/api/user/stats
Получение статистики использования API и информации о квотах.
Пример запроса
# Получить статистику использования
curl -X GET https://image.nalitek.com/api/user/stats \
-H "X-API-Key: your-api-key"
# Форматированный вывод с jq
curl -X GET https://image.nalitek.com/api/user/stats \
-H "X-API-Key: your-api-key" \
| jq '.'
# Проверить оставшиеся квоты
curl -X GET https://image.nalitek.com/api/user/stats \
-H "X-API-Key: your-api-key" \
| jq '.quota'
Успешный ответ
{
"user": {
"id": 1,
"username": "john_doe",
"email": "john@example.com",
"role": "user",
"plan": "pro"
},
"quota": {
"daily_generations": 100,
"daily_upscales": 50,
"used_generations": 37,
"used_upscales": 8,
"remaining_generations": 63,
"remaining_upscales": 42,
"reset_at": "2025-01-16T00:00:00Z"
},
"storage": {
"used_mb": 3276.8,
"limit_mb": 10240,
"percent_used": 32.0
},
"statistics": {
"total_generations": 1847,
"total_upscales": 423,
"total_img2img": 156,
"average_generation_time": 31.2,
"favorite_count": 89,
"created_at": "2024-12-01T10:00:00Z"
}
}
WebSocket События
Для получения обновлений в реальном времени используйте Socket.IO подключение.
Подключение
const socket = io('https://image.nalitek.com', {
auth: {
token: 'your-api-key'
}
});
// Подписка на канал генерации
socket.emit('subscribe', { channel: 'generation_4738' });
// Обработка событий
socket.on('generation_progress', (data) => {
console.log(`Progress: ${data.progress}%`);
});
События генерации
generation_started
{
"image_id": 4738,
"message": "Генерация началась"
}
generation_progress
{
"image_id": 4738,
"progress": 47,
"current_step": 14,
"total_steps": 30,
"phase": "generating",
"message": "Генерация изображения (Шаг 14/30)..."
}
generation_complete
{
"image_id": 4738,
"url": "https://image.nalitek.com/uploads/images/flux_20250115_145230_b3cd4567.png",
"thumbnail_url": "https://image.nalitek.com/uploads/images/thumbnails/flux_20250115_145230_b3cd4567_thumb.png",
"seed": 8472659,
"time": 27.3,
"status": "completed"
}
Batch API - Пакетная обработка
Batch API позволяет отправлять несколько запросов генерации одновременно для более эффективной обработки.
Пакетная генерация изображений
Отправка до 10 запросов генерации в одном вызове API.
Параметры запроса
| Параметр | Тип | Обязательный | Описание |
|---|---|---|---|
batch |
array | Да | Массив запросов генерации (макс. 10) |
batch[].prompt |
string | Да | Текстовое описание для каждого изображения |
batch[].params |
object | Нет | Параметры генерации (width, height, steps и т.д.) |
batch[].id |
string | Нет | Клиентский ID для отслеживания |
parallel |
boolean | Нет | Параллельная обработка (default: false) |
priority |
string | Нет | Приоритет: low, normal, high (default: normal) |
Примеры запросов
cURL
# Пакетная генерация нескольких изображений
curl -X POST https://image.nalitek.com/api/batch/generate \
-H "X-API-Key: your-api-key" \
-H "Content-Type: application/json" \
-d '{
"batch": [
{
"id": "req_001",
"prompt": "futuristic city at night",
"params": {
"width": 1024,
"height": 1024,
"steps": 30,
"seed": 42
}
},
{
"id": "req_002",
"prompt": "magical forest with fireflies",
"params": {
"width": 1920,
"height": 1080,
"smart_upscale": true,
"target_width": 3840,
"target_height": 2160
}
}
],
"parallel": true,
"priority": "high"
}'
# Проверка статуса пакета
curl -X GET https://image.nalitek.com/api/batch/batch_1736856789_a5f3b2c1 \
-H "X-API-Key: your-api-key"
# Отмена пакетной обработки
curl -X DELETE https://image.nalitek.com/api/batch/batch_1736856789_a5f3b2c1 \
-H "X-API-Key: your-api-key"
JSON структура
{
"batch": [
{
"id": "req_001",
"prompt": "futuristic city at night",
"params": {
"width": 1024,
"height": 1024,
"steps": 30,
"seed": 42
}
},
{
"id": "req_002",
"prompt": "magical forest with fireflies",
"params": {
"width": 1920,
"height": 1080,
"smart_upscale": true,
"target_width": 3840,
"target_height": 2160
}
},
{
"id": "req_003",
"prompt": "underwater ancient ruins",
"params": {
"model": "flux-schnell",
"steps": 20
}
}
],
"parallel": true,
"priority": "high"
}
Успешный ответ (202 Accepted)
{
"batch_id": "batch_1736856789_a5f3b2c1",
"status": "processing",
"total": 3,
"queued": 3,
"processing": 0,
"completed": 0,
"failed": 0,
"jobs": [
{
"id": "req_001",
"image_id": 4739,
"status": "queued",
"position": 1
},
{
"id": "req_002",
"image_id": 4740,
"status": "queued",
"position": 2
},
{
"id": "req_003",
"image_id": 4741,
"status": "queued",
"position": 3
}
],
"status_url": "/api/batch/batch_1736856789_a5f3b2c1",
"websocket_channel": "batch_1736856789_a5f3b2c1"
}
Статус пакетной обработки
Получение статуса всех задач в пакете.
Успешный ответ
{
"batch_id": "batch_1736856789_a5f3b2c1",
"status": "completed",
"total": 3,
"queued": 0,
"processing": 0,
"completed": 3,
"failed": 0,
"started_at": "2025-01-15T10:00:00Z",
"completed_at": "2025-01-15T10:02:30Z",
"total_time": 150.5,
"jobs": [
{
"id": "req_001",
"image_id": 4739,
"status": "completed",
"url": "https://image.nalitek.com/uploads/images/flux_20250115_150100_xyz98765.png",
"seed": 2847391,
"generation_time": 45.2
},
{
"id": "req_002",
"image_id": 4740,
"status": "completed",
"url": "https://image.nalitek.com/uploads/images/flux_20250115_145245_def45678.png",
"seed": 7263849,
"generation_time": 62.1
},
{
"id": "req_003",
"image_id": 4741,
"status": "completed",
"url": "https://image.nalitek.com/uploads/images/flux_20250115_145300_ghi78901.png",
"seed": 9182736,
"generation_time": 43.2
}
]
}
Пакетная трансформация изображений
Применение различных трансформаций к одному или нескольким изображениям.
Параметры запроса (multipart/form-data)
| Параметр | Тип | Описание |
|---|---|---|
images[] |
file[] | Массив изображений для обработки |
prompts[] |
string[] | Массив промптов для каждого изображения |
shared_params |
json | Общие параметры для всех изображений |
Примеры использования
cURL
# Пакетная трансформация нескольких изображений
curl -X POST https://image.nalitek.com/api/batch/img2img \
-H "X-API-Key: your-api-key" \
-F "images[]=@image1.jpg" \
-F "images[]=@image2.jpg" \
-F "images[]=@image3.jpg" \
-F "prompts[]=convert to cyberpunk style" \
-F "prompts[]=make it look vintage" \
-F "prompts[]=transform to anime style" \
-F 'shared_params={"strength": 0.75, "steps": 30, "smart_upscale": true, "target_width": 2048, "target_height": 2048}'
# Одно изображение с разными вариациями
curl -X POST https://image.nalitek.com/api/batch/img2img \
-H "X-API-Key: your-api-key" \
-F "images[]=@portrait.jpg" \
-F "prompts[]=oil painting style" \
-F "prompts[]=watercolor style" \
-F "prompts[]=pencil sketch style" \
-F 'shared_params={"strength": 0.8, "steps": 40}'
# С LoRA моделями
curl -X POST https://image.nalitek.com/api/batch/img2img \
-H "X-API-Key: your-api-key" \
-F "images[]=@photo1.jpg" \
-F "images[]=@photo2.jpg" \
-F "prompts[]=anime character with detailed eyes" \
-F "prompts[]=manga style illustration" \
-F 'shared_params={"lora_models": ["anime-style-v2", "detailed-eyes-v1"], "strength": 0.7}'
JavaScript
const formData = new FormData();
// Добавляем изображения
formData.append('images[]', file1);
formData.append('images[]', file2);
// Добавляем промпты
formData.append('prompts[]', 'convert to cyberpunk style');
formData.append('prompts[]', 'make it look vintage');
// Общие параметры
formData.append('shared_params', JSON.stringify({
strength: 0.75,
steps: 30,
smart_upscale: true,
target_width: 2048,
target_height: 2048
}));
const response = await fetch('/api/batch/img2img', {
method: 'POST',
headers: {
'X-API-Key': 'your-api-key'
},
body: formData
});
Отмена пакетной обработки
Отмена всех незавершенных задач в пакете.
Успешный ответ
{
"batch_id": "batch_1736856789_a5f3b2c1",
"cancelled": 2,
"completed": 1,
"message": "Batch processing cancelled"
}
Особенности Batch API
- Эффективность: Экономия на накладных расходах HTTP
- Приоритизация: Управление очередью обработки
- Атомарность: Каждая задача обрабатывается независимо
- Отслеживание: WebSocket уведомления для каждой задачи
- Квоты: Учитывается как отдельные генерации
WebSocket события для Batch
// Подписка на batch канал
socket.emit('subscribe', { channel: 'batch_1736856789_a5f3b2c1' });
// События
socket.on('batch_started', (data) => {
console.log('Batch processing started');
});
socket.on('job_completed', (data) => {
console.log(`Job ${data.job_id} completed`);
});
socket.on('batch_completed', (data) => {
console.log('All jobs completed');
});
🎯 Лучшие практики
- Используйте batch для генерации вариаций одного концепта
- Группируйте запросы с похожими параметрами
- Устанавливайте priority для срочных пакетов
- Используйте client ID для удобного отслеживания
- Обрабатывайте частичные ошибки в пакете
Webhook Интеграция
Для получения уведомлений о завершении генерации можно настроить webhook в параметрах запроса:
Настройка webhook
{
"prompt": "beautiful landscape",
"webhook_url": "https://your-server.com/webhook",
"webhook_events": ["generation.complete", "generation.failed"]
}
Формат webhook запроса
Webhook получит POST запрос с следующей структурой:
{
"event": "generation.complete",
"timestamp": "2025-01-15T10:30:00Z",
"data": {
"image_id": 123,
"url": "https://image.nalitek.com/uploads/images/flux_20250115_150100_xyz98765.png",
"prompt": "futuristic city at night, neon lights, cyberpunk style, ultra detailed",
"seed": 8472659,
"generation_time": 25.5
},
"signature": "sha256=..." // HMAC подпись для верификации
}
Доступные события
generation.started- генерация началасьgeneration.progress- прогресс генерацииgeneration.complete- генерация завершена успешноgeneration.failed- ошибка генерацииupscale.complete- upscale завершенupscale.failed- ошибка upscale
Лимиты и квоты
⚡ Rate Limiting по эндпоинтам
| Эндпоинт | Лимит | Окно времени |
|---|---|---|
| /api/generate | 10 запросов | 1 минута |
| /api/img2img | 10 запросов | 1 минута |
| /api/upscale/{id} | 5 запросов | 1 минута |
| /api/images | 60 запросов | 1 минута |
| /api/batch/generate | 2 запроса | 1 минута |
📊 Дневные квоты по планам
| План | Генераций/день | Img2Img/день | Upscale/день | Макс. разрешение | Хранилище |
|---|---|---|---|---|---|
| Free | 10 | 5 | 5 | 1024×1024 | 100 MB |
| Pro | 100 | 50 | 50 | 2048×2048 | 1 GB |
| Business | 1000 | 500 | 500 | 2048×2048 | 10 GB |
| Enterprise | Без лимитов | Без лимитов | Без лимитов | 4096×4096 | Без лимитов |
Коды ошибок
| Код | Статус | Описание | Решение |
|---|---|---|---|
| 200 | OK | Успешный запрос | - |
| 201 | Created | Ресурс создан | - |
| 400 | Bad Request | Неверные параметры запроса | Проверьте формат данных и обязательные поля |
| 401 | Unauthorized | Отсутствует или неверный API ключ | Добавьте заголовок X-API-Key |
| 403 | Forbidden | Превышен лимит генераций | Дождитесь сброса квоты в 00:00 UTC |
| 404 | Not Found | Ресурс не найден | Проверьте ID или URL |
| 429 | Too Many Requests | Превышен rate limit | Смотрите заголовок Retry-After |
| 500 | Internal Server Error | Ошибка сервера | Повторите позже |
Формат ошибок
{
"error": "Краткое описание ошибки",
"details": "Детальное описание проблемы",
"code": "ERROR_CODE",
"request_id": "req_abc123def456"
}
Модели и форматы
🤖 Доступные модели
flux-dev- основная модель FLUX для высокого качества (30-50 шагов)flux-schnell- быстрая модель FLUX (10-20 шагов)
🖼️ Поддерживаемые форматы изображений
| Входные форматы | PNG, JPEG, WebP |
| Выходные форматы | PNG, JPEG, WebP |
| Максимальный размер файла | 10 MB |
📐 Ограничения размеров
| Минимум | 512×512 |
| Максимум (Free) | 1024×1024 |
| Максимум (Pro/Business) | 2048×2048 |
| Максимум (Enterprise) | 4096×4096 |
| Шаг изменения | 64 пикселя |
| Рекомендуемые размеры | 768×768, 1024×1024, 1920×1080 |
Полные примеры интеграции
Готовые примеры для быстрой интеграции API в ваши проекты.
# flux_api_sdk.py
"""
FLUX API SDK for Python
Complete integration example
"""
import requests
import time
import json
from typing import Optional, Dict, Any, List
from enum import Enum
class Model(Enum):
FLUX_DEV = "flux-dev"
FLUX_SCHNELL = "flux-schnell"
class ImageFormat(Enum):
PNG = "png"
JPEG = "jpeg"
WEBP = "webp"
class FluxAPISDK:
"""Complete FLUX API SDK for Python"""
def __init__(self, api_key: str, base_url: str = "https://image.nalitek.com"):
self.api_key = api_key
self.base_url = base_url
self.headers = {
"X-API-Key": api_key,
"Content-Type": "application/json"
}
def generate(
self,
prompt: str,
negative_prompt: str = "",
width: int = 1024,
height: int = 1024,
steps: int = 30,
guidance_scale: float = 7.5,
seed: int = -1,
model: Model = Model.FLUX_DEV,
format: ImageFormat = ImageFormat.PNG,
lora_id: Optional[str] = None,
webhook_url: Optional[str] = None,
wait_for_completion: bool = True
) -> Dict[str, Any]:
"""
Generate an image from text prompt
Args:
prompt: Text description of desired image
negative_prompt: What to exclude from generation
width: Image width (512-2048, divisible by 64)
height: Image height (512-2048, divisible by 64)
steps: Number of generation steps (10-100)
guidance_scale: Prompt adherence strength (1.0-20.0)
seed: Seed for reproducibility (-1 for random)
model: Model to use (FLUX_DEV or FLUX_SCHNELL)
format: Output format (PNG, JPEG, or WEBP)
lora_id: LoRA model ID for styling
webhook_url: URL for completion notifications
wait_for_completion: Whether to wait for generation to complete
Returns:
Dictionary with image data or generation status
"""
url = f"{self.base_url}/api/generate"
data = {
"prompt": prompt,
"negative_prompt": negative_prompt,
"width": width,
"height": height,
"steps": steps,
"guidance_scale": guidance_scale,
"seed": seed,
"model": model.value,
"format": format.value
}
if lora_id:
data["lora_id"] = lora_id
if webhook_url:
data["webhook_url"] = webhook_url
response = requests.post(url, json=data, headers=self.headers)
if response.status_code == 201:
result = response.json()
if wait_for_completion:
return self._wait_for_image(result["image_id"])
return result
else:
raise Exception(f"API Error {response.status_code}: {response.text}")
def img2img(
self,
image_path: str,
prompt: str,
negative_prompt: str = "",
strength: float = 0.75,
steps: int = 30,
guidance_scale: float = 7.5,
seed: int = -1,
wait_for_completion: bool = True
) -> Dict[str, Any]:
"""
Transform an existing image based on text prompt
Args:
image_path: Path to input image file
prompt: Description of desired transformation
negative_prompt: What to exclude from generation
strength: Transformation strength (0.0-1.0)
steps: Number of generation steps (10-100)
guidance_scale: Prompt adherence strength (1.0-20.0)
seed: Seed for reproducibility (-1 for random)
wait_for_completion: Whether to wait for completion
Returns:
Dictionary with transformed image data
"""
url = f"{self.base_url}/api/img2img"
with open(image_path, 'rb') as f:
files = {'image': (image_path, f, 'image/png')}
data = {
'prompt': prompt,
'negative_prompt': negative_prompt,
'strength': strength,
'steps': steps,
'guidance_scale': guidance_scale,
'seed': seed
}
headers = {"X-API-Key": self.api_key}
response = requests.post(url, headers=headers, files=files, data=data)
if response.status_code == 201:
result = response.json()
if wait_for_completion and 'image_id' in result:
return self._wait_for_image(result["image_id"])
return result
else:
raise Exception(f"API Error {response.status_code}: {response.text}")
def upscale(
self,
image_id: int,
scale: int = 2,
face_enhance: bool = False,
denoise: float = 0.5
) -> Dict[str, Any]:
"""
Upscale an existing image
Args:
image_id: ID of image to upscale
scale: Upscaling factor (2 or 4)
face_enhance: Whether to enhance faces with GFPGAN
denoise: Denoising level (0.0-1.0)
Returns:
Dictionary with upscaled image data
"""
url = f"{self.base_url}/api/upscale/{image_id}"
data = {
"scale": scale,
"face_enhance": face_enhance,
"denoise": denoise
}
response = requests.post(url, json=data, headers=self.headers)
if response.status_code == 201:
return response.json()
else:
raise Exception(f"API Error {response.status_code}: {response.text}")
def get_image(self, image_id: int) -> Dict[str, Any]:
"""Get details of a specific image"""
url = f"{self.base_url}/api/images/{image_id}"
response = requests.get(url, headers=self.headers)
if response.status_code == 200:
return response.json()
else:
raise Exception(f"API Error {response.status_code}: {response.text}")
def list_images(
self,
page: int = 1,
per_page: int = 20,
status: Optional[str] = None,
is_upscaled: Optional[bool] = None,
sort: str = "date_desc"
) -> Dict[str, Any]:
"""
List user's images with pagination and filters
Args:
page: Page number
per_page: Items per page (1-100)
status: Filter by status (generating/completed/failed)
is_upscaled: Filter by upscale status
sort: Sort order (date_desc/date_asc)
Returns:
Dictionary with paginated image list
"""
url = f"{self.base_url}/api/images"
params = {
'page': page,
'per_page': per_page,
'sort': sort
}
if status:
params['status'] = status
if is_upscaled is not None:
params['is_upscaled'] = is_upscaled
response = requests.get(url, params=params, headers=self.headers)
if response.status_code == 200:
return response.json()
else:
raise Exception(f"API Error {response.status_code}: {response.text}")
def delete_image(self, image_id: int) -> bool:
"""Delete an image"""
url = f"{self.base_url}/api/images/{image_id}"
response = requests.delete(url, headers=self.headers)
return response.status_code == 204
def get_loras(self) -> List[Dict[str, Any]]:
"""Get list of available LoRA models"""
url = f"{self.base_url}/api/loras"
response = requests.get(url, headers=self.headers)
if response.status_code == 200:
return response.json()['loras']
else:
raise Exception(f"API Error {response.status_code}: {response.text}")
def get_user_stats(self) -> Dict[str, Any]:
"""Get user statistics and quota information"""
url = f"{self.base_url}/api/user/stats"
response = requests.get(url, headers=self.headers)
if response.status_code == 200:
return response.json()
else:
raise Exception(f"API Error {response.status_code}: {response.text}")
def check_api_status(self) -> Dict[str, Any]:
"""Check API status and service availability"""
url = f"{self.base_url}/api/status"
response = requests.get(url)
if response.status_code == 200:
return response.json()
else:
raise Exception(f"API Error {response.status_code}: {response.text}")
def batch_generate(
self,
prompts: List[str],
common_params: Optional[Dict[str, Any]] = None,
webhook_url: Optional[str] = None
) -> Dict[str, Any]:
"""
Generate multiple images in batch
Args:
prompts: List of prompts (max 10)
common_params: Common parameters for all generations
webhook_url: URL for batch completion notification
Returns:
Dictionary with batch information
"""
url = f"{self.base_url}/api/batch/generate"
batch = []
for prompt in prompts[:10]: # Limit to 10
item = {"prompt": prompt}
if common_params:
item.update(common_params)
batch.append(item)
data = {"batch": batch}
if webhook_url:
data["webhook_url"] = webhook_url
response = requests.post(url, json=data, headers=self.headers)
if response.status_code == 201:
return response.json()
else:
raise Exception(f"API Error {response.status_code}: {response.text}")
def _wait_for_image(self, image_id: int, timeout: int = 120) -> Dict[str, Any]:
"""Wait for image generation to complete"""
start_time = time.time()
while time.time() - start_time < timeout:
image = self.get_image(image_id)
if image['status'] == 'completed':
return image
elif image['status'] == 'failed':
raise Exception(f"Generation failed: {image.get('error_message')}")
time.sleep(2)
raise Exception(f"Generation timeout after {timeout} seconds")
# Example usage
if __name__ == "__main__":
# Initialize SDK
sdk = FluxAPISDK("your-api-key")
# Check API status
status = sdk.check_api_status()
print(f"API Status: {status['status']}")
# Generate an image
try:
image = sdk.generate(
prompt="beautiful sunset over mountains, professional photography",
width=1024,
height=1024,
steps=30,
model=Model.FLUX_DEV,
format=ImageFormat.PNG
)
print(f"Generated image: {image['url']}")
# Upscale the image
upscaled = sdk.upscale(image['id'], scale=2)
print(f"Upscaled image: {upscaled['url']}")
except Exception as e:
print(f"Error: {e}")
# Get user statistics
stats = sdk.get_user_stats()
print(f"Remaining generations: {stats['quota']['remaining_generations']}")
# List available LoRA models
loras = sdk.get_loras()
for lora in loras:
print(f"LoRA: {lora['name']} ({lora['id']})")
// flux-api-sdk.js
/**
* FLUX API SDK for JavaScript
* Complete integration example
*/
class FluxAPISDK {
constructor(apiKey, baseUrl = 'https://image.nalitek.com') {
this.apiKey = apiKey;
this.baseUrl = baseUrl;
}
/**
* Generate an image from text prompt
*/
async generate(options = {}) {
const url = `${this.baseUrl}/api/generate`;
const data = {
prompt: options.prompt,
negative_prompt: options.negative_prompt || '',
width: options.width || 1024,
height: options.height || 1024,
steps: options.steps || 30,
guidance_scale: options.guidance_scale || 7.5,
seed: options.seed || -1,
model: options.model || 'flux-dev',
format: options.format || 'png'
};
if (options.lora_id) data.lora_id = options.lora_id;
if (options.webhook_url) data.webhook_url = options.webhook_url;
const response = await fetch(url, {
method: 'POST',
headers: {
'X-API-Key': this.apiKey,
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
if (response.status === 201) {
const result = await response.json();
if (options.waitForCompletion !== false) {
return await this.waitForImage(result.image_id);
}
return result;
} else {
const error = await response.json();
throw new Error(`API Error ${response.status}: ${error.error}`);
}
}
/**
* Transform an existing image
*/
async img2img(imageFile, options = {}) {
const url = `${this.baseUrl}/api/img2img`;
const formData = new FormData();
formData.append('image', imageFile);
formData.append('prompt', options.prompt);
formData.append('negative_prompt', options.negative_prompt || '');
formData.append('strength', options.strength || 0.75);
formData.append('steps', options.steps || 30);
formData.append('guidance_scale', options.guidance_scale || 7.5);
formData.append('seed', options.seed || -1);
const response = await fetch(url, {
method: 'POST',
headers: {
'X-API-Key': this.apiKey
},
body: formData
});
if (response.status === 201) {
const result = await response.json();
if (options.waitForCompletion !== false && result.image_id) {
return await this.waitForImage(result.image_id);
}
return result;
} else {
const error = await response.json();
throw new Error(`API Error ${response.status}: ${error.error}`);
}
}
/**
* Upscale an image
*/
async upscale(imageId, options = {}) {
const url = `${this.baseUrl}/api/upscale/${imageId}`;
const data = {
scale: options.scale || 2,
face_enhance: options.face_enhance || false,
denoise: options.denoise || 0.5
};
const response = await fetch(url, {
method: 'POST',
headers: {
'X-API-Key': this.apiKey,
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
if (response.status === 201) {
return await response.json();
} else {
const error = await response.json();
throw new Error(`API Error ${response.status}: ${error.error}`);
}
}
/**
* Get image details
*/
async getImage(imageId) {
const url = `${this.baseUrl}/api/images/${imageId}`;
const response = await fetch(url, {
headers: { 'X-API-Key': this.apiKey }
});
if (response.status === 200) {
return await response.json();
} else {
const error = await response.json();
throw new Error(`API Error ${response.status}: ${error.error}`);
}
}
/**
* List images with filters
*/
async listImages(options = {}) {
const url = new URL(`${this.baseUrl}/api/images`);
url.searchParams.append('page', options.page || 1);
url.searchParams.append('per_page', options.per_page || 20);
url.searchParams.append('sort', options.sort || 'date_desc');
if (options.status) url.searchParams.append('status', options.status);
if (options.is_upscaled !== undefined) {
url.searchParams.append('is_upscaled', options.is_upscaled);
}
const response = await fetch(url, {
headers: { 'X-API-Key': this.apiKey }
});
if (response.status === 200) {
return await response.json();
} else {
const error = await response.json();
throw new Error(`API Error ${response.status}: ${error.error}`);
}
}
/**
* Delete an image
*/
async deleteImage(imageId) {
const url = `${this.baseUrl}/api/images/${imageId}`;
const response = await fetch(url, {
method: 'DELETE',
headers: { 'X-API-Key': this.apiKey }
});
return response.status === 204;
}
/**
* Get available LoRA models
*/
async getLoras() {
const url = `${this.baseUrl}/api/loras`;
const response = await fetch(url, {
headers: { 'X-API-Key': this.apiKey }
});
if (response.status === 200) {
const data = await response.json();
return data.loras;
} else {
const error = await response.json();
throw new Error(`API Error ${response.status}: ${error.error}`);
}
}
/**
* Get user statistics
*/
async getUserStats() {
const url = `${this.baseUrl}/api/user/stats`;
const response = await fetch(url, {
headers: { 'X-API-Key': this.apiKey }
});
if (response.status === 200) {
return await response.json();
} else {
const error = await response.json();
throw new Error(`API Error ${response.status}: ${error.error}`);
}
}
/**
* Check API status
*/
async checkApiStatus() {
const url = `${this.baseUrl}/api/status`;
const response = await fetch(url);
if (response.status === 200) {
return await response.json();
} else {
throw new Error(`API Error ${response.status}`);
}
}
/**
* Batch generate images
*/
async batchGenerate(prompts, commonParams = {}, webhookUrl = null) {
const url = `${this.baseUrl}/api/batch/generate`;
const batch = prompts.slice(0, 10).map(prompt => ({
prompt,
...commonParams
}));
const data = { batch };
if (webhookUrl) data.webhook_url = webhookUrl;
const response = await fetch(url, {
method: 'POST',
headers: {
'X-API-Key': this.apiKey,
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
if (response.status === 201) {
return await response.json();
} else {
const error = await response.json();
throw new Error(`API Error ${response.status}: ${error.error}`);
}
}
/**
* Wait for image generation to complete
*/
async waitForImage(imageId, timeout = 120000) {
const startTime = Date.now();
while (Date.now() - startTime < timeout) {
const image = await this.getImage(imageId);
if (image.status === 'completed') {
return image;
} else if (image.status === 'failed') {
throw new Error(`Generation failed: ${image.error_message}`);
}
await new Promise(resolve => setTimeout(resolve, 2000));
}
throw new Error(`Generation timeout after ${timeout}ms`);
}
}
// Example usage
(async () => {
// Initialize SDK
const sdk = new FluxAPISDK('your-api-key');
try {
// Check API status
const status = await sdk.checkApiStatus();
console.log(`API Status: ${status.status}`);
// Generate an image
const image = await sdk.generate({
prompt: 'beautiful sunset over mountains, professional photography',
width: 1024,
height: 1024,
steps: 30,
model: 'flux-dev'
});
console.log(`Generated image: ${image.url}`);
// Upscale the image
const upscaled = await sdk.upscale(image.id, { scale: 2 });
console.log(`Upscaled image: ${upscaled.url}`);
// Get user statistics
const stats = await sdk.getUserStats();
console.log(`Remaining generations: ${stats.quota.remaining_generations}`);
// List available LoRA models
const loras = await sdk.getLoras();
loras.forEach(lora => {
console.log(`LoRA: ${lora.name} (${lora.id})`);
});
} catch (error) {
console.error(`Error: ${error.message}`);
}
})();
// Export for use in other modules
if (typeof module !== 'undefined' && module.exports) {
module.exports = FluxAPISDK;
}
<?php
/**
* FLUX API SDK for PHP
* Complete integration example
*/
class FluxAPISDK {
private $apiKey;
private $baseUrl;
public function __construct($apiKey, $baseUrl = 'https://image.nalitek.com') {
$this->apiKey = $apiKey;
$this->baseUrl = $baseUrl;
}
/**
* Generate an image from text prompt
*/
public function generate($options = []) {
$url = $this->baseUrl . '/api/generate';
$data = array_merge([
'prompt' => '',
'negative_prompt' => '',
'width' => 1024,
'height' => 1024,
'steps' => 30,
'guidance_scale' => 7.5,
'seed' => -1,
'model' => 'flux-dev',
'format' => 'png'
], $options);
$response = $this->makeRequest('POST', $url, $data);
if ($response['status'] === 201) {
$result = $response['data'];
if (!isset($options['wait_for_completion']) || $options['wait_for_completion']) {
return $this->waitForImage($result['image_id']);
}
return $result;
} else {
throw new Exception("API Error {$response['status']}: {$response['data']['error']}");
}
}
/**
* Transform an existing image
*/
public function img2img($imagePath, $options = []) {
$url = $this->baseUrl . '/api/img2img';
$cFile = new CURLFile($imagePath, mime_content_type($imagePath), basename($imagePath));
$data = array_merge([
'image' => $cFile,
'prompt' => '',
'negative_prompt' => '',
'strength' => 0.75,
'steps' => 30,
'guidance_scale' => 7.5,
'seed' => -1
], $options);
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-API-Key: ' . $this->apiKey]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$responseData = json_decode($response, true);
if ($httpCode === 201) {
if (!isset($options['wait_for_completion']) || $options['wait_for_completion']) {
if (isset($responseData['image_id'])) {
return $this->waitForImage($responseData['image_id']);
}
}
return $responseData;
} else {
throw new Exception("API Error $httpCode: {$responseData['error']}");
}
}
/**
* Upscale an image
*/
public function upscale($imageId, $options = []) {
$url = $this->baseUrl . "/api/upscale/$imageId";
$data = array_merge([
'scale' => 2,
'face_enhance' => false,
'denoise' => 0.5
], $options);
$response = $this->makeRequest('POST', $url, $data);
if ($response['status'] === 201) {
return $response['data'];
} else {
throw new Exception("API Error {$response['status']}: {$response['data']['error']}");
}
}
/**
* Get image details
*/
public function getImage($imageId) {
$url = $this->baseUrl . "/api/images/$imageId";
$response = $this->makeRequest('GET', $url);
if ($response['status'] === 200) {
return $response['data'];
} else {
throw new Exception("API Error {$response['status']}: {$response['data']['error']}");
}
}
/**
* List images with filters
*/
public function listImages($options = []) {
$url = $this->baseUrl . '/api/images';
$params = array_merge([
'page' => 1,
'per_page' => 20,
'sort' => 'date_desc'
], $options);
$url .= '?' . http_build_query($params);
$response = $this->makeRequest('GET', $url);
if ($response['status'] === 200) {
return $response['data'];
} else {
throw new Exception("API Error {$response['status']}: {$response['data']['error']}");
}
}
/**
* Delete an image
*/
public function deleteImage($imageId) {
$url = $this->baseUrl . "/api/images/$imageId";
$response = $this->makeRequest('DELETE', $url);
return $response['status'] === 204;
}
/**
* Get available LoRA models
*/
public function getLoras() {
$url = $this->baseUrl . '/api/loras';
$response = $this->makeRequest('GET', $url);
if ($response['status'] === 200) {
return $response['data']['loras'];
} else {
throw new Exception("API Error {$response['status']}: {$response['data']['error']}");
}
}
/**
* Get user statistics
*/
public function getUserStats() {
$url = $this->baseUrl . '/api/user/stats';
$response = $this->makeRequest('GET', $url);
if ($response['status'] === 200) {
return $response['data'];
} else {
throw new Exception("API Error {$response['status']}: {$response['data']['error']}");
}
}
/**
* Check API status
*/
public function checkApiStatus() {
$url = $this->baseUrl . '/api/status';
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode === 200) {
return json_decode($response, true);
} else {
throw new Exception("API Error $httpCode");
}
}
/**
* Batch generate images
*/
public function batchGenerate($prompts, $commonParams = [], $webhookUrl = null) {
$url = $this->baseUrl . '/api/batch/generate';
$batch = [];
foreach (array_slice($prompts, 0, 10) as $prompt) {
$item = array_merge(['prompt' => $prompt], $commonParams);
$batch[] = $item;
}
$data = ['batch' => $batch];
if ($webhookUrl) {
$data['webhook_url'] = $webhookUrl;
}
$response = $this->makeRequest('POST', $url, $data);
if ($response['status'] === 201) {
return $response['data'];
} else {
throw new Exception("API Error {$response['status']}: {$response['data']['error']}");
}
}
/**
* Wait for image generation to complete
*/
private function waitForImage($imageId, $timeout = 120) {
$startTime = time();
while (time() - $startTime < $timeout) {
$image = $this->getImage($imageId);
if ($image['status'] === 'completed') {
return $image;
} elseif ($image['status'] === 'failed') {
throw new Exception("Generation failed: " . $image['error_message']);
}
sleep(2);
}
throw new Exception("Generation timeout after $timeout seconds");
}
/**
* Make HTTP request
*/
private function makeRequest($method, $url, $data = null) {
$ch = curl_init($url);
if ($method === 'POST') {
curl_setopt($ch, CURLOPT_POST, true);
if ($data) {
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
}
} elseif ($method === 'DELETE') {
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
} elseif ($method === 'PUT') {
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
if ($data) {
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
}
}
$headers = ['X-API-Key: ' . $this->apiKey];
if ($method !== 'GET' && $method !== 'DELETE') {
$headers[] = 'Content-Type: application/json';
}
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
return [
'status' => $httpCode,
'data' => json_decode($response, true)
];
}
}
// Example usage
try {
// Initialize SDK
$sdk = new FluxAPISDK('your-api-key');
// Check API status
$status = $sdk->checkApiStatus();
echo "API Status: {$status['status']}\n";
// Generate an image
$image = $sdk->generate([
'prompt' => 'beautiful sunset over mountains, professional photography',
'width' => 1024,
'height' => 1024,
'steps' => 30,
'model' => 'flux-dev'
]);
echo "Generated image: {$image['url']}\n";
// Upscale the image
$upscaled = $sdk->upscale($image['id'], ['scale' => 2]);
echo "Upscaled image: {$upscaled['url']}\n";
// Get user statistics
$stats = $sdk->getUserStats();
echo "Remaining generations: {$stats['quota']['remaining_generations']}\n";
// List available LoRA models
$loras = $sdk->getLoras();
foreach ($loras as $lora) {
echo "LoRA: {$lora['name']} ({$lora['id']})\n";
}
} catch (Exception $e) {
echo "Error: " . $e->getMessage() . "\n";
}