图片 NSFW 检测
Discuse 图片审核会对用户提交的图片进行露骨内容评分。将图片 URL 发送到启用 check_images 的 POST https://api.discuse.com/api/v2/check,API 会返回 porn、sexual 和 neutral 概率,并在 results.images 对象中返回对应的 hit 标记。
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()