javascript - 带有较长文本的 Chrome 语音合成

标签 javascript google-chrome speech-synthesis

我在 Chrome 33 中尝试使用语音合成 API 时遇到问题。它可以完美地处理较短的文本,但如果我尝试较长的文本,它只会停在中间。像这样停止一次后,在浏览器重新启动之前,语音合成在 Chrome 中的任何地方都不起作用。

示例代码 ( http://jsfiddle.net/Mdm47/1/ ):

function speak(text) {
    var msg = new SpeechSynthesisUtterance();
    var voices = speechSynthesis.getVoices();
    msg.voice = voices[10];
    msg.voiceURI = 'native';
    msg.volume = 1;
    msg.rate = 1;
    msg.pitch = 2;
    msg.text = text;
    msg.lang = 'en-US';

    speechSynthesis.speak(msg);
}

speak('Short text');
speak('Collaboratively administrate empowered markets via plug-and-play networks. Dynamically procrastinate B2C users after installed base benefits. Dramatically visualize customer directed convergence without revolutionary ROI. Efficiently unleash cross-media information without cross-media value. Quickly maximize timely deliverables for real-time schemas. Dramatically maintain clicks-and-mortar solutions without functional solutions.');
speak('Another short text');

它在第二个文本中间停止说话,之后我无法让任何其他页面说话。

是浏览器错误还是某种安全限制?

最佳答案

我在使用 Google Chrome 语音合成时遇到这个问题已有一段时间了。经过一番调查,我发现了以下内容:

  • 断言只有当声音不是母语时才会发生
  • chop 通常发生在200-300个字符之间,
  • 当它确实中断时,您可以通过执行 speechSynthesis.cancel();
  • 来解冻它
  • onend”事件有时决定不触发。一个古怪的解决方法是在说出来之前用 console.log() 输出话语对象。我还发现将 speak 调用包装在 setTimeout 回调中有助于解决这些问题。

针对这些问题,我写了一个函数来克服字符限制,将文本分成更小的话语,然后一个接一个地播放。显然,有时您会听到一些奇怪的声音,因为句子可能被分成两个单独的话语,每个话语之间有一个小的时间延迟,但是代码会尝试在标点符号处拆分这些点,以使声音中断不太明显。

更新

我已在 https://gist.github.com/woollsta/2d146f13878a301b36d7#file-chunkify-js 上公开了此解决方法.非常感谢 Brett Zamir感谢他的贡献。

函数:

var speechUtteranceChunker = function (utt, settings, callback) {
    settings = settings || {};
    var newUtt;
    var txt = (settings && settings.offset !== undefined ? utt.text.substring(settings.offset) : utt.text);
    if (utt.voice && utt.voice.voiceURI === 'native') { // Not part of the spec
        newUtt = utt;
        newUtt.text = txt;
        newUtt.addEventListener('end', function () {
            if (speechUtteranceChunker.cancel) {
                speechUtteranceChunker.cancel = false;
            }
            if (callback !== undefined) {
                callback();
            }
        });
    }
    else {
        var chunkLength = (settings && settings.chunkLength) || 160;
        var pattRegex = new RegExp('^[\\s\\S]{' + Math.floor(chunkLength / 2) + ',' + chunkLength + '}[.!?,]{1}|^[\\s\\S]{1,' + chunkLength + '}$|^[\\s\\S]{1,' + chunkLength + '} ');
        var chunkArr = txt.match(pattRegex);

        if (chunkArr[0] === undefined || chunkArr[0].length <= 2) {
            //call once all text has been spoken...
            if (callback !== undefined) {
                callback();
            }
            return;
        }
        var chunk = chunkArr[0];
        newUtt = new SpeechSynthesisUtterance(chunk);
        var x;
        for (x in utt) {
            if (utt.hasOwnProperty(x) && x !== 'text') {
                newUtt[x] = utt[x];
            }
        }
        newUtt.addEventListener('end', function () {
            if (speechUtteranceChunker.cancel) {
                speechUtteranceChunker.cancel = false;
                return;
            }
            settings.offset = settings.offset || 0;
            settings.offset += chunk.length - 1;
            speechUtteranceChunker(utt, settings, callback);
        });
    }

    if (settings.modifier) {
        settings.modifier(newUtt);
    }
    console.log(newUtt); //IMPORTANT!! Do not remove: Logging the object out fixes some onend firing issues.
    //placing the speak invocation inside a callback fixes ordering and onend issues.
    setTimeout(function () {
        speechSynthesis.speak(newUtt);
    }, 0);
};

如何使用它...

//create an utterance as you normally would...
var myLongText = "This is some long text, oh my goodness look how long I'm getting, wooooohooo!";

var utterance = new SpeechSynthesisUtterance(myLongText);

//modify it as you normally would
var voiceArr = speechSynthesis.getVoices();
utterance.voice = voiceArr[2];

//pass it into the chunking function to have it played out.
//you can set the max number of characters by changing the chunkLength property below.
//a callback function can also be added that will fire once the entire text has been spoken.
speechUtteranceChunker(utterance, {
    chunkLength: 120
}, function () {
    //some code to execute when done
    console.log('done');
});

希望人们觉得这很有用。

关于javascript - 带有较长文本的 Chrome 语音合成,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32069150/

相关文章:

C#语音合成

javascript - Appcelerator SQLite 替换或更新命令

javascript - jQuery 在 Chrome 中加载但在 Firefox 中不加载,为什么?

javascript - 如何在网站上的语音合成中设置语言?

web - 如何通过 Google Chrome 中的 Web Speech API 获取女声

.Net Control 做 Google Chrome Docking

javascript - 我正在尝试拆分一个包含大写字母的单词。当重复出现时失败

javascript - 谷歌地图在隐藏的 div 中不显示

javascript - 有时,vue 路由器链接会刷新/重新加载页面。有时却没有

Javascript 在 Safari 中工作,但在 Chrome 或 Firefox 中不工作