I am working on building a call center using Twilio.
Parts of problems are tackled in questions and some answers are old. Given that what I am trying to do is one of the most common usecases, I am trying to use this question to build a tutorial so that people know what is the state of the art way to build this.
Usecase detail is below:
Call Tree:
Customers will call the Twilio number through phone.
Based on phone no identification high priority customers will be sent to Agent handling flow
Other customers have a call tree which they have to navigate, which will support them. Some customers might end up on Agent handling flow.
Call Center: Agent handling flow is as follows:
Agents are handling calls using their desktop computers. They are on the support page which has a Twilio phone call widget as a pop up window.
All agents can handle all calls.
There are two types of queues. High priority and Normal.
All available agents ring at the same time. Anyone can pick and then other agents are moved to the next caller if available.
If not agent available wait for some time, including giving an IVR option for voicemail.
After wait timeout send to IVR.
Following is based on my understanding. Please let me know if there is a better way.
Call Tree will work as per the following tutorial: https://www.twilio.com/docs/tutorials/walkthrough/ivr-phone-tree/node/express
Call Center Agent handling flow will work as follows:
Once workspace
n Workers
2 Task Queues - High priority and Normal
One Workflow which decides based on the task priority which queue to assign to.
My current queries are as follows:
What is the cleaned way of implementing wait for an agent for 1 minute and if agent is not available in 1 minute send to voicemail. Is this part of workflow?
What is the best way implement call receiving in browser. Webrtc?
Is there an HTML widget available for the implementing call receiving in the browser. This would include features like setting agent online/offline, receive call, end call, escalate to supervisor
Help with this will be really appreciated and will help avoid wild goose chases.
Andy , you should look at Twilio taskrouter .
1 You can use task reservation timeout to achieve your requirement 1 . Create a task for an incoming call , taskrouter can direct the call to the matching agent and if the reservatoin timeout is set to 1 minute , the task can be redirected to either a different agent or an IVR as you require
2 You can use Twilio Client , Twilio's WebRTC . You can set incoming/outgoing capabilities as required and can easily integrate with Taskrouter to handle incoming/outgoing calls.
[3] You can build a dialler easily to implement Twilio Client , here's a tutorial to help you progress : https://www.twilio.com/docs/quickstart/client/javascript . You can find a starter up implemented in C#,Java,nodejs,php,python and ruby.
Additionally, you will find this call centre blueprint useful :) https://github.com/nash-md/twilio-contact-center .
Related
In our Twilio application we would like to use TaskRouter to distribute incoming calls. Suppose we would like to handle the following scenario:
All Workers login to front-end application and have their status set to Available. If there are any incoming calls, Workers receive them in the UI.
Some Workers have this custom attribute: {"work_hours": [600, 1600], "phone_numbers": ["+1...", "+1..."]}. If for some reason this Worker becomes Unavailable during their working hours set between "work_hours" attribute, we would still like to have incoming calls forwarded to their personal phones from "phone_numbers" attribute.
If the above fails, we would like to forward the incoming call to Voicemail.
Basically, my question is whether it is possible to include Unavailable workers to Workflows and Task Queues? The above scenario would most likely require 3 Task Queues: one for all Available Workers, one for Unavailable but with "work_hours" attributes where taskrouter.currentTime is between those hours and one for Voicemail.
Twilio Solutions Architect here!
I think that you may already found a solution for your problem, but in case someone else is having this problem, here's my solution:
The best way to do this is actually creating a new Activity on TaskRouter of type Unavailable with Work Hours that is is an available Activity. With that state created, you can set the worker availability to this state when they are on this use case, and with the Task Router Workflows, you can have specific queues for these agents and using the routing strategies, bring a task to this queue if necessary.
Regarding to call the agents on their personal phone numbers, you can create a conference between the original call and the agent's phone number and have them connected.
This is a bit tricky, but is completely possible.
The goal is to receive messages over MQTT in an IoT device that comes out of deep sleep periodically. The exact same considerations exist for OTA update as for any other parameter update. In my case, ultimately, I want to use this for both.
Progress
It runs
The device wakes for about 15 seconds. If during that time, I publish a bunch of messages to the relevant topic, the message arrived successfully. Inside the AWS console I can publish to :
$aws/things/<device-name>/shadow/update/delta
{
"state":{
"desired":{
"output":true
}
}
}
And the delta callback function runs for 'output'. Great but no practical use to anyone.
IoT Job
I created a custom AWS IoT job in the console in an effort to overcome the problem. My thinking was that it might retain the message to ensure delivery. I've been running the job for the past half hour but so far nothing has come through. It had a 20 timeout but is still stuck in queued, not even in progress yet... So, there is clearly a flaw in this approach.
AWS CLI test
Just for completeness, I've attempted to fire off the MQTT message from the console. It has the benefit that you can specify the QOS, (in theory) ensuring that it gets delivered at least once.
aws iot-data publish --topic "$aws/things/<device-name>/shadow/update/delta" --qos 1 --payload file://Downloads/outputTrue.json --cli-binary-format raw-in-base64-out
But oddly this didn't seem to work at all. I didn't see the message arrive at the broker at all: subscribing in the console test.
AWS IoT Core does not support retained messages, see here.
The MQTT specification provides a provision for the publisher to request that the broker retain the last message sent to a topic and send it to all future topic subscribers. AWS IoT doesn't support retained messages. If a request is made to retain messages, the connection is disconnected.
As the wake-up times are perriodically, a possible approach could be to publish the next wake-up slot of your device in a separate topic where your backend is listening to. Your backend will then publish the desired information to your device-topic once the slot opens up.
Of course this approach is quite fragile concerning latency and network stability.
Time to share the answer I found from piecing together numerous posts and reaching out to the very helpful AWS support team. This link is the one that really covers it:
https://docs.aws.amazon.com/iot/latest/developerguide/jobs-devices.html#jobs-workflow-device-online
My summarised pseudo code is :
1. init() & connect() to mqtt as before.
2. Subscribe to the following topics & create callback function for each:
a. Get pending.
b. Notify next.
c. Get next.
d. Update rejected.
e. Update accepted.
3. Create Publish topics:
a. Get pending.
b. Get Next.
4. Pending topics = optional. But necessary to handle many tasks and select between them.
5. Aws-iot-jobs-describe() to publish a request for the next job. It links up to the notify next callback (somehow).
6. In the callback, grab job document, execute job & report Success / Failure.
7. Done.
There is a helpful example in esp-aws-iot/samples/linux/jobs-samples/jobs_sample.c. You need to copy some of the constants over from the sample aws_iot_config.h.
Once you've done all of this, you are able to use AWS Jobs to manage your OTA roll out, which was the original intent.
I'd like to have a support queue and a sales queue that call an available agent when there's someone in the queue. The way queue functionality is described in the Twilio docs, it seems that the only way to connect an agent and a caller is to have the agent call into the queue. Well, that's no good for a queue that would be empty for most of the time -- how would they know when to dial in?
Is there a way for an agent to be called and then connected to the queue when someone is waiting?
Twilio developer evangelist here.
This is the exact use case for the Twilio TaskRouter API. From the docs:
Twilio TaskRouter is a system for distributing tasks such as phone calls, leads, support tickets, and other work items to the people and processes that can best handle them. Example applications for TaskRouter include:
Distributing calls to call center agents. TaskRouter supports common features required in call center environments, such as skills-based routing and task prioritization.
Prioritizing and assigning CRM cases to agents in order to make sure they're handled within service level. TaskRouter lets you specify overflow rules for tasks, allowing you to vary assignment rules based on time spent in queue and case content.
Distributing leads to inside sales teams. TaskRouter's business rules allow you to control prioritization so that your team is always working on the most important opportunity.
Check out the quickstart guide for TaskRouter which takes you through creating a workspace and workers and creating tasks for the workers from phone calls.
I've been looking at an SOA using a messaging broker (rabbitmq / rails), however there are still a few niggles I cant get my head around.
If I wanted to run parallel requests as you would using something like Typhoeus with http
a) how in an asynchronous system like this - when you have potentially multiple threads publishing to the same topic exchange do you connect the response message with your request - would you add a unique routing key?
c) what would be the best way initiating and managing multiple parallel calls of this nature in ruby?
Many thanks
In answer to a), yes you use a routing key, or in the parlance of messaging, a correlation identifier.
In answer to c), sorry I haven't a clue about Ruby, but messaging by nature supports parallelism by using queues to manage throughput. I assume that whatever broker you choose would provide the appropriate samples and tooling for your needs.
I would use at sidekiq or rescue for jobs like that. If your system is larger and distributed you can create a module/class which takes your job including key as argument, sends it to rabbitmq, some worker which is subscribed to fan out or channel picks it up and sends the result back as POST to your app (web hook approach).
For simplicity you can also just put some sort of Ajax spinner on your view and poll every 10 seconds or whatever suits you if the result is back. For sure you should have some kind of id for every job. If you have questions about it I could elaborate more. My apps crunch a lot if data in long running tasks with up to 500,000,000 items in rabbit queues.
Working on a long running workflow, hosted with WorkflowserviceHost, Win Server 2008 R2.
Recently discovered that appFabric is of great help for things like management of workflow instances resumption, idle instances, faileds ones etc.
Got a basic sequence activity : It sends a mail asking for an approval then follows a 'Receive and send' to receive the response. This last activity allows automatic persistence in persistence store. (Which is a great feature !). (This sequence also uses content correlation based on workflow instance Guid.)
Now i'm sort of stuck, because I need to restart sequence (send e-mail) after a few days delay, if approver didn't send the message to the 'receive and send' activity.
My question is : How to implement the delay timer ? Using a pick branch next to the 'receive and send' with a 'while' control-flow in the flowchart ? (Or a parallel activity ? )
Is there something to configure in AppFabric ? Will I find this information going further on AppFabric documentation (r. jacobs videos) ? Have you got a neat example somewhere ?
The basic approach is to use a Pick activity with a branch containing a Delay as a timeout trigger. If the appropriate message is received in the Receieve all is fine. If not the Delay fires, does its work and cycles back to the top of the Pick.