├── .gitignore
├── LICENSE
├── README.md
└── yzz_weixinapp
├── app.js
├── app.json
├── app.wxss
├── config.js
├── pages
├── asr
│ ├── asr.js
│ ├── asr.json
│ ├── asr.wxml
│ └── asr.wxss
├── index
│ ├── index.js
│ ├── index.json
│ ├── index.wxml
│ └── index.wxss
├── logs
│ ├── logs.js
│ ├── logs.json
│ ├── logs.wxml
│ └── logs.wxss
└── test
│ ├── test.js
│ ├── test.json
│ ├── test.wxml
│ └── test.wxss
├── pics
├── bg.jpg
├── voice_icon_speech_sound_1.png
├── voice_icon_speech_sound_2.png
├── voice_icon_speech_sound_3.png
├── voice_icon_speech_sound_4.png
└── voice_icon_speech_sound_5.png
└── utils
├── GUID.js
├── MD5.js
├── NLI.js
└── util.js
/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled class file
2 | *.class
3 |
4 | # Log file
5 | *.log
6 |
7 | # BlueJ files
8 | *.ctxt
9 |
10 | # Mobile Tools for Java (J2ME)
11 | .mtj.tmp/
12 |
13 | # Package Files #
14 | *.jar
15 | *.war
16 | *.ear
17 | *.zip
18 | *.tar.gz
19 | *.rar
20 |
21 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
22 | hs_err_pid*
23 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 happycxz
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # nlp_olami_yaozhizhi_wechat_littleapp_demo
2 | wechat little app, base on olami NLI inteface, named it as '遥知之' (yaozhizhi).
3 |
4 |
5 | ## 微信小程序智能生活小秘书开发详解
6 |
7 |
8 | **>>>>>>>>>>>>>>>>>>>>>>>> 欢迎转载 <<<<<<<<<<<<<<<<<<<<<<<<**
9 |
10 | **本文原地址:[http://blog.csdn.net/happycxz/article/details/75432928](http://blog.csdn.net/happycxz/article/details/75432928)**
11 |
12 | ### 扫码试用(左右皆可)
13 |
14 |  
15 |
16 |
17 | **“遥知之”微信小程序完整源码下载:**
18 |
19 | 码云:[http://git.oschina.net/happycxz/nlp_olami_yaozhizhi_wechat_littleapp_demo](http://git.oschina.net/happycxz/nlp_olami_yaozhizhi_wechat_littleapp_demo)
20 |
21 | github: [https://github.com/happycxz/nlp_olami_yaozhizhi_wechat_littleapp_demo](https://github.com/happycxz/nlp_olami_yaozhizhi_wechat_littleapp_demo)
22 |
23 | ### 实现功能
24 |
25 | 实现一个智能生活信息查询的小秘书功能,支持查天气、新闻、日历、汇率、笑话、故事、百科、诗词、邮编、区号、菜谱、股票、节目预告,还支持闲聊、算24点、数学计算、单位换算、购物、搜索等功能。
26 |
27 | 使用方式:
28 |
29 | **新版上线支持语音识别,按下说话,松开发送。**
30 |
31 | 老版本上支持摇一摇、点界面按钮、手动输入、下拉刷新这四种方式。
32 |
33 | ### 界面展示
34 |
35 | 
36 |
37 |
38 | ### 开发资源
39 | 1. 免费开放语义接口平台 olami.ai
40 | 2. 微信小程序平台
41 | 3. js, css
42 |
43 | 更多代码描述及项目详情,请见原文链接:
44 |
45 | [我的微信小程序支持语音识别啦!“遥知之”不再装聋](http://blog.csdn.net/happycxz/article/details/78024986)
46 |
47 | [微信小程序——智能小秘“遥知之”源码分享(语义理解基于olami)](http://blog.csdn.net/happycxz/article/details/75432928)
48 |
49 |
50 |
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/yzz_weixinapp/app.js:
--------------------------------------------------------------------------------
1 | //app.js
2 |
3 | const corpusList = require('./config').corpus
4 | var UTIL = require('./utils/util.js');
5 |
6 | App({
7 | onShow: function () {
8 | UTIL.log('App Show')
9 | },
10 | onHide: function () {
11 | UTIL.log('App Hide')
12 | },
13 | onLaunch: function () {
14 | UTIL.log('App Launch')
15 | this.updateUserLocation()
16 | },
17 |
18 | updateUserLocation: function() {
19 | var that = this
20 | wx.getLocation({
21 | //type: 'wgs84', // gps原始坐标
22 | type: 'gcj02', //国家标准加密坐标
23 | success: function (res) {
24 | that.globalData.latitude = res.latitude
25 | that.globalData.longitude = res.longitude
26 | that.globalData.speed = res.speed
27 | //var accuracy = res.accuracy
28 | UTIL.log('REFRESH LOCATION: ' + that.globalData.latitude + ' | ' + that.globalData.longitude + ' , speed: ' + that.globalData.speed)
29 | },
30 | fail: function(res) {
31 | UTIL.log('REFRESH LOCATION FAILED...')
32 | }
33 | })
34 | },
35 |
36 | getUserInfo:function(cb){
37 | var that = this
38 | if(this.globalData.userInfo){
39 | typeof cb == "function" && cb(this.globalData.userInfo)
40 | }else{
41 | //调用登录接口
42 | wx.login({
43 | success: function () {
44 | wx.getUserInfo({
45 | success: function (res) {
46 | that.globalData.userInfo = res.userInfo
47 | that.globalData.custId = UTIL.getUserUnique(that.globalData.userInfo);
48 | typeof cb == "function" && cb(that.globalData.userInfo)
49 | }
50 | })
51 | },
52 | fail: function () {
53 | UTIL.log('登录WX失败了!')
54 | }
55 | })
56 | }
57 | },
58 |
59 | clearUserInfo: function() {
60 | var that = this
61 | that.globalData.userInfo = null;
62 | that.globalData.hasLogin = false;
63 | },
64 |
65 | globalData:{
66 | userInfo:null,
67 | corpus: corpusList,
68 | custId: '',
69 | latitude: 0.0,
70 | longitude: 0.0,
71 | speed: 0,
72 | }
73 | })
74 |
--------------------------------------------------------------------------------
/yzz_weixinapp/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "pages": [
3 | "pages/asr/asr",
4 | "pages/test/test",
5 | "pages/index/index",
6 | "pages/logs/logs"
7 | ],
8 | "window": {
9 | "backgroundTextStyle": "black",
10 | "navigationBarBackgroundColor": "#F8F8F8",
11 | "navigationBarTitleText": "遥知之 -- 人工智能小秘书",
12 | "navigationBarTextStyle": "black",
13 | "backgroundColor": "#F8F8F8",
14 | "enablePullDownRefresh": false
15 | },
16 | "networkTimeout": {
17 | "request": 10000,
18 | "connectSocket": 10000,
19 | "uploadFile": 10000,
20 | "downloadFile": 10000
21 | }
22 | }
--------------------------------------------------------------------------------
/yzz_weixinapp/app.wxss:
--------------------------------------------------------------------------------
1 | /**app.wxss**/
2 | .container {
3 | height: 100%;
4 | display: flex;
5 | flex-direction: column;
6 | align-items: center;
7 | justify-content: center;
8 | box-sizing: border-box;
9 | }
10 |
--------------------------------------------------------------------------------
/yzz_weixinapp/config.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 小程序配置文件
3 | */
4 |
5 | module.exports = {
6 |
7 | //NLI appkey
8 | appkey: `b4118cd178064b45b7c8f1242bcde31f`,
9 |
10 | //NLI appsecret
11 | appsecret: `7908028332a64e47b8336d71ad3ce9ab`,
12 |
13 | corpus: [
14 | // '闲聊',
15 | // '天气',
16 | // '诗词',
17 | // '单位换算',
18 | // '新闻',
19 | // '算24点',
20 | // '菜谱',
21 | // '汇率',
22 | // '邮编',
23 | // '区号',
24 | // '股票',
25 | // '日历',
26 | // '节目预告',
27 | // '笑话',
28 | // '故事',
29 | // '购物',
30 | // '数学运算',
31 | // '百科',
32 | // '搜索',
33 |
34 | '你今年多大啦',
35 | '上海今天天气如何',
36 | '北京的呢',
37 | '李白写过什么诗',
38 | '我要听李白的静夜思',
39 | '背一首将进酒',
40 | '一公里等于多少英尺',
41 | '我要看体育新闻',
42 | '4567算24点',
43 | '红烧肉的做法',
44 | '1美元能换算多少人民币',
45 | '查一下南昌的邮编',
46 | '郑州的区号是多少',
47 | '中国石油的股价',
48 | '今年中秋节是哪一天',
49 | '明晚湖南卫视放什么节目',
50 | '来个笑话',
51 | '讲个故事听听',
52 | '我要买电脑',
53 | '1加到100等于多少',
54 | '黄山有多高',
55 | '百度搜一下薛之谦的照片',
56 | ]
57 | };
58 |
--------------------------------------------------------------------------------
/yzz_weixinapp/pages/asr/asr.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 作者:happycxz
3 | * 最后更新时间:2017.11.09
4 | * 源码分享链接:http://www.happycxz.com/m/?p=125
5 | *
6 | * https的silk语音识别API(专供微信小程序调用):https://api.happycxz.com/wxapp/silk2asr
7 | * https的mp3语音识别API(专供微信小程序调用):https://api.happycxz.com/wxapp/mp32asr
8 | * 该API服务搭建全过程解析及源码分享贴:http://blog.csdn.net/happycxz/article/details/78016299
9 | * 需要使用此API请联系作者QQ:404499164
10 | *
11 | * 遵循开放、分享、自由、免费的精神,把开源坚持到底
12 | */
13 |
14 | //获取应用实例
15 | var app = getApp()
16 |
17 | var UTIL = require('../../utils/util.js');
18 | var GUID = require('../../utils/GUID.js');
19 | var NLI = require('../../utils/NLI.js');
20 |
21 | const appkey = require('../../config').appkey
22 | const appsecret = require('../../config').appsecret
23 |
24 | //微信小程序新录音接口,录出来的是aac或者mp3,这里要录成mp3
25 | const mp3Recorder = wx.getRecorderManager()
26 | const mp3RecoderOptions = {
27 | duration: 60000,
28 | sampleRate: 16000,
29 | numberOfChannels: 1,
30 | encodeBitRate: 48000,
31 | format: 'mp3',
32 | //frameSize: 50
33 | }
34 |
35 | //弹幕定时器
36 | var timer;
37 |
38 | var pageSelf = undefined;
39 |
40 | var doommList = [];
41 | class Doomm {
42 | constructor() {
43 | this.text = UTIL.getRandomItem(app.globalData.corpus);
44 | this.top = Math.ceil(Math.random() * 40);
45 | this.time = Math.ceil(Math.random() * 8 + 6);
46 | this.color = getRandomColor();
47 | this.display = true;
48 | let that = this;
49 | setTimeout(function () {
50 | doommList.splice(doommList.indexOf(that), 1);
51 | doommList.push(new Doomm());
52 |
53 | pageSelf.setData({
54 | doommData: doommList
55 | })
56 | }, this.time * 1000)
57 | }
58 | }
59 | function getRandomColor() {
60 | let rgb = []
61 | for (let i = 0; i < 3; ++i) {
62 | let color = Math.floor(Math.random() * 256).toString(16)
63 | color = color.length == 1 ? '0' + color : color
64 | rgb.push(color)
65 | }
66 | return '#' + rgb.join('')
67 | }
68 |
69 | Page({
70 | data: {
71 | j: 1,//帧动画初始图片
72 | isSpeaking: false,//是否正在说话
73 | outputTxt : "", //输出识别结果
74 |
75 | doommData: []
76 | },
77 |
78 | initDoomm: function () {
79 | doommList.push(new Doomm());
80 | doommList.push(new Doomm());
81 | doommList.push(new Doomm());
82 | this.setData({
83 | doommData: doommList
84 | })
85 | },
86 |
87 | onLoad: function () {
88 | pageSelf = this;
89 | this.initDoomm();
90 |
91 | //onLoad中为录音接口注册两个回调函数,主要是onStop,拿到录音mp3文件的文件名(不用在意文件后辍是.dat还是.mp3,后辍不决定音频格式)
92 | mp3Recorder.onStart(() => {
93 | UTIL.log('mp3Recorder.onStart()...')
94 | })
95 | mp3Recorder.onStop((res) => {
96 | UTIL.log('mp3Recorder.onStop() ' + res)
97 | const { tempFilePath } = res
98 | var urls = "https://api.happycxz.com/wxapp/mp32asr";
99 | UTIL.log('mp3Recorder.onStop() tempFilePath:' + tempFilePath)
100 | processFileUploadForAsr(urls, tempFilePath, this);
101 | })
102 | },
103 |
104 | /////////////////////////////////////////////////////////////// 以下是调用新接口实现的录音,录出来的是 mp3
105 | touchdown: function () {
106 | //touchdown_mp3: function () {
107 | UTIL.log("mp3Recorder.start with" + mp3RecoderOptions)
108 | var _this = this;
109 | speaking.call(this);
110 | this.setData({
111 | isSpeaking: true
112 | })
113 | mp3Recorder.start(mp3RecoderOptions);
114 | },
115 | touchup: function () {
116 | //touchup_mp3: function () {
117 | UTIL.log("mp3Recorder.stop")
118 | this.setData({
119 | isSpeaking: false,
120 | })
121 | mp3Recorder.stop();
122 | },
123 |
124 |
125 | //切换到老版本
126 | turnToOld: function () {
127 | wx.navigateTo({
128 | url: '../index/index',
129 | })
130 | },
131 |
132 | /////////////////////////////////////////////////////////////// 以下是调用老接口实现的录音,录出来的是 silk_v3
133 | //手指按下
134 | touchdown_silk: function () {
135 | //touchdown: function () {
136 | UTIL.log("手指按下了... new date : " + new Date)
137 | var _this = this;
138 | speaking.call(this);
139 | this.setData({
140 | isSpeaking: true
141 | })
142 | //开始录音
143 | wx.startRecord({
144 | success: function (res) {
145 | //临时路径,下次进入小程序时无法正常使用
146 | var tempFilePath = res.tempFilePath;
147 | UTIL.log('record SUCCESS file path:' + tempFilePath)
148 | _this.setData({
149 | recordPath: tempFilePath
150 | });
151 | },
152 | fail: function (res) {
153 | //录音失败
154 | wx.showModal({
155 | title: '提示',
156 | content: '录音的姿势不对!',
157 | showCancel: false,
158 | success: function (res) {
159 | if (res.confirm) {
160 | UTIL.log('用户点击确定')
161 | return
162 | }
163 | }
164 | })
165 | }
166 | })
167 | },
168 | //手指抬起
169 | touchup_silk: function () {
170 | //touchup: function () {
171 | UTIL.log("手指抬起了...")
172 | this.setData({
173 | isSpeaking: false,
174 | })
175 | clearInterval(this.timer)
176 | wx.stopRecord()
177 |
178 | var _this = this
179 | setTimeout(function () {
180 | var urls = "https://api.happycxz.com/wxapp/silk2asr/";
181 | UTIL.log(_this.data.recordPath);
182 | processFileUploadForAsr(urls, _this.data.recordPath, _this);
183 | }, 1000)
184 | },
185 |
186 |
187 | })
188 |
189 | //上传录音文件到 api.happycxz.com 接口,处理语音识别和语义,结果输出到界面
190 | function processFileUploadForAsr(urls, filePath, _this) {
191 | wx.uploadFile({
192 | url: urls,
193 | filePath: filePath,
194 | name: 'file',
195 | formData: { "appKey": appkey, "appSecret": appsecret, "userId": UTIL.getUserUnique() },
196 | header: { 'content-type': 'multipart/form-data' },
197 | success: function (res) {
198 | UTIL.log('res.data:' + res.data);
199 |
200 | var nliResult = getNliFromResult(res.data);
201 | UTIL.log('nliResult:' + nliResult);
202 | var stt = getSttFromResult(res.data);
203 | UTIL.log('stt:' + stt);
204 |
205 | var sentenceResult;
206 | try {
207 | sentenceResult = NLI.getSentenceFromNliResult(nliResult);
208 | } catch (e) {
209 | UTIL.log('touchup() 错误' + e.message + '发生在' + e.lineNumber + '行');
210 | sentenceResult = '没明白你说的,换个话题?'
211 | }
212 |
213 | var lastOutput = "==>语音识别结果:\n" + stt + "\n\n==>语义处理结果:\n" + sentenceResult;
214 | _this.setData({
215 | outputTxt: lastOutput,
216 | });
217 | wx.hideToast();
218 | },
219 | fail: function (res) {
220 | UTIL.log(res);
221 | wx.showModal({
222 | title: '提示',
223 | content: "网络请求失败,请确保网络是否正常",
224 | showCancel: false,
225 | success: function (res) {
226 | }
227 | });
228 | wx.hideToast();
229 | }
230 | });
231 | }
232 |
233 | function getNliFromResult(res_data) {
234 | var res_data_json = JSON.parse(res_data);
235 | var res_data_result_json = JSON.parse(res_data_json.result);
236 | return res_data_result_json.nli;
237 | }
238 |
239 | function getSttFromResult(res_data) {
240 | var res_data_json = JSON.parse(res_data);
241 | var res_data_result_json = JSON.parse(res_data_json.result);
242 | return res_data_result_json.asr.result;
243 | }
244 |
245 | //麦克风帧动画
246 | function speaking() {
247 | var _this = this;
248 | //话筒帧动画
249 | var i = 1;
250 | this.timer = setInterval(function () {
251 | i++;
252 | i = i % 5;
253 | _this.setData({
254 | j: i
255 | })
256 | }, 200);
257 | }
258 |
--------------------------------------------------------------------------------
/yzz_weixinapp/pages/asr/asr.json:
--------------------------------------------------------------------------------
1 | {
2 | "window": {
3 | "enablePullDownRefresh": false
4 | }
5 | }
--------------------------------------------------------------------------------
/yzz_weixinapp/pages/asr/asr.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{outputTxt}}
5 |
6 |
7 |
8 |
9 | 语义理解基于olami.ai,作者QQ:404499164
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | {{item.text}}
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/yzz_weixinapp/pages/asr/asr.wxss:
--------------------------------------------------------------------------------
1 | /* pages/asr/asr.wxss */
2 |
3 | page{
4 | background-color:beige;
5 | background-image: url(http://img.blog.csdn.net/20170720105808995?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaGFwcHljeHo=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast);
6 | background-size: cover;
7 | }
8 |
9 | .page-section{
10 | display: flex;
11 | flex-direction: column;
12 | margin-bottom: 10rpx;
13 | }
14 |
15 | .text-head{
16 | color: #ff0000;
17 | font-size: 28rpx;
18 | align-items: center;
19 | margin-top: 5rpx;
20 | }
21 |
22 | .button-selection {
23 | display: flex;
24 | flex-direction: column;
25 | justify-content: center;
26 | align-items: center;
27 | }
28 |
29 | .button-selection2 {
30 | justify-content: space-between;
31 | align-content: space-between;
32 | flex-shrink:1;
33 | }
34 |
35 | .little-gap-top {
36 | margin-top: 10rpx;
37 | }
38 |
39 | .big-gap-top {
40 | margin-top: 100rpx;
41 | }
42 |
43 | .button-show {
44 | display: flex;
45 | align-self: center;
46 | justify-content: center;
47 | }
48 |
49 | .bottom-button {
50 | justify-content: space-around;
51 | flex-shrink:0;
52 | }
53 |
54 | .text-box{
55 | margin-bottom: 0rpx;
56 | margin-left: 50rpx;
57 | margin-right: 50rpx;
58 | padding: 40rpx 0;
59 | display: flex;
60 | min-height: 650rpx;
61 | max-width: 600rpx;
62 | width:600rpx;
63 | background-color: #ffffff;
64 | justify-content: center;
65 | align-items: center;
66 | text-align: left;
67 | font-size: 30rpx;
68 | color: #353535;
69 | line-height: 2em;
70 | word-wrap: break-word;
71 | border: 1px solid cornflowerblue;
72 | }
73 |
74 |
75 | /* 录音 */
76 | .speak-style{
77 | position: relative;
78 | height: 240rpx;
79 | width: 240rpx;
80 | border-radius: 20rpx;
81 | margin: 0 auto;
82 | background: #26A5FF;
83 | }
84 | .record-style{
85 | position: fixed;
86 | bottom: 0;
87 | left: 0;
88 | height: 120rpx;
89 | width: 100%;
90 | }
91 | .btn-style{
92 | margin-left: 30rpx;
93 | margin-right: 30rpx;
94 | }
95 |
96 | .sound-style{
97 | position: absolute;
98 | width: 74rpx;
99 | height:150rpx;
100 | margin-top: 45rpx;
101 | margin-left: 83rpx;
102 | }
103 |
104 |
105 | /* 弹幕 */
106 | .button{
107 | position: absolute;
108 | bottom: 0;
109 | width: 100%;
110 | }
111 | .aon{
112 | position: absolute;
113 | white-space:nowrap;
114 | animation-timing-function: linear;
115 | animation-fill-mode: none;
116 | }
117 | .doommview{
118 | z-index: 3;
119 | height: 80%;
120 | width: 100%;
121 | /* position: absolute; */
122 | }
123 |
124 | @keyframes first{
125 | from{left: 100%; }
126 | to{left: -100%;}
127 | }
--------------------------------------------------------------------------------
/yzz_weixinapp/pages/index/index.js:
--------------------------------------------------------------------------------
1 | //获取应用实例
2 | var app = getApp()
3 |
4 | var UTIL = require('../../utils/util.js');
5 | var GUID = require('../../utils/GUID.js');
6 | var NLI = require('../../utils/NLI.js');
7 |
8 | var cursor = 0;
9 | var lastYYYTime = new Date().getTime();
10 |
11 | var domainCorpus = '';
12 | var lastCorpus = '';
13 |
14 |
15 | Page({
16 |
17 | isShow: false,
18 |
19 | /**
20 | * 页面的初始数据
21 | */
22 | data: {
23 | //调试后门
24 | isDbg: false,
25 | //输入框文本
26 | inputTxt: '',
27 | //输出框文本
28 | outputTxt: ''
29 | },
30 |
31 | /**
32 | * 生命周期函数--监听页面加载
33 | */
34 | onLoad: function (options) {
35 | UTIL.log('index.onLoad')
36 | //调用应用实例的方法获取全局数据
37 | app.getUserInfo(function (userInfo2) {
38 | UTIL.log('user unique 1: ' + UTIL.getUserUnique(userInfo2))
39 | })
40 | UTIL.log('user unique 2: ' + UTIL.getUserUnique(app.globalData.userInfo))
41 | },
42 |
43 | /**
44 | * 生命周期函数--监听页面初次渲染完成
45 | */
46 | onReady: function () {
47 | UTIL.log('index.onReady')
48 | },
49 |
50 | /**
51 | * 生命周期函数--监听页面显示
52 | */
53 | onShow: function () {
54 | UTIL.log('index.onShow')
55 |
56 | var that = this;
57 | that.isShow = true;
58 |
59 | //调用重力加速度传感API模拟摇一摇接口
60 | wx.onAccelerometerChange(function (e) {
61 |
62 | if (!that.isShow) {
63 | //当前界面不显示时不应该调用
64 | return
65 | }
66 |
67 | if (isBong(e.x) && isBong(e.y)) {
68 | if (new Date().getTime() - lastYYYTime <= 2000) {
69 | //1秒限制摇一次,避免摇一下触发多次请求
70 | UTIL.log('摇的太频繁啦,请等2秒再摇!' + e.x + ', '+ e.y + ', ' + e.z);
71 | return;
72 | }
73 |
74 | //更新最后一次成功摇的时间戳
75 | lastYYYTime = new Date().getTime()
76 |
77 | //从语料库中挑选语料运行语义理解,显示结果
78 | var selectedCorpus = selectCorpusRunNli(that);
79 |
80 | //弹Toast窗提示当前刷到哪句语料
81 | wx.showToast({
82 | title: selectedCorpus,
83 | icon: 'success',
84 | duration: 1500
85 | });
86 | }
87 | })
88 | },
89 |
90 | /**
91 | * 生命周期函数--监听页面隐藏
92 | */
93 | onHide: function () {
94 | UTIL.log('index.onHide')
95 | //页面隐藏后,关掉摇一摇检测
96 | wx.stopAccelerometer();
97 | },
98 |
99 | /**
100 | * 生命周期函数--监听页面卸载
101 | */
102 | onUnload: function () {
103 | UTIL.log('index.onUnload')
104 | },
105 |
106 | /**
107 | * 页面相关事件处理函数--监听用户下拉动作
108 | */
109 | onPullDownRefresh: function () {
110 | UTIL.log('index.onPullDownRefresh')
111 |
112 | wx.stopPullDownRefresh();
113 |
114 | //页面下拉,触发轮换语料理解
115 | selectCorpusRunNli(this)
116 | },
117 |
118 | /**
119 | * 页面上拉触底事件的处理函数
120 | */
121 | onReachBottom: function () {
122 | UTIL.log('index.onReachBottom')
123 | },
124 |
125 | /**
126 | * 用户点击右上角分享
127 | */
128 | onShareAppMessage: function () {
129 | UTIL.log('index.onShareAppMessage')
130 |
131 | wx.showToast({
132 | title: '谢谢分享!',
133 | icon: 'success',
134 | duration: 1500
135 | });
136 | },
137 |
138 | switchChange: function (e) {
139 | UTIL.log('index.switchChange by:' + e.detail.value)
140 | },
141 |
142 | //输入文本框聚焦触发清除输入框中的内容
143 | bindFocusClear: function(e) {
144 | UTIL.log('index.bindFocusClear')
145 | if (e.detail.value === '') {
146 | return;
147 | }
148 |
149 | UTIL.log('clear: ' + e.detail.value)
150 | var self = this;
151 | self.setData({
152 | inputTxt: ''
153 | });
154 | },
155 |
156 | //点击完成按钮时触发
157 | bindConfirmControl: function(e) {
158 | var inputTxt = e.detail.value;
159 | UTIL.log('index.bindConfirmControl input string: ' + inputTxt);
160 |
161 | //手动打字输入语料运行语义理解
162 | singleCorpusRunNli(inputTxt, this)
163 | },
164 |
165 | //测试按钮触发事件
166 | bindTest: function () {
167 | UTIL.log('index.bindTest')
168 |
169 | //测试按钮替代摇一摇,从语料库中选语料测试
170 | selectCorpusRunNli(this)
171 | },
172 |
173 | //快捷按钮触发语料运行语义理解
174 | bindCorpusGenerator: function (e) {
175 | UTIL.log('index.bindCorpusGenerator')
176 | //获取"data-cp"中的语料
177 | var corpusList = e.target.dataset.cp.split('|');
178 |
179 | //默认头一次(或新切换时)点击,选用第一句语料
180 | var corpus = corpusList[0];
181 | if (domainCorpus !== corpusList[0]) {
182 | domainCorpus = corpusList[0];
183 | } else {
184 | //否则在语料表中随机挑选一个
185 | corpus = UTIL.getRandomItem(corpusList);
186 |
187 | //与上一句重复就换一句
188 | if (lastCorpus === corpus) {
189 | corpus = UTIL.getRandomItem(corpusList);
190 | if (lastCorpus === corpus) {
191 | corpus = UTIL.getRandomItem(corpusList);
192 | if (lastCorpus === corpus) {
193 | corpus = UTIL.getRandomItem(corpusList);
194 | }
195 | }
196 | }
197 | }
198 |
199 | //记录最近一次使用的语料
200 | lastCorpus = corpus;
201 |
202 | singleCorpusRunNli(corpus, this);
203 | },
204 |
205 | turnToNew: function() {
206 | wx.navigateBack({
207 | })
208 | }
209 | })
210 |
211 |
212 | //处理NLI语义结果
213 | function NliProcess(corpus, self) {
214 | var nliResult;
215 | NLI.process(corpus, function (isSuccess, result) {
216 | if (isSuccess) {
217 | } else {
218 |
219 | }
220 |
221 | var sentenceResult;
222 | try {
223 | var resultJson = JSON.parse(result);
224 | nliResult = resultJson.nli;
225 | UTIL.log("NLI RESULT IS:" + nliResult);
226 | sentenceResult = NLI.getSentenceFromNliResult(nliResult);
227 | } catch (e) {
228 | UTIL.log('NliProcess() 错误' + e.message + '发生在' + e.lineNumber + '行');
229 | sentenceResult = '没明白你说的,换个话题?'
230 | }
231 |
232 | typeof self !== 'undefined' && self.setData({
233 | outputTxt: sentenceResult
234 | })
235 | })
236 | }
237 |
238 | //如输入是dbg且确认,则切换到debug模式,多显示两个按钮
239 | function singleCorpusRunNli(inputTxt, self) {
240 | if (inputTxt === 'dbg' || inputTxt === 'DBG' || inputTxt === 'Dbg') {
241 | self.setData({
242 | //打开调试按钮
243 | isDbg: true,
244 | inputTxt: ''
245 | });
246 | // 打开调试
247 | wx.setEnableDebug({
248 | enableDebug: true
249 | })
250 | return;
251 | } else if(inputTxt === 'gbd' || inputTxt === 'GBD' || inputTxt === 'Gbd') {
252 | self.setData({
253 | //关闭调试按钮
254 | isDbg: false,
255 | inputTxt: ''
256 | });
257 | // 关闭调试
258 | wx.setEnableDebug({
259 | enableDebug: false,
260 | })
261 | return;
262 | }
263 |
264 | //正常用户输入文本
265 | if (inputTxt !== '') {
266 | self.setData({
267 | inputTxt: inputTxt
268 | });
269 | NliProcess(inputTxt, self);
270 | }
271 | }
272 |
273 | //选择预置语料运行语义理解
274 | function selectCorpusRunNli(self) {
275 | var corpus = app.globalData.corpus;
276 |
277 | //顺序选择一句语料
278 | var corpusSelected = corpus[cursor]
279 |
280 | self.setData({
281 | //更新页面input框显示
282 | inputTxt: corpusSelected
283 | })
284 |
285 | UTIL.log('selected corpus:' + corpusSelected)
286 | //调用语料处理,刷新输出框结果
287 | NliProcess(corpusSelected, self);
288 |
289 | //光标后移,备下次挑选下一条语料
290 | if (cursor++ >= corpus.length - 1) {
291 | cursor = 0;
292 | }
293 |
294 | return corpusSelected;
295 | }
296 |
297 | //检测加速度传感器灵敏度
298 | function isBong(val) {
299 | //目前灵敏度设置为0.8,且摇一摇只监测了x和y轴变动,具体见调用此函数的地方
300 | if (val >= 0.8 || val <= -0.8) {
301 | return true;
302 | }
303 |
304 | return false;
305 | }
--------------------------------------------------------------------------------
/yzz_weixinapp/pages/index/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "window": {
3 | "enablePullDownRefresh": true
4 | }
5 | }
--------------------------------------------------------------------------------
/yzz_weixinapp/pages/index/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{outputTxt}}
5 |
6 |
7 |
8 |
9 | 语义理解基于“欧拉蜜”:cn.olami.ai
10 | 支持“摇一摇”、点按钮、手动输入、向下拉
11 |
12 |
13 |
14 |
15 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/yzz_weixinapp/pages/index/index.wxss:
--------------------------------------------------------------------------------
1 | page{
2 | background-color:beige;
3 | background-image: url(http://img.blog.csdn.net/20170720105808995?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaGFwcHljeHo=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast);
4 | background-size: cover;
5 | }
6 |
7 | .page-section{
8 | display: flex;
9 | flex-direction: column;
10 | margin-bottom: 10rpx;
11 | }
12 |
13 | .page-center {
14 | align-items: center;
15 | }
16 |
17 | .page-gap{
18 | margin-top: 5rpx;
19 | }
20 |
21 | .button-selection {
22 | display: flex;
23 | flex-direction: column;
24 | justify-content: center;
25 | align-items: center;
26 | }
27 |
28 | .button-selection2 {
29 | justify-content: space-between;
30 | align-content: space-between;
31 | flex-shrink:1;
32 | }
33 |
34 | .little-gap-top {
35 | margin-top: 15rpx;
36 | }
37 |
38 | .little-gap-left {
39 | margin-left: 5rpx;
40 | }
41 |
42 | .text-description{
43 | color: #ff0000;
44 | font-size: 28rpx;
45 | }
46 |
47 | .text-head{
48 | color: #00BFFF;
49 | font-size: 36rpx;
50 | }
51 |
52 | .common-disappear {
53 | display: none
54 | }
55 |
56 | .button-show {
57 | display: flex;
58 | align-self: center;
59 | justify-content: center;
60 | }
61 |
62 | .text-box{
63 | margin-bottom: 0rpx;
64 | margin-left: 50rpx;
65 | margin-right: 50rpx;
66 | padding: 40rpx 0;
67 | display: flex;
68 | min-height: 300rpx;
69 | max-width: 600rpx;
70 | width:600rpx;
71 | background-color: #ffffff;
72 | justify-content: center;
73 | align-items: center;
74 | text-align: left;
75 | font-size: 30rpx;
76 | color: #353535;
77 | line-height: 2em;
78 | word-wrap: break-word;
79 | border: 1px solid cornflowerblue;
80 | }
81 |
82 | .weui-cells {
83 | position: relative;
84 | margin-top: 1.17647059em;
85 | background-color: #DCDCDC;
86 | line-height: 1.41176471;
87 | font-size: 14px;
88 | }
89 |
90 | .weui-cells_after-title {
91 | margin-top: 0;
92 | }
93 |
94 | .weui-input {
95 | height: 2.58823529em;
96 | width: 17em;
97 | min-height: 2.58823529em;
98 | line-height: 2.58823529em;
99 | }
100 |
101 | .bottom-button {
102 | justify-content: space-around;
103 | flex-shrink:0;
104 | }
105 |
--------------------------------------------------------------------------------
/yzz_weixinapp/pages/logs/logs.js:
--------------------------------------------------------------------------------
1 | //logs.js
2 | var util = require('../../utils/util.js')
3 | Page({
4 | data: {
5 | logs: []
6 | },
7 | onLoad: function () {
8 | this.setData({
9 | logs: (wx.getStorageSync('logs') || []).map(function (log) {
10 | var DATE = new Date(log);
11 | if (typeof DATE === 'date') {
12 | //当log是一个毫秒数,延用官方的案例,转成对应时间存LOG中(util.formatTime被我改成只输出时分秒)
13 | return util.formatTime(new Date(log))
14 | }
15 |
16 | //非毫秒数时,记录LOG原始内容,不作转换
17 | return log;
18 | })
19 | })
20 | }
21 | })
22 |
--------------------------------------------------------------------------------
/yzz_weixinapp/pages/logs/logs.json:
--------------------------------------------------------------------------------
1 | {
2 | "navigationBarTitleText": "调试LOG页"
3 | }
--------------------------------------------------------------------------------
/yzz_weixinapp/pages/logs/logs.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{index + 1}}. {{log}}
5 |
6 |
7 |
--------------------------------------------------------------------------------
/yzz_weixinapp/pages/logs/logs.wxss:
--------------------------------------------------------------------------------
1 | .log-list {
2 | display: flex;
3 | flex-direction: column;
4 | padding: 40rpx;
5 | }
6 | .log-item {
7 | margin: 10rpx;
8 | }
9 |
--------------------------------------------------------------------------------
/yzz_weixinapp/pages/test/test.js:
--------------------------------------------------------------------------------
1 | var page = undefined;
2 |
3 | var UTIL = require('../../utils/util.js');
4 |
5 | Page({
6 | onLoad: function () {
7 | page = this;
8 |
9 | wx.getSystemInfo({
10 | success: function (res) {
11 | UTIL.log('system info:' + JSON.stringify(res))
12 | }
13 | })
14 |
15 | },
16 | bindbt: function () {
17 | var timer = setInterval(this.addDoomm, 1000)
18 | },
19 | data: {
20 | doommData: []
21 | },
22 |
23 | addDoomm : function() {
24 | if (doommList.length < 5) {
25 | doommList.push(new Doomm("弹幕测试程序", Math.ceil(Math.random() * 40 + 50), Math.ceil(Math.random() * 10 + 10), getRandomColor()));
26 | this.setData({
27 | doommData: doommList
28 | })
29 | }
30 | }
31 | })
32 |
33 | var doommList = [];
34 | var i = 0;
35 | class Doomm {
36 | constructor(text, top, time, color) {
37 | this.text = text + i;
38 | this.top = top;
39 | this.time = time;
40 | this.color = color;
41 | this.display = true;
42 | let that = this;
43 | this.id = i++;
44 | setTimeout(function () {
45 | doommList.splice(doommList.indexOf(that), 1);
46 | page.setData({
47 | doommData: doommList
48 | })
49 | }, this.time * 1000)
50 | }
51 | }
52 | function getRandomColor() {
53 | let rgb = []
54 | for (let i = 0; i < 3; ++i) {
55 | let color = Math.floor(Math.random() * 256).toString(16)
56 | color = color.length == 1 ? '0' + color : color
57 | rgb.push(color)
58 | }
59 | return '#' + rgb.join('')
60 | }
--------------------------------------------------------------------------------
/yzz_weixinapp/pages/test/test.json:
--------------------------------------------------------------------------------
1 | {
2 | "navigationBarTitleText": "遥知之 -- 录音测试页"
3 | }
--------------------------------------------------------------------------------
/yzz_weixinapp/pages/test/test.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {{item.text}}
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/yzz_weixinapp/pages/test/test.wxss:
--------------------------------------------------------------------------------
1 | /* pages/asr/asr.wxss */
2 |
3 | page{
4 | background-color:beige;
5 | background-image: url(http://img.blog.csdn.net/20170720105808995?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaGFwcHljeHo=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast);
6 | background-size: cover;
7 | }
8 |
9 | .page-section{
10 | display: flex;
11 | flex-direction: column;
12 | margin-bottom: 10rpx;
13 | }
14 |
15 | .text-head{
16 | color: #ff0000;
17 | font-size: 28rpx;
18 | align-items: center;
19 | margin-top: 5rpx;
20 | }
21 |
22 | .button-selection {
23 | display: flex;
24 | flex-direction: column;
25 | justify-content: center;
26 | align-items: center;
27 | }
28 |
29 | .button-selection2 {
30 | justify-content: space-between;
31 | align-content: space-between;
32 | flex-shrink:1;
33 | }
34 |
35 | .little-gap-top {
36 | margin-top: 10rpx;
37 | }
38 |
39 | .big-gap-top {
40 | margin-top: 100rpx;
41 | }
42 |
43 | .button-show {
44 | display: flex;
45 | align-self: center;
46 | justify-content: center;
47 | }
48 |
49 | .bottom-button {
50 | justify-content: space-around;
51 | flex-shrink:0;
52 | }
53 |
54 | .text-box{
55 | margin-bottom: 0rpx;
56 | margin-left: 50rpx;
57 | margin-right: 50rpx;
58 | padding: 40rpx 0;
59 | display: flex;
60 | min-height: 300rpx;
61 | max-width: 600rpx;
62 | width:600rpx;
63 | background-color: #ffffff;
64 | justify-content: center;
65 | align-items: center;
66 | text-align: left;
67 | font-size: 30rpx;
68 | color: #353535;
69 | line-height: 2em;
70 | word-wrap: break-word;
71 | border: 1px solid cornflowerblue;
72 | }
73 |
74 |
75 | /* 录音 */
76 | .speak-style{
77 | position: relative;
78 | height: 240rpx;
79 | width: 240rpx;
80 | border-radius: 20rpx;
81 | margin: 0 auto;
82 | background: #26A5FF;
83 | }
84 | .record-style{
85 | position: fixed;
86 | bottom: 0;
87 | left: 0;
88 | height: 120rpx;
89 | width: 100%;
90 | }
91 | .btn-style{
92 | margin-left: 30rpx;
93 | margin-right: 30rpx;
94 | }
95 |
96 | .sound-style{
97 | position: absolute;
98 | width: 74rpx;
99 | height:150rpx;
100 | margin-top: 45rpx;
101 | margin-left: 83rpx;
102 | }
103 |
104 |
105 | /* 弹幕 */
106 | .barrage-fly{
107 | z-index: 3;
108 | height: 20%;
109 | width: 100%;
110 | position: absolute;
111 | top: 0;
112 | }
113 | .barrage-textFly{
114 | position: absolute;
115 | white-space:nowrap;
116 | }
117 |
118 | /**index.wxss**/
119 | .button{
120 | position: absolute;
121 | bottom: 0;
122 | width: 100%;
123 | }
124 | .aon{
125 | position: absolute;
126 | white-space:nowrap;/* 防止向下换行*/
127 | animation-timing-function: linear;
128 | animation-fill-mode: none;
129 | }
130 | .doommview{
131 | z-index: 3;
132 | height: 80%;
133 | width: 100%;
134 | position: absolute;
135 | }
136 |
137 | @keyframes first{
138 | from{left: 100%; }
139 | to{left: -100%;}
140 | }
141 |
--------------------------------------------------------------------------------
/yzz_weixinapp/pics/bg.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/happycxz/nlp_olami_yaozhizhi_wechat_littleapp_demo/b6fbec55302851cb623e9ae51144bea73ddc4514/yzz_weixinapp/pics/bg.jpg
--------------------------------------------------------------------------------
/yzz_weixinapp/pics/voice_icon_speech_sound_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/happycxz/nlp_olami_yaozhizhi_wechat_littleapp_demo/b6fbec55302851cb623e9ae51144bea73ddc4514/yzz_weixinapp/pics/voice_icon_speech_sound_1.png
--------------------------------------------------------------------------------
/yzz_weixinapp/pics/voice_icon_speech_sound_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/happycxz/nlp_olami_yaozhizhi_wechat_littleapp_demo/b6fbec55302851cb623e9ae51144bea73ddc4514/yzz_weixinapp/pics/voice_icon_speech_sound_2.png
--------------------------------------------------------------------------------
/yzz_weixinapp/pics/voice_icon_speech_sound_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/happycxz/nlp_olami_yaozhizhi_wechat_littleapp_demo/b6fbec55302851cb623e9ae51144bea73ddc4514/yzz_weixinapp/pics/voice_icon_speech_sound_3.png
--------------------------------------------------------------------------------
/yzz_weixinapp/pics/voice_icon_speech_sound_4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/happycxz/nlp_olami_yaozhizhi_wechat_littleapp_demo/b6fbec55302851cb623e9ae51144bea73ddc4514/yzz_weixinapp/pics/voice_icon_speech_sound_4.png
--------------------------------------------------------------------------------
/yzz_weixinapp/pics/voice_icon_speech_sound_5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/happycxz/nlp_olami_yaozhizhi_wechat_littleapp_demo/b6fbec55302851cb623e9ae51144bea73ddc4514/yzz_weixinapp/pics/voice_icon_speech_sound_5.png
--------------------------------------------------------------------------------
/yzz_weixinapp/utils/GUID.js:
--------------------------------------------------------------------------------
1 |
2 | //表示全局唯一标识符 (GUID)。
3 | function Guid(g) {
4 | var arr = new Array(); //存放32位数值的数组
5 |
6 | if (typeof (g) == "string") { //如果构造函数的参数为字符串
7 | InitByString(arr, g);
8 | } else {
9 | InitByOther(arr);
10 | }
11 |
12 | //返回一个值,该值指示 Guid 的两个实例是否表示同一个值。
13 | this.Equals = function (o) {
14 | if (o && o.IsGuid) {
15 | return this.ToString() == o.ToString();
16 | } else {
17 | return false;
18 | }
19 | }
20 |
21 | //Guid对象的标记
22 | this.IsGuid = function () { }
23 | //返回 Guid 类的此实例值的 String 表示形式。
24 | this.ToString = function (format) {
25 | if (typeof (format) == "string") {
26 | if (format == "N" || format == "D" || format == "B" || format == "P") {
27 | return ToStringWithFormat(arr, format);
28 | } else {
29 | return ToStringWithFormat(arr, "D");
30 | }
31 | } else {
32 | return ToStringWithFormat(arr, "D");
33 | }
34 | }
35 |
36 | //由字符串加载
37 | function InitByString(arr, g) {
38 | g = g.replace(/\{|\(|\)|\}|-/g, "");
39 | g = g.toLowerCase();
40 | if (g.length != 32 || g.search(/[^0-9,a-f]/i) != -1) {
41 | InitByOther(arr);
42 | } else {
43 | for (var i = 0; i < g.length; i++) {
44 | arr.push(g[i]);
45 | }
46 | }
47 | }
48 |
49 | //由其他类型加载
50 | function InitByOther(arr) {
51 | var i = 32;
52 | while (i--) {
53 | arr.push("0");
54 | }
55 | }
56 |
57 | /*
58 | 根据所提供的格式说明符,返回此 Guid 实例值的 String 表示形式。
59 | N 32 位: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
60 | D 由连字符分隔的 32 位数字 xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
61 | B 括在大括号中、由连字符分隔的 32 位数字:{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
62 | P 括在圆括号中、由连字符分隔的 32 位数字:(xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)
63 | */
64 |
65 | function ToStringWithFormat(arr, format) {
66 | switch (format) {
67 | case "N":
68 | return arr.toString().replace(/,/g, "");
69 | case "D":
70 | var str = arr.slice(0, 8) + "-" + arr.slice(8, 12) + "-" + arr.slice(12, 16) + "-" + arr.slice(16, 20) + "-" + arr.slice(20, 32);
71 | str = str.replace(/,/g, "");
72 | return str;
73 | case "B":
74 | var str = ToStringWithFormat(arr, "D");
75 | str = "{" + str + "}";
76 | return str;
77 | case "P":
78 | var str = ToStringWithFormat(arr, "D");
79 | str = "(" + str + ")";
80 | return str;
81 | default:
82 | return new Guid();
83 | }
84 | }
85 | }
86 |
87 | //Guid 类的默认实例,其值保证均为零。
88 | Guid.Empty = new Guid();
89 |
90 | //初始化 Guid 类的一个新实例。
91 | Guid.NewGuid = function () {
92 | var g = "";
93 | var i = 32;
94 |
95 | while (i--) {
96 | g += Math.floor(Math.random() * 16.0).toString(16);
97 | }
98 | return new Guid(g).ToString();
99 | }
100 |
101 | module.exports = {
102 | NewGuid: Guid.NewGuid
103 | }
--------------------------------------------------------------------------------
/yzz_weixinapp/utils/MD5.js:
--------------------------------------------------------------------------------
1 |
2 |
3 | //md5加密算法
4 | function md5(string) {
5 | var x = Array();
6 | var k, AA, BB, CC, DD, a, b, c, d;
7 | var S11 = 7, S12 = 12, S13 = 17, S14 = 22;
8 | var S21 = 5, S22 = 9, S23 = 14, S24 = 20;
9 | var S31 = 4, S32 = 11, S33 = 16, S34 = 23;
10 | var S41 = 6, S42 = 10, S43 = 15, S44 = 21;
11 | string = Utf8Encode(string);
12 | x = ConvertToWordArray(string);
13 | a = 0x67452301;
14 | b = 0xEFCDAB89;
15 | c = 0x98BADCFE;
16 | d = 0x10325476;
17 | for (k = 0; k < x.length; k += 16) {
18 | AA = a;
19 | BB = b;
20 | CC = c;
21 | DD = d;
22 | a = FF(a, b, c, d, x[k + 0], S11, 0xD76AA478);
23 | d = FF(d, a, b, c, x[k + 1], S12, 0xE8C7B756);
24 | c = FF(c, d, a, b, x[k + 2], S13, 0x242070DB);
25 | b = FF(b, c, d, a, x[k + 3], S14, 0xC1BDCEEE);
26 | a = FF(a, b, c, d, x[k + 4], S11, 0xF57C0FAF);
27 | d = FF(d, a, b, c, x[k + 5], S12, 0x4787C62A);
28 | c = FF(c, d, a, b, x[k + 6], S13, 0xA8304613);
29 | b = FF(b, c, d, a, x[k + 7], S14, 0xFD469501);
30 | a = FF(a, b, c, d, x[k + 8], S11, 0x698098D8);
31 | d = FF(d, a, b, c, x[k + 9], S12, 0x8B44F7AF);
32 | c = FF(c, d, a, b, x[k + 10], S13, 0xFFFF5BB1);
33 | b = FF(b, c, d, a, x[k + 11], S14, 0x895CD7BE);
34 | a = FF(a, b, c, d, x[k + 12], S11, 0x6B901122);
35 | d = FF(d, a, b, c, x[k + 13], S12, 0xFD987193);
36 | c = FF(c, d, a, b, x[k + 14], S13, 0xA679438E);
37 | b = FF(b, c, d, a, x[k + 15], S14, 0x49B40821);
38 | a = GG(a, b, c, d, x[k + 1], S21, 0xF61E2562);
39 | d = GG(d, a, b, c, x[k + 6], S22, 0xC040B340);
40 | c = GG(c, d, a, b, x[k + 11], S23, 0x265E5A51);
41 | b = GG(b, c, d, a, x[k + 0], S24, 0xE9B6C7AA);
42 | a = GG(a, b, c, d, x[k + 5], S21, 0xD62F105D);
43 | d = GG(d, a, b, c, x[k + 10], S22, 0x2441453);
44 | c = GG(c, d, a, b, x[k + 15], S23, 0xD8A1E681);
45 | b = GG(b, c, d, a, x[k + 4], S24, 0xE7D3FBC8);
46 | a = GG(a, b, c, d, x[k + 9], S21, 0x21E1CDE6);
47 | d = GG(d, a, b, c, x[k + 14], S22, 0xC33707D6);
48 | c = GG(c, d, a, b, x[k + 3], S23, 0xF4D50D87);
49 | b = GG(b, c, d, a, x[k + 8], S24, 0x455A14ED);
50 | a = GG(a, b, c, d, x[k + 13], S21, 0xA9E3E905);
51 | d = GG(d, a, b, c, x[k + 2], S22, 0xFCEFA3F8);
52 | c = GG(c, d, a, b, x[k + 7], S23, 0x676F02D9);
53 | b = GG(b, c, d, a, x[k + 12], S24, 0x8D2A4C8A);
54 | a = HH(a, b, c, d, x[k + 5], S31, 0xFFFA3942);
55 | d = HH(d, a, b, c, x[k + 8], S32, 0x8771F681);
56 | c = HH(c, d, a, b, x[k + 11], S33, 0x6D9D6122);
57 | b = HH(b, c, d, a, x[k + 14], S34, 0xFDE5380C);
58 | a = HH(a, b, c, d, x[k + 1], S31, 0xA4BEEA44);
59 | d = HH(d, a, b, c, x[k + 4], S32, 0x4BDECFA9);
60 | c = HH(c, d, a, b, x[k + 7], S33, 0xF6BB4B60);
61 | b = HH(b, c, d, a, x[k + 10], S34, 0xBEBFBC70);
62 | a = HH(a, b, c, d, x[k + 13], S31, 0x289B7EC6);
63 | d = HH(d, a, b, c, x[k + 0], S32, 0xEAA127FA);
64 | c = HH(c, d, a, b, x[k + 3], S33, 0xD4EF3085);
65 | b = HH(b, c, d, a, x[k + 6], S34, 0x4881D05);
66 | a = HH(a, b, c, d, x[k + 9], S31, 0xD9D4D039);
67 | d = HH(d, a, b, c, x[k + 12], S32, 0xE6DB99E5);
68 | c = HH(c, d, a, b, x[k + 15], S33, 0x1FA27CF8);
69 | b = HH(b, c, d, a, x[k + 2], S34, 0xC4AC5665);
70 | a = II(a, b, c, d, x[k + 0], S41, 0xF4292244);
71 | d = II(d, a, b, c, x[k + 7], S42, 0x432AFF97);
72 | c = II(c, d, a, b, x[k + 14], S43, 0xAB9423A7);
73 | b = II(b, c, d, a, x[k + 5], S44, 0xFC93A039);
74 | a = II(a, b, c, d, x[k + 12], S41, 0x655B59C3);
75 | d = II(d, a, b, c, x[k + 3], S42, 0x8F0CCC92);
76 | c = II(c, d, a, b, x[k + 10], S43, 0xFFEFF47D);
77 | b = II(b, c, d, a, x[k + 1], S44, 0x85845DD1);
78 | a = II(a, b, c, d, x[k + 8], S41, 0x6FA87E4F);
79 | d = II(d, a, b, c, x[k + 15], S42, 0xFE2CE6E0);
80 | c = II(c, d, a, b, x[k + 6], S43, 0xA3014314);
81 | b = II(b, c, d, a, x[k + 13], S44, 0x4E0811A1);
82 | a = II(a, b, c, d, x[k + 4], S41, 0xF7537E82);
83 | d = II(d, a, b, c, x[k + 11], S42, 0xBD3AF235);
84 | c = II(c, d, a, b, x[k + 2], S43, 0x2AD7D2BB);
85 | b = II(b, c, d, a, x[k + 9], S44, 0xEB86D391);
86 | a = AddUnsigned(a, AA);
87 | b = AddUnsigned(b, BB);
88 | c = AddUnsigned(c, CC);
89 | d = AddUnsigned(d, DD);
90 | }
91 | var temp = WordToHex(a) + WordToHex(b) + WordToHex(c) + WordToHex(d);
92 | return temp.toLowerCase();
93 | }
94 | function RotateLeft(lValue, iShiftBits) {
95 | return (lValue << iShiftBits) | (lValue >>> (32 - iShiftBits));
96 | }
97 | function AddUnsigned(lX, lY) {
98 | var lX4, lY4, lX8, lY8, lResult;
99 | lX8 = (lX & 0x80000000);
100 | lY8 = (lY & 0x80000000);
101 | lX4 = (lX & 0x40000000);
102 | lY4 = (lY & 0x40000000);
103 | lResult = (lX & 0x3FFFFFFF) + (lY & 0x3FFFFFFF);
104 | if (lX4 & lY4) {
105 | return (lResult ^ 0x80000000 ^ lX8 ^ lY8);
106 | }
107 | if (lX4 | lY4) {
108 | if (lResult & 0x40000000) {
109 | return (lResult ^ 0xC0000000 ^ lX8 ^ lY8);
110 | } else {
111 | return (lResult ^ 0x40000000 ^ lX8 ^ lY8);
112 | }
113 | } else {
114 | return (lResult ^ lX8 ^ lY8);
115 | }
116 | }
117 | function F(x, y, z) {
118 | return (x & y) | ((~x) & z);
119 | }
120 | function G(x, y, z) {
121 | return (x & z) | (y & (~z));
122 | }
123 | function H(x, y, z) {
124 | return (x ^ y ^ z);
125 | }
126 | function I(x, y, z) {
127 | return (y ^ (x | (~z)));
128 | }
129 | function FF(a, b, c, d, x, s, ac) {
130 | a = AddUnsigned(a, AddUnsigned(AddUnsigned(F(b, c, d), x), ac));
131 | return AddUnsigned(RotateLeft(a, s), b);
132 | }
133 | function GG(a, b, c, d, x, s, ac) {
134 | a = AddUnsigned(a, AddUnsigned(AddUnsigned(G(b, c, d), x), ac));
135 | return AddUnsigned(RotateLeft(a, s), b);
136 | }
137 | function HH(a, b, c, d, x, s, ac) {
138 | a = AddUnsigned(a, AddUnsigned(AddUnsigned(H(b, c, d), x), ac));
139 | return AddUnsigned(RotateLeft(a, s), b);
140 | }
141 | function II(a, b, c, d, x, s, ac) {
142 | a = AddUnsigned(a, AddUnsigned(AddUnsigned(I(b, c, d), x), ac));
143 | return AddUnsigned(RotateLeft(a, s), b);
144 | }
145 | function ConvertToWordArray(string) {
146 | var lWordCount;
147 | var lMessageLength = string.length;
148 | var lNumberOfWords_temp1 = lMessageLength + 8;
149 | var lNumberOfWords_temp2 = (lNumberOfWords_temp1 - (lNumberOfWords_temp1 % 64)) / 64;
150 | var lNumberOfWords = (lNumberOfWords_temp2 + 1) * 16;
151 | var lWordArray = Array(lNumberOfWords - 1);
152 | var lBytePosition = 0;
153 | var lByteCount = 0;
154 | while (lByteCount < lMessageLength) {
155 | lWordCount = (lByteCount - (lByteCount % 4)) / 4;
156 | lBytePosition = (lByteCount % 4) * 8;
157 | lWordArray[lWordCount] = (lWordArray[lWordCount] | (string.charCodeAt(lByteCount) << lBytePosition));
158 | lByteCount++;
159 | }
160 | lWordCount = (lByteCount - (lByteCount % 4)) / 4;
161 | lBytePosition = (lByteCount % 4) * 8;
162 | lWordArray[lWordCount] = lWordArray[lWordCount] | (0x80 << lBytePosition);
163 | lWordArray[lNumberOfWords - 2] = lMessageLength << 3;
164 | lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29;
165 | return lWordArray;
166 | }
167 | function WordToHex(lValue) {
168 | var WordToHexValue = "", WordToHexValue_temp = "", lByte, lCount;
169 | for (lCount = 0; lCount <= 3; lCount++) {
170 | lByte = (lValue >>> (lCount * 8)) & 255;
171 | WordToHexValue_temp = "0" + lByte.toString(16);
172 | WordToHexValue = WordToHexValue + WordToHexValue_temp.substr(WordToHexValue_temp.length - 2, 2);
173 | }
174 | return WordToHexValue;
175 | }
176 | function Utf8Encode(string) {
177 | var utftext = "";
178 | for (var n = 0; n < string.length; n++) {
179 | var c = string.charCodeAt(n);
180 | if (c < 128) {
181 | utftext += String.fromCharCode(c);
182 | } else if ((c > 127) && (c < 2048)) {
183 | utftext += String.fromCharCode((c >> 6) | 192);
184 | utftext += String.fromCharCode((c & 63) | 128);
185 | } else {
186 | utftext += String.fromCharCode((c >> 12) | 224);
187 | utftext += String.fromCharCode(((c >> 6) & 63) | 128);
188 | utftext += String.fromCharCode((c & 63) | 128);
189 | }
190 | }
191 | return utftext;
192 | }
193 | module.exports = {
194 | md5: md5
195 | }
--------------------------------------------------------------------------------
/yzz_weixinapp/utils/NLI.js:
--------------------------------------------------------------------------------
1 | /*
2 | 对接olami免费开放语义平台的NLI接口
3 | */
4 |
5 | //获取应用实例
6 | var app = getApp()
7 |
8 | const appkey = require('../config').appkey
9 | const appsecret = require('../config').appsecret
10 |
11 | var MD5 = require('./MD5.js');
12 | var UTIL = require('./util.js');
13 |
14 | const requestUrl = "https://cn.olami.ai/cloudservice/api";
15 | const api = "nli";
16 |
17 |
18 | function getLocationJson() {
19 | var lat = app.globalData.latitude;
20 | var lng = app.globalData.longitude;
21 | if (lat < 180 && lng < 180) {
22 | lat *= 1000000;
23 | lng *= 1000000;
24 | }
25 |
26 | return { "position_type": 0, "longitude": lng, "latitude": lat };
27 | }
28 |
29 | //NLI接口访问
30 | //参数:corpus为句子;cb为回调函数(带两个参数,第一个参数表示调用NLI是否成功,第二个参数是NLI的返回数据)
31 | function process(corpus, cb) {
32 | var timestamp = new Date().getTime();
33 | var originalSign = appsecret + "api=" + api + "appkey=" + appkey + "timestamp=" + timestamp + appsecret;
34 | var sign = MD5.md5(originalSign);
35 |
36 | var locationJson = getLocationJson();
37 | var rqdataJson = { "data": { "input_type": 1, "text": corpus, "location": locationJson }, "data_type": "stt" };
38 | var rqdata = JSON.stringify(rqdataJson);
39 |
40 | UTIL.log('input:' + rqdata + '\r\n, custId:' + app.globalData.custId + ', originalSign:' + originalSign);
41 |
42 | wx.request({
43 | url: requestUrl,
44 | data: {
45 | appkey: appkey,
46 | api: api,
47 | timestamp: timestamp,
48 | sign: sign,
49 | rq: rqdata,
50 | cusid: app.globalData.custId,
51 | },
52 | header: {
53 | 'content-type': 'application/x-www-form-urlencoded'
54 | },
55 | method: 'POST',
56 | success: function (result) {
57 | var data = result.data.data;
58 | var jsonData = JSON.stringify(data);
59 | typeof cb == "function" && cb(true, jsonData)
60 | },
61 | fail: function ({errMsg}) {
62 | typeof cb == "function" && cb(false, jsonData)
63 | }
64 | })
65 | }
66 |
67 | //解析NLI接口返回的数据,从语义结果中筛选出适合显示的文本内容
68 | function getSentenceFromNliResult(nliArray) {
69 | var sentence;
70 | try {
71 | for (var i = 0; i < nliArray.length; i++) {
72 | var singleResult = nliArray[i];
73 | sentence = singleResult.desc_obj.result;
74 |
75 | var content = '';
76 | var appName = singleResult.type;
77 | //0: normal, 1: selection, 9 : openweb
78 | var tagType = 0;
79 | if (appName === 'selection') {
80 | appName = singleResult.desc_obj.type;
81 | tagType = 1;
82 | } else if (appName === 'openweb') {
83 | //appName = singleResult.desc_obj.type;
84 | tagType = 9;
85 | }
86 | switch (appName) {
87 | case 'joke':
88 | case 'story':
89 | sentence = singleResult.data_obj[0].content;
90 | break;
91 | case 'poem':
92 | if (tagType === 1) {
93 | for (var k = 0; k < singleResult.data_obj.length; k++) {
94 | content += '第' + (k + 1) + '个: ' + singleResult.data_obj[k].author + ' ' + singleResult.data_obj[k].poem_name + '\n';
95 | }
96 | }
97 | break;
98 | case 'cooking':
99 | if (tagType === 1) {
100 | for (var k = 0; k < singleResult.data_obj.length; k++) {
101 | content += '第' + (k + 1) + '个: ' + singleResult.data_obj[k].name + '\n';
102 | }
103 | } else if (tagType === 0) {
104 | content = singleResult.data_obj[0].content;
105 | }
106 | break;
107 | case 'baike':
108 | var filedNames = singleResult.data_obj[0].field_name;
109 | var filedValues = singleResult.data_obj[0].field_value;
110 | for (var k = 0; k < filedNames.length; k++) {
111 | content += filedNames[k] + ' : ' + filedValues[k] + '\n';
112 | }
113 | break;
114 | case 'news':
115 | if (tagType === 1) {
116 | for (var k = 0; k < singleResult.data_obj.length; k++) {
117 | content += singleResult.data_obj[k].title + '\n';
118 | content += singleResult.data_obj[k].detail + '…………\n';
119 | content += '【欲看此条新闻详情请说第' + (k + 1) + '个,或拷此链接到浏览器中打开:' + singleResult.data_obj[k].ref_url + '】\n\n';
120 | }
121 | } else if (tagType === 0) {
122 | content = singleResult.data_obj[0].detail;
123 | }
124 | break;
125 | case 'stock':
126 | var nowHour = new Date().getHours();
127 | var isKaiPan = (nowHour >= 9) && (nowHour <= 15);
128 | for (var k = 0; k < singleResult.data_obj.length; k++) {
129 | content += singleResult.data_obj[k].name + ' : ' + singleResult.data_obj[k].id + '\n';
130 | content += '开盘:' + singleResult.data_obj[k].price_start + '\n';
131 | if (isKaiPan) {
132 | content += '现价(' + UTIL.getHHMMSS(singleResult.data_obj[k].time) + '):' + singleResult.data_obj[k].cur_price + '\n';
133 | } else {
134 | content += '收盘:' + singleResult.data_obj[k].price_end + '\n';
135 | }
136 | content += '成交量:' + singleResult.data_obj[k].volume + '\n';
137 | content += '成交额:' + singleResult.data_obj[k].amount + '\n';
138 | content += '最高价:' + singleResult.data_obj[k].price_high + '\n\n';
139 | }
140 | break;
141 | case 'tvprogram':
142 | for (var k = 0; k < singleResult.data_obj.length; k++) {
143 | content += singleResult.data_obj[k].time + ' ' + singleResult.data_obj[k].name + '\n';
144 | }
145 | break;
146 | case 'openweb':
147 | content += '【拷此链接到浏览器中打开:' + singleResult.data_obj[0].url + '】\n';
148 | break;
149 | defalt:
150 | break;
151 | }
152 | if (content !== '') {
153 | sentence += '\n\n' + content;
154 | }
155 | UTIL.log('NLI返回sentence:' + sentence)
156 | }
157 | } catch (e) {
158 | UTIL.log('getSentenceFromNliResult() 错误' + e.message + '发生在' + e.lineNumber + '行');
159 | sentence = '没明白你说的,换个话题?'
160 | }
161 |
162 | if (typeof sentence === 'undefined' || sentence === '') {
163 | sentence = '没明白你说的什么意思';
164 | }
165 |
166 | return sentence;
167 | }
168 |
169 |
170 | module.exports = {
171 | process: process,
172 | getSentenceFromNliResult: getSentenceFromNliResult,
173 | }
--------------------------------------------------------------------------------
/yzz_weixinapp/utils/util.js:
--------------------------------------------------------------------------------
1 | //获取应用实例
2 | var app = getApp()
3 |
4 | var Guid = require('./GUID.js');
5 |
6 | var uuidSaved = '';
7 |
8 | //将date格式的数据转成 hh:mm:ss 字符串格式
9 | function formatTime(date) {
10 | var year = date.getFullYear()
11 | var month = date.getMonth() + 1
12 | var day = date.getDate()
13 |
14 | var hour = date.getHours()
15 | var minute = date.getMinutes()
16 | var second = date.getSeconds()
17 |
18 |
19 | //return [year, month, day].map(formatNumber).join('/') + ' ' + [hour, minute, second].map(formatNumber).join(':')
20 | return [hour, minute, second].map(formatNumber).join(':')
21 | }
22 |
23 | function formatNumber(n) {
24 | n = n.toString()
25 | return n[1] ? n : '0' + n
26 | }
27 |
28 | //log接口封装
29 | function log(obj) {
30 | console.log('<' + formatTime(new Date(Date.now())) + '>' + ' ' + obj)
31 |
32 | //往用户缓存去写
33 | // var logs = wx.getStorageSync('logs') || []
34 | // logs.unshift('[' + formatTime(new Date(Date.now())) + ']' + ' ' + obj)
35 | // wx.setStorageSync('logs', logs)
36 | }
37 |
38 | //获取用户唯一标识,NLI接口中要上传用户唯一标识,这里获取:第一次登录时生成的uuid+微信号所在地+昵称
39 | function getUserUnique(userInfo) {
40 | //从缓存中读取uuid
41 | if (typeof uuidSaved === 'undefined' || uuidSaved === '') {
42 | var tmpUuid = wx.getStorageSync('uuid');
43 | if (typeof tmpUuid === 'undefined' || tmpUuid === '') {
44 | uuidSaved = Guid.NewGuid();
45 | wx.setStorageSync('uuid', uuidSaved);
46 | } else {
47 | uuidSaved = tmpUuid;
48 | }
49 | }
50 |
51 | var unique = uuidSaved;
52 | if (userInfo != null) {
53 | unique += '_' + userInfo.province + '_' + userInfo.nickName;
54 | }
55 | log('getUserUnique() return:' + unique)
56 | return unique;
57 | }
58 |
59 | //由 毫秒数字符串 获取 HH:mm:ss 格式时间
60 | function getHHMMSS(dateStr) {
61 | var dateVal = new Date(parseInt(dateStr));
62 | var hh = dateVal.getHours()
63 | var mm = dateVal.getMinutes()
64 | var ss = dateVal.getSeconds()
65 |
66 | return ((hh >= 10) ? hh : '0' + hh) + ':' + ((mm >= 10) ? mm : '0' + mm) + ':' + ((ss >= 10) ? ss : '0' + ss)
67 | }
68 |
69 |
70 | //从语料数组中随机挑选一条语料
71 | function getRandomItem(corpusList) {
72 | var ret = corpusList[0];
73 | ret = corpusList[Math.floor(Math.random() * corpusList.length)];
74 | return ret;
75 | }
76 |
77 | module.exports = {
78 | formatTime: formatTime,
79 | log: log,
80 | getUserUnique: getUserUnique,
81 | getHHMMSS: getHHMMSS,
82 | getRandomItem: getRandomItem,
83 | }
84 |
--------------------------------------------------------------------------------