[{"data":1,"prerenderedAt":267},["ShallowReactive",2],{"DefaultLayouten":3,"language-blog-slug-building-our-own-chatbot-and-cloud-ai-service-i18n-slugs":134,"language-blog-slug-en-building-our-own-chatbot-and-cloud-ai-service":138},{"app":4,"menu":31,"footer":66},{"githubUrl":5,"youtubeUrl":6,"linkedinUrl":7,"phoneNumber":8,"emailAddress":9,"legal":10,"addresses":20},"https:\u002F\u002Fgithub.com\u002Fvoorhoede\u002F","https:\u002F\u002Fwww.youtube.com\u002Fchannel\u002FUCzHuhQVYFRixtQN2-swcuGg","https:\u002F\u002Fwww.linkedin.com\u002Fcompany\u002Fde-voorhoede","+31 20 2610 954","post@voorhoede.nl",[11,14,17],{"title":12,"value":13},"KvK","56017235",{"title":15,"value":16},"BTW","NL851944620B01",{"title":18,"value":19},"IBAN","NL14TRIO0320142078",[21,26],{"address":22,"city":23,"googleMapsLink":24,"postalCode":25},"Koivistokade 70","Amsterdam","https:\u002F\u002Fwww.google.com\u002Fmaps\u002Fplace\u002FDe+Voorhoede+%7C+Front-end+Development\u002F@52.396847,4.8700823,17z\u002Fdata=!3m1!4b1!4m5!3m4!1s0x47c5e21d502d2d59:0xbf570944a96ebf45!8m2!3d52.347647!4d4.8502154","1013 BB",{"address":27,"city":28,"googleMapsLink":29,"postalCode":30},"Koornmarkt 22","Delft","https:\u002F\u002Fwww.google.nl\u002Fmaps\u002Fplace\u002FKoornmarkt+22,+2611+EG+Delft\u002F@52.0093477,4.3573054,17z\u002F","2611 EG",{"title":32,"callToActions":33,"links":39},"Site Menu",[34],{"id":35,"title":36,"link":37},"163140902","Contact",{"__typename":38},"ContactRecord",[40,46,51,56,61],{"id":41,"title":42,"link":43},"163140904","Impact",{"__typename":44,"slug":45},"PageRecord","impact",{"id":47,"title":48,"link":49},"163140905","Services",{"__typename":50},"ServiceOverviewRecord",{"id":52,"title":53,"link":54},"163140906","Cases",{"__typename":55},"CaseOverviewRecord",{"id":57,"title":58,"link":59},"163140908","About us",{"__typename":44,"slug":60},"about-us",{"id":62,"title":63,"link":64},"d6WdFJq2SOuc3dWtpibbXQ","Work at",{"__typename":44,"slug":65},"work-at",{"links":67,"copyrightTitle":93,"copyrightLabel":94,"copyrightLink":95,"privacyTitle":96,"privacyLabel":97,"privacyLink":98,"certificatesGrid":99},[68,71,74,77,82,85,88],{"id":69,"title":42,"link":70},"144185264",{"__typename":44,"slug":45},{"id":72,"title":48,"link":73},"144185265",{"__typename":50},{"id":75,"title":53,"link":76},"144185266",{"__typename":55},{"id":78,"title":79,"link":80},"144185267","Blog",{"__typename":81},"BlogPostOverviewRecord",{"id":83,"title":58,"link":84},"144185268",{"__typename":44,"slug":60},{"id":86,"title":36,"link":87},"144185269",{"__typename":38},{"id":89,"title":90,"link":91},"144185270","FAQ",{"__typename":44,"slug":92},"faq","Creative Commons licence and disclaimer","CC BY 4.0","https:\u002F\u002Fcreativecommons.org\u002Flicenses\u002Fby\u002F4.0\u002F","De Voorhoede privacy statement (pdf)","Privacy statement","https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1763455455-vh-isms-006-privacy-statement-de-voorhoede-en.pdf",[100,112,123],{"id":101,"image":102,"link":107},"Xq4bBfg_TZ6Fkjax9mkbLQ",{"url":103,"alt":104,"width":105,"height":106},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1687353463-b-corp-logo-black-rgb.png","B Corp logo",404,680,{"__typename":108,"id":109,"title":110,"url":111},"ExternalLinkRecord","fGW1ak8XQYaYDLkBSyncog","B Corp","https:\u002F\u002Fwww.bcorporation.net\u002Fen-us\u002Ffind-a-b-corp\u002Fcompany\u002Fde-voorhoede\u002F",{"id":113,"image":114,"link":119},"c5mCXRTiSraRIB25fw1p7Q",{"url":115,"alt":116,"width":117,"height":118},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1687353461-dda-boxlogo-black.png","Dutch Digital Agencies logo",627,480,{"__typename":108,"id":120,"title":121,"url":122},"P6Jh7B0cTv2cKyNEeKVWVQ","Dutch Digital Agencies","https:\u002F\u002Fdutchdigitalagencies.com\u002Fleden\u002Fde-voorhoede\u002F",{"id":124,"image":125,"link":129},"MT5SCyNxSTSr_v5eeATMZw",{"url":126,"alt":127,"width":128,"height":128},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1775730283-dnv.png","DNV logo",518,{"id":130,"title":131,"link":132},"BRtNB5HnT5i-7HkA8IYzBw","DIV",{"__typename":44,"slug":133},"impact\u002Fdigitale-producten-privacy-by-design",[135],{"locale":136,"value":137},"en","building-our-own-chatbot-and-cloud-ai-service",{"page":139},{"slug":137,"i18nSlugs":140,"social":142,"title":147,"subtitle":79,"isArchived":148,"headerIllustration":149,"date":150,"authors":151,"introTitle":144,"items":160,"pivots":254,"relatedBlogPosts":265,"tags":266,"onMountedScript":154,"onUnmountedScript":154},[141],{"locale":136,"value":137},{"title":143,"description":144,"image":145},"Building our own Chatbot and Cloud AI Service","Welcome to Chatty Coffee, a chatbot AI experiment with NLP.js and Netlify functions.",{"url":146},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1583230552-chatty-coffee-cover.jpeg","Building our own chatbot and cloud AI service",false,null,"2020-03-03T01:00:00.000+01:00",[152],{"name":153,"lastName":154,"slug":155,"image":156},"James","","james",{"url":157,"alt":149,"width":158,"height":159},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1683534742-james.jpg",1811,2415,[161,165,169,172,176,181,184,187,190,194,197,200,203,206,209,212,215,219,222,225,228,231,234,237,240,251],{"__typename":162,"id":163,"title":154,"body":164},"TextSectionRecord","3357636","\u003Cp>Natural Language Processing, or NLP for short, is a part of artificial intelligence (AI) that deals with the communication between machines and humans using natural language or ordinary language.\u003C\u002Fp>",{"__typename":166,"id":167,"quote":168,"author":154},"QuoteRecord","3357637","The ultimate purpose of NLP is to parse, understand, and make sense of the human language in a structured manner.",{"__typename":162,"id":170,"title":154,"body":171},"3357638","\u003Cp>With this technology, you can, for example, build advanced and sophisticated chatbots. Of course, there are existing services like Amazon Lex and DialogFlow from Google, but they share your data with those companies. Using NLP.js, you can bootstrap your own \u003Cstrong>private\u003C\u002Fstrong> chatbot and cloud AI service. In this blog post, I will explain how.\u003C\u002Fp>",{"__typename":162,"id":173,"title":174,"body":175},"3357775","Let’s order some Chatty Coffee!","\u003Cp>The hardest part of building chatbots is to understand what our end-users want. In other words, what are their end-goals? Once we know that, we can present them with relevant data. In the NLP world, we call these goals: \u003Cstrong>intents\u003C\u002Fstrong>.\u003C\u002Fp>\u003Cp>Let's say we are building a chatbot for a new, fancy coffee shop. The most important feature our bot should have is the ability to understand and place user orders. So, our first \u003Cstrong>intent\u003C\u002Fstrong> is \u003Cem>order\u003C\u002Fem>.\u003C\u002Fp>\u003Cp>There are infinite ways our users can phrase the same \u003Cstrong>intent\u003C\u002Fstrong>, for example, they could say: \"Can I have one triple espresso please?\" but they could also say: \"I want one triple espresso.\". Thankfully, this is not a challenge for NLP systems, no matter how users phrase themselves, their \u003Cstrong>intent\u003C\u002Fstrong> is the same. All we need to do is to give the system a few training examples, and it will figure the rest by itself.\u003C\u002Fp>",{"__typename":177,"id":178,"language":179,"body":180},"CodeBlockRecord","3357776","js","const { NlpManager } = require(\"node-nlp\");\nconst manager = new NlpManager({ languages: [\"en\"], threshold: 0.90 });\n\n\u002F\u002F I suggest you train each intent with about 10 input examples.\nmanager.addDocument(\"en\", \"Can I get a triple espresso please?\", \"Order\");\nmanager.addDocument(\"en\", \"Can I order a triple espresso please?\", \"Order\");\nmanager.addDocument(\"en\", \"Give me a triple espresso.\", \"Order\");\nmanager.addDocument(\"en\", \"I want a triple espresso.\", \"Order\");\nmanager.addDocument(\"en\", \"One triple espresso please.\", \"Order\");\n\u002F\u002F etc\n\n(async() => {\n  await manager.train();\n  manager.save();\n\n  \u002F\u002F Once you have a model trained, you can reuse it with:\n  \u002F\u002F manager.load();\n\n  const userInput = \"Hi, I'd like one triple espresso, please.\";\n  const response = await manager.process(userInput);\n  console.log(response);\n})();",{"__typename":162,"id":182,"title":154,"body":183},"3357777","\u003Cp>\u003Cstrong>Result:\u003C\u002Fstrong>\u003C\u002Fp>",{"__typename":177,"id":185,"language":179,"body":186},"3357778","{\n   \"utterance\": \"Hi, I'd like one triple espresso, please.\",\n   \"nluAnswer\": { \"classifications\": [{ \"intent\": \"Order\", \"score\": 1 }] },\n   \"intent\": \"Order\",\n   \"score\": 1,\n   ...\n}",{"__typename":162,"id":188,"title":154,"body":189},"3357779","\u003Cp>As you can see, our NLP model had no issue figuring out the user&rsquo;s intent. You can now add as many intents as your use-case requires.\u003C\u002Fp>",{"__typename":162,"id":191,"title":192,"body":193},"3357800","Understanding the user’s order","\u003Cp>Now you may be thinking, a triple espresso is nice and all, but how about, lattes and cappuccinos? Good question! Our NLP model is now smart enough to understand that the user wants to place an order. But it does not know which product, what size or how many the user is asking for. It's time to learn about named \u003Cstrong>entities\u003C\u002Fstrong>.\u003C\u002Fp>\u003Cp>A named \u003Cstrong>entity\u003C\u002Fstrong> is a piece of relevant information extracted from a user&rsquo;s \u003Cstrong>intent\u003C\u002Fstrong>. For example, the string \u003Ccode>\"Hi, I'd like one triple espresso, please.\"\u003C\u002Fcode> contains the following entities: \u003Ccode>[\"one\", \"triple\", \"espresso\"]\u003C\u002Fcode>. They represent all of the needed information to place a new order, the amount, the size, and the \"what\".\u003C\u002Fp>\u003Cp>NLP.js comes with build-in entities which are great, but we also need to add custom ones. You can create custom-named entities using \u003Ccode>addNamedEntityText(ENTITY_TYPE, ENTITY_NAME, LANGUAGES, ALIASES)\u003C\u002Fcode>:\u003C\u002Fp>",{"__typename":177,"id":195,"language":179,"body":196},"3357801","manager.addNamedEntityText(\"size\", \"grande\", [\"en\"], [\"Grande\", \"Large\", \"Triple\"]);\nmanager.addNamedEntityText(\"size\", \"short\", [\"en\"], [\"Short\", \"Small\", \"Single\"]);\nmanager.addNamedEntityText(\"size\", \"tall\", [\"en\"], [\"Tall\", \"Medium\", \"Double\"]);",{"__typename":162,"id":198,"title":154,"body":199},"3357802","\u003Cp>Let&rsquo;s also create named entities for our beverages:\u003C\u002Fp>",{"__typename":177,"id":201,"language":179,"body":202},"3357803","manager.addNamedEntityText(\"drink\", \"americano\", [\"en\"], [\"Americano\", \"Americanos\"]);\nmanager.addNamedEntityText(\"drink\", \"latte\", [\"en\"], [\"Latte\", \"Lattes\"]);\nmanager.addNamedEntityText(\"drink\", \"cappuccino\", [\"en\"], [\"Cappuccino\", \"Cappuccinos\"]);\n...",{"__typename":162,"id":204,"title":154,"body":205},"3357804","\u003Cp>Lastly, we can use our new \u003Cstrong>entities\u003C\u002Fstrong> inside our existing \u003Cstrong>intents\u003C\u002Fstrong>, like this:\u003C\u002Fp>",{"__typename":177,"id":207,"language":179,"body":208},"3357805","manager.addDocument(\"en\", \"Can I get a %size% %drink% please?\", \"Order\");\nmanager.addDocument(\"en\", \"Can I order a %size% %drink% please?\", \"Order\");\nmanager.addDocument(\"en\", \"Give me a %size% %drink%.\", \"Order\");\nmanager.addDocument(\"en\", \"I want a %size% %drink%.\", \"Order\");\nmanager.addDocument(\"en\", \"One %size% %drink% please.\", \"Order\");\n...",{"__typename":162,"id":210,"title":154,"body":211},"3357806","\u003Cp>If we now process the same utterance as before (\u003Ccode>manager.process(\"Hi, I'd like one triple espresso, please.\")\u003C\u002Fcode>, we get the following result:\u003C\u002Fp>",{"__typename":177,"id":213,"language":179,"body":214},"3357807","{\n  \"entities\": [\n    {\n      \"accuracy\": 0.84,\n      \"entity\": \"size\",\n      \"option\": \"grande\",\n      \"sourceText\": \"Triple\",\n      \"utteranceText\": \"tripple\"\n    },\n    {\n      \"accuracy\": 1,\n      \"entity\": \"drink\",\n      \"option\": \"espresso\",\n      \"sourceText\": \"Espresso\",\n      \"utteranceText\": \"espresso\"\n    },\n    {\n      \"accuracy\": 0.95,\n      \"sourceText\": \"one\",\n      \"utteranceText\": \"one\",\n      \"entity\": \"number\",\n      \"resolution\": {\n        \"strValue\": \"1\",\n        \"value\": 1,\n        \"subtype\": \"integer\"\n      }\n    }\n  ],\n  ...\n}",{"__typename":162,"id":216,"title":217,"body":218},"3357845","Dutch? French? German? No problem!","\u003Cp>The NLP.js package also supports multi-language systems. You can easily add additional languages with the following changes:\u003C\u002Fp>\u003Cp>\u003Cstrong>1.\u003C\u002Fstrong> First, we need to update the language array of our NLP manager.\u003C\u002Fp>",{"__typename":177,"id":220,"language":179,"body":221},"3357846","const manager = new NlpManager({ languages: [\"en\", \"nl\", \"fr\", \"de\"], threshold: 0.90 });",{"__typename":162,"id":223,"title":154,"body":224},"3357847","\u003Cp>\u003Cstrong>2.\u003C\u002Fstrong> Next, we need to expand our training data to accommodate the new languages.\u003C\u002Fp>",{"__typename":177,"id":226,"language":179,"body":227},"3357848","manager.addDocument(\"nl\", \"Mag ik een %size% %drink%?\", \"Order\"); \u002F\u002F Dutch\nmanager.addDocument(\"fr\", \"Puis-je avoir un %size% %drink%?\", \"Order\"); \u002F\u002F French\nmanager.addDocument(\"de\", \"Kann ich einen %size% %drink%?\", \"Order\"); \u002F\u002F German\n\u002F\u002F etc",{"__typename":162,"id":229,"title":154,"body":230},"3357849","\u003Cp>\u003Cstrong>3.\u003C\u002Fstrong> Finally, we need to update the language array for each \u003Cstrong>entity\u003C\u002Fstrong>.\u003C\u002Fp>",{"__typename":177,"id":232,"language":179,"body":233},"3357850","\u002F\u002F Shared aliases.\nmanager.addNamedEntityText(\"size\", \"grande\", [\"en\", \"nl\", \"fr\", \"de\"], [\"Grande\", \"Large\", \"Triple\"]);\n\n\u002F\u002F Language specific.\nmanager.addNamedEntityText(\"size\", \"grande\", [\"nl\"], [\"Groot\", \"Grote\"]); \u002F\u002F Dutch\nmanager.addNamedEntityText(\"size\", \"grande\", [\"fr\"], [\"Grand\"]); \u002F\u002F French\nmanager.addNamedEntityText(\"size\", \"grande\", [\"de\"], [\"Groß\", \"Großer\"]); \u002F\u002F German",{"__typename":162,"id":235,"title":154,"body":236},"3357851","\u003Cp>We can either let the system detect the language automatically or we can pass in the language as a parameter: \u003Ccode>manager.process(\"nl\", \"Mag ik een groot cappuccino?\")\u003C\u002Fcode>.\u003C\u002Fp>\u003Cp>That&rsquo;s it! You now have a fully \u003Cstrong>functional\u003C\u002Fstrong> and \u003Cstrong>private\u003C\u002Fstrong> \u003Cstrong>multi-language\u003C\u002Fstrong> NLP system!\u003C\u002Fp>",{"__typename":162,"id":238,"title":239,"body":154},"3357852","Demo",{"__typename":241,"id":242,"mute":148,"loop":148,"autoplay":148,"caption":154,"video":243,"gif":149},"ResponsiveVideoRecord","3357853",{"url":244,"title":245,"height":246,"width":247,"provider":248,"providerUid":249,"thumbnailUrl":250},"https:\u002F\u002Fvimeo.com\u002F390939802","NLP - Chatty Coffee Demo",240,348,"vimeo","390939802","https:\u002F\u002Fi.vimeocdn.com\u002Fvideo\u002F855303014-f9771d6e2a3b4fd41856091a2821d50581102a7feae239da4bf25496e9712f66-d_295x166",{"__typename":162,"id":252,"title":154,"body":253},"3357854","\u003Cp>Live Demo: \u003Ca href=\"https:\u002F\u002Fchatty-coffee.netlify.com\u002F\">https:\u002F\u002Fchatty-coffee.netlify.com\u002F\u003C\u002Fa>\u003C\u002Fp>",[255],{"title":256,"body":257,"links":258,"mailchimpValue":154,"mailchimpName":154,"mailchimpId":154,"formType":154,"contactPerson":149},"Also in love with the web?","\u003Cp>For us, that’s about technology and user experience. Fast, available for all, enjoyable to use. And fun to build. This is how our team bands together, adhering to the same values, to make sure we achieve a solid result for clients both large and small. Does that fit you?\u003C\u002Fp>\n",[259],{"__typename":260,"id":261,"title":262,"link":263},"InternalLinkRecord","163140992","Join our team",{"__typename":44,"slug":264},"jobs",[],[],1776256143434]