2010年10月22日金曜日

Twitterbot移設メモ2

前回はGAE(Python)からPost成功したところまででした。

これからカーチャンbotのメッセージ選択アルゴリズムを移植します。

まずJavaScript動作のときの概要をちょっと書いておきます。

カーチャンbotは、全部で70種類くらいの定型文を用意しています。
お昼や夕食等の定刻用メッセージ、文中にユーザー名、商品名、などが入るものも含まれます。それら定型文自体をDOM要素として持たせていました。また、置換アイテムも同様です。

大雑把に書くと、
・定型文、置換アイテム、followerリストをデータとして持っている
・そしてそれらを使用したかどうかフラグを管理している(ストレージ等に書き出さないRAM上のもの)
・毎時ランダムに未使用のものを選ぶ
・定刻は定刻用定型文から引っ張ってくる
・通常時も、時間縛りあり定型文、時間縛りなし定型文がある
といった感じです。

毎時00分に、定型文をランダムに選び、時刻縛りがある場合はそれにあわせて、置換する必要があればアイテムもランダムに選び、そして投稿する文章が完成します。post完了後には、次の00分00秒000までの時間を計算して、setTimeoutで次の00分にまた同じことをするよう、仕込んでおきます。それを繰り返しています。
(0時過ぎのおやすみpost、followerリスト更新、などはまだ移植してないので、触れないでおきます)


GAE移植にあたって、これらデータの使用/未使用管理をどうするか、です。JavaScriptではRAM上でフラグ管理してました(のでブラウザ再起動で初期化されます)が、今度GAE移植して、cronで毎時動作させるとなると、いくら定型文使用/未使用のフラグをRAM上で管理しても、1回動作が終われば消えますから、ストレージに書き出さないとなりません。当然ですが。(むしろ今までが特異な動作原理のbotだっただけで)

ということで、僕はDBは全くわからないので、csv形式の生データファイルを読み書きする方向で行きます。(※最後に書いてありますが、ちなみにこの方法ではうまくいきません)

たとえば、

0,10-17,%A おかあさんちょっと買い物行って来るからね\n

という感じで。先頭が使用/未使用(1/0)、次が時刻指定/時間範囲縛り設定(なし=N,19時用=19,10時~17時用=9-18といった感じ)、最後が本文です。%AはJ( 'ー`)しに後で置換します。
これがずらーっと並んだデータファイルを作っておきます。

で、実際にPythonで読み込むときはこんな感じに。


import os
import random

# ファイル読み書きクラス
class fileAccess:
def __init__(self, src):
self.src = src
self.lines = []

def readData(self):
try:
f = open(self.src, 'r')
except IndexError:
print 'Index error'
except IOError:
print '"%s" cannot be opened.' % self.src
else: # no error
tmpLines = f.read().split('\n') # \n を区切りとしてファイル内容を読み込む
f.close() # ファイルクローズ

length = len(tmpLines) # 読み込んだ行数
for cnt in range(0, length):
str = tmpLines[cnt]
if str != "": # 空行は除外
self.lines.append(str)

def modifyData(self):
if len(self.lines) == 0:
print 'input lines has no data.'
return

tmpfile = "tmp_" + self.src
try:
f = open(tmpfile, 'w')
except IndexError:
print 'Index error'
except IOError:
print '"%s" cannot be opened.' % tmpfile
else: # no error
length = len(self.lines) # 読み込んだ行数
for cnt in range(0, length):
if self.lines[cnt] != "": # 空行は除外
f.write(self.lines[cnt] + "\n") # 引数の文字列をファイルに書き込む
f.close() # ファイルを閉じる

# ファイル操作: 変更前backupコピーを作成し 変更後tmpを正式にrename
bakfile = "bak_" + self.src
if os.path.exists(bakfile):
os.remove(bakfile)
os.rename(self.src, bakfile)
os.rename(tmpfile, self.src)

# 読み込んだ行をカンマで分けるクラス
class messageStruct:
def __init__(self, str):
tmp = str.split(',')
self.used = tmp[0]
self.timespan = tmp[1]
self.msg = tmp[2]

def setUsedStatus(self):
self.used = "1" # ものぐさで、int()で数値化してないで文字で判定してる

def clearUsedStatus(self):
self.used = "0"

def getCombinedStr(self):
return self.used + ',' + self.timespan + ',' + self.msg

# main
# データ読み込み
messageSource = fileAccess("msg.csv.dat")
messageSource.readData()

found = False
while found == False:
# ランダム
rndMax = len(essageSource.lines) - 1
i = random.randint(0, rndMax)

# カンマ区切りを各パラメータに分解
str = messageStruct(messageSource.lines[i])

if str.used == "0": # 未使用なのでメッセージ確定
str.setUsedStatus() # 使用済みに更新
messageSource.lines[i] = str.etCombinedStr()
found = True

# 略しますが、
# 必要があればuser名など置換してpost処理

# データ更新
messageSource.modifyData()


本当はもっと細かく、現在時刻取得して定刻用メッセージにするかどうか判定したり、置換アイテムが必要か、どの種のアイテムか、などいろいろやりますが、基本はファイル読んでランダムに選んで未使用なら採用、ってやってます。

が、ここで困ったことが。
実はGAEではファイルを静的なデータソースとして置くことはできるっぽいのですが、それを動的に更新したりはできません(知らずにLocalでターミナルからPython実行して↑の仕組み作ってた)。ので、この方法は、ランダムポストだけするには使えますが、本来の目的のどの定型文をポストしたかの管理を行うには、これでは不十分です。GAEのデータストアの方法を知らねばならないようです。僕がさっぱり知らない領域、DBに首を突っ込まねばなりません。

続く

2010年10月9日土曜日

Handycamについての連続Tweet

Handycamについて思うことTweetしてたのを、まとめたくなったので自分のblogに掲載。

---
#1
今日は子どもの運動会があるのでHandycamのHDDを空けとかなければいけない。まだ空きあると思うけど書き出しておく。

#2
子ども生まれてHandycam買ったはいいけど、全然撮る気にならないんだよね。ビデオ撮影って行為がどうにもつまんなくて。撮ったもの見返すと気に入らないんだよ。素人映像で。当たり前だけど。だって素人なんだから。

#3
なんていうか、写真はそれなりに構図とか思い描けるけど、動画の場合、そのイメージが湧かない。どんな長さのどんな映像のものを撮るか、なんて考えながら撮らない方がきっといいんでしょう。

#4
映画監督かっつーの。って。

#5
いや映像イメージは本当はあるんだよ。こうPANしていって、とか、ドリー撮影とか本当はしてみたかったり、Bird視点からの絵が欲しかったりさ。でもそれHandycam手に持った素人からかけ離れてるんだよ。

#6
そんな僕なので、Handycamってよくもまあ25年間たいして変わらないUXで商品売れてるもんだなぁと関心する。

#7
Handycamの話まだするけど、わかってはいますよ、そんなたいそうな「作品」作ろうなんて思わないで、スナップを撮るように、その出来事を記録しておくことが目的とか、そういうのは。

#8
でもそのわりにはさ、邪魔なんだよ、あれ。小さくなったとはいえでけーし時間かかるし手とか疲れるし何より目の前のことを見ていたい僕の裸眼の前に立ちふさがるわけですよあれ。

#9
時間を占有して!

#10
気軽に撮りたいけれど、気が軽くなれないんだ、あの機材。僕にとっては。

2010年10月6日水曜日

Twitterbot移設メモ1

自作Twitterbot(カーチャンbot)を移設しようとしています。※まだ移設できてません

現在は、この過去エントリにあるとおり、botはJavaScriptで動作させています。僕のMacのブラウザ(FF)上で。おかげでMac付けっぱなしです。また誰に@付きメッセージ送ったか、どの定型文を使ったか、などの管理がメモリ上で、なんらかのストレージに書き出してないので、ブラウザ閉じたり、Mac再起動すると、初期状態になります。ので、あまり再起動しないようにしてます(なるべく@付きで選ばれるユーザーは多くのfollowerさんに行き渡るようにしたいので)。

これはちょっと不便です。僕が。なのでサーバ借りてそっちに移そうかと考えていたところ、GAE(Google App Engine)でいいんじゃん?との提案を受けたので、現在移設チャレンジ中です。

とりあえずGAEというとJavaかPythonかになりますが、Pythonにしてみました。なんとなく未知で楽しそうだから。


■GAE開発環境設定
まず環境を用意しなくてはいけませんが、こちらを参考にさせていただきました。

BOT2UKU
http://sites.google.com/site/bot2uku/

Macなのでほとんどすることなしでした。
一応Hello Worldみたいなのはやってみました。それだけなら簡単。


■早速GAEからPost
次、Postできるかどうか試してみます。
Hello WorldのコードをごそっとTwitter投稿用に書き換えました。
以下の記事を参考にさせていただきました。

無題メモランダム: TwitterボットをOAuthに対応させてみた - Google App Engine(Python)
http://blog.mudaimemo.com/2010/03/google-app-engine-twitteroauth.html

すでにbotはJavaScript動作でOAuth対応は済んでおり、必要なキー等は揃っていたので、上記の記事の「2. Twitterにつぶやく」を参考に、そこのサンプルコードに取得済みのキー等を入れるだけでOKでした。(と、超簡単なはずが、AccessTokenとAccessTokenSecretを逆に入れていてそれに気付かずInvalid tokenとか言われて手こずってました)

ここで、cronの設定とか、その他設定、GAEに関していろいろ試してみたいところですが、いったんおいといて、次はbotの投稿メッセージ選択アルゴリズム(たいしたものではない)の移植に取り組みます。