К моим клиентам в call центр иногда поступает большой поток звонков. Одни их них придумали свой нестандартный способ переключения режима фоновой музыки (автоинформатора) в очереди астериска в зависимости от нагрузки на операторов, который не реализуется штатными средствами. Мы будем анализировать логи очередей и по заданным условиям менять настройки диалплана. Условия были озвучены следующие:
1. Если за последний час в очереди было не менее 4х клиентов ожидающих ответа более 4 минут, то менять режим сообщений информатора очереди на усиленный (3852-hard).
2. Если за последний час в очереди было менее 4х клиентов ожидающих ответа более 6 минут, то возвращаем режим сообщений информатора очереди на обычный (3852-soft).
В общем, разобьем работу на 5 частей и начнем колхозить:
1. Если за последний час в очереди было не менее 4х клиентов ожидающих ответа более 4 минут, то менять режим сообщений информатора очереди на усиленный (3852-hard).
2. Если за последний час в очереди было менее 4х клиентов ожидающих ответа более 6 минут, то возвращаем режим сообщений информатора очереди на обычный (3852-soft).
В общем, разобьем работу на 5 частей и начнем колхозить:
- Научим asterisk писать логи очередей в базу mysql.
- Напишем SQL запросы для извлечения нужной статистики.
- Напишем скрипт, который по результатам запросов будет выбирать режим работы фоновой музыки в очереди. Запускать скрипт будет раз в 1 час из крона.
- Зададим новый класс фоновой музыки и научим asterisk брать имя класса из файла.
В нашем случае вся разница между режимами состоит в различных сообщениях голосового информатора, которые проигрываются клиенту в очереди. Поэтому, очередь у нас остается одна, а вот для голосовых сообщений мы зададим дополнительный класс. Далее в диалплане астериска будем использовать переменную, которая будет считывать имя нужного класса из текстового файла. Скрипт будет запускаться 1 раз в час и в случае совпадения заданных условий менять значение этого текстового файла.
Сначала научим писать логи очередей в MySql (самостоятельно установить mysql-server трудностей не вызовет). Нам нужно будет создать базу asterisk и таблицу queue_log с таким содержанием:
Далее отключим запись логов очереди в файл, добавив в секции [general] файла logger.conf строку:
Нас интересуют 2 события: когда клиенту ответил оператор и когда клиент не дождавшись ответа положил трубку. События называются CONNECT и ABANDON соответственно. В поле data1 события CONNECT и в поле data3 события ABANDON как раз указывается время ожидания клиента в секундах до этого события. В итоге мы получим время нахождения клиента в очереди вне зависимости от того, ответили ему или он положил трубку не дождавшись ответа. Более подробно про события в очереди можно прочитать здесь.
Нам нужно выбрать все значения ожидания в данных событиях, отсортировать их по убыванию и ограничить вывод 4 записями. Там мы получим 4 наибольших значения. Далее мы зададим условия для отображения записей длиннее чем 240 (360 во втором запросе) секунд и подсчитаем количество этих записей. Если записей получится меньше чем 4, значит условие не выполнено.
Далее в настройках астериска находим контекст из которого клиент попадает в очередь. Добавляем у него экстеншн задающий класс фоновой музыки, имя которого мы возьмем из файла /etc/asterisk/scripts/musichold.txt.
Научим asterisk писать логи очередей в базу mysql
Сначала научим писать логи очередей в MySql (самостоятельно установить mysql-server трудностей не вызовет). Нам нужно будет создать базу asterisk и таблицу queue_log с таким содержанием:CREATE TABLE IF NOT EXISTS `queue_log` (
`time` datetime DEFAULT NULL,
`callid` char(64) DEFAULT NULL,
`queuename` char(64) DEFAULT NULL,
`agent` char(64) DEFAULT NULL,
`event` char(32) DEFAULT NULL,
`data` char(64) DEFAULT NULL,
`data1` char(64) DEFAULT NULL,
`data2` char(64) DEFAULT NULL,
`data3` char(64) DEFAULT NULL,
`data4` char(64) DEFAULT NULL,
`data5` char(64) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Сразу оговорюсь про поле time. Мануалы в сети рекомендуют использовать типа varchar, но в этом случае сложно будет задавать условия по этому полю относительно времени, например: в течение последнего часа. Поэтому мы будем использовать тип datetime.Далее отключим запись логов очереди в файл, добавив в секции [general] файла logger.conf строку:
nano /etc/asterisk/logger.conf
queue_log_to_file = no
Вторым шагом зададим запись аргументов событий не в строчку c разделителем |, а отдельными полями data1-5nano /etc/asterisk/asterisk.conf
queue_adaptive_realtime = no
Далее для сохранения логов в базу данных по ODBC создаем (если нет) или открываем файл extconfig.conf и пишем в секцию [settings]:nano /etc/asterisk/extconfig.conf
queue_log => odbc,asterisk,queue_log
Теперь нам нужно настроить это самое odbc подключение:nano /etc/asterisk/res_odbc.conf
[asterisk]
enabled => yes
dsn => qs-asterisk
username => db-user
password => db-password
pre-connect => yes
Где dsn, настройки из файла /etc/odbc.ininano /etc/odbc.ini
[qs-asterisk]
Description=MySQL connection to 'asterisk' database
driver=MySQL
server=localhost
database=asterisk
Port=3306
Socket=/var/lib/mysql/mysql.sock
Напишем SQL запросы для извлечения нужной статистики
Теперь перейдем к SQL запросу. Вот кусок данных из базы, чтобы понимать какие события происходят при поступлении звонка в очередь:Нас интересуют 2 события: когда клиенту ответил оператор и когда клиент не дождавшись ответа положил трубку. События называются CONNECT и ABANDON соответственно. В поле data1 события CONNECT и в поле data3 события ABANDON как раз указывается время ожидания клиента в секундах до этого события. В итоге мы получим время нахождения клиента в очереди вне зависимости от того, ответили ему или он положил трубку не дождавшись ответа. Более подробно про события в очереди можно прочитать здесь.
Нам нужно выбрать все значения ожидания в данных событиях, отсортировать их по убыванию и ограничить вывод 4 записями. Там мы получим 4 наибольших значения. Далее мы зададим условия для отображения записей длиннее чем 240 (360 во втором запросе) секунд и подсчитаем количество этих записей. Если записей получится меньше чем 4, значит условие не выполнено.
nano /etc/asterisk/scripts/query1.sql
SELECT COUNT(T.waitdata) FROM
(SELECT (CASE WHEN event = 'CONNECT' THEN data1 ELSE data3 END) AS waitdata FROM queue_log WHERE ( (event = 'CONNECT') OR (event = 'ABANDON'))
AND `time` >= date_sub(now(), INTERVAL 1 HOUR)
AND (CASE WHEN event = 'CONNECT' THEN data1 ELSE data3 END) >= 240
ORDER BY waitdata+0 DESC LIMIT 4
) AS T
nano /etc/asterisk/scripts/query2.sql
SELECT COUNT(T.waitdata) FROM
(SELECT (CASE WHEN event = 'CONNECT' THEN data1 ELSE data3 END) AS waitdata FROM queue_log WHERE ( (event = 'CONNECT') OR (event = 'ABANDON'))
AND `time` >= date_sub(now(), INTERVAL 1 HOUR)
AND (CASE WHEN event = 'CONNECT' THEN data1 ELSE data3 END) >= 360
ORDER BY waitdata+0 DESC LIMIT 4
) AS T
Напишем скрипт
Написать скрипт можно было на php/perl/python, что удобнее. Либо вообще не использовать внешний скрипт: mysql запросы и условия прописать в диалплане напрямую. Но я решил использовать bash, что более "лампово" и универсально:touch /etc/asterisk/scripts/queue.sh
chmod +x /etc/asterisk/scripts/queue.sh
nano /etc/asterisk/scripts/queue.sh
#!/bin/bash
user=root
password=pass
status="$(cat /etc/asterisk/scripts/musichold.txt)"
# Делаем запрос времени ожидания клиента в очереди за последний час. Выводим только 4 наибольших значения, при условии, что время ожидания составило более 4 минут (240 с), и считаем количество полученных строк.
query1="/etc/asterisk/scripts/query1.sql"
# То же самое, но время ожидания более 6 минут (360 с)
query2="/etc/asterisk/scripts/query2.sql"
# Пишем в переменные результаты запроса, ключ -N для того, чтобы не отображать название столбца
waittime1=$(mysql -u$user -p$password asterisk -N < $query1)
waittime2=$(mysql -u$user -p$password asterisk -N < $query2)
# Включаем второй набор музыки если был включен первый набор и 4 клиента ожидало более 4 минут
if [[ "$status" = 3852-soft && "$waittime1" = 4 ]]
then
# Пишем в файл имя секции Musiconhold удаляя символ переноса строки в конце (иначе астериск при чтении переведет строку)
echo -n "3852-hard" > /etc/asterisk/scripts/musichold.txt
# Включаем первый набор музыки, если менее 4 клиентов ожидало более 6 минут и включен второй набор
elif [[ "$status" = 3852-hard && "$waittime2" < 4 ]]
then
echo -n "3852-soft" > /etc/asterisk/scripts/musichold.txt
# В остальных случаях ничего не делаем
else
echo Очередь не изменилась: $status
exit 0
fi
exit
Создадим файл для сохранения имения класса музыки:touch /etc/asterisk/scripts/musichold.txt
Добавим скрипт в крон, чтобы запускался каждый час:nano /etc/crontab
# запускаем скрипт проверки времени ожидания клиентов и выбора режима очереди раз в час
0 * * * * root /etc/asterisk/scripts/queue.sh
Зададим класс фоновой музыки
Теперь добавим новый класс для фоновой музыки. В итоге у нас их будет два: 3852-soft и 3852-hard. Как-то так:nano /etc/asterisk/musiconhold.conf
[3852-soft]
mode=files
directory=/usr/share/asterisk/sounds/ru/3852-soft
sort=alpha ; Sort the files in alphabetical order
[3852-hard]
mode=files
directory=/usr/share/asterisk/sounds/ru/3852-hard
sort=alpha ; Sort the files in alphabetical order
В папки /usr/share/asterisk/sounds/ru/3852-soft и /usr/share/asterisk/sounds/ru/3852-hard мы положим подготовленные файлы. Проигрываться они будут в алфавитном порядке.Далее в настройках астериска находим контекст из которого клиент попадает в очередь. Добавляем у него экстеншн задающий класс фоновой музыки, имя которого мы возьмем из файла /etc/asterisk/scripts/musichold.txt.
nano /etc/asterisk/extensions.conf
...
; задаем класс для музыки в очереди переменной из файла
;это работает только в старых версиях, например 1.8. В 13 версии нет readfile, вместо него мы будем использоваться FILE
;same => n,ReadFile(QUEUENAME=/etc/asterisk/scripts/queue.txt,9);
same => n,Set(QUEUENAME=${FILE(/etc/asterisk/scripts/musichold.txt)})
same => n,Set(CHANNEL(musicclass)=${QUEUENAME})
same => n,Queue(3852,TtxX,,,1800,,logagentnumber); тут ваша очередь (у меня это 3852, на 30 минут с запуском макроса logagentnumber)
...
Комментариев нет:
Отправить комментарий