300行のコードは祖母に音声検索ショッピング機能を実現させます。


「強ちゃん、手書きの板がまたなくなったんですか?」
最近、プログラマーの阿強さんは新しいものを試しているおばあさんで、またネットショッピングに夢中になりました。あまり気を使わずに買い物ソフトを調べてみたら、スムーズなネットショッピングの道だと思いましたが、検索品にひっかかりました。
手書きで入力するコーナーで、誤操作するか、知らない入力方法に切り替えることがあります。インタフェースの抽象的な指令文字を誤って押してしまうか、おばあさんからもよく助けを求められます。
実際には、ショッピングアプリだけではなく、今のスマートフォンに搭載されている大きなアプリは、若いグループに傾いているインタラクティブなデザインであり、高齢者が体験して使えるようになりたいです。
毎回根気よくおばあさんを指導して操作を完成した後に、阿強、この成熟したcoderは自分に需要を持ってきました。入力方法に慣れるだけではなく、入力方法を祖母の好みに合わせて使う。
手動入力は間違いやすいです。音声を書いて文字の入力方法を変えます。録音ボタンを起動しさえすれば、リアルタイムの音声認識入力は簡単で速いです。
効果例
3
アプリケーションシーン
リアルタイム音声認識と音声回転文字は、豊富なアプリケーションのシーンを持っています。
ゲームの応用中の運用:オンラインゲーム場でチームを組んで暗い時、リアルタイムの音声認識でチームメイトと意思疎通ができます。両手を使わない同時に、麦が音を出すのが気まずいことも避けられました。
ビジネスアプリケーションでの運用:職場では、時間がかかる会議で、手でコードワードを記録するのは効果的ではなく、細部まで漏れやすいです。オーディオファイルを使って文字機能を変換し、会議の討論内容を書き換えて、後で書き換えた文字を整理し、色を調整することができます。
応用を学ぶ中の运用:今ますます多くなるオーディオの教育の材料、観ながらノートをすることを停止して、とても容易に学习のリズムを中断して、学习の过程の完备性を破壊して、オーディオのファイルの転书があって、システムの学习は教材を终わった后に、更に文字に対して复习して整理して、学习の体験はもっと良いです。
原理を実現する
ファーウェイ機械学習サービスは、リアルタイムの音声認識および音声ファイルの書き換え能力を提供する。
リアルタイム音声認識
リアルタイムで入力される短い音声(60秒以内)をテキストに変換することができます。識別精度は95%以上になります。現在は中国語共通語、英語、中英混話、フランス語、ドイツ語、スペイン語、イタリア語、アラビア語の識別をサポートしています。
  • はリアルタイムでの単語の出力をサポートしています。
  • は、集音インターフェース、無集音インターフェースの2つの方法を提供する。
  • は、端点検出をサポートし、開始点と終了点を正確に位置決めすることができる。
  • は、静音検査をサポートしており、音声の中で話さない部分は音声パケットを送信しない。
  • は、デジタルフォーマットのインテリジェント変換をサポートしています。例えば、音声入力「二〇二一年」の場合、スマートに「2021年」と認識することができます。
  • オーディオファイルの書き換え
    5時間以内のオーディオファイルを文字に変換して、句読点の出力をサポートし、断句合理的で分かりやすいテキスト情報を形成します。タイムスタンプ付きテキスト情報の生成にも対応していますので、後でより多くの機能を開発することができます。現在のバージョンは英語の書き換えをサポートしています。

    開発ステップ
    開発前準備
    1.ファーウェイのMaven倉住所を配置し、agconnect-services.jsonファイルをappディレクトリの下に置く:
    Android Studioプロジェクトレベルの「build.gradle」ファイルを開きます。

    HUAWEI agcpプラグインとMavenコードライブラリを追加します。
  • は、「allproject」repositoriesにHMS Core SDKのMaven倉アドレスを配置する。
  • は、「buildscript」repositoriesにHMS Core SDKのMaven倉アドレスを配置する。
  • Appに「agconnect-services.json」ファイルを追加すると「buildscript」dependencies」にagcpプロファイルを追加する必要があります。
  • 
    buildscript {
     repositories {
     google()
     jcenter()
     maven { url 'https://developer.huawei.com/repo/' }
     }
     dependencies {
     classpath 'com.android.tools.build:gradle:3.5.4'
     classpath 'com.huawei.agconnect:agcp:1.4.1.300'
     // NOTE: Do not place your application dependencies here; they belong
     // in the individual module build.gradle files
     }
    }
     
    allprojects {
     repositories {
     google()
     jcenter()
     maven { url 'https://developer.huawei.com/repo/' }
     }
    }
    雲端鑑権情報使用心得を参照して、アプリケーションの認証情報を設定します。
    2.コンパイルSDK依存性を追加:
    
    dependencies {
     //         SDK
     implementation 'com.huawei.hms:ml-computer-voice-aft:2.2.0.300'
     //        SDK.
     implementation 'com.huawei.hms:ml-computer-voice-asr:2.2.0.300'
     //        plugin.
     implementation 'com.huawei.hms:ml-computer-voice-asr-plugin:2.2.0.300'
     ...
    }
    apply plugin: 'com.huawei.agconnect' // HUAWEI agconnect Gradle plugin
    3.appのbuildに署名ファイルを配置し、署名ファイル(xxx.jks)をappディレクトリに入れる:
    
    signingConfigs {
     release {
     storeFile file("xxx.jks")
     keyAlias xxx
     keyPassword xxxxxx
     storePassword xxxxxx
     v1SigningEnabled true
     v2SigningEnabled true
     }
     
    }
     
    buildTypes {
     release {
     minifyEnabled false
     proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
     }
     
     debug {
     signingConfig signingConfigs.release
     debuggable true
     }
    }
    4.Manifest.xmlに権限を追加する:
    
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
     
    <application
     android:requestLegacyExternalStorage="true"
     ...
    </application>
    リアルタイム音声認識能力にアクセスする
    1.権限動態申請を行う:
    
    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
     requestCameraPermission();
    }
     
    private void requestCameraPermission() {
     final String[] permissions = new String[]{Manifest.permission.RECORD_AUDIO};
     if (!ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.RECORD_AUDIO)) {
     ActivityCompat.requestPermissions(this, permissions, Constants.AUDIO_PERMISSION_CODE);
     return;
     }
    }
    2.リアルタイム音声認識パラメータを設定するためにIntentを作成します。
    
    //          
    MLApplication.getInstance().setApiKey(AGConnectServicesConfig.fromContext(this).getString("client/api_key"));
       intent      。
    Intent intentPlugin = new Intent(this, MLAsrCaptureActivity.class)
     //          ,    ,       。    :"zh-CN":  ;"en-US":   。
     .putExtra(MLAsrCaptureConstants.LANGUAGE, MLAsrConstants.LAN_ZH_CN)
     //               
     .putExtra(MLAsrCaptureConstants.FEATURE, MLAsrCaptureConstants.FEATURE_WORDFLUX);
    startActivityForResult(intentPlugin, "1");
    3.「onActivityResoult」という方法を繰り返し、音声認識サービスの返却結果を処理します。
    
    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
     super.onActivityResult(requestCode, resultCode, data);
     String text = "";
     if (null == data) {
     addTagItem("Intent data is null.", true);
     }
     if (requestCode == "1") {
     if (data == null) {
      return;
     }
     Bundle bundle = data.getExtras();
     if (bundle == null) {
      return;
     }
     switch (resultCode) {
      case MLAsrCaptureConstants.ASR_SUCCESS:
      //              。
      if (bundle.containsKey(MLAsrCaptureConstants.ASR_RESULT)) {
       text = bundle.getString(MLAsrCaptureConstants.ASR_RESULT);
      }
      if (text == null || "".equals(text)) {
       text = "Result is null.";
       Log.e(TAG, text);
      } else {
       //              
       searchEdit.setText(text);
       goSearch(text, true);
      }
      break;
      //     MLAsrCaptureConstants.ASR_FAILURE      。
      case MLAsrCaptureConstants.ASR_FAILURE:
      //          。
      if (bundle.containsKey(MLAsrCaptureConstants.ASR_ERROR_CODE)) {
       text = text + bundle.getInt(MLAsrCaptureConstants.ASR_ERROR_CODE);
       //         。
      }
      //           。
      if (bundle.containsKey(MLAsrCaptureConstants.ASR_ERROR_MESSAGE)) {
       String errorMsg = bundle.getString(MLAsrCaptureConstants.ASR_ERROR_MESSAGE);
       //          。
       if (errorMsg != null && !"".equals(errorMsg)) {
       text = "[" + text + "]" + errorMsg;
       }
      }
      //          。
      if (bundle.containsKey(MLAsrCaptureConstants.ASR_SUB_ERROR_CODE)) {
       int subErrorCode = bundle.getInt(MLAsrCaptureConstants.ASR_SUB_ERROR_CODE);
       //          。
       text = "[" + text + "]" + subErrorCode;
      }
      Log.e(TAG, text);
      break;
      default:
      break;
     }
     }
    }
    オーディオファイルの書き換えにアクセス
    1.ダイナミック権限の申請。
    
    private static final int REQUEST_EXTERNAL_STORAGE = 1;
    private static final String[] PERMISSIONS_STORAGE = {
     Manifest.permission.READ_EXTERNAL_STORAGE,
     Manifest.permission.WRITE_EXTERNAL_STORAGE };
    public static void verifyStoragePermissions(Activity activity) {
     // Check if we have write permission
     int permission = ActivityCompat.checkSelfPermission(activity,
      Manifest.permission.WRITE_EXTERNAL_STORAGE);
     if (permission != PackageManager.PERMISSION_GRANTED) {
     // We don't have permission so prompt the user
     ActivityCompat.requestPermissions(activity, PERMISSIONS_STORAGE,
      REQUEST_EXTERNAL_STORAGE);
     }
    }
    2.オーディオファイルの書き換えエンジンを新設し、初期化する。オーディオファイルの書き換え設定を新規作成します。
    
    //    ApiKey.
    MLApplication.getInstance().setApiKey(AGConnectServicesConfig.fromContext(getApplication()).getString("client/api_key"));
    MLRemoteAftSetting setting = new MLRemoteAftSetting.Factory()
     //         ,  BCP-47  ,         、    。
     .setLanguageCode("zh")
     //                      ,   false。
     .enablePunctuation(true)
     //                            ,   false(      1         )。
     .enableWordTimeOffset(true)
     //                       ,   false。
     .enableSentenceTimeOffset(true)
     .create();
     
    //           。
    MLRemoteAftEngine engine = MLRemoteAftEngine.getInstance();
    engine.init(this);
    //                         
    engine.setAftListener(aftListener);
    3.オーディオファイルの書き換え結果を処理するために、新しいリスタのフィードバックを作成します。
    短い音声の書き換え:1分未満のオーディオファイルに適用されます。
    
    private MLRemoteAftListener aftListener = new MLRemoteAftListener() {
     public void onResult(String taskId, MLRemoteAftResult result, Object ext) {
     //         。
     if (result.isComplete()) {
      //       。
     }
     }
     @Override
     public void onError(String taskId, int errorCode, String message) {
     //         。
     }
     @Override
     public void onInitComplete(String taskId, Object ext) {
     //     。
     }
     @Override
     public void onUploadProgress(String taskId, double progress, Object ext) {
     //     。
     }
     @Override
     public void onEvent(String taskId, int eventId, Object ext) {
     //     。
     }
    };
    長音声書き換え:1分間以上のオーディオファイルに適用します。
    
    private MLRemoteAftListener asrListener = new MLRemoteAftListener() {
     @Override
     public void onInitComplete(String taskId, Object ext) {
     Log.e(TAG, "MLAsrCallBack onInitComplete");
     //         ,    
     start(taskId);
     }
     @Override
     public void onUploadProgress(String taskId, double progress, Object ext) {
     Log.e(TAG, " MLAsrCallBack onUploadProgress");
     }
     @Override
     public void onEvent(String taskId, int eventId, Object ext) {
     //      
     Log.e(TAG, "MLAsrCallBack onEvent" + eventId);
     if (MLAftEvents.UPLOADED_EVENT == eventId) { //       
      //       
      startQueryResult(taskId);
     }
     }
     @Override
     public void onResult(String taskId, MLRemoteAftResult result, Object ext) {
     Log.e(TAG, "MLAsrCallBack onResult taskId is :" + taskId + " ");
     if (result != null) {
      Log.e(TAG, "MLAsrCallBack onResult isComplete: " + result.isComplete());
      if (result.isComplete()) {
      TimerTask timerTask = timerTaskMap.get(taskId);
      if (null != timerTask) {
       timerTask.cancel();
       timerTaskMap.remove(taskId);
      }
      if (result.getText() != null) {
       Log.e(TAG, taskId + " MLAsrCallBack onResult result is : " + result.getText());
       tvText.setText(result.getText());
      }
      List<MLRemoteAftResult.Segment> words = result.getWords();
      if (words != null && words.size() != 0) {
       for (MLRemoteAftResult.Segment word : words) {
       Log.e(TAG, "MLAsrCallBack word text is : " + word.getText() + ", startTime is : " + word.getStartTime() + ". endTime is : " + word.getEndTime());
       }
      }
      List<MLRemoteAftResult.Segment> sentences = result.getSentences();
      if (sentences != null && sentences.size() != 0) {
       for (MLRemoteAftResult.Segment sentence : sentences) {
       Log.e(TAG, "MLAsrCallBack sentence text is : " + sentence.getText() + ", startTime is : " + sentence.getStartTime() + ". endTime is : " + sentence.getEndTime());
       }
      }
      }
     }
     }
     @Override
     public void onError(String taskId, int errorCode, String message) {
     Log.i(TAG, "MLAsrCallBack onError : " + message + "errorCode, " + errorCode);
     switch (errorCode) {
      case MLAftErrors.ERR_AUDIO_FILE_NOTSUPPORTED:
      break;
     }
     }
    };
    //       
    private void start(String taskId) {
     Log.e(TAG, "start");
     engine.setAftListener(asrListener);
     engine.startTask(taskId);
    }
    //       
    private Map<String, TimerTask> timerTaskMap = new HashMap<>();
    private void startQueryResult(final String taskId) {
     Timer mTimer = new Timer();
     TimerTask mTimerTask = new TimerTask() {
     @Override
     public void run() {
      getResult(taskId);
     }
     };
     // 10s           
     mTimer.schedule(mTimerTask, 5000, 10000);
     //          timerTaskMap
     timerTaskMap.put(taskId, mTimerTask);
    }
    4.オーディオを取得し、オーディオファイルを書き換えエンジンにアップロードする:
    
    //       uri
    Uri uri = getFileUri();
    //      
    Long audioTime = getAudioFileTimeFromUri(uri);
    //          60 
    if (audioTime < 60000) {
     // uri                   ,      1         
     this.taskId = this.engine.shortRecognize(uri, this.setting);
     Log.i(TAG, "Short audio transcription.");
    } else {
     // longRecognize        ,        1  ,  5     。
     this.taskId = this.engine.longRecognize(uri, this.setting);
     Log.i(TAG, "Long audio transcription.");
    }
     
    private Long getAudioFileTimeFromUri(Uri uri) {
     Long time = null;
     Cursor cursor = this.getContentResolver()
      .query(uri, null, null, null, null);
     if (cursor != null) {
     
     cursor.moveToFirst();
     time = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATION));
     } else {
     MediaPlayer mediaPlayer = new MediaPlayer();
     try {
      mediaPlayer.setDataSource(String.valueOf(uri));
      mediaPlayer.prepare();
     } catch (IOException e) {
      Log.e(TAG, "Failed to read the file time.");
     }
     time = Long.valueOf(mediaPlayer.getDuration());
     }
     return time;
    }
    以上で300行のコードについておばあさんに音声検索ショッピング機能を実現させた文章を紹介します。より多くの関連祖母が音声検索ショッピング内容を実現しました。私達の以前の文章を検索してください。または次の関連記事を引き続き閲覧してください。これからもよろしくお願いします。