Chatbot Wiki
Advertisement

This bot plays the employer in a job-conditions negotiation

/* class=gwtchat.server.JavascriptBotUserWizard */



/* RESOURCES */

var turk = new AWSMechanicalTurkClient();

var humanSideName = "Candidate";
var computerSideName = "Employer";

var domain = new NegotiationDomain(wiki.get('JobCandidateDomain.xml'),
humanSideName.toLowerCase(),
computerSideName.toLowerCase()
);

var negotiator = new GeniusNegotiator(domain,
/*humanUtility =*/ wiki.get('Job'+humanSideName+'ShortTermUtilitySpace.xml'),
/* e.g. JobCandidateShortTermUtilitySpace.xml */
/*computerUtility =*/ wiki.get('Job'+computerSideName+'ShortTermUtilitySpace.xml'),
/* e.g. JobEmployerShortTermUtilitySpace.xml */
/*computerAgentClassName = */ "agents.RandomIncreasingUtilAgent",
/*maxOffersByHuman = */ 10);

var YesNoCategorizer = Transformer.recall(wiki, 'YesNo.txt');
var NLU = Transformer.recall(wiki, 'Job'+humanSideName+'Negotiation.regexp');
/* e.g. JobCandidateNegotiation.regexp */
var NLG = Transformer.recall(wiki, 'Job'+computerSideName+'Negotiation.regexp');
/* e.g. JobEmployerNegotiation.regexp */


/* STATUS */
var previousIssue; // used for understanding.
var currentIssue; // used for generation.
var agreedIssues = new DialogStateSlots(domain.getIssues()); // issues both sides agreed upon.
var humanAgreedIssues = new DialogStateSlots(domain.getIssues()); // issues the human agreed upon.
var computerAgreedIssues = new DialogStateSlots(domain.getIssues()); // issues the computer agreed upon.


/* Called once when a human enters the room */
function greethuman(chatter) {
  negotiator.startNegotiationSession();
  chat.say(domain.greeting(chatter.name));
  chat.say("Say 'help' to learn more.");
}

/* Called once when a WOZ enters the room */
function greetwizard(chatter) {
  chat.sayToWizard('Hi, '+chatter.name+'! It is great you are here. You will help me understand the human!');
}


/* Even elements are input patterns; Odd elements are the actions to run. */
var inputsAndActions = [
/^help/i, function(matches) {
chat.say(help());
},
/<question:(.*?)>/i, function(matches) { // question about matches[1]
var issue = matches[1];
if (issue=='initial')
tell("<question:"+slots.setCurrentSlotIfEmpty()+">"); // reply with a counter-question about an arbitrary issue
else if (issue=='agreement')
tell("<question:"+issue+">"); // reply with a counter-question about the same issue
else if (issue=='final')
tell("<question:"+issue+">"); // reply with a counter-question about the same issue
else
tell("<question:"+verifiedIssue(issue)+">", issue); // reply with a counter-question about the same issue
},
/<demand:(.*):(.*)>/i, function(matches) { // demand about matches[1], to get matches[2]
var issue = verifiedIssue(matches[1]); if (!issue) return;
var value = verifiedValue(matches[2],issue); if (!value) return;
tell("<agree:"+issue+":"+value+">"); // reply with an agreement.
},
/<agree:(.*):(.*)>/i, function(matches) { // agree about matches[1], to get matches[2]
var issue = verifiedIssue(matches[1]); if (!issue) return;
var value = verifiedValue(matches[2],issue); if (!value) return;
tell("<demand:"+issue+":"+value+">"); // reply with a demand (for symmetry).
},
/<reject:(.*)>/i, function(matches) { // disagree about matches[1]
var issue = verifiedIssue(matches[1]); if (!issue) return;
tell("<question:"+issue+">"); // reply with a counter-question about the same issue
},
/<promise:(.*):(.*):(.*):(.*)>/i, function(matches) { // "if you agree to matches[1], matches[2], I agree to matches[3], matches[4]"
var issue1 = verifiedIssue(matches[1]); if (!issue1) return;
var value1 = verifiedValue(matches[2],issue1);
var issue2 = verifiedIssue(matches[3]); if (!issue2) return;
var value2 = verifiedValue(matches[4],issue2);
tell("<agree:"+issue1+":"+value1+">"); // reply with an agreement.
},
/^I commit\s*(.+)$/i, function(matches) {
if (chat.getHumanChatter()==null)
chat.complain("Cannot submit without a user","",0.8);
else
chat.say(turk.submitForm(chat.getHumanChatter(), matches[1]));
},
/I want A and B/i, function(matches) {
chat.say("Please talk about one issue at a time, because the computer cannot understand more than that");
},
/Garbage/i, function(matches) {
},
];


function help() {
    return "We will negotiate several issues related to your job conditions.
"+
    "For each issue, there are several possible values, ordered from the best to the worst:
"+

    "
    \n"+
        negotiator.humanUtilitySpaceHTML()+
        "
\n"+

//"
You can make at most "+negotiator.maxOffersByHuman()+" offers.\n"+
    "Try to get the best deal for the most important subjects!\n"+
    "

Please talk about one issue at a time, because the computer cannot understand more than that.\n";
}

function verifiedIssue(issue) {
if (!domain.hasIssue(issue)) {
chat.complain("'"+issue+"' is not one of the issues we negotiate. To view the valid issues, type 'help'.");
return null;
}
return issue;
}

function verifiedValue(value,issue) {
if (!domain.valueIsValidForIssue(value,issue)) {
chat.complain("'"+value+"' is not one of the valid values for "+issue+". To view the valid values, type 'help'.");
return null;
}
return value;
}




/* Called before the first meaningful utterance */
function understandBeforeFirst() {
currentIssue = null; // during understanding, we use previousIssue and set currentIssue
}

/* Called for each meaningful utterance detected at the human's input */
function understand(intention, certainty) { // This is the NLU unit
var intentionSemantics = NLU.transform(intention); // return a string <act:issue:value>
chat.debug("NLU "+intentionSemantics);
for (var i=0; i<inputsAndActions.length; i+=2) {
if (matches = inputsAndActions[i].exec(intentionSemantics)) {
inputsAndActions[i+1](matches);
return;
}
}
chat.complain("Sorry, I didn't understand you", "", certainty);
};

function tell(intentionSemantics, issue) { // This is the NLG unit
chat.debug("NLG "+intentionSemantics);
chat.say(NLG.untransform(intentionSemantics));
if (issue)
previousIssue = issue;
}


/* Called after the last meaningful utterance */
function understandAfterLast() {
previousIssue = null; // during understanding, we use previousIssue and set currentIssue
}

/* Create the input patterns that the WOZ will select from: */
var cachedInputPatterns = domain.inputPatterns();
for (var i=0; i<inputsAndActions.length; i+=2)
cachedInputPatterns.add(regexpToString(inputsAndActions[i]));
function inputPatterns() { return cachedInputPatterns; }

var cachedValuesWithoutInputPatterns = domain.valuesWithoutInputPatterns();
cachedValuesWithoutInputPatterns.add("quality=useless");
cachedValuesWithoutInputPatterns.add("quality=poor");
cachedValuesWithoutInputPatterns.add("quality=moderate");
cachedValuesWithoutInputPatterns.add("quality=good");
cachedValuesWithoutInputPatterns.add("quality=excellent");
function valuesWithoutInputPatterns() { return cachedValuesWithoutInputPatterns; }

function regexpToString(regexp) {
var str = regexp.source.replace(/\(.*\)/, "()").replace(/\\s[+*]/," ");
//print("regexpToString "+str);
if (str.charAt(0)=='^')
str = str.substring(1,str.length);
if (str.charAt(str.length-1)=='$')
str = str.substring(0,str.length-1);
return str;
}

End of bot JobEmployer.js
Advertisement