Λάδι Βιώσας

http://profile.hatena.ne.jp/kenkitii/

音声認識システム Julius を使って twitter に投稿する ruby スクリプト

最近、急に自分の周辺で非技術者の人から twitter の話題を聞くことが多くなりました。うーんツイッター流行ってきてるんだなー、じゃなんかネタスクリプトでも書いてみよっかな、、、と30秒ほど考えて「リアルにつぶやいた内容を音声認識してツイッターにポストするか」と思いつきました。

が、しかし、誰でも思いつくことは同じで、あちこちで似たような事をしている人がいたので、やっぱやめるかと思ったものの、クリスマスで暇だし、Mac OSX上でやってる人は見つけられないしで、勢いで音声入力システムの Julius を利用したツイッター投稿スクリプト書いてみました。ちなみに環境は、Mac OSX 10.5.8 + ruby 1.8.7 です。

音声認識システム Julius のインストール

まず Julius の cvs から最新のソースをダウンロードしてコンパイル&インストールします。インストール先は、prefixで適当に好きなところに設定してください。

% cvs -z3 -d:pserver:anonymous@cvs.sourceforge.jp:/cvsroot/julius co julius4
% cd julius4
% ./configure --prefix=$HOME/bin
% make
% make install

次に Julius のホームページから Linux版 Juliusディクテーション実行キット v4.0 をダウンロードし、適当なフォルダに展開します。ここでは、~/local/dictation-kit-v4.0 に展開しました。

Julius の起動テスト

展開したフォルダにある設定ファイル(fast.jconf) を -C オプションで指定して、以下のように Julius を起動します。

julius -C ~/local/dictation-kit-v4.0/fast.jconf -charconv EUC-JP UTF-8

すると、起動ログが表示されたあとに

<<< please speak >>>

ってでますんでマイクに向かって「こんにちは!」ってしゃべると

pass1_best:  今日 は 、           
sentence1:  こんにちは 。 

こんな感じ↑で音声認識されます。

ruby から Julius を使う

Julius とアプリケーションを連携させるにはいくつか方法があるんですが、Julius をモジュールモードで起動するのがお手軽そうなのでこの方法を使います。

先程 cvs からダウンロードしたソースコードの中に、モジュールモードで起動した Julius をperl から利用するサンプルスクリプト(jclient-perl)があったので、これを参考に ruby で書きなおして twitter 投稿処理などなどを追加しました。

まず、Julius をモジュールモード(-module)で起動します。

julius -C ~/local/dictation-kit-v4.0/fast.jconf -charconv EUC-JP UTF-8 -module

gem install nokogiri twitter してから、以下のソースを動かします。

#! /usr/bin/env ruby
# -*- coding: utf-8 -*-

require "socket"
require "rubygems"
require "nokogiri"
require "twitter"

TWITTER_ID = "your twitter id"
PASSWORD   = "your twitter password"

def twit(s)
  auth = Twitter::HTTPAuth.new(TWITTER_ID, PASSWORD)
  agent = Twitter::Base.new(auth)
  agent.update(s)
end

s = nil
until s
  begin
    s = TCPSocket.open("localhost", 10500)
  rescue
    STDERR.puts "Julius に接続失敗しました\n再接続を試みます"
    sleep 10
    retry
  end
end
puts "Julius に接続しました"

source = ""
while true
  ret = IO::select([s])
  ret[0].each do |sock|
    source += sock.recv(65535)
    if source[-2..source.size] == ".\n"
      source.gsub!(/\.\n/, "")
      xml = Nokogiri(source)
      words = (xml/"RECOGOUT"/"SHYPO"/"WHYPO").inject("") {|ws, w| ws + w["WORD"] }
      unless words == ""
        twit(words)
        puts "#{words}」を twitしました。"
      end
      source = ""
    end
  end
end

実行結果

テストしてる最中、ちょっと雑音が入ったので音声入力に失敗しましたが、3回目でうまく認識してくれました。3回とも同じ言葉をしゃべってます。
実行結果↓
テスト1テスト2テスト3

どーぞご利用ください