LineBot에서 애견 "모나카 Bot"을 만들어 보았습니다.



LineBot 해 보았습니다.
돈이 아쉽기 때문에 GAE로 구축했습니다.
Java는 힘들기 때문에 Python/Flask 사용했습니다.

GCP로 프로젝트 생성



처음 쪽은, 빙글빙글 나옵니다.

app.yaml 준비



소스는 이런 느낌.

app.yaml
runtime: python27
api_version: 1
threadsafe: yes

- url: .*  # This regex directs all routes to main.app
  script: main.app

libraries:
- name: ssl
  version: latest

처음에는 ssl 라이브러리를 추가하지 않고 끼워 넣었습니다.

callback 구현



사용자가 Bot에 대해 말하면 callback에 지정된 API가 호출됩니다.
callback 안에서 Line의 API를 불러 텍스트나 사진을 보내는 느낌입니다.
callback 설정 등은 매뉴얼이나 다른 qiita를 참조하십시오.

소스는 이런 느낌.

main.py
# -*- coding: utf-8 -*-

import logging, random
import requests

from flask import Flask, request,Response

app = Flask(__name__)
app.config.from_object(__name__)
app.logger.setLevel(logging.DEBUG)

LINE_ENDPOINT = "https://trialbot-api.line.me"
HEADERS = {
    "X-Line-ChannelID": "<BasincInformation参照>",
    "X-Line-ChannelSecret": "<BasincInformation参照>",
    "X-Line-Trusted-User-With-ACL": "<BasincInformation参照>"
}

# 固定で返すメッセージ群
TALKS = [
    "わんわん!ごはんよこせ!!",
    "うんこ・・・したい・・・・",
    "しっこ!しっこ!",
    "飼い主どこ行ったのかな",
    "しのとも〜〜〜",
    "んぐ〜んぐ〜〜",
    "へっへっへっへっへっへっ",
    "Uo・ェ・oU",
    "ペロペロペロペロ",
    "かいぬしの手をペロペロしたいなぁ",
    "ごはん落ちてないかな",
    "すやすやすやすや",
    "おらおらー!",
    "ダンス!ダンスダンス!!"
]

# 画像群
IMAGES = [
    {"origin": "https://storage.googleapis.com/linebot-1275.appspot.com/monaka1.jpg",
     "thumb": "https://storage.googleapis.com/linebot-1275.appspot.com/monaka1thum.jpg"}
]


@app.route("/")
def hello():
    return "line bot api"


@app.route("/callback", methods=["POST"])
def callback():
    # TODO Signature validation

    app.logger.info(request.json)
    app.logger.info(request.headers)
    req = request.json["result"][0]

    if req["eventType"] == "138311609100106403":
        """
        友だち申請の受信はここに来る。
        申請されたらすぐお礼メッセージを送る。
        TODO 未検証
        """

        send_text([req["from"]], u"もなかだよ。友だち申請ありがとわん。")

    elif req["eventType"] == "138311609000106303":
        """
        会話メッセージを受信したらここに来る。
        「もなか」と声をかけると写真とメッセージを返す。
        それ以外は準備したテキストをランダムで返す。
        """

        to = [req["content"]["from"]]
        if req["content"]["text"] == u"もなか":
            # 写真送付
            i = random.randint(0, len(IMAGES) - 1)
            send_picture(to, IMAGES[i])
            send_text(to, "よんだー?")
        else:
            # メッセージ送信
            i = random.randint(0, len(TALKS) - 1)
            send_text(to, TALKS[i])

    # 戻り値は200固定
    return Response(status=200)


def send_text(to, text):
    """
    toに対してテキストを送る
    """
    content = {
        "contentType": 1,
        "toType": 1,
        "text": text
    }
    events(to, content)


def send_picture(to, img):
    """
    toに対して画像を送る
    """
    content = {
        "contentType": 2,
        "toType": 1,
        "originalContentUrl": img["origin"],
        "previewImageUrl": img["thumb"]
    }
    events(to, content)


def events(to, content):
    """
    toに対してデータ(テキスト・画像・動画)を送る
    """
    app.logger.info(content)
    data = {
        "to": to,
        "toChannel": "1383378250",
        "eventType": "138311608800106203",
        "content": content
    }
    r = requests.post(LINE_ENDPOINT + "/v1/events", json=data, headers=HEADERS)
    app.logger.info(r.text)


staticIPAddress 설정



서버가 허용 목록이므로 IPAddress를 설정하지 않으면 Line의 서버가 오류를 반환합니다. 그러나 GAE이므로 고정 IPAddress는 없습니다.
시도에 액세스하면 403 오류가 발생하고 다음 메시지가 나타납니다.

{"statusCode":"427","statusMessage":"Your ip address [107.178.194.118] is not allowed to access this API."}

따라서 IPAddress를 추가하고 이동하면

{"statusCode":"427","statusMessage":"Your ip address [107.178.194.122, 10.128.141.149] is not allowed to access this API."}

다음은 내부 IPAddress 같은 것도 설정하라고 나왔으므로 솔직하게 설정합니다.

이것으로 움직였습니다. 언젠가 IPAddress가 바뀌어 움직이지 않을 가능성이 높습니다. 해결 방법은 미래의 나에게 맡기고 싶습니다.

친구 신청하기



QR코드에서 할 수 있는 것 같습니다. (몰라서 계속 괴로워했다)
이번 내 애견 「모나카 Bot」은



에서 추가할 수 있습니다.

좋은 웹페이지 즐겨찾기