Table of contents

COMPLETE ROBOT DOCUMENTATION ON A SINGLE PAGE
Project initiation
Typical Asterisk script
Technical inner workings
Sending robot calls to human agents
APPENDIX A Recent changes and additions
APPENDIX B Detailed installation instructions
APPENDIX C Project initiation checklist

Table of contents

COMPLETE ROBOT DOCUMENTATION ON A SINGLE PAGE
Project initiation
Typical Asterisk script
Technical inner workings
Sending robot calls to human agents
APPENDIX A Recent changes and additions
APPENDIX B Detailed installation instructions
APPENDIX C Project initiation checklist


Project initiation

The CallWeb Robot is a fully featured interactive voice response system using all CallWeb features in conjunction with the Asterisk PBX system.

Therefore, a CallWeb Robot project initiation starts with the creation of a CallWeb CATI-like project using the project initiation checklist. Yet, a Robot project is not quite a CATI project, so here are the differences:

Concerning the .scw questionnaire file:

  • It should include the following instruction: # CATI = ivr
  • It is always unilingual.
  • It may include a # Utiliser les lignes pound instruction to specify which phone lines are available to the Robot project. This is a comma-delimited list which may include interval specifications such as "11-15".
  • The PRESTRATE question lists the available strata. The strata names also include the Asterisk context name to use with the stratum, as in this example:
    Atlantique/oplus_context_e
    The context name follows the stratum name and a slash.
  • Therefore, to use different contexts based on prepopulated language data, the language must be part of the stratum definition.
  • There must be one field for each piece of data collected via the telephone interview.
  • Since the CallWeb script defined in the .scw file will never be displayed as a questionnaire, there is little point customizing its looks.

Concerning the Asterisk context file:

  • Names of Asterisk context files must start with the string "oplus_" to be included in the Asterisk extension definitions. They must be located in the /etc/asterisk directory of the Asterisk server.
  • Place the required .wav or .vox files in the /var/lib/asterisk/sounds/custom directory, probably within a project subdirectory and /fr and /en sub-subdirectories. Change the owner and group to asterisk.
  • In the context file, when data must be stored in the CallWeb data base, include a call to the cwASTstocke.sh script which takes the following form:
    exten => fax,1,system(/usr/bin/cwASTstocke.sh ${prefixe} ${projet} ${telkey} ${interviewer} ${nlignes}) "call_result" field_name value
    • The first 5 parameters must be written as above.
    • The sixth parameter is the call disposition code which corresponds to one of the codes defined in cwcodescati.cgi.
    • The "field_name" and "value" parameters are required if a value must be stored in a CallWeb question (such as the value of the telephone keypad key depressed by the respondent). For example,
      /usr/bin/cwASTstocke.sh ${prefixe} ${projet} ${telkey} ${interviewer} ${nlignes} "complete" Q1 1
      stores a "1" in question Q1 and adds a call in the call history with call disposition "complete" (without quotes in the call history).
    • If the call disposition code is empty (i.e., ""), no call is recorded, but the data fields are updated as requested in the command; for example,
      /usr/bin/cwASTstocke.sh ${prefixe} ${projet} ${telkey} ${interviewer} ${nlignes} "" Q1 99
      stores 99 in Q1 but does not add a call to the call history.
  • The Asterisk extension file must be reloaded after a change is made to a context file. cwrobot.cgi includes a reload command.

Concerning running the Robot project:

  • Of course, no interviewer intervene in the Robot process; cwrobot.cgi acts as the call initiator.
  • cwrobot.cgi works from the CATI call queue; create it and manage it using cwsuper.cgi.
  • Bring up cwrobot.cgi, specify the strata to access and the call dispositions to reach (as interviewers do when they access a project).
  • Confirm the choice of phone lines and click Action! to start phoning.
  • Access to cases by the robot is a function of the same rules as access to cases by interviewers, i.e., cases are randomly selected among the call queue taking into consideration call-back priorities, strata selected, project active times in the day and time zones.
  • It is possible to get more than one cwrobot.cgi session running concurrently on different or the same projects.

Project initiation

The CallWeb Robot is a fully featured interactive voice response system using all CallWeb features in conjunction with the Asterisk PBX system.

Therefore, a CallWeb Robot project initiation starts with the creation of a CallWeb CATI-like project using the project initiation checklist. Yet, a Robot project is not quite a CATI project, so here are the differences:

Concerning the .scw questionnaire file:

  • It should include the following instruction: # CATI = ivr
  • It is always unilingual.
  • It may include a # Utiliser les lignes pound instruction to specify which phone lines are available to the Robot project. This is a comma-delimited list which may include interval specifications such as "11-15".
  • The PRESTRATE question lists the available strata. The strata names also include the Asterisk context name to use with the stratum, as in this example:
    Atlantique/oplus_context_e
    The context name follows the stratum name and a slash.
  • Therefore, to use different contexts based on prepopulated language data, the language must be part of the stratum definition.
  • There must be one field for each piece of data collected via the telephone interview.
  • Since the CallWeb script defined in the .scw file will never be displayed as a questionnaire, there is little point customizing its looks.

Concerning the Asterisk context file:

  • Names of Asterisk context files must start with the string "oplus_" to be included in the Asterisk extension definitions. They must be located in the /etc/asterisk directory of the Asterisk server.
  • Place the required .wav or .vox files in the /var/lib/asterisk/sounds/custom directory, probably within a project subdirectory and /fr and /en sub-subdirectories. Change the owner and group to asterisk.
  • In the context file, when data must be stored in the CallWeb data base, include a call to the cwASTstocke.sh script which takes the following form:
    exten => fax,1,system(/usr/bin/cwASTstocke.sh ${prefixe} ${projet} ${telkey} ${interviewer} ${nlignes}) "call_result" field_name value
    • The first 5 parameters must be written as above.
    • The sixth parameter is the call disposition code which corresponds to one of the codes defined in cwcodescati.cgi.
    • The "field_name" and "value" parameters are required if a value must be stored in a CallWeb question (such as the value of the telephone keypad key depressed by the respondent). For example,
      /usr/bin/cwASTstocke.sh ${prefixe} ${projet} ${telkey} ${interviewer} ${nlignes} "complete" Q1 1
      stores a "1" in question Q1 and adds a call in the call history with call disposition "complete" (without quotes in the call history).
    • If the call disposition code is empty (i.e., ""), no call is recorded, but the data fields are updated as requested in the command; for example,
      /usr/bin/cwASTstocke.sh ${prefixe} ${projet} ${telkey} ${interviewer} ${nlignes} "" Q1 99
      stores 99 in Q1 but does not add a call to the call history.
  • The Asterisk extension file must be reloaded after a change is made to a context file. cwrobot.cgi includes a reload command.

Concerning running the Robot project:

  • Of course, no interviewer intervene in the Robot process; cwrobot.cgi acts as the call initiator.
  • cwrobot.cgi works from the CATI call queue; create it and manage it using cwsuper.cgi.
  • Bring up cwrobot.cgi, specify the strata to access and the call dispositions to reach (as interviewers do when they access a project).
  • Confirm the choice of phone lines and click Action! to start phoning.
  • Access to cases by the robot is a function of the same rules as access to cases by interviewers, i.e., cases are randomly selected among the call queue taking into consideration call-back priorities, strata selected, project active times in the day and time zones.
  • It is possible to get more than one cwrobot.cgi session running concurrently on different or the same projects.

   

Typical Asterisk script

What follows is a typical asterisk script (technically, scripts are called "contexts" in Asterisk jargon). It starts with a greeting followed by an invitation to select a language; then, it asks a single question and stores the answer in Q1. Along the way, the case call history is updated to reflect the circumstances.

 ; ------------------------------------------------ FRANÇAIS

[oplus_petitemusique_f]
exten => s,1,Answer
exten => s,n,Set(CDR(userfield)=${number})
exten => s,n,AMD(3500|1500|300|5000|120|50|5|256)
exten => s,n,GotoIf($["${AMDSTATUS}" = "AMD_MACHINE"]?machine,1)
exten => s,n,GotoIf($["${AMDSTATUS}" = "AMD_PERSON"]?talk,1)
exten => s,n,GotoIf($["${AMDSTATUS}" = "AMD_NOTSURE"]?uncertain,1)
exten => s,n,GotoIf($["${AMDSTATUS}" = "AMD_HANGUP"]?h,1)
exten => uncertain,1,system(/usr/bin/cwASTstocke.sh ${prefixe} ${projet} ${telkey} ${interviewer} ${nlignes} "uncertain")
exten => uncertain,n,Goto(oplus_petitemusique_f_hangup,s,1)

exten => machine,1,system(/usr/bin/cwASTstocke.sh ${prefixe} ${projet} ${telkey} ${interviewer} ${nlignes} "machine")
exten => machine,n,Goto(oplus_petitemusique_f_hangup,s,1)

exten => h,1,system(/usr/bin/cwASTstocke.sh ${prefixe} ${projet} ${telkey} ${interviewer} ${nlignes} "hung_up")
exten => h,n,Goto(oplus_petitemusique_f_hangup,s,1)

exten => fax,1,system(/usr/bin/cwASTstocke.sh ${prefixe} ${projet} ${telkey} ${interviewer} ${nlignes} "fax")
exten => fax,2,Goto(oplus_petitemusique_f_hangup,s,1)

exten => failed,1,set(CODE=-1)
exten => failed,n,Set(CODE=${IF($[ ${OutgoingSpoolFailedReason} = 0 ]?"no_service":${CODE})})
exten => failed,n,Set(CODE=${IF($[ ${OutgoingSpoolFailedReason} = 1 ]?"no_service":${CODE})})
exten => failed,n,Set(CODE=${IF($[ ${OutgoingSpoolFailedReason} = 3 ]?"ring_no_answer":${CODE})})
exten => failed,n,Set(CODE=${IF($[ ${OutgoingSpoolFailedReason} = 5 ]?"busy":${CODE})})
exten => failed,n,Set(CODE=${IF($[ ${OutgoingSpoolFailedReason} = 8 ]?"out_line_unavailable":${CODE})})
exten => failed,n,Set(CODE=${IF($[ ${CODE} = -1 ]?"failed${CODE}":${CODE})})
exten => failed,n,system(/usr/bin/cwASTstocke.sh ${prefixe} ${projet} ${telkey} ${interviewer} ${nlignes} "${CODE}")
exten => failed,n,Goto(oplus_petitemusique_f_hangup,s,1)

exten => talk,1,system(/usr/bin/cwASTstocke.sh ${prefixe} ${projet} ${telkey} ${interviewer} ${nlignes} "response")
exten => talk,n,Goto(oplus_petitemusique_f,s,21)

exten => s,21,Playback(custom/dar/fr/dar-1-intro-f)
exten => s,22,Background(custom/dar/fr/dar-2-langue-f)

exten => 1,1,SetLanguage(fr)
exten => 1,2,Goto(oplus_petitemusique_f_question,s,1)

exten => 2,1,SetLanguage(en)
exten => 2,2,Goto(oplus_petitemusique_e_question,s,1)

exten => i,1,SetLanguage(fr)
exten => i,2,Goto(oplus_petitemusique_f_question,s,1)

exten => t,1,system(/usr/bin/cwASTstocke.sh ${prefixe} ${projet} ${telkey} ${interviewer} ${nlignes} "time_out_1")
exten => t,2,Goto(oplus_petitemusique_f_hangup,s,1)

exten => h,1,system(/usr/bin/cwASTstocke.sh ${prefixe} ${projet} ${telkey} ${interviewer} ${nlignes} "hung_up")
exten => h,2,Goto(oplus_petitemusique_f_hangup,s,1)

[oplus_petitemusique_f_question]
exten => s,1,Set(LOOPCOUNT=0)
exten => s,2,Playback(custom/dar/dar-3-please)
exten => s,3,Background(custom/dar/dar-4-question)

exten => 1,1,system(/usr/bin/cwASTstocke.sh ${prefixe} ${projet} ${telkey} ${interviewer} ${nlignes} "complete" Q1 1)
exten => 1,2,Goto(oplus_petitemusique_f_end,s,1)

exten => 2,1,system(/usr/bin/cwASTstocke.sh ${prefixe} ${projet} ${telkey} ${interviewer} ${nlignes} "complete" Q1 2)
exten => 2,2,Goto(oplus_petitemusique_f_end,s,1)

exten => 0,1,Goto(oplus_petitemusique_f_question,s,1)

exten => i,1,Set(LOOPCOUNT=$[${LOOPCOUNT} + 1])
exten => i,2,GotoIf($[${LOOPCOUNT} > 9]?h,3)
exten => i,3,Goto(oplus_petitemusique_f_question,s,2)

exten => t,1,system(/usr/bin/cwASTstocke.sh ${prefixe} ${projet} ${telkey} ${interviewer} ${nlignes} "time_out_2")
exten => t,2,Goto(oplus_petitemusique_f_hangup,s,1)

exten => h,1,system(/usr/bin/cwASTstocke.sh ${prefixe} ${projet} ${telkey} ${interviewer} ${nlignes} "hung_up")
exten => h,2,Goto(oplus_petitemusique_f_hangup,s,1)
exten => h,3,system(/usr/bin/cwASTstocke.sh ${prefixe} ${projet} ${telkey} ${interviewer} ${nlignes} "excess_loop")
exten => h,4,Goto(oplus_petitemusique_f_hangup,s,1)

[oplus_petitemusique_f_end]
exten => s,1,Playback(custom/dar/dar-5-merci)
exten => s,2,Goto(oplus_petitemusique_f_hangup,s,1)

[oplus_petitemusique_f_hangup]
; Cette section coupe la communication sans déclencher l'extension "h"
; et donc sans ajouter d'appel à l'historique d'appels
exten => s,1,system(/usr/bin/cwASTstocke.sh ${interviewer} "released")
exten => s,n,Hangup

; ------------------------------------------------ ANGLAIS

[oplus_petitemusique_e]
exten => s,1,Answer
exten => s,n,Set(CDR(userfield)=${number})
exten => s,n,AMD(3500|1500|300|5000|120|50|5|256)
exten => s,n,GotoIf($["${AMDSTATUS}" = "AMD_MACHINE"]?machine,1)
exten => s,n,GotoIf($["${AMDSTATUS}" = "AMD_PERSON"]?talk,1)
exten => s,n,GotoIf($["${AMDSTATUS}" = "AMD_NOTSURE"]?uncertain,1)
exten => s,n,GotoIf($["${AMDSTATUS}" = "AMD_HANGUP"]?h,1)
exten => uncertain,1,system(/usr/bin/cwASTstocke.sh ${prefixe} ${projet} ${telkey} ${interviewer} ${nlignes} "uncertain")
exten => uncertain,n,Goto(oplus_petitemusique_e_hangup,s,1)

exten => machine,1,system(/usr/bin/cwASTstocke.sh ${prefixe} ${projet} ${telkey} ${interviewer} ${nlignes} "machine")
exten => machine,n,Goto(oplus_petitemusique_e_hangup,s,1)

exten => h,1,system(/usr/bin/cwASTstocke.sh ${prefixe} ${projet} ${telkey} ${interviewer} ${nlignes} "hung_up")
exten => h,n,Goto(oplus_petitemusique_e_hangup,s,1)

exten => fax,1,system(/usr/bin/cwASTstocke.sh ${prefixe} ${projet} ${telkey} ${interviewer} ${nlignes} "fax")
exten => fax,2,Goto(oplus_petitemusique_e_hangup,s,1)

exten => failed,1,set(CODE=-1)
exten => failed,n,Set(CODE=${IF($[ ${OutgoingSpoolFailedReason} = 0 ]?"no_service":${CODE})})
exten => failed,n,Set(CODE=${IF($[ ${OutgoingSpoolFailedReason} = 1 ]?"no_service":${CODE})})
exten => failed,n,Set(CODE=${IF($[ ${OutgoingSpoolFailedReason} = 3 ]?"ring_no_answer":${CODE})})
exten => failed,n,Set(CODE=${IF($[ ${OutgoingSpoolFailedReason} = 5 ]?"busy":${CODE})})
exten => failed,n,Set(CODE=${IF($[ ${OutgoingSpoolFailedReason} = 8 ]?"out_line_unavailable":${CODE})})
exten => failed,n,Set(CODE=${IF($[ ${CODE} = -1 ]?"failed${CODE}":${CODE})})
exten => failed,n,system(/usr/bin/cwASTstocke.sh ${prefixe} ${projet} ${telkey} ${interviewer} ${nlignes} "${CODE}")
exten => failed,n,Goto(oplus_petitemusique_e_hangup,s,1)

exten => talk,1,system(/usr/bin/cwASTstocke.sh ${prefixe} ${projet} ${telkey} ${interviewer} ${nlignes} "response")
exten => talk,n,Goto(oplus_petitemusique_e,s,21)

exten => s,21,Playback(custom/dar/fr/dar-1-intro-e)
exten => s,22,Background(custom/dar/fr/dar-2-langue-e)

exten => 1,1,SetLanguage(en)
exten => 1,2,Goto(oplus_petitemusique_e_question,s,1)

exten => 2,1,SetLanguage(fr)
exten => 2,2,Goto(oplus_petitemusique_f_question,s,1)

exten => i,1,SetLanguage(en)
exten => i,2,Goto(oplus_petitemusique_e_question,s,1)

exten => t,1,system(/usr/bin/cwASTstocke.sh ${prefixe} ${projet} ${telkey} ${interviewer} ${nlignes} "time_out_1")
exten => t,2,Goto(oplus_petitemusique_e_hangup,s,1)

exten => h,1,system(/usr/bin/cwASTstocke.sh ${prefixe} ${projet} ${telkey} ${interviewer} ${nlignes} "hung_up")
exten => h,2,Goto(oplus_petitemusique_e_hangup,s,1)

[oplus_petitemusique_e_question]
exten => s,1,Set(LOOPCOUNT=0)
exten => s,2,Playback(custom/dar/dar-3-please)
exten => s,3,Background(custom/dar/dar-4-question)

exten => 1,1,system(/usr/bin/cwASTstocke.sh ${prefixe} ${projet} ${telkey} ${interviewer} ${nlignes} "complete" Q1 1)
exten => 1,2,Goto(oplus_petitemusique_e_end,s,1)

exten => 2,1,system(/usr/bin/cwASTstocke.sh ${prefixe} ${projet} ${telkey} ${interviewer} ${nlignes} "complete" Q1 2)
exten => 2,2,Goto(oplus_petitemusique_e_end,s,1)

exten => 0,1,Goto(oplus_petitemusique_e_question,s,1)

exten => i,1,Set(LOOPCOUNT=$[${LOOPCOUNT} + 1])
exten => i,2,GotoIf($[${LOOPCOUNT} > 9]?h,3)
exten => i,3,Goto(oplus_petitemusique_e_question,s,2)

exten => t,1,system(/usr/bin/cwASTstocke.sh ${prefixe} ${projet} ${telkey} ${interviewer} ${nlignes} "time_out_2")
exten => t,2,Goto(oplus_petitemusique_e_hangup,s,1)

exten => h,1,system(/usr/bin/cwASTstocke.sh ${prefixe} ${projet} ${telkey} ${interviewer} ${nlignes} "hung_up")
exten => h,2,Goto(oplus_petitemusique_e_hangup,s,1)
exten => h,3,system(/usr/bin/cwASTstocke.sh ${prefixe} ${projet} ${telkey} ${interviewer} ${nlignes} "excess_loop")
exten => h,4,Goto(oplus_petitemusique_e_hangup,s,1)

[oplus_petitemusique_e_end]
exten => s,1,Playback(custom/dar/dar-5-merci)
exten => s,2,Goto(oplus_petitemusique_e_hangup,s,1)

[oplus_petitemusique_e_hangup]
; Cette section coupe la communication sans déclencher l'extension "h"
; et donc sans ajouter d'appel à l'historique d'appels
exten => s,1,system(/usr/bin/cwASTstocke.sh ${interviewer} "released")
exten => s,n,Hangup

Typical Asterisk script

What follows is a typical asterisk script (technically, scripts are called "contexts" in Asterisk jargon). It starts with a greeting followed by an invitation to select a language; then, it asks a single question and stores the answer in Q1. Along the way, the case call history is updated to reflect the circumstances.

 ; ------------------------------------------------ FRANÇAIS

[oplus_petitemusique_f]
exten => s,1,Answer
exten => s,n,Set(CDR(userfield)=${number})
exten => s,n,AMD(3500|1500|300|5000|120|50|5|256)
exten => s,n,GotoIf($["${AMDSTATUS}" = "AMD_MACHINE"]?machine,1)
exten => s,n,GotoIf($["${AMDSTATUS}" = "AMD_PERSON"]?talk,1)
exten => s,n,GotoIf($["${AMDSTATUS}" = "AMD_NOTSURE"]?uncertain,1)
exten => s,n,GotoIf($["${AMDSTATUS}" = "AMD_HANGUP"]?h,1)
exten => uncertain,1,system(/usr/bin/cwASTstocke.sh ${prefixe} ${projet} ${telkey} ${interviewer} ${nlignes} "uncertain")
exten => uncertain,n,Goto(oplus_petitemusique_f_hangup,s,1)

exten => machine,1,system(/usr/bin/cwASTstocke.sh ${prefixe} ${projet} ${telkey} ${interviewer} ${nlignes} "machine")
exten => machine,n,Goto(oplus_petitemusique_f_hangup,s,1)

exten => h,1,system(/usr/bin/cwASTstocke.sh ${prefixe} ${projet} ${telkey} ${interviewer} ${nlignes} "hung_up")
exten => h,n,Goto(oplus_petitemusique_f_hangup,s,1)

exten => fax,1,system(/usr/bin/cwASTstocke.sh ${prefixe} ${projet} ${telkey} ${interviewer} ${nlignes} "fax")
exten => fax,2,Goto(oplus_petitemusique_f_hangup,s,1)

exten => failed,1,set(CODE=-1)
exten => failed,n,Set(CODE=${IF($[ ${OutgoingSpoolFailedReason} = 0 ]?"no_service":${CODE})})
exten => failed,n,Set(CODE=${IF($[ ${OutgoingSpoolFailedReason} = 1 ]?"no_service":${CODE})})
exten => failed,n,Set(CODE=${IF($[ ${OutgoingSpoolFailedReason} = 3 ]?"ring_no_answer":${CODE})})
exten => failed,n,Set(CODE=${IF($[ ${OutgoingSpoolFailedReason} = 5 ]?"busy":${CODE})})
exten => failed,n,Set(CODE=${IF($[ ${OutgoingSpoolFailedReason} = 8 ]?"out_line_unavailable":${CODE})})
exten => failed,n,Set(CODE=${IF($[ ${CODE} = -1 ]?"failed${CODE}":${CODE})})
exten => failed,n,system(/usr/bin/cwASTstocke.sh ${prefixe} ${projet} ${telkey} ${interviewer} ${nlignes} "${CODE}")
exten => failed,n,Goto(oplus_petitemusique_f_hangup,s,1)

exten => talk,1,system(/usr/bin/cwASTstocke.sh ${prefixe} ${projet} ${telkey} ${interviewer} ${nlignes} "response")
exten => talk,n,Goto(oplus_petitemusique_f,s,21)

exten => s,21,Playback(custom/dar/fr/dar-1-intro-f)
exten => s,22,Background(custom/dar/fr/dar-2-langue-f)

exten => 1,1,SetLanguage(fr)
exten => 1,2,Goto(oplus_petitemusique_f_question,s,1)

exten => 2,1,SetLanguage(en)
exten => 2,2,Goto(oplus_petitemusique_e_question,s,1)

exten => i,1,SetLanguage(fr)
exten => i,2,Goto(oplus_petitemusique_f_question,s,1)

exten => t,1,system(/usr/bin/cwASTstocke.sh ${prefixe} ${projet} ${telkey} ${interviewer} ${nlignes} "time_out_1")
exten => t,2,Goto(oplus_petitemusique_f_hangup,s,1)

exten => h,1,system(/usr/bin/cwASTstocke.sh ${prefixe} ${projet} ${telkey} ${interviewer} ${nlignes} "hung_up")
exten => h,2,Goto(oplus_petitemusique_f_hangup,s,1)

[oplus_petitemusique_f_question]
exten => s,1,Set(LOOPCOUNT=0)
exten => s,2,Playback(custom/dar/dar-3-please)
exten => s,3,Background(custom/dar/dar-4-question)

exten => 1,1,system(/usr/bin/cwASTstocke.sh ${prefixe} ${projet} ${telkey} ${interviewer} ${nlignes} "complete" Q1 1)
exten => 1,2,Goto(oplus_petitemusique_f_end,s,1)

exten => 2,1,system(/usr/bin/cwASTstocke.sh ${prefixe} ${projet} ${telkey} ${interviewer} ${nlignes} "complete" Q1 2)
exten => 2,2,Goto(oplus_petitemusique_f_end,s,1)

exten => 0,1,Goto(oplus_petitemusique_f_question,s,1)

exten => i,1,Set(LOOPCOUNT=$[${LOOPCOUNT} + 1])
exten => i,2,GotoIf($[${LOOPCOUNT} > 9]?h,3)
exten => i,3,Goto(oplus_petitemusique_f_question,s,2)

exten => t,1,system(/usr/bin/cwASTstocke.sh ${prefixe} ${projet} ${telkey} ${interviewer} ${nlignes} "time_out_2")
exten => t,2,Goto(oplus_petitemusique_f_hangup,s,1)

exten => h,1,system(/usr/bin/cwASTstocke.sh ${prefixe} ${projet} ${telkey} ${interviewer} ${nlignes} "hung_up")
exten => h,2,Goto(oplus_petitemusique_f_hangup,s,1)
exten => h,3,system(/usr/bin/cwASTstocke.sh ${prefixe} ${projet} ${telkey} ${interviewer} ${nlignes} "excess_loop")
exten => h,4,Goto(oplus_petitemusique_f_hangup,s,1)

[oplus_petitemusique_f_end]
exten => s,1,Playback(custom/dar/dar-5-merci)
exten => s,2,Goto(oplus_petitemusique_f_hangup,s,1)

[oplus_petitemusique_f_hangup]
; Cette section coupe la communication sans déclencher l'extension "h"
; et donc sans ajouter d'appel à l'historique d'appels
exten => s,1,system(/usr/bin/cwASTstocke.sh ${interviewer} "released")
exten => s,n,Hangup

; ------------------------------------------------ ANGLAIS

[oplus_petitemusique_e]
exten => s,1,Answer
exten => s,n,Set(CDR(userfield)=${number})
exten => s,n,AMD(3500|1500|300|5000|120|50|5|256)
exten => s,n,GotoIf($["${AMDSTATUS}" = "AMD_MACHINE"]?machine,1)
exten => s,n,GotoIf($["${AMDSTATUS}" = "AMD_PERSON"]?talk,1)
exten => s,n,GotoIf($["${AMDSTATUS}" = "AMD_NOTSURE"]?uncertain,1)
exten => s,n,GotoIf($["${AMDSTATUS}" = "AMD_HANGUP"]?h,1)
exten => uncertain,1,system(/usr/bin/cwASTstocke.sh ${prefixe} ${projet} ${telkey} ${interviewer} ${nlignes} "uncertain")
exten => uncertain,n,Goto(oplus_petitemusique_e_hangup,s,1)

exten => machine,1,system(/usr/bin/cwASTstocke.sh ${prefixe} ${projet} ${telkey} ${interviewer} ${nlignes} "machine")
exten => machine,n,Goto(oplus_petitemusique_e_hangup,s,1)

exten => h,1,system(/usr/bin/cwASTstocke.sh ${prefixe} ${projet} ${telkey} ${interviewer} ${nlignes} "hung_up")
exten => h,n,Goto(oplus_petitemusique_e_hangup,s,1)

exten => fax,1,system(/usr/bin/cwASTstocke.sh ${prefixe} ${projet} ${telkey} ${interviewer} ${nlignes} "fax")
exten => fax,2,Goto(oplus_petitemusique_e_hangup,s,1)

exten => failed,1,set(CODE=-1)
exten => failed,n,Set(CODE=${IF($[ ${OutgoingSpoolFailedReason} = 0 ]?"no_service":${CODE})})
exten => failed,n,Set(CODE=${IF($[ ${OutgoingSpoolFailedReason} = 1 ]?"no_service":${CODE})})
exten => failed,n,Set(CODE=${IF($[ ${OutgoingSpoolFailedReason} = 3 ]?"ring_no_answer":${CODE})})
exten => failed,n,Set(CODE=${IF($[ ${OutgoingSpoolFailedReason} = 5 ]?"busy":${CODE})})
exten => failed,n,Set(CODE=${IF($[ ${OutgoingSpoolFailedReason} = 8 ]?"out_line_unavailable":${CODE})})
exten => failed,n,Set(CODE=${IF($[ ${CODE} = -1 ]?"failed${CODE}":${CODE})})
exten => failed,n,system(/usr/bin/cwASTstocke.sh ${prefixe} ${projet} ${telkey} ${interviewer} ${nlignes} "${CODE}")
exten => failed,n,Goto(oplus_petitemusique_e_hangup,s,1)

exten => talk,1,system(/usr/bin/cwASTstocke.sh ${prefixe} ${projet} ${telkey} ${interviewer} ${nlignes} "response")
exten => talk,n,Goto(oplus_petitemusique_e,s,21)

exten => s,21,Playback(custom/dar/fr/dar-1-intro-e)
exten => s,22,Background(custom/dar/fr/dar-2-langue-e)

exten => 1,1,SetLanguage(en)
exten => 1,2,Goto(oplus_petitemusique_e_question,s,1)

exten => 2,1,SetLanguage(fr)
exten => 2,2,Goto(oplus_petitemusique_f_question,s,1)

exten => i,1,SetLanguage(en)
exten => i,2,Goto(oplus_petitemusique_e_question,s,1)

exten => t,1,system(/usr/bin/cwASTstocke.sh ${prefixe} ${projet} ${telkey} ${interviewer} ${nlignes} "time_out_1")
exten => t,2,Goto(oplus_petitemusique_e_hangup,s,1)

exten => h,1,system(/usr/bin/cwASTstocke.sh ${prefixe} ${projet} ${telkey} ${interviewer} ${nlignes} "hung_up")
exten => h,2,Goto(oplus_petitemusique_e_hangup,s,1)

[oplus_petitemusique_e_question]
exten => s,1,Set(LOOPCOUNT=0)
exten => s,2,Playback(custom/dar/dar-3-please)
exten => s,3,Background(custom/dar/dar-4-question)

exten => 1,1,system(/usr/bin/cwASTstocke.sh ${prefixe} ${projet} ${telkey} ${interviewer} ${nlignes} "complete" Q1 1)
exten => 1,2,Goto(oplus_petitemusique_e_end,s,1)

exten => 2,1,system(/usr/bin/cwASTstocke.sh ${prefixe} ${projet} ${telkey} ${interviewer} ${nlignes} "complete" Q1 2)
exten => 2,2,Goto(oplus_petitemusique_e_end,s,1)

exten => 0,1,Goto(oplus_petitemusique_e_question,s,1)

exten => i,1,Set(LOOPCOUNT=$[${LOOPCOUNT} + 1])
exten => i,2,GotoIf($[${LOOPCOUNT} > 9]?h,3)
exten => i,3,Goto(oplus_petitemusique_e_question,s,2)

exten => t,1,system(/usr/bin/cwASTstocke.sh ${prefixe} ${projet} ${telkey} ${interviewer} ${nlignes} "time_out_2")
exten => t,2,Goto(oplus_petitemusique_e_hangup,s,1)

exten => h,1,system(/usr/bin/cwASTstocke.sh ${prefixe} ${projet} ${telkey} ${interviewer} ${nlignes} "hung_up")
exten => h,2,Goto(oplus_petitemusique_e_hangup,s,1)
exten => h,3,system(/usr/bin/cwASTstocke.sh ${prefixe} ${projet} ${telkey} ${interviewer} ${nlignes} "excess_loop")
exten => h,4,Goto(oplus_petitemusique_e_hangup,s,1)

[oplus_petitemusique_e_end]
exten => s,1,Playback(custom/dar/dar-5-merci)
exten => s,2,Goto(oplus_petitemusique_e_hangup,s,1)

[oplus_petitemusique_e_hangup]
; Cette section coupe la communication sans déclencher l'extension "h"
; et donc sans ajouter d'appel à l'historique d'appels
exten => s,1,system(/usr/bin/cwASTstocke.sh ${interviewer} "released")
exten => s,n,Hangup

   

Technical inner workings

For the technically oriented who want to know more about the inner-workings of the system, here is the sequence followed by the Robot system:

  • Once the cwrobot.cgi is started, it verifies how many requests for calls are currently queued for the current project in the Asterisk queue (in the commandes table of the robot data base).
  • If the queue is longer than five calls, the system waits one second before checking again.
  • Otherwise, cwrobot.cgi selects a series of next cases to process based on call selection rules; the number of cases is determined by the number of phone lines awarded to the robot or to the number of lines left accouting for the number of interviewers currently logged in and a user-determined slack value.
  • The call robot registers a series of new requests for a phone call in the queue, adds entries in the case call history indicating that the numbers were dialled and waits for one second before resuming with the second point above.
  • On the Asterisk server, cwASTcall.pl constantly monitors the call queue. If a new call request is found, the script formats the information as an Asterisk call request file and deletes the call request from the queue. It is best to "install" cwASTcall.pl into the Linux system right from the boot (and to ensure that it is always running) by placing the following command in /etc/inittab: ca:2345:respawn:/usr/bin/cwASTcall.pl
  • Asterisk dials the number using the context named in the call request.
  • Within the context, the interaction with the respondent takes place and cwASTstocke.sh stores information in the Asterisk call disposition table upon request.
  • The call robot constantly monitors for new call results recorded by the Asterisk server. When one is found, it is absorbed into the CallWeb case history and deleted from the Asterisk call result list.

Technical inner workings

For the technically oriented who want to know more about the inner-workings of the system, here is the sequence followed by the Robot system:

  • Once the cwrobot.cgi is started, it verifies how many requests for calls are currently queued for the current project in the Asterisk queue (in the commandes table of the robot data base).
  • If the queue is longer than five calls, the system waits one second before checking again.
  • Otherwise, cwrobot.cgi selects a series of next cases to process based on call selection rules; the number of cases is determined by the number of phone lines awarded to the robot or to the number of lines left accouting for the number of interviewers currently logged in and a user-determined slack value.
  • The call robot registers a series of new requests for a phone call in the queue, adds entries in the case call history indicating that the numbers were dialled and waits for one second before resuming with the second point above.
  • On the Asterisk server, cwASTcall.pl constantly monitors the call queue. If a new call request is found, the script formats the information as an Asterisk call request file and deletes the call request from the queue. It is best to "install" cwASTcall.pl into the Linux system right from the boot (and to ensure that it is always running) by placing the following command in /etc/inittab: ca:2345:respawn:/usr/bin/cwASTcall.pl
  • Asterisk dials the number using the context named in the call request.
  • Within the context, the interaction with the respondent takes place and cwASTstocke.sh stores information in the Asterisk call disposition table upon request.
  • The call robot constantly monitors for new call results recorded by the Asterisk server. When one is found, it is absorbed into the CallWeb case history and deleted from the Asterisk call result list.

   

Sending robot calls to human agents

It is possible to refer robot calls to a human agent. Respondents are invited to press a certain key to talk to an agent. Once this key is pressed, the Asterisk server looks for an available agent for up to five seconds before asking the respondent whether they want to wait any longer or return to the robot script (this message is stored in the "all_agent_busy" sound file).

At the other end of the call, the agent logs in using the interviewer access script so that their time is accounted for in BASEtemps. They choose the project(s) from which they wish to receive calls. They are then put in a waiting queue. When a call is sent their way, the system automatically pops-up the questionnaire of the caller. If a call sent to an agent remains unanswered, the Asterisk server logs that agent out to avoid sending more calls to an agent who is unavailable.

The following are required for this function:

  • in the usagerXXX.conf file of the CallWeb instance agents use to log in:
    • the url_to_cwagent installation instruction must contain the full URL to the cwagent.cgi script to bridge agents from int2select.cgi to cwagent.cgi.
  • in the usagerXXX.conf file of the CallWeb instance where cwagent.cgi runs, i.e. in the robot instance:
  • cwagent.cgi and the custom-campaign-agent-queue content (found in the from-robot-to-agent.conf file) must be installed in the robot instance;
  • proper matching of IP addresses to SIP channels must be established in BASEpostes;
  • the agent browser must accept pop-up windows from the server handling cwagent.cgi;
  • the robot context files must include the following lines everytime the option to refer to a human agent is available (assuming the use of the 9 key):
    • exten => 9,1,Set(last_question_context=${CONTEXT})
      exten => 9,n,Goto(custom-campaign-agent-queue,s,1)
  • the robot context files must also include an assignment of the "respondent_language" Asterisk variable somewhere at the beginning of the robot context to direct the case to an agent with the correct language selection; for example:
    • exten => s,1,Set(respondent_language=EN)

Sending robot calls to human agents

It is possible to refer robot calls to a human agent. Respondents are invited to press a certain key to talk to an agent. Once this key is pressed, the Asterisk server looks for an available agent for up to five seconds before asking the respondent whether they want to wait any longer or return to the robot script (this message is stored in the "all_agent_busy" sound file).

At the other end of the call, the agent logs in using the interviewer access script so that their time is accounted for in BASEtemps. They choose the project(s) from which they wish to receive calls. They are then put in a waiting queue. When a call is sent their way, the system automatically pops-up the questionnaire of the caller. If a call sent to an agent remains unanswered, the Asterisk server logs that agent out to avoid sending more calls to an agent who is unavailable.

The following are required for this function:

  • in the usagerXXX.conf file of the CallWeb instance agents use to log in:
    • the url_to_cwagent installation instruction must contain the full URL to the cwagent.cgi script to bridge agents from int2select.cgi to cwagent.cgi.
  • in the usagerXXX.conf file of the CallWeb instance where cwagent.cgi runs, i.e. in the robot instance:
  • cwagent.cgi and the custom-campaign-agent-queue content (found in the from-robot-to-agent.conf file) must be installed in the robot instance;
  • proper matching of IP addresses to SIP channels must be established in BASEpostes;
  • the agent browser must accept pop-up windows from the server handling cwagent.cgi;
  • the robot context files must include the following lines everytime the option to refer to a human agent is available (assuming the use of the 9 key):
    • exten => 9,1,Set(last_question_context=${CONTEXT})
      exten => 9,n,Goto(custom-campaign-agent-queue,s,1)
  • the robot context files must also include an assignment of the "respondent_language" Asterisk variable somewhere at the beginning of the robot context to direct the case to an agent with the correct language selection; for example:
    • exten => s,1,Set(respondent_language=EN)

   

Appendix A

Recent changes and additions

DateChange / addition (other than performance enhancements and bug fixes)
November 18, 2010Support added for Asterisk 1.6.
July 7, 2009Addition of the ability to transfer robot calls to a human agent.
June 4, 2008The information displayed on the called telephone is set by the project designer in configuration files overall and on a project by project basis.
April 4, 2008Addition of extra precautions to avoid calls outside of planned hours (call requests older than 15 minutes are ignored).
April 4, 2008Addition of the Robot caller id pound instruction that specifies which number the IVR robot displays when calling.
April 2, 2007The CallWeb robot system identifies and manages ZAP channels stuck in resetting mode.
April 1, 2007The CallWeb robot system has now placed more than 6 million calls.
March 31, 2007The CallWeb robot system has now placed more than 2 million calls.
March 25, 2007Addition of distinct usage of PRI (local and long distance calls) and LD-T1 (long distance calls only) lines using usager.conf instructions.
November 26, 2006Redesign of the robot system to run as a continuous process rather than as an HTML page; addition of a central robot management module as part of cwsuper.cgi.
November 2, 2006Modification of the call disposition management system to reduce the system requirements and to move the load from the Asterisk server to the CallWeb server.
October 21, 2006The CallWeb robot system has now been tested with half a million calls.
October 3, 2006Addition of the ability to use as many lines as are available while leaving enough for human interviewers.
July 31, 2006Official launch.

Appendix A

Recent changes and additions

DateChange / addition (other than performance enhancements and bug fixes)
November 18, 2010Support added for Asterisk 1.6.
July 7, 2009Addition of the ability to transfer robot calls to a human agent.
June 4, 2008The information displayed on the called telephone is set by the project designer in configuration files overall and on a project by project basis.
April 4, 2008Addition of extra precautions to avoid calls outside of planned hours (call requests older than 15 minutes are ignored).
April 4, 2008Addition of the Robot caller id pound instruction that specifies which number the IVR robot displays when calling.
April 2, 2007The CallWeb robot system identifies and manages ZAP channels stuck in resetting mode.
April 1, 2007The CallWeb robot system has now placed more than 6 million calls.
March 31, 2007The CallWeb robot system has now placed more than 2 million calls.
March 25, 2007Addition of distinct usage of PRI (local and long distance calls) and LD-T1 (long distance calls only) lines using usager.conf instructions.
November 26, 2006Redesign of the robot system to run as a continuous process rather than as an HTML page; addition of a central robot management module as part of cwsuper.cgi.
November 2, 2006Modification of the call disposition management system to reduce the system requirements and to move the load from the Asterisk server to the CallWeb server.
October 21, 2006The CallWeb robot system has now been tested with half a million calls.
October 3, 2006Addition of the ability to use as many lines as are available while leaving enough for human interviewers.
July 31, 2006Official launch.

   

Appendix B

Detailed installation instructions

The following instructions were put together in the context of a full re-installation of an Asterisk-CallWeb system.

  • Asterisk installation
    • Ensure that the AMD Asterisk module is installed (issue asterisk -r -x "show application AMD")
    • Include the following lines in the "from-internal-custom" context in extensions_custom.conf
      ;--
      ===============================================================================
      from-internal-custom
      ===============================================================================
      --;
      [from-internal-custom]
      ; Code permettant d'enregistrer les entrevues
      exten => _XXXX.,1,Set(FILENAME=${CDR(accountcode)}-${telkey}-${TIMESTAMP}) ; calculer le nom du fichier
      exten => _XXXX.,2,GotoIf($[ "${CDR(accountcode)}" != "" ]?3:5) ; si accountcode n'est pas vide, tester le telkey
      exten => _XXXX.,3,GotoIf($[ "${telkey}" != "" ) ]?4:5) ; si le telkey n'est pas vide lui aussi, enregistrer!
      exten => _XXXX.,4,Monitor(wav,${FILENAME},m) ; démarrer l'enregistrement
      exten => _XXXX.,5,Macro(dialout-trunk,1,${EXTEN},)
      exten => _XXXX.,6,Macro(dialout-trunk,2,${EXTEN},)
      exten => _XXXX.,7,Macro(outisbusy) ; No available circuits
    • add the following line before any context in extensions.conf ("op*" is the prefix of the IVR context files)
      #include "op*.conf"
    • add whatever context instructions are required for audio-visual monitoring
    • add whatever context instructions are required for playing audio files during interviews
    • add the custom robot contexts in /etc/asterisk
    • add the following files in /usr/bin
      cwAST.pl
      cwASTsiptozap.pl (make executable)
  • Robot installation
    • add the following files in /usr/bin
      cwAST.pl
      cwASTcall.pl (make executable)
      cwASTstocke.sh (make executable)
  • Server installation
    • create the MySQL data base and tables described in cwrobot.cgi
    • add a mount to /etc/fstab to create a location where to push interview recording .wav files into the CallWeb CATI server
      192.168.10.22:/mnt/wav /mnt/wav nfs rw 0 0
    • create the following directories
      /etc/cron.daily2
      /etc/cron.minute
    • place and make executable the following files in the following directories
      cwASTmovewav.pl in /etc/cron.daily2
    • add the following lines in in /etc/crontab
      30 23 * * * root /etc/cron.daily2/cwASTmovewav.pl
    • add the following lines in /etc/inittab
      # Faire tourner cwASTcall.pl dans toutes les configurations
      cw:2345:respawn:/usr/bin/cwASTcall.pl
    • reboot the server

Appendix B

Detailed installation instructions

The following instructions were put together in the context of a full re-installation of an Asterisk-CallWeb system.

  • Asterisk installation
    • Ensure that the AMD Asterisk module is installed (issue asterisk -r -x "show application AMD")
    • Include the following lines in the "from-internal-custom" context in extensions_custom.conf
      ;--
      ===============================================================================
      from-internal-custom
      ===============================================================================
      --;
      [from-internal-custom]
      ; Code permettant d'enregistrer les entrevues
      exten => _XXXX.,1,Set(FILENAME=${CDR(accountcode)}-${telkey}-${TIMESTAMP}) ; calculer le nom du fichier
      exten => _XXXX.,2,GotoIf($[ "${CDR(accountcode)}" != "" ]?3:5) ; si accountcode n'est pas vide, tester le telkey
      exten => _XXXX.,3,GotoIf($[ "${telkey}" != "" ) ]?4:5) ; si le telkey n'est pas vide lui aussi, enregistrer!
      exten => _XXXX.,4,Monitor(wav,${FILENAME},m) ; démarrer l'enregistrement
      exten => _XXXX.,5,Macro(dialout-trunk,1,${EXTEN},)
      exten => _XXXX.,6,Macro(dialout-trunk,2,${EXTEN},)
      exten => _XXXX.,7,Macro(outisbusy) ; No available circuits
    • add the following line before any context in extensions.conf ("op*" is the prefix of the IVR context files)
      #include "op*.conf"
    • add whatever context instructions are required for audio-visual monitoring
    • add whatever context instructions are required for playing audio files during interviews
    • add the custom robot contexts in /etc/asterisk
    • add the following files in /usr/bin
      cwAST.pl
      cwASTsiptozap.pl (make executable)
  • Robot installation
    • add the following files in /usr/bin
      cwAST.pl
      cwASTcall.pl (make executable)
      cwASTstocke.sh (make executable)
  • Server installation
    • create the MySQL data base and tables described in cwrobot.cgi
    • add a mount to /etc/fstab to create a location where to push interview recording .wav files into the CallWeb CATI server
      192.168.10.22:/mnt/wav /mnt/wav nfs rw 0 0
    • create the following directories
      /etc/cron.daily2
      /etc/cron.minute
    • place and make executable the following files in the following directories
      cwASTmovewav.pl in /etc/cron.daily2
    • add the following lines in in /etc/crontab
      30 23 * * * root /etc/cron.daily2/cwASTmovewav.pl
    • add the following lines in /etc/inittab
      # Faire tourner cwASTcall.pl dans toutes les configurations
      cw:2345:respawn:/usr/bin/cwASTcall.pl
    • reboot the server

   

Appendix C

Project initiation checklist

The following checklist is offered as a guide to control that all steps of the project installation process have been completed.

1

         

Create a standard CallWeb CATI project using the CATI project initiation checklist. The scw file must contain the necessary call management questions and one field for each data element to be stored in the project. The # CATI = IVR instruction must be present.
2

         

Create one sound file for each segment of interaction in each language. Save them in .gsm format. Wavepad is useful to this task.
3

         

Place the sound files in a newly created project sub-directory of the /var/lib/asterisk/sounds/custom directory on the Asterisk server. Change the ownership of the sub-directory and of the sound files to asterisk (chown -R asterisk:asterisk *).
4

         

Create an Asterisk context file according to instructions found in this documentation (and on the Asterisk site). Name this file according to the local conventions (i.e., the first few letters tell Asterisk to read in the instructions).
5

         

Place this context file in the /etc/asterisk directory on the Asterisk server.
6

         

The rest of the work takes place in the robot interface. Request a reload of Asterisk's contexts.
7

         

Add sample to the project (only _telkey, _telephone and PRESTRATE fields are mandatory).
8

         

Add sample to the call queue and set case management rules.
9

         

Create at least one case group in the project.
10

         

Enter the hours of operations for the project.
11

         

Using the third pane in control centre, program the call schedule.

Appendix C

Project initiation checklist

The following checklist is offered as a guide to control that all steps of the project installation process have been completed.

1

         

Create a standard CallWeb CATI project using the CATI project initiation checklist. The scw file must contain the necessary call management questions and one field for each data element to be stored in the project. The # CATI = IVR instruction must be present.
2

         

Create one sound file for each segment of interaction in each language. Save them in .gsm format. Wavepad is useful to this task.
3

         

Place the sound files in a newly created project sub-directory of the /var/lib/asterisk/sounds/custom directory on the Asterisk server. Change the ownership of the sub-directory and of the sound files to asterisk (chown -R asterisk:asterisk *).
4

         

Create an Asterisk context file according to instructions found in this documentation (and on the Asterisk site). Name this file according to the local conventions (i.e., the first few letters tell Asterisk to read in the instructions).
5

         

Place this context file in the /etc/asterisk directory on the Asterisk server.
6

         

The rest of the work takes place in the robot interface. Request a reload of Asterisk's contexts.
7

         

Add sample to the project (only _telkey, _telephone and PRESTRATE fields are mandatory).
8

         

Add sample to the call queue and set case management rules.
9

         

Create at least one case group in the project.
10

         

Enter the hours of operations for the project.
11

         

Using the third pane in control centre, program the call schedule.