週替わりギークス

24時間付き合ってくれる彼氏Botが完成! 満足できる仕上がりに

文●高桑蘭佳(らんらん) 編集● 上代瑠偉/ASCII

2020年06月16日 17時00分

 この処理は以下のように実装しました。引数は入力された単語(input_word)、1つ前のターンに送った単語(send_word)、すでに使った単語リスト(used_word)、小文字を大文字にするマッピング変換テーブル(komoji)です。


#私(user)のターンの条件を確認する関数
def user_turn(input_word, send_word, used_words, komoji):
    global message, search_word
    send_word_oomoji = send_word.translate(komoji)
    p = re.compile('[ぁ-ん]+')
    #入力された単語がひらがな以外の場合
    if not p.search(input_word):
        message = "ひらがなで入力して"
        search_word = 0
    #入力された単語が1文字以下の場合
    if len(input_word) < 2:
        message = "2文字以上じゃないとダメ"
        search_word = 0
    #入力された単語の頭文字が一つ前の単語の最後の文字と異なる場合
    if input_word[0] != send_word_oomoji[-1]:
        first_letter = input_word[0]
        #最後の文字が「ー」の場合、2番目の文字を見る
        if input_word[-1] == "ー":
            last_letter = send_word_oomoji[-2]
        else:
            last_letter = send_word_oomoji[-1]
        if first_letter != last_letter
            message = "最初の文字が間違っている"
            search_word = 0
    #入力された単語がすでに使われている場合
    if input_word in used_words:
        message = "この単語はすでに使われているよ\nしりとり終了\n最初からやり直して"
        search_word = 0
    #入力された単語が「ん」で終わる場合
    if input_word[-1] == "ん":
        message = "これは「ん」で終わる単語だよ\nしりとり終了\n最初からやり直して"
        search_word = 0

    #勝負が続く場合
    search_word = input_word
    message = 0

    return message, search_word

 条件をクリアできていなければ、ここで彼氏(bot)の勝ちが決まります。
クリアしていたら、次は彼氏(bot)のターンです。語彙リストの中から以下の条件に当てはまる単語を探します。

1.前の単語の最後の文字と最初の文字が一致している単語を探す
2.これまでに使われていないか

 条件に当てはまる単語が見つからなければ、私(user)の勝ちです。単語が見つかったら、勝負は続きます。

 この処理は以下のように実装しました。引数は彼氏が検討する(入力された)単語(input_word)、すでに使った単語リスト(used_word)、小文字を大文字にするマッピング変換テーブル(komoji)です。


#彼氏のターンで条件に当てはまる単語を語彙リストから探す関数
def kareshi_turn(search_word, used_words, komoji):
  #語彙リストのファイルを開く
    with open(‘kareshi_words.txt’) as f:
        kareshi_words = f.read()
       #改行で区切ってリスト化する
        kareshi_words_list = kareshi_words.split(‘\n’)
  #小文字を大文字に変換する
    search_word_oomoji = search_word.translate(komoji)
  #検討する単語の最後の文字が「ー」の場合
    if search_word_oomoji[-1] == ‘ー’:
        #最後から2番目の文字から始まる単語を語彙リストから探して、候補リストの入れる
        option = [s for s in kareshi_words_list if s.startswith(search_word_oomoji[-2])]
    else:
        #最後の文字から始まる単語を語彙リストから探して、候補リストの入れる
        option = [s for s in kareshi_words_list if s.startswith(search_word_oomoji[-1])]
  #候補リストの中から既に使われた単語を除く
    option_word = set(option) - set(used_words)
    #候補リストに単語が残らなかった場合
    if len(option_word) == 0:
        #彼氏が負けの場合のメッセージ
        message = ‘負けました’
        sent_word = 0
  #候補リストに単語が残った場合
    else:
        #返す単語を1つ選択する
        sent_word = option_word.pop()
        #返す単語の最後の文字が「ー」の場合
        if sent_word[-1] == 'ー':
            message = ‘▶︎ 次は「'+ sent_word[-2].translate(komoji) + '」から始まる言葉だよ'
        else:
            message = '▶︎ 次は「' + sent_word[-1].translate(komoji) + '」から始まる言葉だよ'
   #返信用のメッセージと返す単語を返却
    return message, sent_word

 以上の関数をベースにしりとりをします。

LINEのMessaging APIを設定する

 次にLINEのMessaging APIの準備をします。今回のように、BotとしてLINEを使用するにはLINE DevelopersでプロバイダーとMessaging APIチャネルを作成する必要があります。チャンネルの作成方法については、公式サイトにとてもわかりやすく載っているので、ぜひ参考にしてください。

 チャンネルの作成が完了したら、「Messaging API設定」を開きます。

 このページにある「チャネルアクセストークン」と「チャンネルシークレット」を発行してメモしておいてください。「チャンネル基本設定」から「LINE Official Account Manager」にアクセスすると、アイコンやチャンネルの説明などを変更することもできます。私はアイコンを彼氏の顔にしました。

 続いて、さきほど作成したしりとりのプログラムを、LINEメッセージの受け渡しを通じて動かせるように実装します。


# coding: UTF-8

import re
import os
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_bot_api = LineBotApi('チャネルアクセストークン’')
handler = WebhookHandler('チャネルシークレット')
#すでに使われた単語が保存されているファイルの場所
path = '/tmp/used_word.txt'

@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):
    #LINEから受け取ったメッセージ
    input_word = event.message.text
  #小文字を大文字にするためのマッピング変換テーブル
    komoji = str.maketrans({'ゃ': 'や', 'ゅ': 'ゆ', 'ょ': 'よ', 'っ': 'つ'})
  #すでに使った単語を記録したテキストファイルの存在を確認して開く
    if os.path.exists(path):
        with open(path) as f:
            words = f.read()
    #改行で区切ってリスト化する
        used_word = words.split('\n')
    else:
    #ファイルを作成する
        reset()
  #入力メッセージが「しりとりを始める」の場合
    if input_word == 'しりとりを始める':
    #すでに使った単語を保存したテキストファイルの中身をリセットする
        reset()
    #彼氏→私に送る単語を設定
        send_word = 'しりとり'
    #返信するメッセージを設定
        reply = 'しりとり \n\n ▶︎ 次は「り」から始まる言葉を入れて'
    #すでに使った単語として保存する単語を設定
        save_word = send_word
    #すでに使った単語を保存したテキストファイルに追記する
        write(save_word)
    else:
    #前に送った単語を確認する
        send_word = used_word[-1]
    #私のターンの条件を確認する
        user_reslut = user_turn(input_word, send_word, used_word, komoji)
    #私のターン条件をクリアしていなかった場合
        if user_reslut[1] == 0:
            reply = user_reslut[0]
        else:
      #彼氏のターンの条件を確認する
            kareshi_reslut = kareshi_turn(user_reslut[1], used_word, komoji)
      #彼氏のターンの条件がクリアできていなかった場合
            if kareshi_reslut[1] == 0:
                reply = kareshi_reslut[0]
            else:
        #彼氏のターンの条件がクリアできていた場合
                reply = kareshi_reslut[1] + '\n\n' + kareshi_reslut[0]
                send_word = kareshi_reslut[1]
    #すでに使った単語として保存する単語を設定
        save_word = '\n' + input_word + '\n' + send_word
    #すでに使った単語を保存したテキストファイルに追記する
        write(save_word)
  #LINEから返信メッセージを送る
    line_bot_api.reply_message(event.reply_token,TextSendMessage(text=reply))

#すでに使われた単語が保存されているファイルの中身をリセットorファイルを作成する関数
def reset():
    with open(path,'w') as f:
        f.write('')

#すでに使われた単語が保存されているファイルに追記する関数
def write(x):
    with open(path,'a') as f:
        f.write(x)

#私のターンの処理(省略)

#彼氏のターンの処理(省略)

if __name__ == ‘__main__’:
        app.run(host='127.0.0.1', port=8080, debug=True)

 かなり長くなってしまったのですが、以上を’main.py’として保存します。

Google App Engineにデプロイする

 Google App EngineはWebアプリケーションをPHP・Python・Java・Go言語を使用して開発し、Googleのインフラストラクチャー上で実行し、バージョン管理できるGoogleのサービスです。

 今回はこのGoogle App Engineにデプロイしてみようと思います。このツールのインストールと使い方については、私が説明する必要などないくらい公式ページに丁寧に書かれています。ここでは、簡単に手順を追えればと思います。

 コマンドプロントから以下のコマンドでGoogle Cloud SDKをインストールします。


$ curl https://sdk.cloud.google.com | bash
$ exec -l $SHELL 
$ gcloud init 

 次にプロジェクトの作成、アプリの作成、リージョンを選択します。


$ gcloud projects create [プロジェクトID] --set-as-default
$ gcloud app create --project=[プロジェクトID]

 準備が整ったら、デプロイするファイルの準備をします。

 すでに準備してある’mainpy’と’kareshi_word.txt’以外に以下のファイルを同じディレクトリに用意してください。

 ファイル名:app.yaml


runtime: python37

 ファイル名:requirements.txt


Flask==1.1.2
line-bot-sdk==1.16.0

 ファイルの準備ができたら、以下のコマンドでデプロイします。


$ gcloud app deploy

 デプロイ完了後、以下のコマンドを実行すると、ログを確認できます。


$ gcloud app logs tail -s default

 最後にLINE Developersに戻り、「Messaging API設定」の「Webhook設定」にある「Webhook URL」にhttps://[プロジェクトID].appspot.comを設定します。

彼氏botとしりとりをしてみた結果

 彼氏の語彙を使ってしりとりをしてくれるLINE Botが完成しました。

 メニューの設定も変更し、彼氏がいつも私をしりとりに誘ってくれる仕様にしました。彼氏の顔のアイコンで彼氏の語彙を使ってしりとりをしてくれます。個人的には非常に満足できる仕上がりとなりました。

 今回は1人遊び用のLINE Botを作成したため、データベースなどを使わずに簡易的に作成しましたが、今後複数人でも使えるようにデータベースを使った実装もしてみたいなと思いました。

 身近なパートナーなどに限らず、人気のキャラクターや著名人などの発言データをもとに、似たようなBotが作成できたら面白そうなので、ぜひ興味のある方は作ってみてください!

高桑蘭佳(たかくわらんか)

 1994年生まれ。石川県出身。東京工業大学大学院環境社会理工学院修士課程在学中。2018年8月にメンヘラテクノロジーを設立。彼氏を束縛したくて起業した大学院生として「アウト×デラックス」(フジテレビ系列)や、「指原莉乃&ブラマヨの恋するサイテー男総選挙」(AbemaTV)などに出演。

mobileASCII.jp TOPページへ