Josh Marinacci

Head of Developer Evangelism

Serverless Chatbots

[image of a chatbot]

AI + network = Chatbot

Your requirements

Your requirements, not your focus

Don't build your own infrastructure

Don't build your own AI

Focus on your domain knowledge

Demo Time

EmojiBot

HeartBot Code

export default (request) => {
    var txt = request.message.text;
    txt = txt.replace(/poop/g,"\uD83D\uDCA9");
    txt = txt.replace(/crap/g,"\uD83D\uDCA9");
    txt = txt.replace(/love/g,"\uD83D\uDE0D");
    txt = txt.replace(/heart/g,"\uD83D\uDC9C");
    txt = txt.replace(/sad/g,"\uD83D\uDE1E");
    txt = txt.replace(/happy/g,"\uD83D\uDE04");

    request.message.text = "Your message isn't hearty enough!"
        +" There I fixed it: <br/>"
        + txt;
    return request.ok(); // Return a promise when you're done
}

HeartBot Architecture

Serverless !== No Servers

Cloudinary

ImageBot

ImageBot Architecture

ImageBot NLP

var words = text.split(" ")
    .map((w)=>w.toLowerCase())
    .filter((w)=>{
        if(w === 'the')return false;
        if(w === 'it') return false;
        if(w === 'to') return false;
        if(w === 'at') return false;
        if(w === 'in') return false;
        return true;
    });
console.log("words",words);
if(!words.includes("please")) return false;

var n = words.findIndex((w) => w === 'please');
var verb = words[n+1];
if(verb === 'upload') return upload(words);
if(verb === 'display') return display(rest);
if(verb === 'show') return show(rest);
if(verb === 'resize') return resize(rest);
if(verb === 'reset') return reset(rest);
if(verb === 'make' && nextWord === 'square') return makeSquare(rest);
...
    
    {
        "action":"resize"
    }

ImageBot Cloudinary Service Calls

return db.get('context').then((context) => {
    if(!context) context = {};
    var command = request.message;
    if(command.action === 'resize') context.width = command.size;
    if(command.action === 'crop') {
        context.crop = true;
        context.shape = 'square';
        context.gravity = command.gravity;
    }

    //generate the final url
    let apiUrl = 'http://res.cloudinary.com/' +
        cloudName + '/' + resource + '/' + operation + '/';
    apiUrl += filename  + '.' + context.format;

    //save the url
    request.message.cloudinaryURL = apiUrl;


    db.set('context',context); //save the context
    return request.ok(); // Return the final message
});

ImageBot lesson

Don't built your own NLP

MR ROCKBOT Architecture

IBM Watson Text Alchemy API

Detect Language and Translate

const query_params = {
    outputMode:'json',
    apikey:'494a8df6f920d85b1de4a8172c21dbc264d6446f',
    extract:'keywords,relations,language',
    maxRetrieve: 1,
    text:request.message.text
};
var url = "http://gateway-a.watsonplatform.net/calls/text/TextGetCombinedData?"
        +query.stringify(query_params);

return xhr.fetch(url).then((x)=>{
    var ret = JSON.parse(x.body);
    if(ret.language != 'english') {
        return translateMessage(request.message, ret.language);
    }
    return cookMessage(ret);
});

IBM Watson Text Alchemy API

IBM Watson Conversations

Use Conversations API

var url = creds.url+'/v1/workspaces/'+creds.workspaceID+'/message?version=2016-09-20';

var payload = { input: {  text: request.message.text   } }

return kvstore.get("context").then((ctx) => {
    if(ctx) payload.context = ctx;

    const http_options = { method:'POST', body: JSON.stringify(payload) }

    return xhr.fetch(url, http_options).then((x)=>{
        var body = JSON.parse(x.body);
        return kvstore.set("context",body.context).then(()=>{
            request.message.text = body.output.text[0];
            request.message.watson = body;
            return request.ok();
        });
    }).catch((e)=>{
        console.log("ERROR");
        return request.ok();
    });
});

Bonus!

Realtime isn't just for text

Don't build your own AI

Don't build your own realtime infrastructure.

@joshmarinacci

josh@pubnub.com

currnet slide
next slide
my notes
questions