微信語義理解接口提供從用戶自然語言輸入到結(jié)構(gòu)化解析的技術(shù)實(shí)現(xiàn)剃斧,使用先進(jìn)的自然語言處理技術(shù)給開發(fā)者提供一站式的語義解析方案奠蹬。該平臺覆蓋多個(gè)垂直領(lǐng)域的語義場景专筷,部分領(lǐng)域還可以支持取得最終的展示結(jié)果。開發(fā)者無需掌握語義理解及相關(guān)技術(shù)宣吱,只需根據(jù)自己的產(chǎn)品特點(diǎn),選擇相應(yīng)的服務(wù)即可搭建一套智能語義服務(wù)桩砰。結(jié)合語音識別接口拓春,通過微信語音識別得到用戶的語音信息之后释簿,經(jīng)過語義分析理解亚隅,得到用戶需求,及時(shí)回復(fù)用戶庶溶。本文介紹如何實(shí)現(xiàn)對微信語義接口的封裝處理煮纵,以及一些常用場景的調(diào)用。
1偏螺、微信語義理解接口
這個(gè)東西也就是把我們?nèi)粘5脑捳Z(稱之為自然語言)解析為對應(yīng)的信息結(jié)構(gòu)體行疏,方便我們提取里面的相關(guān)信息進(jìn)行搜索查詢,并精確回應(yīng)給對應(yīng)的請求者的一個(gè)橋梁套像,其主要的功能就是解析我們所說的內(nèi)容酿联。
微信開放平臺語義理解接口調(diào)用(http請求)簡單方便,用戶無需掌握語義理解及相關(guān)技術(shù)夺巩,只需根據(jù)自己的產(chǎn)品特點(diǎn)贞让,選擇相應(yīng)的服務(wù)即可搭建一套智能語義服務(wù)。我們來看看微信語義理解接口的定義內(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":"查一下明天從北京到上海的南航機(jī)票",
"city":"北京",
"category": "flight,hotel",
"appid":"wxaaaaaaaaaaaaaaaa",
"uid":"123456"
}
參數(shù)說明
注:單類別意圖比較明確,識別的覆蓋率比較大美澳,所以如果只要使用特定某個(gè)類別销部,建議將category只設(shè)置為該類別。
返回說明 正常情況下制跟,微信會(huì)返回下述JSON數(shù)據(jù)包:
{
“errcode”:0,
“query”:”查一下明天從北京到上海的南航機(jī)票”,
“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ù)說明
上面就是微信官方給出的代碼案例雨膨,以及一個(gè)《語義理解接口協(xié)議文檔》擂涛,里面介紹了各個(gè)場景的語義結(jié)構(gòu)信息,雖然這個(gè)文檔好像好久都沒怎么更新哥放,不過總體內(nèi)容還是穩(wěn)定的歼指,我們可以通過這個(gè)文檔進(jìn)行相關(guān)的類庫設(shè)計(jì)工作。
2甥雕、語義理解接口的C#實(shí)現(xiàn)
根據(jù)《語義理解接口協(xié)議文檔》文檔踩身,我們可以定義各種所需的語義結(jié)構(gòu)類庫,這些是我們開展語義接口的基礎(chǔ)類社露。
例如我們定義基礎(chǔ)的時(shí)間協(xié)議類挟阻,如下所示。
/// <summary>
/// 時(shí)間相關(guān)協(xié)議datetime
/// </summary>
public class Semantic_DateTime
{
/// <summary>
/// 單時(shí)間的描述協(xié)議類型:“DT_SINGLE”。DT_SINGLE又細(xì)分為兩個(gè)類別:DT_ORI和DT_INFER附鸽。DT_ORI是字面時(shí)間脱拼,比如:“上午九點(diǎn)”;
/// DT_INFER是推理時(shí)間坷备,比如:“提前5分鐘”熄浓。 時(shí)間段的描述協(xié)議類型:“DT_INTERVAL”
/// 重復(fù)時(shí)間的描述協(xié)議類型:“DT_REPEAT” DT_ REPEAT又細(xì)分為兩個(gè)類別:DT_RORI和DT_RINFER。DT_RORI是字面時(shí)間省撑,比如:“每天上午九點(diǎn)”赌蔑;DT_RINFER是推理時(shí)間,比如:“工作日除外”
/// </summary>
public string type { get; set; }
/// <summary>
/// 24小時(shí)制竟秫,格式:HH:MM:SS娃惯,默認(rèn)為00:00:00
/// </summary>
public string time { get; set; }
/// <summary>
/// Time的原始字符串
/// </summary>
public string time_ori { get; set; }
}
/// <summary>
/// 單時(shí)間的描述協(xié)議datetime
/// </summary>
public class Semantic_SingleDateTime : Semantic_DateTime
{
/// <summary>
/// 格式:YYYY-MM-DD,默認(rèn)是當(dāng)天時(shí)間
/// </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; }
}
當(dāng)然時(shí)間還有很多類型的定義肥败,都基本上按照文檔所列的字段進(jìn)行處理趾浅,上面的代碼只是定義了常用的單時(shí)間的描述協(xié)議類型:“DT_SINGLE”。
除了時(shí)間協(xié)議馒稍,還有數(shù)字皿哨,地點(diǎn)位置等相關(guān)協(xié)議,如數(shù)字協(xié)議如下所示筷黔。
public class Semantic_Number
{
/// <summary>
/// 大類型:“NUMBER” NUMBER又細(xì)分為如下類別: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>
/// 結(jié)束
/// </summary>
public string end { get; set; }
}
地點(diǎn)位置協(xié)議如下所示
/// <summary>
/// 地點(diǎn)相關(guān)協(xié)議
/// </summary>
public class Semantic_Location
{
/// <summary>
/// 大類型:“LOC” LOC又細(xì)分為如下類別: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ù)格式是一個(gè)較為固定的格式內(nèi)容润梯,我們可以把它定義為一個(gè)類过牙,方便數(shù)據(jù)處理甥厦。
POST數(shù)據(jù)格式:JSON,POST數(shù)據(jù)例子如下所示:
{
"query":"查一下明天從北京到上海的南航機(jī)票",
"city":"北京",
"category": "flight,hotel",
"appid":"wxaaaaaaaaaaaaaaaa",
"uid":"123456"
}
那么我們可以定義它的類庫如下所示寇钉。
/// <summary>
/// 語義查詢條件
/// </summary>
public class SemanticQueryJson
{
/// <summary>
/// 輸入文本串
/// 必填
/// </summary>
public string query { get; set; }
/// <summary>
/// 需要使用的服務(wù)類別刀疙,多個(gè)用,隔開,不能為空
/// 必填
/// </summary>
public string category { get; set; }
/// <summary>
/// 城市名稱扫倡,與經(jīng)緯度二選一傳入
/// 見說明谦秧,選填
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public string city { get; set; }
/// <summary>
/// App id,開發(fā)者的唯一標(biāo)識镊辕,用于區(qū)分開放者油够,如果為空蚁袭,則沒法使用上下文理解功能征懈。
/// 非必填
/// </summary>
public string appid { get; set; }
/// <summary>
/// 用戶唯一id(并非開發(fā)者id),用于區(qū)分該開發(fā)者下不同用戶揩悄,如果為空卖哎,則沒法使用上下文理解功能。appid和uid同時(shí)存在的情況下删性,才可以使用上下文理解功能亏娜。
/// 非必填
/// </summary>
public string uid { get; set; }
................
}
接著我們分析語義理解的接口返回值,它們基本上都是很有規(guī)律的內(nèi)容蹬挺,如下所示维贺。
這樣我們也就可以定義一個(gè)通用的類庫對象,用來存儲不同的返回內(nèi)容了巴帮,如下代碼所示溯泣。
/// <summary>
/// 微信語義結(jié)果
/// </summary>
public class SemanticResultJson<T> : ErrorJsonResult
{
/// <summary>
/// 用戶的輸入字符串
/// </summary>
public string query { get; set; }
/// <summary>
/// 服務(wù)的全局類別id
/// </summary>
public string type { get; set; }
/// <summary>
/// 語義理解后的結(jié)構(gòu)化標(biāo)識,各服務(wù)不同
/// </summary>
public T semantic { get; set; }
}
而其中的T semantic就是另外一個(gè)結(jié)構(gòu)體里面的內(nèi)容榕茧,這個(gè)結(jié)構(gòu)體總體也是固定的內(nèi)容垃沦,我們繼續(xù)定義一個(gè)如下的類。
/// <summary>
/// 詳細(xì)信息里面的對象
/// </summary>
/// <typeparam name="T"></typeparam>
public class SemanticDetail<T>
{
/// <summary>
/// 詳細(xì)信息
/// </summary>
public T details { get; set; }
/// <summary>
/// 查詢類型
/// </summary>
public string intent { get; set; }
}
有了這些類庫的支持用押,我們可以封裝語義理解接口的返回值了肢簿,這樣它的接口定義和封裝處理代碼如下所示。
/// <summary>
/// 語意理解接口
/// 微信開放平臺語義理解接口調(diào)用(http請求)簡單方便蜻拨,用戶無需掌握語義理解及相關(guān)技術(shù)池充,只需根據(jù)自己的產(chǎn)品特點(diǎn),選擇相應(yīng)的服務(wù)即可搭建一套智能語義服務(wù)缎讼。
/// </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);
}
由于微信語義結(jié)果是針對不同的服務(wù)協(xié)議收夸,我們需要根據(jù)這些不同的服務(wù)協(xié)議,來定義屬于這些信息結(jié)構(gòu)休涤,如在文檔里咱圆,我們可以看到有很多不同類型的服務(wù)協(xié)議笛辟。
根據(jù)文檔的詳細(xì)字段說明,我們可以定義不同服務(wù)的對應(yīng)類庫序苏。
例如對于旅游服務(wù)的語義理解手幢,它們的協(xié)議類如下所示。
/// <summary>
/// 旅游服務(wù)(travel)
/// </summary>
public class Semantic_Details_Travel
{
/// <summary>
/// 旅游目的地
/// </summary>
public Semantic_Location location { get; set; }
/// <summary>
/// 景點(diǎn)名稱
/// </summary>
public string spot { get; set; }
/// <summary>
/// 旅游日期
/// </summary>
public Semantic_SingleDateTime datetime { get; set; }
/// <summary>
/// 旅游類型詞
/// </summary>
public string tag { get; set; }
/// <summary>
/// 0默認(rèn)忱详,1自由行围来,2跟團(tuán)游
/// </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());
如果我們測試,上面的代碼跑起來會(huì)返回一個(gè)旅游的協(xié)議對象匈睁,包括了相關(guān)的數(shù)據(jù)信息监透。
{
"errcode" : 0,
"query" : "故宮門票多少錢",
"semantic" : {
"details" : {
"answer" : "",
"context_info" : {},
"hit_str" : "故宮 門票 多少 錢 ",
"spot" : "故宮"
},
"intent" : "PRICE"
},
"type" : "travel"
}
我們再來看一個(gè)例子,例如對于航班服務(wù)航唆,我們定義它的語義理解協(xié)議如下所示胀蛮。
/// <summary>
/// 航班服務(wù)(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>
/// 座位級別(默認(rèn)無限制):ECONOMY(經(jīng)濟(jì)艙)BIZ(商務(wù)艙)FIRST(頭等艙)
/// </summary>
public string seat { get; set; }
/// <summary>
/// 排序類型:0排序無要求(默認(rèn)),1價(jià)格升序糯钙,2價(jià)格降序粪狼,3時(shí)間升序,4時(shí)間降序
/// </summary>
public int sort { get; set; }
}
那么調(diào)用獲取語義理解內(nèi)容的代碼如下所示任岸。
json = new SemanticQueryJson
{
appid = appId,
uid = openId,
category = SemanticCategory.flight.ToString(),
query = "查一下明天從廣州到上海的南航機(jī)票",
city = "廣州"
};
var flight = api.SearchSemantic<Semantic_Details_Flight>(token, json);
Console.WriteLine(flight.ToJson());
我們可以獲取到的JSON數(shù)據(jù)如下所示
{
"errcode" : 0,
"query" : "查一下明天從廣州到上海的南航機(jī)票",
"semantic" : {
"details" : {
"airline" : "中國南方航空公司",
"answer" : "已幫您預(yù)定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" : "查 一下 明天 從 廣州 到 上海 南航 機(jī)票 ",
"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ī)的語義享潜,分析成了機(jī)器可以識別的準(zhǔn)確的數(shù)據(jù)結(jié)構(gòu)了困鸥,我們可以根據(jù)不同的語義場合對它進(jìn)行分析,然后給用戶進(jìn)行不同的響應(yīng)就可以了剑按,結(jié)合微信語音識別為文本內(nèi)容疾就,我們可以把它做得很強(qiáng)大,有的類似機(jī)器智能的味道了吕座。
微信語義理解是一個(gè)好東西虐译,不過在微信官網(wǎng)上沒有看到進(jìn)一步的案例,如果能夠有一些與實(shí)際結(jié)合的例子吴趴,估計(jì)更能幫助我們理解和應(yīng)用了漆诽。