如何使用SAP Conversational AI和NodeJS构建电影机器人

by Paul Pinard

保罗·皮纳德(Paul Pinard)

如何使用SAP Conversational AI和NodeJS构建电影机器人 (How to build a movie bot with SAP Conversational AI and NodeJS)

通过在Facebook Messenger上询问自己的聊天机器人,从电影数据库中获取电影推荐。 (Get movie recommendations from The Movie Database by asking your own chatbot on Facebook Messenger.)

By the end of this tutorial, you will be able to build a fully functional movie bot, able to make movie recommendations based on several criteria. We’re using SAP Conversational AI bot building platform (sign up here for free) and The Movie Database for information on movies.

在本教程结束时,您将能够构建功能齐全的电影bot,并能够基于多个条件提出电影推荐。 我们正在使用SAP Conversational AI机器人构建平台 ( 在此处免费注册 )和电影数据库来获取电影信息。

Here’s a demo chat with Movie Bot:

这是与Movie Bot的演示聊天:

我们今天要建造什么? (What are we building today?)

Interacting with third party APIs allows for much more interesting use cases than simple Q/A chatbots. With Bot Skills, we added the option to call webhooks directly from the builder, which makes it even easier.

与第三方API交互比简单的Q / A聊天机器人允许更多有趣的用例。 借助Bot Skills ,我们添加了直接从构建器调用webhooks的选项,这使得操作更加轻松。

Today’s bot requires several steps:

今天的机器人需要执行以下几个步骤:

  1. Extracting key pieces of information in a sentence

    提取句子中的关键信息
  2. Building the bot flow (triggers, requirements, actions)

    构建机器人流程(触发,需求,操作)
  3. Creating and connecting a bot API able to fetch data from The Movie Database

    创建并连接能够从电影数据库中获取数据的机器人API

You’ll need an SAP Conversational AI account, Node.JS and potentially Ngrok for testing.

您将需要一个SAP Conversational AI帐户 Node.JS以及潜在的Ngrok进行测试。

Before we jump in, please check this guide instead if you are looking for a guide detailing the creation of your first bot.

在我们开始之前,如果您正在寻找详细说明第一个机器人的创建指南请改用本指南

Let’s get to it!

让我们开始吧!

步骤1:从句子中提取关键信息 (Step 1: Extracting key info from a sentence)

Intents are helpful to determine the overall meaning of a sentence. For our use case, knowing that the user wants to watch something is not enough.

意图是有助于确定句子的整体意思。 对于我们的用例,仅了解用户想要观看的内容是不够的。

We need to know what the users want to watch.

我们需要知道用户想要观看什么

Entities are designed to solve this problem: they extract key information in a sentence.

实体旨在解决此问题:它们提取句子中的关键信息。

Intents make you understand that you have to do something. Entities help you actually do something.

意图使您了解必须要做的事情。 实体可以帮助您实际做某事。

Let’s imagine you are a telco company providing phone and internet access. Your bot has an intent that understands when people are complaining about an outage:

假设您是一家提供电话和互联网访问的电信公司。 您的机器人的意图可以理解人们何时抱怨停电:

The entities extracted will help understand what is going wrong, where and since when.

提取的实体将有助于了解发生了什么问题, 发生的时间时间

For our movie bot, we will try to extract 3 key pieces of information:

对于我们的电影机器人,我们将尝试提取3个关键信息

  1. What the user wants to watch (a movie vs a TV show)

    用户想要观看的内容(电影与电视节目)
  2. What genre they are looking for

    他们正在寻找什么流派
  3. In which language

    用哪种语言
使用黄金实体 (Using gold entities)

To help you speed up your development, SAP Conversational AI extracts several entities by default: dates, locations, phone numbers…

为了帮助您加快开发速度,SAP Conversational AI默认情况下会提取多个实体:日期,位置,电话号码…

An exhaustive list is available here.

此处提供了详尽的列表

The Language entity will be helpful:

Language实体将有所帮助:

See the little star next to the entity name? It differentiates a gold entity from a custom one.

看到实体名称旁边的小星星吗? 它将黄金实体与定制实体区分开。

We will use it to fulfill our third requirement: the movie language.

我们将使用它来满足我们的第三个要求:电影语言。

创建自定义实体 (Creating custom entities)

We will create custom entities to extract the information we need. As with intents, training is very important: the more examples you add to your bot, the more accurate it gets.

我们将创建自定义实体以提取所需的信息。 与意图一样,培训也非常重要:您向漫游器添加的示例越多,获取的准确性就越高。

Training your entities can happen through multiple intents. Entities are independent of intents.

培训您的实体可以通过多种意图进行。 实体与意图无关。

For our movie bot, we only need one intent, discover, and 2 entities:

对于我们的电影机器人,我们只需要一个intent, discover和2个实体:

  • recording to identify that the user wants to watch a movie or a tv show

    recording以标识用户想要看电影电视节目

  • genre

    genre

Open the intent discover and add expressions. Make sure to cover every possibility, this means a healthy mix of expressions with:

打开意图discover并添加表达式。 确保涵盖所有可能性,这意味着可以将表达式与以下各项进行合理组合:

  • No entities at all: “My boyfriend wants to watch something tonight”

    根本没有实体:“我的男朋友今晚想看点东西”
  • One entity: “I want to watch a movie”

    一个实体:“我想看电影”
  • Many entities: “Can you recommend me some French drama TV shows?”

    许多实体:“您能推荐我一些法国戏剧电视节目吗?”

To tag your expressions, select the text you want to tag and type your entity name:

要标记表达式,请选择要标记的文本,然后输入实体名称:

You should add many more examples: 15 would be nice, but a production-ready bot would require at least 50 examples to perform well. To speed up the process you can fork the entities built within this bot [recording entity, genre entity] and then fork the discover intent from this bot.

您应该添加更多示例:15个示例会很好,但是一个生产就绪型机器人至少需要50个示例才能表现良好。 为了加快该过程,您可以派生在此bot内构建的实体[ 记录实体体裁实体 ],然后派发此bot发现意图

You can see here that “French” was detected as a nationality, not a language because that’s what it is in this context. When building the bot flow, we’ll make sure to check for these two entities.

您可以在此处看到“法语”被检测为国籍,而不是语言,因为在这种情况下就是这种情况。 在构建机器人流程时,我们将确保检查这两个实体。

添加自定义充实 (Adding custom enrichments)

Now that we have labeled have our entities we are going to enrich them! Open the entities panel from your bot under the training tab as shown below:

现在我们已经标记了我们的实体,我们将丰富它们! 在训练标签下的机器人上打开实体面板,如下所示:

Now let’s open the genre entity. If you look at the top right of the panel you should see a toggle saying free - restricted and settings. Open it so we can explain in details the different options you have access to:

现在让我们打开genre实体。 如果您在面板的右上方查看,应该会看到一个切换,显示free - restrictedsettings 。 打开它,以便我们详细解释您可以使用的不同选项:

Within the entity panel you have access to different options for your entity:

在实体面板中,您可以访问实体的不同选项:

  • Free vs Restricted — A free custom entity is used when you don’t have a strict list of values and want machine learning to detect all possible values. Whereas a restricted custom entity is used if you have a strict list of words to detect and don’t need automatic detection of the entity.

    释放vs受限-当您没有严格的值列表并且希望机器学习来检测所有可能的值时,将使用免费的自定义实体。 而如果您有严格的单词列表来检测并且不需要自动检测该实体,则使用受限的自定义实体。
  • Fuzzy matching — Fuzzy matching is an index between 0 and 1 to indicate how close a word can be from the one in your entity list of values. If the word is above this index then the platform will tag it as the closest value within your list.

    模糊匹配-模糊匹配是介于0和1之间的索引,用于指示单词与实体值列表中的一个单词有多接近。 如果单词高于该索引,则平台会将其标记为列表中最接近的值。
  • List of values — This is where you can add all the list of values of your entity which could be different values or synonyms

    值列表-您可以在此处添加实体的所有值列表,这些列表可以是不同的值或同义词

For more in-depth information about entities, you can read our detailed documentation.

有关实体的更深入信息,您可以阅读我们的详细文档

In our case, our genre entity is going to be restricted as theMovie Database API only manages a specific list of genres. Here is the list below:

在我们的案例中,我们的genre实体将受到restricted因为Movie Database API仅管理特定的流派列表。 以下是列表:

[ { id: 28, name: 'Action' }, { id: 12, name: 'Adventure' }, { id: 16, name: 'Animation' }, { id: 35, name: 'Comedy' }, { id: 80, name: 'Crime' }, { id: 99, name: 'Documentary' }, { id: 18, name: 'Drama' }, { id: 10751, name: 'Family' }, { id: 14, name: 'Fantasy' }, { id: 36, name: 'History' }, { id: 27, name: 'Horror' }, { id: 10402, name: 'Music' }, { id: 9648, name: 'Mystery' }, { id: 10749, name: 'Romance' }, { id: 878, name: 'Science Fiction' }, { id: 53, name: 'Thriller' }, { id: 10752, name: 'War' }, { id: 37, name: 'Western' } ]

Add all the different genres to our list of values. Don’t forget to also add synonyms such as SF, Sci-Fi for Science Fiction, Romantic for Romance or Animated, Cartoon for Animation. You can fetch the list of values from there.

将所有不同的流派添加到我们的值列表中。 别忘了还要添加同义词,例如SF,科幻小说中的科幻小说,浪漫史或动画中的浪漫小说,动画中的卡通漫画。 您可以从那里获取值列表。

As you can see from the JSON above, there are IDs associated with the genres. The reason is that the Movie Database can’t search for a specific genre based on its English name, but rather on a custom number. We can associate for each of the genre values a specific id that will be returned within the JSON of the NLP API. We can pass it on to the Movie Database API. This is the purpose of custom enrichments. Whenever an entity is detected, the JSON returned by the NLP API is enriched with additional information about the entity.

从上面的JSON中可以看到,存在与流派相关的ID。 原因是电影数据库无法根据其英文名称而是根据自定义编号来搜索特定类型。 我们可以为每个流派值关联一个特定的ID,该ID将在NLP API的JSON中返回。 我们可以将其传递给Movie Database API。 这是定制充实的目的。 每当检测到实体时,由NLP API返回的JSON都会丰富有关该实体的其他信息。

Within the custom enrichment panel we need to create 3 keys:

在自定义扩展面板中,我们需要创建3个键:

  • name – to map synonyms under the same value

    name -以相同的值映射同义词

  • id – to enrich with the id of the Movie Database

    id –丰富电影数据库的id

  • article – to add the article of the genre (we will use this later)

    article –添加该类型的文章(我们将在以后使用)

In order to add a custom enrichment click add new key and add the three keys listed above. For the article set the default key value to ‘a’ as most of the genres would be with ‘a’. Within name, you can start adding the specific enrichment and map it to all the different values for your article, id and name such as below:

为了添加自定义充实,单击add new key并添加上面列出的三个键。 对于本文,将默认键值设置为“ a”,因为大多数类型都将带有“ a”。 在名称中,您可以开始添加特定的功能并将其映射到您的articleidname所有不同值,如下所示:

You can fork the whole entity from this page which will include the enrichment. Now that this is done, let’s test it within the test console. If you send the sentence “I want to watch an animation movie” you now should now see the following custom enrichment:

您可以从此页面派生整个实体,其中包括充实。 现在已经完成了,让我们在测试控制台中对其进行测试。 如果发送句子“我想看动画电影”,则现在应该看到以下自定义充实内容:

"genre": [      {        "value": "animated",        "raw": "animated",        "confidence": 0.99,        "name": "animation",        "id": 16,        "article": "an"      }

Great, now our enrichment gives us the generic name, id, and the article! Let’s do the same thing for the recording entity. Go back to the entities panel and click on recording. Then make it restricted and add all possible values and synonyms for tv show and movie (such as tv shows, shows, motion picture, film, films, movies, etc.). See the entire list here. Now go to custom enrichments and add the key type and add 2 specific values:

太好了,现在我们的扩充功能为我们提供了通用名称,ID和文章! 让我们对记录实体做同样的事情。 返回到实体面板,然后单击录制。 然后使其受到限制,并为电视节目和电影(例如电视节目,节目,电影,电影,电影,电影等)添加所有可能的值和同义词。 在这里查看整个列表。 现在转到自定义扩充,添加密钥type并添加2个特定值:

  • movie – for all movies synonyms

    movie –所有电影的同义词

  • tv – for all tv shows synonyms

    tv –对于所有电视节目,同义词

It should look like this:

它看起来应该像这样:

Sending back our sentence “I want to watch an animation movie” we now also have the enrichment for recording:

回传我们的句子“我想看动画电影”,我们现在还可以进行录音:

"recording": [      {        "value": "movie",        "raw": "movie",        "confidence": 0.99,        "type": "movie"      }    ]

步骤2:建立漫游器流程 (Step 2: Building your bot flow)

Since we just need to make sure all our criteria are filled before calling a Node.JS API, the build part will be rather simple.

由于我们只需要确保在调用Node.JS API之前已满足所有条件,所以构建部分将非常简单。

We will just need one skill, let’s call it discover.

我们只需要一种技能,我们称之为discover

You can find an example of a configured skill here.

您可以在此处找到配置技能的示例。

扳机 (Triggers)

We want to trigger this skill if the intent @discover is present:

如果存在意图@discover,我们想触发此技能:

This tab helps you collect data before moving to Actions. We want to make sure the user specifies a recording, a genre, a language, and a yes or no intent before moving on:

此选项卡可帮助您在移至“ 操作”之前收集数据。 我们要确保用户在继续进行操作之前指定记录,类型,语言以及是或否意图。

The requirements will be checked one by one. They can all be fulfilled on the first message. For example, if the user says I want to watch a crime movie in English, then the Actions will be triggered immediately.

需求将被一一检查。 它们都可以在第一个消息上实现。 例如,如果用户说我想用英语观看犯罪电影 ,那么动作将立即触发。

For each Requirement, you can choose to send a message if it is complete or if it is missing.

对于每个需求,您可以选择发送一条完整的消息或丢失的消息。

Sending messages when a requirement is complete can make your bot more lively: A crime movie? I love them too!, but are almost mandatory when the requirement is missing: You need to ask your users to fill what you need to know.

完成要求后发送消息可以使您的机器人更加生动: 犯罪电影? 我也喜欢他们! ,但在缺少该要求时几乎是强制性的:您需要让用户填写您需要知道的内容。

For example, I send quick replies with suggested genres if #genre is missing:

例如,如果缺少#genre,我会发送带有建议类型的快速回复:

For the confirmation we are using the memory to display a dynamic message to validate the choice of the user using @yes and @no intent:

为了进行确认,我们使用内存显示动态消息,以使用@yes和@no intent验证用户的选择:

Once you have set up questions for the 4 groups of entities, go to the Actions tab.

为4组实体设置问题后,转到“ Actions标签。

动作 (Actions)

Once the requirements are fulfilled, we want to call our API to actually perform the search if the user said yes. Else we reset the memory and ask again what the user wants to watch.

满足要求后,如果用户说是,我们想调用我们的API来实际执行搜索。 否则,我们将重置记忆并再次询问用户想要观看的内容。

If _memory.no is present – reset the whole memory and send a message such as “Let’s start again, what do you want to watch?”

如果存在_memory.no ,请重置整个内存并发送诸如“让我们重新开始,您想观看什么?”之类的消息。

If _memory.yes is present create a CALL WEHBOOK action. You can either type a full URL (eg: https://mydomainname.com/discover-movies), or a relative URL (/discover-movies). SAP Conversational AI will use the parameter Bot base URL in your bot settings when you type a relative URL.

如果存在_memory.yes则创建CALL WEHBOOK操作。 您可以输入完整的URL(例如: https://mydomainname.com/discover-movies : https://mydomainname.com/discover-movies ),也可以输入相对的URL( /discover-movies )。 当您键入相对URL时,SAP Conversational AI将在机器人设置中使用参数Bot base URL URL。

Next, add an action UPDATE CONVERSATION > EDIT MEMORY > RESET ALL MEMORY to empty the memory once the call has been made.

接下来,添加一个操作UPDATE CONVERSATION > EDIT MEMORY > RESET ALL MEMORY,以在调用后清空内存。

If you don’t have a public server, or if you want to test your bot during development, ngrok is a very handy tool. It creates a public URL for you and forwards requests to your computer.

如果您没有公共服务器 ,或者要在开发过程中测试您的机器人,ngrok是一个非常方便的工具。 它为您创建一个公共URL,并将请求转发到您的计算机。

Once you installed it, run

安装后,运行

ngrok http 5000

And copy the Forwarding URL in HTTPS (https://XXX.ngrok.io) to your bot Settings (“Bot webhook base URL” field). All requests made to these URL will be forwarded to the port 5000 of your computer.

并将HTTPS (https://XXX.ngrok.io)中的Forwarding URL复制到您的漫游器设置(“ Bot webhook基本URL”字段)。 对这些URL的所有请求都将转发到计算机的端口5000。

All your bot needs now are its API to get your movies!

现在,您的机器人所需的全部就是获取电影的API!

第3步:创建电影机器人API (Step 3: Creating the movie bot API)

The NodeJS part of this bot is fairly simple: It will behave as an HTTP proxy between SAP Conversational AI and The Movie Database.

该机器人的NodeJS部分非常简单:它将充当SAP Conversational AI和The Movie Database之间的HTTP代理。

When your application receives a request from SAP Conversational AI, it sends a search query to the Movie Database with the criteria of your user and formats the JSON answer to the SAP Conversational AI message format.

当您的应用程序收到来自SAP Conversational AI的请求时,它将使用您的用户条件将搜索查询发送到电影数据库,并格式化SAP Conversational AI消息格式的JSON答案。

选项1:自动方式 (Option 1: the automatic way)

You can clone the entire project directly from our Git repository: https://github.com/plieb/movie-bot-skills-training

您可以直接从我们的Git存储库中克隆整个项目: https : //github.com/plieb/movie-bot-skills-training

选项2:手动方式 (Option 2: the manual way)

Step 1 — scaffolding your project

第1步-搭建项目

mkdir movie-bot && cd movie-botnpm initnpm install --save express body-parser axiostouch index.js config.jsmkdir discover-movies && cd discover-moviestouch index.js movieApi.jscd..

Step 2— getting a TMDb API token

第2步-获取TMDb API令牌

You will need a token to use the Movie Database API, go here to generate one, and edit your config.js file:

您需要一个令牌才能使用Movie Database API, 请转到此处生成一个令牌,然后编辑config.js文件:

module.exports = { MOVIEDB_TOKEN: process.env.MOVIEDB_TOKEN || 'PURYOURTOKENHERE', PORT: process.env.PORT || 5000, };

Step 3 — filling your index.js with an Express application Let’s create an Express application to handle the requests from SAP Conversational AI. To better organize our project, as seen in Step 1, we have a folder /discover-movies/ which contains the core of our bot code (instead of putting all our files in the same folder), and we call it through loadMovieRoute.

第3步—用Express应用程序填充index.js 让我们创建一个Express应用程序来处理来自SAP Conversational AI的请求。 为了更好地组织我们的项目,如步骤1所示,我们有一个文件夹/discover-movies/ ,其中包含我们的bot代码的核心(而不是将所有文件放在同一文件夹中),我们通过loadMovieRoute对其进行调用。

const express = require('express');const bodyParser = require('body-parser');const config = require('./config');const loadMovieRoute = require('./discover-movies');const app = express();app.use(bodyParser.json());loadMovieRoute(app);app.post('/errors', function(req, res) {  console.log(req.body);  res.sendStatus(200);});const port = config.PORT;app.listen(port, function() {  console.log(`App is listening on port ${port}`);});

Step 4 — filling discover-movies/index.js

第4步—填充discover-movies / index.js

We ask SAP Conversational AI to send a POST request to /discover-movies when a user has filled his search criteria.

当用户满足搜索条件时,我们要求SAP Conversational AI将POST请求发送到/discover-movies

The main goal of our controller is to pick and format the preferences from the memory to send them to the Movie Database’s API:

我们控制器的主要目标是从内存中选择首选项并设置其格式,以将其发送到电影数据库的API:

const config = require('../config'); const { discoverMovie } = require('./movieApi'); function loadMovieRoute(app) { app.post('/discover-movies', function(req, res) { console.log('[GET] /discover-movies'); const kind = req.body.conversation.memory['recording'].type; const genre = req.body.conversation.memory['genre'].id; const language = req.body.conversation.memory['language']; const nationality = req.body.conversation.memory['nationality']; const isoCode = language ? language.short.toLowerCase() : nationality.short.toLowerCase(); return discoverMovie(kind, genreId, isoCode) .then(function(carouselle) { res.json({ replies: carouselle, conversation: { } }); }) .catch(function(err) { console.error('movieApi::discoverMovie error: ', err); }); }); } module.exports = loadMovieRoute;

Step 5— filling discover-movies/movieApi.js

第5步—填充discover-movies / movieApi.js

Now that we have extracted and formatted all the filters of the request, we need to send the request to the Movie Database and format the answer:

现在我们已经提取并格式化了请求的所有过滤器,我们需要将请求发送到电影数据库并格式化答案:

const axios = require('axios');const config = require('../config');function discoverMovie(kind, genreId, language) {  return moviedbApiCall(kind, genreId, language).then(response =>    apiResultToCarousselle(response.data.results)  );}function moviedbApiCall(kind, genreId, language) {  return axios.get(`https://api.themoviedb.org/3/discover/${kind}`, {    params: {      api_key: config.MOVIEDB_TOKEN,      sort_by: 'popularity.desc',      include_adult: false,      with_genres: genreId,      with_original_language: language,    },  });}function apiResultToCarousselle(results) {  if (results.length === 0) {    return [      {        type: 'quickReplies',        content: {          title: 'Sorry, but I could not find any results for your request :(',          buttons: [{ title: 'Start over', value: 'Start over' }],        },      },    ];  }  const cards = results.slice(0, 10).map(e => ({    title: e.title || e.name,    subtitle: e.overview,    imageUrl: `https://image.tmdb.org/t/p/w600_and_h900_bestv2${e.poster_path}`,    buttons: [      {        type: 'web_url',        value: `https://www.themoviedb.org/movie/${e.id}`,        title: 'View More',      },    ],  }));  return [    {      type: 'text',      content: "Here's what I found for you!",    },    { type: 'carousel', content: cards },  ];}module.exports = {  discoverMovie,};

Step 6 — Start the engine!

步骤6 —启动引擎!

That’s all! You’re ready to test your bot.

就这样! 您已经准备好测试您的机器人了。

Start your application by running: node index.js

通过运行以下node index.js启动您的应用程序: node index.js

All being well, you should see: App started on port 5000

一切都很好,您应该看到: App started on port 5000

Movie recommendations, weather, health, traffic… With third-party APIs, everything is possible! Now that you’re familiar with the workflow, we can’t wait to hear from you about what you’re building! And remember, you’re very welcome to contact us if you need help, trough the comment section below or via Slack.

电影推荐,天气,健康状况,交通状况……借助第三方API,一切皆有可能! 现在您已经熟悉了工作流程,我们迫不及待地想听听您正在构建的内容! 请记住,如果您需要帮助,请通过下面的评论或通过Slack与我们联系。

Originally published on SAP Conversational AI blog.

最初发布在SAP Conversational AI博客上

翻译自: https://www.freecodecamp.org/news/how-to-build-a-movie-bot-with-sap-conversational-ai-and-nodejs-5d7221b83267/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值