最近由于要参加微软亚洲研究院的夏令营,需要利用微软的服务搭建一个对话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这种格式。
中间记得用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.1
Host: 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 = new WebClient())
{
//Set the encoding to UTF8
client.Encoding = System.Text.Encoding.UTF8; //Add the subscription key header
client.Headers.Add("Ocp-Apim-Subscription-Key", qnamakerSubscriptionKey);
client.Headers.Add("Content-Type", "application/json");
responseString = client.UploadString(builder.Uri, postBody);
}
得到的响应格式是JSON,如下:
{ "Answer": "Sample response", "Score": "" }
处理响应的代码:
using Newtonsoft.Json; private class QnAMakerResult
{
/// <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.");
}
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,请参考:
- 右键你的C#项目,选择"Manage NuGet Packages".
- 在"Browse"的tab页,输入"Microsoft.Bot.Builder".
- 点击"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>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<html>
<head>
<title>小驰</title>
<meta charset="utf-8" />
</head>
<body style="font-family:'Segoe UI'">
<iframe name="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:
using BOPdemo.Models;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Builder.Luis;
using Microsoft.Bot.Builder.Luis.Models;
using Microsoft.Bot.Connector;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using System.Web; namespace BOPdemo.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>
{
public MengmengDialog()
{
}
public MengmengDialog(ILuisService service)
: base(service)
{
}
[LuisIntent("")]
[LuisIntent("None")]
public async Task 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 Query
var knowledgebaseId = "a00256ee-9316-4476-9fcb-0f6f7e10f8b6"; // Use knowledge base id created.
var qnamakerSubscriptionKey = "417cc12cef9a4b64835b84b657dc4d73"; //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 = new WebClient())
{
//Set the encoding to UTF8
client.Encoding = System.Text.Encoding.UTF8; //Add the subscription key header
client.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
{
await context.PostAsync(answer);
}
//await context.PostAsync(response.Score+"");
//原来的
context.Wait(MessageReceived);
}
public bool TryToFindLocation(LuisResult result, out String location)
{
location = "";
EntityRecommendation title;
if (result.TryFindEntity("地点", out title))
{
location = title.Entity;
}
else
{
location = "";
}
return !location.Equals("");
}
[LuisIntent("查询天气")]
public async Task QueryWeather(IDialogContext context, LuisResult result)
{
string location = "";
string replyString = "";
if (TryToFindLocation(result, out location))
{
replyString = await GetWeather(location);
await context.PostAsync(replyString);
context.Wait(MessageReceived);
}
else
{
await None(context, result);
}
//else
//{
// await context.PostAsync("亲你要查询哪个地方的天气信息呢,快把城市的名字发给我吧");
//context.Wait(AfterEnterLocation);
//}
} private async Task<string> GetWeather(string cityname)
{
WeatherData weatherdata = await BOPdemoTask.GetWeatherAsync(cityname);
if (weatherdata == null || weatherdata.HeWeatherdataservice30 == null)
{
return string.Format("呃。。。萌萌不知道\"{0}\"这个城市的天气信息", cityname);
}
else
{
HeweatherDataService30[] weatherServices = weatherdata.HeWeatherdataservice30;
if (weatherServices.Length <= ) return string.Format("呃。。。萌萌不知道\"{0}\"这个城市的天气信息", cityname);
Basic cityinfo = weatherServices[].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[].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[].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[].daily_forecast;
Now cityNowStatus = weatherServices[].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);
}
}
}
}
WeatherModel.cs:
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web; namespace BOPdemo.Models
{
public class WeatherData
{
[JsonProperty(PropertyName = "HeWeather data service 3.0")]
public HeweatherDataService30[] HeWeatherdataservice30 { get; set; }
} public class HeweatherDataService30
{
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 class Aqi
{
public City city { get; set; }
} public class City
{
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 class Basic
{
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 class Update
{
public string loc { get; set; }
public string utc { get; set; }
} public class Now
{
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 class Cond
{
public string code { get; set; }
public string txt { get; set; }
} public class Wind
{
public string deg { get; set; }
public string dir { get; set; }
public string sc { get; set; }
public string spd { get; set; }
} public class Suggestion
{
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 class Comf
{
public string brf { get; set; }
public string txt { get; set; }
} public class Cw
{
public string brf { get; set; }
public string txt { get; set; }
} public class Drsg
{
public string brf { get; set; }
public string txt { get; set; }
} public class Flu
{
public string brf { get; set; }
public string txt { get; set; }
} public class Sport
{
public string brf { get; set; }
public string txt { get; set; }
} public class Trav
{
public string brf { get; set; }
public string txt { get; set; }
} public class Uv
{
public string brf { get; set; }
public string txt { get; set; }
} public class Daily_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 class Astro
{
public string sr { get; set; }
public string ss { get; set; }
} public class Cond1
{
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 class Tmp
{
public string max { get; set; }
public string min { get; set; }
} public class Wind1
{
public string deg { get; set; }
public string dir { get; set; }
public string sc { get; set; }
public string spd { get; set; }
} public class Hourly_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 class Wind2
{
public string deg { get; set; }
public string dir { get; set; }
public string sc { get; set; }
public string spd { get; set; }
}
}
BOPdemoTask.cs:
using BOPdemo.Models;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Web; namespace BOPdemo
{
public class BOPdemoTask
{
public static async Task<double?> GetStockRateAsync(string StockSymbol)
{
try
{
string ServiceURL = $"http://finance.yahoo.com/d/quotes.csv?s={StockSymbol}&f=sl1d1nd";
string ResultInCSV;
using (WebClient client = new WebClient())
{
ResultInCSV = await client.DownloadStringTaskAsync(ServiceURL).ConfigureAwait(false);
}
var FirstLine = ResultInCSV.Split('\n')[];
var Price = FirstLine.Split(',')[];
if (Price != null && Price.Length >= )
{
double result;
if (double.TryParse(Price, out result))
{
return result;
}
}
return null;
}
catch (WebException ex)
{
//handle your exception here
throw ex;
}
} public static async Task<WeatherData> GetWeatherAsync(string city)
{
try
{
string ServiceURL = $"https://free-api.heweather.com/x3/weather?city={city}&key=e8c9a95d0a0f4d2092def1174c44be17";
string ResultString;
using (WebClient client = new WebClient())
{
client.Encoding = Encoding.UTF8;
ResultString = await client.DownloadStringTaskAsync(ServiceURL).ConfigureAwait(false);
}
WeatherData weatherData = (WeatherData)JsonConvert.DeserializeObject(ResultString, typeof(WeatherData));
return weatherData;
}
catch (WebException ex)
{
//handle your exception here
//throw ex;
return null;
}
}
}
}
QnAMakerResult.cs:
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web; namespace BOPdemo.Models
{
public class QnAMakerResult
{
/// <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; }
}
}
学习资料:
http://studentclub.msra.cn/bop2017/qa
http://studentclub.msra.cn/bop2017/rules/learning
手把手教你利用微软的Bot Framework,LUIS,QnA Maker做一个简单的对话机器人的更多相关文章
-
手把手教你开发chrome扩展一:开发Chrome Extenstion其实很简单
手把手教你开发chrome扩展一:开发Chrome Extenstion其实很简单 手把手教你开发chrome扩展一:开发Chrome Extenstion其实很简单 手把手教你开发Chrome扩 ...
-
netty系列之:小白福利!手把手教你做一个简单的代理服务器
目录 简介 代理和反向代理 netty实现代理的原理 实战 总结 简介 爱因斯坦说过:所有的伟大,都产生于简单的细节中.netty为我们提供了如此强大的eventloop.channel通过对这些简单 ...
-
【转】手把手教你利用Jenkins持续集成iOS项目
前言 众所周知,现在App的竞争已经到了用户体验为王,质量为上的白热化阶段.用户们都是很挑剔的.如果一个公司的推广团队好不容易砸了重金推广了一个APP,好不容易有了一些用户,由于一次线上的bug导致一 ...
-
手把手教你利用Jenkins持续集成iOS项目
前言 众所周知,现在App的竞争已经到了用户体验为王,质量为上的白热化阶段.用户们都是很挑剔的.如果一个公司的推广团队好不容易砸了重金推广了一个APP,好不容易有了一些用户,由于一次线上的bug导致一 ...
-
手把手教你利用Docker+jenkins部署你的网站
更新服务器的安装源为阿里的源,参考链接:https://blog.csdn.net/js_xh/article/details/79166655 安装docker; 1 更新资源 sudo apt-g ...
-
手把手教你利用Python自动下载CL社区图片
需求描述: 最近发现CL社区上好多精华的帖子分享的图片非常棒,好想好想保存下来,但是一张一张地保存太费时间了,因此,造物者思想主义的我就想动手写个工具,实现只要输入帖子的链接,就能把所有的精华 ...
-
CNN实战篇-手把手教你利用开源数据进行图像识别(基于keras搭建)
我一直强调做深度学习,最好是结合实际的数据上手,参照理论,对知识的掌握才会更加全面.先了解原理,然后找一匹数据来验证,这样会不断加深对理论的理解. 欢迎留言与交流! 数据来源: cifar10 (其 ...
-
js利用点击事件做一个简单的计算器
先放一个样式图: 源代码如下: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"&g ...
-
利用JS跨域做一个简单的页面访问统计系统
其实在大部分互联网web产品中,我们通常会用百度统计或者谷歌统计分析系统,通过在程序中引入特定的JS脚本,然后便可以在这些统计系统中看到自己网站页面具体的访问情况.但是有些时候,由于一些特殊情况,我们 ...
随机推荐
-
React Native知识11-Props(属性)与State(状态)
一:Props(属性) 大多数组件在创建时就可以使用各种参数来进行定制.用于定制的这些参数就称为props(属性).props是在父组件中指定,而且一经指定,在被指定的组件的生命周期中则不再改变 通过 ...
-
dp与px之间的转换
代码如下: package com.example.fxvideo.utils; import android.content.Context; public class DensityUtils { ...
-
[转]Visual Studio 2008中如何比较二个数据库的架构【Schema】和数据【Data】并同步
使用场景: 在团队开发中,每一个人都有可能随时更新数据库,这时候数据库中数据和架构等信息都会发生变化.如果更新不及时,就会发生数据错误或数据丢失的风险,影响团队的开发效率和 项目进度,这时候我们该怎么 ...
-
android的快速开发框架集合
出自:http://blog.csdn.net/shulianghan/article/details/18046021 1.Afinal (快速开发框架) 简介:http://www.oschin ...
-
JS中setTimeout()的使用方法具体解释
1. SetTimeOut() 1.1 SetTimeOut()语法样例 1.2 用SetTimeOut()运行Function ...
-
学习REST
REST:Representational State Transfer,资源的表现状态转换.可以理解为对资源的操作. 1. 资源 资源就是业务对象,如图片.文本.歌曲或者客户.交易等.这些是用户 ...
-
Python 学习 第四篇:动态类型模型
Python的变量不用声明,赋值之后就可以直接使用,类型是在运行过程中自动确定的,这就是动态类型模型.该模型把变量和对象设计成两个不同的实体,对象是存储数据的地方,对象的类型是由初始值自动决定的,而变 ...
-
pandas 应用
类似vlookup import pandas as pd file = pd.read_csv('NIN411PF.CSV', encoding='ANSI') a = pd.DataFrame({ ...
-
【Java并发编程】2、无锁编程:lock-free原理;CAS;ABA问题
转自:http://blog.csdn.net/kangroger/article/details/47867269 定义 无锁编程是指在不使用锁的情况下,在多线程环境下实现多变量的同步.即在没有线程 ...
-
A Brief Overview of Deep Learning
A Brief Overview of Deep Learning (This is a guest post by Ilya Sutskever on the intuition behind de ...