FC2ブログ

スマフォのアプリを作りたい(15):音声認識させたい③

   プログラミング [2020/02/27]
react-native-google-speech-apiというパッケージを見つけて
糠喜びしたのもつかの間
ドはまりした話を前回書きました。

やっと、やっとGoogleのSpeech-to-Textを追っかけます。

さて、今回はサンプルコードを追っかけて、実際の音声認識をやってみて、その精度を確認したいと(今時点では)思っています。

◆react-native-google-speech-apiのサンプル
まずは、react-native-google-speech-apiのサイトにあったサンプルコードはちょっと処理が少なかったので、インストールした同パッケージ・フォルダ内のExample\App.jsを参考(丸写し+α)して、Speech.jsを作り直しました。
----Speech.js--------------------------------------
/**
* Sample React Native App
* https://github.com/facebook/react-native
*
* @format
* @flow
*/

import {
NativeModules,
Platform,
NativeEventEmitter,
DeviceEventEmitter,
Text,
View,
Button,
Alert,
PermissionsAndroid,
} from 'react-native';

import React, { Component } from 'react';

const { GoogleSpeechApi } = NativeModules;

const EventEmitter = Platform.select({
android: DeviceEventEmitter,
ios: new NativeEventEmitter(GoogleSpeechApi),
});

export default class Speech extends Component {

constructor(props) {
super(props);
this.state = {
currentText: "",
previousTexts: "",
button: "Start listening"
};
}

componentDidMount(){
GoogleSpeechApi.setApiKey("Your google access token");
EventEmitter.addListener('onSpeechRecognized', (event) => {
var previousTexts = this.state.previousTexts;
var currentText = event['text'];
var button = "I'm listening";
if (event['isFinal']){
currentText = "";
previousTexts = event['text'] + "\n" + previousTexts;
button = "Start listening";
}

this.setState({
currentText: currentText,
previousTexts: previousTexts,
button: button
});
});

EventEmitter.addListener('onSpeechRecognizedError', (error) => {
this.setState({
button: "Start listening"
});
Alert.alert(
"Error occured",
error['message']
);
});

EventEmitter.addListener('onSpeechEnd', (event) => {
console.log('Speech end');
});
EventEmitter.addListener('onSpeechError', (event) => {
console.log('Speech error');
});
EventEmitter.addListener('onSpeechResults', (event) => {
console.log('Speech Results');
});

}


startListening = () => {
this.setState({
button: "I'm listening"
});
GoogleSpeechApi.start();
}

requestAudioPermission = async () => {
try {
const granted = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.RECORD_AUDIO,
{
title: 'Record Audio Permission',
message:
'App needs access to your microphone ' +
'so you can convert speech to text.',
buttonNeutral: 'Ask Me Later',
buttonNegative: 'Cancel',
buttonPositive: 'OK',
},
);
if (granted === PermissionsAndroid.RESULTS.GRANTED) {
console.log('permission granted');
this.startListening();
} else {
console.log('permission denied');
}
} catch (err) {
console.warn(err);
}
}

render() {
return (
<View style={{ margin: 30 }}>
<Text>{this.state.currentText}</Text>
<Text>{this.state.previousTexts}</Text>
<Button
title={this.state.button}
onPress={Platform.OS === 'ios' ? this.startListening : this.requestAudioPermission}/>
</View>
);
}
}
---------------------------------------------------

※サンプルコードから以下を修正しています。
1)サンプルコードではところどころ「;」が無いところがありました。でもBuildは通りました。でも、なんだか気持ちが悪いので、「;」を追加しています。
2)それと、EventEmitter.addListener()メソッドで、イベント発生時のコールバック関数を指定できるようなのですが、デバッグ用に少し追加しました。ただし、イベント名はreact-native-voiceで使っているものを当てずっぽうで持ってきてます。


さらっと見た感じで、
1)Googleアクセス・トークンというのを指定しないといけないみたいです。
2)使用言語を指定している部分が見当たりません。
まずは、上記2点について調べます。




◆Google Cloud Platformの認証情報について
参考:https://cloud.google.com/speech-to-text/docs/reference/libraries
上記のサイトの途中に「[サービスアカウントキーの作成]ページに移動」というリンクがあります。
それをクリックして、表示される画面で「新しいサービスアカウント」/アカウント名/「Project」-「オーナー」/「JSON」を指定して、[作成]ボタンをクリックします。
以降、図の表示が小さくて見えない場合は、クリックすると文字が見える程度の画像で表示すると思います。
20200227_1.jpg

「My First Project-xxxxxxxxxxxx.json」というファイルがダウンロードされます。
中身は、以下の感じ。
どれくらい秘匿性のあるものなのか分からないので、だいぶ省略(・・・・)しちゃってます。
----JSON:------------------------------------------
{
"type": "service_account",
"project_id": "・・・・",
"private_key_id": "・・・・",
"private_key": "-----BEGIN PRIVATE KEY-----\n・・・・\n-----END PRIVATE KEY-----\n",
"client_email": "・・・・",
"client_id": "・・・・",
"auth_uri": "https://・・・・",
"token_uri": "https://・・・・",
"auth_provider_x509_cert_url": "https://・・・・",
"client_x509_cert_url": "https://・・・・"
}
---------------------------------------------------

どれが、トークン? JSON自体がそれ?
指定先のメソッドがGoogleSpeechApi.setApiKey()なので、「APIキー」?を指定するのか?

JSONをダウンロードした後に表示されたブラウザ上ページには、確かに「APIキー」という記述も見えて、先ほどのアカウント(.json)とは別に確保もできるっぽい。

Googleさんの認証に関する説明がありました。
参考:https://cloud.google.com/docs/authentication
ふぇーん。何言ってるのか分かんない。


一生懸命4度読みした結果、こういうことではないかと。
Googleのサービス(API)を使うには、サービスに対するアプリの認証とユーザの認証が必要。
認証のためのアカウントには、サービス用とユーザ用がある。(アカウントをプリンシパルとか言っている。)
アプリケーション認証情報として、APIキー、OAuth 2.0 クライアント資格情報、サービス アカウント キーがある。
認証のプロトコルはOAuth 2.0規格に従う。
※OAuth(オーオースと読む):権限の認可を行うための標準規格。
参考:https://qiita.com/TakahikoKawasaki/items/200951e5b5929f840a1f
Googleの認証フローをサポートしている「Google Cloudクライアントライブラリ」を使用する。

a)一般公開データへの匿名アクセス:
→「APIキー」を使用する。ただし、プリンシパル(ユーザ?、サービス?)を他の方法で認証する必要がある?

b)エンドユーザとしてプライベートデータにアクセス:
→「OAuth 2.0 クライアント資格情報」を使用する。

c)GCP(Google Cloud Platform)内でサービスアカウントとしてプライベートデータにアクセス:
→環境提供のサービスアカウントを使用する。

d)Google Cloud環境外でサービスアカウントとしてプライベートデータにアクセス:
→サービスアカウントキーを使用する。サービスアカウントキーとしてさるがGoogle CloudからダウンロードしたJSONファイルを指定するらしい。

これらa)~d)の意味の違いが判りますか?
さるとしては、「プライベートとじゃないデータって何のこと?」、「GCP内とGoogle Cloud環境外ってとこがいまいち・・・」の疑問が残ったままです。

サンプルコードのメソッド名からするとAPIキーを指定すればいい臭い。
また、音声認識するだけで「データ」をGoogle Cloud環境内に置くつもりはないので、a)として進めてもいいのだが、「別の方法で認証が必要」と注釈されている意味が不明。

ともかく、Google Cloudのサイトで「APIキー」を作成してみます。
以下のURLが入り口かと思います。
https://console.cloud.google.com/

1)Googleアカウント(メールアドレス)/パスワードを指定してログインします。
→GCPホーム画面になります。

2)左側メニュー「APIとサービス」をクリックします。
→結局、画面上の説明では、良くわかりませんでした。以下を参考にAPIキーを作成しました。
参考:https://life89.jp/register_gcp_get_api_key/


上記で得られたキーコードを「GoogleSpeechApi.setApiKey("Your google access token");」の「Your ・・・」と置き換えて実行してみました。
1)エミュレータ起動後に右側のアイコンバー「・・・」をクリックして、microphoneの設定を全部Enableにします。
2)アプリ上の「START LISTENING」をクリックします。
3)マイクに向かって話してみます。

一度だけRecognizeしたみたいで、ボタンの上に何やら謎のテキストが表示されました。
20200227_2.jpg

その後、「START LISTENING」ボタンをクリックしても、反応しなくなりました。
「Google Cloud Platform」サイトを見てみたら、APIの実行回数が見れました。確かに3回使ったみたいです。
20200227_3.jpg

でもこのときは、これっきり。神様の悪戯?
毎回マイクに反応するようになったわけではない。
かなり不安定です。


◆使用言語の設定
いったい、どこでやってるんでしょうか。
まずは、デフォルトの言語が英語っぽいので、「en-US」でreact-native-google-speech-apiフォルダ内をgrepして見ました。
「(プロジェクトフォルダ)\nod_modules\react-native-google-speech-api\」配下
「android\src\main\java\com\reactlibrary\speech_service\SpeechService.java」内に
・「private static final String LANGUAGE_CODE = "en-US";」が、たぶんデフォルトの言語を指定している部分かと思います。
・SpeechServiceクラス内のstartRecognizing()というメソッド内で、.setLanguageCode()メソッドに喰わせています。
・ここの他にsetLanguageCode()をコールしているとことはなく、LANGUAGE_CODE自体も変更できそうな感じではない。
 →括り付けになってる?
そう仮定して、ソース上の設定を"ja-JP"に変更してみました。

デバッガで動作を追っかけてみようとしましたが、SpeechService.java自体がChromeのデベロッパー・ツールのSource/Pageタブのツリーには表示されていませんでした。
無理やりSource/Filesystemタブからソースを表示させて設定個所にBreakPointを噛まして見ましたが、そこのコードでデバッガがBreakしてくれません・・・。
まともに動作しているのかも、よくわかりません。
Step実行的に追っかけようとしましたが・・・使用元のSpeech.jsのステートメントからは深すぎる感じ。
さらに、さるの動作環境がSSD(D:ドライブ)ベースで動かしているので、デバッガの動きもものすごい緩慢です。

ともかくすこもこ何回か立ち上げしている内に・・・
動いたみたいです。
20200227_4.jpg

「START LISTNING」を押して、話すと1文表示されて、ボタンのキャプションが「START LISTNING」に戻ります。
それを繰り返すと、上の図ように表示されます。

少し、先に進めた。(^ ^;)

でも、繰り返し認識させているうちに反応しなくなります。
原因は・・・・?


◆ビルド時に頻発したエラーについて
上記してきた内容をコードに反映して、Build&Go(react-native run-android)している間、不明なGradleのエラーが結構な頻度で発生しました。
多くは、以下の内容。
----コマンドプロンプト-----------------------------

Execution failed for task ':app:transformClassesWithDexBuilderForDebug'.
> Could not read path ・・・・

---------------------------------------------------

毎回のように、react-native-gesture-handlerのビルド中に発生しました。
その都度、pathで示されたフォルダを一旦削除してリトライ、あるいはフォルダを作成してあげてリトライしてましたが、
だんだん上記以外のエラーも発生しだした場合は、以下を実行すると治まる傾向にありました。

1)コマンドプロンプトでプロジェクトフォルダ\androidにカレントを移動します。
2)「gradlew cleanBuildCache」を実行する。

コマンドを実行直後もエラーが出る場合もありますが、リトライを続けるだけで、正常動作する場合もあります。
もう、分けわかんないです。


さて、動作が不安定で、かつreact-native-google-speech-apiパッケージの仕様は未だにさっぱり理解できていないのですが、再度ここで話を切ります。


次回、動作の不安定さの解消・・・動作していない「その他イベント時の動作」の実装見直しの話になろうかと思います。


では、この辺で。ごきげんよう。
(m__)m
スポンサーサイト





コメントの投稿

非公開コメント

カレンダー
01 | 2024/02 | 03
- - - - 1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 - -
プロフィール

さるもすなる

Author:さるもすなる
さるです。別HPサイト「さるもすなる」から侵食してきました。 山菜/きのこ、それとタイトルにしたPPバンド籠のことをメインに徒然に・・・・暇を持て余したさるの手仕事:男手芸のブログってことで。

最新記事
最新コメント
月別アーカイブ
カテゴリ
天気予報

-天気予報コム- -FC2-
本家のHPのトップ
山菜や茸の話です
PPバンドの籠作品と作り方です
投稿をお待ちしております



PVアクセスランキング にほんブログ村 にほんブログ村 ハンドメイドブログへ



マニュアルのお申し込み



検索フォーム
リンク
RSSリンクの表示
ブロとも申請フォーム

この人とブロともになる

QRコード
QR