
5 minutes read
October 11, 2022
How to make a Stable Diffusion discord bot
This post demonstrates how to create a discord bot to generate images with Stable Diffusion.
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.
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).
- Sign in to the discord developer portal (you can use your regular discord account)
- Click the
New Application
on the top right - Once the Application has been created click on
Bot
on the left menu and clickAdd Bot
- To add this bot to your server navigate to
OAuth2/URL Generator
on the left menu and selectbot
on the first scope andUse Slash Commands
under theBot Permissions
. You'll see aGenerated URL
field populated at the bottom of the page, copy and click on it to add it to your server! - Finally, you need to collect your discord bot token under the
Token
tab on your under theBot
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.txt. This post uses python 3.9 and should work for later python versions.
You can install the dependencies in your python environment using
1pip install -r requirements.txt
2# OR
3python -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:
1pipeline_api = PipelineCloud(token="...")
2
3async def handle_generation(image_prompt: str) -> io.BytesIO:
4 response = pipeline_api.run_pipeline(
5 "pipeline_67d9d8ec36d54c148c70df1f404b0369",
6 [[image_prompt], {"width": 512, "height": 512, "num_inference_steps": 50}],
7 )
8 image_b64 = response.result_preview[0][0][0]
9
10 image_decoded = base64.decodebytes(image_b64.encode())
11 buffer = io.BytesIO(image_decoded)
12 new_uid = str(uuid.uuid4())
13 buffer.name = new_uid
14 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:
1# For our '/paint' command we only want to take in a single text prompt,
2# this is included in the 'options' field below and the name of the option
3# is what's used as a key word argument to our function
1@bot.command(
2 name="paint",
3 description="Paint an image that has never existed...",
4 options=[
5 interactions.Option(
6 name="prompt",
7 description="Image generation prompt",
8 type=interactions.OptionType.STRING,
9 required=True,
10 ),
11 ],
12)
13async def paint(ctx: interactions.CommandContext, prompt: str) -> None:
14 # You have to send back a response quickly otherwise
15 # Discord thinks that the bot has died.
16 sent_response = await ctx.send("Generating image...")
17
18 try:
19 image_buffer = await handle_generation(prompt)
20
21 # Edit the original message sent to now include the image and the prompt
22 await sent_response.edit(
23 files=[
24 interactions.api.models.misc.File(
25 filename=prompt + ".jpeg", fp=image_buffer
26 )
27 ],
28 content=prompt
29 # You can add another argument 'ephemeral=True' to only show the
30 # result to the user that sent the request.
31 )
32 except:
33 # If the image generation (or anything else) fails
34 # for any reason it's best to let the user know
35 await sent_response.edit(
36 content="Generation failed, please try again!",
37 )
38
39 # With asyncio you have to call the 'flush=True' on print
40 print(traceback.format_exc(), flush=True)
41Finally we need to add a few things to run the bot and complete our script:
1import os
2import interactions
3import traceback
4import base64
5import io
6import uuid
7
8from pipeline.api.asyncio import PipelineCloud
9
10# The token here is the one we collected earlier from the discord bot
11discord_token = os.getenv("DISCORD_TOKEN")
12pipeline_token = os.getenv("PIPELINE_API_TOKEN")
13bot = interactions.Client(token=discord_token)
14pipeline_api = PipelineCloud(token=pipeline_token)
15
16# As defined earlier
17async def handle_generation(...) -> None:
18 ...
19
20# As defined earlier
21@bot.command(...)
22async def paint(...) -> None:
23 ...
24
25bot.start()
This code was saved on my system as sd_discord_bot.py
, and the environment variables can be passed in as follows:
1env 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 (therequirements.txt
is the one described above):1project_dir/
2 ./bot.py
3 ./requirements.txt
4 ./Dockerfile
5 ./docker-compose.yml
6 ./secrets.env
bot.py
copied into it.
Here is the Dockerfile
used for the project:1FROM python:3.9-slim
2
3WORKDIR /code
4
5COPY ./requirements.txt /code/
6
7ENV PYTHONDONTWRITEBYTECODE=1
8
9RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
10
11COPY ./bot.py /code/
12
13CMD ["python", "bot.py"]
1sudo docker build . -t stable-diffusion-discord-bot:main
2sudo docker run --env DISCORD_TOKEN=... --env PIPELINE_API_TOKEN=... stable-diffusion-discord-bot:main
docker-compose.yml
file:1version: "3.9"
2services:
3stable-diffusion-discord-bot:
4 container_name: stable-diffusion-discord-bot
5 image:
6 build:
7 context: .
8 dockerfile: ./Dockerfile
9 env_file:
10 - secrets.env
DISCORD_TOKEN
& PIPELINE_API_TOKEN
variables. You can run this simply with:1sudo 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!