I made a Line-bot using Python!

Issues found

image.png

Purpose and function

Register your favorite shop / facility with your favorite name and create a Line-bot that can retrieve information about that shop / facility.

image.png

Things necessary

Development flow

1 Register with LINE Developers and heroku (omitted)

2 Let's make LINE-bot for the time being with the sample code distributed by LINE.

app.py Sample code distributed by Line.



from flask import Flask, request, abort

from linebot import (
    LineBotApi, WebhookHandler
)
from linebot.exceptions import (
    InvalidSignatureError
)
from linebot.models import (
    MessageEvent, TextMessage, TextSendMessage,
)

app = Flask(__name__)

# line-access from the developers page_token and channel_Generate each secret and put it in a variable here
#If you don't know, see other articles. Many other people have written it, so I'll omit it here.
line_bot_api = LineBotApi('YOUR_CHANNEL_ACCESS_TOKEN')
handler = WebhookHandler('YOUR_CHANNEL_SECRET')


@app.route("/callback", methods=['POST'])
def callback():
    # get X-Line-Signature header value
    signature = request.headers['X-Line-Signature']
    # get request body as text
    body = request.get_data(as_text=True)
    app.logger.info("Request body: " + body)

    # handle webhook body
    try:
        handler.handle(body, signature)
    except InvalidSignatureError:
        print("Invalid signature. Please check your channel access token/channel secret.")
        abort(400)

    return 'OK'

#The event contains a lot of user information.
@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
    line_bot_api.reply_message(
        event.reply_token,
        TextSendMessage(text=event.message.text))

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

Prepare the following two in the same folder.

requirements.txt (write what you need to install on heroku's server)

Be sure to install gunicorn. (It seems to be a library required for heroku server) Using a python virtual environment called venv makes it even cleaner, but I didn't do it because I couldn't do it well as described in Recent article.

argon2-cffi==20.1.0
asgiref==3.2.10
async-generator==1.10
attrs==20.2.0
backcall==0.2.0
bleach==3.1.5
certifi==2020.6.20
cffi==1.14.2
chardet==3.0.4
click==7.1.2
colorama==0.4.3
decorator==4.4.2
defusedxml==0.6.0
entrypoints==0.3
Flask==1.1.2
gunicorn==20.0.4
idna==2.10
itsdangerous==1.1.0
jedi==0.17.2
Jinja2==2.11.2
json5==0.9.5
jsonschema==3.2.0
line-bot-sdk==1.17.0
MarkupSafe==1.1.1
mistune==0.8.4
nbclient==0.5.0
nbconvert==6.0.2
nbformat==5.0.7
nest-asyncio==1.4.0
notebook==6.1.4
numpy==1.19.2
packaging==20.4
pandocfilters==1.4.2
parso==0.7.1
pickleshare==0.7.5
prometheus-client==0.8.0
prompt-toolkit==3.0.7
pycparser==2.20
Pygments==2.7.0
pyparsing==2.4.7
pyrsistent==0.17.3
python-dateutil==2.8.1
pytz==2020.1
pywinpty==0.5.7
pyzmq==19.0.2
requests==2.24.0
selenium==3.141.0
Send2Trash==1.5.0
six==1.15.0
sqlparse==0.3.1
terminado==0.8.3
testpath==0.4.4
tornado==6.0.4
urllib3==1.25.10
wcwidth==0.2.5
webencodings==0.5.1
Werkzeug==1.0.1

Procfile

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

Follow the steps below to deploy to heroku!

heroku login
heroku git:clone -a [My app name]
cd [My app name]
* If you are working in the current directory, you do not have to do it
git add . #I'm adding a file
git commit -am "make it better" #I'm updating the changed file
git push heroku master #I'm pushing

Let's send a message to line for the time being like this.

Challenges in making the linebot you want to make this time

Use Google Map Api to get store information.

Solution: Nothing in particular. Just look at the Google Map Api documentation.

Save user information individually.

Solution: This was quite annoying. At first I thought I should try using a database, but I stopped this time because the learning cost seemed to be high. Next, I saved the dictionary in a pickle file and tried it, but for some reason it didn't work. Is binary data useless? ?? The cause is not clear. Finally I decided to save the dictionary in json format. It worked, but the data disappears every time I make a change. I thought I'd send the json file when I entered the password on line, but this time I stopped.

Receive a message from user and respond according to the message.

Solution This was quite difficult again. In addition to "register" and "delete" variables, I made four responses: "confirm" the variables I created and "confirm" the information about shops and facilities. (It doesn't explain the solution, but I hope you can see the python file below.)

Created file (other than requirements.txt, Procfile)

I intend to include as many libraries and grammars as possible for my study.

app.py main file.

import json

class create_reply_message(object):
    user_id = None
    user_dictionaries = None
    the_user_dictionary = None

    def __init__(self, user_id=None,*args, **kwargs):
        super().__init__(*args, **kwargs)
        self.user_id = user_id

        #Preparing a dictionary
        with open("users_info.json", 'r') as f:
            self.user_dictionaries = json.load(f)
            self.the_user_dictionary = self.user_dictionaries.setdefault(self.user_id, {})

    def legister_fav_shop_institution(self, shop_institute_actual_name, shop_institute_variable):
        user_dictionaries_copy = self.user_dictionaries.copy()
        the_user_dictionary_copy = user_dictionaries_copy[self.user_id]
        the_user_dictionary_copy[shop_institute_variable] = shop_institute_actual_name
        with open("users_info.json", 'w') as f:
            json.dump(user_dictionaries_copy, f)
        return 'Completion of registration!'

    def confirm_what_legistered(self):
        if self.the_user_dictionary == {}:
            reply_msg = "There are no registered shops / facilities yet ..."
            return reply_msg
        else:
            reply_msg = []
            for dict_key in self.the_user_dictionary:
                reply_msg.append(dict_key)
            reply_msg.insert(0, f'The registered shops and facilities are below{len(self.the_user_dictionary)}Tsu! !!')
            return "\Hmm·".join(reply_msg)

    def delete_fav_shop_institution(self, shop_institute_variable):
        user_dictionaries_copy = self.user_dictionaries.copy()
        the_user_dictionary_copy = user_dictionaries_copy[self.user_id]
        del the_user_dictionary_copy[shop_institute_variable]
        with open("users_info.json", 'w') as f:
            json.dump(user_dictionaries_copy, f)
        return shop_institute_variable + 'Is deleted!'

google_maps_client.py A class that just gets information from Google Map Api and puts it in the self. variable.


import requests
from urllib.parse import urlencode, urlparse, parse_qsl


class locate_fav_shop_institution(object):
    data_type="json"
    location_query = None
    api_key = None

    def __init__(self, api_key=None, shop_institution_name=None,
                 *args, **kwargs):
        super().__init__(*args, **kwargs)
        if api_key == None:
            raise Exception('API key is required')
        self.api_key = api_key
        self.location_query = shop_institution_name

        if self.location_query != None:
            self.place_id = self.extract_place_id()
        if self.place_id == '':
            raise Exception('Your fav shop/instition couldn\'t be located.')
        self.fav_shop_institution_info = self.extract_details()

    def extract_place_id(self):
        base_endpoint_places = f"https://maps.googleapis.com/maps/api/place/findplacefromtext/{self.data_type}"
        params = {
            "key": self.api_key,
            "input": self.location_query,
            "inputtype": "textquery",
             "fields": "place_id"
        }

        params_encoded = urlencode(params)
        places_endpoint = f"{base_endpoint_places}?{params_encoded}"

        r = requests.get(places_endpoint)
        if r.status_code not in range(200, 299):
            return ""
        return r.json()['candidates'][0]['place_id']

    def extract_details(self):
        detail_base_endpoint = f"https://maps.googleapis.com/maps/api/place/details/{self.data_type}"

        detail_params = {
            "place_id": f"{self.place_id}",
            "fields": "business_status,opening_hours,formatted_phone_number,website",
            "language": "ja",
            "key": self.api_key
        }
        detail_params_encoded = urlencode(detail_params)
        detail_url = f"{detail_base_endpoint}?{detail_params_encoded}"
        r = requests.get(detail_url)
        return r.json()['result']

how_to_reply.py A class that enables you to respond to messages received from the other party.


import json

class create_reply_message(object):
    user_id = None
    user_dictionaries = None
    the_user_dictionary = None

    def __init__(self, user_id=None,*args, **kwargs):
        super().__init__(*args, **kwargs)
        self.user_id = user_id

        #Preparing a dictionary
        with open("users_info.json", 'r') as f:
            self.user_dictionaries = json.load(f)
            self.the_user_dictionary = self.user_dictionaries.setdefault(self.user_id, {})

    def legister_fav_shop_institution(self, shop_institute_actual_name, shop_institute_variable):
        user_dictionaries_copy = self.user_dictionaries.copy()
        the_user_dictionary_copy = user_dictionaries_copy[self.user_id]
        the_user_dictionary_copy[shop_institute_variable] = shop_institute_actual_name
        with open("users_info.json", 'w') as f:
            json.dump(user_dictionaries_copy, f)
        return 'Completion of registration!'

    def confirm_what_legistered(self):
        if self.the_user_dictionary == {}:
            reply_msg = "There are no registered shops / facilities yet ..."
            return reply_msg
        else:
            reply_msg = []
            for dict_key in self.the_user_dictionary:
                reply_msg.append(dict_key)
            reply_msg.insert(0, f'The registered shops and facilities are below{len(self.the_user_dictionary)}Tsu! !!')
            return "\Hmm·".join(reply_msg)

    def delete_fav_shop_institution(self, shop_institute_variable):
        user_dictionaries_copy = self.user_dictionaries.copy()
        the_user_dictionary_copy = user_dictionaries_copy[self.user_id]
        del the_user_dictionary_copy[shop_institute_variable]
        with open("users_info.json", 'w') as f:
            json.dump(user_dictionaries_copy, f)
        return shop_institute_variable + 'Is deleted!'

personal_informations.py Since it contains personal information, it will not be posted. I've added s to the uncountable noun information ...

confirm.txt A template text to send when you get information about a store / facility.

$I've seen the name!
$businessStatus

This week's schedule is ↓↓
$openingHours

If anything happens, contact the phone number below!
$phoneNumber

By the way, the homepage is ↓↓
$website

explanation.txt Text for the template to describe the bot.

$Thank you for contacting name!

$If you want to know the shops / facilities that name has registered so far
"Verification"Please send!
(Example: Confirmation)

$When you want to check the information of shops and facilities that name has registered so far
"Verification[Registered name]"Please send!
(Example: Confirmation library)

When you want to register new shop / facility information
"Registration[Official name of shop / facility] [Registered name]"Please send!
(Example: Registered Tokyo Institute of Technology Library)

On the contrary, when you want to delete the information of the shop / facility
"Delete[Registered name]"Please send!
(Example: Deleted library)

nice to meet you! !!

user_info.json A json file that stores user information. It didn't work with the pickle file, so I chose json. I wanted to use a database if possible.

{user_id: {"\u81ea\u8ee2\u8eca\u5c4b": "\u30b5\u30a4\u30af\u30eb\u30d9\u30fc\u30b9\u3042\u3055\u3072\u4e09\u9df9\u4e95\u53e3\u5e97", "\u3061\u305a\u3051": "\u6771\u4eac\u5de5\u696d\u5927\u5b66\u4ed8\u5c5e\u56f3\u66f8\u9928"}}

It's not explained at all, but I completed it like this. I'm a beginner, so even though it's Python, the code has become quite difficult to read, but if you're interested, please read it.

Actually use

Send an appropriate message

Send an appropriate message and it will return a line-bot description. image.png

Send the message "confirmation"

You can check the names you have registered so far! image.png

Send the message "Registration [Official name] [Name you want to register]"

You can newly register your favorite shops and facilities. Be sure to make the space between them full-width! image.png

Send the message "Delete [registered name]"

You can delete the shops / facilities registered so far. image.png

Check again here.

image.png

Send the message "Confirmation [Registered shop / facility]"

You can check business hours, phone numbers, and web pages to see if the store is open. image.png

Task

--The code is dirty. --The explanation is difficult to understand. --There is still little knowledge and few choices (in my own). --I haven't picked up the error (I should have got the error, but I don't know where it came from ... but it still works, but I wanted to find and fix it.) --After a certain amount of time (30 minutes), heroku's server turns off (money problem). The fatal problem that the information is reset when the server is turned off because I did it with the json file this time.

Impressions

There is no end to the list of bad things, but after all manufacturing is really fun! Since my major is mechanical engineering, I don't have many opportunities to write programming, and I may not have time to study other things because I'm going to be quite busy with laboratory-related classes, but I can come up with ideas and make things. It's the same in that respect, and I'm sure it will be beneficial. And above all, it's fun, so I'd like to continue programming.

Finally

It is a line-bot made by ↓. It was made by a beginner, and there are a lot of errors (I know a few, but I haven't fixed it, lol) I made it very hard! I would be grateful if you could add friends. messageImage_1602075610648.jpg

Recommended Posts

I made a Line-bot using Python!
I made a python text
I made a login / logout process using Python Bottle.
I made a fortune with Python.
I made a daemon with Python
I made a quick feed reader using feedparser in Python
I made a Chatbot using LINE Messaging API and Python
I made a payroll program in Python!
I made a character counter with Python
Beginner: I made a launcher using dictionary
I made a Hex map with Python
After studying Python3, I made a Slackbot
I made a roguelike game with Python
I made a simple blackjack with Python
I made a configuration file with Python
I made a neuron simulator with Python
〇✕ I made a game
I made a poker game server chat-holdem using websocket with python
I made a Chatbot using LINE Messaging API and Python (2) ~ Server ~
I made a python dictionary file for Neocomplete
I made a competitive programming glossary with Python
I made a weather forecast bot-like with Python.
I made a GUI application with Python + PyQt5
I made a Twitter fujoshi blocker with Python ①
Procedure for creating a LineBot made with Python
[Python] I made a Youtube Downloader with Tkinter.
I tried reading a CSV file using Python
I made a Caesar cryptographic program in Python.
I made a bin picking game with Python
I made a Mattermost bot with Python (+ Flask)
I made a Python Qiita API wrapper "qiipy"
I made blackjack with python!
[Python] I tried using OpenPose
I made a discord bot
I made blackjack with Python.
I made wordcloud with Python.
I made a Twitter BOT with GAE (python) (with a reference)
I made a prime number generation program in Python
I made a Christmas tree lighting game with Python
I made a net news notification app with Python
I made a VM that runs OpenCV for Python
I made a Python module to translate comment outs
I made a Python3 environment on Ubuntu with direnv.
I made a LINE BOT with Python and Heroku
[Python] I made a classifier for irises [Machine learning]
[Python] I tried running a local server using flask
I tried drawing a pseudo fractal figure using Python
I made a prime number generation program in Python 2
I made a python library to do rolling rank
I made a school festival introduction game using Ren’py
I tried using Python (3) instead of a scientific calculator
I made a script to record the active window using win32gui of Python
I made a simple typing game with tkinter in Python
I made a CUI-based translation script (2)
Create a python GUI using tkinter
I made a wikipedia gacha bot
I made a package to filter time series with python
Drawing a silverstone curve using python
[VSCode] I made a user snippet for Python print f-string
I made my own Python library
I made LINE-bot with Python + Flask + ngrok + LINE Messaging API