Реализация AI-генерации изображений (Kandinsky) в мобильном приложении
Kandinsky — российская модель от Sber AI (КАНДИНСКИЙ 3.1 на момент написания). Основное практическое преимущество для продуктов, работающих с русскоязычной аудиторией: нативное понимание русских промптов без перевода. «Закат над берёзовым лесом» на Kandinsky работает так же, как на западных моделях работает то же на английском — без потерь при трансляции.
Доступные способы интеграции
Fusionbrain API (api.fusionbrain.ai) — официальный API от команды разработчиков Kandinsky. Бесплатный уровень, REST, относительно стабильный. Именно с ним работают большинство интеграций.
Replicate — Kandinsky 2.2 и 3 доступны как community models. Стабильный API, но может быть устаревшая версия модели.
HuggingFace Inference API — kandinsky-community/kandinsky-3. Для прототипов достаточно.
Для продакшена — Fusionbrain API с собственным бэкендом-прокси.
Fusionbrain API: особенности протокола
API использует двухэтапную модель: сначала создаёшь task, затем опрашиваешь статус.
class KandinskyService(private val apiKey: String, private val secretKey: String) {
// Шаг 1: получить ID модели
suspend fun getModelId(): String {
val response = httpClient.get("https://api-key.fusionbrain.ai/key/api/v1/models") {
header("X-Key", "Key $apiKey")
header("X-Secret", "Secret $secretKey")
}
val models = response.body<List<FusionBrainModel>>()
return models.first { it.name == "Kandinsky" }.id.toString()
}
// Шаг 2: создать задачу генерации
suspend fun createTask(modelId: String, prompt: String, width: Int = 1024, height: Int = 1024): String {
val params = JSONObject().apply {
put("type", "GENERATE")
put("numImages", 1)
put("width", width)
put("height", height)
put("generateParams", JSONObject().apply {
put("query", prompt)
})
}
// Multipart запрос
val requestBody = MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("model_id", modelId)
.addFormDataPart(
"params",
"params.json",
params.toString().toRequestBody("application/json".toMediaType())
)
.build()
val response = OkHttpClient().newCall(
Request.Builder()
.url("https://api-key.fusionbrain.ai/key/api/v1/text2image/run")
.header("X-Key", "Key $apiKey")
.header("X-Secret", "Secret $secretKey")
.post(requestBody)
.build()
).execute()
return JSONObject(response.body!!.string()).getString("uuid")
}
// Шаг 3: polling
suspend fun pollResult(taskUuid: String): Bitmap? {
repeat(30) {
delay(3000)
val response = OkHttpClient().newCall(
Request.Builder()
.url("https://api-key.fusionbrain.ai/key/api/v1/text2image/status/$taskUuid")
.header("X-Key", "Key $apiKey")
.header("X-Secret", "Secret $secretKey")
.get()
.build()
).execute()
val json = JSONObject(response.body!!.string())
if (json.getString("status") == "DONE") {
val images = json.getJSONArray("images")
val base64 = images.getString(0)
val bytes = Base64.decode(base64, Base64.DEFAULT)
return BitmapFactory.decodeByteArray(bytes, 0, bytes.size)
}
}
return null
}
}
Ответ приходит как base64-строка в поле images — не URL. Декодируешь в Bitmap / UIImage непосредственно на клиенте. Сохраняешь во внутреннее хранилище, если нужна история.
Параметры генерации
Kandinsky поддерживает:
-
width/height: от 256 до 1024, кратно 64. Оптимально: 768x768 или 1024x1024 -
style:DEFAULT,ANIME,PORTRAIT,NATURE,REALISTIC(доступность зависит от версии модели) -
negativePromptDecoder: негативный промпт — список того, чего не должно быть
val params = JSONObject().apply {
put("type", "GENERATE")
put("numImages", 1)
put("width", 768)
put("height", 1024)
put("style", "PORTRAIT")
put("generateParams", JSONObject().apply {
put("query", "портрет молодой женщины в русском традиционном костюме, детализированный, реализм")
})
put("negativePromptDecoder", "размытость, артефакты, деформация, текст, водяной знак")
}
Русский промпт vs английский
Kandinsky понимает русский без деградации качества. Но на практике для технических описаний (архитектура, механизмы) английский промпт даёт более точный результат — модель обучена на смешанном корпусе, и технические термины лучше представлены в английском. Для художественных, пейзажных, портретных сценариев — русский работает отлично.
Для максимального качества — промпт на обоих языках (если UI позволяет), Kandinsky обработает оба.
Интеграция через Replicate (альтернатива)
let replicateBody: [String: Any] = [
"version": "ai-forever/kandinsky-3:...",
"input": [
"prompt": prompt,
"negative_prompt": negativePrompt,
"num_steps": 50,
"guidance_scale": 4.0,
"scheduler": "DDPMScheduler",
"width": 1024,
"height": 1024
]
]
Replicate даёт более предсказуемое время ответа (8–20 сек), чем Fusionbrain в пиковые часы.
Типичные ошибки
FAIL статус без объяснений от Fusionbrain — обычно промпт нарушает content policy или слишком короткий (менее 3 слов). Минимальный промпт для стабильной работы — 5–10 слов описания.
Декодирование base64 на main thread — это блокировка UI. Всегда в фоновый поток: DispatchQueue.global().async (iOS) или Dispatchers.Default (Android).
Сроки
Базовая интеграция Fusionbrain API с UI — 3–4 дня. Стили, история генераций, сохранение в галерею, обработка ошибок content policy — 8–12 дней.







