最近由于要参加微软亚洲研究院的夏令营,需要利用微软的服务搭建一个对话Bot,以便对俱乐部的情况进行介绍,所以现学了几天,搭建了一个简单的对话Bot,期间参考了大量的资料,尤其是下面的这篇博客:

http://www.cnblogs.com/rocsheh/p/5846009.html

实现的大致效果是可以询问微软俱乐部的相关情况,并且查询天气。效果演示如下:

下面我会将整个过程进行详细的表述。

1. 什么是Bot Framework?

Bot Framework就是帮你快速搭建智能服务的后端,快速在各种终端和服务上提供服务。包括三大组件。

Bot Builder SDKs:

这个是Bot的生成器,快速生成一个ASP.NET和Node.js的后端服务,提供了像Dialog、FormFlow帮你管理与用户的会话。

Bot Connector:

这是个Bot的Channel,帮你把你的服务快速发布到各个渠道,比如说Skype,Facebook Messager等等。这样用户就可以在Skype等Channel上使用你的服务了。

Bot Directory:

这个算是Bot 的商店,在这里可以找到各个bot,你也可以把自己的Bot发布出来,从而大家都可以看到你的Bot。

官方网址:https://docs.microsoft.com/zh-cn/bot-framework,用你的微软账户登录就行。

界面如图所示:

2. 什么是LUIS?

说到LUIS,我们首先谈一下Cognitive Services(认知服务)。

Cognitive Services(认知服务)的前身是Project Oxford(牛津计划),正式发布的时候更名的。这是微软将研究院研究的技术以API和SDK的形式开放给开发者的一系列智能化服务。

主要包括5大类的服务:视觉、语言、语言、知识和搜索。

其实就包括我们今天要讲的"语言理解(Language Understanding Intelligent Service,简称LUIS)"。

LUIS的官网介绍:https://www.luis.ai,用你的微软账户登录就行。

界面如图所示:

点击"App"这一栏,咱们先点击"new App"新建一个app。

新建完成后,点击应用的名称,进入编辑这个应用。

我们先看以下左边的tab,可以看到有仪表盘,意图(Intents),实体(Entities),功能以及发布应用。。。。

Intents:就是意图,比如咱们现在要提供天气查询的服务,那么咱们就创建一个"查询天气"的Intent。

实体里头有两类:

Entities:实体,比如在查询天气的时候需要有地理位置信息,需要把用户的语言里头的地点提取出来,这个地点就是这个句子里头的实例,咱们创建一个"地点"的实例。

Pre-built Entities(预建实体):这个是预置好的实例,比如说时间,数字等等,我加了一个datetime的预置实例。

在功能里头会有:

Phrase List Features(短语列表功能):固定的一些短语,能够直接识别,比如说航空公司的名字等已知信息

Pattern Features(模式功能):正则表达式,可以匹配出相应的一些字段,比如说航班号。

咱们现在来创建一个能够识别查询天气的语言理解服务。

首先,查询天气需要地点信息,咱们先创建一个"地点"的实例。

点击到“实体”里头,“添加自定义实体”:

添加一个“预建实体” datetime:

再创建一个叫做"查询天气"的Intent。

点击save之后会出现以下界面:

在“句式”中,输入几个例子,比如说“北京天气怎么样”,可以多输入几个句子的类型,比如“北京今天有雾霾吗?”等等,没输入完一句按一下回车。

如果北京等地点信息没有显示标记的话,选中北京两个字,然后选择"地点"标注。然后点击"保存"。

之后点击"发布应用",点击该界面里头的"Train"按钮。

开始训练,可能需要点时间,你可以做点其他事情。

训练完成之后,Publish按钮,发布成api的形式。

大家可以看到有“Endpoint url”这个选项,这个url后面加上查询语句就是API了。

如:https://westus.api.cognitive.microsoft.com/luis/v2.0/apps/LUIS_APP_ID?subscription-key=LUIS_subscription-key&timezoneOffset=0.0&verbose=true&q=北京今天天气怎么样?

把LUIS的ID(就是apps后面那串字符)和subscription-key记下来,后面需要用到。

在URL后面可以输入相关的语句,然后回车,就可以看到返回的json字符串了。

3. 什么是QnA Maker?

QnA Maker可以创建、训练并发布一个基于问题对的智能匹配,可以通过简单的训练来组织问题对,特别适合处理的就是标准问答的形式,比如“微软学生俱乐部是什么?”“如何加入微软俱乐部?”等等,后面匹配上标准的答案。

官方网址:https://qnamaker.ai

界面如下:

第一次进入,我们点击Create new Service,进入创建界面。

SERVICE NAME:随便起,我起的BOPdemo。

FAQ URL(S):如果你有相关的URL,可以填写,没有可以不写。样式参考:http://studentclub.msra.cn/bop2017/qa这种格式。

FAQ FILES:如果有相关文件可以直接导入,没有可以不导入,因为最后还可以手动导入。样例文件如下:

中间记得用tab键隔开。至此,就创建完了。

创建完了之后,你会发现在My services多了一个刚才创建的服务,如下:

点进去之后,效果如图:

还可以通过Add new QnA pair添加单独的问题对。添加完了之后别忘了Save and retrain,之后你就可以通过Test进行测试,比如我输入Hi,机器人回复Hello。

通过URL,File以及单独添加的问题对都训练完并且测试满足条件之后,你就可以Publish发布了。

这时你肯定想问,怎么通过自己的代码进行访问啊?我以C#为例:参考文档:https://qnamaker.ai/Documentation/ApiReference

Publish之后,会形成如下HTTP样式:

POST /knowledgebases/<Your KB ID>/generateAnswer HTTP/1.1Host: https://westus.api.cognitive.microsoft.com/qnamaker/v1.0
Ocp-Apim-Subscription-Key: <Your Subscription key>Content-Type: application/json
Cache-Control: no-cache
{"question": "Question goes here"}

请求的代码:

string responseString = string.Empty;var query = “hi”; //User Query
var knowledgebaseId = “YOUR_KNOWLEDGE_BASE_ID”; //Use knowledge base id created.
var qnamakerSubscriptionKey = “YOUR_SUBSCRIPTION_KEY”; //Use subscription key assigned to you.//Build the URI
Uri qnamakerUriBase = new Uri("https://westus.api.cognitive.microsoft.com/qnamaker/v1.0");var builder = new UriBuilder($"{qnamakerUriBase}/knowledgebases/{knowledgebaseId}/generateAnswer");//Add the question as part of the body
var postBody = $"{{\"question\": \"{query}\"}}";//Send the POST request
using (WebClient client = newWebClient())
{//Set the encoding to UTF8client.Encoding =System.Text.Encoding.UTF8;//Add the subscription key headerclient.Headers.Add("Ocp-Apim-Subscription-Key", qnamakerSubscriptionKey);client.Headers.Add("Content-Type", "application/json");responseString=client.UploadString(builder.Uri, postBody);
}

View Code

得到的响应格式是JSON,如下:

{ "Answer": "Sample response", "Score": "0" }

处理响应的代码:

usingNewtonsoft.Json;private classQnAMakerResult
{/// <summary>///The top answer found in the QnA Service./// </summary>[JsonProperty(PropertyName = "answer")]public string Answer { get; set; }/// <summary>///The score in range [0, 100] corresponding to the top answer found in the QnA    Service./// </summary>[JsonProperty(PropertyName = "score")]public double Score { get; set; }
}//De-serialize the response
QnAMakerResult response;try{response= JsonConvert.DeserializeObject< QnAMakerResult >(responseString);
}catch{throw new Exception("Unable to deserialize QnA Maker response string.");
}

View Code

4. 开发流程

1) 首先获取Bot Builder SDK和Bot模拟器

可以去https://docs.microsoft.com/en-us/bot-framework/resources-tools-downloads进行参考。

首先,请下载Bot Framework的SDK,建议下载Bot Framework的Visual Studio的模板Bot Application。

下载下来的模板(不用解压)请直接放置到C:\Users\你的用户名\Documents\Visual Studio 2017\Templates\ProjectTemplates\Visual C# 下面,这样你在C#下面就可以看到有Bot Application的模板了。

如果是使用NuGet来下载SDK,请参考:

  1. 右键你的C#项目,选择"Manage NuGet Packages".
  2. 在"Browse"的tab页,输入"Microsoft.Bot.Builder".
  3. 点击"Install"的按钮.

下载模拟器的地址为:https://github.com/Microsoft/BotFramework-Emulator/releases/tag/v3.5.31

选择.exe那个,直接下一步,下一步就行了。

2)创建一个新项目

快速开始,参考:https://docs.microsoft.com/en-us/bot-framework/dotnet/bot-builder-dotnet-quickstart

创建完之后,默认就是一个完整的项目,可以直接运行。直接点击运行,会打开一个web页面,地址栏如下:

打开模拟器输入URL:http://localhost:3979/api/messages

直接点击Connect即可。此时,你输入一段话,对方就会回一段话,显示你发送的内容,并说明这句话有多少字符。

这个基本的模型就建好了。

看一下项目目录,我们需要写的就是在Dialogs文件夹下新建Dialog,每次新增完在Controllers文件夹下的MessagesController.cs中记得更改一下,如图:

3)将应用发布到Azure云

首先注册中国区Azure云并申请1元订阅。

第一步:搜索引擎输入关键字“世纪互联Azure”,进入世纪互联azure官网,并点击申请试用,如下图红色框所示

图1:中国区Azure官网页面

第二步:点击申请试用后,弹出链接,填写电话号码与手机收到的验证码。

第三步:填写完验证码后将弹出下图页面,将必要信息填入到网页中。身份证正反面扫描件或者照片均可,建议选手在身份证正反面照片中打上水印,如“仅限申请Azure账户使用”,但不应该遮蔽身份证号码等必要的验证信息。

图2:Azure试用申请表

第四步:提交之后,你将收到一封邮件(可能稍有延迟)。打开你上图中填写的邮箱,查看主题为“Azure一元试用激活码”的邮件,邮件正文如下图所示:

图3:Azure一元试用激活码邮件内容

第五步:执行邮件的正文中的第一步“点击进入输入激活码页”

第六步:执行邮件正文中的第二步,创建用户账号并付费完成注册。第七步的具体过程如下:

  • 点击邮件中的链接进入如下界面,填写相关信息,由此生成登录账号。

    图4:填写信息

  • 设置账号密码(密码需要包含大小写字母、符号和数字),并填写手机号获取验证码。

    图5:填写信息

  • 自动跳转登录界面,输入密码登录。

    图6:登录页面

  • 选择支付宝,支付一元钱。

    图7:一元订阅支付页面

第七步:收到主题为“由世纪互联运营的 Windows Azure 购买确认”邮件以及主题为“欢迎使用 Windows Azure Active Directory”表示azure注册成功。具体图片分别如下图8和9所示:

图8:邮件主题为“由世纪互联运营的 Windows Azure 购买确认”截图

图9:邮件主题为“欢迎使用 Windows Azure Active Directory”截图

申请完之后,需要用VS链接到中国区Azure,参考:

https://www.azure.cn/documentation/articles/developerdifferences/

也许这一块你还会有其他很多问题,别着急,在http://studentclub.msra.cn/bop2017/qa肯定能找到答案。

回到VS,点击项目名,右键,发布,最后效果:

此时已经部署到云了。

4)在Bot Framework网站上注册应用

登录 Bot Fraework网站,https://dev.botframework.com/ 如果你还没有账号,请先注册一个。

点击"Register a Bot"https://dev.botframework.com/bots/new 注册一个

填写相关的信息:

"Name":你的bot的名字,比如我的叫做"萌萌"。

"Bot Handle":随便写一串字母,比如我的写"mengmeng",其实就是你的Bot的id。

"Description":你的Bot的描述,会在你的publish之后主页上显示。

下面需要填写你的endpoint,就是你后台服务的地址:https://你的服务器地址/api/messages (刚才咱们发布的template的默认接口)

你需要点击"Create Microsoft App ID and password",创建App ID和Password(注意,切记把这个app password记下来,只显示一次)

下面的必填的一些选项随便填一下就可以了。

点击保存。

在右边的"Channels"里头可以看到"Web Chat",这个网页端的一个channel,已经帮你写好的一个frame,咱们点击"Edit"更新。

生成Web Chat的密钥之后,把密钥复制,点击"I'm done configuring Web Chat"。

5)更新你的后端服务

在你的Web.config里,填上你的botId,刚才创建的App ID和app password。

打开网站的起始页default.htm

复制以下代码:

<!DOCTYPE html>
<metaname="viewport"content="width=device-width, initial-scale=1, maximum-scale=1">
<html>
<head>
<title>小驰</title>
<metacharset="utf-8" />
</head>
<bodystyle="font-family:'Segoe UI'">
<iframename="myframe"scrolling="auto"width="100%"height="100%"onload="document.all['myframe'].style.height=myframe.document.body.scrollHeight"src="https://webchat.botframework.com/embed/mengmeng?s=你 自 己 的 Web Chat 密 钥 "style="height: 502px; max-height: 502px;"></iframe>
</body>
</html>

然后右键项目工程,点击"publish",之后你就可以拥有一个简单的Bot啦。

注意:此时你再想通过模拟器调试,需要加上app id和password了。

5. 核心代码

github地址:https://github.com/DarrenChanChenChi/Microsoft-Bot

MengmengDialog.cs:

usingBOPdemo.Models;usingMicrosoft.Bot.Builder.Dialogs;usingMicrosoft.Bot.Builder.Luis;usingMicrosoft.Bot.Builder.Luis.Models;usingMicrosoft.Bot.Connector;usingNewtonsoft.Json;usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Net;usingSystem.Threading.Tasks;usingSystem.Web;namespaceBOPdemo.Dialogs
{[LuisModel("c26cbbd3-4ee0-4487-a585-e9c17fd1ac40", "857c6cd0cf2744deb8f91b434379582d")][Serializable]//https://westus.api.cognitive.microsoft.com/luis/v2.0/apps/c26cbbd3-4ee0-4487-a585-e9c17fd1ac40?//subscription-key=857c6cd0cf2744deb8f91b434379582d&timezoneOffset=0&verbose=true&q=public class MengmengDialog : LuisDialog<object>{publicMengmengDialog(){}publicMengmengDialog(ILuisService service):base(service){}[LuisIntent("")][LuisIntent("None")]public asyncTask None(IDialogContext context, LuisResult result){/**string message = $"小驰不知道你在说什么,面壁去。。。我现在只会查询天气。。T_T" + string.Join(", ", result.Intents.Select(i => i.Intent));await context.PostAsync(message);context.Wait(MessageReceived);*///var activity = await result as Activity;//calculate something for us to return//int length = (activity.Text ?? string.Empty).Length;//return our reply to the user//await context.PostAsync($"You sent {activity.Text} which was {length} characters");//await context.PostAsync("你好");/*** 发送**/string responseString = string.Empty;var query = result.Query; //User Queryvar knowledgebaseId = "a00256ee-9316-4476-9fcb-0f6f7e10f8b6"; //Use knowledge base id created.var qnamakerSubscriptionKey = "417cc12cef9a4b64835b84b657dc4d73"; //Use subscription key assigned to you.//Build the URIUri qnamakerUriBase = new Uri("https://westus.api.cognitive.microsoft.com/qnamaker/v1.0");var builder = new UriBuilder($"{qnamakerUriBase}/knowledgebases/{knowledgebaseId}/generateAnswer");//Add the question as part of the bodyvar postBody = $"{{\"question\": \"{query}\"}}";//Send the POST requestusing (WebClient client = newWebClient()){//Set the encoding to UTF8client.Encoding =System.Text.Encoding.UTF8;//Add the subscription key headerclient.Headers.Add("Ocp-Apim-Subscription-Key", qnamakerSubscriptionKey);client.Headers.Add("Content-Type", "application/json");responseString=client.UploadString(builder.Uri, postBody);}/*** 接收**///De-serialize the response
QnAMakerResult response;try{response= JsonConvert.DeserializeObject<QnAMakerResult>(responseString);}catch{throw new Exception("Unable to deserialize QnA Maker response string.");}string answer =response.Answer;if (answer.Equals("No good match found in the KB")){await context.PostAsync("小驰不知道你在说什么,面壁去。。。我现在只会介绍微软俱乐部信息和查询天气。。T_T");}else{awaitcontext.PostAsync(answer);}//await context.PostAsync(response.Score+"");//原来的
context.Wait(MessageReceived);}public bool TryToFindLocation(LuisResult result, outString location){location= "";EntityRecommendation title;if (result.TryFindEntity("地点", outtitle)){location=title.Entity;}else{location= "";}return !location.Equals("");}[LuisIntent("查询天气")]public asyncTask QueryWeather(IDialogContext context, LuisResult result){string location = "";string replyString = "";if (TryToFindLocation(result, outlocation)){replyString= awaitGetWeather(location);awaitcontext.PostAsync(replyString);context.Wait(MessageReceived);}else{awaitNone(context, result);}//else//{//await context.PostAsync("亲你要查询哪个地方的天气信息呢,快把城市的名字发给我吧");//context.Wait(AfterEnterLocation);//}
}private async Task<string> GetWeather(stringcityname){WeatherData weatherdata= awaitBOPdemoTask.GetWeatherAsync(cityname);if (weatherdata == null || weatherdata.HeWeatherdataservice30 == null){return string.Format("呃。。。萌萌不知道\"{0}\"这个城市的天气信息", cityname);}else{HeweatherDataService30[] weatherServices=weatherdata.HeWeatherdataservice30;if (weatherServices.Length <= 0) return string.Format("呃。。。萌萌不知道\"{0}\"这个城市的天气信息", cityname);Basic cityinfo= weatherServices[0].basic;if (cityinfo == null) return string.Format("呃。。。萌萌目测\"{0}\"这个应该不是一个城市的名字。。不然我咋不知道呢。。。", cityname);String cityinfoString= "城市信息:" + cityinfo.city + "\n\n"+ "更新时间:" + cityinfo.update.loc + "\n\n"+ "经纬度:" + cityinfo.lat + "," + cityinfo.lon + "\n\n";Aqi cityAirInfo= weatherServices[0].aqi;String airInfoString= "空气质量指数:" + cityAirInfo.city.aqi + "\n\n"+ "PM2.5 1小时平均值:" + cityAirInfo.city.pm25 + "(ug/m³)\n\n"+ "PM10 1小时平均值:" + cityAirInfo.city.pm10 + "(ug/m³)\n\n"+ "二氧化硫1小时平均值:" + cityAirInfo.city.so2 + "(ug/m³)\n\n"+ "二氧化氮1小时平均值:" + cityAirInfo.city.no2 + "(ug/m³)\n\n"+ "一氧化碳1小时平均值:" + cityAirInfo.city.co + "(ug/m³)\n\n";Suggestion citySuggestion= weatherServices[0].suggestion;String suggestionString= "生活指数:" + "\n\n"+ "穿衣指数:" + citySuggestion.drsg.txt + "\n\n"+ "紫外线指数:" + citySuggestion.uv.txt + "\n\n"+ "舒适度指数:" + citySuggestion.comf.txt + "\n\n"+ "旅游指数:" + citySuggestion.trav.txt + "\n\n"+ "感冒指数:" + citySuggestion.flu.txt + "\n\n";Daily_Forecast[] cityDailyForecast= weatherServices[0].daily_forecast;Now cityNowStatus= weatherServices[0].now;String nowStatusString= "天气实况:" + "\n\n"+ "当前温度(摄氏度):" + cityNowStatus.tmp + "\n\n"+ "体感温度:" + cityNowStatus.fl + "\n\n"+ "风速:" + cityNowStatus.wind.spd + "(Kmph)\n\n"+ "湿度:" + cityNowStatus.hum + "(%)\n\n"+ "能见度:" + cityNowStatus.vis + "(km)\n\n";return string.Format("现在{0}天气实况:\n\n{1}", cityname, cityinfoString + nowStatusString + airInfoString +suggestionString);}}}
}

View Code

WeatherModel.cs:

usingNewtonsoft.Json;usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Web;namespaceBOPdemo.Models
{public classWeatherData{[JsonProperty(PropertyName= "HeWeather data service 3.0")]public HeweatherDataService30[] HeWeatherdataservice30 { get; set; }}public classHeweatherDataService30{public Aqi aqi { get; set; }public Basic basic { get; set; }public Daily_Forecast[] daily_forecast { get; set; }public Hourly_Forecast[] hourly_forecast { get; set; }public Now now { get; set; }public string status { get; set; }public Suggestion suggestion { get; set; }}public classAqi{public City city { get; set; }}public classCity{public string aqi { get; set; }public string co { get; set; }public string no2 { get; set; }public string o3 { get; set; }public string pm10 { get; set; }public string pm25 { get; set; }public string qlty { get; set; }public string so2 { get; set; }}public classBasic{public string city { get; set; }public string cnty { get; set; }public string id { get; set; }public string lat { get; set; }public string lon { get; set; }public Update update { get; set; }}public classUpdate{public string loc { get; set; }public string utc { get; set; }}public classNow{public Cond cond { get; set; }public string fl { get; set; }public string hum { get; set; }public string pcpn { get; set; }public string pres { get; set; }public string tmp { get; set; }public string vis { get; set; }public Wind wind { get; set; }}public classCond{public string code { get; set; }public string txt { get; set; }}public classWind{public string deg { get; set; }public string dir { get; set; }public string sc { get; set; }public string spd { get; set; }}public classSuggestion{public Comf comf { get; set; }public Cw cw { get; set; }public Drsg drsg { get; set; }public Flu flu { get; set; }public Sport sport { get; set; }public Trav trav { get; set; }public Uv uv { get; set; }}public classComf{public string brf { get; set; }public string txt { get; set; }}public classCw{public string brf { get; set; }public string txt { get; set; }}public classDrsg{public string brf { get; set; }public string txt { get; set; }}public classFlu{public string brf { get; set; }public string txt { get; set; }}public classSport{public string brf { get; set; }public string txt { get; set; }}public classTrav{public string brf { get; set; }public string txt { get; set; }}public classUv{public string brf { get; set; }public string txt { get; set; }}public classDaily_Forecast{public Astro astro { get; set; }public Cond1 cond { get; set; }public string date { get; set; }public string hum { get; set; }public string pcpn { get; set; }public string pop { get; set; }public string pres { get; set; }public Tmp tmp { get; set; }public string vis { get; set; }public Wind1 wind { get; set; }}public classAstro{public string sr { get; set; }public string ss { get; set; }}public classCond1{public string code_d { get; set; }public string code_n { get; set; }public string txt_d { get; set; }public string txt_n { get; set; }}public classTmp{public string max { get; set; }public string min { get; set; }}public classWind1{public string deg { get; set; }public string dir { get; set; }public string sc { get; set; }public string spd { get; set; }}public classHourly_Forecast{public string date { get; set; }public string hum { get; set; }public string pop { get; set; }public string pres { get; set; }public string tmp { get; set; }public Wind2 wind { get; set; }}public classWind2{public string deg { get; set; }public string dir { get; set; }public string sc { get; set; }public string spd { get; set; }}
}

View Code

BOPdemoTask.cs:

usingBOPdemo.Models;usingNewtonsoft.Json;usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Net;usingSystem.Text;usingSystem.Threading.Tasks;usingSystem.Web;namespaceBOPdemo
{public classBOPdemoTask{public static async Task<double?> GetStockRateAsync(stringStockSymbol){try{string ServiceURL = $"http://finance.yahoo.com/d/quotes.csv?s={StockSymbol}&f=sl1d1nd";stringResultInCSV;using (WebClient client = newWebClient()){ResultInCSV= await client.DownloadStringTaskAsync(ServiceURL).ConfigureAwait(false);}var FirstLine = ResultInCSV.Split('\n')[0];var Price = FirstLine.Split(',')[1];if (Price != null && Price.Length >= 0){doubleresult;if (double.TryParse(Price, outresult)){returnresult;}}return null;}catch(WebException ex){//handle your exception herethrowex;}}public static async Task<WeatherData> GetWeatherAsync(stringcity){try{string ServiceURL = $"https://free-api.heweather.com/x3/weather?city={city}&key=e8c9a95d0a0f4d2092def1174c44be17";stringResultString;using (WebClient client = newWebClient()){client.Encoding=Encoding.UTF8;ResultString= await client.DownloadStringTaskAsync(ServiceURL).ConfigureAwait(false);}WeatherData weatherData= (WeatherData)JsonConvert.DeserializeObject(ResultString, typeof(WeatherData));returnweatherData;}catch(WebException ex){//handle your exception here//throw ex;return null;}}}
}

View Code

QnAMakerResult.cs:

usingNewtonsoft.Json;usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Web;namespaceBOPdemo.Models
{public classQnAMakerResult{/// <summary>///The top answer found in the QnA Service./// </summary>[JsonProperty(PropertyName = "answer")]public string Answer { get; set; }/// <summary>///The score in range [0, 100] corresponding to the top answer found in the QnA    Service./// </summary>[JsonProperty(PropertyName = "score")]public double Score { get; set; }}
}

View Code

学习资料:

http://studentclub.msra.cn/bop2017/qa

http://studentclub.msra.cn/bop2017/rules/learning

转载于:https://www.cnblogs.com/DarrenChan/p/7301380.html

手把手教你利用微软的Bot Framework,LUIS,QnA Maker做一个简单的对话机器人相关推荐

  1. jade怎么查计算机用户名,干货 | 黄继武老师手把手教你利用Jade进行物相检索

    原标题:干货 | 黄继武老师手把手教你利用Jade进行物相检索 前言 Jade是一个32位Windows程序,用于处理X射线衍射数据.除基本的如显示图谱.打印图谱.数据平滑等功能外,主要功能有物相检索 ...

  2. 华为表哥手把手教你利用Jenkins持续集成iOS项目,教不会我花式拉翔!!!

    手把手教你利用Jenkins持续集成iOS项目: 前言 众所周知,现在App的竞争已经到了用户体验为王,质量为上的白热化阶段.用户们都是很挑剔的.如果一个公司的推广团队好不容易砸了重金推广了一个APP ...

  3. 【玩转华为云】手把手教你利用ModelArts识别偶像的声音

    本篇推文共计2000个字,阅读时间约3分钟. 华为云-华为公司倾力打造的云战略品牌,2011年成立,致力于为全球客户提供领先的公有云服务,包含弹性云服务器.云数据库.云安全等云计算服务,软件开发服务, ...

  4. 手把手教你利用 python 爬虫分析基金、股票

    手把手教你利用 python 爬虫分析基金.股票 文章目录 手把手教你利用 python 爬虫分析基金.股票 第一步:基金数据爬取 第二步:股票增持计算 第三步:好股基金选取 桌面程序 exe 从前大 ...

  5. 小白必看、手把手教你利用爬虫爬网页

    接下来从网络爬虫的概念.用处与价值和结构等三个方面,让大家对网络爬虫有一个基本的了解. 网络爬虫及其应用 随着网络的迅速发展,万维网成为大量信息的载体,如何有效地提取并利用这些信息成为一个巨大的挑战, ...

  6. 【玩转华为云】手把手教你利用ModelArts实现人脸年龄预测

    本篇推文共计2000个字,阅读时间约3分钟. 华为云-华为公司倾力打造的云战略品牌,2011年成立,致力于为全球客户提供领先的公有云服务,包含弹性云服务器.云数据库.云安全等云计算服务,软件开发服务, ...

  7. 实战|手把手教你利用Python网络爬虫获取新房数据

    一.项目背景 大家好,我是J哥. 新房数据,对于房地产置业者来说是买房的重要参考依据,对于房地产开发商来说,也是分析竞争对手项目的绝佳途径,对于房地产代理来说,是踩盘前的重要准备. 今天J哥以惠民之家 ...

  8. 手把手教你开发chrome扩展一:开发Chrome Extenstion其实很简单

    手把手教你开发chrome扩展一:开发Chrome Extenstion其实很简单 参考地址为:手把手教你开发chrome扩展一:开发Chrome Extenstion其实很简单

  9. python自己做个定时器_技术图文:如何利用 Python 做一个简单的定时器类?

    原标题:技术图文:如何利用 Python 做一个简单的定时器类? 背景 今天在B站上看有关 Python 最火的一个教学视频 -- "零基础入门学习 Python",这也是我们 P ...

  10. html与css编程证书,利用CSS布局做一个简单的荣誉证书(代码示例)

    本篇文章将给大家介绍如何使用css布局制作一个简单的荣誉证书,有趣且实用,希望对需要的朋友有所帮助! 那么利用css布局实现简单荣誉证书样式的效果是非常简单的,主要用到以下几个基础属性: backgr ...

最新文章

  1. SAP MM PR单据类型的配置里‘Control’和’Doc.Type’字段的作用?
  2. python浪漫代码-python七夕浪漫表白源码
  3. mac brew 安装_无用技能之 Mac 安装relion 步骤
  4. 区块链BaaS云服务(14)华大BGI区块链“概论“
  5. iSCSI 2-环境搭建二
  6. 金融数据分析与挖掘实战4.1 Matplotlib(一)
  7. 武昌工学院计算机专业学费,2016年武昌工学院学费专业收费情况及综合排名
  8. 深度解析服务器需要虚拟化的两大条件
  9. (附源码)ssm天天超市购物网站 毕业设计 022101
  10. 加速计(重力感应功能)的使用
  11. 吐血推荐:数据库你想知道的都在这
  12. 计算机各部分名称ppt,PowerPoint软件界面各部分名称(PPT2010/2013/2016)
  13. PS 进行隐藏图制作
  14. flume学习之一 是什么,主要应用在什么场景
  15. Raft 一致性算法论文
  16. 带你了解什么是Nginx(实操反向代理-负载均衡)
  17. HDU 6082 度度熊与邪恶大魔王 (完全背包)
  18. Cocos Creator一步一步实现重力球游戏,附完整代码
  19. 图表分析2020年和2018年北京积分落户数据
  20. “乐高式”自动驾驶研发开放平台,让开发更简单灵活高效

热门文章

  1. Scala可变参数列表
  2. 敏捷脑图用例实践之路
  3. 再探java基础——对面向对象的理解(1)
  4. jBPM与业务系统集成-通过定制Task Instance等方式实现
  5. fedro1 16 64位安装oracle 11.2.0.1遇到的问题
  6. async await 的用法
  7. nowcoderG 小国的复仇
  8. git的丰富实用经验
  9. 117 Populating Next Right Pointers in Each Node II
  10. #define中的三个特殊符号:#,##,#@