Обнаружение NSFW на изображениях
Модерация изображений Discuse оценивает загружаемые пользователями изображения на наличие откровенного контента. Отправляйте URL изображений на POST https://api.discuse.com/api/v2/check с включённым check_images, и API вернёт вероятности porn, sexual и neutral, а также флаг hit в объекте results.images.
Как работает обнаружение NSFW?
Модель компьютерного зрения Discuse возвращает три вероятности для каждого изображения; в сумме они стремятся к 1.0:
porn: вероятность того, что изображение является порнографическим.sexual: вероятность того, что изображение содержит сексуальный подтекст.neutral: вероятность того, что изображение безопасно.
Флаг hit показывает, что изображение превысило NSFW-пороги вашего проекта. Используйте сырые оценки, чтобы отличать явно откровенные изображения (автоблокировка) от пограничных случаев (проверка модератором).
Как проверить изображение?
Отправьте один или несколько URL изображений и включите проверку изображений с помощью check_images:
curl -X POST https://api.discuse.com/api/v2/check \
-H "Content-Type: application/json" \
-H "X-API-Key: YOUR_API_KEY" \
-d '{
"content": {
"image_urls": ["https://example.com/user-upload.jpg"]
},
"settings": {
"check_images": true
}
}'
Один запрос принимает до 10 URL изображений.
Формат ответа
{
"has_violations": true,
"cached": false,
"message": "NSFW content detected",
"results": {
"hits": true,
"images": {
"status": "ok",
"porn": 0.95,
"sexual": 0.85,
"neutral": 0.02,
"hit": true
}
},
"usage": {
"api_requests_used": 12,
"api_requests_limit": 2000,
"api_requests_remaining": 1988
}
}
Результат проверки изображения находится в results.images. processing_time_ms присутствует только в том случае, если измерение времени включено в настройках вашего проекта.
Проверка нескольких изображений
{
"content": {
"image_urls": [
"https://example.com/image1.jpg",
"https://example.com/image2.jpg",
"https://example.com/image3.jpg"
]
},
"settings": {
"check_images": true
}
}
Каждое просканированное изображение отдельно учитывается в вашей квоте на проверку изображений.
Как интерпретировать оценки?
porn, sexual и neutral — это вероятности от 0.0 до 1.0. Для откровенного изображения porn будет высоким, а neutral — низким; для безопасного изображения будет преобладать neutral.
function interpretImageResult(result) {
const img = result.results.images;
if (img.porn > 0.8) {
return 'block'; // automatically reject
} else if (img.porn > 0.5 || img.sexual > 0.7) {
return 'review'; // queue for human review
} else if (img.sexual > 0.5) {
return 'warn'; // allow with a content-warning label
} else {
return 'allow';
}
}
Вы также можете ориентироваться на флаг hit, который уже учитывает настройки threshold_images_porn и threshold_images_sexual вашего проекта.
Сценарии использования
Социальные платформы
Проверяйте фотографии профиля и изображения в публикациях до того, как они станут доступны пользователям:
async function handleImageUpload(imageUrl) {
const result = await checkImage(imageUrl);
const img = result.results.images;
if (img.porn > 0.7) {
throw new Error('This image violates our community guidelines');
}
if (img.sexual > 0.7) {
return { url: imageUrl, hasContentWarning: true };
}
return { url: imageUrl, hasContentWarning: false };
}
Маркетплейсы
Применяйте более строгий порог для изображений товаров:
def validate_product_image(image_url):
result = check_image(image_url)
img = result['results']['images']
if img['porn'] > 0.3 or img['sexual'] > 0.3:
return {'approved': False, 'reason': 'Image contains inappropriate content'}
return {'approved': True}
Рекомендации
Сканируйте до постоянного хранения
async function processUpload(file) {
const tempUrl = await uploadToTemp(file);
const result = await checkImage(tempUrl);
if (result.has_violations) {
await deleteTempFile(tempUrl);
throw new Error('Image rejected');
}
return await moveToPermanent(tempUrl);
}
Комбинируйте с модерацией текста
Один запрос может одновременно проверить изображение и подпись к нему:
{
"content": {
"text": "Check out this photo from my vacation!",
"image_urls": ["https://example.com/vacation.jpg"]
},
"settings": {
"check_sentiment": true,
"check_spam": true,
"check_images": true
}
}
Используйте кэшированные результаты
Кэшированные ответы не расходуют вашу квоту, поэтому повторный показ или повторная валидация уже просканированного изображения бесплатны. Флаг cached в ответе показывает, когда результат был получен из кэша.
Лимиты использования
| Тариф | Ежемесячные проверки изображений | Стоимость сверх лимита |
|---|---|---|
| Basic | 500 | Недоступно |
| Gold | 2,000 | $0.00075/проверка |
| Platinum | 5,000 | $0.00064/проверка (скидка 15%) |
| Ultimate | 10,000 | $0.00056/проверка (скидка 25%) |
Примеры интеграции
Node.js
const checkImage = async (imageUrl) => {
const response = await fetch('https://api.discuse.com/api/v2/check', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': process.env.DISCUSE_API_KEY
},
body: JSON.stringify({
content: { image_urls: [imageUrl] },
settings: { check_images: true }
})
});
return response.json();
};
Python
import os
import requests
def check_image(image_url):
response = requests.post(
'https://api.discuse.com/api/v2/check',
headers={
'Content-Type': 'application/json',
'X-API-Key': os.environ['DISCUSE_API_KEY']
},
json={
'content': {'image_urls': [image_url]},
'settings': {'check_images': True}
}
)
return response.json()
Дальнейшие шаги
- Анализ текста - добавьте оценку тональности и спама в тот же запрос
- Определение языка - определяйте язык контента и обеспечивайте соблюдение языковых правил
- Антивирусное сканирование файлов - проверяйте документы на наличие вредоносного ПО