[PYTHON] I tried to create a linebot (implementation)

Preparation: https://qiita.com/maihamada/items/2c4d5b4f6ae82db45970 Now that the preparations are complete, we will actually implement it.

(1) The system you want to make this time

When the input "Deacon diagnosis" is received, perform "Deacon diagnosis". The question is the following flow. スクリーンショット 2020-05-09 19.09.01.png The completed image looks like this. S__3842059.jpg

Depending on the response of the button event, the button event may be returned, the message event may be returned, and so on.

(2) Creating a folder

Since the working directory has been created, we will work on it. Create a folder with the following file structure.

situji-bot/ [Working directory(Anything will be fine)]
 ├app.py 
 ├conf.json
 ├Procfile
 ├requirements.txt
 ├runtime.txt
 └template/
  └button_event.py

(3) File description

app.py I'm writing the main one for the application.


import os
import sys
import json

#import flask library
from flask import Flask, request, abort
#import linebot library
from linebot import LineBotApi, WebhookHandler
from linebot.exceptions import InvalidSignatureError
from linebot.models import (
    MessageEvent, PostbackEvent, TextMessage, TextSendMessage
)

#Import your own library
from template import button_event

app = Flask(__name__)

#Read configuration file
ABS_PATH = os.path.dirname(os.path.abspath(__file__))
with open(ABS_PATH+'/conf.json', 'r') as f:
    CONF_DATA = json.load(f)
CHANNEL_SECRET = CONF_DATA['CHANNEL_SECRET']
CHANNEL_ACCESS_TOKEN = CONF_DATA['CHANNEL_ACCESS_TOKEN']

#Create an instance of the client library
line_bot_api = LineBotApi(CHANNEL_ACCESS_TOKEN)
handler = WebhookHandler(CHANNEL_SECRET)

#Code for testing
@app.route("/")
def test():
    app.logger.info("test")
    return('test OK')

#LINE API code
@app.route("/callback", methods=['POST'])
def callback():
    signature = request.headers['X-Line-Signature']
    body = request.get_data(as_text=True)
    app.logger.info(f"Request body: {body}")
    try:
        handler.handle(body, signature)
    except InvalidSignatureError as e:
        print(e)
        abort(400)
    return 'OK'

#Reaction when a message comes
@handler.add(MessageEvent, message=TextMessage)
def message_text(event):
    message_text = event.message.text
    app.logger.info(message_text)

    if message_text == 'Butler diagnosis':
        line_bot_api.reply_message(
            event.reply_token,
            button_event.SitujiSindan().question_a()
        )
    else:
        msg = 'We are sorry, but we do not currently support it.'
        line_bot_api.reply_message(
            event.reply_token,
            TextSendMessage(text=msg)
        )

#Reaction when the value comes back
@handler.add(PostbackEvent)
def on_postback(event):
    reply_token = event.reply_token
    user_id = event.source.user_id

    # postback_msg :method name as a string
    postback_msg = event.postback.data
    # situji_sindan :class object
    situji_sindan = button_event.SitujiSindan()
    #Create a method object from the method name obtained from the class object and the character string
    question = getattr(situji_sindan, postback_msg)
    #Throw the next question
    line_bot_api.reply_message(
        event.reply_token,
        question()
    )

if __name__ == "__main__":
    app.run(debug=True)

conf.json If you look at this file, it's separated so you can see which setting you're using. Currently, I only set the line api, but I would like to include the DB settings in the future. The channel secret channel access token obtained in the preparation is used here.

{
"CHANNEL_SECRET": "[Channel secret]",
"CHANNEL_ACCESS_TOKEN": "[Channel access token]"
}

Procfile Configuration files such as process type. It seems that gunicorn (WSGI server) is required to connect the web server and the flask framework. The way to write is as follows, and the last --log-file-is described only when you want to output a log. [process type]: [command] [api_name] : app --log-file -

web: gunicorn app:app --log-file -

requirements.txt Write the library and version used.

Flask==1.1.2
gunicorn==20.0.4
line-bot-sdk==1.16.0

runtime.txt Write the version of python used.

python-3.8.1

template/button_event.py This time, I created a lot of button events, so I tried to make it a separate module.

from linebot.models import (
    PostbackEvent, TextSendMessage, TemplateSendMessage,
    ButtonsTemplate, PostbackTemplateAction
)

class SitujiSindan:
    def question_a(self):
        button_template = TemplateSendMessage(
            alt_text="Butler diagnosis",
            template=ButtonsTemplate(
                title="question 1",
                text="When you get into a pinch",
                actions=[
                  PostbackTemplateAction(
                    label='Help you with your brain',
                    data='question_b'
                  ),
                  PostbackTemplateAction(
                    label='Stretch your body and help you',
                    data='question_c'
                  )
                ]
            )
        )
        return button_template

    def question_b(self):
        button_template = TemplateSendMessage(
            alt_text="Butler diagnosis",
            template=ButtonsTemplate(
                title="Question 2",
                text="When you do something hard ...",
                actions=[
                  PostbackTemplateAction(
                    label='I want you to follow me gently',
                    data='answer_d'
                  ),
                  PostbackTemplateAction(
                    label='I want you to scold me properly',
                    data='answer_e'
                  )
                ]
            )
        )
        return button_template

    def question_c(self):
        button_template = TemplateSendMessage(
            alt_text="Butler diagnosis",
            template=ButtonsTemplate(
                title="Question 2",
                text="Which is the type?",
                actions=[
                  PostbackTemplateAction(
                    label='Unfriendly',
                    data='answer_f'
                  ),
                  PostbackTemplateAction(
                    label='Friendly',
                    data='answer_g'
                  )
                ]
            )
        )
        return button_template

    def answer_d(self):
        msg = 'The diagnosis result is "Orthodox Butler". Anyway, I'm doing my best for the young lady'
        return TextSendMessage(text=msg)

    def answer_e(self):
        msg = 'The diagnosis result is "Older brother butler". I love her and always care about her.'
        return TextSendMessage(text=msg)

    def answer_f(self):
        msg = 'The diagnosis result is "butler". It's a little unfriendly, but I'm doing my best to protect the young lady. The habit is "because it's just a butler."'
        return TextSendMessage(text=msg)

    def answer_g(self):
        msg = 'The diagnosis result is "younger brother butler". I love my young lady and treat her like a younger brother. I don't usually rely on it, but I will do my best to protect it in a pinch.'
        return TextSendMessage(text=msg)

(4) Test locally.

$ python app.py
 * Serving Flask app "app" (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: on
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 897-298-226

Hit the following url with chrome etc., and when the word "test OK" appears, it's OK. http://127.0.0.1:5000/

(5) Deploy

I set it to deploy automatically when I push it to Git, so push it. Staging.

$ git add .

Check the staging status.

$ git status
On branch master
Your branch is up to date with 'origin/master'.

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
	new file:   Procfile
	new file:   app.py
	new file:   conf.json
	new file:   requirements.txt
	new file:   runtime.txt
	new file:   template/button_event.py

Do commit & push.

$ git commit -m 'first push'
[master 04a377d] first push
 6 files changed, 198 insertions(+)
 create mode 100644 Procfile
 create mode 100644 app.py
 create mode 100644 conf.json
 create mode 100644 requirements.txt
 create mode 100644 runtime.txt
 create mode 100644 template/button_event.py
$ git push origin master
Enumerating objects: 10, done.
Counting objects: 100% (10/10), done.
Delta compression using up to 4 threads
Compressing objects: 100% (6/6), done.
Writing objects: 100% (9/9), 2.80 KiB | 1.40 MiB/s, done.
Total 9 (delta 0), reused 0 (delta 0), pack-reused 0
To github.com:maihamada/situji-bot.git
   fc7af07..04a377d  master -> master

(6) Set up LINE Developers

Set up webhock. (In Messaging API settings) スクリーンショット 2020-05-09 19.52.12.png

Arrange the response settings as you like. スクリーンショット 2020-05-09 19.53.28.png

This completes the creation of LINE BOT.

Impressions

It was easier to implement than I expected. In the future, I would like to increase the response pattern by character strings and change the tone of the butler using the result of this diagnosis.

Recommended Posts

I tried to create a linebot (implementation)
I tried to create a linebot (preparation)
I want to create a plug-in type implementation
I tried to create a table only with Django
I tried to create Quip API
I tried to automatically create a report with Markov chain
I tried to create a bot for PES event notification
I tried adding post-increment to CPython Implementation
I tried to make a Web API
I tried to create a server environment that runs on Windows 10
I tried to create a simple credit score by logistic regression.
I tried to create a list of prime numbers with python
I tried to create Bulls and Cows with a shell program
I tried to debug.
I tried to paste
I tried to build a super-resolution method / ESPCN
I want to easily create a Noise Model
I tried to build a super-resolution method / SRCNN ①
I want to create a window in Python
I tried to generate a random character string
I tried to build a super-resolution method / SRCNN ③
I tried to build a super-resolution method / SRCNN ②
I tried to make a ○ ✕ game using TensorFlow
I tried to create a program to convert hexadecimal numbers to decimal numbers with python
I tried to create a plug-in with HULFT IoT Edge Streaming [Development] (2/3)
I tried to create a plug-in with HULFT IoT Edge Streaming [Execution] (3/3)
[Outlook] I tried to automatically create a daily report email with Python
I tried to create a plug-in with HULFT IoT Edge Streaming [Setup] (1/3)
I tried to create a sample to access Salesforce using Python and Bottle
I tried to make a "fucking big literary converter"
I tried to learn PredNet
I tried to create a class that can easily serialize Json in Python
I tried to draw a route map with Python
I tried to organize SVM.
I tried to implement a pseudo pachislot in Python
When I tried to create a virtual environment with Python, it didn't work
I tried to implement a recommendation system (content-based filtering)
I tried to implement PCANet
I tried to easily create a fully automatic attendance system with Selenium + Python
[Azure] I tried to create a Linux virtual machine in Azure of Microsoft Learn
[Go + Gin] I tried to build a Docker environment
I tried to automatically generate a password with Python3
I tried to reintroduce Linux
I want to manually create a legend with matplotlib
I tried to introduce Pylint
I tried to create a button for Slack with Raspberry Pi + Tact Switch
I tried to summarize SparseMatrix
I tried to touch jupyter
I tried to implement StarGAN (1)
I tried to draw a configuration diagram using Diagrams
I tried to create a model with the sample of Amazon SageMaker Autopilot
I tried to create a reinforcement learning environment for Othello with Open AI gym
[Python] I tried to automatically create a daily report of YWT with Outlook mail
I tried to create a class to search files with Python's Glob method in VBA
I tried scraping food recall information with Python to create a pandas data frame
I tried to implement a volume moving average with Quantx
I tried to implement a basic Recurrent Neural Network model
I tried to create API list.csv in Python from swagger.yaml
I tried to implement a one-dimensional cellular automaton in Python
[Markov chain] I tried to read a quote into Python.
I made a tool to create a word cloud from wikipedia