NSFW

부분 유료
Verified
분류별 API 4 AI | 업데이트됨 לפני חודש | Visual Recognition
인기

9.6 / 10

지연 시간

1,705ms

서비스 수준

100%

Health Check

100%

모든 자습서로 돌아가기 (2)

Making a NSFW moderation bot for Discord

Discord has emerged as a veritable titan among communication platforms, captivating not only gamers, but also diverse communities and businesses with its unmatched versatility.

Amidst this panoply of offerings, one particular facet stands out like a beacon, distinguishing Discord from its counterparts: the prodigious capacity to harness the power of bots.
These automated entities, when integrated into Discord servers, prove to be formidable assets, imbued with the ability to streamline and enhance the user experience.

A typical Discord server is a lively place where people interact. Sometimes, certain individuals break the rules and share inappropriate images, causing disagreements and conflicts.

The goal of our tutorial is to provide a solution so to solve this problem using a Discord moderation bot. This bot is a clever technology that helps address these challenges. By using the bot, server administrators can prevent the spread of inappropriate content automatically. This reduces the need for many human moderators and saves money spent on hiring them.

In summary, the Discord moderation bot is a helpful tool for server owners. It helps them maintain order and save money while protecting their communities.

Learning NSFW API

NSFW API is very easy to use.
Merely by sending a request and get a response with the probability that the photo possesses an adult or Not Safe For Work (NSFW) nature.

import requests
RAPIDAPI_KEY = ''
path_to_img = 'nsfw.jpg'
with open(path_to_img, 'rb') as f:
    response = requests.post('https://nsfw3.p.rapidapi.com/v1/results',
                             headers={'X-RapidAPI-Key': RAPIDAPI_KEY},
                             files={'image': f})
    api_res_json = response.json()
    nsfw_probability = api_res_json['results'][0]['entities'][0]['classes']['nsfw']
    sfw_probability = api_res_json['results'][0]['entities'][0]['classes']['sfw']

Learning discord.py

First of all, let’s create a bot.
Go to https://discord.com/developers/applications?new_application=true and create a new application.

Then go to Bot and turn on message content intent.

Now you can invite the bot to your server using the URL from the OAuth2->URL Generator menu. Do not forget to click bot and set the permissions.

Let’s make a simple echobot.

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 = '2b4d252a-9c7a-4f17-85bf-d7b6390c165b' # get yours at Bot->Token menu
intents = discord.Intents.default()
intents.messages = True
intents.message_content = True

client = MyClient(intents=intents)
client.run(bot_token)

Making a NSFW moderation bot

First of all, follow the steps from the previous chapter and create a bot application in the Discord developer portal.
Let’s start making a bot with a function for checking a photo with NSFW API.


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

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.
Now we are ready to make a bot class.

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()
            )

This part is needed so that the bot does not react to its own messages.

if message.author == self.user:
    return

All that users can send are 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')]

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)

If any photo in the message is NSFW, delete it and send a warning to the user.
Here, too, it is better to use 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()
    )

A Discord bot token will be parsed from command line arguments.

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 https://rapidapi.com/api4ai-api4ai-default/api/nsfw3/details  # noqa
    return parser.parse_args()

The last step left is to run the bot with rights to see message_content and manage messages on servers(guilds).

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()

The ready Python code is:

"""
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 https://rapidapi.com/api4ai-api4ai-default/api/nsfw3/details  # 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()

Conclusion

In this tutorial, we developed a Discord bot for content moderation using our advanced solution for detecting unsafe content. By following our guide, you can create a bot that automatically enforces community guidelines, ensuring a safe environment for all users. We covered setting up the development environment, creating a Discord bot application, implementing moderation features, and utilizing our content detection solution. Let’s get started on building your powerful moderation bot for Discord!