完整的记录一次大屏幕 语音播报的需求解决
Todd

背景

给客户的车间做了一个呼料的系统,大屏幕可以实时显示产线的呼料需求(APP),一方面仓库人员可以手机上看到这些呼料需求,另一方面,仓库的大屏幕可以显示分配到此仓库的呼料需求.

新需求

客户希望有新的呼料请求的时候,大屏幕不仅仅要显示,而且要语音提醒.
因为我们大屏幕用的是 Chrome 的浏览器来显示呼料请求,所以直接使用Chrome 的 TTS 接口即可:

1
2
3
4
5
6
function speakOut(msg) {
var u = new SpeechSynthesisUtterance();
u.lang = 'zh-CN';
u.text = msg;
window.speechSynthesis.speak(u);
};

然后其他的逻辑就不写了,比如如何判断新到语音,如何不再播报已经播报过的,如何播报捡料超时的任务等等.

新问题

问题来自我们的大屏幕客户端,原来的硬件结构是 电视机+小主机(插音箱)+Chrome .
现在换成了 树莓派 RespberryPi(插音箱)+电视机+Chromium(Electron 写了个壳子用来保证无人值守)
问题就变成了一连串:

  1. Chromium在树莓派上貌似没有 TTS 的发音,Google 了一堆,又是加启动参数,又是要装 eSpeak 之类的.全试过没用.具体的表现就是:window.speechSynthesis.getVoices()返回的数组是[].没有Voice,当然读不出来.
  2. 因为大屏幕终端很多,就算这种方法可行,也不可能一个一个树莓派去调整
  3. 所以更换思路,准备换成 Web 版本的接口,利用 js 来远程调用播放 MP3
  4. 找了很多 Web 的接口,貌似都收费…
  5. 终于,下定决心 自己搭一个TTS语音服务器

首先感谢 http://www.eguidedog.net/cn/ekho.php 的 余音(Ekho) 项目,非常给力.
在服务器上装了Linux发行版.具体的安装教程在:
http://www.eguidedog.net/doc/doc_install_ekho.php 下方 ++CENTOS6安装Ekho的方法++

打算帮他搞一个 Docker 版本的方便自己和大家.放到我的 TODOList 里
具体的安装的时候,还有些小问题,貌似 scl 我没装上, 不过没影响到后续使用.
安装的位置在 : /root/eGuideDog/ekho-8.0
装好之后用 Python 写了个脚本,基于 flask 的,非常简单:
假设以后提供服务的 tts 服务器地址为 tts.todd.com

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
from flask import Flask, request, jsonify
import uuid
import os
import sys

@app.route('/speak')
def speak():
txt = request.args.get('txt', '').encode('utf-8').strip()
if not txt:
ret = {
"msg": 'txt is required!',
"code": 0,
}
return jsonify(ret)

file_name = str(uuid.uuid1()) + ".mp3"
path = "/data/wwwroot/tts.todd.com/" + file_name
http_path = "http://tts.todd.com/" + file_name
# TODO 监控文件过多后自动清除历史文件

os.environ['PATH'] += os.pathsep + '/root/eGuideDog/ekho-8.0'
os.environ['EKHO_DATA_PATH'] = '/root/eGuideDog/ekho-8.0/ekho-data/'

cmd = "ekho -o %s -t=mp3 '%s'" % (path, txt)
# 其他需要啥参数,自己来
os.system(cmd)

ret = {
"cmd": cmd,
"path": http_path,
"code": 1,
}
return jsonify(ret)


if __name__ == '__main__':
app.run()

注意里面的几个坑:

  • 文件太多没有自动清理
  • 没有鉴权,不要放出来给别人,容易文件爆炸
  • 因为我装ekho的时候,有些路径问题,所以我启动 cmd 之前,加了环境变量.
  • nginx 要在前面反向代理:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    location ~ .*\.mp3{
    expires 1s;
    access_log off;
    }
    location / {
    add_header Access-Control-Allow-Origin *;
    add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
    add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
    proxy_pass http://127.0.0.1:5000/;
    proxy_redirect off;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-Proto https;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Cookie $http_cookie;
    proxy_connect_timeout 600s;
    proxy_send_timeout 600s;
    proxy_read_timeout 600s;
    chunked_transfer_encoding off;
    }
    上面大部分不用设置,前三行为了防止 js 调用的时候跨域.第四行用来转给 flask.
    其他都不重要.

截至目前 tts 服务器好了.
接下来是前端调用:
把原来的 speakOut函数做一个改造:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function speakOut(msg) {
if (window.speechSynthesis.getVoices().length > 0) {
var u = new SpeechSynthesisUtterance();
u.lang = 'zh-CN';
u.text = msg;
window.speechSynthesis.speak(u);
} else {
$.get("http://tts.todd.com/speak?txt=" + encodeURIComponent(msg), function (res) {
if (res) {
var audio = $("<iframe>");
audio.attr('allow', 'autoplay').attr("src", res.path).css("visibility", 'hidden');
$("body").append(audio);

}
})
}

};

其实这里面还有一个大坑,我直接放出来解决方法了,我并没有使用<audio>标签,
因为我试过,audio标签在Chrome 的某个版本之后,再也不让自动播放了.
不管你手动调用 play 也好,加上 aotuplay 也罢,都没用.

当然了,手机浏览器很早就这样了,不过手机很简单,用户总得摸手机把,只要他敢摸,咱就有办法让语音放出来,可是电脑不一样啊,这特么大屏幕在仓库的高墙上挂着,总不能让语音来的时候,让仓库的人爬上去点下浏览器吧.

不管咋样,我们这种方法也算解决 Chrome 浏览器 自动播放音频的需求.

总结一下,解决的几个问题:

  • CentOS上利用ekho + Python Flask 安装 Web 版本的 TTS 语音服务器,可能给公司省了一大笔钱,无以为报,接下来尝试抽空给人家做一个 Docker,顺便给人家Support 一个十块二十块的.
  • 前端解决 Chrome 浏览器 自动播放音频的问题,在浏览器支持 TTS 时候,调用浏览器接口,不支持的时候,调用 TTS 远程服务器播放 MP3文件.
 评论
评论插件加载失败
正在加载评论插件
由 Hexo 驱动 & 主题 Keep
本站由 提供部署服务
总字数 76.2k 访客数 访问量