Software Development

Using NSFW Js Library with Node Js in Magento 2


What is NSFW Js library:-

NSFW Js is a JavaScript library to help you quickly identify inappropriate images, all within the client’s browser. NSFWJS isn’t perfect, but it’s pretty accurate (90% with small models and 93% with medium models) and it’s getting more accurate.

We can use NSFW JS to identify all types of images and prevent the uploading and use of vulgar images. Try the demo on its official website

Demo –

Here is the explanation of how we can use this library in Magento 2 with Node Js.

Looking for an experienced
Magento 2 business?
Learn more


# We will validate the image via a NSFW js library when we upload product images from admin side in Magento 2

First, I installed all required packages via npm install and my package.json looks like below.

{
  "dependencies": {
    "express": "^4.18.2",
    "jpeg-js": "^0.4.4",
    "multer": "^1.4.5-lts.1",
    "@tensorflow/tfjs-node": "^4.10.0",
    "nsfwjs": "^2.2.0",
  }
}

Next, we will create a server.js API node like below at the root of Magento.

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) => {
  const image = await jpeg.decode(img, 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 x = 0; x < numChannels; ++x) {
        values(i * numChannels + x) = image.data(i * 4 + x);
      }
  }
  
  return tf.tensor3d(values, (image.height, image.width, numChannels), 'int32');
  
}

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

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

load_model().then(() => app.listen(8080, 'localhost', () => {
  console.log('Server is running on port 8080');
}))

And we will run this API by running the command – node server.js

Now let’s create a preference for the product image upload controller by creating a di.xml file in the etc folder.

<?xml version="1.0"?>

<config xmlns:xsi=" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<preference for="Magento\Catalog\Controller\Adminhtml\Product\Gallery\Upload" type="Webkul\NodeWithMagento\Controller\Adminhtml\Product\Gallery\ImageValidation" />
</config>

Now we will create an ImageValidation controller file in the same location as mentioned above.

<?php

namespace Webkul\NodeWithMagento\Controller\Adminhtml\Product\Gallery;

use Magento\Backend\App\Action\Context;
use Magento\Catalog\Controller\Adminhtml\Product\Gallery\Upload as MagentoUpload;
use Magento\Framework\Filesystem\Driver\File as DriverFile;

class ImageValidation extends MagentoUpload
{
    /**
     * @var \Magento\Framework\Json\Helper\Data
     */
    protected $jsonHelper;

    /**
     * @var \Magento\Framework\Filesystem\Driver\File
     */
    protected $driverFile;

    /**
     * @var \Magento\Framework\HTTP\Client\Curl
     */
    protected $curl;

    /**
     * Constructor
     *
     * @param Context $context
     * @param \Magento\Framework\Controller\Result\RawFactory $resultRawFactory
     * @param \Magento\Framework\Image\AdapterFactory $adapterFactory
     * @param \Magento\Framework\Filesystem $filesystem
     * @param \Magento\Catalog\Model\Product\Media\Config $productMediaConfig
     * @param \Magento\Framework\Json\Helper\Data $jsonHelper
     * @param DriverFile $driverFile
     * @param \Magento\Framework\HTTP\Client\Curl $curl
     */
    public function __construct(
        Context $context,
        \Magento\Framework\Controller\Result\RawFactory $resultRawFactory,
        \Magento\Framework\Image\AdapterFactory $adapterFactory,
        \Magento\Framework\Filesystem $filesystem,
        \Magento\Catalog\Model\Product\Media\Config $productMediaConfig,
        \Magento\Framework\Json\Helper\Data $jsonHelper,
        DriverFile $driverFile,
        \Magento\Framework\HTTP\Client\Curl $curl
    ) {
        $this->jsonHelper = $jsonHelper;
        $this->driverFile = $driverFile;
        $this->curl = $curl;
        parent::__construct(
            $context,
            $resultRawFactory,
            $adapterFactory,
            $filesystem,
            $productMediaConfig
        );
    }

    /**
     * Upload image(s) to the product gallery.
     *
     * @return \Magento\Framework\Controller\Result\Raw
     */
    public function execute()
    {
        $imageFile = $this->getRequest()->getFiles('image');
        $isValidImage = $this->isValidImage($imageFile);
        
        if (!$isValidImage) {
            return $this->generateErrorResponse('Invalid image, It contain explict content');
        } else {
            return parent::execute();
        }
    }

    /**
     * Validate images
     *
     * @param array $imageFile
     * @return boolean
     */
    public function isValidImage($imageFile)
    {
        try {
            $url = $this->getApiUrl();
            $imageData = $this->driverFile->fileOpen($imageFile('tmp_name'), 'r');
            $boundary = '------------------------' . uniqid();

            $postData = (
                (
                    'name' => 'image',
                    'contents' => $imageData,
                    'filename' => $imageFile('name'),
                ),
            );

            $headers = (
                'Content-Type' => 'multipart/form-data; boundary=' . $boundary,
            );

            $this->curl->setHeaders($headers);

            $postDataFormatted = ();
            foreach ($postData as $item) {
                $postDataFormatted() = '--' . $boundary;
                $postDataFormatted() = 'Content-Disposition: form-data; name="' .
                $item('name') . '"; filename="' . $item('filename') . '"';
                $postDataFormatted() = 'Content-Type: application/octet-stream';
                $postDataFormatted() = '';
                // phpcs:ignore Magento2.Functions.DiscouragedFunction
                $postDataFormatted() = stream_get_contents($item('contents')); // To manage error in Api
            }

            $postDataFormatted() = '--' . $boundary . '--';

            $this->curl->post($url, implode("\r\n", $postDataFormatted));

            $response = $this->curl->getBody();

            $predictions = $this->jsonHelper->jsonDecode($response, true);

            $threshold = 0.5;
            if ($this->containsExplicitContent($predictions, $threshold)) {
                return false;
            }

            return true;
        
        } catch (\Exception $e) {
            return false;
        }
    }

    /**
     * Get Api Url
     *
     * @return string
     */
    public function getApiUrl()
    {
        // You can manage all the below field dynamically by system.xml
        $isHttps = "
        $host = "localhost"; 
        $port = 8080;
        $apiUrl = $isHttps.$host.':'.$port.'/nsfw';
        
        return $apiUrl;
    }

    /**
     * Validate Explicit Content
     *
     * @param array $predictions
     * @param float $threshold
     * @return boolean
     */
    public function containsExplicitContent($predictions, $threshold)
    {
        $explicitClasses = ('Porn', 'Sexy', 'Hentai');

        foreach ($predictions as $prediction) {
            if (in_array($prediction('className'), $explicitClasses) && $prediction('probability') >= $threshold) {
                return true; // Explicit content found
            }
        }
        return false;
    }

    /**
     * Generate error response for images
     *
     * @param string $errorMessage
     * @return \Magento\Framework\Controller\Result\Raw
     */
    public function generateErrorResponse($errorMessage)
    {
        $result = ('error' => __($errorMessage));
        $response = $this->resultRawFactory->create();
        $response->setHeader('Content-type', 'text/plain');
        $response->setContents($this->jsonHelper->jsonEncode($result));
        return $response;
    }

}

Now when we upload the product images through the node API, the images will validate the explicit content.

Screenshot-2023-09-14T195244.276

This is NSFW usage of node js in Magento 2. Hope this is helpful.

For basic usage of Node in Magento 2, visit the blog – Using node js with magento2

If you have any questions, please comment below and we will try to answer you.

Thanks for visiting the Webkul blog! 🙂



Source link

Related Articles

Leave a Reply

Your email address will not be published. Required fields are marked *

Back to top button