微軟牛津計劃(Project Oxford)提供了一系列機器學習API,,包含計算機視覺,、語音識別和語言理解等認知服務(wù),它能為微信開發(fā)帶來怎樣有趣的功能,?請看本文分解,。 微軟牛津計劃提供了一組基于Rest架構(gòu)的API和SDK工具包,幫助開發(fā)者輕輕松松使用微軟的自然數(shù)據(jù)理解能力為自己的解決方案增加智能服務(wù),。利用微軟牛津計劃構(gòu)建你自己的解決方案,,支持任意語言及任意開發(fā)平臺。主要提供了四個自然語言處理方面的核心問題解決方案:人臉識別,、語音識別,、計算機視覺,以及語言理解智能服務(wù),。 圖1 應(yīng)用界面 微軟提供了這么強大的API,,我第一時間就想,是不是可以遷移到微信平臺上去做一些好玩的應(yīng)用,,不過在這之前,,我沒有做過任何微信開發(fā)的工作,,所以本篇文章將分享整個實現(xiàn)的經(jīng)驗。 ASP.NET WebAPI實現(xiàn)微信接入驗證 首先你需要一個微信公眾號,,很重要的是你需要完成認證,,這點非常重要。當你完成公眾號的基本設(shè)定后,,我們需要為開發(fā)做第一件事情:讓微信驗證通過開發(fā)者中心頁配置的服務(wù)器地址,。微信服務(wù)器將發(fā)送GET請求到我們注冊的服務(wù)器地址URL上,GET請求攜帶四個參數(shù):signature,、timestamp,、nonce、echostr,。我們編寫了一個WebAPI對微信的請求進行反饋,。 public HttpResponseMessage Get(string signature, string timestamp, string nonce, string echostr) { string ArrTmp = { TOKEN, timestamp, nonce }; Array.Sort(ArrTmp); string tmpStr = string.Join('', ArrTmp); var result = FormsAuthentication.HashPasswordForStoringInConfigFile(tmpStr, 'SHA1').ToLower;
return new HttpResponseMessage { Content = new StringContent(result, Encoding.GetEncoding('UTF-8'), 'application/x-www-form-urlencoded') }; }
上面這段代碼的要點是返回值,很多工程師在使用WebAPI返回給微信驗證時一直失敗,,是因為忽略了返回值的編碼要求是application/x-www-form-urlencoded,。 ASP.NET WebAPI實現(xiàn)微信JS-SDK接口注入權(quán)限驗證配置 我們的客戶端采用微信的JS-SDK,但是所有需要使用JS-SDK的頁面必須先注入配置信息,,否則將無法調(diào)用,,當使用JS-SDK的時候,微信會將appId,、timestamp,、nonceStr和signature的參數(shù)進行加密和驗算是否正確,所以我們需要提供一個正確的簽名值,。需要獲得這個簽名必須要完成兩步,,圖2所示的UML描述了這個過程。 圖2 獲取簽名過程示意圖 第一步:獲取Access Token if (HttpRuntime.Cache['access_token'] == ) { var queryString = HttpUtility.ParseQueryString(string.Empty); queryString['grant_type'] = 'client_credential'; queryString['appid'] = APPID; queryString['secret'] = APPSECRET;
var uri = 'https://api.weixin.qq.com/cgi-bin/token?' queryString;
HttpResponseMessage response; response = await client.GetAsync(uri); var msg = await response.Content.ReadAsStringAsync; var jsonobj = Newtonsoft.Json.Linq.JObject.Parse(msg);
HttpRuntime.Cache.Add('access_token', (string)jsonobj['access_token'], , DateTime.Now.AddMinutes((int)jsonobj['expires_in']), new TimeSpan(0, 0, 0), System.Web.Caching.CacheItemPriority.AboveNormal, ); }
第二步:獲取jsapi_ticket if (HttpRuntime.Cache['jsapi_ticket'] == ) { var queryString = HttpUtility.ParseQueryString(string.Empty); queryString['access_token'] = (string)HttpRuntime.Cache['access_token']; queryString['type'] = 'jsapi'; var uri = 'https://api.weixin.qq.com/cgi-bin/ticket/getticket?' queryString; HttpResponseMessage response; response = await client.GetAsync(uri); var msg = await response.Content.ReadAsStringAsync; var jsonobj = Newtonsoft.Json.Linq.JObject.Parse(msg); HttpRuntime.Cache.Add('jsapi_ticket', (string)jsonobj['ticket'], , DateTime.Now.AddMinutes((int)jsonobj['expires_in']), new TimeSpan(0, 0, 0), System.Web.Caching.CacheItemPriority.AboveNormal, ); }
我們用于簽名的素材都到齊了,,我們要實現(xiàn)簽名算法了,。實現(xiàn)的代碼如下。 var pwd = string.Format('jsapi_ticket={0}&noncestr={1}×tamp={2}&url={3}', (string)HttpRuntime.Cache['jsapi_ticket'], noncestr, timestamp, url );
var tmpStr = FormsAuthentication.HashPasswordForStoringInConfigFile(pwd, 'SHA1');
return Request.CreateResponse(HttpStatusCode.OK, tmpStr);
這時候我們前端的HTML5就可以正確的采用JS-SDK了,。 ASP.NET獲取微信客戶端上傳的圖片 本來我以為這是個很簡單的事情,,后來才發(fā)現(xiàn),使用微信JS-SDK的時候,,微信的HTML5客戶端不會將圖片直接POST給我的服務(wù)端,,而是先提交給微信服務(wù)器,然后我的服務(wù)端需要通過serverId 來獲得圖片,,大致的流程我繪制了UML,,見圖3,大家可以理解下。 圖3 獲取微信客戶端上傳圖片的過程 目前我們只關(guān)心服務(wù)器這段,,我們將得到客戶端傳來的serverID,,從微信的服務(wù)器上下載圖片到本地。我們實現(xiàn)的代碼如下,。 public async Task<string> Get(string mediaid) { var queryString = HttpUtility.ParseQueryString(string.Empty); queryString['access_token'] = await Get; queryString['media_id'] = mediaid;
var uri = 'http://file.api.weixin.qq.com/cgi-bin/media/get?' queryString;
HttpResponseMessage response; response = await client.GetAsync(uri);
var msg = await response.Content.ReadAsStreamAsync; var file = response.Content.Headers.ContentDisposition.FileName.Replace('\'', ''); var helper = new ProjecToxfordClientHelper; var content = await FileHelper.ReadAsync (msg); FileHelper.SaveFile(content, file); return file; }</string>
好了,,到了現(xiàn)在,我們對微信服務(wù)器需要實現(xiàn)的接口都差不多了,,接下來就可以設(shè)計微信的客戶端了,。 WeUI設(shè)計微信客戶端首頁樣式 WeUI是一套同微信原生視覺體驗一致的基礎(chǔ)樣式庫,由微信官方設(shè)計團隊為微信網(wǎng)頁開發(fā)量身設(shè)計,,可以令用戶的使用感知更加統(tǒng)一,。在微信網(wǎng)頁開發(fā)中使用 WeUI,有如下優(yōu)勢: 同微信客戶端一致的視覺效果,,令所有微信用戶都能更容易地使用你的網(wǎng)站,; 便捷獲取快速使用,降低開發(fā)和設(shè)計成本,; 微信設(shè)計團隊精心打造,,清晰明確,簡潔大方,。
該樣式庫目前包含button,、cell,、dialog,、progress、toast,、article,、icon等各式元素,我們可以在https://github.com/weui/weui獲得源代碼和DEMO,。 我們先做首頁,,以了解WeUI樣式庫的使用方式。 建立Index.html引入樣式庫和配置head節(jié)點,。 <meta charset='utf-8'> <title>臉探</title> <meta name='viewport' content='initial-scale=1.0,user- scalable=no,maximum- scale=1,width=device-width'> <link href='css/weui.css' rel='stylesheet'> <link href='css/example.css' rel='stylesheet'>
Body節(jié)點下的直接子元素是< div class=”page”>,,其他所有元素都在這個節(jié)點下,我們的Index.html頁面設(shè)計了兩個div元素分別是: <div class='hd'> <div class='bd'></div></div>
hd節(jié)點下的代碼非常簡單,,就是title的描述,。 <h1 class='page_title'>臉探</h1> <p class='page_desc'>測測臉的相似度</p>
bd包含的是一個< div class=”weui_panel weui_panel_access”>,WeUI提供的Panel非常容易設(shè)計圖文組合列表,,WeUI提供了一系列很有用的類:weui_panel,、weui_panel_access、weui_panel_hd、weui_panel_bd,。 我們的Panel的標題就可以用weui_panel_hd進行修飾,。 <div class='weui_panel_hd'></div>
具體的內(nèi)容可以被weui_panel_bd修飾。 <div class='weui_panel_bd'></div>
weui_panel_bd 的子元素如下: <a href='' class=' weui_media_box weui_media_appmsg '> <div class=' weui_media_hd'> <imgsrc='img 4432144_111855038929_2.jpg'='' alt=''> </imgsrc='img></div> <div class=' weui_media_bd'> <h4 class=' weui_media_title '>標題</h4> <p class='weui_grid_label'>內(nèi)容 </p> </div> </a>
了解了如何布局一個列表項,,那首頁就容易完成了,,代碼如下。 <div class='page'> <div class='hd'> <h1 class='page_title'>臉探</h1> <p class='page_desc'>測測臉的相似度</p> </div> <div class='bd'> <div class='weui_panel weui_panel_access'> <div class='weui_panel_hd'>娃像誰 </div> <div class='weui_panel_bd'> <a href='family.html' class='weui_media_box weui_media_appmsg'> <div class='weui_media_hd'> <img class='weui_media_appmsg_thumb' src='fonts/family.jpg' alt=''> </div> <div class='weui_media_bd'> <h4 class='weui_media_title'>三人照</h4> <p class='weui_media_desc'>上傳一家三口三人照,,立即知道孩子與父母相像指數(shù)</p> </div> </a> <a href='family3.html' class='weui_media_box weui_media_appmsg'> <div class='weui_media_hd'> <img class='weui_media_appmsg_thumb' src='fonts/one.jpg' alt=''> </div> <div class='weui_media_bd'> <h4 class='weui_media_title'>單人照</h4> <p class='weui_media_desc'>上傳一家三口各自照片,,立即知道孩子與父母相像指數(shù)</p> </div> </a> </div> </div> </div> <div class='bd'> <div class='weui_panel weui_panel_access'> <div class='weui_panel_hd'>夫妻相 </div> <div class='weui_panel_bd'> <a href='couple2.html' class='weui_media_box weui_media_appmsg'> <div class='weui_media_hd'> <img class='weui_media_appmsg_thumb' src='fonts/couple.jpg' alt=''> </div> <div class='weui_media_bd'> <h4 class='weui_media_title'>雙人照</h4> <p class='weui_media_desc'>上傳你和TA的雙人照,你立即知道你們的天生緣分指數(shù)</p> </div> </a> <a href='couple.html' class='weui_media_box weui_media_appmsg'> <div class='weui_media_hd'> <img class='weui_media_appmsg_thumb' src='fonts/one.jpg' alt=''> </div> <div class='weui_media_bd'> <h4 class='weui_media_title'>單人照</h4> <p class='weui_media_desc'>上傳你們兩人各自照片,,你立即知道你們的天生緣分指數(shù)</p> </div> </a> </div> </div> </div> </div>
我們得到的首頁效果大致如圖4所示,。 圖4 微信客戶端首頁效果圖 設(shè)計微信客戶端功能頁樣式 以娃像誰-單人照的頁面為例,頁面代碼如下,。 <div class='pic_panel'> <div class='parent' id='parent1'> <i class='icon iconfont icon-210 human'></i> </div> <div class='parent' id='parent2'> <i class='icon iconfont icon-nv human'></i> </div> <div class='clear'></div> <div class='parent1like like'></div> <div class='parent2like like'></div> <div class='clear'></div> <div class='picture' id='child'> <i class='icon iconfont icon-child human'></i> </div> <form> <input type='button' class='next' id='uploadImage' value='GO !!!'> </form> </div>
id=”parent1” 和 id=”parent2” 為存放父母照片的容器,,id=”child”為存放孩子照片的容器,點擊容器觸發(fā)選擇照片,,選擇完成點擊按鈕作比較,。class=”parent1like”和class=”parent2like” 分別顯示 id=”child”分別與id=”parent1”和id=”parent2” 對比的結(jié)果。 我們得到的頁面效果類似圖5所示的樣子,。 圖5 娃像誰—單人照的頁面效果圖 實現(xiàn)微信客戶端交互 在之前我們寫了一個WebAPI接口來實現(xiàn)微信JS-SDK接口注入權(quán)限驗證配置,,現(xiàn)在我們的客戶端需要調(diào)用這個接口來做驗證了??蛻舳四阈枰胘weixin-1.0.0.js,。 只要我們的業(yè)務(wù)需要使用微信JS-SDK,則都需要完成接口注入的權(quán)限驗證,,驗證的方式我們來一步步分析見圖6,。 圖6 JS-SDK接口注入的權(quán)限驗證過程 頁面將noncestr(這個可以是頁面定義一個常數(shù))、timestamp(其實也可以是常數(shù)),、url當前頁面地址提交給我們最早寫的/api/weixin接口,,然后將返回的簽名提交給wx.config即可。下面的代碼可以作為你的模板使用,。 $(function { var timestamp = Date.parse(new Date)/1000; var localurl = encodeURIComponent(window.location.href.split('#')[0]); $.ajax({ url: 'http://www.********.cn/wxapi/api/weixin', dataType: 'json', data: { noncestr: 'FFUmZdbWVT9mVP7a', timestamp: timestamp, url: window.location.href.split('#')[0] }, success: function (data) { wxFace(data.toLowerCase); } }) function wxFace(signature) { wx.config({ debug: false, appId: 'wxec54ec7f720993da', timestamp: timestamp, nonceStr: 'FFUmZdbWVT9mVP7a', signature: signature, jsApiList: [ 'checkJsApi', 'onMenuShareTimeline', 'onMenuShareAppMessage', 'chooseImage', 'previewImage', 'uploadImage', 'downloadImage' ] }); } });
然后我們定義選擇圖片函數(shù),,當選擇id=”parent1”、 id=”parent2”,、id=”child”時調(diào)用,。 function chooseUpload(selector) { wx.chooseImage({ success: function (res) { $('#loading').show; $(function { $.each(res.localIds, function (i, n) { wx.uploadImage({ localId: res.localIds.toString, // 需要上傳的圖片的本地ID,由chooseImage接口獲得 isShowProgressTips: 0, // 默認為1,,顯示進度提示 success: function (res1) { $.ajax({ url: 'http://www.******.cn/wxapi/face/detect/' res1.serverId, dataType: 'json', success: function (data) { $('#loading').hide; if (JSON.parse(data).length == 1) { $(selector).html('<img src='' n ''> <br>') .data('faceId', JSON.parse(data)[0].faceId); } else if (JSON.parse(data).length > 1) { alert('請選擇單人照哦') } else { alert('啊,,我看不到你的臉~') } } }) }, fail: function (res) { alert(JSON.stringify(res)); } }); }); }); } }); }
觸發(fā)點擊事件調(diào)用上傳圖片函數(shù),。 document.querySelector('#parent1').onclick = function { chooseUpload('#parent1') }; 定義函數(shù),將拿到的兩張照片的id做對比,。 function verify(selector, parent, child) { $('#loading').show; $.ajax({ url: 'http://www.******.cn/wxapi/face/verify/' parent '/' child, dataType: 'json', success: function (data) { $('#loading').hide; $(selector).html('相似度:' (JSON.parse(data).confidence * 100).toFixed(2) '%') } }) }
最后是我們分享朋友圈的功能實現(xiàn),。 var shareData = { title: '測測孩子跟誰像',//分享的標題 desc: '來看看孩子跟爸爸比較像還是跟媽媽比較像',//分享的描述 link: window.location.href,//分享的快照 imgUrl: 'http://www. .******.cn/WeFace/fonts/family.jpg'//分享的鏈接 }; wx.onMenuShareAppMessage(shareData); wx.onMenuShareTimeline(shareData);
分享結(jié)果如圖7所示。 圖7 朋友圈分享功能效果圖 總結(jié) 本文主要針對如何使用APS.NET WebAPI實現(xiàn)微信注入進行了深入講解,。下期會承接本文,,重點分享服務(wù)的實現(xiàn)過程,內(nèi)容主要有:調(diào)用封裝微軟牛津計劃API,、使用MongoDB存儲數(shù)據(jù)和客戶端如何使用,。全文閱讀完畢后,你將可以自己去編寫更有價值的應(yīng)用了,。 作者:王豫翔,,微軟連續(xù)多年多個方向的MVP,目前主要關(guān)注大數(shù)據(jù),、云技術(shù)和人工智能,。在編程道路上遵循自己的“三少”“三多”原則:少討論概念,少爭論特征,、少議論模型,;多寫代碼、多做測試,、多做應(yīng)用,。
|