C#開發(fā)微信門戶及應用(31)--微信語義理解接口的實現(xiàn)和處理
微信語義理解接口提供從用戶自然語言輸入到結構化解析的技術實現(xiàn),使用先進的自然語言處理技術給開發(fā)者提供一站式的語義解析方案。該平臺覆蓋多個垂直領域的語義場景,部分領域還可以支持取得最終的展示結果。開發(fā)者無需掌握語義理解及相關技術,只需根據(jù)自己的產(chǎn)品特點,選擇相應的服務即可搭建一套智能語義服務。結合語音識別接口,通過微信語音識別得到用戶的語音信息之后,經(jīng)過語義分析理解,得到用戶需求,及時回復用戶。本文介紹如何實現(xiàn)對微信語義接口的封裝處理,以及一些常用場景的調(diào)用。
1)微信語義理解接口
這個東西也就是把我們?nèi)粘5脑捳Z(稱之為自然語言)解析為對應的信息結構體,方便我們提取里面的相關信息進行搜索查詢,并精確回應給對應的請求者的一個橋梁,其主要的功能就是解析我們所說的內(nèi)容。
微信開放平臺語義理解接口調(diào)用(http請求)簡單方便,用戶無需掌握語義理解及相關技術,只需根據(jù)自己的產(chǎn)品特點,選擇相應的服務即可搭建一套智能語義服務。我們來看看微信語義理解接口的定義內(nèi)容。
http請求方式: POST(請使用https協(xié)議)
https://api.weixin.qq.com/semantic/semproxy/search?access_token=YOUR_ACCESS_TOKEN
POST數(shù)據(jù)格式:JSON,POST數(shù)據(jù)例子:
{ "query":"查一下明天從北京到上海的南航機票", "city":"北京", "category": "flight,hotel", "appid":"wxaaaaaaaaaaaaaaaa", "uid":"123456" }
參數(shù)說明
參數(shù) | 是否必須 | 參數(shù)類型 | 說明 |
access_token | 是 | String | 根據(jù)appid和appsecret獲取到的token |
query | 是 | String | 輸入文本串 |
category | 是 | String | 需要使用的服務類型,多個用“,”隔開,不能為空 |
latitude | 見接口協(xié)議文檔 | Float | 緯度坐標,與經(jīng)度同時傳入;與城市二選一傳入 |
longitude | 見接口協(xié)議文檔 | Float | 經(jīng)度坐標,與緯度同時傳入;與城市二選一傳入 |
city | 見接口協(xié)議文檔 | String | 城市名稱,與經(jīng)緯度二選一傳入 |
region | 見接口協(xié)議文檔 | String | 區(qū)域名稱,在城市存在的情況下可省;與經(jīng)緯度二選一傳入 |
appid | 是 | String | 公眾號唯一標識,用于區(qū)分公眾號開發(fā)者 |
uid | 否 | String | 用戶唯一id(非開發(fā)者id),用戶區(qū)分公眾號下的不同用戶(建議填入用戶openid),如果為空,則無法使用上下文理解功能。appid和uid同時存在的情況下,才可以使用上下文理解功能。 |
注:單類別意圖比較明確,識別的覆蓋率比較大,所以如果只要使用特定某個類別,建議將category只設置為該類別。
返回說明 正常情況下,微信會返回下述JSON數(shù)據(jù)包:
{ “errcode”:0, “query”:”查一下明天從北京到上海的南航機票”, “type”:”flight”, “semantic”:{ “details”:{ “start_loc”:{ “type”:”LOC_CITY”, “city”:”北京市”, “city_simple”:”北京”, “l(fā)oc_ori”:”北京” }, “end_loc”: { “type”:”LOC_CITY”, “city”:”上海市”, “city_simple”:”上海”, “l(fā)oc_ori”:”上?!? }, “start_date”: { “type”:”DT_ORI”, “date”:”2014-03-05”, “date_ori”:”明天” }, “airline”:”中國南方航空公司” }, “intent”:”SEARCH” }
?
返回參數(shù)說明
參數(shù) | 是否必須 | 參數(shù)類型 | 說明 |
errcode | 是 | Int | 表示請求后的狀態(tài) |
query | 是 | String | 用戶的輸入字符串 |
type | 是 | String | 服務的全局類型id,詳見協(xié)議文檔中垂直服務協(xié)議定義 |
semantic | 是 | Object | 語義理解后的結構化標識,各服務不同 |
result | 否 | Array | 部分類別的結果 |
answer | 否 | String | 部分類別的結果html5展示,目前不支持 |
text | 否 | String | 特殊回復說明 |
上面就是微信官方給出的代碼案例,以及一個《語義理解接口協(xié)議文檔》,里面介紹了各個場景的語義結構信息,雖然這個文檔好像好久都沒怎么更新,不過總體內(nèi)容還是穩(wěn)定的,我們可以通過這個文檔進行相關的類庫設計工作。
?
2、語義理解接口的C#實現(xiàn)
根據(jù)《語義理解接口協(xié)議文檔》文檔,我們可以定義各種所需的語義結構類庫,這些是我們開展語義接口的基礎類。
例如我們定義基礎的時間協(xié)議類,如下所示。
/// <summary> /// 時間相關協(xié)議datetime /// </summary> public class Semantic_DateTime { /// <summary> /// 單時間的描述協(xié)議類型:“DT_SINGLE”。DT_SINGLE又細分為兩個類別:DT_ORI和DT_INFER。DT_ORI是字面時間,比如:“上午九點”; /// DT_INFER是推理時間,比如:“提前5分鐘”。 時間段的描述協(xié)議類型:“DT_INTERVAL” /// 重復時間的描述協(xié)議類型:“DT_REPEAT” DT_ REPEAT又細分為兩個類別:DT_RORI和DT_RINFER。DT_RORI是字面時間,比如:“每天上午九點”;DT_RINFER是推理時間,比如:“工作日除外” /// </summary> public string type { get; set; } /// <summary> /// 24小時制,格式:HH:MM:SS,默認為00:00:00 /// </summary> public string time { get; set; } /// <summary> /// Time的原始字符串 /// </summary> public string time_ori { get; set; } } /// <summary> /// 單時間的描述協(xié)議datetime /// </summary> public class Semantic_SingleDateTime : Semantic_DateTime { /// <summary> /// 格式:YYYY-MM-DD,默認是當天時間 /// </summary> public string date { get; set; } /// <summary> /// 格式:YYYY-MM-DD 農(nóng)歷 /// </summary> public string date_lunar { get; set; } /// <summary> /// date的原始字符串 /// </summary> public string date_ori { get; set; } }
當然時間還有很多類型的定義,都基本上按照文檔所列的字段進行處理,上面的代碼只是定義了常用的單時間的描述協(xié)議類型:“DT_SINGLE”。
除了時間協(xié)議,還有數(shù)字,地點位置等相關協(xié)議,如數(shù)字協(xié)議如下所示。
public class Semantic_Number { /// <summary> /// 大類型:“NUMBER” NUMBER又細分為如下類別:NUM_PRICE、NUM_PADIUS、NUM_DISCOUNT、NUM_SEASON、NUM_EPI、NUM_CHAPTER。 /// </summary> public string type { get; set; } /// <summary> /// 開始 /// </summary> public string begin { get; set; } /// <summary> /// 結束 /// </summary> public string end { get; set; } }
地點位置協(xié)議如下所示
/// <summary> /// 地點相關協(xié)議 /// </summary> public class Semantic_Location { /// <summary> /// 大類型:“LOC” LOC又細分為如下類別:LOC_COUNTRY、LOC_PROVINCE、LOC_CITY、LOC_TOWN、LOC_POI、NORMAL_POI。 /// </summary> public string type { get; set; } /// <summary> /// 國家 /// </summary> [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public string country { get; set; } /// <summary> /// 省全稱,例如:廣東省 /// </summary> [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public string province { get; set; } /// <summary> /// 省簡稱,例如:廣東|粵 /// </summary> [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public string province_simple { get; set; } /// <summary> /// 市全稱,例如:北京市 /// </summary> [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public string city { get; set; } /// <summary> /// 市簡稱,例如:北京 /// </summary> [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public string city_simple { get; set; } ..............
前面我們看到了,語音立即的POST數(shù)據(jù)格式是一個較為固定的格式內(nèi)容,我們可以把它定義為一個類,方便數(shù)據(jù)處理。
POST數(shù)據(jù)格式:JSON,POST數(shù)據(jù)例子如下所示:
{ "query":"查一下明天從北京到上海的南航機票", "city":"北京", "category": "flight,hotel", "appid":"wxaaaaaaaaaaaaaaaa", "uid":"123456" }
那么我們可以定義它的類庫如下所示。
/// <summary> /// 語義查詢條件 /// </summary> public class SemanticQueryJson { /// <summary> /// 輸入文本串 /// 必填 /// </summary> public string query { get; set; } /// <summary> /// 需要使用的服務類別,多個用,隔開,不能為空 /// 必填 /// </summary> public string category { get; set; } /// <summary> /// 城市名稱,與經(jīng)緯度二選一傳入 /// 見說明,選填 /// </summary> [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public string city { get; set; } /// <summary> /// App id,開發(fā)者的唯一標識,用于區(qū)分開放者,如果為空,則沒法使用上下文理解功能。 /// 非必填 /// </summary> public string appid { get; set; } /// <summary> /// 用戶唯一id(并非開發(fā)者id),用于區(qū)分該開發(fā)者下不同用戶,如果為空,則沒法使用上下文理解功能。appid和uid同時存在的情況下,才可以使用上下文理解功能。 /// 非必填 /// </summary> public string uid { get; set; } ................ }
接著我們分析語義理解的接口返回值,它們基本上都是很有規(guī)律的內(nèi)容,如下所示。
這樣我們也就可以定義一個通用的類庫對象,用來存儲不同的返回內(nèi)容了,如下代碼所示。
/// <summary> /// 微信語義結果 /// </summary> public class SemanticResultJson<T> : ErrorJsonResult { /// <summary> /// 用戶的輸入字符串 /// </summary> public string query { get; set; } /// <summary> /// 服務的全局類別id /// </summary> public string type { get; set; } /// <summary> /// 語義理解后的結構化標識,各服務不同 /// </summary> public T semantic { get; set; } }
而其中的T semantic就是另外一個結構體里面的內(nèi)容,這個結構體總體也是固定的內(nèi)容,我們繼續(xù)定義一個如下的類。
/// <summary> /// 詳細信息里面的對象 /// </summary> /// <typeparam name="T"></typeparam> public class SemanticDetail<T> { /// <summary> /// 詳細信息 /// </summary> public T details { get; set; } /// <summary> /// 查詢類型 /// </summary> public string intent { get; set; } }
有了這些類庫的支持,我們可以封裝語義理解接口的返回值了,這樣它的接口定義和封裝處理代碼如下所示。
/// <summary> /// 語意理解接口 /// 微信開放平臺語義理解接口調(diào)用(http請求)簡單方便,用戶無需掌握語義理解及相關技術,只需根據(jù)自己的產(chǎn)品特點,選擇相應的服務即可搭建一套智能語義服務。 /// </summary> public class SemanticApi : ISemanticApi { /// <summary> /// 發(fā)送語義理解請求 /// </summary> /// <param name="accessToken">調(diào)用接口憑證</param> /// <param name="data">查詢條件</param> public SemanticResultJson<SemanticDetail<T>> SearchSemantic<T>(string accessToken, SemanticQueryJson data) { var url = string.Format("https://api.weixin.qq.com/semantic/semproxy/search?access_token={0}", accessToken); string postData = data.ToJson(); return JsonHelper<SemanticResultJson<SemanticDetail<T>>>.ConvertJson(url, postData); }
由于微信語義結果是針對不同的服務協(xié)議,我們需要根據(jù)這些不同的服務協(xié)議,來定義屬于這些信息結構,如在文檔里,我們可以看到有很多不同類型的服務協(xié)議。
根據(jù)文檔的詳細字段說明,我們可以定義不同服務的對應類庫。
例如對于旅游服務的語義理解,它們的協(xié)議類如下所示。
/// <summary> /// 旅游服務(travel) /// </summary> public class Semantic_Details_Travel { /// <summary> /// 旅游目的地 /// </summary> public Semantic_Location location { get; set; } /// <summary> /// 景點名稱 /// </summary> public string spot { get; set; } /// <summary> /// 旅游日期 /// </summary> public Semantic_SingleDateTime datetime { get; set; } /// <summary> /// 旅游類型詞 /// </summary> public string tag { get; set; } /// <summary> /// 0默認,1自由行,2跟團游 /// </summary> public int category { get; set; } }
那么調(diào)用的旅游語義的案例代碼如下所示
var api = new SemanticApi(); var json = new SemanticQueryJson { appid = appId, uid = openId, category = SemanticCategory.travel.ToString(), query = "故宮門票多少錢", city = "北京市" }; var travel = api.SearchSemantic<Semantic_Details_Travel>(token, json); Console.WriteLine(travel.ToJson());
如果我們測試,上面的代碼跑起來會返回一個旅游的協(xié)議對象,包括了相關的數(shù)據(jù)信息。
{ "errcode" : 0, "query" : "故宮門票多少錢", "semantic" : { "details" : { "answer" : "", "context_info" : {}, "hit_str" : "故宮 門票 多少 錢 ", "spot" : "故宮" }, "intent" : "PRICE" }, "type" : "travel" }
我們再來看一個例子,例如對于航班服務,我們定義它的語義理解協(xié)議如下所示。
/// <summary> /// 航班服務(flight) /// </summary> public class Semantic_Details_Flight { /// <summary> /// 航班號 /// </summary> public string flight_no { get; set; } /// <summary> /// 出發(fā)地 /// </summary> public Semantic_Location start_loc { get; set; } /// <summary> /// 目的地 /// </summary> public Semantic_Location end_loc { get; set; } /// <summary> /// 出發(fā)日期 /// </summary> public Semantic_SingleDateTime start_date { get; set; } /// <summary> /// 返回日期 /// </summary> public Semantic_SingleDateTime end_date { get; set; } /// <summary> /// 航空公司 /// </summary> public string airline { get; set; } /// <summary> /// 座位級別(默認無限制):ECONOMY(經(jīng)濟艙)BIZ(商務艙)FIRST(頭等艙) /// </summary> public string seat { get; set; } /// <summary> /// 排序類型:0排序無要求(默認),1價格升序,2價格降序,3時間升序,4時間降序 /// </summary> public int sort { get; set; } }
那么調(diào)用獲取語義理解內(nèi)容的代碼如下所示。
json = new SemanticQueryJson { appid = appId, uid = openId, category = SemanticCategory.flight.ToString(), query = "查一下明天從廣州到上海的南航機票", city = "廣州" }; var flight = api.SearchSemantic<Semantic_Details_Flight>(token, json); Console.WriteLine(flight.ToJson());
我們可以獲取到的JSON數(shù)據(jù)如下所示
{ "errcode" : 0, "query" : "查一下明天從廣州到上海的南航機票", "semantic" : { "details" : { "airline" : "中國南方航空公司", "answer" : "已幫您預定2016-04-13,從廣州市出發(fā),前往上海市的航班。", "context_info" : { "isFinished" : "1", "null_times" : "0" }, "end_loc" : { "city" : "上海市", "city_simple" : "上海|滬|申", "loc_ori" : "上海", "modify_times" : "0", "slot_content_type" : "2", "type" : "LOC_CITY" }, "hit_str" : "查 一下 明天 從 廣州 到 上海 南航 機票 ", "sort" : "1", "start_date" : { "date" : "2016-04-13", "date_lunar" : "2016-03-07", "date_ori" : "明天", "modify_times" : "0", "slot_content_type" : "2", "type" : "DT_ORI", "week" : "3" }, "start_loc" : { "city" : "廣州市", "city_simple" : "廣州", "loc_ori" : "廣州", "modify_times" : "0", "province" : "廣東省", "province_simple" : "廣東|粵", "slot_content_type" : "2", "type" : "LOC_CITY" } }, "intent" : "SEARCH" }, "type" : "flight" }
這樣就是我們把我們常規(guī)的語義,分析成了機器可以識別的準確的數(shù)據(jù)結構了,我們可以根據(jù)不同的語義場合對它進行分析,然后給用戶進行不同的響應就可以了,結合微信語音識別為文本內(nèi)容,我們可以把它做得很強大,有的類似機器智能的味道了。
微信語義理解是一個好東西,不過在微信官網(wǎng)上沒有看到進一步的案例,如果能夠有一些與實際結合的例子,估計更能幫助我們理解和應用了。
?
專注于Winform開發(fā)框架/混合式開發(fā)框架、Web開發(fā)框架、Bootstrap開發(fā)框架、微信門戶開發(fā)框架的研究及應用。
??轉(zhuǎn)載請注明出處:
撰寫人:伍華聰?
本文摘自 :https://blog.51cto.com/w