2016年12月11日 星期日

關於LineBot(4) - 透過asp.net輕鬆建立Line機器人WebHook

如果你申請好了新版的Line Messaging API帳號。(申請位置位於https://business.line.me/zh-hant/services/bot),就可以建立一個Line對談機器人了,你要讓你的Line機器人能夠透過程式來回覆用戶的訊息,那關鍵當然是底下這個WebHook:

這個WebHook的設定位置可以從Line Messanging的管理介面進入:

一但你設定好WebHook,所有從用戶傳送給LineBot的訊息,就會傳送到這個WebHook,而你透過程式碼寫的這個WebHook,在接收到這個訊息之後,就可以依照用戶的訊息內容,來回應(回覆)不同的訊息給用戶。這就是一個Line對談機器人最基本的架構:

簡單的說就是,你只要寫一個WehHook(C#開發人員可以用WebAPI寫),放上網站,他就是一個網址,而你的機器人與用戶對談時,Line會把這個訊息封包傳送到你的WebHook這個網址,你可以在接受到訊息封包後進行剖析,取得用戶說的話(或是傳送來的圖片),透過後端的對談邏輯(可以用以前我們介紹過的LUIS來進行文字的斷字和語意分析)判斷,然後把該回覆的訊息組出來回覆給用戶,大致上是這樣。

所以你不難理解,那個WebHook顯然是我們第一個要實做的東西。其實開發起來很簡單。首先,請先用Visual Studio 2015建立一個Web專案:

在下一個畫面,專案範本請選擇Empty,但記得勾選底下的WebAPI:

完成後的專案框架大概是底下這樣,請在Controllers資料夾底下新增一個Controller:

我們先叫他LineChatController好了:

完成後大概是底下這樣:

接著我們就可以開始寫程式了,但別忘了,在寫程式之前,請先引用LineBotSDK這個Nuget Package:
SNAGHTML334df3fe

完成後,請直接將底下這段程式碼填入你的WebAPI Controller,請留意你要自行替換掉Channel Access Token:

所謂的Channel Access Token基本上就代表著你的Line Messanging,你在程式碼中想要透過你的Bot回覆或發送訊息,都需要這個Channel Access Token,他可以在你的Line Messanging WebHook管理站台上找到(第一次進來是空的,請按下Issue鈕就會出現)Confused smile:

把程式碼調整好(Channel Access Token換好)之後,請將此程式(其實就是一個網站),編譯後上傳到某個站台,由於該網站必須支援https,因此用windows azure web app是一個不錯的選擇。

上傳完成之後,可以將你的網站的URL,填入Line管理後台的WebHook URL: (這裡請注意,由於我們剛才的Controller取名為LineChat,因此你輸入的位置必須是 https://網址/api/LineChat ,例如底下這樣:

輸入完畢儲存後,你就可以測試你的LineBot了,還記得嗎? 剛才我們的程式碼當中,在第11行的地方取得用戶訊息的封包,將其剖析後,取得ReceivedMessage物件(第13行),接著找到用戶說的訊息,組初一段Echo的文字(16行),最後透過18行的程式碼回覆,程式碼就只有這樣。

我們試試看,當您加入這個bot做為好友(QR Code在管理站台上),對他說test,結果如下:

其實非常的簡單,對吧。

當然,上面程式碼還有很多不完善的地方,目前也都偵測不到傳送照片、加入或取消好友…等行為,不過沒關係,要達成其實也不難,我們後面再找時間跟大家介紹。

--------------------
btw, 有時候blog的留言我會很晚才看到,如果有問題或需要討論,請用底下網址上FB囉…
https://www.facebook.com/DotNetWalker/posts/1308046072568296

2016年11月8日 星期二

關於 LintBot (3) - 使用LineBotSDK發送Line訊息

新版的Line Messaging API,要主動發送訊息給用戶不是很困難,主要是透過Push API,可以參考底下的官方說明:
https://devdocs.line.me/en/#push-message

前陣子說過,我們為了團隊開發方便,做了一個Nuget Package以便於讓撰寫C#的開發人員可以方便的進行Line Messaging API的操作。

所以,如果你想要透過該SDK來發送訊息給用戶,可以透過底下的指令:

isRock.LineBot.Utility.PushMessage(
              UserId, 要傳送的訊息, AccessToken);

別忘了使用前,要先引用linebotSDK這個套件:

當您在.net 4.x的專案中,安裝上述lintbotSDK,即可透過前面提到的指令發送訊息給用戶,但請注意,該用戶必須加你的bot為好友。

你可能在使用時會碰到一個問題,怎麼知道用戶的id呢?
請注意,PushAPI的Line用戶id並非你的line ID,而是一長串項是底下這樣的id:
U6OX388eOX3634X2OX2e341OX06b8OX4123

這個ID會在你的用戶跟你的bot交朋友,或是對談的時候,由系統傳送給你的WebHook網址的JSON資料中獲得。也就是說,你的LineBot後台,所設定的這個WebHook,會收到這些相關的訊息:

訊息內容是以JSON的格式出現。

但是,如果你還不知道怎麼寫一個WebHook,該怎麼辦呢? 寫個WebHook其實很簡單,以asp.net來說,就是寫一個asp.net WebAPI即可。(有空我再說明,但今天比較沒空)

如果你沒空寫,可以先用底下這個工具(注意這個工具僅限測試使用,我們不保證其穩定性與可用性、與資料安全性):
http://isbaas.azurewebsites.net/WebForms/LineTokenManage.aspx

上面這個工具可以幫你產生一個臨時的WebHook網址,你只要到上面這個網址,把Line後台取得的Access Token輸入,並且順便輸入一個你想監聽該封包的 email(一般來說就是你自己的email啦),按下產生WebHook URL,系統會幫你產生一組像是底下這樣的URL:
https://isbaas.azurewebsites.net/api/LineWebHook?key=677510db-c204-46a0-9c72-d74ffac7e51c
你只需要把上面這組URL貼到你的Line管理後台WebHook URL的位置:

你就有一個公版的測試用WebHook了,這時你就可以跟你的line bot說話:

這個WebHook會echo用戶輸入的訊息,並且把整包JSON mail到你指定的email位置,同時間,你也可以透過跟bot說 /showmyid 取得你的line id,以便於測試。

請注意,這個小工具只是為了我們團隊內部測試方便使用,如果可以,我們還是建議你自行建立WebHook,我們並不負責為您保管Access Token,建議您測試完成後,立刻重新Issue你的bot Access Toekn,以確保安全。

2016年10月12日 星期三

Microsoft Graph API (1) - 這啥?

Microsoft Graph API的前身叫做 Office 365 unified API。這什麼東西呢? 這是一套可以access Office 365中各種服務的資料的API,簡單一點說,就是透過這組API你可以存取O365中用戶的資訊。

你看到unified這個字眼,可能會猜測,那它出現之前,可能有一個比較不unifie的API囉?

是的,你沒猜錯。

這一段路是有一個演進的過程的,我們先來介紹一下,我嘗試說個簡易版的故事。

首先,會接觸到這個API,是一年多以前的事情了,那時Office 365開始在台灣推廣,我們需要撰寫一些程式碼來存取O365上的資訊(像是用戶身分、行事曆、檔案…等)。

那,微軟這麼大的軟體公司,應該會有提供一套什麼API來存取這些資訊,用起來應該很簡單,對吧? 如果你這麼想,那就…稍微天真了。

提供API是有的,但你會好幸運的發現,不是提供一套API,是好幾套API。為何呢? 因為本質上Office 365根本就不是『一套』軟體。

什麼意思? Office 365,其實一堆軟體服務(SaaS)的集合,請記得這一點,它不是一套軟體,它是一群軟體所形成的一個平台。例如Office 365中的檔案,其實是Onedrive特殊版,筆記本是OneNote,email、行事曆是Outlook,通訊錄要看你想要抓哪種,有AD的,有email用的…這,還只是個開始。

如果你觀察Office 365,你會發現他一直在長大,最近還推出了Planner、Power BI、Flow …等等等、等等等。聽說以後還要推出類似Slack的Skype Team,總之Office 365跟你想的可能不一樣,它並非是一套軟體,他是很多套軟體服務。

而這很多套軟體服務的網址(網站)根本不同,只是每一個網站之間用oAuth做單一登入(SSO)的身分驗證而已,讓用戶用起來『像是(但根本不是)』在同一個網站裡面,但其實你是在多個網站裡切來切去。

那,這就讓developer很頭痛了,因為你以為的『抓取Office 365的資料』,其實不是在跟一組API打交道,是跟一群API打交道,每一種API都有自己的呼叫方式,都要做一次身分驗證,每一個驗證都要先取得授權,這…也太痛苦了吧。

寫到這邊,你就該知道unified 的必要了,這也是Office 365 unified API誕生的原因,後來隨著時間,他改名叫做Microsoft Graph API, that’s it.

參考底下這張圖:

可以這麼看,Microsoft Graph API是一個入口,讓你的應用程式可以簡單的面對一組API,做一次身分驗證和授權,讓你的日子好過一點。

可以想見,隨著Office 365家族中的Apps越來越多,越長越快,這組Graph API也會持續成長和更新,你現在看到的有 v1.0和beta兩個版本,抓取到的資料有所不同,適用範圍也各異。現在,你可以透過Graph API存取到底下各式各樣的用戶資訊:

不難想像,在企業中除了ERP以外,其他影響企業營運與命脈的資訊,現在全都在Office 365當中(只要你是用戶的話),我曾經勸某一個正在開發協同運作的團隊說,如果你想靠協同運作來掙錢,得要好好想想了。O365在協同運作的領域雖然不算是無敵,但它天生擁有的資源和富爸爸,讓其他產品很難很難超越。

況且微軟似乎還不滿足現狀,發展不僅止於此,Planner和傳說中的Skype team的出現,都意味著O365現在還只是個基礎而已。

這也暗示著,掌握Graph API,對建立企業運作相關加值軟體服務的重要將不言可喻。OK,我們將在接下來幾篇文章當中,開始討論如何使用此API,以其所能達成的效益。

2016年10月4日 星期二

關於Linebot(2) - 新版Line@ Messaging API使用心得 (Line Bot v2)

不廢話,直接切入主題,如果你想看前情提要,請看這裡這裡
如果你對開發Line Bot有興趣,你得先知道原本的Line bot API改版了,最近很奇怪,微軟的bot framework也拼命改版,大家都很隨便敏捷…

新版叫做Messaging API,原則上和舊版的Line bot在概念上很像,但它和Line@整合在一起了。這改版有何影響? 首先,你如果原本有寫好的Line Bot可以暫時不要動它,因為新版v2的Messaging API和舊版並不相容。

其次,新版的bot之所以稱為Line@ Messaging API,是因為,它是透過申請一個Line@帳號開始的,和以前申請一個Line bot帳號不同,這次Line bot的功能被Line@併了。你可以從底下網址直接申請一個"具有Messaging API功能的Line@帳號":
https://business.line.me/zh-hant/services/bot

留意該頁面最下方:

這是三個不同的按鈕。

  1. 開始使用Messaging API
  2. 開始使用Developer Trial
  3. 若要透過現有Line@帳號開始使用Messaging API….

如果你選擇1,2,其實是先建立一個Line@帳號,然後頁面會引導你把該Line@帳號轉成支援Messaging API,如果你選擇3,則是把以前舊的Line@帳號改為支援Messaging API。

但請注意,當你的Line@改為支援Messaging API之後,你就不能用你的Line@ App直接回覆用戶的訊息了(而且這動作不可逆,也就是轉過去轉不回來),用戶的訊息也只會被轉傳到你的Line@ WebHook URL,讓你透過bot程式碼來回覆訊息。
(我覺得這設計…我直說了…糟透了,既然要廢掉Lint bot改用Line@,還不能用Line@ app回訊息,只能在Line@ app和Messaging API中間二選一,那又何必把原本的line bot廢了跟Line@整合在一起呢? 不理解…)

如果你原本的Line@帳號有在用,建議你申請新的Line@去玩這個Messaging API,別用舊的帳號。

接著,你要選擇上面的1還是2呢?請參考底下:

讓我來翻譯一下。

如果你只想要回覆用戶的訊息,那申請哪一個方案都行,但如果你想要主動發訊息給用戶,那只能是developer trial和進階版(月費1888)以上的方案。

developer trial不用錢,但上限50個用戶,你不能把deveeloper trial方案轉換為其他方案。

因此,如果你想要有一個主動傳送訊息的功能,用在production,那你必須付月費1888。好消息是,他說2017年三月前免費。而且付錢很容易,用Line Pay就可以。

你申請好了之後,可以從底下網址到管理後台:
https://admin-official.line.me/ 

當你選擇了某一個Line@帳號,會看到類似底下的管理畫面,下圖(1)的部分,是你正式啟用了支援Messaging API的Line@之後,會出現的選項,如果沒出現這個選項,表示你的Line@帳號尚未支援Messaging API,這時候,你可以去 https://business.line.me/accounts 這個網址把該Line@帳號轉為支援Messaging API
(再次提醒,這個轉換無法回頭,且一旦轉為支援API,則無法用Line@ App回覆用戶訊息,請謹慎為之)

另外,下圖(2)的部分就是你的Line@支援哪一種Message方式,Push就是主動傳訊息給用戶, Reply就是回覆用戶的訊息。如果你只看到Reply,表示你的Line@目前是免費版本,要嘛你升級到進階版($1888),要嘛你申請一個Developer trial帳號(有50個好友限制)

接著你可做些設定,當你允許WebHook傳訊,就表示你可以設定一個WebAPI來接收用戶傳遞給該Line@(就是bot)的訊息。該WebHook在哪設定?

點選Line Developers之後,出現底下畫面:

你可以在上圖(1)的部分設定WebHook URL,在(2)的部分可以取得call API的時候需要的Access Token,而API的document在:
https://devdocs.line.me/en/

後面有機會再介紹怎麼透過程式碼呼叫新版API。

happy coding,各位保重。

2016年9月25日 星期日

在asp.net WebForm當中找個簡單的方法實現非同步檔案上傳

最近由於一些因緣際會,又得回頭寫一點asp.net WebForm相關的東西,但,時代在這5年中實在有了不少的改變,因此一些過去的做法,最近有了不同的實作方式,其實我也是久久沒用怕忘記,紀錄一下。

我們最近碰到一個需求,非常單純,就是希望在網頁上用非同步的方式上傳檔案。

這需求沒啥好說嘴的,對吧。

但環境是這樣的,我們用的開發工具是asp.net WebForm,頁面需要盡可能保持單純,因為我自己不喜歡任何從伺服器端render html到前端的解決方案,因此一開始就盡可能的少用 web control之類的東西。由於現在有jQuery可用,瀏覽器的支援也比當年好了不知多少倍,因此,asp.net AJAX那種龐然大物自然也被排除在選用範圍之外。

為何不用asp.net MVC? 一則因為網站必須和過去開發環境(人員)相容,另外asp.net MVC中的Razor view也會從伺服器端render html到前端,route的對應方式和過去webForm的路徑作法不同,在一個專案裡面同時出現實在太不直覺,因此也不在考慮範圍內。

但專案中我們會用asp.net WebApi,如果需要的話(這表示我們不用Web/WCF Services了)。

簡單的說,就是這雖然用asp.net WebForm技術,但頁面前端盡可能的只有 html 與 js,而後端用C#,盡量不用任何WebControls。OK,背景交代完畢。

怎麼實現,先看前端要怎麼上傳檔案,很簡單,放一個file upload,和一個上傳button,寫一點js做非同步上傳用:

我覺得大部分的程式碼都不需要解釋,留意31行body之後,雖然該頁面是asp.net webform,但除了預設的form tag之外,其他的control我們都是用html而非asp.net web controls,在button click時候,我們呼叫第6行的UploadFileAsync,裡面透過很標準的post方法把用戶選擇的檔案上傳。

就這樣。

那伺服器端怎麼接這個檔案呢? 也容易:
就上面這區區幾行…

ㄟ…我承認,放在Page_Load裡面看起來有點low,但,這是最簡單單純的做法了,整個過程中不需要使用任何第三方套件或工具,頁面也盡可能保持乾淨。

結案,收工。

喔,程式碼在https://github.com/isdaviddong/AspNetWebFormAsyncFileUpload

後記 :

  1. 其實比較有趣的是,透過上面這樣的Code,你很容易猜出asp.net WebForm當中檔案上傳這個機制骨子裡的做法。
  2. github的gist還蠻好用的。
  3. asp.net WebForm用的好,搭配一點js,無須什麼新技術,其實日子也可以蠻好過的。

2016年9月22日 星期四

Microsoft Cognitive Services (4) - 使用Speech API讓你的電腦說話

讓你的電腦說話早已經不是新鮮事了,早期WP7.x的時代,我們就寫過程式碼讓手機說話,適當的採用語音輸出,對於用戶來說也是個不錯的互動體驗。

透過Cognitive Services中的Speech API讓電腦說話,用起來也相當簡單,它可以直接在雲端為你產生你指定的語音,並且將語音檔案binary傳回用戶端。

整體來說,使用該API的方式可參考底下:
Bing Text To Speech API

同樣的,使用時你會用到一組Key,這個Key與先前我們做語音辨識的時候使用的Key相同。呼叫 API前,我們需要先透過這組Key取得一個token (底下是postman呼叫畫面):

取得Token時,請用POST呼叫底下URL :
https://oxford-speech.cloudapp.net/token/issueToken

傳入的body是 :
grant_type=client_credentials&client_id=<Your subscription key>&client_secret=<Your subscription key>&scope=https://speech.platform.bing.com


其中的 Your subscription key 是我們前面說到的 key。

取得後的token應該是類似上圖中一長串的文數字。

接著,請組出底下這樣的XML,這組XML是用來告知Speech API我們要取得什麼語音:
<speak version="1.0" xmlns="http://www.w3.org/2001/10/synthesis" xmlns:mstts="http://www.w3.org/2001/mstts" xml:lang="zh-TW">
<voice name="Microsoft Server Speech Text to Speech Voice (zh-TW, Yating, Apollo)">
哈囉,今天天氣不錯啊
</voice>
</speak>

這組XML是以body的方式傳入http post的呼叫,其URL是:
https://speech.platform.bing.com/synthesize

留意XML中的內容,voice name可讓我們指定語音的語言和類型,可用的內容可以參考底下這裡得知:
https://www.microsoft.com/cognitive-services/en-us/Speech-api/documentation/API-Reference-REST/BingVoiceOutput

你也可以透過底下這邊的工具來組這串XML:
https://www.microsoft.com/cognitive-services/en-us/speech-api

別忘記,呼叫上述http post時必須傳入底下的headers:
Content-Type : application/ssml+xml
X-Microsoft-OutputFormat : raw-8khz-8bit-mono-mulaw
Authorization : Bearer <剛才取得一長串token>

例如(底下是postman呼叫畫面):

也不是很複雜,透過這樣的方式,就能夠取得指定文字的音訊(.wav)檔案囉。

上面是透過測試工具post man來呼叫,如果要透過C#程式碼呼叫,則可參考底下連結:
https://social.msdn.microsoft.com/Forums/sqlserver/en-US/6e7f64e4-052c-4753-8128-43b94045064a/mvp-sample-code-with-voice-output-rest-api-in-c?forum=mlapi

2016年9月8日 星期四

關於bot framework (6) - 如何分辨WebChat用戶並保護Secret key

好不容易透過bot framework建立好了一個bot,要讓用戶和我們的bot chatting,最簡單的方式當然就是透過內建的Web Chat。

你會發現,在後台的管理畫面上,有一個內建的Weh Chat:

要啟動該Web Chat,只需要點選上圖中的Edit,並且產生一個secret key即可:

有了這組secret key,你可以直接透過底下這樣的網址,讓不特定用戶來與你建立好的bot聊天:
https://webchat.botframework.com/embed/test20160826?s=x4fT4xmsjNw.cwA.lLc.MfO35JmnXsxKxihkLaMptAlwTqGwOJFP1kLim174nFh8

畫面大致如下,這個Web Chat UI除了可以文字聊天,還可以上傳圖片,其實蠻好用的:

但問題來了,文件上開宗明義地就說,這組secret如果洩漏出去了,那任何人都可以用iframe指令把你的bot embbed在他們家的網頁裡,這或許你不在意,但還有另一個問題。每一個得知這樣的網址連進來的用戶,對談時都是以匿名的方式進來的,如果將來要查詢聊天紀錄,很不方便。

那麼除了用Skype或是FB Messanger來串這個bot,有沒有什麼方式可以解決這個問題呢? 有的,而且還一石二鳥。

首先,你確實不應該用後台產生的這組secret key作為使用WebChat UI的參數,而是該改用一個token。本來的WebChat網址

https://webchat.botframework.com/embed/botName?s=x4fT4xmsjNw.cwA.lLc.MfO35JmnXsxKxihkLaMptAlwTqGwOJFP1kLim174nFh8

應該改為

https://webchat.botframework.com/embed/botName?t=token

這樣的型式。

那這token怎麼來呢,你可以透過底下這個API取得:
https://webchat.botframework.com/api/conversations

當你用POST呼叫上面這組API,在headers中傳入Authorization(value是BotConnector 加上你的secret key),就可以啟用一個新的Conversation,並透過回傳的JSON取得該Conversation的ID與Token,如下圖 postman畫面:

這Conversation的ID與Token能幹啥? 告訴你,大有用途。

首先,你取得token之後,就可以把剛才連結WebChat的網址改成https://webchat.botframework.com/embed/botName?t=token

這樣你就不會洩漏你的bot的secret key了,而每一組token都是有時間限制的,逾時之後就無法使用了。

另外一個很重要的資訊是ConversationID,有了ConversationID我們就可以在用戶從WehChat的UI與bot對談時,從後端WebAPI程式碼當中,分辨出當前對談的人是誰,而不需要用戶非得從skype或FB Messanger進來,才能得知用戶的身分了。這…怎麼說呢?

首先上面這組POST指令,是可以(也應該要)從後端呼叫的,拿asp.net WebForm/MVC來說,你的流程可以是:
  1. 讓用戶先用Forms驗證登入
  2. 透過User.Identity.Name取得用戶的身分(假設用戶登入為David)
  3. 從後端asp.net C#程式碼中呼叫上面的API https://webchat.botframework.com/api/conversations ,來建立新的Conversation
  4. 取得該Conversation的ID與Token
    (一旦取得ConversationID﹐我們就可以記錄該 ConversationId 的對談對象是 David)
  5. 接著,利用剛才取得的token產生一個WebChat對談URL(https://webchat.botframework.com/embed/botName?t=token ),並redirect過去。
  6. 用戶即可在上面 https://webchat.botframework.com/embed/botName?t=token 這個位置與bot對談,對談中我們的後台bot對談邏輯WebApi中取得的activity.Conversation.Id ,就是剛才我們記錄下來的ConversationID,如此一來,就可以關連到用戶是David了。
瞭解了嗎? 透過上面這個POST API,不僅僅可以保護你的secret key,還可以取得新建立的對談的ConversationID,並且關連到與該bot對談的用戶,功能可說是非常大呢~