ケヴィンのなんかいろいろ

ハースストーンとかその他色々なことについて話すブログです

MENU

C#で人口無能と化した僕.botを作った

突然ですが僕の分身を作りました。2日で作った(コミットログ曰く)。

twitter.com

こいつについて書きます。

なにこれ?

僕(@kvin_MisterD)のツイートを取得し、形態素分析、そしてマルコフ連鎖を使ってツイートする文章を生成し、定期的にツイートするbot。 簡単に言うと僕っぽいツイートを良い感じに作って良い感じにツイートしてくれます。

大昔にあった劣化コピーとかいうやつが近いんじゃないかな。(調べる)うわまだあった!

rekkacopy.com

モチベーション

やりたいからやったんだよ文句あっか

実装とか

ソースはこちら。全部C#7.3で書いてます。

github.com

やってることは上に書いた通りなんですけど、大きく分けて3つ。

  1. ツイートを取得する
  2. 形態素解析して文節を抽出してテーブルを作る
  3. マルコフ連鎖(のような何か)を利用して、ツイートする文章を作る。
  4. ツイートする。

4つやんけ。まあ、ツイート取得とツイートするのはあんまり変わらないので一緒にするとして、これらをそれぞれ小見出しにして話します。

ツイートを取得する、ツイートする

最初は馬鹿正直に直接リクエスト送ろうとしてたんですけど、CoreTweetっていうくそつよライブラリがあったので使いました。先人の知恵って最高ですね。

github.com

Twitterを扱う用にTwitterBotってクラスを作ってやってます。ここで環境変数から値を取得する知見をゲットした。

ツイートするのはマジで1行だからソース適当に読んでほしいんですけど、取得する方がちょっとめんどくさかった。取得したやつをただ分析かけるだけだと、文章生成した時にURLとかハッシュタグが入っちゃってたんですよね。

httpsすき

ということでGetTweet()メソッドでツイートを取得するときに、頑張ってURLとハッシュタグをリストに加える前に削除してます。

//指定したユーザー名(screenName)のツイートを取得する
        public List<string> GetTweets()
        {
            var response = tokens.Statuses.UserTimeline(count => 200, screen_name => observation, exclude_replies => true, include_rts => false);
            var tweets = new List<string>();
            foreach (var tweet in response)
            {
                //URLを省くために頑張る
                var sb = new StringBuilder();
                var format = tweet.Text.Split(' ');
                foreach (var value in format)
                {
                    if (!(Regex.IsMatch(value, @"\As?https?://[-_.!~*'()a-zA-Z0-9;/?:@&=+$,%#]+\z") || Regex.IsMatch(value, "#")))
                    {
                        sb.Append(value);
                    }
                }

                tweets.Add(sb.ToString());
            }
            return tweets;
        }

Regex.IsMatch()の動作をいまいち把握してないけどこう書いたらなんかできるらしいです。できた。やったね!

形態素解析して文節を抽出してテーブルを作る

は?ってなりません?僕はなった。Wikipediaでも見とけ。

形態素解析 - Wikipedia

理論の話は置いといてマルコフ連鎖するのに必要なんですよね。

幸いC#くんにはNMeCabという、形態素解析をするときによく使われるMeCabっていうやつを使えるライブラリがありました。やったね!知らんけど。

ja.osdn.net

最終更新が15年の7月でウーンってはなったけど感謝。NuGetでインストールします。しました。

形態素解析用にKvinMeCabってクラスを作って形態素解析します。しました(GetNode(str)メソッド)。

形態素解析されたデータをもとにテーブル(普通の配列だけど)を作ります。文頭と文末を判別するために、それぞれ"[START]""[END]"を追加してます。

この時引っかかったのが謎のヌル文字が末尾に入っていること。たぶん形態素解析の仕様だと思うんですけど(名推理)。削除してテーブル(普通の配列だけど)にします。しました(GetSurface(str)メソッド)。

形態素解析できたね!

マルコフ連鎖(のような何か)を利用して、ツイートする文章を作る。

形態素解析された文を元にマルコフ連鎖でツイートする文章を作ります(タイトル通り)。

マルコフ連鎖もなんかよく分かんないけど前の単語を元に確率を見て次に繋げる単語を選ぶらしいっすよ。知らんけど。

マルコフ連鎖 - Wikipedia

で(急速話題転換)、今回実装してるものは前の単語2つを見て次の単語を選んでるだけです。確率考えたりしてないんですよね。マルコフ連鎖のような何かと書いた理由はここにあるわけです。

文字列生成はGenerateTextメソッドです。"[START]"を頭に持つやつを見つけて、"[END]"が末尾に来るまで良い感じに繋げてきます。良い感じに理解して。

ランダムでテーブルからピックするんですけど、乱数生成するのが難しかった。最終的にこんな感じ。

var guid = Guid.NewGuid();
var byteGuid = guid.ToByteArray();
var randomKey = BitConverter.ToInt32(byteGuid, 0);
var random = new Random(randomKey);
return candidate[random.Next(candidate.Count - 1)];

作った文章をツイート

わぁい

問題

  • そのまんまの文章が出る

APIの仕様上、取得できるのが直近200件な上RTとリプライが除外されてるので更に少ない。僕のツイートの7割はリプライとRTだ。

  • たまにAPI制限がかかる

ツイートするたびに200件取得してるので制限がかかって取得できなくなる時がある。あと重複取得もいっぱいあるので勿体ない。

  • 普通に使うWin機上で動いてるから電源落とすと動かない

さくらのVPS上で動かしたいんですけどCentOS上でC#って動くんですかね?

  • 空白が消える

URLを削除するのにString.Split(' ')をしてるので、本来文字の一つとしてあるべき空白が消える。悲しい。何とかしたい。

今後

  • ローカルにデータベースを保存する

Twitterはこれまでの全ツイートがCSVで貰えるので、それを解析してCSV(使ったことない)かJson(使ったことない)かMySQL(使ったことない)か何かでローカルに保存したい。ご飯が増えるのでツイートの幅も広がるし、取得する必要数も減るから良いんじゃないかな。

  • リプライも食べたい

URLを削除してる要領で@なんとか~も一緒に消せる気はするんだけど、あれ@って前は接地してても機能するじゃないですか。うーんこのって感じ。

  • VPS上で動かす

うごかしたい

知り合いと推し絵師がことごとく日曜日だったのでこれは行かなきゃなって思ってるんですけど金がキツイ。折角行くなら最低でも3万くらいは持っていきたい。今のままだと1万くらいしか持ってけない感ある。12月25日くらいまでに金が入るバイト探してます。

じゃあな!

高専プロコン民用Discord鯖作ってるからよかったら来てね。

discordapp.com

参考資料

mwc922-hsm.hatenablog.com

m76r.hateblo.jp