Статьи

Создайте интеллектуальное приложение с Google Cloud Speech и API на естественном языке

Приложение, которое действительно понимает естественный язык — это то, о чем мечтали ученые, программисты и исследователи искусственного интеллекта десятилетиями. Сегодня, благодаря значительному прогрессу в технологиях машинного обучения, эта мечта как никогда близка к воплощению в жизнь. Более того, облачные сервисы, такие как Google Cloud Machine Learning, сделали эти технологии свободно доступными для всех.

В этом руководстве вы узнаете, как использовать два мощных API-интерфейса, ориентированных на естественный язык, предлагаемых платформой Google Cloud Machine Learning: Cloud Speech API и Cloud Natural Language API . Используя их вместе, вы можете создавать приложения, которые могут обрабатывать речь на различных широко распространенных языках.

Чтобы следовать, вам нужно:

Приложение, которое может обрабатывать речь, должно иметь следующие возможности:

  • Он должен быть в состоянии извлечь отдельные слова из необработанных аудиоданных.
  • Он должен быть в состоянии сделать обоснованные предположения о грамматических отношениях между словами, которые он извлек.

Облачные API-интерфейсы Cloud Speech и Cloud Natural Language позволяют в считанные минуты добавить вышеуказанные возможности в ваше приложение для Android.

Cloud Speech API служит современным средством распознавания речи, которое может точно транскрибировать речь на более чем 80 языках. Он также может эффективно обрабатывать региональные акценты и шумные условия.

Аналогичным образом, Cloud Natural Language API — это система языковой обработки, которая может с точностью, близкой к человеческой, определять роли, которые играют слова в данных предложениях. В настоящее время он поддерживает десять языков, а также предлагает анализ сущностей и настроений.

Прежде чем использовать API речи и естественного языка, необходимо включить их в консоли Google Cloud. Так что войдите в консоль и перейдите к API Manager> Библиотека .

Облачная консольная библиотека

Чтобы включить Speech API, нажмите на ссылку Speech API в разделе Google Cloud Machine Learning . На открывшейся следующей странице нажмите кнопку « Включить» .

Включение API Cloud Speech

Нажмите кнопку назад вашего браузера, чтобы вернуться на предыдущую страницу.

На этот раз активируйте API естественного языка, щелкнув ссылку API естественного языка и нажав кнопку « Включить» на следующей странице.

Включение API Cloud Natural Language

Вам понадобится ключ API при взаимодействии с API. Если у вас его еще нет, откройте вкладку « Учетные данные », нажмите кнопку « Создать учетные данные» и выберите ключ API .

Теперь вы увидите всплывающее окно, отображающее ваш ключ API. Запишите это, чтобы вы могли использовать его позже.

Ключ API сгенерирован

Оба API основаны на JSON и имеют конечные точки REST, с которыми вы можете напрямую взаимодействовать, используя любую сетевую библиотеку. Однако вы можете сэкономить много времени — а также написать более читаемый код — используя доступные для них клиентские библиотеки Google API . Поэтому откройте файл build.gradle модуля app вашего проекта и добавьте в него следующие зависимости compile :

1
2
3
4
compile ‘com.google.api-client:google-api-client-android:1.22.0’
compile ‘com.google.apis:google-api-services-speech:v1beta1-rev336-1.22.0’
compile ‘com.google.apis:google-api-services-language:v1beta2-rev6-1.22.0’
compile ‘com.google.code.findbugs:jsr305:2.0.1’

Кроме того, в этом руководстве мы выполним несколько операций ввода-вывода файлов. Чтобы упростить их, добавьте зависимость compile для библиотеки ввода-вывода Commons .

1
compile ‘commons-io:commons-io:2.5’

Наконец, не забудьте запросить разрешение INTERNET в файле AndroidManifest.xml . Без этого ваше приложение не сможет подключаться к серверам Google.

1
<uses-permission android:name=»android.permission.INTERNET»/>

Само собой разумеется, что Cloud Speech API ожидает аудиоданные в качестве одного из своих входных данных. Поэтому сейчас мы будем создавать приложение для Android, которое может транскрибировать аудиофайлы.

Для простоты мы будем транскрибировать только файлы FLAC, файлы, которые используют формат кодирования Free Lossless Audio Codec. Возможно, у вас уже есть такие файлы на вашем устройстве. Если вы этого не сделаете, я предлагаю вам скачать несколько из Wikimedia Commons .

Макет нашего приложения будет иметь виджет Button пользователи могут нажимать для отображения средства выбора файлов, интерфейса, через который они могут просматривать и выбирать аудиофайлы, доступные на их устройствах.

Макет также будет иметь виджет TextView для отображения транскрипта выбранного аудиофайла. Соответственно, добавьте следующий код в XML-файл макета вашей деятельности:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
<TextView
    android:layout_width=»match_parent»
    android:layout_height=»wrap_content»
    android:text=»»
    android:id=»@+id/speech_to_text_result»
    android:textSize=»18sp»
    android:layout_alignParentTop=»true»/>
 
<Button
    android:layout_width=»match_parent»
    android:layout_height=»wrap_content»
    android:layout_alignParentBottom=»true»
    android:id=»@+id/browse_button»
    android:text=»Browse»/>

Интерфейс средства выбора файлов должен отображаться, когда пользователь нажимает кнопку, созданную на предыдущем шаге, поэтому OnClickListener объект OnClickListener с ним. Прежде чем сделать это, убедитесь, что вы инициализируете кнопку с findViewById() метода findViewById() .

1
2
3
4
5
6
7
8
Button browseButton = (Button)findViewById(R.id.browse_button);
 
browseButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        // More code here
    }
});

Благодаря платформе Android Storage Access Framework, которая доступна на устройствах с API уровня 19 или выше, создание средства выбора файлов занимает очень мало усилий. Все, что вам нужно сделать, это создать намерение для действия ACTION_GET_CONTENT и передать его startActivityForResult() . При желании вы можете ограничить setType() файлов отображением только файлов FLAC, передав соответствующий тип MIME setType() объекта Intent .

1
2
3
Intent filePicker = new Intent(Intent.ACTION_GET_CONTENT);
filePicker.setType(«audio/flac»);
startActivityForResult(filePicker, 1);

Вывод средства выбора файлов будет другим объектом Intent содержащим URI файла, выбранного пользователем. Чтобы иметь доступ к нему, вы должны переопределить метод onActivityResult() вашего класса Activity .

01
02
03
04
05
06
07
08
09
10
11
@Override
protected void onActivityResult(int requestCode, int resultCode,
                                                    Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if(resultCode == RESULT_OK) {
        final Uri soundUri = data.getData();
 
        // More code here
         
    }
}

Cloud Speech API ожидает, что его аудиоданные будут в форме строки Base64. Чтобы сгенерировать такую ​​строку, вы можете прочитать содержимое файла, выбранного пользователем, в byte массив и передать его в служебный метод encodeBase64String() предлагаемый клиентской библиотекой Google API.

Однако в настоящее время у вас есть только URI выбранного файла, а не его абсолютный путь. Это означает, что для чтения файла вы должны сначала разрешить URI. Вы можете сделать это, передав его в метод openInputStream() преобразователя содержимого вашей деятельности. Получив доступ к входному потоку файла, вы можете просто передать его toByteArray() класса IOUtils чтобы преобразовать его в массив байтов. Следующий код показывает вам, как:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
AsyncTask.execute(new Runnable() {
    @Override
    public void run() {
        InputStream stream = getContentResolver()
                                .openInputStream(soundUri);
        byte[] audioData = IOUtils.toByteArray(stream);
        stream.close();
 
        String base64EncodedData =
                        Base64.encodeBase64String(audioData);
 
        // More code here
    }
}

Как видно из приведенного выше кода, мы используем новый поток для выполнения всех операций ввода-вывода. Это важно для того, чтобы пользовательский интерфейс приложения не зависал.

По моему мнению, воспроизведение звукового файла, который транскрибируется, пока он транскрибируется, является хорошей идеей. Это не займет много усилий, и это улучшает пользовательский опыт.

Вы можете использовать класс MediaPlayer для воспроизведения звукового файла. Как только вы setDataSource() его на URI файла, используя метод setDataSource() , вы должны вызвать его метод prepare() для синхронной подготовки проигрывателя. Когда проигрыватель готов, вы можете вызвать его метод start() чтобы начать воспроизведение файла.

Кроме того, вы должны помнить, чтобы освободить ресурсы проигрывателя после завершения воспроизведения файла. Для этого назначьте OnCompletionListener объект OnCompletionListener и вызовите его метод release() . Следующий код показывает вам, как:

01
02
03
04
05
06
07
08
09
10
11
12
13
MediaPlayer player = new MediaPlayer();
player.setDataSource(MainActivity.this, soundUri);
player.prepare();
player.start();
 
// Release the player
player.setOnCompletionListener(
        new MediaPlayer.OnCompletionListener() {
            @Override
            public void onCompletion(MediaPlayer mediaPlayer) {
                mediaPlayer.release();
            }
});

На этом этапе мы можем отправить аудиоданные в кодировке Base64 в Cloud Speech API для их расшифровки. Но сначала я предлагаю вам сохранить ключ API, сгенерированный вами ранее, как переменную-член вашего класса Activity .

1
private final String CLOUD_API_KEY = «ABCDEF1234567890»;

Чтобы иметь возможность общаться с Cloud Speech API, вы должны создать объект Speech используя экземпляр Speech.Builder . В качестве аргументов его конструктор ожидает транспорт HTTP и фабрику JSON. Кроме того, чтобы убедиться, что ключ API включен в каждый HTTP-запрос к API, необходимо связать объект SpeechRequestInitializer со SpeechRequestInitializer и передать ему ключ.

Следующий код создает объект Speech используя класс AndroidJsonFactory в качестве фабрики JSON и класс NetHttpTransport в качестве транспорта HTTP:

1
2
3
4
5
6
7
Speech speechService = new Speech.Builder(
               AndroidHttp.newCompatibleTransport(),
               new AndroidJsonFactory(),
               null
       ).setSpeechRequestInitializer(
           new SpeechRequestInitializer(CLOUD_API_KEY))
        .build();

API Cloud Speech необходимо указать, на каком языке содержится аудиофайл. Вы можете сделать это, создав объект RecognitionConfig и вызвав его setLanguageCode() . Вот как вы настраиваете его для расшифровки только американского английского:

1
2
RecognitionConfig recognitionConfig = new RecognitionConfig();
recognitionConfig.setLanguageCode(«en-US»);

Кроме того, строка в кодировке Base64 должна быть обернута в объект RecognitionAudio прежде чем ее можно будет использовать API.

1
2
RecognitionAudio recognitionAudio = new RecognitionAudio();
recognitionAudio.setContent(base64EncodedData);

Затем, используя объекты RecognitionConfig и RecognitionAudio , вы должны создать объект SyncRecognizeRequest . Как следует из его названия, он позволяет создавать HTTP-запрос для синхронной записи аудиоданных. После того как объект создан, вы можете передать его в качестве аргумента syncrecognize() и вызвать результирующий метод execute() объекта Speech.SpeechOperations.Syncrecognize для фактического выполнения HTTP-запроса.

Возвращаемое значение метода execute() — это объект SyncRecognizeResponse , который может содержать несколько альтернативных стенограмм. Пока мы будем использовать только первый вариант.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
// Create request
SyncRecognizeRequest request = new SyncRecognizeRequest();
request.setConfig(recognitionConfig);
request.setAudio(recognitionAudio);
 
// Generate response
SyncRecognizeResponse response = speechService.speech()
                                    .syncrecognize(request)
                                    .execute();
 
// Extract transcript
SpeechRecognitionResult result = response.getResults().get(0);
final String transcript = result.getAlternatives().get(0)
                                .getTranscript();

Наконец, чтобы отобразить стенограмму для пользователя, вы можете передать ее в виджет TextView . Конечно, поскольку изменения в пользовательском интерфейсе всегда должны происходить в потоке пользовательского интерфейса, убедитесь, что вы делаете это после вызова метода runOnUiThread() вашей деятельности.

1
2
3
4
5
6
7
8
runOnUiThread(new Runnable() {
    @Override
    public void run() {
        TextView speechToTextResult =
                (TextView)findViewById(R.id.speech_to_text_result);
        speechToTextResult.setText(transcript);
    }
});

Теперь вы можете запустить свое приложение, выбрать файл FLAC, содержащий речь на американском английском, и увидеть, как Cloud Speech API создает для него стенограмму.

Стоит отметить, что Cloud Speech API в настоящее время может обрабатывать только одноканальные аудиофайлы. Если вы отправите на него файл с несколькими каналами, вы получите ответ об ошибке.

Теперь, когда у нас есть стенограмма, мы можем передать ее в Cloud Natural Language API для ее анализа. Чтобы этот урок был коротким, мы будем проводить анализ сущностей и настроений только в стенограмме. Другими словами, мы собираемся определить все сущности, которые упоминаются в стенограмме, такие как люди, места и профессии, а также сказать, является ли его общее настроение отрицательным, нейтральным или положительным.

Чтобы позволить пользователю начать анализ, наш макет должен содержать другой виджет Button . Поэтому добавьте следующий код в XML-файл макета вашей деятельности:

1
2
3
4
5
6
<Button
   android:layout_width=»match_parent»
   android:layout_height=»wrap_content»
   android:layout_above=»@+id/browse_button»
   android:id=»@+id/analyze_button»
   android:text=»Analyze»/>

API-интерфейс Cloud Natural Language REST предлагает удобную опцию annotateText, которая позволяет выполнять анализ настроений и сущностей в документе всего одним HTTP-запросом. Мы будем использовать его для анализа нашего стенограммы.

Поскольку анализ должен начинаться, когда пользователь нажимает кнопку, созданную на предыдущем шаге, добавьте в нее OnClickListener .

1
2
3
4
5
6
7
Button analyzeButton = (Button)findViewById(R.id.analyze_button);
analyzeButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        // More code here
    }
});

Чтобы взаимодействовать с API с помощью клиентской библиотеки Google API, необходимо создать объект CloudNaturalLanguage с CloudNaturalLanguage.Builder класса CloudNaturalLanguage.Builder . Его конструктор также ожидает транспорт HTTP и фабрику JSON.

Кроме того, назначив CloudNaturalLanguageRequestInitializer экземпляр CloudNaturalLanguageRequestInitializer , вы можете принудительно включить ключ API во все свои запросы.

1
2
3
4
5
6
7
8
final CloudNaturalLanguage naturalLanguageService =
            new CloudNaturalLanguage.Builder(
                AndroidHttp.newCompatibleTransport(),
                new AndroidJsonFactory(),
                null
).setCloudNaturalLanguageRequestInitializer(
        new CloudNaturalLanguageRequestInitializer(CLOUD_API_KEY)
).build();

Весь текст, который вы хотите проанализировать с помощью API, должен быть размещен внутри объекта Document . Объект Document также должен содержать информацию о конфигурации, такую ​​как язык текста и форматирование его в виде простого текста или HTML. Соответственно добавьте следующий код:

1
2
3
4
5
6
7
8
String transcript =
            ((TextView)findViewById(R.id.speech_to_text_result))
                        .getText().toString();
 
Document document = new Document();
document.setType(«PLAIN_TEXT»);
document.setLanguage(«en-US»);
document.setContent(transcript);

Затем вы должны создать объект Features определяющий функции, которые вы хотите проанализировать. В следующем коде показано, как создать объект Features который говорит, что вы хотите извлечь сущности и выполнить только анализ настроений.

1
2
3
Features features = new Features();
features.setExtractEntities(true);
features.setExtractDocumentSentiment(true);

Теперь вы можете использовать объекты Document и Features для создания объекта AnnotateTextRequest , который можно передать методу annotateText() для создания объекта AnnotateTextResponse .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
final AnnotateTextRequest request = new AnnotateTextRequest();
request.setDocument(document);
request.setFeatures(features);
 
AsyncTask.execute(new Runnable() {
    @Override
    public void run() {
        AnnotateTextResponse response =
                        naturalLanguageService.documents()
                        .annotateText(request).execute();
 
        // More code here
    }
}

Обратите внимание, что мы генерируем ответ в новом потоке, потому что сетевые операции не разрешены в потоке пользовательского интерфейса.

Вы можете извлечь список объектов из объекта AnnotateTextResponse , вызвав его getEntities() . Точно так же вы можете извлечь общее настроение транскрипта, вызвав метод getDocumentSentiment() . Однако, чтобы получить реальную оценку настроения, вы также должны вызвать метод getScore() , который возвращает число с float .

Как и следовало ожидать, оценка настроения, равная нулю, означает, что настроение является нейтральным, оценка выше нуля означает, что настроение является положительным, а оценка меньше нуля означает, что настроение является отрицательным.

То, что вы делаете со списком сущностей и оценкой настроения, конечно, зависит от вас. А пока давайте просто отобразим их оба, используя экземпляр AlertDialog .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
final List<Entity> entityList = response.getEntities();
final float sentiment = response.getDocumentSentiment().getScore();
 
runOnUiThread(new Runnable() {
    @Override
    public void run() {
        String entities = «»;
        for(Entity entity:entityList) {
            entities += «\n» + entity.getName().toUpperCase();
        }
        AlertDialog dialog =
            new AlertDialog.Builder(MainActivity.this)
              .setTitle(«Sentiment: » + sentiment)
              .setMessage(«This audio file talks about :»
                                                    + entities)
              .setNeutralButton(«Okay», null)
              .create();
        dialog.show();
    }
});

С помощью приведенного выше кода оценка настроения будет отображаться в заголовке диалога, а список сущностей будет отображаться в его теле.

Если вы запустите приложение сейчас, вы сможете анализировать содержимое аудиофайлов, а также транскрибировать их.

Теперь вы знаете, как совместно использовать API-интерфейсы Cloud Speech и Cloud Natural Language для создания приложения для Android, которое может не только транскрибировать аудиофайл, но и выполнять для него анализ сущностей и настроений. В этом руководстве вы также узнали, как работать с библиотеками хранилища доступа Android и API-интерфейсами Google Client.

Google регулярно добавляет новые и интересные функции — наряду с поддержкой большего количества языков — в оба API. Чтобы оставаться в курсе о них, обратитесь к официальной документации .

И пока вы здесь, ознакомьтесь с некоторыми другими нашими публикациями об облачных сервисах мобильных приложений и машинном обучении!

  • Android SDK
    Бессерверные приложения с облачными функциями Firebase
    Чике Мгбемена
  • Android вещи
    Android вещи и машинное обучение
    Пол Требилкокс-Руис
  • Android SDK
    Как использовать Google Cloud Machine Learning Services для Android