あらまし
住み着いているDiscordサーバで対話のできるBOTが動かせたら面白いなと思って、とりあえず簡単に動きそうなマルコフ連鎖を使ったBOTを作ってみた。
入力されたテキストを含むマルコフ連鎖のモデルを作って、それを元に返信する単純な学習機能を入れてます。
環境
私はUbuntuServerでscreenの中にvenvを建てて動かしてます。
こいつらを入れて動かします。
ライブラリのインストール
python3 -m pip install -U discord.py
py -3 -m pip install -U discord.py #Windowsの場合はこっち
pip install mecab-python3
pip install unidic-lite
pip install markovify
中身
BOTを動かしたいサーバのチャンネルIDとBOTのトークンは適宜書き換えてください。
discordbot.pyと同ディレクトリにm.txtを置いて動かします。m.txtにはある程度文章を入れておきます。
マルコフ連鎖に使うデータが無いと返信が帰ってこないのでモデル生成の部分は state_size=1 としています。会話を進めてある程度m.txtに文章量が集まったら1ずつ増やすといいです。
discordbot.py
import discord
import MeCab
import unidic_lite
import markovify
import random
CHANNELID = XXXXXXXXXXXXXXXXXXX #チャンネルID
TOKEN = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' #BOTのトークン
intents = discord.Intents.default()
intents.message_content = True
intents.messages = True
client = discord.Client(intents=discord.Intents.all())
@client.event
async def on_ready():
print('---------------------------------------------------')
print(' 起動しました ')
print('---------------------------------------------------')
@client.event
async def on_message(message):
if message.channel.id != CHANNELID:
return
if not message.author.bot:
channel = client.get_channel(CHANNELID)
m1 = (message.content)
# 末尾を"。"に定める
matubi = (m1[-1])
if matubi == "。":
m2 = m1
else:
m2 = m1 + "。"
# 学習データに書き込み
f = open('m.txt', 'a')
f.write(m2)
f.write("\n")
f.close()
# 学習データを読み込み
with open('m.txt', 'r') as f:
kotoba = f.read().split("\n")
print(m2)
# 話題になりそうなワードを抽出
mecab = MeCab.Tagger()
result = mecab.parse(m2)
l1 = [line.split()[0] for line in mecab.parse(m2).splitlines()
if '0' in line.split()[-1]]
l2 = [line.split()[0] for line in mecab.parse(m2).splitlines()
if '1' in line.split()[-1]]
l3 = l1 + l2
#リストを作成できなかった場合冒頭の単語を取る
kazu = len(l3)
if kazu < 1:
words = mecab.parse(m2).split()
#print(words)
wadai = words[0]
else:
wadai = random.choice(l3)
# 文章の処理
breaking_chars = ['(', ')', '[', ']', '"', "'"]
splitted_kotoba = ''
for line in kotoba:
parsed_nodes = mecab.parseToNode(line)
while parsed_nodes:
try:
if parsed_nodes.surface not in breaking_chars:
splitted_kotoba += parsed_nodes.surface
if parsed_nodes.surface != '。' and parsed_nodes.surface != '、':
splitted_kotoba += ' '
if parsed_nodes.surface == '。':
splitted_kotoba += '\n'
except UnicodeDecodeError as error:
print('Error : ', line)
finally:
parsed_nodes = parsed_nodes.next
# モデル作成
model = markovify.NewlineText(splitted_kotoba,well_formed=False,state_size=1)
# wadaiから続く文章を生成
sentence = model.make_sentence_with_start(beginning=wadai,strict=False)
if sentence is not None:
#。を除く
out = (''.join(sentence.split()))
out = out[:-1]
print(out)
else:
print('None')
out = 'None'
# discordに送信
await message.channel.send(out)
client.run(TOKEN)
雑にコピペしたりして書いたので蛇足な部分があるかも。
おわりに
偶に偶然人間らしく振る舞ったりしてなかなか面白いです。