PHP という蜂と音声という蜜: アクセシビリティーを考慮したエージェント・ベースの音声アラートとフィードバック

PHP エージェントを使って音声システムに情報をフィードする

この記事では、オープンソースのツールを使って情報を収集、編集し、中央のデータベースに追加するシステムについて説明します。このシステムでは、情報はユーザーへの伝達用に適切に構成されますが、その構成された情報は画面に表示されるのではなく、視覚障害のあるユーザーなどのために音声システムを使って伝達されます。また、このシステムではいくつかの PHP エージェントが使われますが、これらのエージェントは単独で動作して情報を生成、編集し、音声で伝達するための調整を行ってから、その情報を音声で伝達します。

Colin Beckingham, Writer, Researcher

Colin Beckingham はカナダのオンタリオ州東部に住むフリーランスの研究者であり、ライターであり、プログラマーでもあります。Queen's University, Kingston で学位を取得している彼は、園芸、競馬、教育、行政サービス、小売業、旅行/観光業などにも関わってきました。彼はデータベース・アプリケーションの作成者であり、無数の新聞記事や雑誌記事、オンライン記事を執筆しており、また Linux® でのオープンソース・プログラミングや音声制御アプリケーションも研究しています。



2009年 10月 13日

チームリーダーがあなたに対して、あなたの会社による XYZ 株式会社の買収についての方針説明書を準備するように指示したとします。この書類は現地時間の午後 4時ちょうどに開始される会議に使用され、そこで買収を進めるかどうかの判断が下されます。午後 3時 50分、あなたは静かに自分のデスクに向かい、その書類の最後の仕上げを行っています。その時突然、あなたのコンピューターがヘッドセットをとおして、「お知らせします (Just a moment)。お知らせします。BCD から XYZ 社に関するメッセージ・フィードが届いています。」と音声で通知します。あなたはそのフィード・リーダーにアクセスし、その情報をメモし、方針説明書を手直しし、会議に最新の情報を提供することで、出席者達を驚かせます。この場合には、あなたに視覚障害があっても、まったく問題になりません。

よく使われる頭字語

  • FIFO: First In, First Out
  • HTML: HyperText Markup Language
  • RDBMS: Relational Database Management System
  • RSS: Really Simple Syndication
  • SQL: Structured Query Language
  • TTS: Text-To-Speech
  • XML: Extensible Markup Language

音声システムを使っている皆さんの強みは、いくつかのエージェントが皆さんのために作業をし、情報の収集と構成をしてくれることです。まだ皆さん以外の人は誰も、そのフィードを読んでいません。そのニュースは、ほんの数分前のものだからです。そして、コンピューターはポップアップ・ウィンドウを画面に表示する代わりに、皆さんの耳を介して注意を喚起します。皆さんにとって画面はあまり役に立たないため、これは有益です。

音声によるコンピューター出力は、視覚障害のある人達にとっては特に、画面に代わる便利でアクセシブルな表現手段です。この、コンピューターが音声を発するという概念は決して新しいものではありません。映画好きの人であれば、先ほどの「お知らせします (Just a moment)」という言い回しが「2001年宇宙の旅」(1968年公開) からの引用であることにお気付きかと思います。この映画では、通信機の部品が故障するとコンピューターが音声で知らせてくれます。しかし、今日のコンピューターの出力の圧倒的大部分は、相変わらず画面に出力されます。

なぜ、アーサー・C・クラークとスタンリー・キューブリック (訳注: いずれも「2001年宇宙の旅」の脚本家です) は音声によるやり取りを選び、画面や印刷物で表現する方法を選ばなかったのでしょう。それは、視覚障害がなくても、ある種の情報を、視覚ではなく音声で受け取りたい場合があるからです。

印刷物ではなく、音声で

HAL (訳注: HAL は、「2001年宇宙の旅」に登場する人工知能を持ったコンピューターの名前です) の声は親しみやすく、気持ちを和やかにしてくれるため、ペースの速い世界では好感が持たれます。音声は画面の前にいなくても聴くことができるのに加え、聴覚の方が視覚よりも信頼できる場合がよくあります。またデスクに向かいっぱなしでいるよりも、歩き回っている方が良い考えが浮かぶことがあります。場合によると、音声によるアラートは視覚障害のない人にもメリットがあることがあります。例えば、電源ユニットから出力される電圧を監視しているとします。画面上では電圧が常に更新されていますが、電圧の変化に気付かないことがあります。このような場合は、エージェントの設定を、電圧が適切な範囲内にあるときには低い音を出すように、そして問題が起こると高い音を出すようにすることができます。これは蜜蜂と同じで、蜜蜂は邪魔をされると相手に伝わるように羽音を変えて警告を発します。人間の場合も、ヘッドセットやスピーカーがオフになっていない限り、耳からメッセージを受ける方が、変化に気付く可能性がはるかに高いはずです。

Festival TTS エンジン

Festival は TTS (Text-To-Speech: 音声合成) エンジンです。テキスト・ストリングを指定すると、Festival はコンピューターの音声システムを使ってそれらの単語を読み上げようとします (「参考文献」を参照)。 Festival のインストールが適切に動作しているかどうかを簡単に確認するためには、$ festival を実行し、続いて festival> (SayText "Hello world") を実行します。

一方で、音声でメッセージを知らせる方法にも問題があります。メッセージの中に「PM late」という文字ストリングが含まれている場合、これは「午後の遅く」を意味するのでしょうか、それとも「Prime Minister (首相) が遅れた」ことを意味するのでしょうか。人間が読む場合には、少し考えて文脈で判断することができますが、PHP エージェントはどうすればよいのでしょう。こうした状況は確かに複雑ですが、こうした状況が発生した場合には、状況ごとに個別に対処することができます。これは蜜蜂が花蜜の種類ごとに異なる蜂蜜を作るのと同じです。

HAL は、その状況の真実を正確に音声で知らせているわけではありません。このことから、その音声による通知がどのように準備されたのかを注意深く検証する必要があることがわかります。とりあえず、この XYZ 社に関するメッセージ・フィードの通知を行うという特別な目的には、印刷物よりも音声の方が優れていると仮定し、このシステムがどのように動作するのか、その概要を調べてみましょう。


マッシュアップの概要

メッセージを中に含んだ RDBMS データベースがクラウドの中にあると考えてみてください。これらのメッセージは (テキスト・メッセージの場合も、音声ファイルの名前の場合もありますが)、 PHP スクリプトによってスキャンされ、この PHP スクリプトはメッセージの内容を読み上げるための TTS エンジン (Festival など) または音声プレーヤー (MPlayer など) をインテリジェントに選択します。新しいメッセージは PHP によるスクリプトによってデータベースに追加されます。これらのスクリプトはさまざまな情報源 (ニュース・フィード (XML)、Web ページ (HTML)、bash スクリプトからの出力、等々) を検証しますが、検証する目的は、意味のあるメッセージを作成してキューに入れるためです。このシステムの構成を示したものが図 1 です。

図 1. 音声システム
音声システムの構成図です。構成図には、エージェント、端末機器、データベース・ストレージ、そしてサーバーが表示されており、いずれも互いにクラウドをとおしてやり取りが行われます。

図 1 は構成として考えられる 1 つの例を示しています。図の左側が入力であり、右側が出力です。中央にはクラウドがあります。クラウドは、システムのどの部分も論理的に接続されてさえいれば、他の部分から物理的に切り離せることを示しています。クラウドの上と下には、メッセージを適切に送達するために必要なデータベース・ストレージや HTTP サーバーなど、特別なサービスがあります。また、この図では出力が複数あることを示しており、例えば、何人かのユーザーが同じメッセージを受信することを示しています。

この説明を読んだ限りでは、このシステムは単純そうに思えるかもしれません。実際に単純ではありますが、プロセスの各段階には十分注意を払わなければならない詳細事項が数多くあります。では、そうした詳細事項を調べてみましょう。


バックエンド・ストレージ

サンプルのバックエンド・データベースには、いくつかの単純なフィールドを持つ 1 つのテーブルしか含まれていません。このデータベースを説明したものがリスト 1 です。

リスト 1. バックエンドの MySQL でのデータの定義
CREATE TABLE IF NOT EXISTS `queue` (
  `qid` int(11) NOT NULL AUTO_INCREMENT,
  `enunc` text COLLATE latin1_general_ci NOT NULL,
  `ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `sys` tinyint(1) NOT NULL DEFAULT '0',
  `engine` tinyint(4) NOT NULL DEFAULT '0',
  `procd` tinyint(4) NOT NULL DEFAULT '0',
  `pause` tinyint(4) NOT NULL DEFAULT '0',
  PRIMARY KEY (`qid`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci AUTO_INCREMENT=607 ;

このコードは MySQL からエクスポートされたもので (他の RDBMS の場合には、それに合わせて適当な変更を加えてください)、まだテーブルが存在しない場合にテーブルを作成するコードです。最初のフィールドは、各レコードを識別するための非常に重要な一意の ID です。その後に text 型のフィールドが続いており (このフィールドを場合によっては varchar 型にすることもできます)、このフィールドに実際のメッセージが格納されます。その次のフィールドはタイムスタンプであり、デフォルトはエントリーが記録された時点の時刻です。sys は yes または no の論理フィールドです。このフィールドは、このメッセージがシステムからの優先度の高いメッセージであり、他のすべてのメッセージよりも前に再生する必要があるかどうかを示します (例えば、重要なスクリプトの動作が停止したことを伝えるメッセージなど)。その次の engine フィールドは、どのプログラム (Festival、MPlayer、あるいは他のサウンド・マネージャー) を使って情報を再生するのかを表す数字です。その次の procd フィールドは、このメッセージが既に再生されたかどうかを示します。このフィールドを利用すると、必要に応じて、すべてのメッセージのレコードを保持した上で新しいメッセージのみを再生することができます。最後の pause フィールドを使用すると、他の何らかの条件が存在する間、あるメッセージをシステムが保留することができます。以上のフィールドに加え、他のフィールドを必要に応じて追加することもできます。特に、別の procd フィールドを追加することで、そのメッセージが他のマシンで既に再生されたことを示すことができます。私は後でテーブルの結合や関係の作成ができるように、InnoDB データベース・エンジンを使用することにしました。状況が複雑でなければ、デフォルトの MyISAM エンジンでも十分です。


音声の再生

バックエンドの用意ができ、メッセージを保管する準備が整ったら、今度は音声の再生機能を用意する必要があります。音声を再生するスクリプトはキュー・テーブルの中にあるレコード群を調べます。そして、レコードが停止中ではなく、まだ再生されていない場合には、FIFO の順番でそれらのレコードを読み上げます。ただし、システム・メッセージはすべて、記録時刻にかかわらず優先されます。

リスト 2 は、必要なデータを抽出するための、簡潔で単純化された PHP の命令セットを示しています。

リスト 2. 音声再生用の PHP コード・スニペット
<?php
$mysqli = new mysqli($server,$user,$password,$database);
$sql = "select qid,enunc,engine from queue
	  where procd=0 and pause=0
	  order by sys desc,qid asc";
$result = $mysqli->query($sql) or die("Error:".$mysqli->error);
if ($result->num_rows > 0) {
  $row = $result->fetch_array();
  echo $row['enunc']."\n";
  switch ($row['engine']) {
    case 0: // festival TTS
      saytext($row['enunc']);
    break;
    case 1: // mplayer sounds/music
      playsound($row['enunc']);
    break;
    default: // must be something else
      echo "I m sorry Dave, I can t do that, 
	  you did not define an engine for ".$row['enunc']."\n";
    break;
  }
  $qid = $row['qid'];
  set_pron($qid);
}
?>

上記のコードでは、まだ再生されていないレコードで、しかも停止中ではないレコードのリストを SQL 文が要求します。SQL 文は次に、これらのレコードに対してループ処理を行い、どのプレーヤーが使用されるかに応じて switch 文で指定されるアクションを実行します。この場合には、数字の 0 は Festival エンジンを使って音声を読み上げることを示し、数字の 1 は MPlayer を使って再生することを示します。また、デバッグの補助用に診断情報が画面に出力されるポイントがいくつかあります。各メッセージの再生または読み上げが終わると、set_pron() が簡単な関数を呼び出します。この関数はバックエンドの procd フィールドをゼロ以外に設定し、このスクリプトが再度実行された場合に、既に再生や読み上げが行われたメッセージが再び処理されることがないようにします。

メッセージを読み上げるプレーヤーを呼び出すための関数は、使用されるプレーヤーによって異なります。リスト 3 は Festival の例を示しています。

リスト 3. Festival を呼び出す PHP 関数
function saytext($phrase) {
global $debug;
    if ($debug) echo $phrase."\n";
    exec('festival -b \'(SayText "'.$phrase.'")\'');
}

この関数が PHP の exec() 関数を呼び出していることに注意してください。この関数を利用すると、音声の再生中にスクリプトの実行を停止することができます。スクリプトの実行を停止すると、音声の再生が終了し、次のレコードを再生しようとします。さらに、Festival に渡す語句をチェックし、TTS エンジンがその語句を構文的に受け入れられるかどうか、また読み上げられる内容が聴き手に理解されるものであるかを確認する必要があります (これについては後ほどさらに説明します)。また、音声再生のタスクとして、一方のチャンネルの音量を下げ、もう一方のチャンネルの音を聞こえやすくする必要があるかもしれません。

注: 必要であれば、このスクリプトを手動で実行することもできますが、cron ジョブとして繰り返し実行し、繰り返しの間に適切な遅延を挿入する方が得策です。


働き者のエージェント

音声再生機能がバックグラウンドで実行され、新しいメッセージを待ち構える状態になったら、興味深いものをキューに入れる必要があります。最初の例では RSS フィードをスキャンするエージェントを紹介したので、リスト 4 のコードでもそれに従います。RSS フィードは XML 標準を使用しているため、PHP の XML 関数を使うことでフィードから必要なレコードを引き出すことができます。

リスト 4. RSS をスキャンするエージェントのための基本的な PHP コード
<?php
    $mysqli = new mysqli($server,$user,$password,$database);
    $rss = "URI_of_feed_goes_here";
    $xmlstr = file_get_contents($rss);
    $xml = new SimpleXMLElement($xmlstr);
    $crit = "XYZ";
    $jam = "Just a moment";
    foreach ($xml->channel->item as $item) {
	$thistitle = $item->title;
	if (strpos($thistitle,$crit) > 0) {
	    // $titl = speakize($item->title,'news');
	    // $detl = speakize($item->description,'news');
	    $alert = "$jam, $jam, there is a news item in the feed";
	    echo "$titl : $detl\n";
	    // table has `qid`, `enunc`, `ts`, `sys`, `engine`, `procd`, `pause`
	    $sql = "insert into queue values(NULL,'$alert',NULL,0,0,0,0)";
	    $result = $mysqli->query($sql) or die($mysqli->error);
	}
    }
?>

このスキャニング・エージェントは以下のタスクを実行します。

  • データベースへの mysqli 接続を設定した後、どの RSS フィードを検証するのかを指定し、そのフィードを取得してストリング変数の中に入れます。
  • このストリングは次に、XML オブジェクトの中に読み込まれます。変数 $crit“XYZ” に設定されます。これが検索の基準となり、XYZ に関するすべてのフィード項目が検索対象となります。
  • foreach 文はニュース項目に対してループ処理を行い、タイトルの中に XYZ に関する項目がないかどうか検索します。
    注: このタスクはタイトルを参照することを想定していますが、より完璧なものにするために論理条件を拡張して OR 文に入れ、フィードの中にある他の要素を検索することもできます。
  • ニュース項目が見つかると、スクリプトは作業を開始してレコードをキューに追加します。
    この場合、次の 3 つのストリングをデータベースに追加することができます。その 3 つとは、フィード項目のタイトル、フィードの説明、基準に一致するフィード項目があることを伝える一節です。最後に挙げた一節には Festival が再生できる既知の単語群が含まれているため、最も確実に再生することができます。この場合はデバッグの補助用にタイトルと説明が画面に出力されます。
  • 最後に、NULL,'$alert',NULL,0,0,0,0 という一連の引数があることに注意してください。これらの引数は順に以下の内容を意味しています。
    • 最初の NULL は任意の ID です。
    • '$alert'alert 変数の内容を置き換えます。
    • 3 番目の NULL はサーバーからのタイムスタンプです。
    • 次の 0 は、このメッセージが優先メッセージではないことを示します。
    • 次の 0 は、このエンジンが Festival であることを示します。
    • 次の 0 は、このメッセージがまだ読み上げられていないことを示します。
    • 次の 0 は、このメッセージが停止されていないことを示します。

注意深い読者は、ここでは説明されていない speakize() という関数がリスト 4 で使われていることに気付いたと思います。この時点では、この関数は画面用に設計されたテキストを「耳にとっての蜂蜜」に変え、出力先を変えることによって必要となる変更を行う、とだけ説明しておけば十分でしょう。

この時点でサイクルが完結します。エージェントは情報をデータベースに追加し、音声再生機能は再生対象が現れるのを待ちます。それ以外に必要なことは、1 つのエージェントがニュース・フィードから XYX に関する項目を抽出し、メッセージを送信することだけです。それが実行されると、音声によるアラートが出力されます。実際の状況では、エージェントが複数あり、すべてのエージェントが必要に応じて順次音声を再生していきます。


マネージャー

容易にわかることですが、このシステムが実行を開始したら、バックエンドのデータベースのレコードを管理する手段があると便利です。つまり場合によると、最後の項目を繰り返したり、最後の 10 項目を未読とマーキングして次回再生時に再度読み上げられるようにしたり、最新の項目までジャンプしたり、すべての項目を最初から読み上げたり、といったことが必要かもしれません。こうした管理機能については、この記事では説明しませんが、バックエンド・データベースの構造を見れば、適当な SQL 操作を使ってレコードの並べ替えや確認ができることがわかるはずです。


問題

コンピューター・システム上で人の声を再生するという性質上、このシステムには多くの落とし穴があります。そうした落とし穴を以下に挙げます。

  • 不自然なテキスト文字や頭字語。speakize() 関数の目的は、入力されるテキストをスキャンし、それを読み上げ可能な形式に変換することです。先ほど触れたように、「PM」は「午後」や「夕刻」を意味するのでしょうか、それとも「首相」を意味するのでしょうか。関係するのは 1 つの特定のフィードのみなので、エージェントをカスタマイズし、文脈を考慮して略語を処理させることができます。Speakize() は要件の変更に応じて調整できる関数の 1 つです。
  • システムが TTS を使って長い文章を読み上げている最中に、緊急のシステム・サウンド・ファイルが突然キューに追加された場合にはどうなるのでしょう。exec() 関数はその読み上げを行うスクリプトの実行を停止してしまうため、システムは新しいメッセージに気付かないかもしれません。1 つの対策として、2 つの音声再生機能を用意し、一方には Festival による言葉の再生を担当させ、もう一方にシステム・サウンドを担当させる方式が考えられます。このソリューションには複数のサウンド出力デバイスが必要となるか (多くのシステムでは、Festival や MPlayer などのプログラムは出力を特定のデバイスに出力します)、1 つのデバイスへの合成入力が必要となります。人間であれば、何の問題もなく人が話すのを聞くのと同時にその他の音を処理することができます (旋律と和音を考えてみてください)。しかし、TTS チャンネルが 2 つ同時にあると問題が発生する可能性があります。 この関数が PHP の exec() 関数を呼び出していることに注意してください。この関数を利用すると、音声の再生中にスクリプトの実行を停止することができます。スクリプトの実行を停止すると、音声の再生が終了し、次のレコードを再生しようとします。
  • コンピューターを使いながらヘビー・メタルの曲を聴くことが好きな場合、着信メッセージはかき消されてしまわないでしょうか。音量制御を完全にシステムに任せると、コンピューターは自動的に一方のチャンネルの音量を下げ、快適な環境で音声が再生されるようになります。
  • フィードを編集する人は、必ずしも TTS アプリケーションで処理できるようにタイトルや説明のフォーマットを設定するとは限りません。フィードは印刷されることを前提としており、多くの場合、タイトルや説明などの項目は印刷用のページから引用されています。そのため、フィードの記事全体を理解しない限り、タイトルも説明も理解できないものになってしまいます。「He does it again! (彼はまたやってしまった)」と言う場合、誰が何をしたのでしょう。ニュース・ソースを注意深く選択すると同時に、意外な内容にも対応できるようにする必要があります。

まとめ

この記事では、PHP と他のオープンソース技術を組み合わせることで、有益な情報のメッセージを音声システムに送信する便利なマッシュアップを作成できることを説明しました。ここで説明した方法は、人の注意を引くための数多くの方法の 1 つにすぎません。ユーザーに視覚障害がある場合や、自由に画面を見ることが困難な (あるいは不可能な) システムやプロセスを使用する場合には、ここで説明した方法が特に有用です。人間の読み手よりもエージェントの方が素早く正確に読み上げを行えることがよくありますが、ただしエージェントは意味合いを理解して再生対象の項目を処理することは非常に苦手です。

これらの PHP エージェントは、まさに小さな蜜蜂と同じです。それぞれが特定の仕事を持ち、情報を収集して消化し、データベースという蜂の巣に集約した形で保管します。こうすることで、他のエージェントが必要に応じて蜂蜜を吸い出すことができます。しかし、ある日、コンピューターが皆さんの耳元で、「申し訳ありません、Dave さん。それは私にはできません。」と言ったとしたら、大いに心配する必要があります。

参考文献

学ぶために

  • ウィキペディアで音声合成の項目を調べ、TTS について学んでください。
  • Open Directory プロジェクトで音声合成に関する情報を調べてください。
  • XenoCafe にある Festival のチュートリアルとデモを見てください。Festival は Linux 用の音声合成システムです。
  • developerWorks の Web development ゾーンには Web 2.0 開発のためのツールや情報が豊富に用意されています。
  • developerWorks の「Recommended PHP reading list」には、PHP に関する有益な情報へのリンクが豊富に掲載されています。
  • developerWorks の Technical events and webcasts で最新情報を入手してください。
  • My developerWorks を訪れ、Web 開発やその他、皆さんのあらゆる関心事項についてのグループやブログ、アクティビティーを見つけ、あるいは作成してください。

製品や技術を入手するために

  • Festival 音声合成システムについて、その作成者であるエジンバラ大学 (University of Edinburgh) から学んでください。
  • MPlayer ムービー・プレーヤーについて学んでください。
  • PHP Builder は PHP コード・サンプルのリソースです。
  • IBM 製品の試用版をダウンロードし、DB2® や Lotus®、Rational®、Tivoli®、WebSphere® などが提供するアプリケーション開発ツールやミドルウェア製品をお試しください。

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Web development
ArticleID=446933
ArticleTitle=PHP という蜂と音声という蜜: アクセシビリティーを考慮したエージェント・ベースの音声アラートとフィードバック
publish-date=10132009