패키지, 저장소 및 앱 카테고리 검색

패키지 상세v2.0.2

nsfw_detector_flutter

자산 없이 NSFW(업무에 부적합/노출/성인용) 콘텐츠를 감지하고 안전한 콘텐츠를 분류하는 Flutter 패키지입니다. 앱에 쉽게 NSFW 감지 기능을 통합할 수 있습니다.

AndroidiOS
30일 다운로드
3.9천
좋아요
16
Pub 점수
150

패키지 설치

flutter pub add nsfw_detector_flutter

패키지 개요

공개 정보를 바탕으로 생성한 선택 가이드입니다.

노출 또는 성인 콘텐츠와 같은 업무에 부적절한 내용(NSFW)을 탐지하는 플러터 패키지로, 추가 자산 없이 이미지를 안전 또는 위험으로 분류합니다. 앱 내에서 직접 이미지를 분석하기 위해 머신 러닝 모델을 활용하여 실시간 콘텐츠 모니터링을 가능하게 합니다. 사용자 업로드 미디어에 대한 자동화된 안전 검사를 필요로 하는 앱에 적합합니다. 이 패키지는 안드로이드 및 iOS 플랫폼을 모두 지원하며 간단한 pub 명령어를 통해 원활하게 통합됩니다.

사용 사례

  • 소셜 미디어 앱에서의 콘텐츠 모더레이션
  • 사용자 생성 이미지 필터링
  • 안전한 브라우징 기능
  • 자동 사진 검토 시스템
  • 부모 통제 애플리케이션

주요 기능

  • 실시간 NSFW 감지
  • 외부 자산이 필요하지 않습니다
  • 크로스 플랫폼 지원 (Android 및 iOS)
  • Flutter와의 간단한 통합
  • 경량 머신러닝 모델

적합한 대상

  • 소셜 플랫폼을 구축하는 개발자
  • 자동 콘텐츠 안전이 필요한 앱
  • 사용자 업로드 기능이 있는 모바일 앱
  • 개인정보 보호 중심 애플리케이션
  • AI 기반 모더레이션을 구현하는 팀

고려 사항

  • 정확도는 모델 훈련 데이터에 따라 달라집니다
  • 다양한 이미지 세트에서 테스트가 필요할 수 있습니다
  • 저사양 장치에 대한 성능 영향
  • 이미지 기반 탐지에 제한됨
  • 법적 준수 전용으로는 적합하지 않습니다

원본 README

연결된 소스 저장소의 README 원문 스냅샷입니다. 최신 내용은 저장소에서 확인하세요.

🙈 nsfw_detector_flutter

pub version pub points pub likes platform license GitHub issues

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
  • 🎯 Confidence score — raw NSFW/safe scores (0.0–1.0) + three-tier classification
  • ⚡ Background isolate — detectBytesInBackground() for UI-safe detection
  • 🖼️ Multiple input sources — File, bytes, XFile, URL, package:image Image
  • 🗂️ Batch processing — scan multiple images in one call
  • 🎮 GPU acceleration — optional GPU delegate with automatic CPU fallback
  • 🔄 Singleton support — share one detector instance across your app

📋 Requirements

Platform Minimum version
Android SDK 26+ (API level 26)
iOS Xcode with "Strip Linked Product" set to No
Flutter 3.10.0+
Dart 3.3.1+

🛠️ Installation

flutter pub add nsfw_detector_flutter

Then follow the platform setup steps below.

🚀 Quick Start

import 'package:nsfw_detector_flutter/nsfw_detector_flutter.dart';

// Initialize once (e.g., in main() or app startup)
await NsfwDetector.initialize();

// Detect from anywhere in your app
final result = await NsfwDetector.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 closes
NsfwDetector.disposeInstance();

📖 API Reference

Initialization
Singleton (recommended for most apps)
// Initialize once at startup — idempotent, safe to call multiple times
await NsfwDetector.initialize();                    // default threshold: 0.7
await NsfwDetector.initialize(threshold: 0.8);     // stricter threshold

// Check initialization state
print(NsfwDetector.isInitialized); // true

// Access the shared instance
final 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 = await NsfwDetector.load();
final detectorGpu = await NsfwDetector.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 file
final result = await detector.detectNSFWFromFile(File('/path/to/image.jpg'));

// From asset bytes
final data = await rootBundle.load('assets/photo.jpg');
final result = await detector.detectNSFWFromBytes(data.buffer.asUint8List());

// From image_picker / camera (XFile)
final pickedFile = await ImagePicker().pickImage(source: ImageSource.gallery);
if (pickedFile != null) {
  final result = await detector.detectNSFWFromXFile(pickedFile);
}

// From URL
final result = await detector.detectNSFWFromUrl(
  Uri.parse('https://example.com/photo.jpg'),
  timeout: const Duration(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 smooth
final result = await NsfwDetector.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 JSON
final 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) {
  case NsfwClassification.safe:
    // show content normally
  case NsfwClassification.questionable:
    // blur or prompt user
  case NsfwClassification.nsfw:
    // block content
}

Error Handling
try {
  final result = await detector.detectNSFWFromFile(imageFile);
} on NsfwDetectorException catch (e) {
  print(e.message);   // human-readable description
  print(e.cause);     // original underlying error
} on StateError catch (e) {
  // detector was closed, or concurrent inference attempted
  print(e.message);
} on ArgumentError catch (e) {
  // e.g. empty bytes, invalid threshold
  print(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

Enable ProGuard in android/app/build.gradle:

buildTypes {
    release {
        minifyEnabled true
        shrinkResources true
        proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
    }
}

iOS

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

See example/README.md for more details.


💳 License

This project is licensed under the MIT License — see the LICENSE file for details.

Model

The bundled model is derived from yahoo/open_nsfw via open_nsfw_android, licensed under the BSD 3-Clause License.

BSD 3-Clause License (Yahoo)
Copyright 2016, Yahoo Inc.

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. Redistributions in 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 Yahoo Inc. 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.

카테고리

의존성

의존성 목록 3 개

소스 저장소

이 패키지를 사용하는 프로젝트

아직 데이터가 없습니다.