C#開發(fā)微信門戶及應(yīng)用(31)--微信語義理解接口的實(shí)現(xiàn)和處理

微信語義理解接口提供從用戶自然語言輸入到結(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)用了漆诽。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市锣枝,隨后出現(xiàn)的幾起案子厢拭,更是在濱河造成了極大的恐慌,老刑警劉巖撇叁,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件供鸠,死亡現(xiàn)場離奇詭異,居然都是意外死亡陨闹,警方通過查閱死者的電腦和手機(jī)楞捂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進(jìn)店門薄坏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人寨闹,你說我怎么就攤上這事胶坠。” “怎么了繁堡?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵沈善,是天一觀的道長。 經(jīng)常有香客問我椭蹄,道長闻牡,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任绳矩,我火速辦了婚禮罩润,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘埋酬。我一直安慰自己哨啃,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布写妥。 她就那樣靜靜地躺著,像睡著了一般审姓。 火紅的嫁衣襯著肌膚如雪珍特。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天魔吐,我揣著相機(jī)與錄音扎筒,去河邊找鬼。 笑死酬姆,一個(gè)胖子當(dāng)著我的面吹牛嗜桌,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播辞色,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼骨宠,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了相满?” 一聲冷哼從身側(cè)響起层亿,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎立美,沒想到半個(gè)月后匿又,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡建蹄,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年碌更,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了裕偿。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,716評論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡痛单,死狀恐怖击费,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情桦他,我是刑警寧澤蔫巩,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站快压,受9級特大地震影響圆仔,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蔫劣,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一坪郭、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧脉幢,春花似錦歪沃、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至萎羔,卻和暖如春液走,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背贾陷。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工缘眶, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人髓废。 一個(gè)月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓巷懈,卻偏偏與公主長得像,于是被迫代替她去往敵國和親慌洪。 傳聞我的和親對象是個(gè)殘疾皇子顶燕,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,612評論 2 350

推薦閱讀更多精彩內(nèi)容