C#开发微信门户及应用(31)--微信语义理解接口的实现和处理

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介:

微信语义理解接口提供从用户自然语言输入到结构化解析的技术实现,使用先进的自然语言处理技术给开发者提供一站式的语义解析方案。该平台覆盖多个垂直领域的语义场景,部分领域还可以支持取得最终的展示结果。开发者无需掌握语义理解及相关技术,只需根据自己的产品特点,选择相应的服务即可搭建一套智能语义服务。结合语音识别接口,通过微信语音识别得到用户的语音信息之后,经过语义分析理解,得到用户需求,及时回复用户。本文介绍如何实现对微信语义接口的封装处理,以及一些常用场景的调用。

1)微信语义理解接口

这个东西也就是把我们日常的话语(称之为自然语言)解析为对应的信息结构体,方便我们提取里面的相关信息进行搜索查询,并精确回应给对应的请求者的一个桥梁,其主要的功能就是解析我们所说的内容。

微信开放平台语义理解接口调用(http请求)简单方便,用户无需掌握语义理解及相关技术,只需根据自己的产品特点,选择相应的服务即可搭建一套智能语义服务。我们来看看微信语义理解接口的定义内容。

http请求方式: POST(请使用https协议)

https://api.weixin.qq.com/semantic/semproxy/search?access_token=YOUR_ACCESS_TOKEN

POST数据格式:JSON,POST数据例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
{
 
"query" : "查一下明天从北京到上海的南航机票" ,
 
"city" : "北京" ,
 
"category" "flight,hotel" ,
 
"appid" : "wxaaaaaaaaaaaaaaaa" ,
 
"uid" : "123456"
 
}

参数说明

参数 是否必须 参数类型 说明
access_token String 根据appid和appsecret获取到的token
query String 输入文本串
category String 需要使用的服务类型,多个用“,”隔开,不能为空
latitude 见接口协议文档 Float 纬度坐标,与经度同时传入;与城市二选一传入
longitude 见接口协议文档 Float 经度坐标,与纬度同时传入;与城市二选一传入
city 见接口协议文档 String 城市名称,与经纬度二选一传入
region 见接口协议文档 String 区域名称,在城市存在的情况下可省;与经纬度二选一传入
appid String 公众号唯一标识,用于区分公众号开发者
uid String 用户唯一id(非开发者id),用户区分公众号下的不同用户(建议填入用户openid),如果为空,则无法使用上下文理解功能。appid和uid同时存在的情况下,才可以使用上下文理解功能。

注:单类别意图比较明确,识别的覆盖率比较大,所以如果只要使用特定某个类别,建议将category只设置为该类别。

返回说明 正常情况下,微信会返回下述JSON数据包:

{ 

“errcode”:0, 

“query”:”查一下明天从北京到上海的南航机票”, 

“type”:”flight”, 

“semantic”:{ 

    “details”:{

        “start_loc”:{ 

            “type”:”LOC_CITY”, 

            “city”:”北京市”, 

            “city_simple”:”北京”, 

            “loc_ori”:”北京” 

            }, 

        “end_loc”: { 

            “type”:”LOC_CITY”, 

            “city”:”上海市”, 

            “city_simple”:”上海”, 

            “loc_ori”:”上海” 

          }, 

        “start_date”: { 

            “type”:”DT_ORI”, 

            “date”:”2014-03-05”, 

            “date_ori”:”明天” 

          }, 

       “airline”:”中国南方航空公司” 

    }, 

“intent”:”SEARCH” 

}

返回参数说明

参数 是否必须 参数类型 说明
errcode Int 表示请求后的状态
query String 用户的输入字符串
type String 服务的全局类型id,详见协议文档中垂直服务协议定义
semantic Object 语义理解后的结构化标识,各服务不同
result Array 部分类别的结果
answer String 部分类别的结果html5展示,目前不支持
text String 特殊回复说明

上面就是微信官方给出的代码案例,以及一个《语义理解接口协议文档》,里面介绍了各个场景的语义结构信息,虽然这个文档好像好久都没怎么更新,不过总体内容还是稳定的,我们可以通过这个文档进行相关的类库设计工作。

2、语义理解接口的C#实现

根据《语义理解接口协议文档》文档,我们可以定义各种所需的语义结构类库,这些是我们开展语义接口的基础类。

例如我们定义基础的时间协议类,如下所示。

    /// <summary>
    /// 时间相关协议datetime
    /// </summary>
    public class Semantic_DateTime
    {
        /// <summary>
        /// 单时间的描述协议类型:“DT_SINGLE”。DT_SINGLE又细分为两个类别:DT_ORI和DT_INFER。DT_ORI是字面时间,比如:“上午九点”;
        /// DT_INFER是推理时间,比如:“提前5分钟”。 时间段的描述协议类型:“DT_INTERVAL”
        /// 重复时间的描述协议类型:“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>
    /// 单时间的描述协议datetime
    /// </summary>
    public class Semantic_SingleDateTime : Semantic_DateTime
    {
        /// <summary>
        /// 格式:YYYY-MM-DD,默认是当天时间
        /// </summary>
        public string date { get; set; }

        /// <summary>
        /// 格式:YYYY-MM-DD 农历
        /// </summary>
        public string date_lunar { get; set; }

        /// <summary>
        /// date的原始字符串
        /// </summary>
        public string date_ori { get; set; }
    }

当然时间还有很多类型的定义,都基本上按照文档所列的字段进行处理,上面的代码只是定义了常用的单时间的描述协议类型:“DT_SINGLE”。

除了时间协议,还有数字,地点位置等相关协议,如数字协议如下所示。

    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; }
    }

地点位置协议如下所示

    /// 地点相关协议
    /// </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数据格式是一个较为固定的格式内容,我们可以把它定义为一个类,方便数据处理。

POST数据格式:JSON,POST数据例子如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
{
 
"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>
        /// 城市名称,与经纬度二选一传入
        /// 见说明,选填
        /// </summary>
        [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
        public string city { get; set; }

        /// <summary>
        /// App id,开发者的唯一标识,用于区分开放者,如果为空,则没法使用上下文理解功能。
        /// 非必填
        /// </summary>
        public string appid { get; set; }

        /// <summary>
        /// 用户唯一id(并非开发者id),用于区分该开发者下不同用户,如果为空,则没法使用上下文理解功能。appid和uid同时存在的情况下,才可以使用上下文理解功能。
        /// 非必填
        /// </summary>
        public string uid { get; set; }

        ................
    }

接着我们分析语义理解的接口返回值,它们基本上都是很有规律的内容,如下所示。

这样我们也就可以定义一个通用的类库对象,用来存储不同的返回内容了,如下代码所示。

    /// <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就是另外一个结构体里面的内容,这个结构体总体也是固定的内容,我们继续定义一个如下的类。

    /// <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>
    /// 语意理解接口
    /// 微信开放平台语义理解接口调用(http请求)简单方便,用户无需掌握语义理解及相关技术,只需根据自己的产品特点,选择相应的服务即可搭建一套智能语义服务。
    /// </summary>
    public class SemanticApi : ISemanticApi
    {
        /// <summary>
        /// 发送语义理解请求
        /// </summary>
        /// <param name="accessToken">调用接口凭证</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);
        }

由于微信语义结果是针对不同的服务协议,我们需要根据这些不同的服务协议,来定义属于这些信息结构,如在文档里,我们可以看到有很多不同类型的服务协议。

根据文档的详细字段说明,我们可以定义不同服务的对应类库。

例如对于旅游服务的语义理解,它们的协议类如下所示。

    /// <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; }
    }

那么调用的旅游语义的案例代码如下所示

            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());

如果我们测试,上面的代码跑起来会返回一个旅游的协议对象,包括了相关的数据信息。

{
   "errcode" : 0,
   "query" : "故宫门票多少钱",
   "semantic" : {
      "details" : {
         "answer" : "",
         "context_info" : {},
         "hit_str" : "故宫 门票 多少 钱 ",
         "spot" : "故宫"
      },
      "intent" : "PRICE"
   },
   "type" : "travel"
}

我们再来看一个例子,例如对于航班服务,我们定义它的语义理解协议如下所示。

    /// <summary>
    /// 航班服务(flight)
    /// </summary>
    public class Semantic_Details_Flight
    {
        /// <summary>
        /// 航班号
        /// </summary>
        public string flight_no { get; set; }
        /// <summary>
        /// 出发地
        /// </summary>
        public Semantic_Location start_loc { get; set; }
        /// <summary>
        /// 目的地
        /// </summary>
        public Semantic_Location end_loc { get; set; }
        /// <summary>
        /// 出发日期
        /// </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(经济舱)BIZ(商务舱)FIRST(头等舱)
        /// </summary>
        public string seat { get; set; }
        /// <summary>
        /// 排序类型:0排序无要求(默认),1价格升序,2价格降序,3时间升序,4时间降序
        /// </summary>
        public int sort { get; set; }
    }

那么调用获取语义理解内容的代码如下所示。

            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数据如下所示

{
   "errcode" : 0,
   "query" : "查一下明天从广州到上海的南航机票",
   "semantic" : {
      "details" : {
         "airline" : "中国南方航空公司",
         "answer" : "已帮您预定2016-04-13,从广州市出发,前往上海市的航班。",
         "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"
}

这样就是我们把我们常规的语义,分析成了机器可以识别的准确的数据结构了,我们可以根据不同的语义场合对它进行分析,然后给用户进行不同的响应就可以了,结合微信语音识别为文本内容,我们可以把它做得很强大,有的类似机器智能的味道了。

微信语义理解是一个好东西,不过在微信官网上没有看到进一步的案例,如果能够有一些与实际结合的例子,估计更能帮助我们理解和应用了。

本文转自博客园伍华聪的博客,原文链接:C#开发微信门户及应用(31)--微信语义理解接口的实现和处理,如需转载请自行联系原博主。



目录
相关文章
|
9天前
|
人工智能 JavaScript 定位技术
微信的接口都有哪些?
【10月更文挑战第17天】微信的接口都有哪些?
86 43
|
14天前
|
JSON 小程序 JavaScript
uni-app开发微信小程序的报错[渲染层错误]排查及解决
uni-app开发微信小程序的报错[渲染层错误]排查及解决
208 7
|
14天前
|
小程序 JavaScript 前端开发
uni-app开发微信小程序:四大解决方案,轻松应对主包与vendor.js过大打包难题
uni-app开发微信小程序:四大解决方案,轻松应对主包与vendor.js过大打包难题
279 1
|
4天前
|
C# Python
使用wxpython开发跨平台桌面应用,对wxpython控件实现类似C#扩展函数处理的探究
【10月更文挑战第30天】使用 `wxPython` 开发跨平台桌面应用时,可以通过创建辅助类来模拟 C# 扩展函数的功能。具体步骤包括:1. 创建辅助类 `WxWidgetHelpers`;2. 在该类中定义静态方法,如 `set_button_color`;3. 在应用中调用这些方法。这种方法提高了代码的可读性和可维护性,无需修改 `wxPython` 库即可为控件添加自定义功能。但需要注意显式调用方法和避免命名冲突。
|
11天前
|
JSON C# 开发者
C#语言新特性深度剖析:提升你的.NET开发效率
【10月更文挑战第15天】C#语言凭借其强大的功能和易用性深受开发者喜爱。随着.NET平台的演进,C#不断引入新特性,如C# 7.0的模式匹配和C# 8.0的异步流,显著提升了开发效率和代码可维护性。本文将深入探讨这些新特性,助力开发者在.NET开发中更高效地利用它们。
23 1
|
14天前
|
JSON 前端开发 API
使用微信JS-SDK调用发票接口的完整开发指南
本文介绍了如何使用微信JS-SDK的`chooseInvoiceTitle`接口来调用微信的发票功能。通过微信发票接口,用户可以选择开具个人或单位发票,并获取相关发票信息,如抬头、税号、公司地址等。在文中,详细描述了JS-SDK的初始化、发票接口的调用方式,并提供了完整的代码示例。文章还介绍了如何处理返回的发票信息,帮助开发者快速集成微信发票功能。
59 2
|
9天前
|
存储 小程序 安全
微信的开发管理都需要配置什么?
【10月更文挑战第17天】微信的开发管理都需要配置什么?
21 0
|
14天前
|
JavaScript 小程序 开发者
uni-app开发实战:利用Vue混入(mixin)实现微信小程序全局分享功能,一键发送给朋友、分享到朋友圈、复制链接
uni-app开发实战:利用Vue混入(mixin)实现微信小程序全局分享功能,一键发送给朋友、分享到朋友圈、复制链接
155 0
|
6月前
|
开发框架 前端开发 .NET
C#编程与Web开发
【4月更文挑战第21天】本文探讨了C#在Web开发中的应用,包括使用ASP.NET框架、MVC模式、Web API和Entity Framework。C#作为.NET框架的主要语言,结合这些工具,能创建动态、高效的Web应用。实际案例涉及企业级应用、电子商务和社交媒体平台。尽管面临竞争和挑战,但C#在Web开发领域的前景将持续拓展。
183 3
|
18天前
|
安全 C# 数据安全/隐私保护
实现C#编程文件夹加锁保护
【10月更文挑战第16天】本文介绍了两种用 C# 实现文件夹保护的方法:一是通过设置文件系统权限,阻止普通用户访问;二是使用加密技术,对文件夹中的文件进行加密,防止未授权访问。提供了示例代码和使用方法,适用于不同安全需求的场景。