微信語(yǔ)義理解接口提供從用戶自然語(yǔ)言輸入到結(jié)構(gòu)化解析的技術(shù)實(shí)現(xiàn),使用先進(jìn)的自然語(yǔ)言處理技術(shù)給開發(fā)者提供一站式的語(yǔ)義解析方案。該平臺(tái)覆蓋多個(gè)垂直領(lǐng)域的語(yǔ)義場(chǎng)景,部分領(lǐng)域還可以支持取得最終的展示結(jié)果。開發(fā)者無需掌握語(yǔ)義理解及相關(guān)技術(shù),只需根據(jù)自己的產(chǎn)品特點(diǎn),選擇相應(yīng)的服務(wù)即可搭建一套智能語(yǔ)義服務(wù)。結(jié)合語(yǔ)音識(shí)別接口,通過微信語(yǔ)音識(shí)別得到用戶的語(yǔ)音信息之后,經(jīng)過語(yǔ)義分析理解,得到用戶需求,及時(shí)回復(fù)用戶。本文介紹如何實(shí)現(xiàn)對(duì)微信語(yǔ)義接口的封裝處理,以及一些常用場(chǎng)景的調(diào)用。
1、微信語(yǔ)義理解接口
這個(gè)東西也就是把我們?nèi)粘5脑捳Z(yǔ)(稱之為自然語(yǔ)言)解析為對(duì)應(yīng)的信息結(jié)構(gòu)體,方便我們提取里面的相關(guān)信息進(jìn)行搜索查詢,并精確回應(yīng)給對(duì)應(yīng)的請(qǐng)求者的一個(gè)橋梁,其主要的功能就是解析我們所說的內(nèi)容。
微信開放平臺(tái)語(yǔ)義理解接口調(diào)用(http請(qǐng)求)簡(jiǎn)單方便,用戶無需掌握語(yǔ)義理解及相關(guān)技術(shù),只需根據(jù)自己的產(chǎn)品特點(diǎn),選擇相應(yīng)的服務(wù)即可搭建一套智能語(yǔ)義服務(wù)。我們來看看微信語(yǔ)義理解接口的定義內(nèi)容。
http請(qǐng)求方式: POST(請(qǐng)使用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ù)說明
注:?jiǎn)晤悇e意圖比較明確,識(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”:”中國(guó)南方航空公司”
},
“intent”:”SEARCH”
}
返回參數(shù)說明
上面就是微信官方給出的代碼案例,以及一個(gè)《語(yǔ)義理解接口協(xié)議文檔》,里面介紹了各個(gè)場(chǎng)景的語(yǔ)義結(jié)構(gòu)信息,雖然這個(gè)文檔好像好久都沒怎么更新,不過總體內(nèi)容還是穩(wěn)定的,我們可以通過這個(gè)文檔進(jìn)行相關(guān)的類庫(kù)設(shè)計(jì)工作。
2、語(yǔ)義理解接口的C#實(shí)現(xiàn)
根據(jù)《語(yǔ)義理解接口協(xié)議文檔》文檔,我們可以定義各種所需的語(yǔ)義結(jié)構(gòu)類庫(kù),這些是我們開展語(yǔ)義接口的基礎(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>
/// 國(guó)家
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public string country { get; set; }
/// <summary>
/// 省全稱,例如:廣東省
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public string province { get; set; }
/// <summary>
/// 省簡(jiǎn)稱,例如:廣東|粵
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public string province_simple { get; set; }
/// <summary>
/// 市全稱,例如:北京市
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public string city { get; set; }
/// <summary>
/// 市簡(jiǎn)稱,例如:北京
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public string city_simple { get; set; }
..............
前面我們看到了,語(yǔ)音立即的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"
}
那么我們可以定義它的類庫(kù)如下所示。
/// <summary>
/// 語(yǔ)義查詢條件
/// </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)識(shí),用于區(qū)分開放者,如果為空,則沒法使用上下文理解功能。
/// 非必填
/// </summary>
public string appid { get; set; }
/// <summary>
/// 用戶唯一id(并非開發(fā)者id),用于區(qū)分該開發(fā)者下不同用戶,如果為空,則沒法使用上下文理解功能。appid和uid同時(shí)存在的情況下,才可以使用上下文理解功能。
/// 非必填
/// </summary>
public string uid { get; set; }
................
}
接著我們分析語(yǔ)義理解的接口返回值,它們基本上都是很有規(guī)律的內(nèi)容,如下所示。
這樣我們也就可以定義一個(gè)通用的類庫(kù)對(duì)象,用來存儲(chǔ)不同的返回內(nèi)容了,如下代碼所示。
/// <summary>
/// 微信語(yǔ)義結(jié)果
/// </summary>
public class SemanticResultJson<T> : ErrorJsonResult
{
/// <summary>
/// 用戶的輸入字符串
/// </summary>
public string query { get; set; }
/// <summary>
/// 服務(wù)的全局類別id
/// </summary>
public string type { get; set; }
/// <summary>
/// 語(yǔ)義理解后的結(jié)構(gòu)化標(biāo)識(shí),各服務(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ì)信息里面的對(duì)象
/// </summary>
/// <typeparam name="T"></typeparam>
public class SemanticDetail<T>
{
/// <summary>
/// 詳細(xì)信息
/// </summary>
public T details { get; set; }
/// <summary>
/// 查詢類型
/// </summary>
public string intent { get; set; }
}
有了這些類庫(kù)的支持,我們可以封裝語(yǔ)義理解接口的返回值了,這樣它的接口定義和封裝處理代碼如下所示。
/// <summary>
/// 語(yǔ)意理解接口
/// 微信開放平臺(tái)語(yǔ)義理解接口調(diào)用(http請(qǐng)求)簡(jiǎn)單方便,用戶無需掌握語(yǔ)義理解及相關(guān)技術(shù),只需根據(jù)自己的產(chǎn)品特點(diǎn),選擇相應(yīng)的服務(wù)即可搭建一套智能語(yǔ)義服務(wù)。
/// </summary>
public class SemanticApi : ISemanticApi
{
/// <summary>
/// 發(fā)送語(yǔ)義理解請(qǐng)求
/// </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);
}
由于微信語(yǔ)義結(jié)果是針對(duì)不同的服務(wù)協(xié)議,我們需要根據(jù)這些不同的服務(wù)協(xié)議,來定義屬于這些信息結(jié)構(gòu),如在文檔里,我們可以看到有很多不同類型的服務(wù)協(xié)議。
根據(jù)文檔的詳細(xì)字段說明,我們可以定義不同服務(wù)的對(duì)應(yīng)類庫(kù)。
例如對(duì)于旅游服務(wù)的語(yǔ)義理解,它們的協(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)用的旅游語(yǔ)義的案例代碼如下所示
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());
如果我們測(cè)試,上面的代碼跑起來會(huì)返回一個(gè)旅游的協(xié)議對(duì)象,包括了相關(guān)的數(shù)據(jù)信息。
{
"errcode" : 0,
"query" : "故宮門票多少錢",
"semantic" : {
"details" : {
"answer" : "",
"context_info" : {},
"hit_str" : "故宮 門票 多少 錢 ",
"spot" : "故宮"
},
"intent" : "PRICE"
},
"type" : "travel"
}
我們?cè)賮砜匆粋€(gè)例子,例如對(duì)于航班服務(wù),我們定義它的語(yǔ)義理解協(xié)議如下所示。
/// <summary>
/// 航班服務(wù)(flight)
/// </summary>
public class Semantic_Details_Flight
{
/// <summary>
/// 航班號(hào)
/// </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>
/// 座位級(jí)別(默認(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)用獲取語(yǔ)義理解內(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" : "中國(guó)南方航空公司",
"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ī)的語(yǔ)義,分析成了機(jī)器可以識(shí)別的準(zhǔn)確的數(shù)據(jù)結(jié)構(gòu)了,我們可以根據(jù)不同的語(yǔ)義場(chǎng)合對(duì)它進(jìn)行分析,然后給用戶進(jìn)行不同的響應(yīng)就可以了,結(jié)合微信語(yǔ)音識(shí)別為文本內(nèi)容,我們可以把它做得很強(qiáng)大,有的類似機(jī)器智能的味道了。
微信語(yǔ)義理解是一個(gè)好東西,不過在微信官網(wǎng)上沒有看到進(jìn)一步的案例,如果能夠有一些與實(shí)際結(jié)合的例子,估計(jì)更能幫助我們理解和應(yīng)用了。