DEV Community

Cover image for NSFW Image Moderation on Discord: Creating Your Own Bot from Scratch
Tarana Murtuzova for API4AI

Posted on

NSFW Image Moderation on Discord: Creating Your Own Bot from Scratch

Introduction

Discord has become one of the leading communication platforms for gamers, communities, and teams around the globe. Thanks to its intuitive interface and extensive customization options, it's no surprise that millions of users turn to Discord for both casual and professional interactions. However, like any large online community, it is crucial to maintain a safe and respectful environment. This is where moderation becomes essential.

Moderation is key to promoting a positive community experience. It helps prevent inappropriate content, such as NSFW (Not Safe For Work) images, from disrupting the server's harmony. NSFW content, which includes explicit or offensive images, can not only degrade the community's atmosphere but also breach Discord’s terms of service. Therefore, it is vital for server administrators and moderators to implement effective moderation tools.

This guide aims to offer a detailed tutorial for creating a Discord bot specifically tailored for NSFW image moderation. By the end of this guide, you will have a fully operational bot capable of detecting and managing NSFW images, ensuring your server remains a safe and welcoming space for all members.

Who This Guide Is For

This guide is designed for:

Server Admins and Moderators: If you manage a Discord server and aim to improve its moderation capabilities, this guide will provide you with the essential tools to do so effectively.

Developers Interested in Building Moderation Tools: Whether you're an experienced developer or looking to improve your skills in bot development, this guide offers valuable insights and practical steps to create a robust NSFW image moderation bot.

Prerequisites

Before you start creating the bot, ensure you meet the following prerequisites for a smooth experience:

Basic Understanding of Python Programming: This guide assumes you have a basic understanding of Python, including familiarity with functions, loops, and library management.

Knowledge of Using Discord: You should be comfortable navigating Discord, including understanding server roles, permissions, and basic server management.

Necessary Tools

  • Python: Make sure you have Python installed on your computer. This guide will include instructions for setting up the development environment.
  • Discord Account: You will need a Discord account to create and manage your bot.
  • API Access: We will use third-party APIs for image moderation. Part of the process will involve signing up for API access and obtaining the necessary keys.

With these prerequisites in place, you'll be well-prepared to follow along and create an effective Discord bot for moderating NSFW images. Let's get started!

Basic Bot Setup

Creating a New Discord Application

To begin creating your Discord bot for NSFW image moderation, you need to set up a new application on the Discord Developer Portal. This application will provide you with the credentials required to connect your bot to Discord and manage its interactions. Follow these steps to create your new Discord application:

Log in to the Discord Developer Portal:

  • Open your web browser and navigate to the Discord Developer Portal.
  • Log in using your Discord account credentials. If you don’t have an account, you will need to create one.

Create a New Application:

  • Once logged in, you’ll be directed to a dashboard displaying a list of your applications (if any). Click on the "New Application" button located at the top right corner of the screen.
  • A pop-up window will appear, asking you to enter a name for your application. Choose a name that reflects your bot's purpose (e.g., "NSFW Image Moderator Bot") and click "Create".

discord

Configure Your Application

  • After setting up the application, you’ll be taken to the application's settings page where you can configure various details.
  • In the left-hand sidebar, click on "Bot" to access the bot settings.
  • Enable the 'Message Content Intent' option.

Image description

Retrieve Your Bot Token

  • After creating your bot, locate the "Token" section under the bot settings. Click the "Copy" button to save your bot token. This token is crucial for authenticating your bot and enabling it to interact with the Discord API.
  • Important: Keep your bot token secure and never share it publicly. If your token is exposed, anyone can control your bot.

Set Bot Permissions

  • Scroll down to the "OAuth2" section in the left sidebar and click on it.
  • In the "OAuth2 URL Generator" section, select the "bot" scope under "SCOPES".

Image description

  • Under "BOT PERMISSIONS", select the permissions your bot will need. For an NSFW image moderation bot, you’ll typically need the following permissions: Read Messages, Manage Messages.

Image description

  • Copy the generated URL under the "OAuth2 URL Generator" section.

Invite Your Bot to Your Server

  • Paste the copied URL into your web browser's address bar and press Enter.
  • You will be taken to a page where you can select the server you wish to invite your bot to. Choose the appropriate server and click "Authorize". You might need to complete a CAPTCHA to confirm.

With your Discord application configured and your bot added to your server, you’re ready to proceed to the next step: writing the bot script. This initial setup ensures that your bot is authenticated and has the required permissions to effectively moderate NSFW images.

Creating the Bot Script

With your Discord application configured and your bot invited to your server, it's time to develop the bot script. This script will enable your bot to connect to Discord and interact with your server.

We will use Python for this development, and you can choose any code editor you prefer. Python is a versatile and widely-used programming language, making it an excellent choice for creating a Discord bot.

Let’s start by writing a simple echo bot (code provided below) to ensure the bot can receive messages from your Discord server and respond to them. An echo bot is a basic bot that repeats any message it receives, making it an excellent way to verify that our bot is properly set up and communicating with the server.

import discord

class MyClient(discord.Client):
    ## Triggered when the bot is launched and ready.
    async def on_ready(self):
        print(f'We have logged in as {self.user}')

    ## Triggered when a user sends a message.
    async def on_message(self, msg):
        if msg.author == self.user:
            return
        await msg.channel.send(msg.content)

bot_token = 'YOUR_BOT_TOKEN' # Use yours that you saved before.
intents = discord.Intents.default()
intents.messages = True
intents.message_content = True

client = MyClient(intents=intents)
client.run(bot_token)
Enter fullscreen mode Exit fullscreen mode

After running this script, you should see the following message: 'We have logged in as NSFW Image Moderator Bot'.

Integrating Image Moderation

Choosing an Image Moderation API

For effective NSFW image moderation, we will utilize the API4AI NSFW Recognition API. This API provides several advantages:

  • High Accuracy: Utilizes advanced machine learning models to ensure precise detection of NSFW content.
  • Ease of Use: Features simple and intuitive API endpoints, making it straightforward to integrate into your application.
  • Scalability: Efficiently handles large volumes of requests, making it ideal for expanding communities.
  • Affordable Pricing: Offers cost-effective plans to accommodate various needs and budgets.

Understanding API4AI NSFW Recognition API

This API analyzes images to identify and categorize sexual content, marking them as either Safe For Work (SFW) or Not Safe For Work (NSFW). It also provides a confidence percentage for each category. The NSFW tag can detect various types of inappropriate content, including explicit material such as porn, hentai, or milder but still explicit content that may not be suitable for work or public viewing. For detailed integration options, refer to the documentation.

A comprehensive solution is available via subscription on the Rapid API platform. You can also test it through the demo at https://demo.api4ai.cloud. To see it in action, run the following command in the Terminal:

$ curl -X "POST" \
    "https://demo.api4ai.cloud/nsfw/v1/results" \
    -F "url=https://storage.googleapis.com/api4ai-static/samples/nsfw-1.jpg"
Enter fullscreen mode Exit fullscreen mode

Function for Checking a Photo with NSFW API

To integrate the API into our bot, let’s start with a function that sends images to the API and processes the response. Here’s a sample function:

import argparse
import asyncio

import discord
import requests
from requests.adapters import HTTPAdapter, Retry

API_URL = 'https://nsfw3.p.rapidapi.com'

NSFW_THRESHOLD = 0.8

async def is_nsfw_photo(img_url: str, nsfw_token: str):
    url = API_URL + '/v1/results'

    # We strongly recommend you use exponential backoff.
    error_statuses = (408, 409, 429, 500, 502, 503, 504)
    session = requests.Session()
    retries = Retry(backoff_factor=1.5, status_forcelist=error_statuses)
    session.mount('https://', HTTPAdapter(max_retries=retries))

    api_res = session.post(url, data={'url': img_url},
                           headers={'X-RapidAPI-Key': nsfw_token}, timeout=20)
    api_res_json = api_res.json()

    if (api_res.status_code != 200 or
            api_res_json['results'][0]['status']['code'] == 'failure'):
        raise RuntimeError('Image cannot be processed.')

    return api_res_json['results'][0]['entities'][0]['classes']['nsfw'] >= NSFW_THRESHOLD  # noqa
Enter fullscreen mode Exit fullscreen mode

Please note that the function is declared as async, as it will allow you to send several photos from the message at once for processing.

Making a Bot Class

Next, we’ll create a bot class that integrates the NSFW checking function. This class will handle connecting to Discord, processing messages, and reacting to NSFW content.

class ModerationBot(discord.Client):
    def __init__(self, *args, nsfw_token: str = None, **kwargs):
        discord.Client.__init__(self, *args, **kwargs)
        self.nsfw_token = nsfw_token

    async def on_ready(self):
        print(f'We have logged in as {self.user}')

    async def on_message(self, message: discord.Message):
        if message.author == self.user:
            return

        photos = [a for a in message.attachments
                  if a.content_type in ('image/jpeg', 'image/png')]

        tasks = [is_nsfw_photo(photo.url, self.nsfw_token) for photo in photos]
        results = await asyncio.gather(*tasks)
        if any(results):
            await asyncio.gather(
                message.author.send(f'You not allowed to send NSFW content to {message.channel.jump_url}.'),
                message.delete()
            )
Enter fullscreen mode Exit fullscreen mode

This part is necessary to ensure that the bot does not react to its own messages:

if message.author == self.user:
    return
Enter fullscreen mode Exit fullscreen mode

Users can send various types of attachments, including videos, photos, and voice messages. That's why we have to distinguish photos from the rest of the attachments:

photos = [a for a in message.attachments
          if a.content_type in ('image/jpeg', 'image/png')]
Enter fullscreen mode Exit fullscreen mode

Most of the time, when the script sends a request, it is idling. That's why we made is_nsfw_photo async. Use asyncio.gather() to call is_nsfw_photo asynchronously.

tasks = [is_nsfw_photo(photo.url, self.nsfw_token) for photo in photos]
results = await asyncio.gather(*tasks)
Enter fullscreen mode Exit fullscreen mode

If any photo in the message is NSFW, delete it and send a warning to the user. Here, too, it is better to use asyncio.gather() to avoid idling.

if any(results):
    await asyncio.gather(
        message.author.send(f'You not allowed to send NSFW content to {message.channel.jump_url}.'),
        message.delete()
    )
Enter fullscreen mode Exit fullscreen mode

Parsing Arguments and Implementing the Main Function

To enhance flexibility and security, we will parse the Discord bot token from the command line arguments. This method prevents the token from being hard-coded into the script, allowing it to be supplied at runtime. This approach simplifies managing different environments and configurations. We will use a command line argument parsing library to ensure the token is accurately retrieved and utilized to authenticate the bot.

def parse_args():
    parser = argparse.ArgumentParser()
    parser.add_argument('--discord-token',
                        help='Discord bot token. Go to '
                             'https://discord.com/developers/applications'
                             ' for token.',
                        required=True)
    parser.add_argument('--api-token',
                        help='NSFW API token.',
                        required=True)  # Get your API key at RapidAPI # noqa 
    return parser.parse_args()
Enter fullscreen mode Exit fullscreen mode

The final step is to run the bot with the required permissions to read message content and manage messages on servers (guilds). These permissions are essential for the bot to operate correctly, enabling it to read messages, detect NSFW content, and take appropriate actions, such as deleting the content or notifying users. Make sure the bot has been granted these permissions in the Discord Developer Portal before starting it.

def main():
    """Program entry point."""
    args = parse_args()

    intents = discord.Intents.default()
    intents.guild_messages = True
    intents.message_content = True

    client = ModerationBot(intents=intents, nsfw_token=args.api_token)
    client.run(args.discord_token)

if __name__ == '__main__':
    main()
Enter fullscreen mode Exit fullscreen mode

The Completed Python Code

That's all! Below is the full Python script for your NSFW Image Moderation bot. This code contains all essential elements, including parsing the Discord bot token from command line arguments, configuring the bot with the necessary permissions to read and manage message content, and implementing asynchronous functions to handle image moderation. Follow these steps and modify the code as needed to integrate it into your server.

"""
NSFW photo moderation bot for Discord.

Discord bot for moderating NSFW images on a server.

How to launch:
`pip install discord.py requests`
`python3 main.py --discord-token <BOT TOKEN> --api-token <NSFW API TOKEN>`
"""

import argparse
import asyncio

import discord
import requests
from urllib3 import Retry
from requests.adapters import HTTPAdapter


API_URL = 'https://nsfw3.p.rapidapi.com'

NSFW_THRESHOLD = 0.8


async def is_nsfw_photo(img_url: str, nsfw_token: str):
    """
    Check if a photo is Not Safe For Work.

    API4AI is used for checking.
    Learn more at https://api4.ai/apis/nsfw

    Parameters
    ----------
    img_url : str
    nsfw_token : str
    """
    url = API_URL + '/v1/results'

    # We strongly recommend you use exponential backoff.
    error_statuses = (408, 409, 429, 500, 502, 503, 504)
    session = requests.Session()
    retries = Retry(backoff_factor=1.5, status_forcelist=error_statuses)
    session.mount('https://', HTTPAdapter(max_retries=retries))

    api_res = session.post(url, data={'url': img_url},
                           headers={'X-RapidAPI-Key': nsfw_token}, timeout=20)
    api_res_json = api_res.json()

    if (api_res.status_code != 200 or
            api_res_json['results'][0]['status']['code'] == 'failure'):
        raise RuntimeError('Image cannot be processed.')

    return api_res_json['results'][0]['entities'][0]['classes']['nsfw'] >= NSFW_THRESHOLD  # noqa


class ModerationBot(discord.Client):
    """
    Discord py client implementing event handlers.

    Official documentation: https://discordpy.readthedocs.io/en/stable
    """

    def __init__(self, *args, nsfw_token: str = None, **kwargs):
        """
        Client init function. Pass your NSFW API token here.

        Learn discord.Client arguments at
        https://discordpy.readthedocs.io/en/stable/api.html#discord.Client

        Parameters
        ----------
        args: tuple
            discord.Client arguments
        nsfw_token: str
        kwargs: dict
            discord.Client arguments
        """
        discord.Client.__init__(self, *args, **kwargs)
        self.nsfw_token = nsfw_token

    async def on_ready(self):
        """
        Print when the bot is ready.

        Also, it will be online on your server.
        """
        print(f'We have logged in as {self.user}')

    async def on_message(self, message: discord.Message):
        """
        Handle the on_message event.

        Test all images in a message if there are any NSFW photos.
        Checks only jpeg and png images.

        Parameters
        ----------
        message : discord.Message
            sent by a user on a server.
        """
        # Do not handle the bot's own message.
        if message.author == self.user:
            return

        # In Discord, images, voice messages, videos, and others are attachments.
        photos = [a for a in message.attachments
                  if a.content_type in ('image/jpeg', 'image/png')]

        tasks = [is_nsfw_photo(photo.url, self.nsfw_token) for photo in photos]
        results = await asyncio.gather(*tasks)
        if any(results):
            await asyncio.gather(
                message.author.send(f'You not allowed to send NSFW content to '
                                    f'{message.channel.jump_url}.'),
                message.delete()
            )


def parse_args():
    """Parse command line arguments."""
    parser = argparse.ArgumentParser()
    parser.add_argument('--discord-token',
                        help='Discord bot token. Go to '
                             'https://discord.com/developers/applications'
                             ' for token.',
                        required=True)
    parser.add_argument('--api-token',
                        help='NSFW API token.',
                        required=True)  # Get your API key at RapidAPI  # noqa
    return parser.parse_args()


def main():
    """Program entry point."""
    args = parse_args()

    intents = discord.Intents.default()
    intents.guild_messages = True
    intents.message_content = True

    client = ModerationBot(intents=intents, nsfw_token=args.api_token)
    client.run(args.discord_token)


if __name__ == '__main__':
    main()
Enter fullscreen mode Exit fullscreen mode

Conclusion

In this thorough guide, we have carefully detailed the process of creating a Discord bot tailored for NSFW (Not Safe For Work) image moderation. From setting up the initial development environment to incorporating advanced image moderation features, we have covered each step to ensure you can successfully deploy a bot that suits your community's needs.

Effective moderation is essential for managing any online community, as it helps maintain order and provides a positive experience for all members. By implementing a bot that automatically detects and removes NSFW images, you play a crucial role in maintaining a respectful and safe environment. This proactive approach not only enhances the user experience by preventing exposure to inappropriate content but also ensures compliance with Discord’s community guidelines. These measures foster a welcoming and inclusive community where members can interact freely without the concern of encountering offensive or harmful material.

To expand your knowledge of Discord bot development and explore more advanced moderation techniques, consider the following resources:

Discord.py Documentation:

  • The comprehensive documentation for the discord.py library is crucial for developing Discord bots.
  • Discord.py Documentation.

API4AI Documentation:

By delving into these resources, you can enhance your bot's capabilities, ensuring thorough and effective moderation. Continuous learning and adapting to new tools and techniques will help you manage your community more efficiently and maintain a welcoming space for everyone.

More about Image Processing Solutions

Top comments (0)