- 天気予報
- マルコフ連鎖で作文
2021/01/01
2012/04/06
原稿ヒイロbot EasyBotter.phpスケルトン
素のEasyBotter.phpはちょっと関数の並び方の基準がよく分からなかったので、自分に分かりやすいように並び替えています。ついでに、アクセス権付加の真似事のようなこともしています。元スクリプトはメソッドは全部public扱いだったような?
<?php
class EasyBotter {
/*=========================================== 変数宣言一式 */
/*=========================== コンストラクタ・デストラクタ */
//コンストラクタ
public function __construct() {
}
//デストラクタ
public function __destruct() {
}
/*============================== bot.phpから利用する関数群 */
//自動フォロー返し
public function autoFollow(){
}
//ランダムにポスト
//bot.php側で何も指定しなければdata.txtを見に行く
public function postRandom($datafile = DIALOG_DATA){
}
//順番にポスト
//bot.php側で何も指定しなければdata.txtを見に行く
public function postRotation($datafile = DIALOG_DATA, $lastPhrase = FALSE){
}
//リプライする
//bot.php側で何も指定しなければDIALOG_REPLY→DIALOG_DATAの順番で見に行く
public function reply($cron = 2, $replyFile = DIALOG_DATA, $replyPatternFile = DIALOG_REPLY){
}
/*===================================== プライベート関数群 */
/*------------------------------------- ツイート生成関数群 */
//通常の発言を作る
//$file:対象ファイル指定
//$number:対象ファイル内$number目の行を取得
private function makeTweet($file, $number = FALSE){
}
//キーフレーズ置換で発言を作る
private function makeSwapKeyPhraseTweet() {
}
//キーフレーズを元にした発言を作る
//$text:キーフレーズ取得対象文字列
private function makeKeyphraseTweet($text) {
}
//ガンダムリストに追加
private function addMemberToList($user_id) {
}
//ガンダムリストから削除
private function removeMemberFromList($user_id) {
}
//リプライを作る
//$replies:リプライ作成元文字列(配列)
//$replyFile:対象ランダムファイル
//$replyPatternFile:対象パターンファイル
private function makeReplyTweets($replies, $replyFile, $replyPatternFile){
}
//タイムラインへの反応を作る
//$timeline:
//$replyPatternFile:対象パターンファイル
private function makeReplyTimelineTweets($timeline, $replyPatternFile){
}
/*------------------------------------- ツイート操作関数群 */
//タイムラインの最近の呟きからランダムに一つを取得
private function getRandomTweet(){
}
//つぶやきの中から$minute分以内のものと、最後にリプライしたもの以降のものだけを返す
private function getRecentTweets($response,$minute){
}
//必要なつぶやきのみに絞る
private function selectTweets($response) {
}
//リプライ一覧から自分が既に返事したものを除く
private function removeRepliedTweets($response){
}
/*----------------------------------- キーワード変換関数群 */
//文章を変換する
private function convertText($text, $reply = FALSE){
}
//日付・時刻を変換
private function convertDateAndTime($text) {
}
//カウントダウンを変換
private function convertCountDown($text) {
}
/*----------------------------------------- HTML出力関数群 */
//HTML冒頭部分出力
private function printHeader() {
}
//HTML末尾部分出力
private function printFooter() {
}
//結果を表示する
private function showResult($response) {
}
/*----------------------------------- 内部データ保存関数群 */
//リプライツイートIDをログファイルに記録(どこまでリプライしたかを覚えておく)
private function saveLog() {
}
//ログの順番を並び替える(というかたぶん使用した行を最下部に移動するだけ)
private function rotateData($file) {
}
/*-------------------------------------- ファイルI/O関数群 */
//つぶやきデータを読み込む
private function readDataFile($file) {
}
//リプライパターンデータを読み込む
private function readPatternFile($file) {
}
/*------------------------------- TwitterAPIアクセス関数群 */
//基本的なAPIを叩く
private function _setData($url, $value = array()) {
}
private function _getData($url) {
}
private function setUpdate($value) {
}
private function getFriendsTimeline() {
}
private function getReplies($page = false) {
}
private function getFriends($id = null) {
}
private function getFollowers() {
}
private function followUser($screen_name) {
}
private function createListMember($list_id, $user_id) {
}
private function destroyListMember($list_id, $user_id) {
}
}
/*=========================================== その他関数群 */
function is_noun($word) {
}
?>
2012/04/05
名詞入れ替えで作文
EasyBotter.phpを以下のように改造して様子見中。あまり正規表現に詳しくないので悲惨なことになっております。
template.csvはあらかじめ作成していたものを、word.csvは、キーフレーズ抽出時にこっそり保存していたものを流用しています。
class EasyBotter {
// キーフレーズ置換で発言を作る
private function makeSwapKeyPhraseTweet() {
$keyphrase = array();
$poem = array();
$table = "。";
$status = "";
// キーフレーズCSVを読み込み
$fp = fopen('word.csv', 'r') or die('ファイルが開けません');
while(($columns = fgetcsv($fp, 4096, ",", '"')) !== FALSE) {
array_push($keyphrase, $columns[0]);
}
fclose($fp);
shuffle($keyphrase);
// 原文CSVを読み込み
$fp = fopen('template.csv', 'r') or die('原文ファイルが開けません');
while(($columns = fgetcsv($fp, 4096, ",", '"')) !== FALSE) {
array_push($poem, array($columns[0], $columns[1]));
}
fclose($fp);
// 名詞を適当に入れ替える
$keyphrase_num = count($keyphrase);
$rd_keys = array_rand(array_filter($poem, 'is_noun'), $keyphrase_num);
for($i=0; $i<$keyphrase_num; $i++) {
$poem[$rd_keys[$i]][0] = $keyphrase[$i];
}
// テーブル作成
for($i=0; $i<count($poem); $i++) {
$table .= $poem[$i][0];
}
// 一致している間は選びなおす
$status_1 = "";
$status_2 = "";
while($status_1 === $status_2) {
// キーフレーズを選出×2
$rd_keys = array_rand($keyphrase, 2);
$matches_1 = array();
$matches_2 = array();
$pattern_1 = '/^(.*)[。?](.*?)'.$keyphrase[$rd_keys[0]].'(.*?[。?])/u';
$pattern_2 = '/^(.*)[。?](.*?)'.$keyphrase[$rd_keys[1]].'(.*?[。?])/u';
preg_match_all($pattern_1, $table, $matches_1);
preg_match_all($pattern_2, $table, $matches_2);
$status_1 = $matches_1[2][0].$keyphrase[$rd_keys[0]].$matches_1[3][0];
$status_2 = $matches_2[2][0].$keyphrase[$rd_keys[1]].$matches_2[3][0];
}
$status = "「".$status_1.$status_2."」";
return $status;
}
// 途中省略
private function makeReplyTweets($replies, $replyFile, $replyPatternFile){
if(empty($this->_replyPatternData[$replyPatternFile]) && !empty($replyPatternFile)){
$this->_replyPatternData[$replyPatternFile] = $this->readPatternFile($replyPatternFile);
}
$replyTweets = array();
foreach($replies as $reply){
$status = "";
// 追加ここから
if(strpos((string)$reply->text, "作文して") !== FALSE) {
// キーフレーズで作文
$status = $this->makeSwapKeyPhraseTweet();
}
// 追加ここまで
// 以下省略
}
}
}
各データファイルの構造
word.csv
1行1カラムの単純なデータです。相手のキーフレーズ+定型文で作文 でこっそり保存していたものです。
"スカイツリー" "お台場" "実績取り" "競合他社" "以下略" "デスマッチ" "中心" "沿岸部"
template.csv
元となる作文をあらかじめ形態素解析しておいたものです。この中から名詞をランダムに取り出して、word.csvの中身と入れ替えています。
"太陽系","名詞" "に","助詞" "生物","名詞" "が","助詞" "生息","名詞" "する","助動詞" "こと","名詞" "を","助詞" "奇跡的","形容動詞" "に","助詞" "可能","名詞" "に","助詞" "し","動詞" "た","助動詞" "惑星","名詞" "、","特殊" "それ","名詞" "が","助詞" "地球","名詞" "で","助動詞" "ある","助動詞" "。","特殊"
特定の日付までのカウントダウン
EasyBotter.phpを以下のように改造します。
例によってあまり賢い方法ではありません……。
class EasyBotter {
// 途中省略
// 文章を変換する
private function convertText($text, $reply = FALSE){
// 途中省略
// 追加ここから
// カウントダウン
if(strpos($text, "{countdown}") !== FALSE){
$text = $this->convertCountDown($text);
}
// 追加ここまで
// フッターを追加
$text .= $this->_footer;
return $text;
}
// カウントダウンを変換
private function convertCountDown($text) {
$return_text = "";
// デリミタで分割
$event_array = explode( ",", $text);
$target_array = explode("-", $event_array[0]);
// 目標の日付
$target_date = mktime(0, 0, 0, $target_array[1], $target_array[2], $target_array[0]);
// 今日の日付
$current_date = mktime(0, 0, 0, date("n"), date("j"), date("Y"));
// 差を計算
$interval = ($target_date - $current_date) / 86400;
// 日付を日本語表記に
$event_array[0] = date("Y年n月j日", $target_date);
if($interval > 0) {
// 日程より前
$return_text = $event_array[0].$event_array[1]."の".$event_array[2]."まで、あと".$interval.$event_array[4]."……。";
} elseif($interval == 0) {
// 当日
$return_text = "今日は".$event_array[1]."の".$event_array[2]."当日だ。任務了解。明朝より作戦行動に入る。";
} elseif($interval == -1) {
// 昨日
$return_text = $event_array[0].$event_array[1]."は、昨日".$event_array[2]."を完了している……任務、完了。";
} else {
// 2日前以前
$return_text = $event_array[0].$event_array[1]."は、".abs($interval).$event_array[4]."前に".$event_array[2]."を完了している……。";
}
return $return_text;
}
// 以降省略
}
パターンファイルやランダムファイルの方では、例えば以下のように記述しています。
2012-4-26,ガンダムエース6月号,発売,{countdown},日
2012-5-3,SUPER COMIC CITY 21 1日目,開催,{countdown},日
電力予報
全面的にTwitterBotPHP掲示板の天気予報機能を参考にしています……いたと思います。
EasyBotter.phpの改造ですが、改造箇所が複数に亘るのでご注意ください。
また、Yahoo!デベロッパーズネットワークの電気予報APIを使用しますので、前もってアプリケーションIDを取得しておいてください。
class EasyBotter {
// 途中省略
// まるっと関数を新造
function makePowerForecastTweet($text){
$api_key_yahoo = '取得したアプリケーションID';
// いつの?
$today = date("Ymd", time());
$tomorrow = date("Ymd", time()+(24*3600));
$dayaftertomorrow = date("Ymd", time()+24*3600*2);
$w_day = array(
"今日"=> $today, "きょう"=> $today,
"明日"=> $tomorrow, "あす"=> $tomorrow, "あした"=> $tomorrow,
"明後日"=> $dayaftertomorrow, "あさって"=> $dayaftertomorrow
);
foreach( $w_day as $w_time => $w_timeNo){
if(preg_match( "/".$w_time."/u", $text)) {
$timeName = $w_time;
break;
}
}
if(empty($timeName)) {
$timeName = $today;
}
$day = $w_day["$timeName"];
// どこの?
$w_city = array(
"東北"=>"tohoku",
"東京"=>"tokyo", "関東"=>"tokyo", "東電"=>"tokyo",
"中部"=>"chubu", "名古屋"=>"chubu",
"大阪"=>"kansai", "関西"=>"kansai", "関電"=>"kansai",
"九州"=>"kyushu", "福岡"=>"kyushu"
);
foreach( $w_city as $w_area => $w_areaNo){
if(preg_match( "/".$w_area."/u", $text)) {
$cityName = $w_area;
break;
}
}
if( empty($cityName) ){
$w_flg = FALSE;
$cityName = "東京";
}
$where = $w_city["$cityName"];
// Yahoo!電力予報APIからPHP切片を取得
$powerforecast_url
= "http://setsuden.yahooapis.jp/v1/Setsuden/electricPowerForecast?appid="
.$api_key_yahoo."&area=tokyo&date=".$day;
$forecastxml = simplexml_load_file($powerforecast_url);
// 配列に押し込む
$i = 0;
$powers = array();
foreach($forecastxml->Forecast as $forecast){
if(!is_array($forecast)) {
$hour[$i] = intval($forecast->Hour);
$percent[$i] = round((intval($forecast->Usage)/intval($forecast->Capacity))*100);
$i++;
}
}
// 最大値検出
array_multisort($percent, SORT_DESC, $hour, SORT_ASC);
// メッセージ整形
$maxs = array();
$times = "";
for($i = 0; $i < count($hour); $i++) {
if($percent[$i] === $percent[0]) {
array_push($maxs, $hour[$i]."時");
} else {
break;
}
}
if($day === $today) {
$timeName .= "のこれから";
}
if($i > 1) {
$times = "のだいたい".$i."回";
}
$status = $timeName."の電力最大使用率は".$percent[0]."%で、ピークは"
.join($maxs, "、").$times."だってさ。";
return $status;
}
// 途中省略
//リプライを作る
function makeReplyTweets($replies, $replyFile, $replyPatternFile){
if(empty($this->_replyPatternData[$replyPatternFile]) && !empty($replyPatternFile)){
$this->_replyPatternData[$replyPatternFile] = $this->readPatternFile($replyPatternFile);
}
$replyTweets = array();
foreach($replies as $reply){
$status = "";
// ここから追加
if(strpos((string)$reply->text, "電力") !== FALSE) {
$status = $this->makePowerForecastTweet((string)$reply->text);
}
// ここまで追加
// リプライパターンと照合
if(empty($status) && !empty($this->_replyPatternData[$replyPatternFile])){
// 以降省略
}
登録:
投稿 (Atom)