Python3
Telegram

Telegram用の人工無能を作ってみた

概要

python-telegram-botモジュールを使って、人工無能というか自動応答BOTを実装しました。

経緯

GoogleのサービスでHangoutというものがあるのですが、2020年にサービスが終了になってしまうという話が出てきています。
チャット自体はTelegramやDiscordを使ってしまおうと思っているのですが、問題がありまして。

cc58b8865aa52f4589ddd56b1c5d1fdc.png
私が何時間も使って作ったBOTちゃんが使えなくなってしまうのでした。

https://qiita.com/Ovismeme/items/75b30d6d1b78e90d9ef8
これは前にこちらの記事であげたBOTですけれども、そもそもコア部分は
https://github.com/hangoutsbot/hangoutsbot
このプロジェクトで作られているので、技術的ハードルはほぼありませんでした。
クラウドからGoogleログインする、あたりができればそこまで問題が起きませんでしたので。

しかし、Telegramで自動応答を作ろうとすると、python-telegram-botというモジュールはあるのですが、ちょっと手を動かさないとダメですね。
中国の方が作りこんでそうなbotも見つけたのですが、せっかくのお正月なので作ってみることにしました。

大したコードでもありませんが本体3時間くらい、コマンド機能3時間くらいでなんだかんだ作れました。
その間集中しすぎで肝心の私の本体のほうが嫁の発話に応答しなかったため、色々問題がおきましたが、そんな話はおいといて。

導入方法

Telegram側

de2c064a206656ea41fb153f4400d782.png
「botfather」(公式のBOT管理アカウントです)というアカウントを探して話しかけると、自動応答でTOKENの発行までやってくれます。
baa6ea5bdf0a560d9d9eab2d0282ab43.png
739fe5f74ee28bd378054133f11db60c.png
こんな感じで対話式で画像変更までとっても簡単にできます。

開発環境

pip python-telegram-bot
だけはしておいてください。

ソースを放り込んでおいたので、
https://github.com/ovismeme/telegram_autoreply_bot
ここから引っ張ってください。
中のconfig.iniをsettingフォルダに投げ込んで、先ほど発行したAPIトークンを記入いただければ、
多分動くと思います。

419027a8bb2b83571365d675100b4e81.png
ほら動いた!

入っている発話は見ての通りあんまりというかかなりろくでもないのですが、「おみくじ」と入れていただければ私のぼやきにすぎないおみくじが100通り以上入っています。時間のムダオブジイヤー

あと、グループで動かすときはBOTに発言権限与えないとだめなので、そこはご注意を。

どうやって作ったか

サンプルソースに置かれていたechoBotを改造して、チャットの更新内容を見て返答をする仕組みを作りました。

autoreply.py
def autoreply(bot, replyLists):
    """autoreply the message the user sent."""
    global update_id
    # 前回更新以降の更新がないかを確認
    for update in bot.get_updates(offset=update_id, timeout=10):
        update_id = update.update_id + 1

        if update.message:  # メッセージ更新時に発火
            for reply_ptn in replyLists['autoreplies']:
                for reply_trgs in reply_ptn[0]:
                    matched = False
                    rcv_text = str(update.message.text)
                    if re.match('regex:', reply_trgs) is not None:
                        fix_reply_trg = reply_trgs.replace('regex:', '')
                        if re.match(fix_reply_trg, rcv_text) is not None:
                            matched = True
                    elif(rcv_text == reply_trgs):
                        matched = True

                    if(matched is True):
                        reply_len = len(reply_ptn[1])
                        random.seed
                        if reply_len != 1:
                            reply_point = random.randrange(reply_len)
                        else:
                            reply_point = 0
                        reply_text = reply_ptn[1][reply_point]
                        # リプライに"/がついていたら機能判定実施
                        if re.match('/', reply_text) is not None:
                            reply_text = checkReply(reply_text, rcv_text)
                        # Reply to the message
                        update.message.reply_text(reply_text)

あとは回答する中身ですね。
質問/回答の構造はHangoutBotから流用しました。

reply.json
{
  "autoreplies": [
    [
      [
        "regex:.*ちん(ぽ|こ).*",
        "regex:.*チン(ポ|コ).*"
      ],
      [
        "そいや!",
        "そいや!",
        "そいや!",
        "そいや!",
        "そいや!",
        "そいや!",
        "そいや!",
        "そいや!",
        "くいっ!"
      ]
    ]
  ]
}

{"autoreplies":[[発話1(,発話2)…],[回答1(,回答2)…]]…}
の構造で、発話配列のどれかに引っかかれば回答配列の中からランダムで返すようにしています。
発話の頭に"regex:"と書くと正規表現にも対応します。 性器だけにな!

この発話例でいうと、2パターンの正規表現のどちらかに引っかかると、
「そいや!」(89%)「くいっ!」(11%)の返答が来ますね。

単純に発話に対応するだけではつまらないので、コマンドを入れたらそっちに行く機能もつけています。
例えば/cpというコマンドを入れると、私が触っているIngressというゲームのチェックポイントを返してくれますね。
が、その辺説明すると長くなる上に大したソースでもないので、興味があったら覗いていただけると。

回答に「/」で始まるものが入っていると、コマンド解釈に流れるので、対応するコマンドを実装しておけば何かしら作れます。
reply.jsonも色々使いどころがありそうですし。

もし面白いのが作れたらぜひ投げつけていただけると中の人が喜びます。
何か不明な点や間違っているところがあったら教えてくださいませ。
autorepliesのほうも面白かったらどんどんmergeしちゃいますので、ぜひ投げつけてください!