Line_bot

Posted on

あいさつするだけの LINE BOT

深夜 0 時に「お疲れさま!」っていうだけの LINE BOT を作ります。

LINE BOT 用のアカウントを作成

LINE developers からコンソールにログインします。

Create a new channel から Messaging API を作成します。

Messaging API の設定から、チャット系の機能を全て切ります。

Channel access token を生成し、その値を記録しておきます。

Basic settings から Channel secret を記録しておきます。

LINE BOT 用のスクリプトを作成

ソースをとりあえずぺっと貼ります。こんな感じになりました。 ここ1年以内に line-bot-sdk が v3 に移行したらしいです。

import os
import ssl
import uuid

from flask import Flask, abort, request
from linebot.v3 import WebhookHandler
from linebot.v3.exceptions import InvalidSignatureError
from linebot.v3.messaging import (ApiClient, BroadcastRequest, Configuration,
                                  MessagingApi, ReplyMessageRequest,
                                  TextMessage)
from linebot.v3.webhooks import MessageEvent, TextMessageContent

# 環境変数取得
CHANNEL_ACCESS_TOKEN = os.environ["CHANNEL_ACCESS_TOKEN"]
CHANNEL_SECRET = os.environ["CHANNEL_SECRET"]
CERTS_KEY_PATH = os.environ["CERTS_KEY_PATH"]
PEM_PATH = os.environ["PEM_PATH"]

app = Flask(__name__)
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
ssl_context.load_cert_chain(PEM_PATH, CERTS_KEY_PATH)


configuration = Configuration(
    access_token=CHANNEL_ACCESS_TOKEN)
handler = WebhookHandler(CHANNEL_SECRET)

daily_text = "今日もおつかれさま!"


@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:
        app.logger.info("Invalid Signature")
        abort(400)

    return 'OK'


@app.route("/daily", methods=['GET'])
def daily_message():
    with ApiClient(configuration) as api_client:
        line_bot_api = MessagingApi(api_client)
        broadcast_request = BroadcastRequest(
            messages=[TextMessage(
                text=daily_text)]
        )
        x_line_retry_key = str(uuid.uuid4())
        try:
            api_response = line_bot_api.broadcast(broadcast_request,
                                                  x_line_retry_key=x_line_retry_key
                                                  )
        except Exception as e:
            print(e)
    return 'the day ended'


if __name__ == "__main__":
    port = int(os.getenv("PORT", 5000))
    app.run(host="0.0.0.0", port=port, ssl_context=ssl_context)

dockerize

同じディレクトリに以下のような Dockerfile を置きます。

FROM python:3.12

WORKDIR /usr/src/app
ENV FLASK_APP=main

COPY requirements.txt ./

RUN pip install --upgrade pip
RUN pip install -r requirements.txt

んで、以下のような docker-compose.yml を置きます。

version: "3"
services:
  app:
    build: .
    ports:
      - ${PORT}:${PORT}
    container_name: daily-dev
    volumes:
      - ./:/usr/src/app
    command: gunicorn main:app
    environment:
      - CHANNEL_ACCESS_TOKEN=${CHANNEL_ACCESS_TOKEN}
      - CHANNEL_SECRET=${CHANNEL_SECRET}
      - PORT=${PORT}
      - CERTS_KEY_PATH=${CERTS_KEY_PATH}
      - PEM_PATH=${PEM_PATH}

それぞれの環境変数はそれっぽいのを入れてください。 ボクは自前のサーバーで LINE BOT を動かす関係で、自己証明ではない証明書を使用しています。 そのため、証明書関係の path を指定しています。

requirements.txt

ちなみに requirements.txt はこちら。

aenum==3.1.15 ; python_version >= "3.12" and python_version < "4.0"
aiohttp==3.9.1 ; python_version >= "3.12" and python_version < "4.0"
aiosignal==1.3.1 ; python_version >= "3.12" and python_version < "4.0"
annotated-types==0.6.0 ; python_version >= "3.12" and python_version < "4.0"
attrs==23.1.0 ; python_version >= "3.12" and python_version < "4.0"
blinker==1.7.0 ; python_version >= "3.12" and python_version < "4.0"
certifi==2023.11.17 ; python_version >= "3.12" and python_version < "4.0"
charset-normalizer==3.3.2 ; python_version >= "3.12" and python_version < "4.0"
click==8.1.7 ; python_version >= "3.12" and python_version < "4.0"
colorama==0.4.6 ; python_version >= "3.12" and python_version < "4.0" and platform_system == "Windows"
deprecated==1.2.14 ; python_version >= "3.12" and python_version < "4.0"
flask==3.0.0 ; python_version >= "3.12" and python_version < "4.0"
frozenlist==1.4.1 ; python_version >= "3.12" and python_version < "4.0"
future==0.18.3 ; python_version >= "3.12" and python_version < "4.0"
gunicorn==21.2.0 ; python_version >= "3.12" and python_version < "4.0"
idna==3.6 ; python_version >= "3.12" and python_version < "4.0"
itsdangerous==2.1.2 ; python_version >= "3.12" and python_version < "4.0"
jinja2==3.1.2 ; python_version >= "3.12" and python_version < "4.0"
line-bot-sdk==3.7.0 ; python_version >= "3.12" and python_version < "4.0"
markupsafe==2.1.3 ; python_version >= "3.12" and python_version < "4.0"
multidict==6.0.4 ; python_version >= "3.12" and python_version < "4.0"
packaging==23.2 ; python_version >= "3.12" and python_version < "4.0"
pydantic-core==2.14.6 ; python_version >= "3.12" and python_version < "4.0"
pydantic==2.5.3 ; python_version >= "3.12" and python_version < "4.0"
python-dateutil==2.8.2 ; python_version >= "3.12" and python_version < "4.0"
requests==2.31.0 ; python_version >= "3.12" and python_version < "4.0"
six==1.16.0 ; python_version >= "3.12" and python_version < "4.0"
typing-extensions==4.9.0 ; python_version >= "3.12" and python_version < "4.0"
urllib3==2.1.0 ; python_version >= "3.12" and python_version < "4.0"
werkzeug==3.0.1 ; python_version >= "3.12" and python_version < "4.0"
wrapt==1.16.0 ; python_version >= "3.12" and python_version < "4.0"
yarl==1.9.4 ; python_version >= "3.12" and python_version < "4.0"

うごかす

docker 化したので、docker compose up -d で動きます。

なお、自前サーバーで動かす場合は port 80, 443 を開けるのを忘れずに。

これで、/hello を GET することで友だち全員に労いの挨拶を送ることができます。

あとは、cron で、毎日 0 時に /hello を curl すればヨシです。