こんにちは、Habraユーザーの皆様。
1つのプロジェクトでは、アスタリスクIP-PBXに基づいたスマートIVRを作成する必要がありました。 「スマート」という言葉の意味は次のとおりです。特定の番号に電話をかけると、ステーションは加入者の名前を要求し、回線の反対側にいる人が名前を呼び出し、ステーションはそれを目的の加入者に接続します。
私の場合、FreePBXがプリインストールされた既製のAsteriskNowのアセンブリを使用しましたが、この場合は特別な役割を果たしません。 違いは、ダイヤルプランの編集のみです。
ステップ1:
グーグルで働く
最初のことは、何らかの方法で発信者のスピーチを認識することです。 Habrには、Google Translateを使用してこれを行う方法についての十分な( 1、2、 )記事がありました。 Asteriskが音声を認識できるように、githubのオープンスペースにある既製のスクリプトgoogletts.agi -Asteriskに話すこととspeech-recog.agiを教えるために用意することにしました。
ファイルgoogletts.agiおよびspeech-recog.agiは、フォルダー/ var / lib / asterisk / agi-binにスローされます。
スクリプトを正常に機能させるには、Perl、perl-libwww、IO-Socket-SSL、flac、sox、mpg123のパッケージが必要です。 リポジトリから(yum installを介して)正常にダウンロードおよびインストールされたすべてのパッケージは、mpg123を除き、個別にダウンロードする必要がありました。
googletts.agiでは、$ lang変数の値をenからruに変更します。これは、アスタリスクがロシア語を話せるようにするためです。
speech-recog.agiでは、$言語変数の値をen-USからru-RUに変更して、Googleがロシア語で結果を返すようにします。
すべて、スクリプト内の他の部分には触れませんでした。
ステップ2:
ダイヤルプランの作成
前述したように、FreePBXがインストールされているため、extensions_custom.confファイルにすべての変更を加えます。
まず、発信者に挨拶し、次に何をすべきかについてコメントを与えるのは良いことです。
exten => 100,1,Answer()
exten => 100,n,agi(googletts.agi,”! .”,ru)
次に、speech-recog.agiを使用して、ユーザーの発言を聞き、記録し、変換し、Googleに送信して、ユーザーから結果を取得します。
exten => 100,n(record),agi(speech-recog.agi,ru-RU)
次に、 GotoIf関数を使用して、スクリプトの動作を確認します。
スクリプトは次の値を返します。
status:実行ステータスを返します。 0は成功を意味します
発話: Googleが返す文字列
信頼性:正しい認識の確率を示す0〜1の値
exten => 100,n,GotoIf($[$["${status}" = "0"] & $["${confidence}" > "0.8"]]?if1:retry)
テストが成功した場合はif1イベントに進み、失敗した場合は再試行イベントに進みます。このイベントでは、ユーザーに繰り返しを依頼します。
exten => 100,n(retry),agi(googletts.agi,”, ”,ru)
次に、Googleから受け取った回線自体を直接操作します。 受信した文字列$ {utterance}を何らかのテンプレートと比較し、次に何をするかを決定する必要があります。 GotoIf関数を使用する
exten => 100,n(if1),GotoIf($[“${utterance}” = “”]?vasya:retry)
Googleから受信した行が「Vasya」と一致する場合は、vasyaイベントに進み、一致しない場合は、ユーザーに繰り返しを依頼します。
そして、Vasyaに電話するだけです
exten => 100,n(vasya),Dial(SIP/101)
完全なダイヤルプラン:
exten => 100.1、回答()
exten => 100、n、agi(googletts.agi、「こんにちは!ビープ音が鳴ったら、加入者の名前を言ってください。」、ru)
exten => 100、n(レコード)、agi(speech-recog.agi、ru-RU)
exten => 100、n、GotoIf($ [$ ["$ {status}" = "0"]&$ ["$ {confidence}"> "0.8"]] if1:再試行)
exten => 100、n(if1)、GotoIf($ [“ $ {utterance}” =“ Vasya”]?vasya:再試行)
exten => 100、n(再試行)、agi(googletts.agi、「繰り返してください」、ru)
exten => 100、n(vasya)、ダイヤル(SIP / 101)
exten => 100、n、agi(googletts.agi、「こんにちは!ビープ音が鳴ったら、加入者の名前を言ってください。」、ru)
exten => 100、n(レコード)、agi(speech-recog.agi、ru-RU)
exten => 100、n、GotoIf($ [$ ["$ {status}" = "0"]&$ ["$ {confidence}"> "0.8"]] if1:再試行)
exten => 100、n(if1)、GotoIf($ [“ $ {utterance}” =“ Vasya”]?vasya:再試行)
exten => 100、n(再試行)、agi(googletts.agi、「繰り返してください」、ru)
exten => 100、n(vasya)、ダイヤル(SIP / 101)
テーマのバリエーション
- 例を簡単にするために、聞いた内容をテンプレートと比較するための条件を1つだけ引用しましたが、実際にはさらに多くの条件があります。
- Googleの「鉄の女性」と言うあまり良くないフレーズ。 もちろん、作業バージョンでは、「ライブ」音声でフレーズを録音し、再生機能を使用してフレーズを再生すると便利です。
微妙
このタイプのGoogle翻訳との連携では、完全にではなく完全に機能することを考慮する価値があります。Googleから得られた結果を比較するテンプレートを作成する際には、これを考慮する必要があります。
ここに私が踏んだレーキの例があります:
私の名前はシリル(末尾に2つの「L」)です。 何らかの理由で彼にしか知られていないGoogleは、再び「Cyril」または「Cyril」を返しました。
あとがき
比較はもっと技術的な方法で実装できるとの疑いがあります。コメントであなたの意見や提案を聞いてうれしいです。
そして、スケールに関する未解決の問題が残っています:サブスクライバーが多数いる場合はどうなるか、すべての比較を実行するのにどれくらい時間がかかるか、もちろん、私が提案した方法を使用して実装される場合。 ただし、約20人の加入者の小規模なPBXの場合、この方法は受け入れられます。
ご清聴ありがとうございました。
UPD
例
例として、私はわずかに異なるダイヤルプランを使用しましたが、この本質は変わりません。
ダイヤルプランの例:
exten => 8251.1、回答()
exten => 8251、n、MixMonitor(/ var /スプール/アスタリスク/モニター/ 8251 / $ {CDR(開始)}-$ {DST-NUM}-$ {ID_CALL} -full.wav)
exten => 8251、n、agi(googletts.agi、「接続している加入者の名前を教えてください。」、ru)
exten => 8251、n(レコード)、agi(speech-recog.agi、ru-RU)
exten => 8251、n、GotoIf($ [$ ["$ {status}" = "0"]&$ ["$ {confidence}"> "0.5"]] if1:再試行)
exten => 8251、n(if1)、GotoIf($ ["$ {utterance}" = "alexander"]?al:再試行)
exten => 8251、n(al)、ダイヤル(SIP / 8201)
exten => 8251、n(再試行)、agi(googletts.agi、「繰り返してください?」、ru)
exten => 8251、n、goto(レコード)
exten => 8251、n、MixMonitor(/ var /スプール/アスタリスク/モニター/ 8251 / $ {CDR(開始)}-$ {DST-NUM}-$ {ID_CALL} -full.wav)
exten => 8251、n、agi(googletts.agi、「接続している加入者の名前を教えてください。」、ru)
exten => 8251、n(レコード)、agi(speech-recog.agi、ru-RU)
exten => 8251、n、GotoIf($ [$ ["$ {status}" = "0"]&$ ["$ {confidence}"> "0.5"]] if1:再試行)
exten => 8251、n(if1)、GotoIf($ ["$ {utterance}" = "alexander"]?al:再試行)
exten => 8251、n(al)、ダイヤル(SIP / 8201)
exten => 8251、n(再試行)、agi(googletts.agi、「繰り返してください?」、ru)
exten => 8251、n、goto(レコード)
認識に成功したリンクを記録します。
アステステリスクの結論:
-新しいスタックで[8251 @ from-internal:1] Answer( "SIP / 8211-00000000"、 "")を実行する
-[8251 @ from-internal:2] MixMonitorの実行(「SIP / 8211-00000000」、「/ var /スプール/アスタリスク/モニター/ 8251 / 2013-04-24 10:28:03 --- full.wav」 )新しいスタック
-[8251 @ from-internal:3] AGI(「SIP / 8211-00000000」、「googletts.agi」、接続先のサブスクライバーの名前を教えてください。「、Ru」)を新しいスタックで実行します
-AGIスクリプト/var/lib/asterisk/agi-bin/googletts.agiを起動しました
== MixMonitor記録SIPの開始/ 8211-00000000
-「/ tmp / 16ae8d012843179807cfdabd9a34608f」の再生(escape_digits =)(sample_offset 0)
-「/ tmp / ef3ccb070117857a8045932052f3fd7b」の再生(escape_digits =)(sample_offset 0)
-<SIP / 8211-00000000> AGIスクリプトgoogletts.agiが完了し、0を返します
-新しいスタックで[8251 @ from-internal:4] AGI( "SIP / 8211-00000000"、 "speech-recog.agi、ru-RU")を実行
-AGIスクリプト/var/lib/asterisk/agi-bin/speech-recog.agiを起動しました
-<SIP / 8211-00000000>「beep.ulaw」(言語「en」)の再生
-<SIP / 8211-00000000> AGI Script speech-recog.agiが完了し、0を返します
-新しいスタックで[8251 @ from-internal:5] GotoIf( "SIP / 8211-00000000"、 "1?If1:retry")を実行する
-後藤(内部から、8251.6)
-[8251 @ from-internal:6] GotoIf( "SIP / 8211-00000000"、 "1?Al:retry")を新しいスタックで実行する
-後藤(内部から、8251.7)
-新しいスタックで[8251 @ from-internal:7]ダイヤル(「SIP / 8211-00000000」、「SIP / 8201」)を実行
== SIP RTP TOSビット184の使用
== SIP RTP CoSマーク5を使用
-SIP / 8201と呼ばれる
-SIP / 8201-00000001が鳴っている
-SIP / 8201-00000001がSIP / 8211-00000000と応答した
-[h @ from-internal:1] Hangup( "SIP / 8211-00000000"、 "")を新しいスタックで実行する
==「SIP / 8211-00000000」でスポーン拡張機能(from-internal、h、1)がゼロ以外で終了しました
==スポーン拡張機能(from-internal、8251、7)が「SIP / 8211-00000000」でゼロ以外で終了しました
== MixMonitorがファイルストリームを閉じる
== MixMonitor記録SIPの終了/ 8211-00000000
-[8251 @ from-internal:2] MixMonitorの実行(「SIP / 8211-00000000」、「/ var /スプール/アスタリスク/モニター/ 8251 / 2013-04-24 10:28:03 --- full.wav」 )新しいスタック
-[8251 @ from-internal:3] AGI(「SIP / 8211-00000000」、「googletts.agi」、接続先のサブスクライバーの名前を教えてください。「、Ru」)を新しいスタックで実行します
-AGIスクリプト/var/lib/asterisk/agi-bin/googletts.agiを起動しました
== MixMonitor記録SIPの開始/ 8211-00000000
-「/ tmp / 16ae8d012843179807cfdabd9a34608f」の再生(escape_digits =)(sample_offset 0)
-「/ tmp / ef3ccb070117857a8045932052f3fd7b」の再生(escape_digits =)(sample_offset 0)
-<SIP / 8211-00000000> AGIスクリプトgoogletts.agiが完了し、0を返します
-新しいスタックで[8251 @ from-internal:4] AGI( "SIP / 8211-00000000"、 "speech-recog.agi、ru-RU")を実行
-AGIスクリプト/var/lib/asterisk/agi-bin/speech-recog.agiを起動しました
-<SIP / 8211-00000000>「beep.ulaw」(言語「en」)の再生
-<SIP / 8211-00000000> AGI Script speech-recog.agiが完了し、0を返します
-新しいスタックで[8251 @ from-internal:5] GotoIf( "SIP / 8211-00000000"、 "1?If1:retry")を実行する
-後藤(内部から、8251.6)
-[8251 @ from-internal:6] GotoIf( "SIP / 8211-00000000"、 "1?Al:retry")を新しいスタックで実行する
-後藤(内部から、8251.7)
-新しいスタックで[8251 @ from-internal:7]ダイヤル(「SIP / 8211-00000000」、「SIP / 8201」)を実行
== SIP RTP TOSビット184の使用
== SIP RTP CoSマーク5を使用
-SIP / 8201と呼ばれる
-SIP / 8201-00000001が鳴っている
-SIP / 8201-00000001がSIP / 8211-00000000と応答した
-[h @ from-internal:1] Hangup( "SIP / 8211-00000000"、 "")を新しいスタックで実行する
==「SIP / 8211-00000000」でスポーン拡張機能(from-internal、h、1)がゼロ以外で終了しました
==スポーン拡張機能(from-internal、8251、7)が「SIP / 8211-00000000」でゼロ以外で終了しました
== MixMonitorがファイルストリームを閉じる
== MixMonitor記録SIPの終了/ 8211-00000000
成功していない認識へのリンク 。
アステステリスクの結論:
-[8251 @ from-internal:1] Answer( "SIP / 8211-00000002"、 "")を新しいスタックで実行する
-[8251 @ from-internal:2] MixMonitorの実行( "SIP / 8211-00000002"、 "/ var /スプール/アスタリスク/モニター/ 8251 / 2013-04-24 10:36:29 --- full.wav" )新しいスタック
-[8251 @ from-internal:3] AGI(「SIP / 8211-00000002」、「googletts.agi」、接続している加入者の名前を教えてください。「、Ru」)を新しいスタックで実行します
-AGIスクリプト/var/lib/asterisk/agi-bin/googletts.agiを起動しました
== MixMonitor記録SIPの開始/ 8211-00000002
-「/ tmp / 16ae8d012843179807cfdabd9a34608f」の再生(escape_digits =)(sample_offset 0)
-「/ tmp / ef3ccb070117857a8045932052f3fd7b」の再生(escape_digits =)(sample_offset 0)
-<SIP / 8211-00000002> AGIスクリプトgoogletts.agiが完了し、0を返します
-[8251 @ from-internal:4] AGI( "SIP / 8211-00000002"、 "speech-recog.agi、ru-RU")を新しいスタックで実行
-AGIスクリプト/var/lib/asterisk/agi-bin/speech-recog.agiを起動しました
-<SIP / 8211-00000002>「beep.ulaw」(言語「en」)の再生
-<SIP / 8211-00000002> AGI Script speech-recog.agiが完了し、0を返します
-[8251 @ from-internal:5] GotoIf( "SIP / 8211-00000002"、 "1?If1:retry")を新しいスタックで実行
-後藤(内部から、8251.6)
-[8251 @ from-internal:6] GotoIf( "SIP / 8211-00000002"、 "0?Al:retry")を新しいスタックで実行
-後藤(from-internal、8251.8)
-[8251 @ from-internal:8] AGI(「SIP / 8211-00000002」、「googletts.agi、「繰り返してください」、「Ru」)を新しいスタックで実行
-AGIスクリプト/var/lib/asterisk/agi-bin/googletts.agiを起動しました
-'/ tmp / 0c5de11c17dda57dabeaebe335110036'(escape_digits =)(sample_offset 0)の再生
-<SIP / 8211-00000002> AGIスクリプトgoogletts.agiが完了し、0を返します
-[8251 @ from-internal:2] MixMonitorの実行( "SIP / 8211-00000002"、 "/ var /スプール/アスタリスク/モニター/ 8251 / 2013-04-24 10:36:29 --- full.wav" )新しいスタック
-[8251 @ from-internal:3] AGI(「SIP / 8211-00000002」、「googletts.agi」、接続している加入者の名前を教えてください。「、Ru」)を新しいスタックで実行します
-AGIスクリプト/var/lib/asterisk/agi-bin/googletts.agiを起動しました
== MixMonitor記録SIPの開始/ 8211-00000002
-「/ tmp / 16ae8d012843179807cfdabd9a34608f」の再生(escape_digits =)(sample_offset 0)
-「/ tmp / ef3ccb070117857a8045932052f3fd7b」の再生(escape_digits =)(sample_offset 0)
-<SIP / 8211-00000002> AGIスクリプトgoogletts.agiが完了し、0を返します
-[8251 @ from-internal:4] AGI( "SIP / 8211-00000002"、 "speech-recog.agi、ru-RU")を新しいスタックで実行
-AGIスクリプト/var/lib/asterisk/agi-bin/speech-recog.agiを起動しました
-<SIP / 8211-00000002>「beep.ulaw」(言語「en」)の再生
-<SIP / 8211-00000002> AGI Script speech-recog.agiが完了し、0を返します
-[8251 @ from-internal:5] GotoIf( "SIP / 8211-00000002"、 "1?If1:retry")を新しいスタックで実行
-後藤(内部から、8251.6)
-[8251 @ from-internal:6] GotoIf( "SIP / 8211-00000002"、 "0?Al:retry")を新しいスタックで実行
-後藤(from-internal、8251.8)
-[8251 @ from-internal:8] AGI(「SIP / 8211-00000002」、「googletts.agi、「繰り返してください」、「Ru」)を新しいスタックで実行
-AGIスクリプト/var/lib/asterisk/agi-bin/googletts.agiを起動しました
-'/ tmp / 0c5de11c17dda57dabeaebe335110036'(escape_digits =)(sample_offset 0)の再生
-<SIP / 8211-00000002> AGIスクリプトgoogletts.agiが完了し、0を返します