Синтез и распознавание речи от Google для Asterisk

Доброе утро!

Вчера вечером заглянул на Хабр, увидел статью Google translate+Asterisk IVR и у меня волосы зашевелились в подмышках.

Синтез речи, как это просто!
Не нужно собирать Festival и искать для него семплы. Все уже готово, просто и от Google.


Сразу переписал предложенный вариант на свою любимый php и оформил в виде AGI для вызова из Астериска. Хотел чтобы синтез можно было использовать одной строкой в диалпланет, как стандартную команду SayDigits():

Пример использования в extensions.ael:
s => {
        Answer();
        Wait(1);
        AGI(say.php,"Здравствуйте");
        AGI(say.php,"Вас приветствует компания");
        AGI(say.php,"Habrahabr!",en);
        AGI(say.php,"Ваш звонок важен для нас!");
        AGI(say.php,"Пожалуйста!");
        AGI(say.php,"оставайтесь на линии");
        AGI(say.php,"Вам обязательно ответят!");
};


И сам php код (должен быть /var/lib/asterisk/agi-bin/say.php):
#!/usr/bin/php -q
<?php
$agivars = array();
while (!feof(STDIN)) {
    $agivar = trim(fgets(STDIN));
    if ($agivar === '')
        break;

    $agivar = explode(':', $agivar);
    $agivars[$agivar[0]] = trim($agivar[1]);
}
extract($agivars);

$text = $_SERVER["argv"][1];
if (isset($_SERVER["argv"][2])) $lang = $_SERVER["argv"][2];
else $lang = 'ru';

$md5 = md5($text);

$prefix = '/var/lib/asterisk/festivalcache/';
$filename = $prefix.$md5;

if (!file_exists($filename.'.alaw')) {
    $wget = 'wget -U "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5" ';
    $wget.= '"http://translate.google.com/translate_tts?q='.$text.'&tl='.$lang.'" -O '.$filename.'.mp3';
    $ffmpeg = 'ffmpeg -i '.$filename.'.mp3 -ar 8000 -ac 1 -ab 64 '.$filename.'.wav -ar 8000 -ac 1 -ab 64 -f alaw '.$filename.'.alaw -map 0:0 -map 0:0';
    $exec = $wget.' && '.$ffmpeg.' && rm '.$filename.'.mp3 '.$filename.'.wav';
    exec($exec);
}

echo 'STREAM FILE "'.$filename.'" ""'."\n";
fgets(STDIN);
exit(0);
?>

В моем Asterisk основным кодеком является alaw, по этому mp3 конвертирую сразу в alaw.

После 10 минут восторга, я вспомнил, что у Google есть возможность распознавать речь (как в поиске с мобильного телефона). Полазил по интернетам и нашел статью Управление голосом. Распознавание русской речи, где лежит пример на php для распознавания речи средствами Google.

Переписал код в форму AGI и получил (/var/lib/asterisk/agi-bin/voice.php):
#!/usr/bin/php -q
<?
$agivars = array();
while (!feof(STDIN)) {
    $agivar = trim(fgets(STDIN));
    if ($agivar === '')
        break;

    $agivar = explode(':', $agivar);
    $agivars[$agivar[0]] = trim($agivar[1]);
}
extract($agivars);

$filename = $_SERVER["argv"][1];

exec('flac -f -s '.$filename.'.wav -o '.$filename.'.flac');

$file_to_upload = array('myfile'=>'@'.$filename.'.flac');
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,"https://www.google.com/speech-api/v1/recognize?xjerr=1&client=chromium&lang=ru-RU");
curl_setopt($ch, CURLOPT_POST,1);
curl_setopt($ch, CURLOPT_HTTPHEADER, array("Content-Type: audio/x-flac; rate=8000"));
curl_setopt($ch, CURLOPT_POSTFIELDS, $file_to_upload);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
$result=curl_exec ($ch);
curl_close ($ch);

$json_array = json_decode($result, true);
$voice_cmd = $json_array["hypotheses"][0]["utterance"];

unlink($filename.'.flac');
unlink($filename.'.wav');

echo 'SET VARIABLE VOICE "'.$voice_cmd.'"'."\n";
fgets(STDIN);
echo 'VERBOSE ("'.$voice_cmd.'")'."\n";
fgets(STDIN);
exit(0);
?>

Google Speech API принимает звуковые файлы в формате flac и speex, из примера оставил flac.
В переменную ${VOICE} будет установлен распознанный текст.

Общий пример использование в extensions.ael:
s => {
        Answer();
        Wait(1);
        AGI(say.php,"Здравствуйте");
        AGI(say.php,"Пожалуйста");
        AGI(say.php,"Скажите имя сотрудника");
        Record(/tmp/${UNIQUEID}.wav,3,20);
        AGI(say.php,"Вы сказали");
        Playback(/tmp/${UNIQUEID});
        AGI(voice.php,/tmp/${UNIQUEID});
        AGI(say.php,"Система услышала");
        AGI(say.php,"${VOICE}");
        Hangup();
    };

Record записывает wav файл максимальной длиной 20 секунд и заканчивает запись после 3 секунд тишины.
Так как это тестовый пример мы прослушиваем сказанное и потом синтезируем распознаный текст.

Что можно сказать, Google — молодцы!
Теперь понятно как чистый Asterisk обучить синтезу и распознаванию речи, без использования Festival и Sphinx.

И если начальство попросит быстро сделать голосовую IVR менюшку, мы сможем удивить!

Добавил

Прочитал коментарий пользователя int80h, прочитал про миграцию с Google Translate API на Bing Translate API и подумал что во всем нужна альтернатива.

Версия 2.0
say.php с возможностью синтеза речи через Microsoft Translator:
#!/usr/bin/php -q
<?php
$agivars = array();
while (!feof(STDIN)) {
    $agivar = trim(fgets(STDIN));
    if ($agivar === '')
        break;
    $agivar = explode(':', $agivar);
    $agivars[$agivar[0]] = trim($agivar[1]);
}
extract($agivars);

$text = $_SERVER["argv"][1];
if (isset($_SERVER["argv"][2]) && in_array($_SERVER["argv"][2], array('g','m'))) $voice = $_SERVER["argv"][2];
else $voice = 'g';
if (isset($_SERVER["argv"][3])) $lang = $_SERVER["argv"][3];
else $lang = 'ru';

$md5 = md5($text.$voice.$lang);

$prefix = '/var/lib/asterisk/festivalcache/';
$appid = 'T0CQJrrwQ1NcJFlJshEfWTzaI18B4TzVvBKx9CDoLvf8*';
$filename = $prefix.$md5;

if (!file_exists($filename.'.alaw')) {
    if ($voice == 'm') {
        $ext = '.wav';
        exec('wget "http://api.microsofttranslator.com/V2/Http.svc/Speak?language='.$lang.'&format=audio/wav&options=MaxQuality&appid='.$appid.'&text='.$text.'" -O '.$filename.$ext);
    } else {
        $ext = '.mp3';
        exec('wget -U "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5" "http://translate.google.com/translate_tts?q='.$text.'&tl='.$lang.'" -O '.$filename.$ext);
    }

    if (@filesize($filename.$ext) > 0) {
        exec('ffmpeg -i '.$filename.$ext.' -ar 8000 -ac 1 -ab 64 -f alaw '.$filename.'.alaw -map 0:0');
    }

    unlink($filename.$ext);
}

if (file_exists($filename.'.alaw')) {
    echo 'STREAM FILE "'.$filename.'" ""'."\n";
    fgets(STDIN);
} else {
    echo 'VERBOSE ("Speech Error!")'."\n";
    fgets(STDIN);
}
exit(0);
?>

Microsoft отдает звук в формате wav (у mp3 качество нулевое) и просит какой-то Bing AppId (взял с сайта microsofttranslator.com, посмотрим сколько проживет).
Качество синтеза мне показалось хуже чем у Google, но ударение в именах ставит более правильно.

AGI(say.php,"Здравствуйте",m);

AGI(say.php,"Здравствуйте",${ГОЛОС},${ЯЗЫК});
${ГОЛОС} - может быть m или g (если опустить = g)
${ЯЗЫК} - ru, en и прочее (если опустить = ru)

Русский текст будет работать только при ru, английский будет всегда, но при ru будет «ломаным».
В тексте работают ударения (' перед гласной) и знаки препинания (например !) меняют интонацию.

PS: Заменил, что распознавание речи может выдавать пустой текст, но при повторной отправке того же файла, все проходит гладко, странно это :-)
Share post

Similar posts

AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 14

    +8
    Только если вдруг интернет недоступен, или перегружен, или еще какой факап, система отвалится.
    Тогда как «локальная» копия just works.
      +3
      Если инет не доступен, то тогда и sip телефония не доступна, вот если гугл отвалится… то да. epic fail
        +6
        Asterisk это не только SIP телефония, да и она не обязана ходить по public internet, а может быть на отдельном интерфейсе в vlan'е.
        +1
        Конечно без интернета хуже.
        Но синтезированный голос остается в кэше и если фраза уже произносилась система будет говорить.

        Фразы из кэше можно произносить без php:
        Playback(/var/lib/asterisk/festivalcache/${MD5(Здравствуйте)});
          0
          recognize точно не будет работать :))
        0
        Осталось еще прикрутить годный AI и можно, например, организовать call-центр без операторов :)
          0
          Не понятно, почему все так радуются этой ужасной (не похожей на человеческую речь) озвучки от гугла?

          Вот пример работы встроенного движка в mac os («Здравствуйте, оставайтесь на линии»): zalil.ru/32182164 (111 Kb)

          через консольную утилиту можно выбирать десятки голосов для почти всех стран, в том числе по несколько вариантов для некоторых стран включая пол, десяток разных форматов файла для вывода, качество, битрейт, количество каналов для некоторых голосов и т.д. При этом можно сразу хоть книжку целую озвучить в один подход.
            +2
            Ну так, для «встроенного движка в mac os» нужен сам Mac OS, также как для Microsoft Speech нужен Windows.
            То есть, нужно или астериск под macos/windows ставить или придумывать как все связать, не говоря уже о покупке лицензий и фруктового железа.

            Или, если ты говоришь о разовом синтезе (по готовому сценарию) и ручном переносе, то да, все верно.
            Хотя живой человек еще лучше прочитает. С тем же успехом можно позвонить в свой call-центр (или можно даже в чужой) и сказать: «Привет девчонки! Повторяйте за мной».

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

            Статья о простом и быстром, а не о качественном :-)
            –2
            Круто, как все просто!!!)) не надо придумывать велосипед )
            Молодец аффтарр)
            Сегодня обязательно попробую!!!
              0
              Круть неимоверная, только в систему надо несколько пакетов доустановить.
              ffmpeg,flac,php5-curl

              Есть энтузиасты которые смогут реализовать следующую схему?
              Звоним Астериску, Астериск записывает и с помощью Google Speech API выдает нам текст.
              Тест загоняем в переводчик, из переводчика озвучиваем его на английском языке и отдаем Siri.
              С ответом от Siri производим обратный порядок действий, и как в итоге общаемся с ней на ломаном русском. :)
              • UFO just landed and posted this here
                  +1
                  Надо предусмотреть ещё вариант, когда инет отвалился и звонят на городскую линию… Что-то типа альтернативного заранее записанного меню…

                  Добавил в закладки: высплюсь и повторю у себя!
                  • UFO just landed and posted this here
                    • UFO just landed and posted this here

                    Only users with full accounts can post comments. Log in, please.