Статьи

Управляемые голосом PHP-приложения с API.ai

В этом уроке мы рассмотрим Api.ai , API, который позволяет нам создавать приложения, которые понимают естественный язык, очень похожий на Siri. Он может принимать либо текст, либо речь в качестве входных данных, которые затем анализирует и возвращает строку JSON, которую можно интерпретировать кодом, который мы пишем.

Все файлы, которые мы будем использовать в этом руководстве, доступны в этом репозитории Github .

Microphone in front of blurred audience

Концепции

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

  • агенты — агенты приложения. Мы создаем агента как средство группировки отдельных лиц и намерений.

  • лица — лица — это пользовательские понятия, которые мы хотим включить в наше приложение. Они дают возможность придать смысл конкретной концепции путем добавления примеров. Образцом сущности будет «валюта». Мы определяем это, добавляя синонимы, такие как «доллар США», «доллар США» или просто «доллары». Затем каждому синониму присваивается эталонное значение, которое можно использовать в коде. Это просто список слов, которые можно использовать для обозначения этого понятия. Api.ai уже предоставляет некоторые базовые сущности, такие как @sys.number , который является сущностью, ссылающейся на любое число, и @sys.email которая является сущностью, ссылающейся на любой адрес электронной почты. Мы можем использовать встроенные объекты, указав @sys в качестве префикса.

  • намерения — намерения позволяют нам определить, какие действия будет выполнять программа, в зависимости от того, что говорит пользователь. Примером намерения будет «конвертировать валюту». Затем мы перечисляем все возможные фразы или предложения, которые пользователь скажет, если они хотят конвертировать валюту. Например, пользователь может сказать «сколько стоит @ sys.number: number @currency: fromCurrency in @currency: toCurrency?». В этом примере мы использовали 2 объекта: @sys.number и @currency . Использование двоеточия после сущности позволяет нам определить псевдоним для этой сущности. Этот псевдоним затем может быть использован в нашем коде для получения значения сущности. Нам нужно дать одному и тому же объекту другой псевдоним, чтобы мы могли обрабатывать их отдельно в нашем коде. Чтобы люди поняли вышеупомянутое намерение, все, что нам нужно сделать, это заменить сущности действительными значениями. Таким образом, пользователь может сказать: «Сколько стоит 900 долларов США в японских иенах?» и Api.ai просто отобразит «900» в качестве значения для @sys.number , «доллара США» для ofCurrency @currency и «японской йены» для toCurrency @currency .

  • контексты — контексты представляют текущий контекст пользовательского выражения. Например, пользователь может сказать: «Сколько стоит 55 долларов США в японских иенах?» а затем следуйте с «а как насчет филиппинского песо?». В этом случае Api.ai использует в качестве контекста для второго выражения то, что ранее говорил пользователь «Сколько стоит 55 долларов США».

  • псевдонимы — псевдонимы предоставляют способ ссылки на конкретную сущность в вашем коде, как мы видели ранее в объяснении намерений.

  • домены — домены — это заранее определенные пакеты знаний. Мы можем думать о них как о коллекции встроенных сущностей и намерений в Api.ai. Другими словами, это трюки, которые Api.ai может выполнять практически без необходимости настройки или кодирования. Например, пользователь может сказать: «Найти видео Пикачу на YouTube». и Api.ai уже знает, как его проанализировать, и возвращает «Pikachu» в качестве поискового термина и «Youtube» в качестве службы. Оттуда мы можем просто использовать возвращенные данные, чтобы перейти на Youtube и найти «Пикачу». В JavaScript это только вопрос установки location.href чтобы он указывал на страницу результатов поиска Youtube:

     window . location . href =   "https://www.youtube.com/results?search_query=pikachu" ; 

Чтобы использовать домены для своего агента, выберите своего агента в консоли и затем нажмите на меню доменов в верхней части. Оттуда, включить базу знаний доменов и выполнения. Обратите внимание, что домены в настоящее время находятся в бета-версии, но вы всегда можете использовать консоль API для их тестирования.

api console

Включение базы знаний доменов включает функциональность доменов. Включение выполнения позволяет использовать сторонние сервисы, такие как Small Talk и Weather. Это означает, что нам не нужно будет делать отдельный запрос к определенному API, если необходимая нам служба уже интегрируется с Api.ai.

Получение текущего времени в определенном месте

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

Если вы этого еще не сделали, зарегистрируйте бесплатную учетную запись на веб-сайте Api.ai , подтвердите свой адрес электронной почты, а затем войдите в систему / войдите, используя свои учетные данные.

Затем перейдите на страницу агентов и создайте нового агента, нажав кнопку «Создать агента». Находясь на странице для создания нового агента, введите имя, описание и язык и сохраните.

timeapp agent

Это дает вам ключ подписки, токен доступа разработчика и токен доступа клиента. Вы можете использовать их для отправки запросов к API, либо с клиента (браузера), либо с сервера. Одним из преимуществ выполнения запросов от сервера является скрытие ваших учетных данных.

Агент, который мы создали, будет использовать домены. Это означает, что нам не нужно устанавливать сущности и намерения. Нам нужна небольшая помощь от двух API Google: API геокодирования и API часового пояса. API геокодирования используется для преобразования местоположения, которое мы получаем из Api.ai, в координаты. Затем мы используем эти координаты для запроса API часового пояса, чтобы получить текущее время для этого местоположения. Перейдите в консоль Google и включите API часового пояса. API геокодирования не требует предоставления ключа API, поэтому нам не нужно его включать.

Далее установите Guzzle. Мы будем использовать Guzzle 5, чтобы сделать запрос к Api.ai.

 composer require  guzzlehttp / guzzle :~ 5.0 

Затем создайте новый файл PHP ( time.php ) и добавьте следующий код, чтобы мы могли использовать Guzzle из нашего файла.

 <? php require   'vendor/autoload.php' ; 

 use   GuzzleHttp \Client ; $client =   new   Client (); 

После этого определите ваши ключи API:

 $google_api_key =   'YOUR_GOOGLE_API_KEY' ; $apiai_key =   'YOUR_API_AI_AGENT_DEVELOPER_ACCESS_TOKEN' ; $apiai_subscription_key =   'YOUR_API_AI_SUBSCRIPTION_KEY' ; 

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

Теперь мы можем сделать запрос к Api.ai. Чтобы сделать запрос, нам нужно передать маркер доступа разработчика и ключ подписки в качестве заголовков. Затем мы передаем тело запроса как JSON. Тело запроса должно содержать query и ключи lang . query передается со стороны клиента через запрос POST . Пример запроса для этого приложения: «Сколько времени в Барселоне, Испания?» Или «Сколько времени в Икебукуро, Япония?». Возвращаемый ответ является строкой JSON, поэтому мы конвертируем ее в массив, вызывая метод json для $response .

 $query =  $_POST [ 'query' ];   //the users query $response =  $client -> post ( 'https://api.api.ai/v1/query' ,  array ( 
     'headers'   =>  array ( 
         'Authorization'   =>   "Bearer {$apiai_key}" , 
         'ocp-apim-subscription-key'   =>  $apiai_subscription_key , 
         'Content-Type'   =>   'application/json; charset=utf-8' 
     ), 
     'json'   =>  array ( 
         "query"   =>  $query , 
         "lang"   =>   "en" 
     ) 
 )); $result =  $response -> json (); 

Вот пример ответа, который мы получаем, когда делаем запрос выше:

 Array ( [id] => eb69f468-6e1a-41c9-883d-6ac7c71cd187 1580655990 => 2015-05-16T09:19:47.519Z [result] => Array ( [source] => domains [resolvedQuery] => What's the current time in Barcelona Spain? [speech] => [action] => clock.time [parameters] => Array ( [location] => Barcelona Spain ) [metadata] => Array ( [inputContexts] => Array ( ) [outputContexts] => Array ( ) [contexts] => Array ( ) ) ) [status] => Array ( [code] => 200 [errorType] => success ) ) 

Если мы получим код состояния 200, это означает, что запрос был успешным. Данные, которые нам нужны, хранятся в элементе result . В этом случае нам нужно только извлечь location из parameters . Если местоположение не возвращается, мы просто сообщаем пользователю, что это местоположение не найдено.

 if (! empty ( $result [ 'result' ])   &&   ! empty ( $result [ 'result' ][ 'parameters' ][ 'location' ])){ $location =  $result [ 'result' ][ 'parameters' ][ 'location' ]; 

 } else { echo "Sorry, I could not find that location." ; 
 } 

Если местоположение найдено, мы делаем запрос к API геокодирования Google, чтобы преобразовать местоположение в координаты. Если status в OK , это значит, что мы получили результат. Таким образом, мы просто извлекаем значения широты и долготы из первого результата.

 $place_response =  $client -> get ( "http://maps.googleapis.com/maps/api/geocode/json?address={$location}&sensor=false" ); $place_result =  $place_response -> json (); 

 if ( $place_result [ 'status' ]   ==   'OK' ){ $lat =  $place_result [ 'results' ][ 0 ][ 'geometry' ][ 'location' ][ 'lat' ]; $lng =  $place_result [ 'results' ][ 0 ][ 'geometry' ][ 'location' ][ 'lng' ]; 
 } 

Далее мы получаем текущую метку времени Unix. Мы передаем это значение вместе с широтой и долготой в качестве запроса по нашему запросу в API часового пояса Google. Затем мы извлекаем timeZoneId который мы можем использовать для временной установки часового пояса, используя метод date_default_timezone_set . Наконец, мы просто выводим отформатированное время пользователю.

 $timestamp =  time ();   //get the current unix timestamp $time_response =  $client -> get ( "https://maps.googleapis.com/maps/api/timezone/json?location={$lat},{$lng}&timestamp={$timestamp}&key={$google_api_key}" ); $time_result =  $time_response -> json (); 

 if ( $time_result [ 'status' ]   ==   'OK' ){ $timezone =  $time_result [ 'timeZoneId' ]; date_default_timezone_set ( $timezone ); echo 'It' s currently ' . date(' l ,  F j ,  Y g : i A ') . '   in   ' . $location; } 

Давайте перейдем к клиентской части. Создайте файл index.html со следующим кодом:

 <!DOCTYPE html> 
 <html   lang = "en" > 
 <head> 
     <meta   charset = "UTF-8" > 
     <title> time </title> 
     <script   src = "http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js" ></script> 
     <script   src = "responsive-voice.js" ></script> 
 </head> 
 <body> 
     <div> 
         <input   type = "text"   id = "query"   name = "query" >   <button   id = "rec" > Speak </button> 
     </div> 
     <div   id = "response" ></div> 
     <script   src = "speech-recognition.js" ></script> 
     <script   src = "main.js" ></script> 
 </body> 
 </html> 

Мы используем jQuery (для обработки событий) и responseive-voice.js . Библиотека отзывчивого голоса позволяет нам преобразовывать текст в речь. Мы используем его, чтобы высказать результаты, которые мы получаем от сервера.

У нас также есть речи-распознавания.js , который мы используем для преобразования речи в текст. Это использует API веб-речи. К сожалению, на момент написания он все еще поддерживается только частично в нескольких браузерах , поэтому в этом руководстве предполагается, что вы используете Chrome (который его поддерживает).

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

 var  recognition ; 

Далее startRecognition метод startRecognition . Это создает новый объект распознавания речи. Это попросит пользователя использовать микрофон. Затем мы устанавливаем язык на английский и запускаем распознавание речи. Затем мы слушаем onstart событие. Когда это событие вызвано, это означает, что распознавание речи началось. Когда это происходит, мы вызываем метод updateRec , который изменяет текст кнопки для запуска и остановки распознавания речи. Мы также прослушиваем событие onresult которое срабатывает, когда пользователь перестает говорить на пару секунд. Это содержит результаты распознавания речи. Мы должны пройтись по результатам и использовать каждый элемент transcript чтобы получить нужный нам текст. Как только это будет сделано, мы вызываем метод setInput который изменяет значение текстового поля запроса и вызывает метод send который отправляет запрос на сервер. Затем мы вызываем метод stopRecognition чтобы остановить распознавание речи и обновить пользовательский интерфейс. Мы также должны сделать то же самое в onend мероприятии.

 function  startRecognition (){ recognition =   new  webkitSpeechRecognition (); recognition . lang =   "en-US" ; recognition . start (); recognition . onstart =   function ( event ){ updateRec (); 
     }; recognition . onresult =   function ( event ){ 
         var  text =   "" ; 
         for ( var  i =   event . resultIndex ;  i <   event . results . length ;   ++ i ){ text +=   event . results [ i ][ 0 ]. transcript ; 
         } setInput ( text ); stopRecognition (); 
     }; recognition . onend =   function (){ stopRecognition (); 
     }; 
 } 

Вот метод updateRec .

 function  updateRec (){ $ ( "#rec" ). text ( recognition ?   "Stop"   :   "Speak" ); 
 } 

метод setInput .

 function  setInput ( text ){ $ ( "#query" ). val ( text ); send (); 
 } 

метод stopRecognition .

 function  stopRecognition (){ 
     if ( recognition ){ recognition . stop (); recognition =   null ; 
     } updateRec (); 
 } 

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

 function  switchRecognition (){ 
     if ( recognition ){ stopRecognition (); 
     } else { startRecognition (); 
     } 
 } $ ( "#rec" ). click ( function ( event ){ switchRecognition (); 
 }); 

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

 $ ( "#query" ). keypress ( function ( event ){ 
     if ( event . which ==   13 ){ 
         event . preventDefault (); send (); 
     } 
 }); 

Большая часть кода в файле speech -ognition.js взята из этой сущности, которая показывает пример использования Api.ai на стороне клиента.

Далее main.js файл main.js где мы отправляем наш запрос на сервер. Получив ответ, мы используем отзывчивый голос, чтобы высказать его, а также вывести его в контейнер ответов. Таким образом, мы можем проверить ответ визуально.

 function  send (){ 
     var  text =  $ ( "#query" ). val (); $ . post ( 
         'http://localhost/tester/api-ai/time.php' , 
         { 
             'query' :  text }, 
         function ( response ){ responsiveVoice . speak ( response ); $ ( '#response' ). text ( response ); 
         } 
     ); 
 } 

Конвертер валют

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

Сначала создайте нового агента и назовите его CurrencyConverter .

currency converter

Под этим агентом создайте новый объект и назовите его currency . Это будет представлять различные валюты, которые мы можем конвертировать. Определите несколько валют, которые мы можем использовать для тестирования, и нажмите «Сохранить».

currency entity

Затем создайте новое намерение и назовите его convertMoney .

convertMoney intent

На приведенном выше снимке экрана видно, что мы добавили следующее в разделе «пользователь говорит»:

 @sys . number : number @currency : fromCurrency to @currency : toCurrency convert @sys . number : number @currency : fromCurrency to @currency : toCurrency how much is   @sys . number : number @currency : fromCurrency in   @currency : toCurrency ? 

В разделе «пользователь говорит» мы определяем примеры того, что пользователь может сказать, чтобы вызвать это конкретное намерение. Здесь мы используем сущности в качестве заменителей реальных значений, которые может использовать пользователь. @sys.number может относиться к любому номеру. @currency может ссылаться на любую валюту, которую мы добавили ранее, когда создавали сущность валюты. Использование двоеточия после объекта позволяет нам присвоить ему псевдоним. Этот псевдоним затем может быть использован для получения значения, используемого пользователем в коде.

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

В разделе «Выполнение» мы определяем шаблон для речи, которую мы хотим вывести после использования намерения. Например, мы можем поставить следующее:

 $number $fromCurrency is  equivalent to $result $toCurrency 

Затем он будет доступен для элемента speech в результате, который мы получим. Оттуда мы можем выполнить замену строки, чтобы заменить эти переменные фактическими значениями, которые мы получаем. Но давайте оставим это поле пустым для этого приложения.

Когда вы закончите, нажмите кнопку «Сохранить», чтобы сохранить намерение.

Теперь мы готовы приступить к коду. Создайте файл exchange-rate.php в вашем рабочем каталоге, затем добавьте следующий код:

 <? php require   'vendor/autoload.php' ; 

 use   GuzzleHttp \Client ; $client =   new   Client (); $apiai_key =   'YOUR_API_AI_AGENT_DEVELOPER_ACCESS_TOKEN' ; $apiai_subscription_key =   'YOUR_API_AI_SUBSCRIPTION_KEY' ; $currencylayer_apikey =   'YOUR_CURRENCYLAYER_API_KEY' ; $query =  $_POST [ 'query' ]; $response =  $client -> post ( 'https://api.api.ai/v1/query' ,  array ( 
     'headers'   =>  array ( 
         'Authorization'   =>   "Bearer {$apiai_key}" , 
         'ocp-apim-subscription-key'   =>  $apiai_subscription_key , 
         'Content-Type'   =>   'application/json; charset=utf-8' 
     ), 
     'json'   =>  array ( 
         "query"   =>  $query , 
         "lang"   =>   "en" 
     ) 
 )); $result =  $response -> json (); 

Как видно из приведенного выше кода, он в основном такой же, как мы делали ранее в нашем предыдущем приложении. Только на этот раз мы добавили переменную $currencylayer_apikey . Здесь хранится ключ API, который мы получили от currencylayer.com , API, который позволяет нам получать текущий курс обмена от одной валюты к другой. Если вы хотите продолжить, зарегистрируйтесь и получите ключ API .

Затем мы проверяем, есть ли какие-либо результаты, и извлекаем данные, которые нам нужны. В этом случае нам нужно получить валюту, которую пользователь желает конвертировать, валюту, в которую он будет конвертироваться, а затем сумму.

 if (! empty ( $result [ 'result' ])){ $currency_from =  $result [ 'result' ][ 'parameters' ][ 'fromcurrency' ]; $currency_to =  $result [ 'result' ][ 'parameters' ][ 'tocurrency' ]; $amount =  $result [ 'result' ][ 'parameters' ][ 'number' ]; 
 } 

Затем мы делаем запрос в API и извлекаем курс обмена из результатов:

 $conversion_response =  $client -> get ( "http://apilayer.net/api/live?access_key={$currencylayer_apikey}&source={$currency_from}&currencies={$currency_to}" ); $conversion_result =  $conversion_response -> json (); $rate =  $conversion_result [ 'quotes' ][ $currency_from .  $currency_to ]; 

Результаты, которые мы получаем от API, выглядят так:

 Array 
 ( 
     [ success ]   =>   1 
     [ terms ]   =>  https : //currencylayer.com/terms 
     [ privacy ]   =>  https : //currencylayer.com/privacy 
     [ timestamp ]   =>   1440296829 
     [ source ]   =>  USD [ quotes ]   =>   Array 
         ( 
             [ USDPHP ]   =>   46.655499 
         ) 

 ) 

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

 $converted_amount =  $amount *  $rate ; $speech =   "{$amount} {$currency_from} is equivalent to {$converted_amount} {$currency_to}" ; echo $speech ; 

На стороне клиента мы все еще используем тот же HTML и файлы, которые мы использовали ранее в нашем первом приложении. Вы можете пойти дальше и поместить те же файлы в свой рабочий каталог, если вы следуете.

 <!DOCTYPE html> 
 <html   lang = "en" > 
 <head> 
     <meta   charset = "UTF-8" > 
     <title> exchange rate </title> 
     <link   rel = "stylesheet"   href = "style.css" > 
     <script   src = "http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js" ></script> 
     <script   src = "responsive-voice.js" ></script> 
 </head> 
 <body> 
     <div> 
         <input   type = "text"   id = "query"   name = "query" >   <button   id = "rec" > Speak </button> 
     </div> 
     <div   id = "response" ></div> 
     <script   src = "speech-recognition.js" ></script> 
     <script   src = "main.js" ></script> 
 </body> 
 </html> 

Единственное отличие — это URL, на который мы отправляем запрос. Укажите, где находится ваш exchange-rate.php :

 function  send (){ 
     var  text =  $ ( "#query" ). val (); $ . post ( 
         'http://localhost/tester/api-ai/exchange-rate.php' , 
         { 
             'query' :  text }, 
         function ( response ){ responsiveVoice . speak ( response ); $ ( '#response' ). text ( response ); 
         } 
     ); 
 } 

Вывод

В этом уроке мы узнали, как использовать Api.ai для создания голосовых приложений PHP. Поддержка браузеров все еще довольно ограничена, потому что Web Speech API все еще не получил широкого применения. Но Api.ai поддерживает другие платформы, кроме Интернета. Android, Cordova, .Net, iOS — несколько примеров. Это означает, что мы можем использовать Api.ai, не беспокоясь о поддержке на этих платформах. Не забудьте проверить их документы, если вы хотите узнать больше. Файлы, которые мы использовали в этом руководстве, доступны в этом репозитории Github .