├── README.md ├── heartSound V1.dmg ├── heartSound V2.dmg ├── heartSound-master V0 GITHUB.dmg ├── heartSound ├── app.js ├── app.json ├── app.wxss ├── components │ └── waiting-icon │ │ ├── index.js │ │ ├── index.json │ │ ├── index.wxml │ │ └── index.wxss ├── images │ ├── about.png │ ├── back.png │ ├── begin.png │ ├── box_1.png │ ├── box_2.png │ ├── button.png │ ├── dele-blue.png │ ├── dele-pink.png │ ├── dele.png │ ├── enter.png │ ├── fail.png │ ├── hbty.png │ ├── issue.png │ ├── microphone.png │ ├── rotate-blue.png │ ├── rotate-pink.png │ ├── speak.png │ ├── stop.png │ ├── tips.png │ ├── triangleLeft.png │ ├── triangleRight.png │ ├── user_1.png │ ├── user_2.png │ ├── xljj.png │ ├── xxs.png │ └── zxct.png ├── pages │ ├── index │ │ ├── draw │ │ │ ├── draw.js │ │ │ ├── draw.json │ │ │ ├── draw.wxml │ │ │ └── draw.wxss │ │ ├── index.js │ │ ├── index.json │ │ ├── index.wxml │ │ ├── index.wxss │ │ ├── longtalk │ │ │ ├── longtalk.js │ │ │ ├── longtalk.json │ │ │ ├── longtalk.wxml │ │ │ └── longtalk.wxss │ │ └── talk │ │ │ ├── talk.js │ │ │ ├── talk.json │ │ │ ├── talk.wxml │ │ │ └── talk.wxss │ └── user │ │ ├── about │ │ ├── about.js │ │ ├── about.json │ │ ├── about.wxml │ │ └── about.wxss │ │ ├── feedback │ │ ├── feedback.js │ │ ├── feedback.json │ │ ├── feedback.wxml │ │ └── feedback.wxss │ │ ├── user.js │ │ ├── user.json │ │ ├── user.wxml │ │ └── user.wxss ├── project.config.json └── utils │ └── util.js └── 项目截图 ├── about.jpg ├── code.jpg ├── draw.jpg ├── index.jpg ├── letdraw.jpg ├── longtalk.jpg ├── talk.jpg └── user.jpg /README.md: -------------------------------------------------------------------------------- 1 | # heartSound 2 | 心声Lite是一款为听障者服务的微信小程序,提供语音识别、语音合成、画板写字等功能,希望能为他们的生活提供一些便利。本项目使用了“同声传译”插件,希望能和大家一起把这个微信小程序完善地更好,为听障者们带来福音。
3 | 4 | **👏👏如果觉得本项目对你学习小程序插件的使用或其他方面有帮助的话,欢迎右上star支持👏👏** 5 | 6 | ### “微信同声传译”插件使用教程: 7 | 8 | 微信公众平台添加插件 9 | 10 | https://developers.weixin.qq.com/miniprogram/introduction/plugin.html#%E4%BD%BF%E7%94%A8%E6%8F%92%E4%BB%B6 11 | 12 | 浏览插件使用文档 13 | 14 | https://developers.weixin.qq.com/miniprogram/dev/framework/plugin/using.html 15 | 16 | 查看微信同声传译开发文档 17 | 18 | https://mp.weixin.qq.com/wxopen/plugindevdoc?appid=wx069ba97219f66d99&token=321904791&lang=zh_CN 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 | 二、用你添加了插件的小程序的AppID作为小程序开发者创建项目 52 | 53 | 三、在项目的app.json引入插件 54 | ``` 55 | { 56 | "pages": [ 57 | ... 58 | ], 59 | 60 | ... 61 | 62 | "plugins": { 63 | "WechatSI": { 64 | "version": "0.1.0", 65 | "provider": "wx069ba97219f66d99" 66 | } 67 | } 68 | } 69 | ``` 70 | 71 | 四、在需要用到插件功能的页面引入和使用插件,以下的讲解我都写在注释里啦,认真看注释唷!!! 72 | ``` 73 | // pages/talk/talk.js 74 | 75 | // 引入插件 76 | var plugin = requirePlugin("WechatSI") 77 | let manager = plugin.getRecordRecognitionManager() 78 | 79 | Page({ 80 | 81 | /** 82 | * 页面的初始数据 83 | */ 84 | data: { 85 | showmicro:false, 86 | input:'', 87 | content_up:'', 88 | content_down:'你好,我听力不好,你可以按住底部的按钮,对我说普通话' 89 | }, 90 | 91 | //监听字的输入,实时显示在屏幕,并且content_down还会用在文字转语音(语音合成)上。 92 | listenInput: function (e) { 93 | var content = e.detail.value 94 | if (content==''){ 95 | content = '你好,我听力不好,你可以按住底部的按钮,对我说普通话' 96 | } 97 | this.setData({ 98 | content_down: content 99 | }) 100 | }, 101 | 102 | // 清空输入框的内容 103 | dele: function (e) { 104 | this.setData({ 105 | content_down: '', 106 | input:'' 107 | }) 108 | }, 109 | 110 | // 插件使用重要步骤!!! 111 | 112 | // 手指按下 113 | touchdown_plugin: function () { 114 | 115 | // 开始识别语音,设置最长能录30s(插件默认最长能录60s,我觉得30s够了,反正也显示不完- -。) 116 | manager.start({ 117 | duration: 30000, lang: "zh_CN" 118 | }) 119 | 120 | //让“正在说话”的遮罩层出现 121 | this.setData({ 122 | showmicro:true 123 | }) 124 | }, 125 | 126 | // 手指松开 127 | touchup_plugin: function () { 128 | var that = this 129 | 130 | // 语音停止识别的时候会调用的函数,这里是把最终识别结果返回的内容呈现在content_up中 131 | manager.onStop = function (res) { 132 | that.setData({ 133 | content_up: res.result 134 | }) 135 | } 136 | 137 | // 当有新的识别内容返回,就会调用此事件。一般用于想马上得到结果的那种,否则还是onstop用的习惯一些,项目没用到这个,仅作讲解 138 | // manager.onRecognize = function (res) { 139 | // that.setData({ 140 | // content_up: res.result 141 | // }) 142 | //} 143 | 144 | //语音识别停止(此时就会调用manager.onStop函数) 145 | manager.stop(); 146 | 147 | //让“正在说话”的遮罩层消失 148 | this.setData({ 149 | showmicro: false, 150 | }) 151 | }, 152 | 153 | // 文字转语音(语音合成) 154 | wordtospeak: function(e) { 155 | 156 | // 将wxml中传过来的文本内容存起来,用api传给插件 157 | var content = e.currentTarget.dataset.content 158 | 159 | var that = this 160 | plugin.textToSpeech({ 161 | lang: "zh_CN", 162 | tts: true, 163 | content: content, 164 | success: function (res) { 165 | 166 | // 插件返回合成好以后的mp3文件,用api自动播放 167 | const innerAudioContext = wx.createInnerAudioContext() 168 | innerAudioContext.autoplay = true 169 | innerAudioContext.src = res.filename 170 | innerAudioContext.onPlay(() => { 171 | console.log('开始播放') 172 | }) 173 | 174 | console.log("succ tts", res.filename) 175 | }, 176 | fail: function (res) { 177 | console.log("fail tts", res) 178 | } 179 | }) 180 | }, 181 | 182 | /** 183 | * 用户点击右上角分享 184 | */ 185 | onShareAppMessage: function () { 186 | return { 187 | title: '心声Lite,让爱发声', 188 | path: '/pages/index/talk/talk', 189 | imageUrl: '/images/xxs.png' 190 | } 191 | }, 192 | }) 193 | ``` 194 | 195 | 196 | ### 更新日志: 197 | 198 | #### 2018年8月6日 周一 199 | 1.因为“同声传译”插件那边的问题,第一次识别的时候总是没有返回值,所以我只能加一个标签说需要第一次试音之后才能正常使用来提示用户。
200 | 2.当开始识别语音时,加入了一个提示的遮罩层。V0是必须要录够3S,才能结束一次,现在修改成了松开后就停止录音,返回识别,遮罩层消失。
201 | 3.增加了onShareAppMessage的内容
202 | 203 | #### 2018年8月7日 周二 204 | 1.修复了第一次无法识别的问题,其实是我自己的代码问题- -。以后还是要好好看别人的开发手册和别人写的demo呀,然后要学会调试,看错误码。
205 | 2.语音合成并播放的时候增加了一个提示,这样听障用户就知道自己的语音已经在播放了,播放完毕时,这个提示才会消失。
206 | 3.语音合成的按钮修复了可以连续点击的bug,一直点会很鬼畜- -。所以改成了每次点击都会停止前一个语音的播放,然后开启当前的语音播放,保证每次都只有一条语音在播放。
207 | 4.之前还忽略了一个录音授权的bug,如果不写在onload里面的话,当用户点击按钮才会自动调用授权,这样子的话已经按了按钮一次了,有些值就会发生变化,所以现在加上了录音授权的```app.getRecordAuth()```,并且用户可能会按拒绝授权,这时候我也考虑到了,我在没有授权的回调函数里写了个 208 | ``` 209 | wx.showToast({ 210 | title: '录音授权失败', 211 | image:'/images/fail.png', 212 | duration:1000 213 | }) 214 | setTimeout(function () { 215 | wx.openSetting({ 216 | 217 | }) 218 | }, 1000) 219 | ``` 220 | 这样就会toast提示,然后跳转到设置界面,让用户可以点击授权(毕竟不授权录音就肯定没法识别呀)
221 | 222 | #### 2018年8月8日 周三 223 | 1.修复了文字转语音(语音合成)遇到纯字符文本时会出问题的bug。debug过程主要是根据api返回的错误码
224 | 2.从face2face的demo中偷了个component——animation-icon,就是用在正在录音时提示用户的,我觉得还挺好看哈哈,就用上了
225 | 3.增加了坐下长谈的部分,原本想着api限制的manager.start最长只能录制1分钟,但是我发现了听障者使用语音合成功能时,语音识别会自动中断,于是我就在语音合成的按钮点击事件里加上了一个识别停止,然后播放完语音,又开始识别的过程。一般比较少听障者1分钟一直不讲话一直都在听,所以就算比较好的解决这个问题了,在做这个功能模块的过程中也是遇到了不少坑的。
226 | 4.坐下长谈的部分是用了“微信同声传译”中提供的一个方法```manager.onRecognize```有新的识别内容返回,则会调用此事件 227 | ``` 228 | manager.onRecognize = function(res) { 229 | console.log("current result", res.result) 230 | } 231 | ``` 232 | 然后就是在语音识别的过程中,识别到了什么就返回什么,但是感觉这个AI在断句上还有待提高- -。感觉经常断错句哈哈
233 | 5.为了充分利用布局,并且想加个分享按钮,我把授权登陆的那块换成了,这里有个知识点,就是如果想在其他按钮上出发转发事件(而不是右上角的那个转发),就要给button加上一个```open-type="share"```,这样点击这个按钮就会触发转发事件了。如果有多个按钮想触发不同的转发文本的事件的话可以给button设置传id,然后根据res.target.id来区分 234 | 235 | ``` 236 | wxml 237 | 238 | 241 | 242 | 245 | ``` 246 | 247 | ``` 248 | js 249 | 250 | onShareAppMessage: function () { 251 | return { 252 | title: '心声Lite,用心说话', 253 | desc: '语音识别,语音合成,画板涂鸦,心声Lite — 致力于为听障者服务。', 254 | path: '/pages/index/index', 255 | imageUrl: '/images/xxs.png' 256 | } 257 | }, 258 | ``` 259 | 260 | 261 | #### 目前待添加功能: 262 | 1.快捷输入,可以将清空input框的那个按钮换成快捷输入的按钮,就是用户可以自己预设,即提前输入一些常用的句子,这样在聊天的过程中可以通过点击这个快捷输入按钮,再点击想要的预设句子,快速的输入想表达的内容。可以将该按钮设置成长按触发的按钮这样。 263 | -------------------------------------------------------------------------------- /heartSound V1.dmg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonLam0990/HeartSound/2dd0cbcd1772c929088ca565cff9d04065cb3a4c/heartSound V1.dmg -------------------------------------------------------------------------------- /heartSound V2.dmg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonLam0990/HeartSound/2dd0cbcd1772c929088ca565cff9d04065cb3a4c/heartSound V2.dmg -------------------------------------------------------------------------------- /heartSound-master V0 GITHUB.dmg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonLam0990/HeartSound/2dd0cbcd1772c929088ca565cff9d04065cb3a4c/heartSound-master V0 GITHUB.dmg -------------------------------------------------------------------------------- /heartSound/app.js: -------------------------------------------------------------------------------- 1 | //app.js 2 | App({ 3 | onLaunch: function () { 4 | // 展示本地存储能力 5 | var logs = wx.getStorageSync('logs') || [] 6 | logs.unshift(Date.now()) 7 | wx.setStorageSync('logs', logs) 8 | 9 | // 登录 10 | wx.login({ 11 | success: res => { 12 | // 发送 res.code 到后台换取 openId, sessionKey, unionId 13 | } 14 | }) 15 | // 获取用户信息 16 | wx.getSetting({ 17 | success: res => { 18 | if (res.authSetting['scope.userInfo']) { 19 | // 已经授权,可以直接调用 getUserInfo 获取头像昵称,不会弹框 20 | wx.getUserInfo({ 21 | success: res => { 22 | // 可以将 res 发送给后台解码出 unionId 23 | this.globalData.userInfo = res.userInfo 24 | 25 | // 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回 26 | // 所以此处加入 callback 以防止这种情况 27 | if (this.userInfoReadyCallback) { 28 | this.userInfoReadyCallback(res) 29 | } 30 | } 31 | }) 32 | } 33 | } 34 | }) 35 | }, 36 | // 权限询问 37 | getRecordAuth: function () { 38 | wx.getSetting({ 39 | success(res) { 40 | console.log("succ") 41 | console.log(res) 42 | if (!res.authSetting['scope.record']) { 43 | wx.authorize({ 44 | scope: 'scope.record', 45 | success() { 46 | // 用户已经同意小程序使用录音功能,后续调用 wx.startRecord 接口不会弹窗询问 47 | console.log("succ auth") 48 | }, fail() { 49 | wx.showToast({ 50 | title: '录音授权失败', 51 | image:'/images/fail.png', 52 | duration:1000 53 | }) 54 | setTimeout(function () { 55 | wx.openSetting({ 56 | 57 | }) 58 | }, 1000) 59 | console.log("fail auth") 60 | } 61 | }) 62 | } else { 63 | console.log("record has been authed") 64 | } 65 | }, fail(res) { 66 | console.log("fail") 67 | console.log(res) 68 | } 69 | }) 70 | }, 71 | onHide: function () { 72 | wx.stopBackgroundAudio() 73 | }, 74 | globalData: { 75 | userInfo: null 76 | } 77 | }) -------------------------------------------------------------------------------- /heartSound/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "pages": [ 3 | "pages/index/index", 4 | "pages/index/draw/draw", 5 | "pages/index/talk/talk", 6 | "pages/index/longtalk/longtalk", 7 | "pages/user/user", 8 | "pages/user/about/about", 9 | "pages/user/feedback/feedback" 10 | ], 11 | "window": { 12 | "backgroundTextStyle": "light", 13 | "navigationBarBackgroundColor": "#f3a09e", 14 | "navigationBarTitleText": "心声Lite", 15 | "navigationBarTextStyle": "fff" 16 | }, 17 | "tabBar": { 18 | "color": "#8a8a8a", 19 | "selectedColor": "#f3a09e", 20 | "borderStyle": "#f3a09e", 21 | "list": [ 22 | { 23 | "iconPath": "images/box_1.png", 24 | "selectedIconPath": "images/box_2.png", 25 | "pagePath": "pages/index/index", 26 | "text": "工具" 27 | }, 28 | { 29 | "iconPath": "images/user_1.png", 30 | "selectedIconPath": "images/user_2.png", 31 | "pagePath": "pages/user/user", 32 | "text": "我的" 33 | } 34 | ] 35 | }, 36 | "plugins": { 37 | "WechatSI": { 38 | "version": "0.1.0", 39 | "provider": "wx069ba97219f66d99" 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /heartSound/app.wxss: -------------------------------------------------------------------------------- 1 | /**app.wxss**/ 2 | .container { 3 | font-size: 60rpx; 4 | display: flex; 5 | flex-direction: column; 6 | width: 100%; 7 | height: 100%; 8 | background: #f0f0f0; 9 | color: #515151; 10 | position: fixed; 11 | top: 0; 12 | left: 0; 13 | right: 0; 14 | bottom: 0; 15 | } 16 | 17 | .section{ 18 | height: 1%; 19 | width: 100%; 20 | background: #999999; 21 | } 22 | 23 | -------------------------------------------------------------------------------- /heartSound/components/waiting-icon/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | Tencent is pleased to support the open source community by making Face-2-Face Translator available. 3 | 4 | Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. 5 | 6 | Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at 7 | http://opensource.org/licenses/MIT 8 | 9 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. 10 | */ 11 | 12 | Component({ 13 | 14 | properties: { 15 | 16 | }, 17 | 18 | data: { 19 | waiting_animation: {}, 20 | waiting_animation_1: {}, 21 | }, 22 | 23 | ready: function () { 24 | console.log("ready waitting") 25 | this.waiting_animation = wx.createAnimation({ 26 | duration: 600 27 | }) 28 | this.waiting_animation_1 = wx.createAnimation({ 29 | duration: 400 30 | }) 31 | 32 | this.setWaitInterval() 33 | 34 | }, 35 | 36 | // 组件生命周期函数,在组件实例被从页面节点树移除时执行 37 | detached: function() { 38 | this.clearAnimation() 39 | }, 40 | 41 | methods: { 42 | 43 | clearAnimation: function() { 44 | this.endWaitAnimation() 45 | }, 46 | 47 | /** 48 | * 清除动画 49 | */ 50 | endWaitAnimation: function() { 51 | clearInterval(this.data.waiting_interval) 52 | 53 | this.setData({ waiting_animation : {}}) 54 | this.setData({ waiting_animation_1: {} }) 55 | }, 56 | startWaitAnimation: function () { 57 | 58 | this.waiting_animation.opacity(0).scale(1.2, 1.2).step() 59 | this.waiting_animation.opacity(1).scale(1, 1).step() 60 | this.setData({ waiting_animation: this.waiting_animation.export() }) 61 | 62 | this.waiting_animation_1.opacity(0).scale(1.2, 1.2).step() 63 | this.waiting_animation_1.opacity(1).scale(1, 1).step() 64 | this.setData({ waiting_animation_1: this.waiting_animation_1.export() }) 65 | 66 | }, 67 | 68 | /** 69 | * 设置动画 70 | */ 71 | setWaitInterval: function() { 72 | this.endWaitAnimation() 73 | 74 | this.data.waiting_interval = setInterval( ()=>{ 75 | this.startWaitAnimation() 76 | },600 ) 77 | 78 | }, 79 | 80 | 81 | } 82 | }); -------------------------------------------------------------------------------- /heartSound/components/waiting-icon/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true 3 | } 4 | -------------------------------------------------------------------------------- /heartSound/components/waiting-icon/index.wxml: -------------------------------------------------------------------------------- 1 | 2 | . 3 | . 4 | . 5 | -------------------------------------------------------------------------------- /heartSound/components/waiting-icon/index.wxss: -------------------------------------------------------------------------------- 1 | 2 | .loading { 3 | position: relative; 4 | display: inline; 5 | } 6 | 7 | .loading-icon { 8 | display: inline; 9 | } 10 | -------------------------------------------------------------------------------- /heartSound/images/about.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonLam0990/HeartSound/2dd0cbcd1772c929088ca565cff9d04065cb3a4c/heartSound/images/about.png -------------------------------------------------------------------------------- /heartSound/images/back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonLam0990/HeartSound/2dd0cbcd1772c929088ca565cff9d04065cb3a4c/heartSound/images/back.png -------------------------------------------------------------------------------- /heartSound/images/begin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonLam0990/HeartSound/2dd0cbcd1772c929088ca565cff9d04065cb3a4c/heartSound/images/begin.png -------------------------------------------------------------------------------- /heartSound/images/box_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonLam0990/HeartSound/2dd0cbcd1772c929088ca565cff9d04065cb3a4c/heartSound/images/box_1.png -------------------------------------------------------------------------------- /heartSound/images/box_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonLam0990/HeartSound/2dd0cbcd1772c929088ca565cff9d04065cb3a4c/heartSound/images/box_2.png -------------------------------------------------------------------------------- /heartSound/images/button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonLam0990/HeartSound/2dd0cbcd1772c929088ca565cff9d04065cb3a4c/heartSound/images/button.png -------------------------------------------------------------------------------- /heartSound/images/dele-blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonLam0990/HeartSound/2dd0cbcd1772c929088ca565cff9d04065cb3a4c/heartSound/images/dele-blue.png -------------------------------------------------------------------------------- /heartSound/images/dele-pink.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonLam0990/HeartSound/2dd0cbcd1772c929088ca565cff9d04065cb3a4c/heartSound/images/dele-pink.png -------------------------------------------------------------------------------- /heartSound/images/dele.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonLam0990/HeartSound/2dd0cbcd1772c929088ca565cff9d04065cb3a4c/heartSound/images/dele.png -------------------------------------------------------------------------------- /heartSound/images/enter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonLam0990/HeartSound/2dd0cbcd1772c929088ca565cff9d04065cb3a4c/heartSound/images/enter.png -------------------------------------------------------------------------------- /heartSound/images/fail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonLam0990/HeartSound/2dd0cbcd1772c929088ca565cff9d04065cb3a4c/heartSound/images/fail.png -------------------------------------------------------------------------------- /heartSound/images/hbty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonLam0990/HeartSound/2dd0cbcd1772c929088ca565cff9d04065cb3a4c/heartSound/images/hbty.png -------------------------------------------------------------------------------- /heartSound/images/issue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonLam0990/HeartSound/2dd0cbcd1772c929088ca565cff9d04065cb3a4c/heartSound/images/issue.png -------------------------------------------------------------------------------- /heartSound/images/microphone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonLam0990/HeartSound/2dd0cbcd1772c929088ca565cff9d04065cb3a4c/heartSound/images/microphone.png -------------------------------------------------------------------------------- /heartSound/images/rotate-blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonLam0990/HeartSound/2dd0cbcd1772c929088ca565cff9d04065cb3a4c/heartSound/images/rotate-blue.png -------------------------------------------------------------------------------- /heartSound/images/rotate-pink.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonLam0990/HeartSound/2dd0cbcd1772c929088ca565cff9d04065cb3a4c/heartSound/images/rotate-pink.png -------------------------------------------------------------------------------- /heartSound/images/speak.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonLam0990/HeartSound/2dd0cbcd1772c929088ca565cff9d04065cb3a4c/heartSound/images/speak.png -------------------------------------------------------------------------------- /heartSound/images/stop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonLam0990/HeartSound/2dd0cbcd1772c929088ca565cff9d04065cb3a4c/heartSound/images/stop.png -------------------------------------------------------------------------------- /heartSound/images/tips.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonLam0990/HeartSound/2dd0cbcd1772c929088ca565cff9d04065cb3a4c/heartSound/images/tips.png -------------------------------------------------------------------------------- /heartSound/images/triangleLeft.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonLam0990/HeartSound/2dd0cbcd1772c929088ca565cff9d04065cb3a4c/heartSound/images/triangleLeft.png -------------------------------------------------------------------------------- /heartSound/images/triangleRight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonLam0990/HeartSound/2dd0cbcd1772c929088ca565cff9d04065cb3a4c/heartSound/images/triangleRight.png -------------------------------------------------------------------------------- /heartSound/images/user_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonLam0990/HeartSound/2dd0cbcd1772c929088ca565cff9d04065cb3a4c/heartSound/images/user_1.png -------------------------------------------------------------------------------- /heartSound/images/user_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonLam0990/HeartSound/2dd0cbcd1772c929088ca565cff9d04065cb3a4c/heartSound/images/user_2.png -------------------------------------------------------------------------------- /heartSound/images/xljj.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonLam0990/HeartSound/2dd0cbcd1772c929088ca565cff9d04065cb3a4c/heartSound/images/xljj.png -------------------------------------------------------------------------------- /heartSound/images/xxs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonLam0990/HeartSound/2dd0cbcd1772c929088ca565cff9d04065cb3a4c/heartSound/images/xxs.png -------------------------------------------------------------------------------- /heartSound/images/zxct.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonLam0990/HeartSound/2dd0cbcd1772c929088ca565cff9d04065cb3a4c/heartSound/images/zxct.png -------------------------------------------------------------------------------- /heartSound/pages/index/draw/draw.js: -------------------------------------------------------------------------------- 1 | let ctx; 2 | Page({ 3 | data: { 4 | isrotate:false, 5 | tempFilePath:'', 6 | pen: { 7 | lineWidth: 5, 8 | color: "#2c2c2c" 9 | } 10 | }, 11 | onShareAppMessage: function () { 12 | return { 13 | title: '心声Lite,用画笔说话', 14 | path: '/pages/index/draw/draw', 15 | imageUrl: '/images/xxs.png' 16 | } 17 | }, 18 | onLoad(options) { 19 | ctx = wx.createCanvasContext('myCanvas'); 20 | ctx.setStrokeStyle(this.data.pen.color); 21 | ctx.setLineWidth(this.data.pen.lineWidth); 22 | ctx.setLineCap('round'); 23 | ctx.setLineJoin('round'); 24 | }, 25 | touchstart(e) { 26 | ctx.setStrokeStyle(this.data.pen.color); 27 | ctx.setLineWidth(this.data.pen.lineWidth); 28 | ctx.moveTo(e.touches[0].x, e.touches[0].y); 29 | }, 30 | touchmove(e) { 31 | let x = e.touches[0].x; 32 | let y = e.touches[0].y; 33 | ctx.lineTo(x, y) 34 | ctx.stroke(); 35 | ctx.draw(true); 36 | ctx.moveTo(x, y) 37 | }, 38 | dele: function () { 39 | ctx.setFillStyle('#ffffff') 40 | ctx.fillRect(0, 0, 750, 1000) 41 | ctx.draw() 42 | }, 43 | rotate: function () { 44 | wx.showToast({ 45 | title: '旋转功能开发中', 46 | image: '/images/fail.png', 47 | duration: 1000, 48 | mask: true, 49 | }) 50 | }, 51 | }) 52 | -------------------------------------------------------------------------------- /heartSound/pages/index/draw/draw.json: -------------------------------------------------------------------------------- 1 | { 2 | "navigationBarTitleText": "画板涂鸦" 3 | } -------------------------------------------------------------------------------- /heartSound/pages/index/draw/draw.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /heartSound/pages/index/draw/draw.wxss: -------------------------------------------------------------------------------- 1 | 2 | page{ 3 | width: 100%; 4 | height: 100%; 5 | background: #ffffff 6 | } 7 | 8 | .canvas-area{ 9 | margin-top: 15%; 10 | width:750rpx; 11 | height: 80%; 12 | background: #ffffff 13 | } 14 | .myCanvas{ 15 | width: 100%; 16 | height: 100%; 17 | } 18 | .canvas-tools-you{ 19 | position: fixed; 20 | top: 0; 21 | height: 10%; 22 | width: 100%; 23 | display: flex; 24 | justify-content: center; 25 | align-items: center; 26 | } 27 | .canvas-tools-me{ 28 | position: fixed; 29 | bottom: 0; 30 | height: 10%; 31 | width: 100%; 32 | display: flex; 33 | justify-content: center; 34 | align-items: center; 35 | } 36 | .icon-box{ 37 | width: 350rpx; 38 | } 39 | .icon{ 40 | height: 70rpx; 41 | width: 70rpx; 42 | margin-left: 70rpx; 43 | } -------------------------------------------------------------------------------- /heartSound/pages/index/index.js: -------------------------------------------------------------------------------- 1 | //index.js 2 | //获取应用实例 3 | const app = getApp() 4 | 5 | Page({ 6 | data: { 7 | 8 | }, 9 | onShareAppMessage: function () { 10 | return { 11 | title: '心声Lite,用心说话', 12 | desc: '语音识别,语音合成,画板涂鸦,心声Lite — 致力于为听障者服务。', 13 | path: '/pages/index/index', 14 | imageUrl:'/images/xxs.png' 15 | } 16 | }, 17 | //事件处理函数 18 | gotoSmallTalk: function() { 19 | wx.navigateTo({ 20 | url: '/pages/index/talk/talk' 21 | }) 22 | }, 23 | gotoLongTalk: function () { 24 | wx.navigateTo({ 25 | url: '/pages/index/longtalk/longtalk' 26 | }) 27 | }, 28 | gotoDraw: function () { 29 | wx.navigateTo({ 30 | url: '/pages/index/draw/draw' 31 | }) 32 | }, 33 | onLoad(){ 34 | } 35 | }) 36 | -------------------------------------------------------------------------------- /heartSound/pages/index/index.json: -------------------------------------------------------------------------------- 1 | { 2 | 3 | } -------------------------------------------------------------------------------- /heartSound/pages/index/index.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /heartSound/pages/index/index.wxss: -------------------------------------------------------------------------------- 1 | /**index.wxss**/ 2 | 3 | .box{ 4 | display: flex; 5 | justify-content: center; 6 | align-items: center; 7 | height: 50%; 8 | width: 100%; 9 | } 10 | 11 | .icon-button{ 12 | height: 300rpx; 13 | width: 300rpx; 14 | } -------------------------------------------------------------------------------- /heartSound/pages/index/longtalk/longtalk.js: -------------------------------------------------------------------------------- 1 | const app = getApp() 2 | 3 | var plugin = requirePlugin("WechatSI") 4 | let manager = plugin.getRecordRecognitionManager() 5 | const innerAudioContext = wx.createInnerAudioContext() 6 | 7 | Page({ 8 | data: { 9 | recording:false, 10 | scrollTop: 10000, 11 | content:[ 12 | { 13 | 'content':'可用于和别人较长时间的交谈,请对方戴上耳机交谈会更加方便,识别也更加清晰。', 14 | 'person':'me' 15 | } 16 | ], 17 | ison:false, 18 | now:'me', 19 | content_now:'', 20 | content_temp:'', 21 | addinput: '',//清楚input框的值 22 | }, 23 | initRecord: function () { 24 | var that = this 25 | 26 | manager.onStart = (res) => { 27 | 28 | } 29 | 30 | manager.onRecognize = (res) => { 31 | var content_temp = that.data.content_temp 32 | if (content_temp == res.result){ 33 | 34 | }else{ 35 | var array = [] 36 | array = that.data.content 37 | console.log(array) 38 | 39 | var a = content_temp 40 | var b = res.result 41 | var text = b.slice(a.length, b.length) 42 | 43 | var temp = { 44 | 'content': text, 45 | 'person': 'you' 46 | } 47 | array.push(temp) 48 | console.log(array) 49 | that.setData({ 50 | content: array, 51 | content_temp: res.result, 52 | scrollTop: that.data.scrollTop + 100 53 | }) 54 | } 55 | } 56 | 57 | // 识别结束事件 58 | manager.onStop = (res) => { 59 | 60 | } 61 | }, 62 | 63 | onLoad: function (options) { 64 | this.initRecord() 65 | app.getRecordAuth() 66 | }, 67 | 68 | touchdown_plugin: function() { 69 | var that = this 70 | if(that.data.recording){ 71 | manager.stop() 72 | 73 | wx.showToast({ 74 | title: '停止识别', 75 | image: '/images/stop.png', 76 | duration: 800 77 | }) 78 | 79 | that.setData({ 80 | recording: false 81 | }) 82 | 83 | }else{ 84 | wx.stopBackgroundAudio(); 85 | 86 | manager.start({ 87 | lang: "zh_CN" 88 | }) 89 | wx.showToast({ 90 | title: '开始识别', 91 | image:'/images/begin.png', 92 | duration:800 93 | }) 94 | that.setData({ 95 | recording: true 96 | }) 97 | } 98 | }, 99 | 100 | listenInput: function (e) { 101 | var content = e.detail.value 102 | this.setData({ 103 | content_now: content 104 | }) 105 | console.log(e.detail.value) 106 | }, 107 | 108 | // 清空输入框的内容 109 | dele: function (e) { 110 | this.setData({ 111 | content_down: '', 112 | input: '' 113 | }) 114 | }, 115 | 116 | // 文字转语音(语音合成) 117 | wordtospeak: function (e) { 118 | let flag = 0 119 | if (this.data.recording){ 120 | manager.stop 121 | flag = 1 122 | } 123 | 124 | if (e.currentTarget.dataset.content == '') { 125 | wx.showToast({ 126 | title: '请勿发空消息', 127 | image: '/images/fail.png', 128 | }) 129 | } else if (/[@\/'\\"#$%&\^*]/.test(e.currentTarget.dataset.content)){ 130 | wx.showToast({ 131 | title:'有非法字符', 132 | image:'/images/fail.png' 133 | }) 134 | }else{ 135 | // 将wxml中传过来的文本内容存起来,用api传给插件 136 | var content = e.currentTarget.dataset.content 137 | 138 | var that = this 139 | 140 | plugin.textToSpeech({ 141 | lang: "zh_CN", 142 | tts: true, 143 | content: content, 144 | success: function (res) { 145 | console.log(" tts", res) 146 | innerAudioContext.autoplay = true 147 | innerAudioContext.src = res.filename 148 | innerAudioContext.onPlay(() => { 149 | console.log('开始播放') 150 | }) 151 | 152 | wx.showLoading({ 153 | title: '正在播放', 154 | }) 155 | 156 | innerAudioContext.onError((res) => { 157 | if(res){ 158 | wx.hideLoading(), 159 | wx.showToast({ 160 | title: '文本格式错误', 161 | image: '/images/fail.png', 162 | }) 163 | } 164 | }) 165 | 166 | innerAudioContext.onEnded(function () { 167 | wx.stopBackgroundAudio(); 168 | 169 | manager.start({ 170 | lang: "zh_CN" 171 | }) 172 | 173 | setTimeout(function () { 174 | wx.hideLoading() 175 | }, 300) 176 | 177 | that.setData({ 178 | content_temp: '' 179 | }) 180 | }) 181 | }, 182 | fail: function (res) { 183 | console.log("fail tts", res) 184 | 185 | } 186 | }) 187 | 188 | var array = [] 189 | array = this.data.content 190 | var temp = { 191 | 'content': e.currentTarget.dataset.content, 192 | 'person' : 'me' 193 | } 194 | array.push(temp) 195 | console.log(array) 196 | that.setData({ 197 | content:array, 198 | scrollTop:that.data.scrollTop + 100 199 | }) 200 | } 201 | }, 202 | 203 | onUnload: function () { 204 | manager.stop() 205 | }, 206 | }) -------------------------------------------------------------------------------- /heartSound/pages/index/longtalk/longtalk.json: -------------------------------------------------------------------------------- 1 | { 2 | "navigationBarTitleText": "坐下长谈", 3 | "usingComponents": { 4 | "waiting-icon": "/components/waiting-icon/index" 5 | } 6 | } -------------------------------------------------------------------------------- /heartSound/pages/index/longtalk/longtalk.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 开始识别 7 | 8 | 9 | 正在识别 10 | 11 | 12 | 13 | 33 | 34 |
35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 |
47 | 48 |
49 | -------------------------------------------------------------------------------- /heartSound/pages/index/longtalk/longtalk.wxss: -------------------------------------------------------------------------------- 1 | /* pages/commom/personChat/personChat.wxss */ 2 | .top-bar{ 3 | height: 100rpx; 4 | background: #515151; 5 | width: 100%; 6 | display: flex; 7 | align-items: center; 8 | justify-content: center; 9 | } 10 | .start-button{ 11 | font-size: 40rpx; 12 | color: #fff; 13 | } 14 | .waiting-icon{ 15 | position: relative; 16 | left: 10rpx; 17 | bottom: 10rpx; 18 | } 19 | 20 | .container{ 21 | background: #ffffff; 22 | color: #fff; 23 | font-size: 55rpx; 24 | padding-bottom: 20%; 25 | } 26 | .container { 27 | height: 100%; 28 | width: 100%; 29 | flex-direction: column; 30 | } 31 | .container { 32 | display: flex; 33 | display:-webkit-flex; 34 | box-sizing: border-box; 35 | } 36 | .placeholder{ 37 | color: #999; 38 | } 39 | /*聊天盒子*/ 40 | .scrollwechat { 41 | flex: 1; 42 | display: flex; 43 | flex-direction: column; 44 | overflow: hidden; 45 | height: 100%; 46 | padding-top: 10rpx; 47 | } 48 | .scrollview{ 49 | height: 100%; 50 | 51 | } 52 | .scrollwechat li { 53 | width: 100%; 54 | display: flex; 55 | margin-top: 20rpx; 56 | } 57 | 58 | .container .user { 59 | flex-direction: row; 60 | } 61 | 62 | .container .sys{ 63 | flex-direction: row-reverse; 64 | } 65 | 66 | .input-layer{ 67 | height: 10%; 68 | width: 100%; 69 | position: fixed; 70 | bottom: 0; 71 | background: blue; 72 | } 73 | .input-panel { 74 | height: 100%; 75 | padding: 0 15rpx 0 15rpx; 76 | background: #f0f0f0; 77 | box-sizing: border-box; 78 | display: flex; 79 | align-items: center; 80 | } 81 | input{ 82 | color: #515151; 83 | } 84 | .send-input { 85 | font-size: 38rpx; 86 | flex: 1; 87 | height: 95rpx; 88 | background: #fff; 89 | border:#ddd 1rpx solid; 90 | border-radius: 10rpx; 91 | box-sizing: border-box; 92 | padding: 0 10rpx; 93 | } 94 | .send-btn { 95 | display: flex; 96 | justify-content: center; 97 | align-items: center; 98 | width: 120rpx; 99 | height: 80rpx; 100 | line-height: 75rpx; 101 | background-color: #474646; 102 | font-size: 32rpx; 103 | color:#fff; 104 | border-radius: 10rpx; 105 | margin-left: 15rpx; 106 | } 107 | .send-btn:active{ 108 | opacity: .7; 109 | } 110 | .icon{ 111 | height: 40rpx; 112 | width: 40rpx; 113 | } 114 | 115 | .me-box{ 116 | margin: 20rpx; 117 | margin-left: 180rpx; 118 | } 119 | .me{ 120 | padding: 20rpx; 121 | border: 5rpx solid #7aa0cb; 122 | } 123 | .you{ 124 | padding: 20rpx; 125 | margin: 20rpx; 126 | margin-left: 180rpx; 127 | border: 5rpx solid #7aa0cb; 128 | } 129 | 130 | 131 | .triangle image{ 132 | width: 20rpx; 133 | height: 80rpx; 134 | } 135 | .textview1 { 136 | width:70%; 137 | border-radius: 10rpx; 138 | background: #7aa0cb; 139 | padding: 20rpx; 140 | } 141 | .textview2 { 142 | width:70%; 143 | background: #f3a09e; 144 | border-radius: 10rpx; 145 | padding: 20rpx; 146 | } 147 | .link{ 148 | height: 150rpx; 149 | } 150 | -------------------------------------------------------------------------------- /heartSound/pages/index/talk/talk.js: -------------------------------------------------------------------------------- 1 | // pages/talk/talk.js 2 | 3 | // 引入插件 4 | const app = getApp() 5 | 6 | var plugin = requirePlugin("WechatSI") 7 | let manager = plugin.getRecordRecognitionManager() 8 | const innerAudioContext = wx.createInnerAudioContext() 9 | 10 | Page({ 11 | 12 | /** 13 | * 页面的初始数据 14 | */ 15 | data: { 16 | shownull:false, 17 | showmicro: false, 18 | input: '', 19 | content_up: '', 20 | content_down: '你好,我听力不好,你可以按住底部的按钮,对我说普通话' 21 | }, 22 | 23 | initRecord: function () { 24 | var that = this 25 | manager.onStart = (res) => { 26 | that.setData({ 27 | showmicro:true 28 | }) 29 | } 30 | 31 | // 识别结束事件 32 | manager.onStop = (res) => { 33 | var that = this 34 | let text = res.result 35 | 36 | if (text == '') { 37 | this.setData({ 38 | shownull: true 39 | }) 40 | setTimeout(function () { 41 | that.setData({ 42 | shownull: false 43 | }) 44 | }, 500) 45 | } 46 | 47 | this.setData({ 48 | content_up: text, 49 | showmicro: false 50 | }) 51 | } 52 | 53 | }, 54 | //监听字的输入,实时显示在屏幕,并且content_down还会用在文字转语音(语音合成)上。 55 | listenInput: function (e) { 56 | var content = e.detail.value 57 | if (content == '') { 58 | content = '你好,我听力不好,你可以按住底部的按钮,对我说普通话' 59 | } 60 | this.setData({ 61 | content_down: content 62 | }) 63 | }, 64 | 65 | // 清空输入框的内容 66 | dele: function (e) { 67 | this.setData({ 68 | content_down: '', 69 | input: '' 70 | }) 71 | }, 72 | 73 | // 插件使用重要步骤!! 74 | 75 | //手指按下 76 | touchdown_plugin: function (e) { 77 | wx.stopBackgroundAudio(); 78 | 79 | manager.start({ 80 | lang: "zh_CN" 81 | }) 82 | }, 83 | //手指松开 84 | touchup_plugin: function () { 85 | 86 | manager.stop(); 87 | }, 88 | 89 | // 文字转语音(语音合成) 90 | wordtospeak: function (e) { 91 | var that = this 92 | 93 | var content = e.currentTarget.dataset.content 94 | 95 | if (content==''){ 96 | wx.showToast({ 97 | title: '请输入文字', 98 | image: '/images/fail.png', 99 | }) 100 | } 101 | 102 | plugin.textToSpeech({ 103 | lang: "zh_CN", 104 | tts: true, 105 | content: content, 106 | success: function (res) { 107 | innerAudioContext.autoplay = true 108 | innerAudioContext.src = res.filename 109 | innerAudioContext.onPlay(() => { 110 | console.log('开始播放') 111 | }) 112 | 113 | wx.showLoading({ 114 | title: '正在播放', 115 | }) 116 | 117 | innerAudioContext.onError((res) => { 118 | if (res) { 119 | wx.hideLoading(), 120 | wx.showToast({ 121 | title: '文本格式错误', 122 | image: '/images/fail.png', 123 | }) 124 | } 125 | }) 126 | 127 | innerAudioContext.onEnded(function(){ 128 | wx.hideLoading() 129 | }) 130 | console.log("succ tts", res.filename) 131 | }, 132 | fail: function (res) { 133 | console.log("fail tts", res) 134 | }, 135 | }) 136 | }, 137 | 138 | 139 | /** 140 | * 用户点击右上角分享 141 | */ 142 | onShareAppMessage: function () { 143 | return { 144 | title: '心声Lite,让爱发声', 145 | path: '/pages/index/talk/talk', 146 | imageUrl: '/images/xxs.png' 147 | } 148 | }, 149 | onLoad: function (){ 150 | this.initRecord() 151 | app.getRecordAuth() 152 | }, 153 | }) -------------------------------------------------------------------------------- /heartSound/pages/index/talk/talk.json: -------------------------------------------------------------------------------- 1 | { 2 | "navigationBarTitleText": "小聊几句", 3 | "usingComponents": { 4 | "waiting-icon": "/components/waiting-icon/index" 5 | } 6 | } -------------------------------------------------------------------------------- /heartSound/pages/index/talk/talk.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | {{content_up}} 9 | 10 | 11 | 12 | 13 | {{content_down}} 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 31 | 32 | 33 | 正在识别 34 | 35 | 36 | 37 | 38 | 请说话 39 | 40 | -------------------------------------------------------------------------------- /heartSound/pages/index/talk/talk.wxss: -------------------------------------------------------------------------------- 1 | /* pages/talk/talk.wxss */ 2 | 3 | .button-layer{ 4 | display: flex; 5 | justify-content: center; 6 | align-items: center; 7 | padding-top: 15rpx; 8 | height: 20%; 9 | width: 100%; 10 | background: #f0f0f0; 11 | } 12 | .showme-layer{ 13 | height: 35%; 14 | width: 100%; 15 | background: #ffffff; 16 | } 17 | .content-box-showme{ 18 | height: 100%; 19 | line-height: 1.5; 20 | padding: 20rpx 20rpx 0 30rpx; 21 | box-sizing: border-box; 22 | border-bottom: 1px solid #e5e5e5; 23 | } 24 | .content-box-showyou{ 25 | height: 100%; 26 | line-height: 1.5; 27 | padding: 20rpx 20rpx 0 30rpx; 28 | box-sizing: border-box; 29 | border-bottom: 1px solid #e5e5e5; 30 | transform: scaleY(-1); 31 | } 32 | .showyou-layer{ 33 | height: 35%; 34 | width: 100%; 35 | background: #ffffff; 36 | transform: scaleX(-1); 37 | } 38 | .input-layer{ 39 | height: 10%; 40 | width: 100%; 41 | position: fixed; 42 | bottom: 0; 43 | background: blue; 44 | } 45 | 46 | .speak-button{ 47 | height: 220rpx; 48 | width: 220rpx; 49 | margin-bottom: 20rpx; 50 | } 51 | .speak-button:active{ 52 | opacity: .7; 53 | } 54 | .tips{ 55 | position: absolute; 56 | width: 400rpx; 57 | height: 200rpx; 58 | left: 175rpx; 59 | top: 320rpx; 60 | } 61 | .input-panel { 62 | height: 100%; 63 | padding: 0 15rpx 0 15rpx; 64 | background: #f0f0f0; 65 | box-sizing: border-box; 66 | display: flex; 67 | align-items: center; 68 | } 69 | .send-input { 70 | font-size: 38rpx; 71 | flex: 1; 72 | height: 95rpx; 73 | background: #fff; 74 | border:#ddd 1rpx solid; 75 | border-radius: 10rpx; 76 | box-sizing: border-box; 77 | padding: 0 10rpx; 78 | } 79 | .send-btn { 80 | display: flex; 81 | justify-content: center; 82 | align-items: center; 83 | width: 120rpx; 84 | height: 80rpx; 85 | line-height: 75rpx; 86 | background-color: #474646; 87 | font-size: 32rpx; 88 | color:#fff; 89 | border-radius: 10rpx; 90 | margin-left: 15rpx; 91 | } 92 | .send-btn:active{ 93 | opacity: .7; 94 | } 95 | .icon{ 96 | height: 40rpx; 97 | width: 40rpx; 98 | } 99 | 100 | .toast{ 101 | background: rgba(0,0,0, 0.7); 102 | color: #fff; 103 | display: flex; 104 | align-items: center; 105 | height: 130rpx; 106 | width: 300rpx; 107 | padding: 20rpx; 108 | border-radius: 20rpx; 109 | position: fixed; 110 | top: 340rpx; 111 | left: 225rpx; 112 | } 113 | .toast text{ 114 | font-size: 36rpx; 115 | } 116 | .waiting-icon{ 117 | position: relative; 118 | left: 10rpx; 119 | bottom: 15rpx; 120 | } 121 | .microphone{ 122 | height: 80rpx; 123 | width: 80rpx; 124 | } 125 | .warning{ 126 | height: 80rpx; 127 | width: 80rpx; 128 | margin-left: 20rpx; 129 | } 130 | .warning-text{ 131 | margin-left: 20rpx; 132 | } -------------------------------------------------------------------------------- /heartSound/pages/user/about/about.js: -------------------------------------------------------------------------------- 1 | //about.js 2 | //获取应用实例 3 | var app = getApp(); 4 | Page({ 5 | data: { 6 | 7 | }, 8 | onLoad: function () { 9 | 10 | }, 11 | }); -------------------------------------------------------------------------------- /heartSound/pages/user/about/about.json: -------------------------------------------------------------------------------- 1 | { 2 | "navigationBarTitleText": "关于", 3 | "enablePullDownRefresh": false 4 | } -------------------------------------------------------------------------------- /heartSound/pages/user/about/about.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 心声Lite 7 | 公益项目 8 | 9 | 10 | 11 | 简介 12 | 13 | 14 | 15 | 16 | 简介 17 | 我们的身边有很多听障者,他们或许来到这个世界就未曾听到过任何欢声笑语。或者被忽然降临的疾病夺去了本该属于他们的平凡人的生活。 18 | 心声Lite是一款帮助听障者与普通人交流的微信小程序,希望能用微薄的力量,给予他们一点便利。 19 | 语音识别,使得街头路人可以告诉他们车站在何方 20 | 语音合成,可以帮他们向爸爸妈妈说一声“爸妈,让你们受累了”。 21 | 心声Lite,只为让世界多一点温暖 22 | 23 | 24 | 心声Lite诚挚的欢迎各大公众号关联小程序,并期待与您的合作。AppID:wxfb65ccf6436cd4f6 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /heartSound/pages/user/about/about.wxss: -------------------------------------------------------------------------------- 1 | /**about.wxss**/ 2 | /* pages/user/feedback/feedback.wxss */ 3 | 4 | .version{ 5 | height: 100rpx; 6 | background: #fff; 7 | display: flex; 8 | align-items: center; 9 | padding: 0 45rpx; 10 | box-sizing: border-box; 11 | font-size: 13pt; 12 | color: #666; 13 | border-bottom: 1px #e5e5e5 solid; 14 | } 15 | .version-title{ 16 | flex: 1; 17 | display: flex; 18 | align-items: center; 19 | } 20 | .title-name{ 21 | padding-right: 10rpx; 22 | } 23 | .version-text{ 24 | font-size: 10pt; 25 | line-height: 100%; 26 | color: #7acfa6; 27 | border: 1px solid #7acfa6; 28 | padding: 5rpx 10rpx; 29 | border-radius: 5rpx; 30 | margin-left: 10rpx; 31 | text-align: center; 32 | } 33 | .version-log-link{ 34 | position: relative; 35 | font-size: 12pt; 36 | color: #7acfa6; 37 | } 38 | .version-log-link:active{ 39 | opacity: .8; 40 | } 41 | .update-log::after{ 42 | content: ''; 43 | position: absolute; 44 | right: -3px; 45 | top: -1px; 46 | width: 5px; 47 | height: 5px; 48 | border-radius: 50%; 49 | background: #e55c5c; 50 | } 51 | 52 | .container{ 53 | background: #f4f4f4; 54 | padding: 0; 55 | font-size: 11pt; 56 | } 57 | .header{ 58 | position: relative; 59 | width: 100%; 60 | height: 400rpx; 61 | text-align: center; 62 | box-sizing: border-box; 63 | overflow: hidden; 64 | display: flex; 65 | align-items: center; 66 | justify-content: center; 67 | } 68 | .header .title{ 69 | position: relative; 70 | width: 600rpx; 71 | height: 200rpx; 72 | z-index: 3; 73 | opacity: .95; 74 | } 75 | .black-cover{ 76 | position: absolute; 77 | z-index: 2; 78 | top:0; 79 | left: 0; 80 | width: 100%; 81 | height: 100%; 82 | background: #888; 83 | opacity: .18; 84 | } 85 | .logo{ 86 | position: absolute; 87 | top:0; 88 | left: 0; 89 | z-index: 1; 90 | width: 100%; 91 | height: 750rpx; 92 | border-radius: 10rpx; 93 | margin-top: -175rpx; 94 | filter: blur(15px); 95 | } 96 | .content{ 97 | height: 80%; 98 | flex: 1; 99 | } 100 | .version{ 101 | height: 100rpx; 102 | background: #fff; 103 | display: flex; 104 | align-items: center; 105 | padding: 0 45rpx; 106 | box-sizing: border-box; 107 | font-size: 13pt; 108 | color: #666; 109 | border-bottom: 1px #e5e5e5 solid; 110 | } 111 | .version-title{ 112 | flex: 1; 113 | display: flex; 114 | align-items: center; 115 | } 116 | .title-name{ 117 | padding-right: 10rpx; 118 | } 119 | .version-text{ 120 | font-size: 10pt; 121 | line-height: 100%; 122 | color: #7acfa6; 123 | border: 1px solid #7acfa6; 124 | padding: 5rpx 10rpx; 125 | border-radius: 5rpx; 126 | margin-left: 10rpx; 127 | text-align: center; 128 | } 129 | .version-log-link{ 130 | position: relative; 131 | font-size: 12pt; 132 | color: #7acfa6; 133 | } 134 | .version-log-link:active{ 135 | opacity: .8; 136 | } 137 | .update-log::after{ 138 | content: ''; 139 | position: absolute; 140 | right: -3px; 141 | top: -1px; 142 | width: 5px; 143 | height: 5px; 144 | border-radius: 50%; 145 | background: #e55c5c; 146 | } 147 | .log-list{ 148 | display: flex; 149 | flex-direction: column; 150 | align-items: stretch; 151 | } 152 | .describe{ 153 | width: 100%; 154 | box-sizing: border-box; 155 | padding: 20rpx 45rpx 30rpx; 156 | display: flex; 157 | flex-flow: column wrap; 158 | color: #545454; 159 | line-height: 175%; 160 | background: #fff; 161 | margin-top: 15rpx; 162 | border-top: 1px #e5e5e5 solid; 163 | border-bottom: 1px #e5e5e5 solid; 164 | } 165 | .desc-title{ 166 | display: flex; 167 | font-size: 13pt; 168 | line-height: 200%; 169 | margin-bottom: 15rpx; 170 | } 171 | .desc-v{ 172 | flex: 1; 173 | } 174 | .desc-time{ 175 | font-size: 11pt; 176 | color: #888; 177 | } 178 | .desc-list{ 179 | display: flex; 180 | flex-direction: column; 181 | border-left: 8rpx solid #ddd; 182 | padding-left: 15rpx; 183 | color: #777; 184 | margin-bottom: 15rpx; 185 | font-size: 30rpx; 186 | } 187 | 188 | .desc-content{ 189 | padding-bottom: 15rpx; 190 | } 191 | .footer{ 192 | display: flex; 193 | flex-direction: column; 194 | font-size: 9pt; 195 | line-height: 150%; 196 | text-align: center; 197 | padding: 100rpx 0 15rpx; 198 | color: #c2c2c2; 199 | } 200 | .footer-lanshan{ 201 | font-size: 10pt; 202 | height: 10pt; 203 | line-height: 10pt; 204 | display: flex; 205 | align-items: center; 206 | justify-content: center; 207 | margin-bottom: 8rpx; 208 | } 209 | .footer-lanshan image{ 210 | width: 10pt; 211 | height: 10pt; 212 | margin-right: 5rpx; 213 | } 214 | -------------------------------------------------------------------------------- /heartSound/pages/user/feedback/feedback.js: -------------------------------------------------------------------------------- 1 | // pages/user/feedback/feedback.js 2 | Page({ 3 | 4 | /** 5 | * 页面的初始数据 6 | */ 7 | data: { 8 | 9 | }, 10 | 11 | /** 12 | * 生命周期函数--监听页面加载 13 | */ 14 | onLoad: function (options) { 15 | 16 | }, 17 | 18 | /** 19 | * 生命周期函数--监听页面初次渲染完成 20 | */ 21 | onReady: function () { 22 | 23 | }, 24 | 25 | /** 26 | * 生命周期函数--监听页面显示 27 | */ 28 | onShow: function () { 29 | 30 | }, 31 | 32 | /** 33 | * 生命周期函数--监听页面隐藏 34 | */ 35 | onHide: function () { 36 | 37 | }, 38 | 39 | /** 40 | * 生命周期函数--监听页面卸载 41 | */ 42 | onUnload: function () { 43 | 44 | }, 45 | 46 | /** 47 | * 页面相关事件处理函数--监听用户下拉动作 48 | */ 49 | onPullDownRefresh: function () { 50 | 51 | }, 52 | 53 | /** 54 | * 页面上拉触底事件的处理函数 55 | */ 56 | onReachBottom: function () { 57 | 58 | }, 59 | 60 | /** 61 | * 用户点击右上角分享 62 | */ 63 | onShareAppMessage: function () { 64 | 65 | } 66 | }) -------------------------------------------------------------------------------- /heartSound/pages/user/feedback/feedback.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /heartSound/pages/user/feedback/feedback.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 反馈邮箱 5 | 6 | 7 | 535073920@qq.com 8 | 简介 9 | 10 | -------------------------------------------------------------------------------- /heartSound/pages/user/feedback/feedback.wxss: -------------------------------------------------------------------------------- 1 | /* pages/user/feedback/feedback.wxss */ 2 | .version{ 3 | height: 100rpx; 4 | background: #fff; 5 | display: flex; 6 | align-items: center; 7 | padding: 0 45rpx; 8 | box-sizing: border-box; 9 | font-size: 13pt; 10 | color: #666; 11 | border-bottom: 1px #e5e5e5 solid; 12 | } 13 | .version-title{ 14 | flex: 1; 15 | display: flex; 16 | align-items: center; 17 | } 18 | .title-name{ 19 | padding-right: 10rpx; 20 | } 21 | .version-text{ 22 | font-size: 10pt; 23 | line-height: 100%; 24 | color: #7acfa6; 25 | border: 1px solid #7acfa6; 26 | padding: 5rpx 10rpx; 27 | border-radius: 5rpx; 28 | margin-left: 10rpx; 29 | text-align: center; 30 | } 31 | .version-log-link{ 32 | position: relative; 33 | font-size: 12pt; 34 | color: #7acfa6; 35 | } 36 | .version-log-link:active{ 37 | opacity: .8; 38 | } 39 | .update-log::after{ 40 | content: ''; 41 | position: absolute; 42 | right: -3px; 43 | top: -1px; 44 | width: 5px; 45 | height: 5px; 46 | border-radius: 50%; 47 | background: #e55c5c; 48 | } -------------------------------------------------------------------------------- /heartSound/pages/user/user.js: -------------------------------------------------------------------------------- 1 | //index.js 2 | //获取应用实例 3 | const app = getApp() 4 | 5 | Page({ 6 | data: { 7 | motto: 'Hello World', 8 | userInfo: {}, 9 | hasUserInfo: false, 10 | canIUse: wx.canIUse('button.open-type.getUserInfo') 11 | }, 12 | //事件处理函数 13 | gotoAbout: function () { 14 | wx.navigateTo({ 15 | url: '/pages/user/about/about' 16 | }) 17 | }, 18 | gotoFeedback: function () { 19 | wx.navigateTo({ 20 | url: '/pages/user/feedback/feedback' 21 | }) 22 | }, 23 | gotoShare: function () { 24 | this.onShareAppMessage() 25 | }, 26 | onLoad: function () { 27 | if (app.globalData.userInfo) { 28 | this.setData({ 29 | userInfo: app.globalData.userInfo, 30 | hasUserInfo: true 31 | }) 32 | } else if (this.data.canIUse) { 33 | // 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回 34 | // 所以此处加入 callback 以防止这种情况 35 | app.userInfoReadyCallback = res => { 36 | this.setData({ 37 | userInfo: res.userInfo, 38 | hasUserInfo: true 39 | }) 40 | } 41 | } else { 42 | // 在没有 open-type=getUserInfo 版本的兼容处理 43 | wx.getUserInfo({ 44 | success: res => { 45 | app.globalData.userInfo = res.userInfo 46 | this.setData({ 47 | userInfo: res.userInfo, 48 | hasUserInfo: true 49 | }) 50 | } 51 | }) 52 | } 53 | }, 54 | getUserInfo: function (e) { 55 | console.log(e) 56 | app.globalData.userInfo = e.detail.userInfo 57 | this.setData({ 58 | userInfo: e.detail.userInfo, 59 | hasUserInfo: true 60 | }) 61 | }, 62 | onShareAppMessage: function () { 63 | return { 64 | title: '心声Lite,用心说话', 65 | desc: '语音识别,语音合成,画板涂鸦,心声Lite — 致力于为听障者服务。', 66 | path: '/pages/index/index', 67 | imageUrl: '/images/xxs.png' 68 | } 69 | }, 70 | }) 71 | -------------------------------------------------------------------------------- /heartSound/pages/user/user.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /heartSound/pages/user/user.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | {{userInfo.nickName}} 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 反馈 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 关于 26 | 27 | 28 | 29 | 30 | 31 | 32 | 35 | 36 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /heartSound/pages/user/user.wxss: -------------------------------------------------------------------------------- 1 | 2 | .user-wechat-info { 3 | display: flex; 4 | flex-wrap: wrap; 5 | justify-content: center; 6 | width: 95%; 7 | margin: 25rpx auto; 8 | height: 280rpx; 9 | border-radius: 30rpx; 10 | box-shadow: 0px 2px 2px 1px #cccccc; 11 | background-color: #f3a09e; 12 | overflow: hidden; 13 | } 14 | .avatar image { 15 | width: 150rpx; 16 | height: 150rpx; 17 | border-radius: 50%; 18 | margin-top: 30rpx; 19 | display: block; 20 | } 21 | .nick-name { 22 | display: flex; 23 | justify-content: center; 24 | color: #ffffff; 25 | font-size: 34rpx; 26 | position: absolute; 27 | top: 225rpx; 28 | } 29 | .nav-item-box{ 30 | display: flex; 31 | flex-wrap: wrap; 32 | } 33 | .nav-item{ 34 | margin-top: 60rpx; 35 | display: block; 36 | height: 125rpx; 37 | width: 125rpx; 38 | } 39 | .append{ 40 | display: flex; 41 | justify-content: center; 42 | } 43 | 44 | /**more.wxss**/ 45 | .container{ 46 | background-color: #f6f6f6; 47 | } 48 | .user-info, .more-btn { 49 | display: flex; 50 | background-color: #fff; 51 | min-height: 85rpx; 52 | border-top: 1px solid #e5e5e5; 53 | border-bottom: 1px solid #e5e5e5; 54 | } 55 | /**user-info**/ 56 | .user-info-box{ 57 | margin-bottom: 40rpx; 58 | } 59 | .user-info { 60 | flex-direction: column; 61 | margin: 30rpx 0 -1px; 62 | padding: 25rpx 30rpx 20rpx; 63 | } 64 | .info-hd { 65 | display: flex; 66 | align-items: center; 67 | } 68 | .bind-btn { 69 | color: #aaa; 70 | } 71 | .user-avatar { 72 | width: 120rpx; 73 | height: 120rpx; 74 | border-radius: 5px; 75 | } 76 | .user-title { 77 | flex: 1; 78 | display: flex; 79 | flex-direction: column; 80 | padding-left: 25rpx; 81 | } 82 | .time-box { 83 | display: flex; 84 | flex-direction: column; 85 | align-items: center; 86 | font-size: 10pt; 87 | line-height: 140%; 88 | color: #aaa; 89 | } 90 | .user-name { 91 | font-size: 16pt; 92 | line-height: 160%; 93 | letter-spacing: 1px; 94 | } 95 | .user-id { 96 | font-size: 11pt; 97 | color: #8b8b8b; 98 | } 99 | .info-bd { 100 | display: flex; 101 | justify-content: space-between; 102 | padding: 25rpx 15rpx 0 5rpx; 103 | font-size: 11pt; 104 | line-height: 150%; 105 | color: #8b8b8b; 106 | } 107 | .info-bd-left, .info-bd-right { 108 | display: flex; 109 | flex-direction: column; 110 | } 111 | .info-bd-left{ 112 | flex-shrink: 0; 113 | padding-right: 30rpx; 114 | } 115 | /**more-list**/ 116 | .more-list { 117 | flex: 1; 118 | display: flex; 119 | flex-direction: column; 120 | } 121 | .more-btn { 122 | align-items: center; 123 | font-size: 13pt; 124 | padding: 0 30rpx; 125 | margin-top: 20rpx; 126 | } 127 | .issue-link, .about-link { 128 | margin-bottom: 20rpx; 129 | } 130 | .btn-icon { 131 | width: 55rpx; 132 | height: 55rpx; 133 | margin-right: 15rpx; 134 | } 135 | .btn-text { 136 | flex: 1; 137 | font-size: 36rpx; 138 | color: #515151; 139 | } 140 | .btn-open { 141 | display: flex; 142 | align-items: center; 143 | justify-content: flex-end; 144 | margin-left: 10rpx; 145 | } 146 | .btn-enter { 147 | width: 18rpx; 148 | height: 27rpx; 149 | } 150 | .login-btn { 151 | font-size: 13pt; 152 | line-height: 85rpx; 153 | height: 85rpx; 154 | background: #7aa0cb; 155 | color: #fff; 156 | text-align: center; 157 | border-radius: 5px; 158 | margin: 40rpx 3%; 159 | } -------------------------------------------------------------------------------- /heartSound/project.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "description": "项目配置文件。", 3 | "packOptions": { 4 | "ignore": [] 5 | }, 6 | "setting": { 7 | "urlCheck": true, 8 | "es6": true, 9 | "postcss": true, 10 | "minified": true, 11 | "newFeature": true 12 | }, 13 | "compileType": "miniprogram", 14 | "libVersion": "2.2.2", 15 | "appid": "wxfb65ccf6436cd4f6", 16 | "projectname": "heartSound%20latest", 17 | "isGameTourist": false, 18 | "condition": { 19 | "search": { 20 | "current": -1, 21 | "list": [] 22 | }, 23 | "conversation": { 24 | "current": -1, 25 | "list": [] 26 | }, 27 | "game": { 28 | "currentL": -1, 29 | "list": [] 30 | }, 31 | "miniprogram": { 32 | "current": -1, 33 | "list": [] 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /heartSound/utils/util.js: -------------------------------------------------------------------------------- 1 | const formatTime = date => { 2 | const year = date.getFullYear() 3 | const month = date.getMonth() + 1 4 | const day = date.getDate() 5 | const hour = date.getHours() 6 | const minute = date.getMinutes() 7 | const second = date.getSeconds() 8 | 9 | return [year, month, day].map(formatNumber).join('/') + ' ' + [hour, minute, second].map(formatNumber).join(':') 10 | } 11 | 12 | const formatNumber = n => { 13 | n = n.toString() 14 | return n[1] ? n : '0' + n 15 | } 16 | 17 | module.exports = { 18 | formatTime: formatTime 19 | } 20 | -------------------------------------------------------------------------------- /项目截图/about.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonLam0990/HeartSound/2dd0cbcd1772c929088ca565cff9d04065cb3a4c/项目截图/about.jpg -------------------------------------------------------------------------------- /项目截图/code.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonLam0990/HeartSound/2dd0cbcd1772c929088ca565cff9d04065cb3a4c/项目截图/code.jpg -------------------------------------------------------------------------------- /项目截图/draw.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonLam0990/HeartSound/2dd0cbcd1772c929088ca565cff9d04065cb3a4c/项目截图/draw.jpg -------------------------------------------------------------------------------- /项目截图/index.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonLam0990/HeartSound/2dd0cbcd1772c929088ca565cff9d04065cb3a4c/项目截图/index.jpg -------------------------------------------------------------------------------- /项目截图/letdraw.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonLam0990/HeartSound/2dd0cbcd1772c929088ca565cff9d04065cb3a4c/项目截图/letdraw.jpg -------------------------------------------------------------------------------- /项目截图/longtalk.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonLam0990/HeartSound/2dd0cbcd1772c929088ca565cff9d04065cb3a4c/项目截图/longtalk.jpg -------------------------------------------------------------------------------- /项目截图/talk.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonLam0990/HeartSound/2dd0cbcd1772c929088ca565cff9d04065cb3a4c/项目截图/talk.jpg -------------------------------------------------------------------------------- /项目截图/user.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonLam0990/HeartSound/2dd0cbcd1772c929088ca565cff9d04065cb3a4c/项目截图/user.jpg --------------------------------------------------------------------------------