[Node.js] Node.jsとTwitterAPIを使って文章生成(マルコフ連鎖もどき)をしてみる

初めに

今回はNode.jsとTwitterAPIを叩いて文章生成をしてみようと思います。

文章生成にはマルコフ連鎖を使用してみようと思いますが、あくまでもマルコフ連鎖もどきなので本来のものとは異なるかもしれません。ご承知おきください。

使用するもの

ソフトウェア

・Node.js
・VisualStudioCode (エディタ)
・MeCab (形態素解析) (mecab-ipadic-NEologd辞書使用)

モジュール

・mecab-lite
・twitter

作ってみる

1. サンプルを集める

まず初めに、文章生成するためにはサンプルが必要なのでサンプルを収集します。

サンプルですが、いろいろ悩んだ結果ツイートをサンプルにすることにしました。(楽なため)

ちなみにツイートですが、利用規約に適切な形であれば、利用者の許諾を得ずとも再利用が可能と記載されているためサンプルとして使用する分には問題は無さそうです。

ここではTwitterAPIのPublicStreamである”statuses/sample“を使用します。

statuses/sampleは、Twitterの全タイムライン上からランダムに選ばれたツイートをStreamで投げてくれるエンドポイントです。

それではTwitterAPIを叩いてから情報取得する部分までのソースコードを書いていきます。

client.stream('statuses/sample', function (stream) {
        stream.on('data', function (tweet) {
            if (tweet.in_reply_to_status_id === null) {
                if(!tweet.text.match(/RT|#|http|@/)) {
                    if(tweet.user.lang === "ja") {
                        if (tweet.source.match(/Twitter Web Client|Twitter for Android|Twitter for iPhone|Twitter for iPad/)) {
                            console.log("match: " + tweet.text)
                            learning(tweet.text)
                        }
                    }
                }
            }
        });
        stream.on('error', function (error) {
            console.log(error);
        });
})

このソースコードでは、取得したデータが以下の条件にマッチングした場合のみ学習するようになっています。

・特定のユーザーに対するツイート(リプライ/メンション)ではない
・ツイートの本文に「RT」「http」「#」「@」が入っていない
・クライアントが Twitter Web Client/Twitter for android/Twitter for iPhone/Twitter for iPad

2. 形態素解析して辞書を作成する

ここで、形態素解析で有名な”MeCab“を使用します。

ちなみにMeCabですが、備え付けの辞書だと最近の単語などが未知語として処理されてしまう(たとえば「けものフレンズ」であれば「けもの」と「フレンズ」で分けられてしまう)のでmecab-ipadic-NEologdという辞書を使用します。

これは週2回以上更新され、新語・固有表現に強く、語彙数が多いという最強の辞書です。使ってみるとわかりますが、本当に便利です。

ここからは取得したツイートを形態素解析して辞書登録するソースコードになります。

function learning(text) {
    mecab.wakatigaki(text, function (err, result) {
        if (err) throw err
        console.log(result)

        // 始端だった場合はその単語を登録
        var tmp = dictionaly["!SOS"]
        tmp.push(result[0])
        dictionaly["!SOS"] = tmp

        for (var i = 0; result.length > i; i++) {
            // その単語が辞書に登録されているか否か
            // されていなかったら辞書登録を済ませる
            if (dictionaly[result[i]] === undefined) {
                dictionaly[result[i]] = []
            }

            // 本処理
            if (result[i + 1] === undefined) {
                // 終端だった場合
                var tmp = dictionaly[result[i]]
                tmp.push("!EOS")
                dictionaly[result[i]] = tmp
                // 辞書ファイル保存する
                fs.writeFileSync('./dictionaly.db', JSON.stringify(dictionaly, null, '  '))
            } else {
                // 始端でも終端でもなかった場合
                var tmp = dictionaly[result[i]]
                tmp.push(result[i + 1])
                dictionaly[result[i]] = tmp
            }
        }
    })
}

3. 学習した辞書を使用して文章生成をする

ここでは、先程生成した辞書を使用して文章生成を行っています。

大まかに説明すると、始端をランダムで選択→その単語から!EOS(End of strings)が来るまでループ処理を行って文章生成をしています。

以下がソースコードです。

function markovchain() {
    var textbox = []
    var pre = dictionaly["!SOS"]
    var temp = pre[Math.floor(Math.random() * pre.length)]
    textbox.push(temp)
    while(true) {
        var textCd = dictionaly
        var temp = textCd[Math.floor(Math.random() * textCd.length)]
        if(temp !== "!EOS") {
            textbox.push(temp)
        } else {
            break
        }
    }
    return(textbox.join(""))
}

4. おわり

以上で文章生成が出来てしまいます。めっちゃお手軽。

Githubにて完全版のソースコードを公開していますのでもし良ければ。

コメント

タイトルとURLをコピーしました