AI-генерация аватаров по фото: реализация в мобильном приложении
Наш типичный запрос: «Хочу, чтобы пользователь загрузил селфи и получил 10 стилизованных аватаров за 10 секунд». Звучит как стандартная задача, но на деле упирается в выбор модели (Stable Diffusion + LoRA против специализированных API), управление очередями, приемлемое время ожидания и работу с фото-разрешениями. Мы реализовали такие проекты под ключ — с нуля до App Store и Google Play. Оценим ваш проект, свяжитесь для консультации.
Почему не стоит генерировать аватары on-device?
Stable Diffusion 1.5 в FLOAT16 весит ~2.5 GB. Apple ML Stable Diffusion Swift package позволяет запустить его на iPhone 14 Pro — 20 шагов DDIM на 512×512 занимают около 8 секунд. Это на топовом устройстве. На iPhone 12 или среднебюджетном Android — нереально. Серверная генерация через специализированные сервисы — единственный разумный путь для продакшена.
| Сервис | Подход | Время | Качество |
|---|---|---|---|
| Replicate (SDXL + IP-Adapter) | REST API | 15–40 сек | Высокое |
| Fal.ai | REST + WebSocket | 5–15 сек | Высокое |
| Leonardo.ai | REST API | 10–30 сек | Очень высокое |
| Astria.ai | Fine-tune + генерация | 10–30 мин (fine-tune) + 15 сек | Максимальное |
Для аватаров «похожих на пользователя» лучший результат даёт IP-Adapter или InstantID — они сохраняют черты лица без полноценного fine-tune LoRA. Если нужна максимальная точность (как в Lensa App) — Dreambooth LoRA с 10–20 фото пользователя, но это займёт 10–20 минут обработки.
Как мы организуем асинхронный флоу на клиенте?
Генерация занимает время — пользователю нужен понятный feedback. Наш флоу на iOS с polling и экспоненциальной задержкой:
// iOS: запуск генерации и polling статуса
class AvatarGenerationService {
private let apiClient: APIClient
func generateAvatar(photo: UIImage, style: AvatarStyle) async throws -> [UIImage] {
// 1. Compress + upload photo
let photoData = photo.jpegData(compressionQuality: 0.85)!
let uploadURL = try await apiClient.uploadPhoto(data: photoData)
// 2. Start generation job
let jobId = try await apiClient.startGeneration(
photoURL: uploadURL,
style: style.rawValue,
count: 6
)
// 3. Poll with exponential backoff
return try await pollJobResult(jobId: jobId)
}
private func pollJobResult(jobId: String) async throws -> [UIImage] {
var delay: TimeInterval = 2.0
for _ in 0..<30 {
try await Task.sleep(nanoseconds: UInt64(delay * 1_000_000_000))
let status = try await apiClient.checkJob(id: jobId)
switch status.state {
case .completed: return try await downloadResults(urls: status.resultURLs)
case .failed: throw AvatarError.generationFailed(status.error)
case .pending, .processing: delay = min(delay * 1.5, 8.0)
}
}
throw AvatarError.timeout
}
}
На Android аналогично через Kotlin Coroutines + kotlinx.coroutines.delay. Мы гарантируем стабильную работу — наш опыт включает проекты с 5+ лет на рынке и более 50 успешных релизов.
Подготовка фото: что проверить перед отправкой?
Качество аватара напрямую зависит от входного фото. Мы выполняем валидацию на клиенте:
- Лицо детектировано (iOS:
VNDetectFaceRectanglesRequest, Android: ML KitFaceDetector) - Освещение приемлемое — проверяем среднее значение яркости через
CIAreaAverage - Разрешение минимум 512×512
- Одно лицо в кадре (если несколько — показываем предупреждение)
Фото компрессируем до 1024×1024 JPEG 85% перед отправкой — избыточное разрешение не улучшает результат, но увеличивает время загрузки и стоимость.
Как организовать кеширование и галерею результатов?
Сгенерированные аватары храним в FileManager с метаданными в Core Data (iOS) или Room (Android). Это позволяет не генерировать повторно при каждом открытии. Важный момент: если приложение уходит в бэкграунд во время генерации — polling прерывается. Мы решаем это сохранением jobId в UserDefaults / SharedPreferences и проверкой статуса незавершённых задач при следующем запуске.
Push-уведомление о готовности
Ждать 20–40 секунд с открытым приложением — неплохо. Но если пользователь свернул приложение — нужен push. Сервер отправляет FCM/APNs-уведомление после завершения генерации. На клиенте — UNNotificationAction с deep link в галерею аватаров.
Права и конфиденциальность
App Store Review (Section 5.1) требует декларировать сбор фотографий. Если фото уходит на сервер — это Photos data type, usage: App Functionality. В проекте мы обязательно:
- запрашиваем явное согласие пользователя
- храним исходное фото не дольше 24 часов и удаляем после генерации
- не передаём данные третьим сторонам для обучения без согласия
На Android с targetSdk 33+ запрашиваем READ_MEDIA_IMAGES вместо устаревшего READ_EXTERNAL_STORAGE. Наши инженеры имеют сертификаты и опыт публикации в обоих сторах — это гарантия соответствия гайдлайнам.
Что входит в работу?
- Анализ и выбор AI-провайдера под ваши задачи
- Разработка клиентского SDK: загрузка, валидация, polling, кеширование
- Серверная интеграция (REST/GraphQL) с очередями и push
- Тестирование на реальных устройствах (iOS 15+, Android 10+)
- Подготовка документации и сопровождение при публикации
Сроки и стоимость
Базовый флоу (загрузка фото, API вызов, polling, показ результатов) — 3–5 дней. С валидацией лица, галереей, push-уведомлениями и поддержкой нескольких стилей — 2–3 недели. Стоимость рассчитывается индивидуально и зависит от платформы (iOS/Android/оба) и выбранного AI-провайдера. Свяжитесь с нами — оценим ваш проект, ответим на вопросы.







