[PYTHON] The story of making a slackbot that outputs as gif or png when you send the processing code

Introduction

I wrote it all at once with midnight tension, so I may fix it a lot. In this article, I will explain how to start slackbot. Deploy and operate! I hope you can do your best while looking at other articles ... The code used in this article is posted here [https://github.com/kota-shiokara/processing-slackbot).

Please note that various explanations are omitted in this article.

Text

Environment etc. (Because it is my environment, it is just a guide)

Install slackbot and Pillow library with pip. (In some cases pip3)


$ pip install slackbot
$ pip install Pillow

$ pip list #Check installed libraries

Also, install processing-java. This article is recommended for the introduction of processing. You should be able to install it by going to Download processing, launching it, and selecting Tools> Install processing-java from the toolbar.

Creating a bot

Please create a bot from the following site. Be careful not to make a mistake in the workspace you create. https://my.slack.com/services/new/bot (Originally, this is not recommended, and you have to do some troublesome things such as setting the scope, but this time I will go with this.)

Enter the name of your bot in this username and press "Add bot integration". slackでの設定.png

Make a note of the displayed "API token" by copying it. Customize the name, icon, etc. as you like. When you're done, press the button at the bottom of the page to save your settings. After that, you can edit and check the token on the page that appears by searching for "bots" on the page ``` https: // / apps` ``.

Ready to move the bot

Prepare a directory like the one below. If you clone here, you can skip most of the work. (In that case, please prepare the (*) folder and files!)

slackbot         #A directory that organizes programs. Arbitrary string
├─ run.py        #Main file for starting bot
├─ slackbot_settings.py   #File to write settings related to bot(※)
├─ plugins                #Add bot functionality to this directory
   ├─ __init__.py         #A file to indicate the module. OK in the sky
   └─ func.py       #A file to write the function. Arbitrary string
   └─ cfg.py        #File to put the sketch path(※)
└─ sketch (※)
   └─ sketch.pde    #A sketch file to write once. OK in the sky(※)

Write the code below.

`` `run.py``` code

run.py


from slackbot.bot import Bot

def main():
    bot = Bot()
    bot.run()

if __name__ == "__main__":
    print('start slackbot')
    main()
``` slackbot_settings.py``` code

slackbot_settings.py


API_TOKEN = "<Noted API token>"
DEFAULT_REPLY = "<Any string you want to return by default>"
PLUGINS = ['plugins'] #The name of the directory that contains the code that writes the bot's functionality
`` `func.py``` code

func.py


from slackbot.bot import respond_to     # @botname:Decoder that reacts with
from slackbot.bot import listen_to      #Decoder that responds to in-channel remarks
from slackbot.bot import default_reply  #Decoder that reacts when there is no corresponding response
import sys, subprocess, os.path, os, glob, time
from .cfg import * #Cfg in the same hierarchy.import from py
from PIL import Image

@listen_to('!output (.*)')
def output(message, arg): #arg is optional
    #Format sent text
    tmp = message.body['text']
    tmp = tmp.replace("&lt;", "<")
    tmp = tmp.replace("&gt;", ">")

    #Formatted into a string for overwriting pde
    pdeCode = shaping_code(tmp.strip("!output " + arg + "\n"), arg)
    message.send('wait...')

    #Overwrite pde
    print(pdeCode)
    f = open('sketch/sketch.pde', 'w')
    f.write(pdeCode)
    f.close()

    cp = subprocess.run(['processing-java',  sketch_path, '--run']) #Execution of processing
    if cp.returncode != 0: #Processing when execution failure of processing
        message.send('Run is failed.')
        sys.exit(1) #Sys that doesn't work for some reason.exit()
    
    upload_sequence(message, arg) #upload process


def shaping_code(code, option): #Added image output method to pde code
    if option == '--png': #png option
        pictFunc = "  if((frameCount <= 15) && (frameCount % 15 == 0)) saveFrame(\"####.png\");\n  else if(frameCount > 15) exit();"
    elif option == '--gif': #gif option
        pictFunc = "  if((frameCount <= 300) && (frameCount % 15 == 0)) saveFrame(\"####.png\");\n  else if(frameCount > 300) exit();"
    else : #Returns as png by default
        pictFunc = "  if((frameCount <= 15) && (frameCount % 15 == 0)) saveFrame(\"####.png\");\n  else if(frameCount > 15) exit();"
    return code.replace("void draw(){", "void draw(){\n" + pictFunc)

def upload_sequence(message, option):
    if option == '--png': #png option
        message.channel.upload_file(fname="sketch/0015.png ", fpath="sketch/0015.png ")
        if os.path.exists('sketch/0015.png'):
            os.remove('sketch/0015.png')
    elif option == '--gif': #gif option
        time.sleep(6)
        file_list = sorted(glob.glob('sketch/*.png'))  
        images = list(map(lambda file : Image.open(file) , file_list))
        images[0].save('sketch/output.gif' , save_all = True , append_images = images[1:] , duration = 400 , loop = 0)
        if os.path.exists('sketch/output.gif'):
            message.channel.upload_file(fname="sketch/output.gif", fpath="sketch/output.gif")
            for p in glob.glob('sketch/*.png'):
                if os.path.isfile(p):
                    os.remove(p)
            os.remove('sketch/output.gif')
    else : #Upload with png by default
        message.channel.upload_file(fname="sketch/0015.png ", fpath="sketch/0015.png ")
        if os.path.exists('sketch/0015.png'):
            os.remove('sketch/0015.png')
``` cfg.py``` code
Declare the path of the sketch folder as a variable, but of course it changes depending on where you put it, so please refer to your directory. It is specified by an absolute path.

cfg.py


sketch_path = '--sketch=/Users/<username>/slackbot/sketch' #Specify the directory containing the sketch folder you want to read with an absolute path

bot launch

Let's actually start the bot when the preparation is completed. Go to the slackbot directory and


$ python3 run.py

Let's run the program by hitting.

--For png

png.png If you send the code with ```! Output --png``` and the bot that returns in png moves like this, you win. In addition, since the completed png is automatically deleted, you do not have to worry about the pressure on the capacity.

--For gif

gif.gif If you send the code with ! Output --gif and the bot that returns in png moves like this, you win. Both gif and png will be deleted in the same way.

At the end

This is a poor explanation, but this is the end of the explanation up to startup. It was interesting to be able to hit commands with subprocess and create various commands using regular expressions. If you get motivated, I will write an article explaining the method used and an article on bot operation. It's unknown because I haven't deployed it yet ... ~~ (What is infrastructure) ~~

Reference article

-I tried running slackbot (python) on Heroku [Omikuji BOT] -Create a Slack bot with Python's slackbot library -Since the staggered commuting started, I made a bot that tells me the time to leave

Recommended Posts

The story of making a slackbot that outputs as gif or png when you send the processing code
The story of making a module that skips mail with python
The story of blackjack A processing (python)
The story of making a package that speeds up the operation of Juman (Juman ++) & KNP
The story of making a box that interconnects Pepper's AL Memory and MQTT
The story of making a web application that records extensive reading with Django
The story of making a lie news generator
The story of making a Line Bot that tells us the schedule of competitive programming
The story of making a mel icon generator
It is a piggybacking story about the service that returns "Nyan" when you ping
A story that reduces the effort of operation / maintenance
# Function that returns the character code of a string
The story of making a music generation neural network
A story that analyzed the delivery of Nico Nama.
Extract the value of dict or list as a string
The story of making a question box bot with discord.py
The story of making a tool that runs on Mac and Windows at the game development site
When incrementing the value of a key that does not exist
Save the result of the life game as a gif with python
The story that a hash error came out when using Pipenv
A story that struggled to handle the Python package of PocketSphinx
Precautions when using a list or dictionary as the default argument
The story of making a standard driver for db with python.
A function that measures the processing time of a method in python
[Python] Code that can be written with brain death at the beginning when scraping as a beginner
[AtCoder for beginners] A story about the amount of calculation that you want to know very roughly
The story of making a tool to load an image with Python ⇒ save it as another name
The story of writing a program
A story that visualizes the present of Qiita with Qiita API + Elasticsearch + Kibana
If you want a singleton in python, think of the module as a singleton
The story of developing a web application that automatically generates catchphrases [MeCab]
The story of making a sound camera with Touch Designer and ReSpeaker
[Python3] Code that can be used when you want to change the extension of an image at once