はじめに
この記事は「大垣Pythonハッカソン@ヒーローズ・リーグ 2019 by MA」にて開発したシステム「二次元執事」の技術的な解説をしていきます。Qiitaへの投稿は初めてなので分からない事だらけですが、頑張って書いていきます!
今回の開発チームの紹介をします。
チーム名: 特攻野朗A
朗の字が違うのは仕様です。(チーム名決める時に学生さんが間違えたのでそのまま採用!)
- 社会人 1人 僕です(=゚ω゚)ノ
- 学生 3人
このようなチーム構成で今回のシステムを開発しました。
学生さんの内の1人がハッカソン経験者で、チームの雰囲気を非常に盛り上げてくれました。
伺か(うかがか)とは?
そもそもタイトルにある **伺か(うかがか)**とは何なのか?
その謎を明らかにすべく我々はアマゾンの奥地へ向かった。(違う)
伺かとは2000年初頭からネット上に存在していたデスクトップマスコットです。
制御に関しては さくらスクリプト という制御文字と読み上げ文章からなる専用の言語で行います。
↑ 今回のハッカソンにて登場した伺か「二次元執事」
皆さんが今回のハッカソンで目撃したデスクトップマスコットこそが伺かと呼ばれるものです!
伺かについての用語等をインプットも兼ねて下記のリンク先にまとめているので、詳しく知りたい方は見て下さい!
伺かマインドマップ
以降は皆さんに馴染みの少ない「伺か」という語をハッカソンで開発した「二次元執事」に統一します。
二次元執事の技術的なお話
プレゼンではざっくりとしか話せなかった箇所を解説していきたいと思います。
プレゼンで使った構成図では1か所だけやり取りが欠けていたので修正を加えました(ごめんなさい)
1. 音声認識Webアプリケーションの解説
Angular製のWebアプリケーションで音声認識をしています。
UIは非常にシンプルです。画面下のボタンを押すと音声認識が開始されます。
音声認識の機能に関しては外部のライブラリ等を使用せずに、Chromeで使用出来る WebSpeechAPI を使用しています。
使用方法は極めてシンプルです(説明に必要の無い import 等のコードは省略しています)
1-1. ソースコードの全容
音声認識のロジックを記述しているのは実質1ファイルです。
// TypeScriptでグローバルオブジェクトのwebkitSpeechRecognitionを動かせるようにする
declare const webkitSpeechRecognition;
export class MicrophoneComponent {
recognition: any;
constructor(private http: HttpClient, private sharedService: SharedService) {
// WebSpeechAPIのインスタンスを生成後、recognitionフィールドに代入
this.recognition = new webkitSpeechRecognition();
}
// ボタンを押した後に走るメソッドを実装
async recordVoice() {
// 言語設定を日本語に設定
this.recognition.lang = 'ja';
// 音声認識後に走る処理を設定(やりとり1の後に走る)
this.recognition.onresult = (event) => {
// nobyの設定(送信するテキストや人格設定など)
const params = {
// Nobyのキー
appkey: 'XXXXXXXXXXXXXXXXXXXXXXX',
// 下記の event.results[0][0].transcript に音声認識で解析された文章が入っている
text: event.results[0][0].transcript,
// 学習機能あり 1 なし 0
study: '1',
// 人格 :0:ノーマル」,「1:ツンデレ(女)」,「2:ツンデレ(男)」,「3:神」
persona: '0',
// 語尾
ending: 'だね'
};
// NobyAPIに対してパラメタを指定してGetリクエスト(やりとり2)
this.http.get('https://app.cotogoto.ai/webapi/noby.json', {params: params}).subscribe((data: any) => {
const paramsSsp = {message: data.text, nobydata: data};
// NobyAPIから受け取ったレスポンスをlocalhostのNode.jsのサーバにPostリクエスト(やりとり3)
// localhostを外部へ公開する手段としてはServeoを採用(https://serveo.net/)
this.http.post('https://hogehuga.serveo.net/api/readText', paramsSsp).subscribe(() => {
console.log('success');
});
});
};
// 音声認識開始(やりとり1)
this.recognition.start();
// トーストの起動
await this.sharedService.presentToast('マイクに話しかけて下さい');
}
}
1-2. WebSpeechAPI の生成
コンストラクタで WebSpeechAPI のインスタンスを生成後にrecognitionフィールドに代入しています。
// TypeScriptでグローバルオブジェクトのwebkitSpeechRecognitionを動かせるようにする
declare const webkitSpeechRecognition;
export class MicrophoneComponent {
recognition: any;
constructor(private http: HttpClient, private sharedService: SharedService) {
// WebSpeechAPIのインスタンスを生成後、recognitionフィールドに代入
this.recognition = new webkitSpeechRecognition();
}
}
1-3. ボタンが押された後に走るメソッドの実装
Angularのイベントバインディングを使用して、ボタンが押されたタイミングで
下記のメソッドが発火されるようになっています。(テンプレート側にちょっとした記述がありますが、今回は割愛)
// ボタンを押した後に走るメソッドを実装
async recordVoice() {
// 言語設定を日本語に設定
this.recognition.lang = 'ja';
// 音声認識後に走る処理を設定(やりとり1の後に走る)
this.recognition.onresult = (event) => {
// nobyの設定(送信するテキストや人格設定など)
const params = {
// Nobyのキー
appkey: 'XXXXXXXXXXXXXXXXXXXXXXX',
// 下記の event.results[0][0].transcript に音声認識で解析された文章が入っている
text: event.results[0][0].transcript,
// 学習機能あり 1 なし 0
study: '1',
// 人格 :0:ノーマル」,「1:ツンデレ(女)」,「2:ツンデレ(男)」,「3:神」
persona: '0',
// 語尾
ending: 'だね'
};
// NobyAPIに対してパラメタを指定してGetリクエスト(やりとり2)
this.http.get('https://app.cotogoto.ai/webapi/noby.json', {params: params}).subscribe((data: any) => {
const paramsSsp = {message: data.text, nobydata: data};
// NobyAPIから受け取ったレスポンスをlocalhostのNode.jsのサーバにPostリクエスト(やりとり3)
// localhostを外部へ公開する手段としてはServeoを採用(https://serveo.net/)
this.http.post('https://hogehuga.serveo.net/api/readText', paramsSsp).subscribe(() => {
console.log('success');
});
});
};
// 音声認識開始(やりとり1)
this.recognition.start();
// トーストの起動
await this.sharedService.presentToast('マイクに話しかけて下さい');
}
ちょっと一休み...
この記事に全ての解説を載せてまとめて公開しようと思いましたが、書いてる人の貧弱なモチベーションが死にそうだったので
とりあえず今回はウェブアプリケーション側の解説だけに留めたいと思います😅
(アウトプットつよつよマンになりたい🙃)
次回は ExpressAPIサーバ と 二次元執事本体 の解説をしていきます!
最後に
惜しくも時間内に作品を最後まで作り切る事は出来ませんでしたが、いくつかの賞を頂けたのは
良きチームメンバーや、粘り強くサポートして頂いた企業の方のお陰だと思っております。
運営の方々も2日間お世話になりました!
また来年もよろしくお願いいたします。