読者です 読者をやめる 読者になる 読者になる

ゆっくりハイクラジオ

Ruby ハイク

「ゆっくり」で有名なAquesTalkのRubyバインディングが出たというので早速遊んでみました。
AquesTalk/Ruby - Ruby bindings for AquesTalk.
AquesTalkはWindows用ソフトなので今回はWindowsのRuby環境構築から始めました。

WindowsにRubyをインストール

(手順1)One-click Rubyをインストール
以上。
これでRuby1.8.6もirbrubygemsも一発で入ります。世の中は怖いぐらい便利なものがあるんですね。
ちなみにRailsを一発で入れるInstant Railsは学校のパソコンで利用したことがあります。これもオススメ。
テキストエディタサクラエディタをインストールしました。Fedoraではemacs使ってます。

AquesTalk Rubyのインストール

AquesTalk/Ruby - Ruby bindings for AquesTalk.
にあるとおり、rubygemsでaqtkパッケージをインストールすれば大丈夫です。これでAquesTalkのdllもインストールされます。
ちょっと喋らせるだけなら
require 'rubygems'
require 'aqtk'
AquesTalk::Da.play_sync('ゆっくりしていってね!!', 100)
でオッケーです。100という第2引数は喋る速度を表しています。
漢字→かな変換のKAKASIも組み込まれているので、ちょっとした漢字も読めます。
再生実行には同期再生と非同期再生があり、上の例は同期再生で、再生終了を待たずに返ってくる非同期再生の方法はAquesTalk/Ruby - Ruby bindings for AquesTalk.に例があります。

ゆっくりハイクラジオ

さて、ソースコード。前に組んだハイクのタイムラインを読むコードを流用してちゃっちゃ(のはずだった)とゆっくりしてみました。機能は3分おきにはてなハイクAPIから取得したパブリックタイムラインのデータを利用して、一番はてなスターの多い投稿の内容をDJゆっくりが読んでくれます。それだけです。

$KCODE = 's'
require 'rubygems'
require 'aqtk'
require 'open-uri'
require 'rexml/document'
require 'kconv'

# はてなハイクAPI参照
PUBLIC_TIMELINE_URI = "http://h.hatena.ne.jp/api/statuses/public_timeline.xml"

INTERVAL = 60*3  # 秒

#
# YukkuriHR
#
class YukkuriHR

  def run_yukkuri_process
    # INTERVAL毎にゆっくりする
    loop do
      begin
        yukkuri( "私は最終人道兵器ゆっくりDJちゃん、お便りを紹介するよー。" )
        parse_timeline_xml
        yukkuri( make_sentence )
        yukkuri( "でわでわ、次もゆっくりしていってね!!" )
      rescue => error
        puts error
        yukkuri( "エラーですが、あわてるな、孔明の罠だ。" )
      end
          
        sleep( INTERVAL )
    end
  end


  # タイムラインのXMLデータを取得、解析
  def parse_timeline_xml
    @data_set    = Hash.new  # 最終的に読ませるデータが格納される
    max_stars    = -1        # はてなスター数の最高値
    
    timeline_xml = REXML::Document.new( open( PUBLIC_TIMELINE_URI ) )
     
    timeline_xml.elements.each("*/status") do |status|
    
      # 現在の星の最高値よりも、現在読み込んでいる投稿の方が星が多いなら各ノードのデータを取り込む。
      # url等は削除し、ある程度多い文字数の内容でないと次点を読みにいく。
      if ( status.elements["favorited"].text.to_i > max_stars )
        keyword = status.elements["keyword"].text
        content = status.elements["text"].text.split(/=/)[-1]  # textの中身が「キーワード名=本文」という形式への対処
        
        content.sub!( /http:\/\/.+/, "" ) # 画像などは改行されるので、http://から改行までを置き換える。超適当。
        
        if ( keyword.split(//s).length >= 1 && content.split(//s).length > 4 ) # キーワードは1文字以上、投稿内容は4文字以上
          @data_set[:keyword] = keyword.tosjis
          @data_set[:content] = content.tosjis
          @data_set[:name]    = status.elements["user/name"].text
          
          max_stars = status.elements["favorited"].text.to_i
        end
      end
    end
  end
  
  
  # お喋りの内容
  def make_sentence
    sentence = "はてな県はてな市のid" + @data_set[:name] + "さんから"
    sentence << @data_set[:keyword] + "についてのお便りです。"
    sentence << @data_set[:content] + "だってさ"
    
    return sentence
  end
  
  
  # ゆっくりする
  def yukkuri( sentence )
    AquesTalk::Da.play_sync( sentence, 100 )
  end

end

#
# Main
#
start_comment = <<EOF
ピーピーガーガーピーピーガーガー
ゆっくりハイクラジオが起動しました。
EOF

AquesTalk::Da.play_sync( start_comment, 100)

yhr = YukkuriHR.new
yhr.run_yukkuri_process

終了はCtrl+Cでプロセス終了シグナルを送ってください。スレッドでコマンド処理をしたかったのだけど、Win32版Rubyは標準入力を受け取るgets等で他のスレッドも止めてしまうみたいですね(なんで動かないの、あれ〜?とプログラムを組んだ倍の時間を費やしてしまいました)。Ruby1.9以降では大丈夫っぽいです(http://arton.no-ip.info/data/Sapporo2008/ASR.pdf)。

課題点

  • 1件だけとかケチくさいことは言わず、APIから受け取ったデータを全部表示すればいーじゃん(DJゆっくりが喋らない間が寂しい)。
  • やっぱりこういう「人格」を立てるなら、定型文はかっこ悪いってカミナギの中の人も言ってた。
  • 超適当と書いてあるところが気がかり。

aqtk使いたいが為に書いただけなので、不安定にも程がありますが、手直しは暇があったらします。メールを音声で読んでくれるのにも需要があるのだし(車内等のハンズフリー環境が必要なだけだが)、twitterやハイクにもそういった機能が流行るといいのになあ。twitterはタイムラインが早すぎて非効率的にはなるのでしょうけどね。
最近のネット界隈での人工無能botブームに乗っかって考えると、声を発してくれた方が人間らしさが出るし、人間は突拍子の無い予期せぬ発言を人工無能に期待していると思う。だから音声で喋った上に、読み間違いとかしてくれた方が「人工無能らしさ」が一層引き立つのではないでしょうか。音声言語処理も面白そうだなあとかそんな事をつらうつらと考えてた徹夜明けでした。