📜 ⬆️ ⬇️

Making a New Year's Call Center

The new 2015 is approaching and, having a little thought, we decided to entertain people and at the same time realize the idea of ​​a New Year call center with blackjack Santa Clauses and Snow Maidens answering calls wishing to chat in the pre-New Year time. Anyone can become an operator of this call center by selecting the gender of the operator, just as anyone can call this call center directly from the browser (you need a microphone) or simply by dialing a phone number. The operator's seat of Santa Claus / Snow Maiden will work directly in the browser (hello WebRTC) and there is no way to do without a microphone. It may take a lot of time to implement such a service if everything is done from scratch, but we will use the VoxImplant platform, which will greatly facilitate and speed up the whole process. In total, you need to make a web service for registering those who want to become operators, as well as 2 web applications - a dialer and carrier space + write a couple of scripts in javascript. We hope that there are enough willing to act as operators of our call center, and the callers will have to wait a long time for a conversation in the queue. To make it more interesting, we will organize the rating of the most talkative operators and give them VoxImplant gift certificates so that they can then realize their own service with blackjack ... well, in general, you understand. The most interesting, as usual, under the cut!

Result


For those who can not wait to try the service immediately give the link http://demos.zingaya.com/newyear/ , I think that the interface does not require special comments. We choose our side and call / receive calls.
We register an operator account, log in and set the status “Ready to receive calls”

As soon as any of the incoming calls is distributed to the operator, the melody will play and a pop-up window will appear where you can answer the call.


Create application


Let us log in to the VoxImplant control panel ( https://manage.voximplant.com ) and create a newyear application in the Applications section, this is just a virtual entity to which we will hook users-operators, and also describe the call processing rules (which script should process which calls).
')

Creating a VoxEngine script


Now you need to write a script that will handle incoming calls and distribute them to operators. Scripts for VoxImplant are written in JS. Ours will look like this:
//   ACD ( )  ASR ( ) require(Modules.ACD); require(Modules.ASR); var request, originalCall, callerid, statusInterval, asrTimeout, asr, queueName = 'MainQueue'; //     VoxEngine.addEventListener(AppEvents.CallAlerting, handleInboundCall); // -   function handleInboundCall(e) { originalCall = e.call; //     callerid = e.callerid; //  caller id //   originalCall.addEventListener(CallEvents.Connected, handleCallConnected); originalCall.addEventListener(CallEvents.Failed, cleanup); originalCall.addEventListener(CallEvents.Disconnected, cleanup); //     originalCall.answer(); } //      function cleanup(e) { if (request) { //      -  request.cancel(); request = null; } //   VoxEngine.terminate(); } //       TTS function handlePlaybackFinished(e) { e.call.startPlayback("http://cdn.voximplant.com/newyear.mp3"); } //        TTS function getNumEnding(iNumber, aEndings) { var sEnding, i; iNumber = iNumber % 100; if (iNumber >= 11 && iNumber <= 19) { sEnding = aEndings[2]; } else { i = iNumber % 10; switch (i) { case (1): sEnding = aEndings[0]; break; case (2): case (3): case (4): sEnding = aEndings[1]; break; default: sEnding = aEndings[2]; } } return sEnding; } //   function handleCallConnected(e) { //   e.call.say(" -  !!! " + "        ?", Language.RU_RUSSIAN_FEMALE); e.call.addEventListener(CallEvents.PlaybackFinished, handleIntroPlayed); } //    function handleIntroPlayed(e) { e.call.removeEventListener(CallEvents.PlaybackFinished, handleIntroPlayed); //         asr = VoxEngine.createASR(ASRLanguage.RUSSIAN_RU, [" ", "", "", "  ", " ", " " ]); //     asr.addEventListener(ASREvents.CaptureStarted, function (e) { clearTimeout(asrTimeout); }); //   asr.addEventListener(ASREvents.Result, function (e) { //   asr.stop(); //   ,      SnegurQueue if ((e.text == ' ' || e.text == '' || e.text == '') && e.confidence >= 50) { originalCall.say("!       .", Language.RU_RUSSIAN_FEMALE); queueName = 'SnegurQueue'; originalCall.addEventListener(CallEvents.PlaybackFinished, addToQueue); } else if ((e.text == '  ' || e.text == ' ' || e.text == ' ') && e.confidence >= 50) { //    ,   - MorozQueue originalCall.say("!        .", Language.RU_RUSSIAN_FEMALE); queueName = 'MorozQueue'; originalCall.addEventListener(CallEvents.PlaybackFinished, addToQueue); } else { //    ( < 50%),      - MainQueue originalCall.say("         .", Language.RU_RUSSIAN_FEMALE); originalCall.addEventListener(CallEvents.PlaybackFinished, addToQueue); } }); //     ASR originalCall.sendMediaTo(asr); //    3       ,      asrTimeout = setTimeout(function () { asr.stop(); originalCall.say("         .", Language.RU_RUSSIAN_FEMALE); originalCall.addEventListener(CallEvents.PlaybackFinished, addToQueue); }, 3000); } //         queueName function addToQueue(e) { Logger.write('Adding call to queue: '+queueName); originalCall.removeEventListener(CallEvents.PlaybackFinished, addToQueue); //   TTS    originalCall.addEventListener(CallEvents.PlaybackFinished, handlePlaybackFinished); //    request = VoxEngine.enqueueACDRequest(queueName, callerid); //      request.addEventListener(ACDEvents.Queued, function (acdevent) { request.getStatus(); }); //       request.addEventListener(ACDEvents.Waiting, function (acdevent) { var minutesLeft = acdevent.ewt + 1, txt = '      '; if (queueName == 'SnegurQueue') txt = "   "; else if (queueName == 'MorozQueue') txt = "    "; originalCall.say("     " + acdevent.position + ". " + txt + " " + (acdevent.ewt + 1) + getNumEnding(minutesLeft, ['', '', '']), Language.RU_RUSSIAN_FEMALE); }); //   -     request.addEventListener(ACDEvents.OperatorReached, function (acdevent) { VoxEngine.sendMediaBetween(acdevent.operatorCall, originalCall); acdevent.operatorCall.sendMessage(JSON.stringify({ number: originalCall.callerid() })); acdevent.operatorCall.addEventListener(CallEvents.Disconnected, VoxEngine.terminate); clearInterval(statusInterval); }); //    request.addEventListener(ACDEvents.Offline, function (acdevent) { clearInterval(statusInterval); //         ,       if (queueName == 'SnegurQueue') { originalCall.say(" ,       .    !", Language.RU_RUSSIAN_FEMALE); queueName = 'MainQueue'; originalCall.addEventListener(CallEvents.PlaybackFinished, addToQueue); } else if (queueName == 'MorozQueue') { originalCall.say(" ,        .   !", Language.RU_RUSSIAN_FEMALE); queueName = 'MainQueue'; originalCall.addEventListener(CallEvents.PlaybackFinished, addToQueue); } else { //        ,        originalCall.say(" ,          .    " + "      -!   !", Language.RU_RUSSIAN_FEMALE); originalCall.addEventListener(CallEvents.PlaybackFinished, VoxEngine.Terminate); } }); //        30  statusInterval = setInterval(request.getStatus, 30000); } 


Creating processing rules


Incoming calls from the number and from the web sdk should be sent to be processed by our script. In the web application for outgoing calls, we stitched the newyearcall number, and in the section with phone numbers we connected the number 74951330204 to our application. Create 2 rules:


Queuing


In the context of this project, we will need to create 3 different queues (Settings -> Queues) - MainQueue (all), MorozQueue (Santa Clauses only) and SnegurQueue (Snow Maiden only). The caller is asked to choose with whom he wants to talk - with the Snow Maiden or Santa Claus, the choice is made using the voice recognition system, which is available in VoxImplant, from the previously described dictionary. If within 3 seconds the choice was not voiced or the system is not sure of the recognized option (probability <50%), then the call is sent to the general queue that I serve both grandfathers frosts and snow maidens. If the choice was made successfully, then we send it to a specific queue. If this queue is not served by any operator, then we redefine the call to the common queue, and if there is no one there, we lose the message and offer to become an operator.
In addition to creating queues, you also need to create appropriate skill groups, since the binding of application users (operators) to queues is done precisely through skills (Settings -> Skills). We create 3 skills : NewYearSkillAll , NewYearSkillMoroz and NewYearSkillSnegur , respectively, we set a turn for each skill - MainQueue, MorozQueue and SnegurQueue. When creating user-operators, we will cling them immediately to 2 skill groups - NewYearSkillAll + NewYearSkillMoroz (Santa Claus) or NewYearSkillSnegur (Snow Maiden).


Camera place


An operator site, like a web dialer, is made using the VoxImplant Web SDK . The important points are the implementation of the operator status switch using the setOperatorACDStatus function.

 vox.setOperatorACDStatus(VoxImplant.OperatorACDStatuses.Ready); //  vox -  VoxImplant.Client 

Calls will be distributed to the operator only when he is in the Ready state. Being in the remaining states is reflected in the statistics on the work of the operator.

In general, this is enough, the remaining bolts (remote creation of users of the application, etc.) are already done on the basis of the HTTP API VoxImplant .

Once again link to the result http://demos.zingaya.com/newyear/ or you can simply dial +74951330204

PS completed the top operators


So, the winners of our competition are the operators with logins:
frizalzal
iboldurev
pizdag
zoor4117
ThereIsNoSanta
Fiesta
DedMorozZzZ
Sheriff
BenterShot
joloweb6
Guys, write in a personal to receive prizes.

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


All Articles