[PYTHON] Play with GCP free frame ① ~ Cloud Run, Datastore & LINE Messaging API ~

About this article

Here's what you can do with GCP's free tier in several parts. The content of the free tier is subject to change, and pay-as-you-go ones may be charged if the limit is exceeded, so Official Information Please use at your own risk while checking = ja).

This time, we will link ** Cloud Run ** and ** Datastore ** with LINE's ** Messaging API ** to create the following simple bot. At the end of the article, I'll also introduce a slightly more practical bot created in the same way, so please take a look there as well (I implemented it on App Engine, but it has a lot in common).

4.png
  1. When you receive a message, record the time
  2. Return "Nice to meet you!" For the first time
  3. From the second time onward, the time of the latest message is returned (the image above is off by 9 hours due to the time difference in Japan)

A brief introduction to each service

Cloud Run A GCP service that allows you to run stateless containers in a serverless environment. This time it's just running Flask's web server, so using App Engine may be the royal road, but Cloud Run seems to have fewer articles, so I'll introduce it.

Datastore GCP's scalable NoSQL database. Since it is currently built into Firestore, we will use Firestore in Datastore mode to be exact. By the way, Official explains how to use Datastore mode and Native mode properly as follows.

For new server projects, use Cloud Firestore in Datastore mode.

Messaging API You can create a bot that runs on LINE. The created bot is linked to the LINE official account, so people who have registered as friends can use it.

Cloud Run settings

The following 3 files are prepared this time. Place them all in the same directory.

app.py First is app.py, which describes the main processing contents. The outline is based on here.

app.py


from flask import Flask, request, abort
from linebot import LineBotApi, WebhookHandler
from linebot.exceptions import InvalidSignatureError
from linebot.models import MessageEvent, TextMessage, TextSendMessage
import config #Messaging API access token, etc.
from google.cloud import datastore
import datetime
import os

app = Flask(__name__)
client = datastore.Client()
line_bot_api = LineBotApi(config.token)
handler = WebhookHandler(config.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'

@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
    user_id = event.source.user_id
    user_key = client.key("TestTable", user_id) #Get Key with kind and id as arguments
    user_entity = client.get(user_key) #Get Entity with Key as an argument
    if user_entity is None:
        user_entity = datastore.Entity(key=user_key, exclude_from_indexes=("timestamp",))
        msg = "Nice to meet you!"
    else:
        timestamp = user_entity["timestamp"]
        ts = datetime.datetime.fromtimestamp(timestamp/1000)
        msg = "{}Year{}Month{}Day{}Time{}Since minutes!".format(ts.year, ts.month, ts.day, ts.hour, ts.minute)
    user_entity.update({ #Entity update
        "timestamp": event.timestamp
    })
    client.put(user_entity) #Save argument Entity in Datastore
    line_bot_api.reply_message(
        event.reply_token,
        TextSendMessage(text=msg))

if __name__ == "__main__":
    app.run(debug=True, host="0.0.0.0", port=int(os.environ.get("PORT", 8080)))

The handle_message immediately after the @ handler.add decorator is the function that corresponds to the message from the Messaging API. The argument event contains various information such as the user_id of the sender (listed in here). Can be seen). I'm not familiar with Datastore related functions, so I've made a brief comment, but please check the Documentation for details.

config.py This is the file read by ʻimport config` in app.py. Access token etc. are set to link with Messaging API (confirmation method will be described later). You can write it directly to app.py, but it is recommended to make it a separate file so that it can be easily managed with .gitignore.

config.py


token = "xxxxx"
secret = "xxxxx"

Dockerfile Finally, the Dockerfile. The required Python packages are installed with RUN pip install ....

# Use the official Python image.
# https://hub.docker.com/_/python
FROM python:3.7

# Copy local code to the container image.
ENV APP_HOME /app
WORKDIR $APP_HOME
COPY . .

# Install production dependencies.
RUN pip install Flask gunicorn line-bot-sdk google-cloud-datastore

# Run the web service on container startup. Here we use the gunicorn
# webserver, with one worker process and 8 threads.
# For environments with multiple CPU cores, increase the number of workers
# to be equal to the cores available.
CMD exec gunicorn --bind :$PORT --workers 1 --threads 8 app:app

Deploy

When you reach this point, deploy with the following command. Please read the project name and region as appropriate. On the way, you will be asked ʻAllow unauthenticated invocations to [qiita-sample](y / N)?, But this time it is a test, so set it to y`. When you're done, check the URL from the GCP console.

gcloud builds submit --tag gcr.io/$gcp_project/qiita-sample
gcloud beta run deploy qiita-sample --image gcr.io/$gcp_project/qiita-sample --platform managed --region us-west1

console.png

Messaging API settings

First, log in to LINE Developers, go to Console, and select Provider (if not). Create).

1.png

If there is no channel yet, the screen below will be displayed. Go to the Create a Messaging API channel and fill in the required information.

2.png

Next is the setting change and confirmation.

--Check Channel secret from Basic Settings and Channel access token from Messaging API settings (issue with Issue if not issued) and describe in config.py. --Set Webhooks in Messaging API settings. This time, add / callback to the end of the URL confirmed on the Cloud Run console, and the URL as shown in the image below. After inputting, turn on ʻUse webhook. --Similarly, set ʻAuto-reply Messages to Disabled in Messaging API settings.

retry.png

The setting is completed up to this point.

Operation check

Add it to your LINE friends with the QR code or ID on the settings screen, and talk to them. If you have already deployed Cloud Run, you will get a reply as shown in the image at the beginning. You can also confirm that the latest response time is recorded normally from the Datastore console.

5.png

Finally

Actually, it was my first post, so I think there were many parts that were difficult to read, but I hope it will be helpful as much as possible. Finally, I would like to introduce the bot that I created as described in this article.

logo.png

The park is closed due to Corona, but it is a convenient bot at a theme park that I made dreaming of going to Disney again. If you invite with a QR code or ID (@ 541rhynx), you can ** split the bill ** or ** pair the vehicle ** in the LINE talk. This implementation is App Engine, but you should be able to do the same just by rewriting the app.py of the bot I made this time. The code and instructions are available on github.

Recommended Posts

Play with GCP free frame ① ~ Cloud Run, Datastore & LINE Messaging API ~
Play with GCP free frame ② ~ Airflow (on Compute Engine), Cloud Functions ~
Text extraction with GCP Cloud Vision API (Python3.6)
[GCP] [Python] Deploy API serverless with Google Cloud Functions!
[LINE Messaging API] Create parrot return BOT with Python
I made LINE-bot with Python + Flask + ngrok + LINE Messaging API
Play RocketChat with API / Python
[LINE Messaging API] Create a BOT that connects with someone with Python
Translate Coursera's WebVTT format subtitles with the GCP Cloud Translation API
LINE BOT (Messaging API) development with API Gateway and Lambda (Python) [Part 2]
Run Rotrics DexArm with python API
Run XGBoost with Cloud Dataflow (Python)
How to make an artificial intelligence LINE bot with Flask + LINE Messaging API