Архив метки: Linux

FreePBX, Elastix. Уведомление о пропущенных вызовах

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

Уведомления при потерянных вызовах на IVR

Если вызовы поступают на IVR, и звонящий не дождавшись ответа положил трубку, то для отчетов правим файл /etc/asterisk/extensions_override_freepbx.conf

# nano /etc/asterisk/extensions_override_freepbx.conf

 

[ivr-1] ;Номер ivr

exten => h,1,System(python /usr/local/bin/sendmail.py "Пропущенный вызов в ${STRFTIME(${EPOCH},,%Y-%m-%d %H:%M:%S)}с номера ${CALLERID(name)}")


Сохраняем и делаем reload астериска. Тепер. если позвонивший положит трубку слушая голосовое меню, то на почту прийдет уведомление. Сам  sendmail.py находится в конце статьи.

Уведомление в группах вызова

Если необходимо уведомлять о потерянных вызовах в группах вызова, то также правим файл /etc/asterisk/extensions_override_freepbx.conf

# nano /etc/asterisk/extensions_override_freepbx.conf

 

[ext-group]

exten => h,1,System(python /usr/local/bin/sendmail.py "Пропущенный вызов в ${STRFTIME(${EPOCH},,%Y-%m-%d %H:%M:%S)}с номера ${CALLERID(name)}")

exten => h,2,Macro(hangupcall,)

 Уведомление в очередях

Если же вызов поступает в очередь, то в /etc/asterisk/extensions_override_freepbx.conf  прописываем

[ext-queues]

exten => h,1,ExecIf($["${CDR(dstchannel)}"=""]?System(python /usr/local/bin/sendmail.py "Пропущенный вызов в ${STRFTIME(${EPOCH},,%Y-%m-%d %H:%M:%S)} с номера ${CALLERID(name)}"))

exten => h,2,Macro(hangupcall,)

Сам файл sendmail.py

#!/usr/bin/python

# -*- coding: utf-8 -*-

from email.MIMEText import MIMEText

import smtplib

import sys

sender = 'noanswer@yourdomain.ru' # От кого

recivers = 'youremail' # Ваш e-mail

host = "localhost"

text = sys.argv[1]

msg = MIMEText(text, "", "utf-8")

msg["Subject"] = "Уведомление о пропущенном вызове"

smtpObj = smtplib.SMTP('localhost')

smtpObj.sendmail(sender, recivers, msg.as_string())

smtpObj.close()


Не забудте дать права на запуск

chmod 755 /usr/local/bin/sendmail.py



2018-09-29T23:30:16
Asterisk

Asetrisk, распознавание и генерации речи с помощью yandex speechkit

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

Итак, настройка Asterisk, для простоты настраивать будем через ael:

На Астериске организован цикл while

1234567 => {

Answer;

Set(audio=/var/lib/asterisk/sounds/custom/enteraccount);

flag=1;

label=1;

while (${flag} = 1){

Background(${audio});

Record(/tmp/${UNIQUEID}label${label}.wav,3,20);

Agi(yandex.agi,/tmp/${UNIQUEID}, ${label});

label=${label}+1;



                  };



    };

В начале позвонившему проигрывается фудио файл «enteraccount» с просьбой назвать лицевой счет

На каждом шаге цикла, позвонившему человеку проигрывается аудио файл «audio», путь к которому получен из agi скрипта, далее записывается ответ, и путь к полученному записанному файлу отправляется agi скрипту, также в скрипт отправляется текущий шаг «label», после чего шаг увеличивается на 1, и цикл повторяется. Из agi скрипта астерис получает 2 параметра, это обязательный параметр «audio», путь к аудиофайлу который нужно проиграть, и не обязательный «label», метка с помощью которой происходит синхронизация астериска и agi. Выход из цикла происходит если человек положил трубку, а также если из agi прийдет параметр «flag» не равный 1.

Еще неплохо бы после завершения вызова удалить все временные файлы, для этого в макросе который срабатывает после завершения вызова пропишем

[macro-hangupcall]

exten => s,1,System(find /tmp/ -name "${UNIQUEID}*" | xargs rm);

На этом настройка астериска завершена.

Далее сам скрипт yandex.agi, написанный на python, для работы необходимо установить pyst

# wget http://heanet.dl.sourceforge.net/project/pyst/pyst/0.6.50/pyst-0.6.50.zip

# unzip pyst-0.6.50.zip

# cd pyst-0.6.50

# python setup.py install

Сам agi:

#!/usr/bin/python

# -*- coding: utf-8 -*-

import urllib2

import urllib

import sys

import random

from xml.dom.minidom import *

import os

import asterisk.agi



agi=asterisk.agi.AGI()

uuid=''

key='28b22b47-a7b0-40d2-892d-ad79bbdbc304'

def yadexASR(uuid, key, topic, callid):

# Функция для преобразования аудио файла в текст

# Генерим уникальный код id для запроса

    while (len(uuid)<32):

        uuid=uuid+random.choice('1234567890abcdef')

    #Ссылка для пост запроса 

    url = 'https://asr.yandex.net/asr_xml?uuid=%s&key=%s&topic=%s&lang=ru-RU' % (uuid, key, topic)

    filename = callid+'.wav'

    #Считываем файл в двоичном режиме

    audio = open(filename,'rb').read()

    #Указываем тип аудиофайла для заголовка в POST запрос

    headers={'Content-Type': 'audio/x-pcm;bit=16;rate=8000'}

    #Отправляем запрос

    request = urllib2.Request(url, data=audio, headers=headers)

    response = urllib2.urlopen(request)

    #Считываем ответ

    answer=response.read()

    # Создаем xml файл для полученного ответа

    f_answer=('%s.xml' % callid)

    f=open(f_answer, 'w')

    # записываем в файл ответ полученный на POST запрос (ответ получен в xml формате)

    f.write(answer)

    f.close()

    # Парсим xml файл

    xml = parse(f_answer)

    # Выбираем из файла значение между тегами variant

    var = xml.getElementsByTagName('variant')

    # Выбираем первое значение из xml файла, оно же наиболее точное в распознании

    result=var[0].childNodes[0].nodeValue

    return result



def generate(key,text, file):

# Функция для преобразования текста в аудио формат

    #Форматируем текс для GET запрса (нужен для корректной обработки кирилици)

    text_f=urllib.quote_plus(text.encode('utf-8'))

    #отправляем запрос на яндекс

    url='http://tts.voicetech.yandex.net/generate?text=%s&format=mp3&lang=ru-RU&speaker=jane&key=%s' % (text_f, key)

    # Сохраняем айдио файл в file

    urllib.urlretrieve(url, file)



if sys.argv[2].replace(' ','')=="1":

    agi.verbose('label='+sys.argv[2].replace(' ',''))

    try:

        # Распознаем полученный файл

        result=yadexASR(uuid, key, 'notes', sys.argv[1]+'label'+sys.argv[2].replace(' ',''))

        # Формируем ответ

        file=sys.argv[1]+'outlabel'+sys.argv[2].replace(' ','')

        generate(key, u'Вы сказали '+result+u'Скажите да или Нет', file+'.mp3')

        agi.set_variable('audio', file)

    except:

        agi.set_variable('audio', '/var/lib/asterisk/sounds/custom/enteraccount')

        agi.set_variable('label', '0')

        agi.verbose('label=0')



elif sys.argv[2].replace(' ','')=="2":

    agi.verbose('label='+sys.argv[2].replace(' ',''))

    try:

        result=yadexASR(uuid, key, 'notes', sys.argv[1]+'label'+sys.argv[2].replace(' ',''))

    except:

        agi.set_variable('label', '1')

    if 'Да' in str(result.encode('utf-8')):

        agi.verbose('Yes')

        #///////////////////////////////

        # Здест должна быть проверка на существование абонента в базе данных

        #/////////////////////////////

    

        file=sys.argv[1]+'outlabel'+sys.argv[2].replace(' ','')

        generate(key, u'Показания какого счетчика вы хотите сообщить горячего или холодного?', file+'.mp3')

        agi.set_variable('audio', file)

    elif 'Нет' in str(result.encode('utf-8')):

        agi.verbose('No')

        # Ставим метку в 0 что бы вернуться к шагй 1 и проигрываем файл

        agi.set_variable('label', '0')

        agi.set_variable('audio', '/var/lib/asterisk/sounds/custom/enteraccount')

    else:

        agi.verbose('Error')

        # Если ответ не да и ни нет, говорим об ошибки и ставим метку на 1 что бы вернуться к шагу 2

        agi.set_variable('label', '1')

elif sys.argv[2].replace(' ','')=="3":

    agi.verbose('label='+sys.argv[2].replace(' ',''))

    try:

        result=yadexASR(uuid, key, 'notes', sys.argv[1]+'label'+sys.argv[2].replace(' ',''))

    except:

        agi.set_variable('label', '2')

    if 'Горяч' in str(result.encode('utf-8')):

        agi.verbose('Hot')      

        file=sys.argv[1]+'outlabel'+sys.argv[2].replace(' ','')

        generate(key, u'Сообщите показания горячего счетчика', file+'.mp3')

        agi.set_variable('audio', file)

    elif 'Холод' in str(result.encode('utf-8')):

        agi.verbose('Cold')     

        file=sys.argv[1]+'outlabel'+sys.argv[2].replace(' ','')

        generate(key, u'Сообщите показания холодного счетчика', file+'.mp3')

        agi.set_variable('audio', file)

    else:

        agi.verbose('Error')

        agi.set_variable('label', '2')

elif sys.argv[2].replace(' ','')=="4":

    agi.verbose('label='+sys.argv[2].replace(' ',''))

    try:

        result=yadexASR(uuid, key, 'notes', sys.argv[1]+'label'+sys.argv[2].replace(' ',''))      

        file=sys.argv[1]+'outlabel'+sys.argv[2].replace(' ','')

        generate(key, u'Ваши показания '+result+u'Скажите да или Нет', file+'.mp3')

        agi.set_variable('audio', file)

    except:

        agi.set_variable('label', '3')

        agi.verbose('label=3')

elif sys.argv[2].replace(' ','')=="5":

    try:

        result=yadexASR(uuid, key, 'notes', sys.argv[1]+'label'+sys.argv[2].replace(' ',''))

    except:

        agi.set_variable('label', '1')

    if 'Да' in str(result.encode('utf-8')):

        

        #/////////////

        #Обрабатываем результат и заносим в базу

        #/////////////

 

        file=sys.argv[1]+'outlabel'+sys.argv[2].replace(' ','')

        generate(key, u'Хотите сообщить показания другого счетчика да или нет?', file+'.mp3')

        agi.set_variable('audio', file)

    elif 'Нет' in str(result.encode('utf-8')):

        agi.set_variable('label', '2')

        file=sys.argv[1]+'outlabel'+sys.argv[2].replace(' ','')

        generate(key, u'Показания какого счетчика вы хотите сообщить горячего или холодного?', file+'.mp3')

        agi.set_variable('audio', file)

    else:

        agi.verbose('Error')

        agi.set_variable('label', '2')

elif sys.argv[2].replace(' ','')=="6":

    try:

        result=yadexASR(uuid, key, 'notes', sys.argv[1]+'label'+sys.argv[2].replace(' ',''))

    except:

        agi.set_variable('label', '1')

    if 'Да' in str(result.encode('utf-8')):

        file=sys.argv[1]+'outlabel'+sys.argv[2].replace(' ','')

        generate(key, u'Показания какого счетчика вы хотите сообщить горячего или холодного?', file+'.mp3')

        agi.set_variable('audio', file)

        agi.set_variable('label', '2')

    elif 'Нет' in str(result.encode('utf-8')):

        file=sys.argv[1]+'outlabel'+sys.argv[2].replace(' ','')

        generate(key, u'Досвидания', file+'.mp3')

        agi.set_variable('audio', file)

    else:

        agi.verbose('Error')

        file=sys.argv[1]+'outlabel'+sys.argv[2].replace(' ','')

        generate(key, u'Хотите сообщить показания другого счетчика да или нет', file+'.mp3')

        agi.set_variable('label', '5')



2018-09-29T23:27:08
Asterisk

Elastix, права на прослушивание записей и просмотр статистики звонков

По умолчанию прослушивать запись и просматривать статистику всех звонков в Elastix может только пользователь admin, все остальные пользователи могут прослушивать и просматривать статистику только своих звонков. Если же нужно разрешить пользователю из группы Operator доступ ко всем звонкам, но при этом не делать его администратором, то в Elastix, в файле:

var/www/html/libs/paloSantoACL.class.php

В функции:

function isUserAdministratorGroup($username)

после строчки:

 $is = array_search('1', $arrGroup);

Добавить следующий код:

if(isset($arrGroup['Operator']))

$is=true;


После этого все пользователи группы Operator смогут просматривать отчет по всем звонкам, а также прослушивать все разговоры.



2018-09-29T23:25:09
Asterisk

Сброс пароля Elastix на web интерфейс

Если в качестве IP PBx вы используете Elastix, и забыли пароль на доступ по WEB интерфейсу. Есть простой способ сменить пароль администратора на WEB интерфейс, для этого у вас должен быть root доступ на консоль. Для изменения пароля на пароль по умолчанию «palosanto» нужно в консоли выполнить следующую команду:

sqlite3 /var/www/db/acl.db "update acl_user set md5_password='7a5210c173ea40c03205a5de7dcd4cb0' where id=1"

На Elastix 3.0, вышеописанная инструкция не работает. Сменить пароль можно командой

/usr/bin/elastix-admin-passwords --change

Ну и не забываем что теперь пользователь у нас superadmin и у пароля есть большие ограничения по сложности (не менее 10 разнокалиберных символов и цифр).



2018-09-28T12:32:17
Asterisk

Защита OpenVPN с помощью Fail2Ban

В связи с последними блокировками IP-адресов Роскомнадзором, встала необходимость завести свой собственный VPN сервер.

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

Запуск Windows игр в Linux через Steam Play

Компания Valve продолжает работать, чтобы улучшить поддержку игр в операционных системах Linux. Раньше была выпущена версия клиента Steam для Linux, потом для этой платформы было адаптировано множество отличных игр, среди которых есть и очень популярные.

И вот разработчики сделали ещё один шаг, чтобы улучшить совместимость Windows-игр с платформой Linux. В клиент Steam добавили возможность запускать их через Wine. Здесь эта возможность называется Steam Play. В этой статье мы поговорим о том, как запускать Windows-игры в Linux через Steam Play.

Читать