Laravel ve Nexmo ile Etkileşimli Sesli Yanıt Sistemi Oluşturma

Laravel ve Nexmo ile Etkileşimli Sesli Yanıt Sistemi Oluşturma

Laravel uygulamasını aramak ve sizinle konuşmasını ister misiniz? Laravel ve Nexmo ile "telefon menüsü" olan gerçekten basit bir IVR (etkileşimli sesli yanıt) oluşturma konusuna hızlı bir göz atalım. İşiniz bittiğinde, cep telefonunuzu alıp bir telefon numarası arayıp Laravel uygulamasının duyduğunuz şeyleri kontrol edebileceksiniz.

Düşündüğünüzden muhtemelen daha kolaydır, başlayalım!

Kurulum

İlk önce, Composer'ı kullanarak standart Laravel kurulumuyla kurulum alacağız. Laradock kullanarak bunları bir araya getiriyorum , bu yüzden öncelikle konteynerlerdenbash birinde çalışmak için bir işleme başlamalıyım:

$docker-compose exec --user=laradock workspace bash

Bu beni proje dizinime götürür, bu yüzden burada yeni bir Laravel projesi oluşturacağım. workspaceKonteyner besteci zaten yüklüdür. Laradock kullanmıyorsanız, geliştirme sisteminize besteci yüklemeniz gerekir:

$composer create-project laravel/laravel laravel-hotline

Oldukça güzel bir vanilidir, ancak bu noktada kodu inceleyebilirsiniz . Orada çok şey göremiyorum, bu yüzden Nexmo paketlerini ekleyelim:

$composer require nexmo/laravel

Ve bu nedenle telefon hattımız ilginç bir şeyler yapabilir, iki bağımlılık daha ekleyeceğiz. SimplePie, RSS yayınlarını ve bir Twitter istemcisini çözümleyebiliyoruz, böylece bir Tweet çekebiliyoruz.

$composer require simplepie/simplepie
$composer require thujohn/twitter

Tüm kütüphaneler kurulduktan sonra servis sağlayıcıları konfigürasyonumuza ekleyebiliriz. Bu iki satırı aşağıdaki providersbölümün içine yerleştirin config/app.php:

'providers' => [
    //...
    Nexmo\Laravel\NexmoServiceProvider::class,
    Thujohn\Twitter\TwitterServiceProvider::class,
],

Ayrıca iki Facade takma adını aynı dosyaya ekleyebiliriz:

'aliases' => [
    //...
    'Nexmo' => Nexmo\Laravel\Facade\Nexmo::class,
    'Twitter' => Thujohn\Twitter\Facades\Twitter::class,
]

Son adım yapılandırma dosyalarını üretmek ve düzenlemektir. Nexmo ve Twitter için yapılandırma dosyaları oluşturmak için, projenin kökünden şu komutu çalıştırın:

$php artisan vendor:publish

Sonra config/nexmo.phpNexmo anahtarınızı ve sırrınızı düzenleyip ekleyin. Elinde yok mu? Nexmo.com adresinden ücretsiz üye olabilirsiniz . Kimlik bilgilerini config/ttwitter.phpde eklemek zorunda kalacaksınız . O yoksa, sından Twitter'ın uygulama yönetimi sayfasına ve yeni bir uygulama oluşturun.

Yapılandırma dosyalarını düzenlemek yerine, yalnızca kimlik bilgilerini dosyanıza ekleyebilirsiniz .envAyrıntılar için Nexmo ve Twitter istemci readmes bölümüne göz atın.

İsterseniz, kurulumu atlayabilir ve bu noktada kodu kaldırabilirsiniz.

Bir Nexmo Uygulaması Oluşturma

Web isteğini uygulamanıza yönlendirmek gibi, sunucumuzun IP adresini gösteren bir alan adı gerektirir; yönlendirme telefonları, kodumuzun dışındaki bazı yapılandırmaları gerektirir. Nexmo, bu yapılandırmayı 'Uygulamalar' için bir API ile yönetir .

Bir Uygulama, bir dizi web kancası tanımlamamıza, bir telefon numarası eklememize ve kimlik bilgilerini saklamamıza izin veren yapılandırma için bir kapsayıcıdır. Webhook'lar, bir şey olduğunda, Nexmo'nun gelen bir telefon çağrısı gibi istekte bulunabileceği belirli URL'lerdir. Telefon numaraları Nexmo'dan gelir ve hesabımızda bir tane bulduktan sonra onu uygulamaya ekleyebiliriz.

Bir uygulama oluşturup bir telefon numarası eklediğinizde, sık gerçekleşen veya bir web isteği tarafından tetiklenmesi gereken görevler değildir (en azından uygulamalarımız için), bir Esnaf komutası için mükemmel hedeflerdir .

AppCreate Komutu

Yeni komutumuzun yapısını oluşturmak için mevcut Artisan komutunu kullanacağız :

php artisan make:command AppCreate

Temel yapı oluşturulduktan sonra (onu buluruz /app/Console/Commands/AppCreate.php) yapıcıyı, daha önce besteci ile birlikte dahil ettiğimiz Nexmo PHP İstemcisini vermek üzere güncelleştirebiliriz .

<?php
namespace App\Console\Commands;
use Nexmo\Client;

//...

protected $client;

public function __construct(Client $client)
{
    $this->client = $client;
    parent::__construct();
}

Komutların açıklamasını da güncellememiz gerekiyor ve imzası var. Bu, --helpyararlı olmasını sağlayacak ve komutun verileceğini beklediğimiz argümanları tanımlayacaktır. $descriptionOldukça nettir:

protected $description = 'Create a new Nexmo Application';
protected $signature = 'nexmo:app:create {name} {answer_url} {event_url} {--type=voice} {--answer_method} {--event_method} {--keyfile=nexmo.key}';

Bu $signaturebiraz daha karmaşık. Biz o tanımlayarak işe başlamak nexmo:app:createbiz komut diyoruz nasıl olacak. Sonra bir uygulama bekleyeceğiz {name}. Bundan sonra, iki web kancasına ihtiyacımız var. Yeni gelen bir çağrı answer_urlolduğunda kullanılacak web kancası, adlı olarak adlandırılır ve herhangi bir çağrı ile ilgili olay için (asılan bir çağrı gibi) kullanılacak web kancasıdır event_url.

İsteğe bağlı olarak, bir uygulamanın ayarlanmasına izin vereceğiz --type(ancak şu anda API, yalnızca voiceuygulamaları desteklemektedir) ve web kanca HTTP yöntemlerinin ayarlanmasına izin veriyoruz. Varsayılan olarak, kullanılan yöntem answer_url, bir olduğunu GETve kullandığı yöntem event_urlbir olduğunu POST.

Son olarak, bir uygulama oluşturulduğunda API yanıtında özel bir anahtar gönderilir. Bu sadece bir uygulamanın oluşturulması için sağlanır, bu nedenle bir yere kaydedilmesi gerekir. --keyfileNerede olduğunu belirtmeme izin vereceğiz; Ancak, varsayılan olarak içinde saklanır nexmo.key.

Bu bağımsız değişken kümesi ve sırası , yalnızca bir uygulama oluşturmaktan çok daha fazlasını yapan Nexmo CLI aracındaki aynı komutun koşulu ve sırasını izler . Açıkçası, bir Esnaf komutunun yerine kullanılabilir, ancak bu bize PHP İstemcisi'ni kullanarak yeni bir Uygulama oluşturmak ne kadar kolay olduğunu görmek için bir şans verir.

Komutumuzu tanımladıkça, kodu handle()komuta yazalım . PHP İstemcisi akıcı bir şekilde bir Uygulama oluşturmamıza izin verir, ancak netlik uğruna bunu birkaç satırlık kodla oluşturacağız. Yeni Applicationbir VoiceConfigtane oluşturacağız ve webhooks'la yeni bir tane geçeceğiz:

<?php
namespace App\Console\Commands;
use Nexmo\Client;
use Nexmo\Application\Application;
use Nexmo\Application\VoiceConfig;

//...

public function handle()
{
    $application = new Application();
    $application->setName($this->argument('name'));

    $config = new VoiceConfig();
    $config->setWebhook(VoiceConfig::ANSWER, $this->argument('answer_url'), $this->option('answer_method'));
    $config->setWebhook(VoiceConfig::EVENT,  $this->argument('event_url'),  $this->option('event_method'));

    $application->setVoiceConfig($config);
    //...

Uygulama yapılandırıldıktan sonra handle()yöntemi bitirip API yapabiliriz . API çağrısı başarısız olabileceğinden (geçersiz kimlik bilgileri, kötü bir ağ bağlantısı, vb.), Aramayı bir tryblokta sararız . Ayrıca, ilerlememizi kullanıcıya bildireceğiz ve başarıyla, Başvuruya atıf yapmak için daha sonra kullanılabilecek olan Uygulama Kimliği'ni sağlayacağız.

    //...
    try {
        $this->info('Making API Request');
        $application = $this->client->applications()->post($application);
        file_put_contents($this->option('keyfile'), $application->getPrivateKey());
        $this->info('Key Saved To: ' . realpath($this->option('keyfile')));
        $this->info('Created Application: ' . $application->getId());
    } catch (\Exception $e) {
        $this->error('Request Failed: ' . $e->getMessage());
        $this->error($e->getTraceAsString(), \Symfony\Component\Console\Output\OutputInterface::VERBOSITY_DEBUG);
    }
} //end of handle() 

API isteği başarısız olursa, kullanıcıyı bilgilendiririz ve istekte bulunsalar - yığın izlemeyi ekleyin.

Komut işlemi yapılırken onu $commandsdizindeki dizine eklemeliyiz app/Console/Kernel.php.

    protected $commands = [
        //...
        \App\Console\Commands\AppCreate::class
    ];

Şimdi tek yapmamız gereken buyruğu çalıştırıp uygulamanızı yaratmaktır:

$php artisan nexmo:app:create Laravel-Hotline \
    http://tjlytle.ngrok.io/nexmo/answer \
    http://tjlytle.ngrok.io/nexmo/event

Making API Request
Key Saved To: /var/www/nexmo.key
Created Application: e2de8f00-0400-4475-89c9-a9c4fde5f40d

Bu noktada localhost, uygulamanın çalıştığı yerin muhtemel olmasına rağmen, web kuyruklarında referans olmadığımızı fark edeceksiniz. Nexmo'nun gelen çağrı web kancasını uygulamaya göndermek için URL'nin harici olarak erişilebilir olması gerekir. Daha önce kullanmadıysanız , ngrok , halka açık internet ortamında yerel bir geliştirme ortamı erişilebilir kılmak için mükemmel bir çözümdür.

Bağlantı Uygulama Komutu

Şimdi, Laravel Yardım Hattına işaret eden web kuyruklu bir Nexmo Uygulamamız var, ancak bu Uygulama telefon numarası olmadan çağrılamıyor. Numaralar Nexmo gösterge tablosunu kullanarak, Nexmo CLI aracıyla veya bir API çağrısıyla edinilebilir.

Yeni bir Nexmo hesabı oluşturduysanız, kontrol panelinizde bir test numarası olabilir. Değilse, giriş yapın ve birini bulun .

Numaralarınızdan birini, Uygulama Kimliği'ni kullanarak yeni Başvurunuza bağlayabilirsiniz; Bununla birlikte, API ile bağlayabilirsiniz, bu yüzden bunu yapmak için başka bir Artisan komutu oluşturalım:

php artisan make:command LinkApp

CreateAppKomut gibi, komutun kurucusunu Nexmo PHP İstemcisini enjekte edecek şekilde güncelleyeceğiz. $signatureBu sefer çok daha basittir ve benzeri CreateAppo Nexmo CLI aracında kardeş komutu ile aynı formatı aşağıdaki gibidir:

protected $description = 'Link a Number to an Application';
protected $signature = 'nexmo:link:app {number} {app}';

Komut, yalnızca iki bağımsız değişkeni, telefon numarasının bağlanmasını ve bağlantılandırılması gereken uygulamayı beklemektedir. handle()İlişkiyi kurmak için yöntemin birkaç satırını ekleyeceğiz:

<?php
namespace App\Console\Commands;
use Nexmo\Client;
use Nexmo\Application\Application;
use Nexmo\Numbers\Number;

//...

public function handle()
{
    $application = new Application($this->argument('app'));
    $number = new Number($this->argument('number'));

    $number->setVoiceDestination($application);
    //...

Gördüğünüz gibi, bir Applicationuygulama kimliğiyle oluşturulabilir ve bu API eşleştirme Uygulamasını başvurmak gerekir. Aynı şey a Numberiçin de geçerlidir, eğer telefon numarası bir kimlik numarası ile oluşturulduysa, Nexmo hesabınızda aynı numaraya referans verecektir.

İki kaynağı bulduktan sonra, numarayı herhangi bir sesli çağrı için uygulamayı kullanacak şekilde yapılandırabiliriz.

Gibi CreateAppbir API çağrısı sarmak edeceğiz trybloğun yüzden hataları yakalamak ve kullanıcıyı bilgilendirebilir:

    //...
    try{
        $this->info('Making API Request');
        $this->client->numbers()->update($number);
        $this->info('Linked Number to Application');
    } catch (\Exception $e) {
        $this->error('Request Failed: ' . $e->getMessage());
        $this->error($e->getTraceAsString(), \Symfony\Component\Console\Output\OutputInterface::VERBOSITY_DEBUG);
    }
} //end of handle()

Ekleyerek komutu Kayıt $commandsyanında dizideki AppCreateiçinde app/Console/Kernel.php.

    protected $commands = [
        //...
        \App\Console\Commands\AppCreate::class,
        \App\Console\Commands\LinkApp::class        
    ];

Sonra bir spin verin (elbette Nexmo numaranızla birlikte):

$php artisan -vvv nexmo:link:app 14045559404 e2de8f00-0400-4475-89c9-a9c4fde5f40d

Making API Request
Linked Number to Application

Certianly hepsi Nexmo CLI aracı birkaç komutları ile yapılmış olabilir; Bununla birlikte, SaaS benzeri bir ürün oluşturuyorsanız, uygulamalarınızı otomatik olarak sağlama ve numaraları bağlama, uygulamanızda yapmak istediğiniz bir şeydir. Birkaç kod satırı ile yapmak kolaydır.

Sadece okuyor musun? Sen edebilirsiniz kodunu görmek de bu noktada.

Telefon Almak

Telefonunuzun kilidini açmadan ve uygulamanızı aramadan önce, tanımladığımız web kancalarının arkasına bazı kodlar koymamız gerekir.

Webhooks Hakkında Biraz

Uygulama numaramıza bir çağrı yapıldığında Nexmo, bir HTTP isteği yapacak /nexmo/answerve HTTP yanıtının geçerli bir NCCO (Nexmo çağrı kontrolü nesnesi) yığınının JSON yapısı olacağını bekleyecektir. Bu yığın, aramada neler olacağını tanımlar. Örneğin, "Laravel Yardım Hattı'na hoş geldiniz" diyerek veya kullanıcının telefonunda bir numaraya basarak yakalamasını söyleyerek.

Bir NCCO, hangi URL'nin sonraki web kancasını alması gerektiğini de tanımlayabilir. Bir inputkullanıcının tuşlarını NCCO kullanarak yakaladığımızda, HTML'nin olduğu gibi , verilerin gönderildiği URL'yi de tanımlıyoruz <form>.

Nexmo Belgeleri, NCCO'lar hakkında bilmeniz gereken her şeye sahiptir .

Tanımladığımız diğer web kancasıydı /nexmo/event. Nexmo, bir çağrı değiştiğinde her URL'ye bir HTTP isteği yapacaktır. Örneğin, uygulamanızın numarasına gelen bir çağrı, çağrı olduğunda bir web kancasına, çağrı başvurumuza göre ringingbaşka bir çağrıya neden answeredolur. Bu web kuyrukları, arama durumunu izlememizi sağlar.

Rotaları Yapılandırma

Varsayılan olarak, Laravel normal rota için CSRF katmanını ekler (iyi bir şey). Defaul tarafından Nexmo, bir NCCO'ya herhangi bir kullanıcı girdisinin yanı sıra etkinlik webhook'larını POSTda (iyi bir şey olarak) gönderir .

CSFR katmanını düzenlemeyle kaldırabiliriz app/Http/Kernel.php, ancak hem web arayüzü hem de sesli arayüzü olan bir uygulama oluşturuyorsak bunu yapmamamız gerekir.

Ayrıca katman yazılımının kendisine bir URI istisnası da ekleyebiliriz ve bu URL'lerin tümünün öneki /nexmoolarak yalnızca bir satır alacağız:

protected $except = [
    'nexmo/*',
];

Bunun yerine, tüm Nexmo rotaları için yeni bir katman grubu oluşturalım. Burada app/Providers/RouteServiceProvider.phpmevcut API eşleme yöntemine benzeyen bir yöntem ekleyeceğiz:

protected function mapNexmoRoutes()
{
    Route::prefix('nexmo')
        ->middleware('bindings')
        ->namespace($this->namespace)
        ->group(base_path('routes/nexmo.php'));
}

Ve bu yöntemi şu adresten arayın map():

public function map()
    {
        $this->mapApiRoutes();
        $this->mapWebRoutes();
        $this->mapNexmoRoutes();
    }

Şimdi bulunan herhangi bir routes/nexmo.phpgüzergahta CSRF katmanının yanı sıra diğer weble ilgili katmanlar da olmayacaktır. Ve tanımlanan herhangi rotalar routes/nexmo.phptarafından öneki /nexmoböylece işlemek için, /nexmo/answerwebhook, sadece bir rota tanımlamak /answer.

En yaratalım routes/nexmo.phpve basit bir yol tanımlar:

<?php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;

//simple hello world
Route::get('/answer', function (Request $request) {
    return [
        [
            'action' => 'talk',
            'text' => 'Welcome to the Laravel Hotline'
        ]

    ];
});

//just log the events so we can inspect the data
Route::post('/event', function (Request $request) {
    error_log($request->getContent());
    return;
});

Kadar basit! Laravel, bir dizi json_encodeveri döndürdüğümüzü göreceğiz ve verileri doğru ayarladık content/type. Devam edin, arayın ve kendiniz görün.

Uygulamayı oluştururken belirttiğimiz gibi, Nexmo için webhook'ları yapacak /nexmo/answerve /nexmo/eventuygulama, uygulama oluştururken kullanılan alan adında kamuya açık internette erişilebilir olmalıdır. Bu web kancalarını güncellemeniz gerekiyorsa , API çağrısı veya Nexmo CLI komutu kadar kolaydır .

Bu noktada kodu kontrol ederek bir dönme için bunu alın .

Bir Kontrol Ünitesi Yapmak

routes/nexmo.phpNCCO'nun sağına koymak, her şeyin harekete geçtiğini görmek için hızlı bir yol olmakla birlikte, sesli isteklerimizi yerine getirmek için uygun bir IVR kontrolörü oluşturmamız gerekir. Rotamızı bir denetleyiciye işaret edecek şekilde güncelleyelim:

Route::get ('/answer', 'IvrController@answer')->name('ivr.answer');
Route::post('/menu',   'IvrController@menu'  )->name('ivr.menu');

/menuTebrikten sonra kullanıcı girdilerini işlemek için yeni bir rota ekledik . Ayrıca, daha sonra URL'ler üretebilmemiz için rotaları adlandırdık. Artisan'ı yeni bir kontrolör oluşturmak için kullanalım:

$php artisan make:controller IvrController

Açacağız /app/Http/Controllers/IvrController.phpve answergelen aramaları cevaplayacak yöntemi ekleyeceğiz. Bu, bir selamlama olarak daha önce kullandığımız basit NCCO'yı alacak ve yığına iki tane daha NCCO ekleyecek:

public function answer(Request $request)
{
    return [
        [
            'action'    => 'talk',
            'text'      => 'Welcome to the Laravel Hotline'
        ],
        [
            'action'    => 'talk',
            'text'      => "Press 1 to hear Taylor's latest tweet. Press 2 to listen to the latest Laravel Podcast",
            'bargeIn'   => true
        ],
        [
            'action'    => 'input',
            'eventUrl'  => [route('ivr.menu')],
            'maxDigits' => 1
        ]

    ];
}

İlk NCCO tam olarak daha önce kullandığımız şey. İkincisi de bir talk, ama bargeInçağrıda bulunulan kişinin herhangi bir zamanda basamağa basmasını sağlayan bayrak ekledik . İlk beri talkyok bargeIn, metin kullanıcı bir tuşa basıldığında bile oynamaya devam edecektir.

Son NCCO kullanıcı girdisini yakalar ve sonuçları bir ivr.menuroute ( /nexmo/menu) olarak a olarak gönderir POST. Şimdi bu basit yöntemi oluşturalım ( menu()şimdi:

public function menu(Request $request)
{
    switch ($request->json('dtmf')){
        case '1';
            return $this->tweet($request);
        case '2':
            return $this->podcast($request);
        default:
            return $this->answer($request);
    }
}

Bu basit switch, geçerli seçenekler arar ve hiçbiri bulunmazsa menü tekrarlanır. Kullanıcı bir çevirdiğinde 1NCCO tarafından oluşturulan her türlü biz dönüşünü tweet()ve için 2biz NCCO tarafından oluşturulan kullanın podcast().

Bizim tweet()yöntem en son tweet getirir @taylorotwell (bireysel tweet almak için kullanılır dereferencing diziyi dikkat edin):

public function tweet()
{
    $tweet = \Twitter::getUserTimeline(['screen_name' => 'taylorotwell', 'count' => 1, 'format' => 'array'])[0];
    $text = $tweet['text'];
    //...

Makul bir şans olduğundan, bir bağlantı tweetledi ve Nexmo TTS t.cokısaltılmış bir URL okumak, tüm bu bilgilendirici değil, URL'yi alan adına bir referansla değiştirebiliriz (en azından, bunun için bazı içerik ekleyeceğiz) Çağırın):

    //...
    foreach($tweet['entities']['urls'] as $link){
        $domain = parse_url($link['expanded_url'], PHP_URL_HOST);

        $text = substr($text, 0, $link['indices'][0]) .
                'and a link to ' . $domain .
                substr($text, $link['indices'][1]);
    }
    //....

Cıvata biraz daha okunaklı hale talkgetirildiğinde basit bir NCCO iade edeceğiz :

    //...
    return [
        [
            'action' => 'talk',
            'text'   => \Twitter::ago($tweet['created_at']) . ' he tweeted ' . $text
        ]
    ];
} // end of tweet()

Devam edin, deneyin - yardım hattınızı arayın ve tuşuna basın 1.

Şimdi ikinci seçeneği bitirelim. Bunun için, Laravel Podcast için RSS akışını alıp en yeni ses dosyasını bulacağız. Yapılandırmayı basit tutmak için önbelleği devre dışı bırakacağız:

public function podcast()
{
    $rss = new \SimplePie();
    $rss->enable_cache(false);
    $rss->set_feed_url('https://rss.simplecast.com/podcasts/351/rss');
    $rss->init();

    $item = $rss->get_item(0);
    //...

talkAyrıştırılan RSS özet akışıyla ve ilk öğe bulunursa, bölüm tanımını okur ve a streamda ses dosyasını çalar. Bu , NCCO yığınını döndürür :

    //...
    return [
        [
            'action' => 'talk',
            'text'   => $item->get_description()
        ],
        [
            'action' => 'stream',
            'streamUrl' => [$item->get_enclosure(0)->get_link()]
        ]
    ];
} //end of podcast()

Şimdi telefon hattını ararsanız, sadece bir düğmeye basarak en yeni Laravel Podcast'i dinleyebilirsiniz.

Nexmo ve Laravel ile başka ne yapabilirsiniz? Bir dahaki sefere Laravel Hotline uygulamamıza ses yongası ekleyeceğiz. Arkadaşlarınızı arayabilir ve konuşma sırasında en sevdiğiniz Laravel ses bitlerini konuşmaya enjekte edebilirsiniz.

Ve tabii ki, Laravel Hotline uygulamasının kaynağını tamamlanmış haliyle kapabilirsiniz.

2 Yorum Yapıldı

  1. hekim malzemeleri 2018-01-02 22:53:37

    I love looking through a post that can make people think. Also, thank you for allowing for me to comment!

  2. veteriner malzemeleri 2018-01-23 23:08:26

    Just want to say your article is as surprising. The clearness in your submit is simply great and i could suppose you're knowledgeable in this subject. Fine with your permission allow me to snatch your feed to stay updated with drawing close post. Thanks one million and please continue the enjoyable work.

Yorum Yollayın