AI-модерація контенту (зображення) в мобільних додатках
Зображення модерувати складніше тексту. Користувач намагається обійти фільтри: редагує фото, змінює розрізняльну здатність, додає наклейки поверх проблемного контенту. Надійна система — багаторівнева: клієнт, сервер, асинхронна перевірка, хеш-база відомого контенту.
Чому не можна покладатися тільки на одну перевірку
Хеш-порівняння PhotoDNA / CSAM добре для виявлення відомого контенту, але не нового. Окремо Vision API можна обійти легкою обробкою зображення. Потрібна комбінація.
Клієнтська перевірка: Vision Safe Search
На iOS VNClassifyImageRequest містить категорії типу explicit, але вони не дають достатньо точного сигналу. Найкращий on-device варіант — CoreML модель типу NudeNet-mobile (відкритий вихідний код, ~8 MB):
class LocalImageModerator {
private let model: NudeNetMobile
func check(_ image: CGImage) throws -> LocalModerationResult {
let resized = resize(image, to: CGSize(width: 320, height: 320))
let input = NudeNetInput(image: MLMultiArray(from: resized))
let output = try model.prediction(input: input)
// Класи: SAFE / EXPOSED_BREAST / EXPOSED_GENITALIA / etc.
let topClass = output.classLabels.max(by: { output.classProbability[$0]! < output.classProbability[$1]! })!
return LocalModerationResult(
isSafe: topClass == "SAFE",
confidence: output.classProbability[topClass]!
)
}
}
Час інференцу — 30–50 мс на iPhone 13. Застосуйте ЯК ПЕРЕД завантаженням на сервер: якщо клієнтська модель блокує — не витрачайте трафік та гроші на серверну перевірку.
Серверна модерація: AWS Rekognition
AWS Rekognition DetectModerationLabels — промисловий стандарт. Гарна точність, підтримка ієрархічних міток:
# Backend
import boto3
rekognition = boto3.client('rekognition', region_name='eu-west-1')
def moderate_image(s3_bucket: str, s3_key: str) -> ModerationResult:
response = rekognition.detect_moderation_labels(
Image={'S3Object': {'Bucket': s3_bucket, 'Name': s3_key}},
MinConfidence=60.0
)
labels = response['ModerationLabels']
top_level = [l for l in labels if not l.get('ParentName')]
blocked_categories = {'Explicit Nudity', 'Violence', 'Visually Disturbing'}
for label in top_level:
if label['Name'] in blocked_categories and label['Confidence'] > 80:
return ModerationResult(blocked=True, reason=label['Name'],
confidence=label['Confidence'])
return ModerationResult(blocked=False)
Ціна: ~$0,001 на зображення (1000 запитів = $1). Для додатків з активним UGC — істотна стаття витрат; оптимізуємо через клієнтський pre-check.
Google Cloud Vision Safe Search — альтернатива з аналогічною ціною. Повертає adult, violence, racy, spoof, medical як ймовірності від VERY_UNLIKELY до VERY_LIKELY.
PhotoDNA / Хеш-детекція CSAM
Для додатків з публічним UGC — юридична вимога в деяких юрисдикціях. Microsoft PhotoDNA SDK та аналогічні рішення — це перцептивний хешинг, стійкий до обрізання, масштабування та невеликого стиснення. Хеш порівнюється з базою відомого противоправного контенту (NCMEC Hash Database у США).
Інтеграція — звичайно через партнерство з NCMEC або Microsoft. Не відкритий вихідний код. Для російського ринку — IWF (Internet Watch Foundation) надає аналогічний сервіс.
Простий перцептивний хеш (pHash) для дедупліцирення — доступний через open-source:
// Android: pHash через dcperceptualhash
fun computePHash(bitmap: Bitmap): Long {
val scaled = Bitmap.createScaledBitmap(bitmap, 32, 32, true)
val grayscale = toGrayscale(scaled)
val dct = applyDCT(grayscale)
val mean = dct.average()
return dct.foldIndexed(0L) { i, acc, v -> if (v > mean) acc or (1L shl i) else acc }
}
// Hamming distance <= 10 = схожі зображення
fun hammingDistance(a: Long, b: Long): Int = java.lang.Long.bitCount(a xor b)
Асинхронна перевірка та ретроактивне видалення
Синхронна модерація при завантаженні — необхідна, але недостатньо. Додаємо асинхронний шар:
- Зображення пройшло синхронну перевірку → опубліковано
- Асинхронно: важча модель (GPT-4 Vision, дорогий endpoint Rekognition) перепроверяє
- Якщо флаг — контент помічений для перевірки або автовидалено
Для високозавантажених додатків — окрема очередь SQS/RabbitMQ для асинхронної модерації, worker-процеси.
UX при блокуванні
Користувач повинен зрозуміти, чому фото відхилено, та мати можливість обжалувати:
// iOS: показати екран з причиною та кнопкою аппеляції
struct ModerationRejectionView: View {
let reason: ModerationReason
var body: some View {
VStack {
Image(systemName: "exclamationmark.triangle")
Text("Фото не відповідає правилам спільноти")
Text(reason.userFriendlyDescription)
.foregroundStyle(.secondary)
Button("Обжалувати") { /* відкрити форму аппеляції */ }
Button("Вибрати інше фото") { /* dismiss */ }
}
}
}
Аппеляція — форма з текстовим полем, йде в систему тикетів для ручної модерації. Відповідаємо протягом 24–48 годин.
Часові рамки
Backend з Rekognition + клієнтський CoreML pre-check — 4–6 днів. Повна система з pHash, асинхронною перевіркою, аппеляціями та аналітикою — 3–4 тижні. Вартість залежить від обсягу контенту та вимог до точності.







