手把手教你利用微軟的Bot Framework,LUIS,QnA Maker做一個簡單的對話機器人


最近由於要參加微軟亞洲研究院的夏令營,需要利用微軟的服務搭建一個對話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.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);
}
View Code

得到的響應格式是JSON,如下:

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

處理響應的代碼:

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.");
}
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>
<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 <= 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:

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; }
    }
}
View Code

 

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')[0];
                var Price = FirstLine.Split(',')[1];
                if (Price != null && Price.Length >= 0)
                {
                    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;
            }
        }
    }
}
View Code

 

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; }
    }
}
View Code

 

 

學習資料:

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

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM