[PYTHON] Serverless LINE Bot that can be done in 2 hours (source identifier acquisition)

Motivated

――It's interesting to see the photos from high school and college recently. ――But it's annoying to find it every day --I want a bot that will post photos on time every day

――I want to start touching AWS ――It is troublesome to set up a server & increase the frustration rate -This article was discovered --Lambda makes server construction easy! !! !!

tl;dr The aim is ** in a group room containing a bot, when a specific word appears, one image is randomly acquired from the image placed in S3, and the bot returns the photo **

  1. Fire Lambda from LINE server
  2. Get the URL from RDS
  3. Send a POST containing the URL to the LINE server
  4. The S3 image is posted to the app

Is it the flow?

In addition, we will implement it so that we can also acquire the source identifier, which is a bottleneck in creating a LINE Bot.

Configuration diagram (scheduled to be completed)

Untitled Diagram.png

In this article, as the first step, I would like to use Lambda for the time being to check communication and play with various things.

Configuration diagram (current status)

Untitled Diagram-2.png

Get a LINE Bot account

https://business.line.me/ja/

First of all, let's register a business account here.

You will be asked about the type of job, but it is generally appropriate and ok (I don't remember the details, because I created an account last year ,,,) The occupation of the author is beauty

Then, there is "Create a business account" at the bottom of the "Account list" screen, so go here. スクリーンショット 2017-08-31 0.37.26.png

You will then be asked what kind of service your account offers, but here select the small "Start Developer Trial" at the bottom of the ** Messaging API **.

apapapap.png

This will make your account plan a Developer Trial. The big difference from the general free plan is

developper free
pushAPI OK NG
Number of friends that can be added 50 No limit

Developer Trial is enough if you make it as a hobby

Enter the account name, image, occupation, etc. to apply After that, it is easy to forget this part, but please move to ** LINE @ MANAGER **

Then you should come across this screen (account settings> Messaging API settings) スクリーンショット 2017-08-31 0.52.46.png

Let's proceed as it is Now it's sunny and the bot account creation is complete

Here, let's make a note of ** CHANNEL_ACCESS_TOKEN ** to connect the LINE server and Lambda. スクリーンショット 2017-09-01 14.26.12.png

Lambda function creation & Lambda => Connection setting to LINE server

Next, I would like to create a serverless server with Lambda and also set the connection to the Lambda => LINE server.

With AWS Lambda, you can run your code without provisioning or managing servers. You only pay for the compute time you actually use, and you don't pay when your code isn't running. With Lambda, you can run virtually any type of application or back-end service without the need for management. Once you've uploaded your code, Lambda does everything you need to run and scale your code for high availability. You can set your code to automatically trigger from other AWS services, or you can set it to call directly from your web or mobile application.

  1. Select Lambda from the AWS Console
  2. Create function
  3. Blueprint: Create from scratch
  4. Trigger: ʻAPI Gateway`
  5. API name: {optional}, security: open, deployed stage: prod
  6. Name: {optional}, Description: {optional}: Runtime: python3.6

This time, I will use python3.6 (w because I like it recently)

In fact, when you try to do something for a particular user group room using LINE's Messagein API, you get a destination identifier. this is,

You can specify the sender user, group, and talk room identifiers for Webhook events as destination identifiers. You cannot specify the LINE ID used in the LINE app.

It seems that. Even if the user who develops the bot has his / her own destination identifier written in LINE Developers, he / she does not know the identifiers of other user group rooms at all.

So, first of all, the code implemented in Lambda will ** return the destination identifier of the group user who sent to the bot **.

Below is the sample code I made


import urllib.request, json, os, ast

def lambda_handler(event, context):

    #Preparing to hit the LINE server
    url = "https://api.line.me/v2/bot/message/push"
    method = "POST"
    headers = {
        'Authorization': os.getenv("CHANNEL_ACCESS_TOKEN"),
        'Content-Type': 'application/json'
    }

    #Parse string to dict type
    apiParam = ast.literal_eval(event['body'])
    source = apiParam['events'][0]['source']

    sourceList = []
    for key, value in source.items():
        sourceList.append({"type": "text", "text": key + "#" + value})

    obj = {
        #Requests from the room are returned to the room. Others return to the caller.
        "to": source["roomId"] if "roomId" in source else source["userId"],
        "messages": sourceList
    }
    json_data = json.dumps(obj).encode("utf-8")

    #Prepare http request and POST
    request = urllib.request.Request(url, data=json_data, method=method, headers=headers)
    with urllib.request.urlopen(request) as response:
        response_body = response.read().decode("utf-8")
    return 0

Handler: index.lambda_handler Role: Create a custom role => Now add S3 object read-only access to your policy template. Let's make the others appropriately.

Also, set the following in the environment variable part

CHANNEL_ACCESSS_TOKEN:{CHANNEL that I wrote down on the LINE screen earlier_ACCESS_TOKEN}

Paste this and let's save

LINE server => Connection settings to Lambda

Finally, we will set up the connection from the LINE server to Lambda.

From the Lambda trigger item created earlier (see the figure below)

スクリーンショット 2017-09-02 22.17.31.png

I will pick up the URL, I am Method: AMY, so if you hit this URL with GET or POST, the code written in Lambda will be executed.

Now, set the URL for this firing on the LINE server.

Log in to LINE Developers and set it to Webhook URL

スクリーンショット 2017-09-02 22.22.58.png

At this time, be sure to add port number 443. Seems to be played (not tried)

This completes the LINE Bot on a sunny day.

Register as a friend from the QR code of LINE Developers and send something in the appropriate room 1to1 It should look like this These are the destination identifiers, in this case my own identifier and the identifier of the room I sent to are displayed

スクリーンショット 2017-09-02 22.56.19.png

tips1 Can I use an external library?

In Lambda, you can just write code and get on it, so in the initial state you can only use basic libraries. So, when I hit the API from Lambda, I couldn't use urllib2 and used urllib by pushing it. Actually, if you upload the zipped code and the library set, you can use the library, but I will introduce it next time.

tips2 Why are you parsed again?

A quick read of the LINE API Reference The webhook request was written as follows.

{
  "events": [
      {
        "replyToken": "nHuyWiB7yP5Zw52FIkcQobQuGDXCTA",
        "type": "message",
        "timestamp": 1462629479859,
        "source": {
             "type": "user",
             "userId": "U206d25c2ea6bd87c17655609a1c37cb8"
         },
         "message": {
             "id": "325708",
             "type": "text",
             "text": "Hello, world"
          }
      }
  ]
}

On the other hand, the arguments of Lambda are as follows

def lambda_handler(event, context):

They are included in the argument ʻevent`.

{
    ~~~~~Abbreviation~~~~~~~
    "body": "{"events":[{"type":"message","replyToken":"cd8477b1e2844fb7ac535ba8cfb7e604","source":{"userId":"Ue49159d045ba254087865fb1c09ce0e7","type":"user"},"timestamp":1504100774524,"message":{"type":"text","id":"6623088374597","text":"fewgvlkwgw"}}]}"
    ~~~~~Abbreviation~~~~~~~
}

It's stored as a character string ... I thought it was a dict type, and I was addicted to it ...

So

apiParam = ast.literal_eval(event['body'])

That's how I parse it.

Impressions

――Because it is serverless, there are few addictive elements ――I haven't used the push API even though I can use it with my LINE developers account. ――The feeling that the waste of python has been removed - ||ButorOr in phparray_key_exist()But in pythonA in BCan be felt from

Next time preview

next time ** RDS & S3 interlocking edition ** So, if you send "please", we will make a response from RDS (S3) with a random photo.

Recommended Posts

Serverless LINE Bot that can be done in 2 hours (source identifier acquisition)
Text analysis that can be done in 5 minutes [Word Cloud]
A story that heroku that can be done in 5 minutes actually took 3 days
Functions that can be used in for statements
Building Sphinx that can be written in Markdown
Morphological analysis and tfidf (with test code) that can be done in about 1 minute
A mechanism to call a Ruby method from Python that can be done in 200 lines
Basic algorithms that can be used in competition pros
ANTs image registration that can be used in 5 minutes
It seems that Skeleton Tracking can be done with RealSense
Goroutine (parallel control) that can be used in the field
Goroutine that can be used in the field (errgroup.Group edition)
Scripts that can be used when using bottle in Python
I investigated the pretreatment that can be done with PyCaret
Evaluation index that can be specified in GridSearchCV of sklearn
A record that GAMEBOY could not be done in Python. (PYBOY)
Make a Spinbox that can be displayed in Binary with Tkinter
A timer (ticker) that can be used in the field (can be used anywhere)
About character string handling that can be placed in JSON communication
Python standard input summary that can be used in competition pro
Make a Spinbox that can be displayed in HEX with Tkinter
Python standard module that can be used on the command line