惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

H
Help Net Security
J
Java Code Geeks
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
H
Hackread – Cybersecurity News, Data Breaches, AI and More
V
Visual Studio Blog
G
Google Developers Blog
V
V2EX
The Register - Security
The Register - Security
博客园 - 三生石上(FineUI控件)
云风的 BLOG
云风的 BLOG
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
博客园_首页
S
SegmentFault 最新的问题
博客园 - Franky
Martin Fowler
Martin Fowler
Stack Overflow Blog
Stack Overflow Blog
A
About on SuperTechFans
人人都是产品经理
人人都是产品经理
aimingoo的专栏
aimingoo的专栏
罗磊的独立博客
C
Check Point Blog
MyScale Blog
MyScale Blog
T
The Blog of Author Tim Ferriss
MongoDB | Blog
MongoDB | Blog
The GitHub Blog
The GitHub Blog
Last Week in AI
Last Week in AI
Microsoft Azure Blog
Microsoft Azure Blog
IT之家
IT之家
F
Fortinet All Blogs
Jina AI
Jina AI
P
Proofpoint News Feed
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
阮一峰的网络日志
阮一峰的网络日志
B
Blog
L
LangChain Blog
月光博客
月光博客
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
宝玉的分享
宝玉的分享
博客园 - 【当耐特】
T
Tailwind CSS Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
Microsoft Security Blog
Microsoft Security Blog
WordPress大学
WordPress大学
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
B
Blog RSS Feed
博客园 - 聂微东
Hugging Face - Blog
Hugging Face - Blog
M
MIT News - Artificial intelligence
GbyAI
GbyAI

夜行人

回家路上 第一期的直播演示项目 震动检测器 正能量 在线参观CodeLab Neverland 发布 CodeLab Adapter 3.3.1 DynamicTable 之 纸糊方向盘 CodeLab DynamicTable: 一个可实施的技术方案 CodeLab Insight 发布 Alpha 版 情人节 Home Assistant 周报 && IoT 周报 (02) Joplin: 关注隐私的 Evernote 开源替代软件 浏览器的未来与 Web 传感器 Home Assistant 周报 && IoT 周报 (01) 百宝箱(01) 论自由 介绍 WebThings Home Assistant 周报 && iot 周报 (00) 百宝箱(00) 毛姆读书心得 传世之作 周末徒步 CodeLab Adapter ❤️ Jupyter/Python 航班 躲雨 夏令营途中 [译]思想--作为一种技术 The future of coding 美国之行 三门问题的程序模拟 从Python转向Pharo https://blog.just4fun.site/post/iot/iot-open-source-projects/ Python异步编程笔记 https://blog.just4fun.site/post/iot/iot-open-source-hardware-community/ 万物积木化开发者社区 CodeLab ❤️ Blender Scratch3技术分析之云变量 API(第7篇) [译]对管道(Pipes)的偏爱 [译]提出正确的问题比得到正确答案更重要 蓝牙设备与Scratch3.0 创建你的第一个Scratch3.0 Extension Scratch3技术分析之项目内部数据(第6篇) Scratch3技术分析之社区 API(第5篇) Scratch3技术分析之User API(第4篇) Scratch3技术分析之项目主页API(第3篇) Scratch3技术分析之静态资源API(第2篇) Scratch3.0、micro:bit与Windows7 https://blog.just4fun.site/post/iot/zerynth-vs-micropython/ 核聚变、方所与半宅空间 可视化编程为何是个糟糕的主意 codelab.club周末聚会 关于codelab.club '下一件大事'是一个房间 Hungry Robot - Eat everything 编程作为一种思考方式 今日简史 史蒂夫·乔布斯传 罗素自选文集 https://blog.just4fun.site/post/edx/tianjin-scratch-ai/ https://blog.just4fun.site/post/edx/richie-cms-openedx/ 徒步武功山 WebUSB与micro:bit 积木化编程与3D场景 夜宿武功山顶 scratch3-adapter接入优必选Alpha系列机器人 https://blog.just4fun.site/post/edx/video-migration-note/ scratch3-adapter重构笔记 https://blog.just4fun.site/post/edx/edx-community-members/ 两种硬件编程风格的比较 使用micro:bit自制PPT翻页笔 柏拉图对话集 scratch3.0 + micro:bit 七月电影放映计划 非营利组织的管理 Screenly--用树莓派让任何屏幕变为可编程的数字标牌 以最佳实践开始你的Django项目 micro:bit与事件驱动 为Scratch3.0设计的插件系统(上篇) OCR应用一例 近两年读过的一些好书 blockly开发之使用python驱动浏览器中的turtle(2) 牛顿新传 文学理论入门 逻辑的引擎 人生的意义 blockly开发之生成并运行js代码(1) blockly开发之hello world(0) micro:bit使用笔记 神器之Termux https://blog.just4fun.site/post/iot/micropython-notes/ Cozmo what is this Scratch的前世今生 下段旅程 我行在远方 爆裂 途中杂记 https://blog.just4fun.site/post/edx/open-edx-startup/ cozmo系列之入门 - 有性格且可编程的机器人 PaperWeekly开发笔记 创业二三事
在blockly中构建语音识别/合成 积木块
2017-05-12 · via 夜行人

背景

近期在完善blockly4pi中AI的相关部分,语音和图像/视频流是常见的输入,语音的输入之前计划在硬件积木那边采集,之后流向树莓派,交由树莓派来处理,不过协议因此变得复杂许多,一番权衡之下,我们决定在浏览器里来处理多媒体输入

我一直在关注浏览器中的webRTC和Web Speech,之前在几个项目中也接触过它们,这些接口现在越发强大了,而且浏览器的支持也在变好

Web Speech

HTML5中和Web Speech相关的API有两类, 一类是"语音合成(Speech Synthesis)",一类是"语音识别(Speech Recognition)",无论哪种,使用起来都非常简单.

语音合成

之前语音合成我一直用百度语音来做,效果还不错,不过多了一层网络请求.

Chrome 浏览器在版本25之后开始支持这一特性,效果非常棒.你可以调出你的控制台,让浏览器说: ‘你好,世界’,像下边这样:

1
2
var utterThis = new window.SpeechSynthesisUtterance('你好,世界!');
window.speechSynthesis.speak(utterThis);

神奇的是,竟然没有用到云服务,完全在本地完成!

语音识别

相比于语音合成,语音识别还有些坑。

我们先来说下它的简单用法

1
2
3
4
5
var newRecognition = new webkitSpeechRecognition();
newRecognition.onresult = function(event) {
        console.log(event);
}
newRecognition.start();

上边短短的几行,你就完成了浏览器调用麦克风,等待语音输入到结果输出的完成流程

如果你只是想拿到输出结果的内容,可以这样:

1
2
3
4
5
6
7
8
9
var newRecognition = new webkitSpeechRecognition();
//newRecognition.continuous = false;
newRecognition.onresult = function(event) {
        //console.log(event);
        result = event.results[0][0];
        transcript = result.transcript;
        console.log(transcript);
}
newRecognition.start();

识别结果比较理想

有个恼人的坑是,识别开始后,浏览器有时候一直在等待输入,而无法返回识别结果(可能是墙的原因),这种情况时常发生,而且在各个平台下(mac/windows)下都是如此

不过在chrome的开发版(canary)中一切正常,我的当前版本号是: 60.0.3099.0(正式版本)canary (64 位

为了将其纳入到blockly4pi体系中,我们需要将Web Speech包装为blockly积木块

语音合成部分比较简单,在积木中接受用户输入,传到api中即可,@dsl已经完成了这个工作

语音识别部分会比较麻烦,在上边的语音识别示例代码里,我们看到对语音的识别结果出现在onresult事件回调的函数里,这样一来控制流就不是线性的了(哈哈 在js中这才是常态),如何在blockly中表达变达这种控制流,是个值得思考的问题

熟悉js的同学会觉得思路上不难,可要在blockly中表达也没有很容易,首先得熟悉blockly的表达习惯和api,有些部分涉及比较高级的api

这个问题webduino团队给出了漂亮的解答,我们稍后对其源码做个分析

源码分析

熟悉blockly的小伙伴,很轻松能定位到目标积木块的源码(我们只关注sound_recognition块,其他块相对简单)

在注释中我们找到了积木块的生成方式:sound_recognition blockfactory

积木外观由以下代码定义:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
Blockly.Blocks['sound_recognition'] = {
  init: function() {
    this.appendDummyInput()
        .appendField("開始語音辨識 ( Chrome 限定,不支援 iOS )");
    this.appendDummyInput()
        .appendField("辨識語言:")
        .appendField(new Blockly.FieldDropdown([["中文","cmn-Hant-TW"], ["English","en-US"]]), "lang_")
        .appendField("    即時辨識:")
        .appendField(new Blockly.FieldDropdown([["on","on"], ["off","off"]]), "interimResults_")
        .appendField("( 行動裝置勾選 off )");
    this.appendStatementInput("recognition_");
    this.setPreviousStatement(true);
    this.setNextStatement(true);
    this.setTooltip('');
    this.setHelpUrl('');
  }
};

(以js为例)拿到积木中的用户的输入很简单:

1
2
3
4
5
6
7
8
Blockly.JavaScript['sound_recognition'] = function(block) {
  var dropdown_lang_ = block.getFieldValue('lang_');
  var dropdown_interimresults_ = block.getFieldValue('interimResults_');
  var statements_recognition_ = Blockly.JavaScript.statementToCode(block, 'recognition_');
  // TODO: Assemble JavaScript into code variable.
  var code = '...;\n';
  return code;
};

其中statements_recognition_值得留意

至此整个积木块已经完成,只剩下最后也最核心的问题了,sound_recognition是如何来generate出代码的,上边提到的回调的问题也是在这里处理

直接上代码更直观些:

抛开辅助性的代码,我们看到最核心的部分是

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
    '    window._recognition.onresult = async function(event,result) {\n' +
    '      result = {};\n' +
    '      result.resultLength = event.results.length-1;\n' +
    '      result.resultTranscript = event.results[result.resultLength][0].transcript;\n' +
    '      if(event.results[result.resultLength].isFinal===' + inter1 + '){\n' +
    '        console.log(result.resultTranscript);\n' +
    '        ' + statements_recognition_ +
    '        ' + consoleFinal1 +
    '      }else if(event.results[result.resultLength].isFinal===' + inter2 + '){\n' +
    '        ' + consoleFinal2 +
    '      }\n' +
    '    };\n' +
    '    window._recognition.start();\n' +

特别注意statements_recognition_

顺便吐个槽,尽管code的拼接极尽排版的工整,但读起来还是不舒服,用es6的模版字符串来写会好看很多

参考