Spice Telephony User Guide

From SpiceCSM

Revision as of 02:11, 10 December 2009 by Micahw (Talk | contribs)
(diff) ←Older revision | Current revision (diff) | Newer revision→ (diff)
Jump to: navigation, search

If you are looking for the agent interface guide, try Spice Telephony Agent Guide

There are two ways to configure Spice Telephony, using the erl shell and using the web interface. For most tasks, it is recommended to use the web interface.

By default the web interface will run on port 9999 on the first node that Spice Telephony was started on. The default username/password is administrator/Password123.

The erl shell is always available.

Contents

Agents Tab

Managing agents is split into 4 sections: Agent Modules, Release Codes, Agent Profiles, and Agents.

Agent Modules

Agent Modules

Of the three modules available for agents, the only one that is fully implemented is the Agent Web Server. The configuration for these modules may move in a future release. The settings for these are unique to each node; you will need to enable the agent web server on each node it should run on.

Agent TCP Server

Currently unsupported, the module to create a fat client is available for experimentation.

Agent Web Server

Shown to the right with default port, this is the recommended way to enable an agent client. This will enable the built in web server on the specified port for the agent interface. It is enabled by default.

Via erl shell:

1> cpx_supervisor:add_conf(agent_web_listener, agent_web_listener,start_link, [5050],agent_connection_sup).

Integration with SpiceCSM

This option may be removed in a future release as it requires a specially patched version of SpiceCSM.

Release Codes

Example release codes

Release codes are what an agent will see in their interface for options when they try to go released. Common options are Restroom or smoke. The bias can be used for tracking information. the Supervisor view gives no benefit to 0 bias, a penalty to -1 bias, and bonus to +1 bias when calculating "agent health."

When a change is made, agents will not see it until they reload their interface.

Release codes are common across all nodes.

There is always a default release option that has a bias of -1. It cannot be changed.

Adding Release Codes

Click the "+" at the top, fill out the form, and click "Submit".

1>> rr("include/agent.hrl").
2>> agent_auth:new_release(#release_opt{id = "newid", label = "agent_sees", bias = 0}).

Editing Release Codes

Double click the field you wish to change. When done, hit the enter key.

1>> rr("include/agent.hrl").
2>> agent_auth:update_release("label", #release_opt{id = "newid", label = "new_label", bias = -1}).


Dropping Release Codes

Click on the release code you wish to delete, then click the "-" button at the top.

1>> rr("include/agent.hrl").
2>> agent_auth:destroy_release("label").

Agent Profiles

Form for editing and creating agent profiles

Beneath the Release Codes, agents are grouped into their profiles. An agent can only be a member of one profile. A profile is a list of skills that will be applied to any member agents in addition to any skills they already have.

List profiles from shell:

1> agent_auth:get_profiles().

Adding a Profile

Click the "+Profile" button, and fill out the new form on the left. When done, hit the "Submit" button.

1> agent_auth:new_profile("Name", [skill1, skill2]).

Editing a Profile

Click the profile name, and fill out the form on the left. When done, hit the "Submit" button.

1> agent_auth:set_profile("Oldname", "NewName", [skill1, skill2]).

Dropping a profile

To remove a profile, select it, and click the '-' button below the list. Any member agents of that profile will be moved the "Default" profile.

1> agnet_auth:destroy_profile("Name").

Agents

Editing or Creating a new agent

Agents not only define who can take calls, but are also used for supervisor and admin logins.

To see the agents of a particular profile, expand that profile's list.

Login 
The username of the Agent.
Last Integrated 
The date the user was last updated if agent authentication integration is enabled. If there is no integration, this will display "undefined".
Password 
Leave this and "Confirm Password" blank to leave the agent's password untouched. Required when adding an agent.
Profile 
The profile this agent is a member of.
Security Level 
agent is the default security level, able to login to the agent interface
supervisor have an extended agent interface and the rights of 'Agent'.
admin can log into the Web Management interface and have the rights of 'Supervisor'.
Skills 
Like the list when editing Profiles. These skills are individual to the agent.

Adding an Agent

Click the "+" button at the bottom, fill out the form on the right, and click "Submit".

1> agent_auth:add_agent("Username", "Password", [skill1, skill2], SecurityLevel, "Profile").

Editing an Agent

To edit an agent, click on their login name from the list. If the agent has ever be cached from authentication integration, the time of that will be displayed below the login name, other wise it will be "undefined".

leaving Password and Confirm Password blank will leave the password unchanged.

1> agent_auth:set_agent("OldUsername", "NewUsername", [skill1, skill2], SecurityLevel, "Profile").
1> agent_auth:set_agent("OldUsername", "NewUsername", "NewPassword", [skill1, skill2], SecurityLevel, "Profile").

Dropping an Agent

click on the agent's name, then click the "-" button at the bottom.

1> agent_auth:destroy("Username").

Skill Management

Editing a Skilll

Skills, as the name implies, refer to the competences that agents may have, like speaking a certain language or being trained on some advanced topic, product or application, etc.

Spice telephony uses skills to determine whether an agent or group of agents can be offered a call or not. So, a call may require a specific set of skills. That set will be compared against the agent skills and the skills included in the agents's Profile. If they match, voilà, we will have a candidate eligible to take that call.

A call may get skills added to its list of required skills during its flow through the system. They can come in via the media manager and the queue(s) the call enters.

There exist two kinds of skills: static and magic. Static skills are created by the users and never change its value; we refer to them simply as skills. Magic skills on the other side, are expanded to a particular value through out the system or serve as wildcard to several skills. You can distinguish them because the Magic skills have an underscore as the first character in the atom that identifies them. The default Magic skills are protected and cannot be edited.

Skills can be grouped purely for organization purpose; a skill's group has nothing to do with it's behavior. To create a skill group, give a skill a group that does not exist. A group is automatically deleted when there are no skills in it.

There is no delete button for skills because even if a skill is removed from the database, it's atom will remain in the system's memory. A skill may be completely repurposed since the atom does not need to have a logical link to the skill it represents. After a skill is created, the atom cannot be changed. The atom is the portion of the skill that is used internally for routing. Name, group, and description are solely for the benefit of the end user.

Skill groups, and their skills are automatically listed on the left in the Skill tab of the management interface. Commands to list skills in the shell:

List skill

1> call_queue_config:get_skills().

List skills in a Group

1> call_queue_config:get_skills("Group").

Get skill

1> call_queue_config:get_skill(atom).

Create a skill

Click on the '+' button in the lower left corner of the skills list, then fill out the form, and click 'Submit'.

1> call_queue_config:new_skill(atom, "Name", "Description", "Group").

Updating a skill

Select the skill you wish to edit, fill out the form, and click 'Submit'. Note that doing an update from the shell will allow you to change that atom. As discussed above, this is discouraged as the skill's atom will remain in memory.

1> rr("include/queue.hrl").
2> call_queue_config:set_skill(atom, #skill_rec{name="Name", atom=atom, description="Description", group = "Group"}).

Updating a skill Group

Select the skill group, fill out the new name, and click 'Submit'.

1> call_queue_config:rename_skill_group("OldGroup", "NewGroup").

Deleting a skill

There is no way to delete skill via the web interface. If you are determined to do so, you can do it from the shell.

1> call_queue_config:destroy_skill("Name").

Magic Skills

There are a number of magic skills that are expanded to a particular value:

Atom Meaning Expanded by
_queue A queue name Media in queue
_brand A brand name Media
_node The node an agent is logged into or media was initialized on Agents and Media
_agent An agent's login name Agents
_profile An agent's profile name Agents
_all skip further skill checking, and assert a positive match Never; it's meaning is inherent

So each agent can be represented by that _agent skill, which means that the agent "john" has the agent:"john" skill. This lets you apply a skill to a call such that only a particular agent can handle a particular call. You can also make agents members of a queue by using the _queue skill or restrict calls to local delivery by using the _node skill. Additionally, recipes exist for modifying the skills on a call in queue when the conditions for that recipe to run are satisfied.

Magic skills are expanded to the form {magicskill, Value} so that _agent for the agent john becomes {_agent, "john"}. This system lets us unexpand magic skills and remove them correctly (and prevent conflicts and duplicates).

Only one instance of each magic skill can be applied to a call (so you can't have 2 _queue or _brand skills which could make the call undeliverable). Agents can have unique duplicates of _queue and _brand but not _agent or _node (so an agent could have both the {'_brand', "XYZ Corporation"} and {'_brand', "ABC LLC"} without conflict).

A magic skill can be stored in it's expanded form anywhere, however, assigning an unexpanded magic skill will only work in certain cases. Consult the above table to see when a skill is expanded.

Queue Management

A call goes into a queue. To aid configuration, queues have groups just like agents have profiles. The list is structured the same. Just like agents get skills from the profile, a queue will get recipe steps from its group.

Now would be a good time to discuss what, exactly, a recipe is.

Recipes

A recipe is a list of changes or actions to take on a call while it is in queue, and when to make those changes. A recipe in english might read something like:

  • At 10 seconds, make the call more important.
  • At 20 seconds, remove the '_node' limitation from the call so agents off site can take it.
  • Every 40 seconds, apologize to the caller for them being in queue so long.
  • At 200 seconds, and if there are no agents available, send the call to voicemail.

There are various operations that a 'recipe' can perform when it's triggered:

  • add_skills : add one or more skills to this call
  • remove_skills : ...
  • set_priority : set the call's priority to an absolute value
  • prioritize : increment the call's priority
  • deprioritize : decrement the call's priority
  • voicemail : send the call to voicemail
  • announce : play a periodic announce
  • add_recipe : add another recipe to be run

The recipes can be of two types: run_once and run_many, run_once removes itself from the recipe list after it's triggered the first time, run_many runs every time it's triggered.

The available trigger conditions for the recipe are as follows:

  • ticks - Every X ticks this trigger fires
  • eligible_agents - Checks against the number of eligible agents for this call
  • available_agents - Checks against the number of eligible agents that are available to take this call
  • queue_position - Checks against the current queue position
  • calls_queued - Checks against the number of calls in queue

Possible additional triggers (feel free to suggest some):

  • Overall time in queue
  • Average queue time (or service level)

"Ticks" are the poll interval where we check the various dispatchers for agents to send a call to and, failing that, run any appropriate recipes. It is defined to be a second.

Every trigger but 'ticks' takes a comparison (less than, equal to or greater than) and a number to apply that comparison against. So if you wanted to take some action when the call is the first one in queue: {queue_position, '=', 1}

A recipe can have multiple triggers; the recipe will be run only if all conditions are met. A recipe step should have at least one condition, otherwise it will run every tick.

The order recipe steps are evaluated to run is currently the same as what is in the management interface.

Recipes can either be set per-queue or inherited from the group the queue is in. This should make it easier to construct many similar queues with only minor differences.

Broken down, we have a list of actions, and each action has the conditions that cause the action to be take. Furthermore, we have whether a particular action is take only once, or is repeated each time it's conditions are met. Spice Telephony calls the list a 'recipe', and each action a 'recipe step.'

When a call is put into a queue, that queue starts a process to monitor the call. Every tick, that new process checks it's recipe to see which steps should have it's action taken. A recipe step is only run if all of it's conditions are met.

A recipe can be a list of no steps.

The web management interface has a recipe editor to help create a recipe for both queues and queue groups. On the left hand side is the conditions for the currently selected step. A step must have at least one condition, or it will never run. The right hand side has the actions, any parameters that action requires, and if the action should be done only once, or every time the conditions are met (run many). The "-" removes the recipe step, while the "+" adds a new step.

Configuring a recipe is possible on the shell. the definition of a recipe is as follows:

-type(recipe_runs() :: 'run_once' | 'run_many').

-type(recipe_comparison() :: '<' | '>' | '=').

-type(recipe_condition() ::
	{'ticks', pos_integer()} |
	{'eligible_agents', recipe_comparison(), non_neg_integer()} |
	{'available_agents', recipe_comparison(), non_neg_integer()} |
	{'queue_position', recipe_comparison(), non_neg_integer()} |
	{'calls_queued', recipe_comparison(), non_neg_integer()}).
	
-type(recipe_step() ::
	{[recipe_condition(), ...], 'add_skills', [atom(),...], recipe_runs()} |
	{[recipe_condition(), ...], 'remove_skills', [atom(),...], recipe_runs()} |
	{[recipe_condition(), ...], 'set_priority', integer(), recipe_runs()} |
	{[recipe_condition(), ...], 'prioritize', [], recipe_runs()} |
	{[recipe_condition(), ...], 'deprioritize', [], recipe_runs()} |
	{[recipe_condition(), ...], 'voicemail', [], recipe_runs()} |
	{[recipe_condition(), ...], 'announce', string(), recipe_runs()} |
	{[recipe_condition(), ...], 'add_recipe', tuple(), recipe_runs()}). % no recursive types, so you can't use recipe_step here.

-type(recipe() :: [recipe_step()]).

So storing a recipe with one step to a variable from the shell would look like

1> Recipe = [ { [{ticks, 20}, {call_queued, '>', 10}], annouce, "sorry_really_busy.wav", run_many } ].

Examples

Remove the level 2 skill after 10 'ticks'

 {[{ticks, 10}], remove_skills, [level2], run_once}

Increase the priority of a call every 30 ticks:

 {[{ticks, 30}], prioritize, [], run_many}

After 60 ticks in queue, play a message about high call volume:

 {[{ticks, 60}], announce, "ivr/8000/high_call_volume.wav", run_once}

After 60 ticks in queue, play a 'thank you for holding message' every 10 ticks:

 {[{ticks, 60}], add_recipe, {[{ticks, 10}], announce, "ivr/8000/thank_you_for_holding.wav", run_many}, run_once}

If the call is first in queue, play 'you are the next caller' every 20 'ticks':

 {[{ticks, 20}, {queue_position, '=', 1}], announce, "ivr/8000/you_are_the_next_caller.wav", run_many}

Queue Groups

A queue group holds common recipe steps for it's member queues. You cannot rename or delete the default queue group. To add a new queue group, click the "+ Group" button. To remove a group, select the group, then click the "-" button. Any queues that were a member of the deleted group are moved to the default group.

Sort is the display order for supervisors.

To accomplish the same tasks in the shell:

Adding a queue group

1> Sort = 5, Recipe = [], call_queue_config:new_queue_group("Name", Sort, Recipe).

Updating a queue group

1> Sort = 5, Recipe = [], call_queue_config:set_queue_group("Oldname", "Newname", Sort, Recipe).

Deleting a queue group

1> call_queue_config:destroy_queue_group("Name").

Queues

Add a queue by clicking the "+" button. Remove a queue by selecting it then clicking the "-" button.

Name 
Name of the queue.
Group 
The group the queue belongs to.
Skills 
Any additional skills a call gains when added to the queue.
Weight 
To make a queue more important when routing calls, make the weight higher.
Group Recipe 
This is for display only; shows the recipe of the group this queue is a member of.
Queue Recipe 
Recipe editor for the queue.

Once more, to do this in the shell:

First, read the records for a call queue:

1> rr("include/queue.hrl").

Adding a queue:

2> call_queue_config:set_queue(#call_queue{name = "Name", weight = 5, skills = [skill1, skill2], recipe = [], group = "Default"}).

Updating a queue:

2> call_queue_config:set_queue("Oldname", #call_queue{name = "Newname", weight = 5, skills = [skill1, skill2], recipe = [], group = "Default"}).

Deleting a queue:

2> call_queue_config:destroy_queue("Name").

Testing Queues Recipes

If you want to test if a queue's recipe is working as expected, you can take advantage of the dummy_media module. Dummy_media is, as the name implies, a dummy call. It is designed for testing the systems integration with a generic media without the need to install freeswitch or another 'real' media system. It's used in our tests to ensure the system will correctly route a call.

The easiest way to use it is through the shell. After starting up the system:

dummy_media:q().

This will create a dummy_media call and place it in the default queue. If you want to test if a queue's recipe is working as expected, you create, then edit the dummy media:

{ok, Pid} = dummy_media:start("testcall").
dummy_media:set_skills(Pid, [english, german]).
Qpid = queue_manager:get_queue("default_queue").
call_queue:add(Qpid, Pid).

Dummy_media_manager is, at the moment, a very simple gen_server used in testing cpx_middle_supervisor. It will either be replaced or extended as more tests need a media_manager (or other gen_server).

Media Management

Each node that Spice Telephony is running on can have unique media (call types) it is able to handle. Some may be able to take video, email, and voice, while others may be voice only. Thus, the Media Types tab's list is broken down by node in the Spice Telephony system.

As more media types are supported, the options below each node will expand. Clicking on a media type's name will edit that media for the node it is listed under.

FreeSWITCH

C Node 
The name of the node the freeswitch installation is running at. Examples are freeswitch@myhost in shortname nodes and freeswitch@myhost.com for longnamed nodes.
Domain 
Domain used to route calls to agents. Example is myhost.com.
Voice gateway 
Gateway used to route outbound calls.