手把手给文章添加TTS朗读功能
如题,这个想法在博客界也只有本人会去折腾,之前实现过给wordpress文章加上TTS语音朗读,后来看到麦田一根葱也跟着加上这个功能(他的不知道用什么方法,不过语音很死板),但本站使用的方法由于稳定性问题把它给撤下了。
PS:最新更新:给博客添加TTS语音朗读 简单快速版
今天,因为特殊原因需要登录百度云后台,发现更新了这方面的服务,并且主页显示了各种已经开启的开发选项,其中百度语音合成就再次吸引住我的目光,OK,既然这样,我们就再折腾一次吧!相信百度经过这么久的时间应该会稳定了吧。
查看演示请换一篇文章,文章开头有播放按钮,这篇文章字数太多,自动跳过。
也因为之前实现的方法是没有用apiKey来折腾,估计稳定性有限制,于是决定再次折腾!
之前实现的方法是这样的:
http://tts.baidu.com/text2audio?lan=zh&ie=UTF-8&spd=5&text=你好这是百度语音合成
播放器播放上面地址即可听到语音朗读!后面文字部分直接获取整篇文章,所以可以使用播放器播放这个URL链接,这方法虽然简单,但是今天测试,发现声音和原来不一样了,变成了低沉的老人音。
再试试APIKey那个,可以有很多声音选择,OK,开始折腾。
问题来了:
1.百度语音不支持超过900字(所以这篇文章不支持就跳过了),原以为是因为无APIKey造成的,今天折腾完以后,还是不行。
2.那么我就把文章进行分割分组,让播放器进行批量按顺序播放。
3.目前只能分3组,因为大部分文章不超过2700字。
OK,以上就这样解决,上次没有记方法,后来又得重新折腾,所以这次决定分享一下方法,之前也有人问,下面直接说步骤:
1.首先进入百度云申请APIKEY,如果不想申请,直接用文章开头那个方法,只是声音不好听。
2.拷贝如下代码:
<?php
function mbStrSplit ($string, $len=1) {
$start = 0;
$strlen = mb_strlen($string);
while ($strlen) {
$array[] = mb_substr($string,$start,$len,"utf8");
$string = mb_substr($string, $len, $strlen,"utf8");
$strlen = mb_strlen($string);
}
return $array;
}function match_chinese($chars,$encoding='utf8') //过滤特殊字符串
{
$pattern =($encoding=='utf8')?'/[\x{4e00}-\x{9fa5}a-zA-Z0-9,,。 ]/u':'/[\x80-\xFF]/';
preg_match_all($pattern,$chars,$result);
$temp =join('',$result[0]);
return $temp;
}$zishu=mb_strlen(preg_replace('/\s/','',html_entity_decode(strip_tags($post->post_content))),'UTF-8');
if($zishu<=2700){ //字数限制2700,超过不输出朗读功能。$str = "你好吗"; //删除$str =后面的内容,替换成这个:strip_tags($post->post_content);
$str = str_replace("、",",",$str );//保留顿号
$str=match_chinese($str);
$r = mbStrSplit($str, 900);
$qian="http://tsn.baidu.com/text2audio?tex=";
$hou=""; //例子:&per=0&spd=5&pit=5&vol=5&aue=3&cuid=123456PHP&tok=25.d7787ede620fd2fd516f119ab668f50b.2582090.1546809998.282335-15079228&lan=zh&ctp=1复制这一段你的tok号在双引号里面//以上是文章切割部分
//下面是百度云部分
define('DEMO_CURL_VERBOSE', false);
# 填写网页上申请的appkey 如 $apiKey="g8eBUMSokVB1BHGmgxxxxxx"
$apiKey = "";
# 填写网页上申请的APP SECRET 如 $secretKey="94dc99566550d87f8fa8ece112xxxxx"
$secretKey = "";
# text 的内容为"欢迎使用百度语音合成"的urlencode,utf-8 编码
# 可以百度搜索"urlencode"
//$text = strip_tags($post->post_content);
//$text2 = iconv("UTF-8", "GBK", $text);
//echo "text length :" . mb_strlen($text2, "GBK") . "\n";
#发音人选择, 0为普通女声,1为普通男生,3为情感合成-度逍遥,4为情感合成-度丫丫,默认为普通女声
$per = 0;
#语速,取值0-15,默认为5中语速
$spd = 5;
#音调,取值0-15,默认为5中语调
$pit = 5;
#音量,取值0-9,默认为5中音量
$vol = 5;
// 下载的文件格式, 3:mp3(default) 4: pcm-16k 5: pcm-8k 6. wav
$aue = 3;
$formats = array(3 => 'mp3', 4 => 'pcm', 5 => 'pcm', 6 => 'wav');
$format = $formats[$aue];
$cuid = "123456PHP";
/** 公共模块获取token开始 */
$auth_url = "https://openapi.baidu.com/oauth/2.0/token?grant_type=client_credentials&client_id=".$apiKey."&client_secret=".$secretKey;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $auth_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
//信任任何证书
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
// 检查证书中是否设置域名,0不验证
curl_setopt($ch, CURLOPT_VERBOSE, DEMO_CURL_VERBOSE);
$res = curl_exec($ch);
if (curl_errno($ch)) {
print curl_error($ch);
}
curl_close($ch);
//echo "Token URL response is " . $res . "\n";
$response = json_decode($res, true);
if (!isset($response['access_token'])) {
echo "ERROR TO OBTAIN TOKEN\n";
exit(1);
}
if (!isset($response['scope'])) {
echo "ERROR TO OBTAIN scopes\n";
exit(2);
}
if (!in_array('audio_tts_post',explode(" ", $response['scope']))) {
echo "DO NOT have tts permission\n";
// 请至网页上应用内开通语音合成权限
exit(3);
}
$token = $response['access_token'];
//echo "token = $token ; expireInSeconds: ${response['expires_in']}\n\n";
/** 公共模块获取token结束 */
/** 拼接参数开始 **/
// tex=$text&lan=zh&ctp=1&cuid=$cuid&tok=$token&per=$per&spd=$spd&pit=$pit&vol=$vol
$params = array(
'tex' => urlencode($text), // 为避免+等特殊字符没有编码,此处需要2次urlencode。
'per' => $per,
'spd' => $spd,
'pit' => $pit,
'vol' => $vol,
'aue' => $aue,
'cuid' => $cuid,
'tok' => $token,
'lan' => 'zh', //固定参数
'ctp' => 1, // 固定参数
);
$paramsStr = http_build_query($params);
$url = 'http://tsn.baidu.com/text2audio';
$urltest = $url . '?' . $paramsStr;
echo $urltest; //删除这行代码!
/** 拼接参数结束 **/
$g_has_error = true;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt ($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $paramsStr);
function read_header($ch, $header) {
global $g_has_error;$comps = explode(":", $header);
// 正常返回的头部 Content-Type: audio/*
// 有错误的如 Content-Type: application/json
if (count($comps) >= 2) {
if (strcasecmp(trim($comps[0]), "Content-Type") == 0) {
if (strpos($comps[1], "audio/") > 0) {
$g_has_error = false;
} else {
echo $header ." , has error \n";
}
}
}
return strlen($header);
}
curl_setopt($ch, CURLOPT_HEADERFUNCTION, 'read_header');
$data = curl_exec($ch);
if (curl_errno($ch)) {
echo curl_error($ch);
exit(2);
}
curl_close($ch);
$file = $g_has_error ? "result.txt" : "result." . $format;
file_put_contents($file, $data);
//echo "\n$file saved successed, please open it \n";?>
<?php if ($zishu<=2700): ?> //字数限制2700,超过不输出朗读功能。
<span class="du">
<video id="langdu" style="display:none">
<source id="source" src="<?php echo $qian.$r[0].$hou; ?>" type="video/mp4">
</video><script type="text/javascript">
function playPause() {
var music = document.getElementById('langdu');
var music_btn = document.getElementById('music_btn01');if (music.paused) {
music.play();
music_btn.src = '<?php bloginfo('template_url'); ?>/images/zanting.png'; //播放图片
var aud = document.getElementById("langdu");
aud.onended = function() {
aud.src = "<?php echo $qian.$r[1].$hou; ?>"
aud.play();
aud.addEventListener("ended", function() {
aud.src = "<?php echo $qian.$r[2].$hou; ?>"
aud.play();
aud.addEventListener("ended", function() {
aud.pause();
}, false);
}, false);
};} else {
music.pause();
music_btn.src = '<?php bloginfo('template_url'); ?>/images/bofang.png'; //暂停图片
}
}</script>
<a href="javascript:playPause();"><img src="<?php bloginfo('template_url'); ?>/images/bofang.png" width="25" height="25" id="music_btn01" border="0"></a>
</span><?php endif;?>
3.复制以上代码粘贴到single.php文章页面文件的<?php the_content(); ?>前面,代码中的png播放暂停按钮图片自己从本站右键下载放到你主题的images目录下,如果路径不同,自己修改图片路径。
4.保存,看看你的文章页。
5.先执行第2步红色字部分。
6.再执行第2步蓝色字部分。
5.大功告成!
好吧,不要觉得很繁琐,其实很简单,只是解释比较多,当然,你要是有更简单的方法,请告知。
PS:播放按钮用CSS的话,js代码也简化了,播放按钮CSS和js代码:
页面调用按钮代码:
<div class='music_btn01'></div>
CSS按钮:
.music_btn01 {
box-sizing: border-box;
width: 0;
height: 20px;
margin-left: 2px;
border-color: transparent transparent transparent #b7b7b7;
transition: 100ms all ease;
cursor: pointer;
margin-top: 4px;
border-style: solid;
border-width: 10px 0 8px 15px;
}
.paused {
border-style: double;
border-width: 0px 0 0px 15px;
}.music_btn01:hover {
border-color: transparent transparent transparent #404040;
}
JS代码:
<script>
$(document).ready(function() {
var music = document.getElementById('langdu');
var btn = $(".music_btn01");
btn.click(function() {
if (music.paused) {
music.play();
btn.toggleClass("paused");
} else {
music.pause();
btn.toggleClass("paused");
}
});
});
</script>
上一篇:纯CSS绘制灯泡
下一篇:代码高亮,这配色能亮瞎你的眼睛
百度手机端APP里就就集成了这个语音朗读!感觉还是很不错的!
@明月登楼 我看里面开发项目还有人脸识别方案,哈哈。。越来越普及了,之后登陆后台也直接人脸识别,或则评论也人脸识别。
这个挺有意思,有空也研究下~~
@山小炮 嗯,我这个是懒人法,深入研究的话,估计不用这么多代码,直接调用相关参数就OK。
虽然没啥大用(玩博客的文盲应该lim->0吧?),不过赞还是要点的
@老虎 其实不是给文盲用的,是解放眼睛,哈哈。。记得当时安卓可以朗读小说文本的时候,多少人大赞TTS功能,这功能甚至今天用在各种人机交流上,比如车站的语音广播,小爱同学等等。
对这个没需求,貌似你这个语音说话也听着瘆人……
@灰常记忆 感觉还行哈,比微软那个死板好听多了,不过确实手头忙的时候可以解放眼睛。
@郑永 听着别扭
@灰常记忆 你看到现在很多ai机器人,大部分都是语音回应,哈哈,机器人时代,有你听的了
@灰常记忆 改革刚开放时候,超短裤不也是种另类吧,如今成为常态了。
tts挺好玩的,今天看到王麻子整了一个,我也想弄个来玩玩。
@wys 嗨起来
没看到朗读的按钮??
@fffou 看红色部分有提,认真看文章哈,看来朗读对你很适用。
这个功能还是挺有趣的,我觉得比较适合非技术类文章,这女读代码真的听不懂
@fooleap 嗯,可以判断技术文分类跳过。
感觉折腾一下还可以,语音朗读这个功能大概很多时候用不到
@ZAERA 我说我自己会用你可能不相信,哈哈。。我自己有收藏文章,有时候会听一下,另外,我发现很多人没办法看完整篇文章,有的只是看看标题就评论,有这个现象吧?然后如果没时间看,那就按下播放,至少会听完的,如果别人博客有,我会选择这样方式,因为手头忙,听没问题,一切为了节省时间,哈哈。
感觉还挺有意思的,回头研究下~~对了,为啥是video而不是audio标签呢?
@夜枫 哈哈。。兼容性更大。
插放弹出一个黑色的播放器窗口,失败。我看了另一个模版实现是没有弹窗的。通过播放器按钮来实现。
@yankee 不会啊,你用神马浏览器能做到这点啊?我chrome,火狐狸,腾讯浏览器,PC端都没问题。
您使用的是哪个版本wordprss呀?对模板有什么要求,您这个两种方法测试了,都没有成功,读取的内容是“如题,以前就一直在找这个功能,但是迟迟没办法添加因为中文TTS语音做得最好的就是讯飞语音但是,讯飞语音居然没有提供这方面的调用想起前段时间用百度百科,发现百度用上了网页朗读功能,”这段文字,怎么处理呢?
@xu 我这里正常啊。