まだプログラマーですが何か?

プログラマーネタ中心。たまに作成したウェブサービス関連の話も https://twitter.com/dotnsf

2015/07

IBM Bluemix から提供されている認識型人工知能 API の1つ "Speech to Text" が2015年7月1日のアップデートで日本語に対応しました!
http://www.ibm.com/smarterplanet/us/en/ibmwatson/developercloud/speech-to-text.html

音声ファイル(.wav など)をインプットとして与えると、その内容のテキストと、その変換の確度をテキストでアウトプットしてくれる、というサービスです。オンラインのデモサイトが用意されているので、まずはどのような内容なのかをデモで確認してみましょう:
https://speech-to-text-demo.mybluemix.net/

2015072001


まず "Transcribe Audio" と書かれている所を参照し、今回のデモで行う作業を IBM Watson の学習にご協力いただけるかどうかを設定します。学習にご協力いただける場合は "Allow Watson to learn from this session" を、この作業を学習してほしくない場合は "Opt Out" を選択してください。更にその下で今回の作業で使う音声の言語情報を設定します。今回は日本語音声でテストしたいので "Japanese broadband model (16KHz)" を選択しておきます。加えて実際の音声が聞こえるように PC のスピーカーを有効にしておきます。これだけで事前準備は完了です:
2015072002


では実際にサンプル音声データを使って認識させてみます。"Play Sample 1" ボタンをクリックします:
2015072003


サンプルの日本語音声が流れ始めます。同時にその音声の認識結果が表示されはじめます。
2015072006


最後まで再生が終わると、最終認識結果が表示されます。実際に試していただくとわかるのですが、Sample 1 は正しい結果に認識できていることがわかります。しかもちゃんと漢字になっていますね。。:
 2015072004


これが Watson Speech to Text API を使ったアプリの例です。このアプリで実現している内容と同様に、音声データをインプットとしてポストすると、認識結果がテキストで得られる、という API が用意されています。この API を自分のアプリケーションの中で利用することができる、というものです。

では実際にこの API をアプリケーションに組み込んで使ってみる、という具体例を紹介します。まずは Bluemix にログインし、実際のアプリケーションサーバーとなるランタイムを作成します。Speech to Text API は REST API なのでプログラミング言語に依存していませんが、今回は Java のサンプルを紹介するので Liberty for Java のランタイムを作成します:
2015072007


アプリ名は適当に(この例では kkimura-java-s2t と)付けておきます:
2015072008


ランタイムが作成できたら「概要」メニューから「サービスまたは API の追加」をクリックします:
2015072009


サービスの一覧が表示されます。今回の目的である Watson カテゴリ内の "Speech To Text" を選択します:
2015072010


"Speech To Text" サービスの説明が表示されます。日本語に対応していることが確認できます。この画面で「作成」ボタンを押して、このサービスが先程作成したランタイムに紐付けた形で利用できるようにします:
2015072011


ちなみに、この画面の下部にはサービスの価格に関する情報も表示されているので念のため確認ください。この API は音声データの長さで課金されます。最初の 1000 分が無料、それ以降は1分につき 2.10 円です。なお無料トライアル期間中のユーザーは課金対象ではありません:
2015072012


ランタイムに Speech to Text サービスが紐付けられると、ランタイムの環境変数からこのサービスを利用するための情報を参照できるようになります:
2015072013


この環境情報はこのような内容になっているはずです。"url" に API のエンドポイント(のベースとなる)値、そして "username" と "password" にはこの API を利用する際に必要になる認証情報が記載されています。これらの値を後で使います:
{
  "speech_to_text": [
    {
      "name": "Speech To Text-fc",
      "label": "speech_to_text",
      "plan": "standard",
      "credentials": {
        "url": "https://stream.watsonplatform.net/speech-to-text/api",
        "username": "(username)",
        "password": "(password)"
      }
    }
  ]
}

そして、実際に API にポストする日本語音声ファイルを用意します。今回はこちらのサイトから「あいうえお1(wav)」と書かれた .wav ファイル(aiueo1.wav)をダウンロードして使わせていただくことにします。もちろん他の音声ファイルでも構いません。現時点での対応フォーマットは flac/l16/wav です:
日本語音声サンプル


で、こんな感じのアプリケーションを作ってみました。まずはシンプルに音声ファイルを指定してアップロードする HTML ページのファイルです。アップロードするファイルは "audio_file" という名前で、./speech2text にポストします:
<html>
<head>
<title>Speech to Text</title>
</head>

<body>

<form name="frm" method="post" enctype="multipart/form-data" action="./speech2text">
<input type="file" name="audio_file"/><input type="submit" value="Submit"/>
</form>

</body>

</html>



そして、このページからアップロードされた音声ファイルを使って Speech To Text API を実行して、その結果を返すサーブレット(./speech2text)を以下の内容で作成します。なおこのサーブレットは Jakarta Commons HTTPClient 3.1JSON Simple 1.1.1 を使っています。必要であればこれらのモジュールも入手してください:
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.fileupload.FileItemIterator;
import org.apache.commons.fileupload.FileItemStream;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.ByteArrayRequestEntity;
import org.apache.commons.httpclient.methods.PostMethod;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;

public class SpeechToTextServlet extends HttpServlet {
  @Override
  protected void doPost( HttpServletRequest req, HttpServletResponse res ) throws ServletException, IOException{
    String contenttype = "application/json; charset=UTF-8";
    String audio_type = "audio/wav";
    byte[] audio_file = null;
    String out = "";

    // Speech to Text を使うための username と password(環境変数にかかれていたもの)
String username = "(username)", password = "(password)"; req.setCharacterEncoding( "UTF-8" ); ServletFileUpload upload = new ServletFileUpload(); upload.setHeaderEncoding( "UTF-8" ); JSONParser parser = new JSONParser(); try{ FileItemIterator iterator = upload.getItemIterator( req ); while( iterator.hasNext() ){ FileItemStream item = iterator.next(); InputStream stream = item.openStream(); if( !item.isFormField() ){ String fieldname = item.getFieldName();
// audio_file フィールドに指定された音声ファイルのバイナリを取得する if( fieldname.equals( "audio_file" ) ){ audio_type = item.getContentType(); // 音声ファイルの Content-Type int len, size = 0; byte[] buffer = new byte[10*1024*1024]; //. 10MB MAX ByteArrayOutputStream baos = new ByteArrayOutputStream(); while( ( len = stream.read( buffer, 0, buffer.length ) ) != -1 ){ baos.write( buffer, 0, len ); size += len; } audio_file = baos.toByteArray(); // 音声ファイルのバイト配列 } } } if( audio_file != null ){ HttpClient client = new HttpClient(); byte[] b64data = Base64.encodeBase64( ( username + ":" + password ).getBytes() );
// /v1/recognize に音声ファイルのバイナリをポストする(パラメータで日本語音声であることを指定) PostMethod post = new PostMethod( "https://stream.watsonplatform.net/speech-to-text/api/v1/recognize?model=ja-JP_BroadbandModel" ); post.setRequestHeader( "Authorization", "Basic " + new String( b64data ) ); post.setRequestHeader( "Content-Type", audio_type ); ByteArrayRequestEntity entity = new ByteArrayRequestEntity( audio_file ); post.setRequestEntity( entity ); int sc = client.executeMethod( post ); if( sc == 200 ){
// ポスト結果(JSON)を UTF-8 テキストで取り出す byte[] b = post.getResponseBody(); out = new String( b, "UTF-8" ); // ※
// テキスト内の日本語認識結果と、その確度(自信)を取り出す JSONObject obj = ( JSONObject )parser.parse( out ); JSONArray results = ( JSONArray )obj.get( "results" ); if( results.size() > 0 ){ JSONObject result = ( JSONObject )results.get( 0 ); JSONArray alternatives = ( JSONArray )result.get( "alternatives" ); for( int i = 0; i < alternatives.size(); i ++ ){ JSONObject alternative = ( JSONObject )alternatives.get( i ); Double confidence = ( Double )alternative.get( "confidence" ); String transcript = ( String )alternative.get( "transcript" ); out = transcript + "\t" + confidence; // 結果をタブでつないで出力する //System.out.println( out ); } } } } }catch( Exception e ){ e.printStackTrace(); } res.setContentType( contenttype ); res.setCharacterEncoding( "UTF-8" ); res.getWriter().println( out ); } }

肝になっているのは赤字で記載した部分です。Speech to Text には何種類かの API がありますが、今回はシンプルに実行する /v1/recognize を使った例を紹介しています。この API はまず model パラメータで言語情報を指定します。今回は日本語音声ファイルを試したいので、model=ja-JP_BroadbandModel と決め打ちで指定しています。これ以外にも認識の途中経過を結果テキストに含めるような指定をすることもできますが、今回は認識した最終結果だけをその確度と一緒に返す仕様(デフォルト)で実行しています。

そして環境変数で確認した username と password を使った Basic 認証、および認識させる音声ファイルの Content-Type を HTTP ヘッダに追加し、音声ファイルのバイナリを本体としてする、という内容になっています。上記例は Java でその内容を実装していますが、同様の処理を記述すれば他の言語でも同じ処理を実行できるはずです。

この処理が成功すると、HTTP のレスポンス(上記コードの※の out の内容)として以下の様な JSON テキストが返されるはずです:
{
  "results": [
    {
      "alternatives": [
        {
          "confidence": 0.5490435361862183, 
          "transcript": "ああ いう よう "
        }
      ], 
      "final": true
    }
  ], 
  "result_index": 0
}

上記の中身の "transcript" が認識結果のテキスト(「あいうえお」のはずが「ああ いう よう」と聞こえちゃったんですね。。)、その確度が "confidence" に付与されています。 なので、この JSON フォーマットから目的の値だけを取り出して、上記例では "transcript" と "confidence" の値をタブ("\t")でつないで返す、という内容のサーブレットにしました。

したがって、このプログラムを実際に動かして、用意した aiueo1.wav をアップロードすると、このような結果がブラウザ画面に表示されることになります:
2015072001


Watson Speech to Text API の特徴の1つとして、「一般的な会話がなされている前提で、会話として確率の高そうな結果が優先される」ように感じています。上記例だと、一般的な会話の中には「あいうえお」という発音だけがなされる可能性は低いのも事実だと思っています。一方で「ああ、言うよ~」はより会話っぽいので、こういう結果の方がどちらかというと(会話として)可能性が高い、と判断するようです。良くも悪くも会話優先で変換してくれるような印象を持っています。


と、これが Watson の Speech to Text API の具体的な利用例です。パラメータで挙動をある程度コントロールすることもできますし、結果により詳しい情報を含めることもできます。音声というメディアをアプリケーションに組み組むのに便利な API だと思うので、様々なアプリアイデアの中で使ってみてください。


なお、Speech to Text API のリファレンスはこちらを参照ください:
http://www.ibm.com/smarterplanet/us/en/ibmwatson/developercloud/apis/#!/speech-to-text/


IBM Bluemix の IoT アプリ開発でも重宝する IoT センサーシミュレーターサービスについての地味で大事な更新情報です:
https://quickstart.internetofthings.ibmcloud.com/iotsensor/


上記サイトにアクセスして表示される画面は「あるセンサーデバイスの温度、湿度、機器温度の状態をシミュレートしてネット上に自らの状態を知らせてくれる機能を持ったサイト」です。この辺りの詳細はこちらのエントリを参照してください:
Bluemix の Node-RED サービスで IoT アプリを作る

さて、このセンサーシミュレーターのサービスですが、いつの間にか少し進化していました。画面右上にはデバイス ID としてネット上での MAC アドレスが表示されているのですが、この表記からコロンが抜け、また初めからアルファベットが小文字になっています!
2015071701

(↑これまでのバージョンでは右上部分は 4F:A2:0A:09:A8:C8 と表示されていました)


これは結構大きなインパクトがあります。なんといっても「これで表示内容がデバイス ID としてがそのまま使えるようになった」のです。Node-RED エディタなどでデバイス ID を指定する際に単純に画面からコピペすればよくなりました(以前はコピペした値のコロンを取り除いて、アルファベット大文字を小文字に手で修正する必要がありました)。

Bluemix の IoT 関連サービス、ますます使いやすくなってます!


自分は自己紹介する時に「言語マニア」である、ということがあります。

ある程度モノにしている言語は日本語と英語。読むだけなら韓国語とフランス語、かじった程度ではアラビア語。かじった直後に断念したのがヒエログリフ(象形文字)。 言語という意味では更に加えて Java, PHP, JavaScript, C, C++, (Visual)Basic, LotusScript, Perl, Pascal, Fortran, CASL,  ... あたりのプログラミング言語も使えます。が、今回は前者の話です。

最近はウェブの翻訳サービスを使うことも多いのですが、外国語を勉強するには実際に使うのが近道だと思ってます。英語のアルファベットはパソコンで普通に入力できますが、フランス語アルファベットには特殊な表記をするものがあったり、韓国語のハングルに至っては普通には入力できません(よね?)。どうせならパソコンでも勉強中の文字入力をできるようにして、それらの言語でパワポの資料を作ってみたりできるとカッコいいです。


というわけで、Windows パソコンで日本語/英語以外の文字が入力できるようにするための設定方法を紹介します。ちなみに多言語入力は Windows XP 以降から標準機能として可能になっていますが、以下の紹介画面は Windows 7 です。


まずコントロールパネルを開き、「地域と言語」を選択します:
2015071901


「キーボードと言語」タブから「キーボードの変更」ボタンをクリックします:
2015071902


「全般」タブの「インストールされているサービス」には現在使うことのできる、英語以外の言語サービスの一覧が表示されます(画面では日本語だけです)。ここに韓国語を追加してみます。「追加」ボタンをクリックします:
2015071903


「韓国語」 - 「キーボード」 - 「Microsoft IME」にチェックを入れて「OK」ボタンをクリックします:
2015071904


先ほどの画面に戻り、「インストールされているサービス」に「韓国語」が追加されていることを確認します。必要であれば、同様に他の言語も追加します。最後に「適用」ボタンをクリックしてから「OK」ボタンをクリックします。これで準備は完了です:
2015071905


では実際に韓国語を入力してみます。メモ帳を起動しておきます:
2015071906


ここでキーボードの 左Alt + Shift を押す度に使用言語が切り替わっていくはずです。韓国語を入力するには図のように "KO" と書かれた表記になるまで切り替えます。これでハングル入力モードになりました:
2015071907


日本語入力モードでも日本語と英語を切り替えて入力するように、ハングル入力モードでも同様の切り替えを意識する必要があります。ハングル入力モードで 右Alt を押す度にハングルと英語の切り替えができます。ハングルを入力する場合は「A」ではなく「가」という表記に切り替えます。
2015071908


この状態でメモ帳内で適当にキーボードを叩くと、ハングルが入力されていくはずです(ちなみにこの内容は適当に打っただけなので意味無いです):
2015071909


キーボード配列をまだ覚えていない場合はソフトウェアキーボードを参照することも可能です。そのためにはまずソフトウェアキーボードを有効にする必要があります。言語バーの▼印をクリックし、メニューから "Soft Keyboard" にチェックを入れます:
2015071910


チェックすると言語バーにソフトウェアキーボードボタンが現れます:
2015071911


ここをクリックすると画面内にソフトウェアキーボードが表示され、ここからハングルを入力することもできますし、このキーボード配列を参照しながら目的の文字をキーボード入力する(ための勉強をする)こともできます:
2015071912


同様にしてアラビア語なども導入し、言語を切り替えて入力することで多言語テキストを作成することも可能です。ちなみにアラビア語はちゃんと(?)右から左に入力されていきます:
2015071913


実際問題として、たまに外国人が日本語のローマ字変換でパワポの資料を作っているのを目の当たりにすると、それだけで尊敬してしまいます。ただでさえ難しい外国語である日本語を、それもローマ字変換とか・・・ そんな感じで自分も色んな言語が操れるようになったらいいなあ、と思ってます。


余談ですが、この多言語テキストが標準機能として入力できるようになったのは Windows XP からでした。当時アラビア語を勉強していた自分にとって Windows XP は神 OS でした。開発者としてはシステムデバッグが楽な Windows 2000 も気に入っていたのですが、この機能を知って乗り換えを決意したものでした。


今回のブログエントリは ThinkPad ユーザー向けです。


lenovo の ThinkPad のほとんどの機種には APS(Active Protection System) と呼ばれている、ハードディスク保護システムが用意されています(画面はコントロールパネル):
2015071801


世の中にはありがたい人がいてくれて、この APS 機能を SDLAccel というライブラリにして、色々なアプリケーションに応用できるようにしてくれた方がいました。このリンク先のダウンロードボタンをクリックして、SDLAccel.zip をダウンロードしてください:
https://docs.google.com/open?id=0B3tL0c24sdXwSnpLSHpwYUxHZ0k

2015071802


この zip ファイルを展開し、SDL.dll だけを取り出しておきます:
2015071803


これが(一般的に多く使われている)SDL ライブラリの APS 対応版です。これがどういう意味かは後で紹介しますが、普通の SDL.dll と置き換えて使うことができるものです。

では実際に置き換えて使ってみるための、SDL を使ったアプリケーションをダウンロードしてみましょう。例えばこの Tux Racer というゲームは SDL 対応ゲームなので、これで試してみます:



Tux Racer を SourceForge からダウンロードして、展開します:
http://sourceforge.net/projects/tuxracer/


展開後の tuxracer.exe をダブルクリックすると、普通にゲームを始めることができますが、今回はその前に一手間かけてみます。
2015071804


この Tux Racer のフォルダにある SDL.dll を SDL.dll_org にリネームし、先程ダウンロードした SDLAccel.zip から取り出した SDL.dll を同フォルダにコピーします。つまり、SDL.dll を SDLAccel.zip のものに置き換えます:
2015071805


これで準備完了です。改めて tuxracer.exe をダブルクリックしてゲームを起動してみます。

このゲームは主人公の Tux(ペンギン)を方向キーで左右に動かしてアイテムを取りつつ、上下キーでスピードを調整しながらゴールを目指す、というアクションゲームです:
2015071806


ただ SDL.dll を更新後は方向キーが使えなくなっています。代わりに APS を使ったコントロールが有効になっていて、ThinkPad 自体を前後左右に傾けることで Tux をコントロールできるようになっているはずです:
2015071807


ThinkPad 本体を落とさないように、気をつけて遊んでください。

簡単にタグクラウドっぽい UI を作れないかなあ、と思ってたら、jQuery のプラグインがありました:
jQCloud

CDN などで jQuery をロードしてから、この jQCloud の CSS および JavaScript をロードして使います。

実際のタグクラウドとしての使い方は公式の README.md を参照いただきたいのですが、タグクラウドにしたい要素を配列で与えて、jQuery で読み込ませるだけです。具体的にはこんな感じです:
<html>
<head>
<title>jQCloud</title>
<!-- jQuery と jQCloud をロード -->
<script src="http://code.jquery.com/jquery-2.0.3.min.js"></script>
<link rel="stylesheet" type="text/css" href="./jqcloud.css" />
<script type="text/javascript" src="./jqcloud-1.0.4.js"></script>
<script type="text/javascript">
//. タグクラウドの要素(文字と、大きさと、リンク先)を配列で用意
var word_list = [
  { text: 'クラウド', weight: 19 }
  ,{ text: 'IBM Bluemix', weight: 14, link: 'http://bluemix.net/' }
  ,{ text: 'マンホール', weight: 12, link: 'http://manholemap.juge.me/' }
  ,{ text: 'ねっぴ', weight: 9, link: 'http://neppi.co/' }
  ,{ text: 'ツイートマッパー', weight: 9, link: 'http://tweetsmapper.juge.me/' }
];

$(function(){
  //. 上記で用意した配列をタグクラウドとして表示
  $("#tagcloud").jQCloud( word_list, {
    width: 500, height: 200
  });
});
</script>
</head>
<body>

<!-- ここにタグクラウドを表示する -->
<div id="tagcloud"></div>

</body>
</html>


このページをブラウザで開くと、このようなタグクラウドが表示されるはずです。文字とその大きさは JavaScript で指定した通りになっているはずです:
2015071700


また「クラウド」という文字以外にはリンク先を指定していたので、クリックするとそれぞれに指定されたページに移動するはずです。

かなり簡単に実現できちゃいました。


このページのトップヘ