Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/infinitered/nsfwjs

NSFW detection on the client-side via TensorFlow.js
https://github.com/infinitered/nsfwjs

content-management javascript machine-learning machinelearning node-module nsfw-recognition tensorflow-js tensorflowjs

Last synced: 6 days ago
JSON representation

NSFW detection on the client-side via TensorFlow.js

Awesome Lists containing this project

README

        


NSFWJS Logo

Client-side indecent content checking

[![All Contributors](https://img.shields.io/badge/all_contributors-15-green.svg?style=flat-square)](#contributors)
[![CircleCI](https://dl.circleci.com/status-badge/img/gh/infinitered/nsfwjs/tree/master.svg?style=svg)](https://dl.circleci.com/status-badge/redirect/gh/infinitered/nsfwjs/tree/master)
[![Netlify Status](https://api.netlify.com/api/v1/badges/72d19dc0-d316-4f75-9904-a33d833ff628/deploy-status)](https://app.netlify.com/sites/nsfwjs/deploys)

A simple JavaScript library to help you quickly identify unseemly images; all in the client's browser. NSFWJS isn't perfect, but it's pretty accurate (~90% with small and ~93% with midsized model)... and it's getting more accurate all the time.

Why would this be useful? [Check out the announcement blog post](https://shift.infinite.red/avoid-nightmares-nsfw-js-ab7b176978b1).


demo example

## NOTE

If you're trying to access the Cloudfront hosted model and are running into an error, it's likely due to the fact that the model has been moved to a new location. Please take a look at our [Host your own model](#host-your-own-model) section. We will be returning the model after some hotlinkers have been dealt with.

## **Table of Contents**

- [QUICK: How to use the module](#quick-how-to-use-the-module)
- [Library API](#library-api)
- [`load` the model](#load-the-model)
- [Caching](#caching)
- [`classify` an image](#classify-an-image)
- [Production](#production)
- [Install](#install)
- [Host your own model](#host-your-own-model)
- [Run the Examples](#run-the-examples)
- [Tensorflow.js in the browser](#tensorflowjs-in-the-browser)
- [Browserify](#browserify)
- [React Native](#react-native)
- [Node JS App](#node-js-app)
- [NSFW Filter](#nsfw-filter)
- [Learn TensorFlow.js](#learn-tensorflowjs)
- [More!](#more)
- [Open Source](#open-source)
- [Need the experts? Hire Infinite Red for your next project](#need-the-experts-hire-infinite-red-for-your-next-project)
- [Contributors](#contributors)

The library categorizes image probabilities in the following 5 classes:

- `Drawing` - safe for work drawings (including anime)
- `Hentai` - hentai and pornographic drawings
- `Neutral` - safe for work neutral images
- `Porn` - pornographic images, sexual acts
- `Sexy` - sexually explicit images, not pornography

> _The demo is a continuous deployment source - Give it a go: http://nsfwjs.com_

## QUICK: How to use the module

With `async/await` support:

```js
import * as nsfwjs from "nsfwjs";

const img = document.getElementById("img");

// If you want to host models on your own or use different model from the ones available, see the section "Host your own model".
const model = await nsfwjs.load();

// Classify the image
const predictions = await model.classify(img);
console.log("Predictions: ", predictions);
```

Without `async/await` support:

```js
import * as nsfwjs from "nsfwjs";

const img = document.getElementById("img");

// If you want to host models on your own or use different model from the ones available, see the section "Host your own model".
nsfwjs
.load()
.then(function (model) {
// Classify the image
return model.classify(img);
})
.then(function (predictions) {
console.log("Predictions: ", predictions);
});
```

## Library API

### `load` the model

Before you can classify any image, you'll need to load the model.

```js
const model = nsfwjs.load(); // Default: "MobileNetV2"
```

You can use the optional first parameter to specify which model you want to use from the three that are bundled together. Defaults to: `"MobileNetV2"`. This supports tree-shaking on supported bundlers like Webpack, so you will only be loading the model you are using.

```js
const model = nsfwjs.load("MobileNetV2Mid"); // "MobileNetV2" | "MobileNetV2Mid" | "InceptionV3"
```

You can also use same parameter and load the model from your website/server, as explained in the [Host your own model](#host-your-own-model) section. Doing so could reduce the bundle size for loading the model by approximately 1.33 times (33%) since you can directly use the binary files instead of the base64 that are bundled with the package. i.e. The `"MobileNetV2"` model bundled into the package is 3.5MB instead of 2.6MB for hosted binary files. This would only make a difference if you are loading the model every time (without [Caching](#caching)) on the client-side browser since on the server-side, you'd only be loading the model once at the server start.

Model MobileNetV2 - [224x224](https://github.com/infinitered/nsfwjs/blob/master/models/mobilenet_v2/)

```js
const model = nsfwjs.load("/path/to/mobilenet_v2/");
```

If you're using a model that needs an image of dimension other than 224x224, you can pass the size in the options parameter.

Model MobileNetV2Mid - [Graph](https://github.com/infinitered/nsfwjs/tree/master/models/mobilenet_v2_mid)

```js
/* You may need to load this model with graph type */
const model = nsfwjs.load("/path/to/mobilenet_v2_mid/", { type: 'graph' });
```

If you're using a graph model, you cannot use the infer method, and you'll need to tell model load that you're dealing with a graph model in options.

Model InceptionV3 - [299x299](https://github.com/infinitered/nsfwjs/tree/master/models/inception_v3)

```js
const model = nsfwjs.load("/path/to/inception_v3/", { size: 299 });
```

### Caching

If you're using in the browser and you'd like to subsequently load from indexed db or local storage (NOTE: model size may be too large for local storage!) you can save the underlying model using the appropriate scheme and load from there.

```js
const initialLoad = await nsfwjs.load(
"/path/to/different/model/" /*, { ...options }*/
);
await initialLoad.model.save("indexeddb://exampleModel");
const model = await nsfwjs.load("indexeddb://exampleModel" /*, { ...options }*/);
```

**Parameters**

Initial Load:
1. URL or path to folder containing `model.json`.
2. Optional object with size or type property that your model expects.

Subsequent Load:
1. IndexedDB path.
2. Optional object with size or type property that your model expects.

**Returns**

- Ready to use NSFWJS model object

**Troubleshooting**

- On the tab where the model is being loaded, inspect element and navigate to the the "Application" tab. On the left pane under the "Storage" section, there is a subsection named "IndexedDB". Here you can view if the model is being saved.

### `classify` an image

This function can take any browser-based image elements (``, ``, ``) and returns an array of most likely predictions and their confidence levels.

```js
// Return top 3 guesses (instead of all 5)
const predictions = await model.classify(img, 3);
```

**Parameters**

- Tensor, Image data, Image element, video element, or canvas element to check
- Number of results to return (default all 5)

**Returns**

- Array of objects that contain `className` and `probability`. Array size is determined by the second parameter in the `classify` function.

## Production

Tensorflow.js offers two flags, `enableProdMode` and `enableDebugMode`. If you're going to use NSFWJS in production, be sure to enable prod mode before loading the NSFWJS model.

```js
import * as tf from "@tensorflow/tfjs";
import * as nsfwjs from "nsfwjs";
tf.enableProdMode();
//...
let model = await nsfwjs.load(`${urlToNSFWJSModel}`);
```

**NOTE:** Consider downloading and hosting the model yourself before moving to production as explained in the [Host your own model](#host-your-own-model) section. This could potentially improve the initial load time of the model. Furthermore, consider [Caching](#caching) the model, if you are using it in the browser.

## Install

NSFWJS is powered by TensorFlow.js as a peer dependency. If your project does not already have TFJS you'll need to add it.

```bash
# peer dependency
$ yarn add @tensorflow/tfjs
# install NSFWJS
$ yarn add nsfwjs
```

For script tags include all the bundles as shown [here](#browserify). Then simply access the nsfwjs global variable. This requires that you've already imported TensorFlow.js as well.

### Host your own model

The magic that powers NSFWJS is the [NSFW detection model](https://github.com/gantman/nsfw_model). By default, the models are bundled into this package. But you may want to host the models on your own server to reduce bundle size by loading them as raw binary files or to host your own custom model. If you want to host your own version of [the model files](https://github.com/infinitered/nsfwjs/tree/master/models), you can do so by following the steps below. You can then pass the relative URL to your hosted files in the `load` function along with the `options` if necessary.

Here is how to install the default model on a website:

1. Download the project by either downloading as zip or cloning `git clone https://github.com/infinitered/nsfwjs.git`. **_If downloading as zip does not work use cloning._**
2. Extract the `models` folder from the root of the project and drop it in the `public` directory of your web application to serve them as static files along side your website. (You can host it anywhere such as on a s3 bucket as long as you can access it via URL).
3. Retrieve the URL and put it into `nsfwjs.load()`. For example: `nsfwjs.load(https://yourwebsite.com/models/mobilenet_v2/model.json)`.

## Run the Examples

### Tensorflow.js in the browser

The demo that powers https://nsfwjs.com/ is available in the [`examples/nsfw_demo`](https://github.com/infinitered/nsfwjs/tree/master/examples/nsfw_demo) folder.

To run the demo, run `yarn prep` which will copy the latest code into the demo. After that's done, you can `cd` into the demo folder and run with `yarn start`.

### Browserify

A browserified version using nothing but promises and script tags is available in the [`minimal_demo`](https://github.com/infinitered/nsfwjs/tree/master/examples/minimal_demo) folder.

```js

```

You should host the `nsfwjs.min.js` file and all the model bundles that you want to use alongside your project, and reference them using the `src` attribute in the script tags.

### React Native

The [NSFWJS React Native app](https://github.com/infinitered/nsfwjs-mobile)
![React Native Demo](./_art/nsfwjs-mobile.jpg)

Loads a local copy of the model to reduce network load and utilizes TFJS-React-Native. [Blog Post](https://shift.infinite.red/nsfw-js-for-react-native-a37c9ba45fe9)

### Node JS App

Using NPM, you can also use the model on the server side.

```bash
$ npm install nsfwjs
$ npm install @tensorflow/tfjs-node
```

```javascript
const axios = require("axios"); //you can use any http client
const tf = require("@tensorflow/tfjs-node");
const nsfw = require("nsfwjs");
async function fn() {
const pic = await axios.get(`link-to-picture`, {
responseType: "arraybuffer",
});
const model = await nsfw.load(); // To load a local model, nsfw.load('file://./path/to/model/')
// Image must be in tf.tensor3d format
// you can convert image to tf.tensor3d with tf.node.decodeImage(Uint8Array,channels)
const image = await tf.node.decodeImage(pic.data, 3);
const predictions = await model.classify(image);
image.dispose(); // Tensor memory must be managed explicitly (it is not sufficient to let a tf.Tensor go out of scope for its memory to be released).
console.log(predictions);
}
fn();
```

Here is another full example of a [multipart/form-data POST using Express](examples/node_demo), supposing you are using JPG format.

```javascript
const express = require("express");
const multer = require("multer");
const jpeg = require("jpeg-js");

const tf = require("@tensorflow/tfjs-node");
const nsfw = require("nsfwjs");

const app = express();
const upload = multer();

let _model;

const convert = async (img) => {
// Decoded image in UInt8 Byte array
const image = await jpeg.decode(img, { useTArray: true });

const numChannels = 3;
const numPixels = image.width * image.height;
const values = new Int32Array(numPixels * numChannels);

for (let i = 0; i < numPixels; i++)
for (let c = 0; c < numChannels; ++c)
values[i * numChannels + c] = image.data[i * 4 + c];

return tf.tensor3d(values, [image.height, image.width, numChannels], "int32");
};

app.post("/nsfw", upload.single("image"), async (req, res) => {
if (!req.file) res.status(400).send("Missing image multipart/form-data");
else {
const image = await convert(req.file.buffer);
const predictions = await _model.classify(image);
image.dispose();
res.json(predictions);
}
});

const load_model = async () => {
_model = await nsfw.load();
};

// Keep the model in memory, make sure it's loaded only once
load_model().then(() => app.listen(8080));

// curl --request POST localhost:8080/nsfw --header 'Content-Type: multipart/form-data' --data-binary 'image=@/full/path/to/picture.jpg'
```

You can also use [`lovell/sharp`](https://github.com/lovell/sharp) for preprocessing tasks and more file formats.

### NSFW Filter

[**NSFW Filter**](https://github.com/navendu-pottekkat/nsfw-filter) is a web extension that uses NSFWJS for filtering out NSFW images from your browser.

It is currently available for Chrome and Firefox and is completely open-source.

Check out the project [here](https://github.com/navendu-pottekkat/nsfw-filter).

## Learn TensorFlow.js

Learn how to write your own library like NSFWJS with my O'Reilly book "Learning TensorFlow.js" available on [O'Reilly](https://learning.oreilly.com/library/view/learning-tensorflowjs/9781492090786/) and [Amazon](https://amzn.to/3dR3vpY).

[![Learning TensorFlow.js JavaScript Book Red](_art/red_mockup_top.jpg)](https://amzn.to/3dR3vpY)

## More!

An [FAQ](https://github.com/infinitered/nsfwjs/wiki/FAQ:-NSFW-JS) page is available.

More about NSFWJS and TensorFlow.js - https://youtu.be/uzQwmZwy3yw

The [model was trained in Keras over several days](https://medium.freecodecamp.org/how-to-set-up-nsfw-content-detection-with-machine-learning-229a9725829c) and 60+ Gigs of data. Be sure to [check out the model code](https://github.com/GantMan/nsfw_model) which was trained on data provided by [Alexander Kim's](https://github.com/alexkimxyz) [nsfw_data_scraper](https://github.com/alexkimxyz/nsfw_data_scraper).

### Open Source

NSFWJS, as open source, is free to use and always will be :heart:. It's MIT licensed, and we'll always do our best to help and quickly answer issues. If you'd like to get a hold of us, join our [community slack](http://community.infinite.red).

### Need the experts? Hire Infinite Red for your next project

If your project's calling for the experts in all things React Native, Infinite Red’s here to help! Our experienced team of software engineers have worked with companies like Microsoft, Zoom, and Mercari to bring even some of the most complex projects to life.

Whether it’s running a full project or training a team on React Native, we can help you solve your company’s toughest engineering challenges – and make it a great experience at the same time.
Ready to see how we can work together? [Send us a message](mailto:[email protected])

## Contributors

Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):



Gant Laborde
Gant Laborde

πŸ’¬ πŸ“ πŸ’» πŸ’‘ πŸ€” πŸš‡ πŸ‘€ ⚠️
Jamon Holmgren
Jamon Holmgren

πŸ“– πŸ€” πŸ’» πŸ–‹
Mazen Chami
Mazen Chami

πŸ“– πŸ’» πŸ‘€ ⚠️
Jeff Studenski
Jeff Studenski

🎨
Frank von Hoven III
Frank von Hoven III

πŸ“– πŸ€”
Sandesh Soni
Sandesh Soni

πŸ’»
Sean Nam
Sean Nam

πŸ“–


Gilbert Emerson
Gilbert Emerson

πŸ’»
Oleksandr Kozlov
Oleksandr Kozlov

πŸš‡ ⚠️ πŸ’»
Morgan
Morgan

πŸ’» πŸ€”
Michel Hua
Michel Hua

πŸ’» πŸ“–
Kevin VanGelder
Kevin VanGelder

πŸ’» πŸ“–
Jesse Nicholson
Jesse Nicholson

πŸ”£ πŸ€”
camhart
camhart

πŸ“–


Cameron Burkholder
Cameron Burkholder

🎨
qwertyforce
qwertyforce

πŸ“–
Yegor <3
Yegor <3

πŸ’» ⚠️
Navendu Pottekkat
Navendu Pottekkat

πŸ“–
Vladislav
Vladislav

πŸ’» πŸ“–
Nacht
Nacht

πŸ’»
kateinkim
kateinkim

πŸ’» πŸ“–


jan
jan

πŸ“–
Rohan Mukherjee
Rohan Mukherjee

πŸ’¬ πŸš‡ 🚧 πŸ’»
Hasitha Wickramasinghe
Hasitha Wickramasinghe

πŸ’» πŸ“– πŸ’‘ πŸ€” πŸš‡ ⚠️

This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!