Skip to content
feature image for post with title: How to make a Stable Diffusion discord bot

How to make a Stable Diffusion discord bot

Learn to craft a Discord bot using the Stable Diffusion API from Mystic AI. Utilize the discord interactions library in Python for dynamic image generation.

  • Digest time

    5 min read
  • Published

    10/11/2022
  • Tags

    Tutorial
  • Author

    Paul Hetherington

This post demonstrates how to create a discord bot to generate images with Stable Diffusion. We will be using the Stable Diffusion API provided by pipeline.ai to handle the ML compute. The bot will be created in python using the discord interactions library and can run on your laptop.

Figure 1. Demo of the bot using the /paint command.

If you don't want to make this yourself, you can add the bot I made to your server (for free) by clicking here or checkout the git repo here.

Initial setup 

Discord developer setup

Before we can hookup to the Discord API you will first have to create a Discord developer account. Below is a basic set of steps to do this (or you can view a more in-depth guide here).

  1. Sign in to the discord developer portal (you can use your regular discord account)
  2. Click the New Application on the top right
  3. Once the Application has been created click on Bot on the left menu and click Add Bot
  4. To add this bot to your server navigate to OAuth2/URL Generator on the left menu and select bot on the first scope and Use Slash Commands under the Bot Permissions. You'll see a Generated URL field populated at the bottom of the page, copy and click on it to add it to your server!
  5. Finally, you need to collect your discord bot token under the Token tab on your under the Bot tab on the left menu.

Dependencies

There are two main libraries for working with Discord in python:

We will be using interactions.py, but they are relatively interchangable. The full list of dependencies can be found here requirements.txtThis post uses python 3.9 and should work for later python versions.

You can install the dependencies in your python environment using

pip install -r requirements.txt
# OR
python -m pip install -r requirements.txt

Making the bot

Generating an image with Stable Diffusion

The core code to generate the image with the pipeline.ai library is straight forward as it has native asyncio support for use in production APIs:

pipeline_api = PipelineCloud(token="...")

async def handle_generation(image_prompt: str) -> io.BytesIO:
    response = pipeline_api.run_pipeline(
        "pipeline_67d9d8ec36d54c148c70df1f404b0369",
        [[image_prompt], {"width": 512, "height": 512, "num_inference_steps": 50}],
    )
    image_b64 = response.result_preview[0][0][0]

    image_decoded = base64.decodebytes(image_b64.encode())
    buffer = io.BytesIO(image_decoded)
    new_uid = str(uuid.uuid4())
    buffer.name = new_uid
    return buffer

Bot client

To add a command to your bot with the interactions.py library you create an async function with the @bot.command(...) decorator:

# For our '/paint' command we only want to take in a single text prompt, 
# this is included in the 'options' field below and the name of the option 
# is what's used as a key word argument to our function
@bot.command(
    name="paint",
    description="Paint an image that has never existed...",
    options=[
        interactions.Option(
            name="prompt",
            description="Image generation prompt",
            type=interactions.OptionType.STRING,
            required=True,
        ),
    ],
)
async def paint(ctx: interactions.CommandContext, prompt: str) -> None:
    # You have to send back a response quickly otherwise 
    # Discord thinks that the bot has died.
    sent_response = await ctx.send("Generating image...")

    try:
        image_buffer = await handle_generation(prompt)

        # Edit the original message sent to now include the image and the prompt
        await sent_response.edit(
            files=[
                interactions.api.models.misc.File(
                    filename=prompt + ".jpeg", fp=image_buffer
                )
            ],
            content=prompt
            # You can add another argument 'ephemeral=True' to only show the 
            # result to the user that sent the request.
        )
    except:
        # If the image generation (or anything else) fails 
        # for any reason it's best to let the user know
        await sent_response.edit(
            content="Generation failed, please try again!",
        )

        # With asyncio you have to call the 'flush=True' on print
        print(traceback.format_exc(), flush=True)
Finally we need to add a few things to run the bot and complete our script:
import os
import interactions
import traceback
import base64
import io
import uuid

from pipeline.api.asyncio import PipelineCloud

# The token here is the one we collected earlier from the discord bot
discord_token = os.getenv("DISCORD_TOKEN")
pipeline_token = os.getenv("PIPELINE_API_TOKEN")
bot = interactions.Client(token=discord_token)
pipeline_api = PipelineCloud(token=pipeline_token)

# As defined earlier
async def handle_generation(...) -> None:
    ...

# As defined earlier
@bot.command(...)
async def paint(...) -> None:
    ...

bot.start()  

This code was saved on my system as sd_discord_bot.py, and the environment variables can be passed in as follows:

env DISCORD_TOKEN=... PIPELINE_API_TOKEN=... python bot.py

You can now navigate to your discord server and run /paint!

Docker & docker compose

The bot will run for as long as you have your terminal open, but to run this system continually Docker is a great solution. Docker has a quick start guide here but for this post you will only need it installed and not much further understanding.

br> This section uses the following project directory layout (the requirements.txt is the one described above):
project_dir/
    ./bot.py
    ./requirements.txt
    ./Dockerfile
    ./docker-compose.yml
    ./secrets.env
All the bot requires to run is the standard python docker image with our secrets and bot.py copied into it. Here is the Dockerfile used for the project:
FROM python:3.9-slim

WORKDIR /code

COPY ./requirements.txt /code/

ENV PYTHONDONTWRITEBYTECODE=1

RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt

COPY ./bot.py /code/

CMD ["python", "bot.py"]
This can run standalone via the following commands in the project directory:
sudo docker build . -t stable-diffusion-discord-bot:main
sudo docker run --env DISCORD_TOKEN=... --env PIPELINE_API_TOKEN=... stable-diffusion-discord-bot:main
Alternatively, if you'd like to run the Docker image through docker compose you can use the following docker-compose.yml file:
version: "3.9"
services:
stable-diffusion-discord-bot:
    container_name: stable-diffusion-discord-bot
    image: 
    build:
      context: .
      dockerfile: ./Dockerfile
    env_file:
      - secrets.env
To run this you will have to populate the secrets.env with the DISCORD_TOKEN & PIPELINE_API_TOKEN variables. You can run this simply with:
sudo docker-compose run --build -d

------------------------------------------------------

If you run into issues, the Pipeline team are always willing to help in any way. Contact us here or join us on Discord!


ABOUT Mystic

Mystic makes it easy to work with ML models and to deploy AI at scale. The self-serve platform provides a fast pay-as-you-go API to run pretrained or proprietory models in production. If you are looking to deploy a large product and would like to sign up as an Enterprise customer please get in touch. In the meantime follow us on Twitter and Linkedin.