curious4dev

中国旅行、Arduinoなどを使った電子工作、その他色々。

*

寝坊検知&遅刻の言い訳提案システム #2

 

お疲れ様です。高橋です。

昨日作った遅刻の言い訳提案システムですが、Tweetの採取(search)と言い訳の提案(reply)、提案内容のA/Bテスト、寝坊した人の反応(ネガ/ポジ)を踏まえ、色々な知見を得ることが出来ました。

わかった事

  1. 土日の寝坊者は、遊び関連イベントへの遅刻が多い
  2. 個人に対するピンポイントなReplyなので、面白系の提案が来たらリツイートする率が高い
  3. いかにも自動的に生成した風なReplyのほうがポジ反応
  4. 10分前以上の「寝坊した」に提案するとネガ反応
  5. まるっきり的外れな提案するとネガ反応
  6. ドンピシャな提案するとポジ反応

対応した事

  1. 土日は完全対象外としました。
  2. 面白系をもっと増やそうと思います。
  3. もう少し「人間っぽい」パターンと「機械っぽい」パターンを継続し、ネガポジを見極めます。
  4. 毎分、1分以内の物にしか提案させないようにしました。
  5. これはもう、面白系の率を増やすしか無いかと思います。
  6. その人の過去Tweetの内容やTweet時間帯、プロフィール内容、Follower/Followの人たちを自動分析した上で出せれば究極。いつか、余力があったら。

コード

テーブル構造は最終的に下記の通り。

+------------+----------+------+-----+---------+-------+
| Field |
+------------+----------+------+-----+---------+-------+
| tweet_id | TwitterのStatusID
| user_id | TwitterのuserのID
| user_name | Twitterのscreen_name
| tweet_date | 寝坊Tweetの日時
| reply_date | 言い訳提案Replyの日時
| tweet | 寝坊Tweetの文言
| reply | 言い訳提案Replyの文言
+------------+----------+------+-----+---------+-------+

cron的に 「* 7-8 * * 1-5」(月曜~金曜 7時~8時 毎分)として動かすコードは下記の通り。

<?php
// initialize
require 'twitteroauth/autoload.php';
use Abraham\TwitterOAuth\TwitterOAuth;

// configure
$consumerKey = 'consumer keyを入れて下さい';
$consumerSecret = 'consumer secretを入れて下さい';
$accessToken = 'access tokenを入れて下さい';
$accessTokenSecret = 'access token secretを入れて下さい';

$db_host = 'dbのhost';
$db_user = 'dbのuser';
$db_pass = 'dbのpass';
$db_name = 'dbのname';

//$reply_tweet = 'もしかして寝坊しましたか?相手が納得出来る遅刻の言い訳を作るAndroidアプリは http://curious4dev.mydns.jp/ewake/redirect.php?tid=';
$reply_tweet = array('寝坊を検知しました。遅刻の言い訳を提案します。','もしかして寝坊しましたか?勝手に遅刻の言い訳を考えました!');
$sql_select = 'select count(1) as count from ewakeLog where date_add(reply_date, interval 24 hour) > now() and user_id = :user_id;';
$sql_insert = 'insert into ewakeLog (tweet_id, user_id, user_name, tweet, reply, tweet_date, reply_date) values(:tweet_id, :user_id, :user_name, :tweet, :reply, :tweet_date, now());';

// load file
$ewake_text = file('ewake.txt');

// conenct to mysql
$pdo = new PDO("mysql:dbname=" . $db_name, $db_user, $db_pass, array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET CHARACTER SET `utf8`"));

// create Twitter object and search from tweets
$twObj = new TwitterOAuth($consumerKey, $consumerSecret, $accessToken, $accessTokenSecret);
$search_key = "寝坊した";
$options = array('q' => $search_key, 'count' => '100', 'lang' => 'ja');
$json = $twObj->get('search/tweets', $options);

// check tweets
foreach ($json->statuses as $result) {
 // get parameters from tweet
 $tweet_id = $result->id_str;
 $user_id = $result->user->id_str;
 $tweet = $result->text;
 $user_name = $result->user->screen_name;
 $created_at = $result->created_at;

 // delete \n
 $tweet = str_replace("\r\n", '', $tweet);
 $tweet = str_replace("\n", '', $tweet);

 // is Reply?
 if (mb_substr_count($tweet, '@') > 0 ) {
 $isReply = true;
 } else {
 $isReply = false;
 }

 // is RT?
 if (strpos($tweet, "RT") ==false) {
 $isRT = false;
 } else {
 $isRT = true;
 }

 // is寝坊した?
 if (mb_strpos($tweet, $search_key) ==false) {
 $isNebou = false;
 } else {
 $isNebou = tue;
 }

 // with HashTag?
 if (strpos($tweet, "#") == false) {
 $isHashTag = false;
 } else {
 $isHashTag = true;
 }

 // is Fresh Tweet?(less than 1 minute)
 $now = strtotime("-1 min");
 $check = strtotime($created_at);
 if($now <= $check) {
 $isFresh = true;
 } else {
 $isFresh = false;
 }

 // check already send last 24 hour
 $statement = $pdo->prepare($sql_select);
 $statement->bindValue(':user_id', $user_id, PDO::PARAM_INT);
 $statement->execute();
 $count = 0;
 if ($row = $statement->fetch()) $count = $row['count'];
 if ($count == 0) {
 $isAlreadySend = false;
 } else {
 $isAlreadySend = true;
 }

 // send reply when not reply and not RT and not send
 if ($isReply == false && $isRT == false && $isAlreadySend == false && $isHashTag == false && $isFresh == true && $isNebou == true) {
 // send reply
 $tmp_text = $ewake_text[mt_rand(0,count($ewake_text)-1)];
 $tmp_text = str_replace("\r",'',$tmp_text);
 $tmp_text = str_replace("\n",'',$tmp_text);
 $tmp_text = str_replace("\r\n",'',$tmp_text);
 $ewake = $reply_tweet[mt_rand(0,1)] . '「' . $tmp_text .'」';
 $reply = '@' . $user_name. ' '. $ewake;
 $reply_json = $twObj -> post('statuses/update', ['status'=>$reply, 'in_reply_to_status_id'=>$tweet_id]);
 // insert to log when success
 $created_at = date('Y-m-d H:i:s', strtotime($created_at));
 $statement = $pdo->prepare($sql_insert);
 $statement->bindParam(':tweet_id', $tweet_id, PDO::PARAM_STR);
 $statement->bindParam(':user_id', $user_id, PDO::PARAM_STR);
 $statement->bindParam(':tweet', $tweet, PDO::PARAM_STR);
 $statement->bindParam(':reply', $reply, PDO::PARAM_STR);
 $statement->bindParam(':tweet_date', $created_at, PDO::PARAM_STR);
 $statement->bindParam(':user_name', $user_name, PDO::PARAM_STR);
 $statement->execute();
 }
}
?>

コードの中で、A/Bテスト用パラメータとして、人間っぽいのと機械っぽいのを設定しているのが下記の部分で、

$reply_tweet = array('寝坊を検知しました。遅刻の言い訳を提案します。','もしかして寝坊しましたか?勝手に遅刻の言い訳を考えました!');

↑の2つのどっちかをランダムに冒頭部分で使い、reply文言を生成してます。

$ewake = $reply_tweet[mt_rand(0,1)] . '「' . $tmp_text .'」';

あとは、

  1. 寝坊ツイートの中に @ が入っていたら提案しない
  2. 寝坊ツイートの中に # が入っていても提案しない
  3. RTされた寝坊ツイートにも提案しない
  4. 本当に「寝坊した」が含まれていないと提案しない
  5. 取得時点から1分以内のものにしか提案しない
  6. 24時間以内に同一寝坊者に再提案しない

という条件を定めています。

採用事例

採用してくれると、ちょっと嬉しい。

auto02

 

しかし、たまに「本当に人が送ってくれている」と誤認されている方がいらっしゃるようです。丁寧な御礼のリプライを頂いた事例が3例あり、いずれも年齢層若いような感じでした。

ネガにしろポジにしろ、反応がすぐに返ってくるから楽しいです。

 

 

 

 

もう、アプリじゃなくても良いんじゃないか?という考えが一瞬だけ頭をよぎりましたが、それは考えちゃダメだな、と。

 

明日の朝7:00~08:59がいよいよ平日の本番となります。

以上、よろしくお願い致します。

 - アプリ開発

  関連記事

URL付き言い訳提案システム 稼働初日

お疲れ様です。高橋です。 本日から、よりDL数を高める施策として、提案の中にUR …

西野カナ風な歌詞自動生成「カナかな?」をリリースしてみた。

お疲れ様です。高橋です。 昨日はずっと助詞に関する実装をしていたのですが、どうし …

遅刻の言い訳提案システム 稼働二日目

お疲れ様です。高橋です。 遅刻の言い訳提案システムについて、先日課題として上げた …

遅刻の言い訳提案システムとウコンの力

お疲れ様です。高橋です。 現在稼働を続けている遅刻の言い訳提案システムは、改めて …

【完全版】 Androidで広告ID(Advertising ID)を取得する方法

お疲れ様です。高橋です。 非常に長い時間掛けて他人に実機デバッグをやってもらう事 …

8bitサウンドを出すAndroidアプリをリリースしてみた。

お疲れ様です。高橋です。 先日の「Androidで8bitサウンドをモノフォニッ …

「カナかな?」の2週間分のダウンロード数

お疲れ様です。高橋です。 本日の貴重な帰宅後の時間は、妻からの「なんとかっていう …

SurfaceViewを使って絵を書き動かすサンプルをコピペして動かしてみた

お疲れ様です。高橋です。 本日はcocos2d-xの3.3rc0を導入しようと試 …

FreeなWindows向けDAWを使って作った音楽をwavからoggにしてAndroidアプリで鳴らしてみた。

お疲れ様です。高橋です。 先日POSTした「DAWを使って、ゲームの裏側で鳴らす …

広告IDが取得出来なかった理由がわかってきた。かな?

お疲れ様です。高橋です。 しばらく前からめぼしい更新を停止していた「カナかな?」 …