Um pacote Flutter para detectar conteúdo NSFW (não apropriado para o trabalho / nu / adulto) e classificar conteúdo seguro sem exigir ativos. Integre facilmente a detecção NSFW ao seu aplicativo.
Orientação gerada a partir de informações públicas. Apenas para referência.
Um pacote Flutter que detecta conteúdo NSFW (não seguro para o trabalho), como nudez ou material adulto, classificando imagens como seguras ou inseguras sem exigir ativos adicionais. Ele utiliza modelos de aprendizado de máquina para analisar imagens diretamente no aplicativo, permitindo moderação em tempo real. Ideal para aplicativos que precisam de verificações automáticas de segurança em mídias enviadas por usuários. O pacote suporta tanto plataformas Android quanto iOS e se integra perfeitamente por meio de um simples comando pub.
Casos de uso
Moderação de conteúdo em aplicativos de mídia social
filtro de imagem gerado pelo usuário
Recursos de navegação segura
Sistemas automatizados de revisão de fotos
Aplicativos de controle parental
Principais recursos
Detecção em tempo real de conteúdo impróprio
Nenhum ativo externo necessário
Suporte multiplataforma (Android e iOS)
Integração simples com o Flutter
Modelo de aprendizado de máquina leve
Indicado para
Desenvolvedores construindo plataformas sociais
Aplicativos que exigem segurança automatizada de conteúdo
Aplicativos móveis com uploads de usuários
Aplicativos focados na privacidade
Equipes que implementam moderação baseada em IA
Considerações
A precisão depende dos dados de treinamento do modelo
Pode ser necessário testar em conjuntos de imagens diversos
Impacto no desempenho em dispositivos de baixa potência
Limitado à detecção baseada em imagem
Não adequado para conformidade legal sozinho
README original
Snapshot do README original do repositório-fonte vinculado. Consulte o repositório para o conteúdo mais recente.
🙈 nsfw_detector_flutter
On-device NSFW image detection for Flutter — no internet, no server, no extra assets required. Powered by the Yahoo/open_nsfw TensorFlow Lite model.
✨ Features
🔒 100% on-device — no images ever leave the user's device
📦 Zero setup — model is bundled, no extra download needed
import'package:nsfw_detector_flutter/nsfw_detector_flutter.dart';
// Initialize once (e.g., in main() or app startup)awaitNsfwDetector.initialize();
// Detect from anywhere in your appfinal result = awaitNsfwDetector.instance.detectNSFWFromBytes(imageBytes);
if (result != null) {
print(result.isNsfw); // true / false (based on threshold)print(result.score); // 0.0–1.0 (NSFW probability)print(result.safeScore); // 0.0–1.0 (safe probability)print(result.classification); // NsfwClassification.safe / .questionable / .nsfw
}
// Release resources when the app closesNsfwDetector.disposeInstance();
📖 API Reference
Initialization
Singleton (recommended for most apps)
// Initialize once at startup — idempotent, safe to call multiple timesawaitNsfwDetector.initialize(); // default threshold: 0.7awaitNsfwDetector.initialize(threshold: 0.8); // stricter threshold// Check initialization stateprint(NsfwDetector.isInitialized); // true// Access the shared instancefinal detector = NsfwDetector.instance;
// Release when done (e.g., app lifecycle dispose)NsfwDetector.disposeInstance();
Direct instantiation
// Create your own instance (you manage its lifecycle)final detector = awaitNsfwDetector.load();
final detectorGpu = awaitNsfwDetector.load(useGpu: true); // GPU-accelerated// Always close when done to release native memory
detector.close();
Parameter
Type
Default
Description
threshold
double
0.7
Minimum NSFW score to classify as NSFW. Must be 0.0–1.0.
useGpu
bool
false
Use GPU delegate (Android/iOS). Falls back to CPU on failure.
Detection Methods
All methods return NsfwResult?. Returns null if the image could not be decoded (unsupported format). Throws NsfwDetectorException on infrastructure failures (file not found, network error, etc.).
Method
Input
Notes
detectNSFWFromBytes(Uint8List)
Raw image bytes
Supports JPEG, PNG, WebP, BMP, GIF
detectNSFWFromFile(File)
dart:io File
Async file read + decode
detectNSFWFromXFile(XFile)
package:cross_file XFile
Compatible with image_picker, camera
detectNSFWFromUrl(Uri)
HTTP/HTTPS URL
10s timeout, 32 MB limit, follows redirects
detectNSFWFromImage(img.Image)
package:image Image
Pre-decoded image
detectBatch(List<Uint8List>)
List of byte arrays
Sequential, returns List<NsfwResult?>
detectBytesInBackground(Uint8List)
Raw image bytes
Static. Runs in background isolate via compute()
Examples
import'dart:io';
import'package:cross_file/cross_file.dart';
final detector = NsfwDetector.instance;
// From filefinal result = await detector.detectNSFWFromFile(File('/path/to/image.jpg'));
// From asset bytesfinal data = await rootBundle.load('assets/photo.jpg');
final result = await detector.detectNSFWFromBytes(data.buffer.asUint8List());
// From image_picker / camera (XFile)final pickedFile = awaitImagePicker().pickImage(source: ImageSource.gallery);
if (pickedFile != null) {
final result = await detector.detectNSFWFromXFile(pickedFile);
}
// From URLfinal result = await detector.detectNSFWFromUrl(
Uri.parse('https://example.com/photo.jpg'),
timeout: constDuration(seconds: 10),
maxBytes: 32 * 1024 * 1024,
);
// Batch scan (e.g., gallery images before upload)final results = await detector.detectBatch([bytes1, bytes2, bytes3]);
// Background isolate — keeps UI thread smoothfinal result = awaitNsfwDetector.detectBytesInBackground(
imageBytes,
threshold: 0.7,
);
NsfwResult
final result = await detector.detectNSFWFromBytes(imageBytes);
result.isNsfw; // bool — true if score >= threshold
result.score; // double — NSFW probability (0.0–1.0)
result.safeScore; // double — safe probability (0.0–1.0); score + safeScore ≈ 1.0
result.classification; // NsfwClassification enum (see below)
result.toJson(); // Map<String, dynamic>
result.copyWith(score: 0.9); // NsfwResult with updated fields// Reconstruct from JSONfinal restored = NsfwResult.fromJson(json);
NsfwClassification
Three-tier classification based on the NSFW score:
Value
Score range
Meaning
NsfwClassification.safe
< 0.4
Clearly safe content
NsfwClassification.questionable
0.4 – 0.7
Borderline / suggestive content
NsfwClassification.nsfw
≥ 0.7
Likely NSFW content
switch (result.classification) {
caseNsfwClassification.safe:
// show content normallycaseNsfwClassification.questionable:
// blur or prompt usercaseNsfwClassification.nsfw:
// block content
}
Error Handling
try {
final result = await detector.detectNSFWFromFile(imageFile);
} onNsfwDetectorExceptioncatch (e) {
print(e.message); // human-readable descriptionprint(e.cause); // original underlying error
} onStateErrorcatch (e) {
// detector was closed, or concurrent inference attemptedprint(e.message);
} onArgumentErrorcatch (e) {
// e.g. empty bytes, invalid thresholdprint(e.message);
}
⚙️ Platform Setup
Android
1. Minimum SDK version
In android/app/build.gradle:
android {
defaultConfig {
minSdkVersion 26
}
}
2. ProGuard / R8 rules
Add to android/app/proguard-rules.pro:
# TensorFlow Lite GPU Delegate
-keep class org.tensorflow.lite.gpu.GpuDelegateFactory$Options { *; }
-dontwarn org.tensorflow.lite.gpu.GpuDelegateFactory$Options
In Xcode → Build Settings → Deployment → Strip Linked Product, set to No.
⚠️ Known Limitations
HEIC images (iOS)
HEIC is the default camera format on iOS, but the image package does not support it. Calling any detect method with a HEIC file will return null without throwing.
Workaround: Convert to JPEG before passing to the detector. With image_picker, use imageQuality parameter or configure preferredCameraDevice to capture in JPEG.
Concurrent inference
A single NsfwDetector instance does not support concurrent calls. Calling a detect method while another is already running throws a StateError. For concurrent use, create multiple instances or use detectBytesInBackground() which creates its own isolate-local instance.
App size
The bundled TFLite model adds ~22 MB to your APK/IPA. This is a one-time cost and does not require any network downloads at runtime.
🧪 Testing
Run integration tests on a physical device or emulator:
cd example
flutter drive \
--driver=test_driver/integration_test_driver.dart \
--target=integration_test/native_test.dart
Copyright2016, YahooInc.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributionsin binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of YahooInc. nor the names of its contributors may be
used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.