C#开发微信门户及应用(31)--微信语义理解接口的实现和处理
微信语义理解接口提供从用户自然语言输入到结构化解析的技术实现,使用先进的自然语言处理技术给开发者提供一站式的语义解析方案。该平台覆盖多个垂直领域的语义场景,部分领域还可以支持取得最终的展示结果。开发者无需掌握语义理解及相关技术,只需根据自己的产品特点,选择相应的服务即可搭建一套智能语义服务。结合语音识别接口,通过微信语音识别得到用户的语音信息之后,经过语义分析理解,得到用户需求,及时回复用户。本文介绍如何实现对微信语义接口的封装处理,以及一些常用场景的调用。
1)微信语义理解接口
这个东西也就是把我们日常的话语(称之为自然语言)解析为对应的信息结构体,方便我们提取里面的相关信息进行搜索查询,并精确回应给对应的请求者的一个桥梁,其主要的功能就是解析我们所说的内容。
微信开放平台语义理解接口调用(http请求)简单方便,用户无需掌握语义理解及相关技术,只需根据自己的产品特点,选择相应的服务即可搭建一套智能语义服务。我们来看看微信语义理解接口的定义内容。
http请求方式: POST(请使用https协议)
https://api.weixin.qq.com/semantic/semproxy/search?access_token=YOUR_ACCESS_TOKEN
POST数据格式:JSON,POST数据例子:
{
"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>
/// 地点相关协议
/// </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数据例子如下所示:
{
"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" : ,
"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" : ,
"query" : "查一下明天从广州到上海的南航机票",
"semantic" : {
"details" : {
"airline" : "中国南方航空公司",
"answer" : "已帮您预定2016-04-13,从广州市出发,前往上海市的航班。",
"context_info" : {
"isFinished" : "",
"null_times" : ""
},
"end_loc" : {
"city" : "上海市",
"city_simple" : "上海|沪|申",
"loc_ori" : "上海",
"modify_times" : "",
"slot_content_type" : "",
"type" : "LOC_CITY"
},
"hit_str" : "查 一下 明天 从 广州 到 上海 南航 机票 ",
"sort" : "",
"start_date" : {
"date" : "2016-04-13",
"date_lunar" : "2016-03-07",
"date_ori" : "明天",
"modify_times" : "",
"slot_content_type" : "",
"type" : "DT_ORI",
"week" : ""
},
"start_loc" : {
"city" : "广州市",
"city_simple" : "广州",
"loc_ori" : "广州",
"modify_times" : "",
"province" : "广东省",
"province_simple" : "广东|粤",
"slot_content_type" : "",
"type" : "LOC_CITY"
}
},
"intent" : "SEARCH"
},
"type" : "flight"
}
这样就是我们把我们常规的语义,分析成了机器可以识别的准确的数据结构了,我们可以根据不同的语义场合对它进行分析,然后给用户进行不同的响应就可以了,结合微信语音识别为文本内容,我们可以把它做得很强大,有的类似机器智能的味道了。
微信语义理解是一个好东西,不过在微信官网上没有看到进一步的案例,如果能够有一些与实际结合的例子,估计更能帮助我们理解和应用了。
C#开发微信门户及应用(31)--微信语义理解接口的实现和处理的更多相关文章
- C#开发微信门户及应用(38)--微信摇一摇红包功能
摇一摇周边红包接口是为线下商户提供的发红包功能.用户可以在商家门店等线下场所通过摇一摇周边领取商家发放的红包.我曾经在<C#开发微信门户及应用(28)--微信“摇一摇·周边”功能的使用和接口的实 ...
- C#开发微信门户及应用(37)--微信公众号标签管理功能
微信公众号,仿照企业号的思路,增加了标签管理的功能,对关注的粉丝可以设置标签管理,实现更加方便的分组管理功能.开发者可以使用用户标签管理的相关接口,实现对公众号的标签进行创建.查询.修改.删除等操作, ...
- C#开发微信门户及应用(36)--微信卡劵管理的封装操作
前面几篇介绍了微信支付方面的内容,本篇继续微信接口的一些其他方面的内容:卡劵管理.卡劵管理是微信接口里面非常复杂的一个部分,里面的接口非常多,我花了不少时间对它进行了封装处理,重构优化等等工作,卡劵在 ...
- C#开发微信门户及应用(35)--微信支付之企业付款封装操作
在前面几篇随笔,都是介绍微信支付及红包相关的内容,其实支付部分的内容还有很多,例如企业付款.公众号支付或刷卡支付.摇一摇红包.代金券等方面的内容,这些都是微信接口支持的内容,本篇继续微信支付这一主题, ...
- C#开发微信门户及应用(34)--微信裂变红包
在上篇随笔<C#开发微信门户及应用(33)--微信现金红包的封装及使用>介绍了普通现金红包的封装和使用,这种红包只能单独一次发给一个人,用户获取了红包就完成了,如果我们让用户收到红包后,可 ...
- C#开发微信门户及应用(33)--微信现金红包的封装及使用
我在上篇随笔<C#开发微信门户及应用(32)--微信支付接入和API封装使用>介绍为微信支付的API封装及使用,其中介绍了如何配置好支付环境,并对扫码支付的两种方式如何在C#开发中使用进行 ...
- C#开发微信门户及应用(32)--微信支付接入和API封装使用
在微信的应用上,微信支付是一个比较有用的部分,但也是比较复杂的技术要点,在微商大行其道的年代,自己的商店没有增加微信支付好像也说不过去,微信支付旨在为广大微信用户及商户提供更优质的支付服务,微信的支付 ...
- C#开发微信门户及应用(25)-微信企业号的客户端管理功能
我们知道,微信公众号和企业号都提供了一个官方的Web后台,方便我们对微信账号的配置,以及相关数据的管理功能,对于微信企业号来说,有通讯录中的组织架构管理.标签管理.人员管理.以及消息的发送等功能,其中 ...
- C#开发微信门户及应用(24)-微信小店货架信息管理
在前面微信小店系列篇<C#开发微信门户及应用(22)-微信小店的开发和使用>里面介绍了一些微信小店的基础知识,以及<C#开发微信门户及应用(23)-微信小店商品管理接口的封装和测试& ...
随机推荐
- Django
一.Django 简介 Django 是一个由 Python 写成的开放源代码的 Web 应用框架.它最初是被开发来用于管理劳伦斯出版集团旗下的一些以新闻内容为主的网站的,即是 CMS(内容管理系统) ...
- MySQL 系列(二) 你不知道的数据库操作
第一篇:MySQL 系列(一) 生产标准线上环境安装配置案例及棘手问题解决 第二篇:MySQL 系列(二) 你不知道的数据库操作 本章内容: 查看\创建\使用\删除 数据库 用户管理及授权实战 局域网 ...
- 使用RequireJS并实现一个自己的模块加载器 (一)
RequireJS & SeaJS 在 模块化开发 开发以前,都是直接在页面上引入 script 标签来引用脚本的,当项目变得比较复杂,就会带来很多问题. JS项目中的依赖只有通过引入JS的顺 ...
- 解决“chrome提示adobe flash player 已经过期”的小问题
这个小问题也确实困扰我许久,后来看到chrome吧里面有人给出了解决方案: 安装install_flash_player_ppapi, 该软件下载地址:http://labs.adobe.com/do ...
- SQL面试笔试经典题(Part 1)
本文是在Cat Qi的原贴的基础之上,经本人逐题分别在MySql数据库中实现的笔记,持续更新... 参考原贴:http://www.cnblogs.com/qixuejia/p/3637735.htm ...
- linux常用命令(2)pwd命令
pwd 命令1 命令格式:pwd [选项]2 命令功能查看当前工作目录的完整路径3 常用参数一般不带任何参数如果目录是链接时:pwd -P 显示实际路径,而非使用链接路径4 常用实例:4.1 用pwd ...
- 我的MYSQL学习心得(七) 查询
我的MYSQL学习心得(七) 查询 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据类 ...
- 初探领域驱动设计(2)Repository在DDD中的应用
概述 上一篇我们算是粗略的介绍了一下DDD,我们提到了实体.值类型和领域服务,也稍微讲到了DDD中的分层结构.但这只能算是一个很简单的介绍,并且我们在上篇的末尾还留下了一些问题,其中大家讨论比较多的, ...
- Flexbox 自由的布局
css3提出了一种新的布局方式.她并没有以摧枯拉朽之势博得我的喜爱.我和她的故事总是伴随着苦涩的味道.世道变了,总要做出些选择才能跟紧步伐.她很强大,能满足你天马行空的需求而不必抓掉一大把头发.她却很 ...
- 2000条你应知的WPF小姿势 基础篇<40-44 启动关闭,Xaml,逻辑树>
在正文开始之前需要介绍一个人:Sean Sexton. 来自明尼苏达双城的软件工程师.最为出色的是他维护了两个博客:2,000Things You Should Know About C# 和 2,0 ...