代码详解|如何快速从硬盘里找到小电影?

代码详解|如何快速从硬盘里找到小电影?

看电影还要找豆瓣?别人的喜好怎能左右你的欢心~

豆瓣评分不靠谱,关键时刻得自己动手!

本文将手把手教你打造一个专属电影机器人,它能根据你的要求来推荐电影。科幻悬疑恐怖还是爱情文艺小清新,统统hold住!

本文基于SAP Conversational AI 来构建模型,并通过电影数据库 来获取电影信息。和简单的Q / A聊天机器人相比,与第三方API交互能实现更多有趣的案例。通过Bot Skills,我们添加了直接从构建器调用webhooks的选项,非常简单。

今天的机器人学习,分为以下步骤:

1.在句子中提取关键信息

2.构建机器人流程(触发,需求,操作)

3.创建并连接能从电影数据库中获取数据的 API

你需要一个SAP Conversational AI 帐户 ,Node.js ,测试时可能还需要Ngrok 。

代码详解|如何快速从硬盘里找到小电影?

代码详解|如何快速从硬盘里找到小电影?

1.在句中提取关键信息

“意图机制”有助于确定句子的整体含义。对实际运用而言,仅仅知道用户想看“某些”是不够的,我们需要知道用户想看“什么”。

“实体”被设计出来,正是旨在解决这个问题:它们可以在句子中提取关键信息。“意图机制”让你明白你必须做什么,而“实体”帮助你怎么做。

假设你是一家提供电话和互联网接入的电信公司,而机器人的意图是了解人们何时抱怨断网:

代码详解|如何快速从硬盘里找到小电影?

“实体”就可以从句中提取出关键信息。提取出的字符有助于了解“什么、哪里、何时”出了问题。

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

1. 用户想看什么(电影还是电视节目)

2. 用户想看的电影类别

3. 语种

代码详解|如何快速从硬盘里找到小电影?

2.使用“黄金实体”

为了加速开发进程,SAP Conversational AI可以默认提取多个实体:日期、位置、电话号码等。

在“language”实体中,名称旁的小星星就是黄金实体与普通实体的区别。

代码详解|如何快速从硬盘里找到小电影?

我们可以用这个实体解决第三个要求:电影语种。

代码详解|如何快速从硬盘里找到小电影?

3.创建自定义实体

创建自定义实体,可以有效提取我们所需要的信息。与“意图”一样,训练非常重要:添加到机器人的示例越多,获得的样本准确性就越高。

你可以通过多种意图对实体进行训练:

对电影机器人而言,只需要1个意图discover和2个实体:

• recording并识别用户想看电影还是电视节目

• genre(观看类别)

打开你的意图“discover”,添加表达式,一定要确保表达式包含了所有可能情况,如:

• 无实体:“我男朋友今晚想看点东西”

• 一个实体:“我想看一部电影”

• 多个实体:“你能给我推荐一些法国戏剧电视节目吗?”

要想标记表达式,请选择要标记的文本,并输入实体名称。

代码详解|如何快速从硬盘里找到小电影?

15个示例虽然可以,但应该添加更多的示例。生产就绪的机器人需要至少50个示例,才能表现良好。为了加快过程,你可以把机器人 中构建的实体[记录实 体 ,派别 实体 ]进行分叉,然后在机器中发现意图 。

你可以发现,在这里“法国”被检测为国籍,而不是语种,因为这就是实体在这种情况下的含义。在构建bot流程时,我们将确保检查这两个实体。

代码详解|如何快速从硬盘里找到小电影?

4.添加自定义进行丰富

我们已经标记了实体,现在让它们更丰富一些吧! 在训练选项卡下打开机器人中的实体面板,如下所示:

代码详解|如何快速从硬盘里找到小电影?

现在,打开genre实体。如果你注意一下面板的右上角,你会看到一个切换:free - restricted and settings。打开它,以便我们对你可以访问的不同选项进行详细解释:

代码详解|如何快速从硬盘里找到小电影?

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

• Free与Restricted——你没有严格的值列表,但你希望机器学习能检测到所有可能的值,这时使用免费的(Free)自定义实体。然而,如果你有严格的单词列表要检测,则使用受限制的自定义实体不需要自动检测实体。

• 模糊匹配——模糊匹配是0和1之间的索引,用于表示单词与实体值列表中单词的接近程度。如果单词在此索引之外,平台则会按照列表中最接近的值,对它进行标记。

• 值列表——你可以在此处添加实体的所有值列表,可以是不同的值,或者同义词。

在我们的例子中,我们的genre实体将受到限制,因为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' }

把所有的类型添加到我们的值列表中,但不要忘记添加同义词,如科幻小说(SF,Sci-Fi),浪漫主义(Romantic)或卡通动画(AnimatedCartoon)等。你会发现,正如JSON中那样,会有一系列ID与类型相关联,因为电影数据库无法根据英文名称搜索特定类型,而只能搜索自定义数字。我们可以做的,就是为每个类型值关联一个特定的id,它将在NLP API的JSON中执行返回,这样我们就可以将它传递给Movie Database API。这就是丰富自定义的目的:每当检测到实体时,从NLP API返回的JSON都会添加有关该实体的信息。

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

• name——在同一值下映射同义词

• id——丰富电影数据库的id

• article——添加该类型的文章(稍后我们将用到它)

要添加自定义,请单击add new key 并添加上面列出的三个键——关于article,将默认键值设置为“a”,因为大多数类型都使用“a”。在name中,你可以开始添加特定的内容并将所有不同的值映射到name、ID、article中,如下所示:

代码详解|如何快速从硬盘里找到小电影?

代码详解|如何快速从硬盘里找到小电影?

代码详解|如何快速从硬盘里找到小电影?

你可以从此页面开始,分叉整个实体,其中包括丰富的自定义部分。既然已经完成了,就可以在测试控制台中测试一下。假设发送句子“我想看动画电影”,你应该可以看到以下自定义内容:

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

现在这些添加为我们提供了通用名称,ID和Article。我们会以同样的方法操作录音实体。返回实体面板并单击录音,然后进行限制,并为电视节目和电影添加所有可能的值和同义词(如tv shows, shows, motion picture, film, films, movies等等)。

现在转到自定义丰富界面并添加Key选项,赋2个特定值:

• movie -所有电影的同义词

• tv - 所有电视节目的同义词

就像这样:

代码详解|如何快速从硬盘里找到小电影?

发回我们的句子:“我想看一部动画电影”,我们便有了录音的丰富内容:

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

代码详解|如何快速从硬盘里找到小电影?

5.建立你的机器人流程

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

我们只需要一种技能 —— Discover。

5.1触发器

如果意图@Discover已经存在,我们将触发它:

代码详解|如何快速从硬盘里找到小电影?

5.2要求

此选项卡可帮助你在操作之前收集数据。我们希望确保用户在继续之前指定录音、类别、语种以及意图的是否:

代码详解|如何快速从硬盘里找到小电影?

这些要求将被逐一检查,它们都可以在第一条消息上实现。例如,如果用户说“我观看英语犯罪电影”,会立即触发操作。

对于每个要求,你都可以选择在消息完成或缺失时发送消息。

在要求完成后发送消息,可以让机器人更生动:“一部犯罪电影?我也爱他们!”但是,当缺少要求时,它们几乎是强制性的:你需要让用户告诉你想要的内容。

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

代码详解|如何快速从硬盘里找到小电影?

为了确认,我们将使用内存来显示动态消息,以验证用户对意图的选择@yes还是@no:

代码详解|如何快速从硬盘里找到小电影?

(使用内存显示动态消息)

一旦4组实体的问题都设置完毕,你就可以进行Actions了。

5.3操作(Actions)

一旦满足要求,如果用户说是,我们将调用API来实际执行搜索,否则我们会重置内存并再次询问用户想观看什么。

如果_memory.no存在,请重置整个内存并发送消息,例如“让我们重新开始,你想看什么?”

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

接下来,添加操作(actions)UPDATE CONVERSATION> EDIT MEMORY> RESET ALL MEMORY,以在调用完成后清空内存。

代码详解|如何快速从硬盘里找到小电影?

(操作)

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

安装后,运行...

ngrok http 5000

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

现在,机器人只需要API来获取电影了!

代码详解|如何快速从硬盘里找到小电影?

6.创建Movie Bot API

机器人的NodeJS部分非常简单,它将作为SAP会话AI和电影数据库之间的HTTP代理。

当你的应用程序收到来自SAP Conversational AI的请求时,它会根据用户标准向电影数据库发送搜索查询,并将JSON答案格式化为SAP Conversational AI消息格式。

代码详解|如何快速从硬盘里找到小电影?

选择1:自动操作

你可以直接从Git存储库复制整个项目:https://github.com/plieb/movie-bot-skills-training .

选择2:手动操作

第一步:支持你的项目

mkdir movie-bot && cd movie-bot
npm init
npm install --save express body-parser axios
touch index.js config.js
mkdir discover-movies && cd discover-movies
touch index.js movieApi.js
cd..

第二步:获取TMDb API令牌

你将需要一个令牌来使用Movie Database API,然后编辑你的config.js文件:

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

第三步:使用Express应用程序填充index.js

让我们创建一个Express应用程序来处理来自SAP Conversational AI的请求。为了更好地组织项目,如第1步所示,我们有一个文件夹/ discover-movies /,包含了我们机器人代码的核心(不是将所有文件放在同一个文件夹中),我们通过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}`);
});

第四步:填写discover-movies / index.js

当用户填写搜索条件时,我们要求SAP Conversational AI向/ discover-movies发送POST请求。

控制器的主要目标是从内存中选择和格式化首选项,以将它们发送到电影数据库的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;

第五步:填写 discover-movies/movieApi.js

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

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,
};

第六步:启动吧!

就这样! 准备好测试你的机器人。

运行:启动应用程序 —— node index.js

一切顺利,你应该会看到: App started on port 5000

电影推荐,天气,健康,交通...使用第三方API,一切皆有可能!

代码详解|如何快速从硬盘里找到小电影?

相关推荐