Node.js × 音声認識 - 東京Node学園 2012 LT枠 6番目

23
Node.js で音声認識 Presented by @hecomi X

description

2012/11/18 に行われた東京 Node 学園の LT セッション、6 番目の発表です。 デモの解説はこちら:http://d.hatena.ne.jp/hecomi/20121123/1353843800

Transcript of Node.js × 音声認識 - 東京Node学園 2012 LT枠 6番目

Page 1: Node.js × 音声認識 - 東京Node学園 2012 LT枠 6番目

Node.js で音声認識

Presented by@hecomi

X

Page 2: Node.js × 音声認識 - 東京Node学園 2012 LT枠 6番目

LTの趣旨:C++ モジュール

色々出来て楽しいよ!

Page 3: Node.js × 音声認識 - 東京Node学園 2012 LT枠 6番目

自己紹介

•  名前 : hecomi

•  Node歴 : 半年とちょっと

•  言語 : C++ / JavaScript

•  Web : http://d.hatena.ne.jp/hecomi/

最近は音声認識リモコンとか

未来のお部屋を作る活動をしています

Page 4: Node.js × 音声認識 - 東京Node学園 2012 LT枠 6番目

賢いお部屋

集音マイクiRemocon

音声認識エンジン

ZigBee

音声合成

①エアコン26度!

③26度にします 今部屋30℃か…

⑤ピピッ!

④26℃の信号出します

②26度っすね

Page 5: Node.js × 音声認識 - 東京Node学園 2012 LT枠 6番目

賢いお部屋

集音マイクiRemocon

音声認識エンジン

ZigBee

音声合成

①エアコン26度!

③26度にします 今部屋30℃か…

⑤ピピッ!

④26℃の信号出します

②26度っすね

Node.js 上で動かそうとしています

Page 6: Node.js × 音声認識 - 東京Node学園 2012 LT枠 6番目

Node.js 上で動かそうとしています

賢いお部屋

集音マイクiRemocon

ZigBee

音声合成

①エアコン26度!

③26度にします 今部屋30℃か…

⑤ピピッ!

④26℃の信号出します

音声認識エンジン

②26度っすね

この部分について紹介します

Node.js 上で動かそうとしています

Page 7: Node.js × 音声認識 - 東京Node学園 2012 LT枠 6番目

•  オープンソースの音声認識エンジン– http://julius.sourceforge.jp/

•  いろんな機能があります– 認識方法

• ディクテーション(文章自動筆記、誤認識多)

• ★文法認識   (特定の文章、 誤認識少)

– 実行方法• ★ローカル   (普通に実行)

• サーバモード (認識結果を XML でくれます)

Page 8: Node.js × 音声認識 - 東京Node学園 2012 LT枠 6番目

…(前略)Jconf *jconf = j_config_load_args_new(j_argc, const_cast<char**>(j_argv));

if (jconf == nullptr) { std::cout << "Error @ j_config_load_args_new" << std::endl; return -1;}

Recog *recog = j_create_instance_from_jconf(jconf);if (recog == nullptr) { std::cout << "Error @ j_create_instance_from_jconf" << std::endl; return -1;}

callback_add(recog, CALLBACK_EVENT_SPEECH_READY, [](Recog *recog, void*) { std::cout << "<<< PLEASE SPEAK! >>>" << std::endl;}, nullptr);

callback_add(recog, CALLBACK_EVENT_SPEECH_START, [](Recog *recog, void*) {

std::cout << "...SPEECH START..." << std::endl;}, nullptr);

callback_add(recog, CALLBACK_RESULT, OnOutputResult, nullptr);…(後略)

C++/Juliusの設定ファイルを普通に書いていると…

Page 9: Node.js × 音声認識 - 東京Node学園 2012 LT枠 6番目

…(前略)Jconf *jconf = j_config_load_args_new(j_argc, const_cast<char**>(j_argv));

if (jconf == nullptr) { std::cout << "Error @ j_config_load_args_new" << std::endl; return -1;}

Recog *recog = j_create_instance_from_jconf(jconf);if (recog == nullptr) { std::cout << "Error @ j_create_instance_from_jconf" << std::endl; return -1;}

callback_add(recog, CALLBACK_EVENT_SPEECH_READY, [](Recog *recog, void*) { std::cout << "<<< PLEASE SPEAK! >>>" << std::endl;}, nullptr);

callback_add(recog, CALLBACK_EVENT_SPEECH_START, [](Recog *recog, void*) {

std::cout << "...SPEECH START..." << std::endl;}, nullptr);

callback_add(recog, CALLBACK_RESULT, OnOutputResult, nullptr);…(後略)

C++/Juliusの設定ファイルを普通に書いていると…

S : NS_B KADEN_ NOISE PLEASE NS_ES : NS_B JUMON NS_EKADEN_ : KADENKADEN_ : KADEN WO% KADEN

Page 10: Node.js × 音声認識 - 東京Node学園 2012 LT枠 6番目

…(前略)Jconf *jconf = j_config_load_args_new(j_argc, const_cast<char**>(j_argv));

if (jconf == nullptr) { std::cout << "Error @ j_config_load_args_new" << std::endl; return -1;}

Recog *recog = j_create_instance_from_jconf(jconf);if (recog == nullptr) { std::cout << "Error @ j_create_instance_from_jconf" << std::endl; return -1;}

callback_add(recog, CALLBACK_EVENT_SPEECH_READY, [](Recog *recog, void*) { std::cout << "<<< PLEASE SPEAK! >>>" << std::endl;}, nullptr);

callback_add(recog, CALLBACK_EVENT_SPEECH_START, [](Recog *recog, void*) {

std::cout << "...SPEECH START..." << std::endl;}, nullptr);

callback_add(recog, CALLBACK_RESULT, OnOutputResult, nullptr);…(後略)

C++/Juliusの設定ファイルを普通に書いていると…

% KADENテレビ t e r e b i電気 d e n k i% WOを w oを o% PLEASEつけて t u k e t e消して k e s i t e切替 k i r i k a e次 t u g i前 m a e% JUMONバルス b a r u s u% NOISE<sp> sp% NS_B<s> silB% NS_E<s> silE S : NS_B KADEN_ NOISE PLEASE NS_E

S : NS_B JUMON NS_EKADEN_ : KADENKADEN_ : KADEN WO% KADEN

Page 11: Node.js × 音声認識 - 東京Node学園 2012 LT枠 6番目

…(前略)Jconf *jconf = j_config_load_args_new(j_argc, const_cast<char**>(j_argv));

if (jconf == nullptr) { std::cout << "Error @ j_config_load_args_new" << std::endl; return -1;}

Recog *recog = j_create_instance_from_jconf(jconf);if (recog == nullptr) { std::cout << "Error @ j_create_instance_from_jconf" << std::endl; return -1;}

callback_add(recog, CALLBACK_EVENT_SPEECH_READY, [](Recog *recog, void*) { std::cout << "<<< PLEASE SPEAK! >>>" << std::endl;}, nullptr);

callback_add(recog, CALLBACK_EVENT_SPEECH_START, [](Recog *recog, void*) {

std::cout << "...SPEECH START..." << std::endl;}, nullptr);

callback_add(recog, CALLBACK_RESULT, OnOutputResult, nullptr);…(後略)

C++/Juliusの設定ファイルを普通に書いていると…

% KADENテレビ t e r e b i電気 d e n k i% WOを w oを o% PLEASEつけて t u k e t e消して k e s i t e切替 k i r i k a e次 t u g i前 m a e% JUMONバルス b a r u s u% NOISE<sp> sp% NS_B<s> silB% NS_E<s> silE S : NS_B KADEN_ NOISE PLEASE NS_E

S : NS_B JUMON NS_EKADEN_ : KADENKADEN_ : KADEN WO% KADEN

<?xml version="1.0" encoding="UTF-8"?><iRemocon> <command word="テレビ(を|)(つけて|消して)" num="1" /> <command word="テレビ(を|)切替" num="2" /> <command word="テレビ(を|)次" num="3" /> <command word="テレビ(を|)前" num="4" /> <command word="電気(を|)つけて" num="11" /> <command word="電気(を|)消して" num="12" /></iRemocon>�

Page 12: Node.js × 音声認識 - 東京Node学園 2012 LT枠 6番目

…(前略)Jconf *jconf = j_config_load_args_new(j_argc, const_cast<char**>(j_argv));

if (jconf == nullptr) { std::cout << "Error @ j_config_load_args_new" << std::endl; return -1;}

Recog *recog = j_create_instance_from_jconf(jconf);if (recog == nullptr) { std::cout << "Error @ j_create_instance_from_jconf" << std::endl; return -1;}

callback_add(recog, CALLBACK_EVENT_SPEECH_READY, [](Recog *recog, void*) { std::cout << "<<< PLEASE SPEAK! >>>" << std::endl;}, nullptr);

callback_add(recog, CALLBACK_EVENT_SPEECH_START, [](Recog *recog, void*) {

std::cout << "...SPEECH START..." << std::endl;}, nullptr);

callback_add(recog, CALLBACK_RESULT, OnOutputResult, nullptr);…(後略)

C++/Juliusの設定ファイルを普通に書いていると…

% KADENテレビ t e r e b i電気 d e n k i% WOを w oを o% PLEASEつけて t u k e t e消して k e s i t e切替 k i r i k a e次 t u g i前 m a e% JUMONバルス b a r u s u% NOISE<sp> sp% NS_B<s> silB% NS_E<s> silE S : NS_B KADEN_ NOISE PLEASE NS_E

S : NS_B JUMON NS_EKADEN_ : KADENKADEN_ : KADEN WO% KADEN

<?xml version="1.0" encoding="UTF-8"?><iRemocon> <command word="テレビ(を|)(つけて|消して)" num="1" /> <command word="テレビ(を|)切替" num="2" /> <command word="テレビ(を|)次" num="3" /> <command word="テレビ(を|)前" num="4" /> <command word="電気(を|)つけて" num="11" /> <command word="電気(を|)消して" num="12" /></iRemocon>�

_人人人人人人人人人人_>               <>               <>               <>               <>               < ̄Y^Y^Y^Y^Y^Y^Y^Y^Y ̄

   _,,..,,,,_/  ,'  3   `ヽーっl    ⊃ ⌒_つ  `'ー---­‐'''''"面倒くさい!

Page 13: Node.js × 音声認識 - 東京Node学園 2012 LT枠 6番目

もっと簡単にできるようにしたい!

Page 14: Node.js × 音声認識 - 東京Node学園 2012 LT枠 6番目

どうせなら色んな機能と連携したい…

Page 15: Node.js × 音声認識 - 東京Node学園 2012 LT枠 6番目

そうだ! Node.js のC++ モジュール化しよう!

Page 16: Node.js × 音声認識 - 東京Node学園 2012 LT枠 6番目

C++ モジュール作ったことある方?

Page 17: Node.js × 音声認識 - 東京Node学園 2012 LT枠 6番目

C++ モジュール 難しくないです!

•  C++ ですが v8 / node.js のお作法に従うだけです•  例: hello() すると 'world' が返ってくる関数

#include <node.h> using namespace v8;

Handle<Value> Method(const Arguments& args) { HandleScope scope; return scope.Close( String::New("world") );}

void init(Handle<Object> target) { NODE_SET_METHOD (target, "hello", Method);}

NODE_MODULE(hello, init)

JavaScript に引き渡す関数

Node.js の世界へ C++ の

関数を送り出す

Page 18: Node.js × 音声認識 - 東京Node学園 2012 LT枠 6番目

C++ モジュール 難しくないです!

•  C++ ですが v8 / node.js のお作法に従うだけです•  例: hello() すると 'world' が返ってくる関数

#include <node.h> using namespace v8;

Handle<Value> Method(const Arguments& args) { HandleScope scope; return scope.Close( String::New("world") );}

void init(Handle<Object> target) { NODE_SET_METHOD (target, "hello", Method);}

NODE_MODULE(hello, init)

JavaScript に引き渡す関数

Node.js の世界へ C++ の

関数を送り出す

Page 19: Node.js × 音声認識 - 東京Node学園 2012 LT枠 6番目

C++ モジュール作り方

•  公式サイト … 大体ひと通り書いてある–  Node.js v0.8.14 マニュアル & ドキュメンテーション

•  http://nodejs.jp/nodejs.org_ja/docs/v0.8/api/addons.html

•  V8 について … v8 の世界について詳しく知りたい時–  Embedder's Guide - V8 JavaScript Engine

•  http://javascript.g.hatena.ne.jp/edvakf/20100407/1270626241

•  EventEmitter 利用方法 … libuv 用お作法–  Node.js で C++ アドオンから EventEmitter のイベントリスナ

を呼ぶ - 凹みTips•  http://d.hatena.ne.jp/hecomi/20121020/1350764244

•  マルチスレッド対応方法 … libuv の uv_queue_work を利用–  Node.js でマルチスレッド対応のネイティブモジュールを作成

する- 凹みTips•  http://d.hatena.ne.jp/hecomi/20121021/1350819390

この辺りが今回のミソ

Page 20: Node.js × 音声認識 - 東京Node学園 2012 LT枠 6番目

出来たモジュールを使ったコード1

var Julius  = require('julius') , grammar = new Julius.Grammar() ;  

grammar.add('(テレビ|エアコン)を?(つけて|消して)');grammar.add(‘お早う御座います');

grammar.compile(function(err, result) { if (err) throw err; var julius = new Julius( grammar.getJconf() );

julius.on('result', function(str) { console.log('認識結果:', str); });

julius.start();});

認識したい言葉を覚えさせる

コールバックの登録

他にも発話のタイミング等

各種コールバック登録可

Page 21: Node.js × 音声認識 - 東京Node学園 2012 LT枠 6番目

デモ(別途エントリ書きます)

Page 22: Node.js × 音声認識 - 東京Node学園 2012 LT枠 6番目

まとめ

C++ モジュール楽しいです!

Page 23: Node.js × 音声認識 - 東京Node学園 2012 LT枠 6番目

ご清聴ありがとうございました