📜 ⬆️ ⬇️

Automatic Customer Calling System

How to make automatic dialing has already been written a lot, including on this site. Flexibility asterisk'a has no boundaries. Written a huge number of articles on the implementation of the simplest actions with built-in tools, or using third-party products and solutions. Therefore, in my opinion, the most interesting solution would be not a standard task, for which it was necessary to completely develop and implement a system from scratch, given compatibility with the current call center scheme.

Prehistory


At the moment, more than a year has passed since its introduction. About 90-95% of the total program code of the system has been rewritten and I clearly understand how the system is developing and how it should be developed. But at that moment when the task was set before me, I had a vague idea of ​​how the code should look like judging by the TK, and there wasn’t any experience in dealing with asterisk. I’ll say right away that the main idea is not mine, my task was to implement or even rather portray what was painted in the context of the task. But at the same time, the most important thing was that I was virtually unlimited in choosing technologies and solutions - which in my opinion allowed me to bring the whole scheme to the form I wanted.

At that time, the company already had a working call center. About 10 queues, from 4 to 20 operators in each queue and about 12-15 thousand calls around the clock. 5 providers for local, long-distance and international calls. For a long time, the call center was overgrown with a large number of different functional and own developments. The main software platform is an asterisk server, a database with call statistics and business logic on MySQL , as well as an AGI script binding.

Task


From time to time there is a need to ring up clients for various types of questions. This may be needed periodically, for example, once a month (debt, notifications for promotions or advertising), as well as occasionally (unsolved problems, technical issues). To date, several people are selected from the line-up who ring up such clients and form a report on their work, which is then transmitted to each other. If there is a large queue of calls - the operators return to incoming calls and they help to eliminate the load, then come back again. As a result, there are many problems as a human factor, a person can make a mistake in the room, forget one of the clients, or in the administration department - you need to monitor the queue and transfer agents from telephone calls to incoming calls and back.
Therefore, you need a machine that will ring up the right customers, while taking into account the load in the queue, so that for simple questions, you can call around only with a minimum load, and for more complex and important - even over incoming calls. The machine should directly connect the operator and the client, so that the client immediately began a conversation with a live person, without going through the IVR or waiting in the queue. The operator of which was chosen for the call - must remain in the queue and after the end of the conversation without any action could take a normal incoming call or another call. After connecting with the operator, you need a timeout in order for the operator to grasp the essence of the call - to understand why he is calling the client, and after the call is completed, regardless of the result, the timeout is for commenting out the task. The planned load of 2000 calls per month and then in the future up to 10 000 - 15 000.
')

Implementation plan


Judging by the description of the conditions of the problem we form the technical model:

Life time


Planning

Now, after the passage of time, it is difficult to recall the chronology of execution, but the first thing I immediately decided was that all planning should be in billing. Tasks will be formed on the basis of an existing client and its attributes: phone numbers tied to it, balance, equipment tied to it, business statistics, and so on. Initially, it was clear what wide prospects such automation provides for communication with the client. We can request all - who connected to any service - does not use it. When a new firmware is released, call the customers to suggest upgrades if there is no auto provisioning . Warn customers about planned work, or push forward to additional company services. But such a task from the technical side of telephony just looks like a phone number and the reason for which we are calling.
We can call for a banal problem, but we may need a more urgent connection with the client - for example, during a call, the call was interrupted. We need to contact the client as soon as possible and solve his question. Therefore, we need such a parameter as a priority. You can call him at any time and first of all.
Each task has its own solution. If we have a question of the administrative plan, we solve it through the subscriber department. The technical issue is solved through technical support. Accordingly, when creating a task, you need to choose which service will receive the task.

As a result, a billing view was made through the internal logic of the billing, from which you can get a task in the form of: task id, phone number, priority and queue for which the created task. For my part, a demon was written that constantly monitors the queue loading - takes the current number of calls waiting for an answer to the maximum allowed in percent, as well as the number of free operators. For example, for tasks with low priority, 0% queue loading and at least 1 free agent are required. If the priority is higher then the load is not more than 70%. For higher priority loading is not equal to 100%. Under favorable conditions, the demon receiving the task, changes its status to "executed" and throws the call into the queue. The task number is recorded in the local cache of the daemon, by which the task is monitored in the dictionary table in our database of the form: task id -> dialstatus . If the status has appeared, then we change the status of the task in the billing system and delete the task from the dictionary and local cache. Accordingly, when the daemon starts, all tasks with the status “run” are collected from the billing to monitor their status.

Work with the operator

Developing the scheme of work with the operator - I highlighted the main characteristics:

When I began to look for a solution, I immediately realized that the current statistics did not correctly see and call off the call to the operator as successful, besides, it was not clear how to pull the operator to receive such special calls, therefore attempts were made to make crutches such as dialing to the operator and parrying it with the shoulder of the client, as well as various frauds with queue slots. The collected schemes were working, but extremely unstable and time consuming when collecting statistics. As a result, I refused to try to adapt to the current scheme and decided to write an independent part of the logic for handling incoming calls of a new type. The mechanism for working with the operator was selected. Many people oppose the call file, the technology is certainly cool, and for some kind of tasks it has the right to exist, but it wouldn’t work for my task: to connect with the operator, an instant response is required, whether or not the operator can accept the call, in the case of a file, you need to monitor the file itself that from my point of view is not convenient and not rational. I just fulfill the ami request, wait about 5 seconds, if the operator picked up the phone, then the call goes to the next stage, if not, then return the call to the queue and look for the next operator. Also, files are characterized by local work on an asterisk, for which it is formed. That is, we will need a local script on each server, which will locally generate the file, simultaneously finding out who of the server's colleagues is the least loaded now. Complete decentralization of management. In my case, I simply request the load on all servers and selecting the least loaded one sends him an ami request. For the work was used library Asterisk :: AMI .
After the operator answers the call, in the formed call through local variables, the “exten” is selected for the call, where the timeout through “Wait” before the “Dial” is set . The main problem was that if the operator deliberates at the time of the timeout or the call and hangs up - then the call disappears. Therefore, when a dialstatus “Cancel” is received , the call is considered not processed and returns to the queue. We deactivate the operator from the queue. Next on dialplan, there is a Dial with an additional parameter “g” to continue execution after the end of the conversation. Upon completion of the timeout after the conversation through the “hangup” extension, an entry is added to the dictionary - job ID and dialstatus, insert by request. Thus, having a working machine and a client sip on it, enabling the “auto answer” function — the operator only comments on the tasks in the interface, all call processing takes place behind it. Maybe someone will say that this is a bad idea, but this was done for several reasons. If we want our customers to try guaranteed to get a phone call for 30 seconds, then we simply set a timeout for the dial command, and not wait for any action from the operator. Again, we get a scheme in which monotonous work for people is reduced. It so happened that at the very beginning I worked in the same company as a technical support operator and I do not know by hearsay how tedious the monotonous actions are, by the customers themselves.

Balancing and reservation

If you search the Internet for information on how to reserve outgoing calls when one of the providers is unavailable - most often you will find a recommendation of the type to make several Dials in diaplan one after the other. For my part, I wanted to do something more flexible and dynamic. The main problem was that we used a lot of different glands and before forming a call there is no time to bypass them in search of the least loaded and accessible trunk. The main idea was to work with aggregated information. To do this, a separate daemon was written, whose tasks were as follows: collect load from TDM, TDM difference between free slots, accessibility through sip peers from voip providers, and choose asterisks based on current channels from asterisks. But besides the choice of direction, it is necessary to take into account that any of the trunks can fall, so you need to choose an alternative. In my case, these were voip providers, but they also have their own rates, so balancing should choose from the cheapest to the most expensive ones (they are absolutely equivalent in quality). For such a sample, I made my own weight or value for each provider. Thus, we have a list of keys and values ​​of this type:


So if one of the providers is not available - we are looking for a replacement from lower to higher, or more expensive.

But in addition to this, there is also a distribution depending on the number of the room. That is, for example, you should call Moscow numbers through your local provider, to Siberia or other countries through yours, if you have one, or through a long-distance and international route. Here there is a need to determine to which region the number belongs. For this, I wrote a registry parser to connect to the database. Looks like:

mysql> select local.get_region(903599****); +-------------------------------------+ | voicecon_new.get_region(903599****) | +-------------------------------------+ | Moskva i Moskovskaya oblast | +-------------------------------------+ 


The general scheme of work and various nuances



  1. We request all asterisk servers that are in balance.
  2. Calling parameters are requested for the current queue. This is the waiting time for a response from the operator and the client, the “source” number that the client sees when an incoming call is received - for each service it is different.
  3. According to the client number, we choose the direction through the table with the register of numbers.
  4. Select the uplink for the call. If you set 0 - uplink will not participate in the selection, respectively, you can balance by shifting the priority to providers. The selected trunk is checked for availability and then for download. If conditions are not met, uplink is skipped and we move on to the next in weight.
  5. Next, we select the asterisk server with the least number of channels. Since in Redis we have all the channels from all servers, we just get the total through the built-in function hlen . Choosing a server, we are trying to connect to it - if the server did not respond, we take the next one, again with the lowest load.
  6. Lastly, for the variable parameter, an array of service variables is formed, on the basis of which both the call accounting and the direction selection are performed. Also, there is used the binding of the current call of the operator to the task for which calls are made.


Conclusion


Despite the stated load, the figure has now reached about 30,785 calls in the last month. Initially, the scheme planned only for a narrow circle of tasks has expanded to a service capable of solving a wide range of tasks and will cope with a large load. At the moment, work on it has not stopped - I constantly add something and expand the functionality, and also plan to conduct another refactoring.

Source: https://habr.com/ru/post/172227/


All Articles