Chrome 语音合成具有较长的文本

2024-02-08

我在 Chrome 33 中尝试使用语音合成 API 时遇到问题。它可以完美地处理较短的文本,但如果我尝试较长的文本,它就会停在中间。一旦停止后,语音合成将无法在 Chrome 中的任何地方工作,直到浏览器重新启动。

示例代码(http://jsfiddle.net/Mdm47/1/ 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 语音合成时遇到这个问题已经有一段时间了。经过一番调查,我发现了以下几点:

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

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

Update

我已将此解决方法公开发布于https://gist.github.com/woollsta/2d146f13878a301b36d7#file-chunkify-js https://gist.github.com/woollsta/2d146f13878a301b36d7#file-chunkify-js。非常感谢布雷特·扎米尔 https://gist.github.com/brettz9感谢他的贡献。

功能:

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');
});

希望人们发现这很有用。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Chrome 语音合成具有较长的文本 的相关文章

随机推荐

  • 获取场景图中具有 styleClass 的所有节点

    我想在我的程序中定义全局搜索 我的程序在一个场景中有很多节点 不同节点上有很多共同的东西可以被搜索 我考虑定义一个可搜索的类和一个在每个节点中搜索的方法 因此 当我通过类选择器搜索时 我将能够到达所有节点 为用户突出显示它们 例如 如果 S
  • Windows Phone 内存泄漏 90MB - 只有两个静态页面

    我创建了两个 尽可能基本的 XAML 页面 静态页面 xaml 显示内存使用情况 MemoryTest xaml 的链接 内存测试 xaml 不执行任何操作 只是显示 10 个左右的文本块 每个文本块带有 Text This is some
  • 在弹出窗口中显示部分视图[关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 我是 MVC 框架的新手 我需要您的
  • 如何在知道线程 id 的情况下获取消息线程 URL?

    有如果我有消息 ID 如何构建链接以查看 facebook com 上的消息 http facebook stackoverflow com questions 7747622 how can i construct a link to v
  • jquery mobile 和 ui 不兼容

    尽管有很多人提到类似的兼容性问题 但 50 的问题在 StackOverflow 上得到了解决 我希望我的问题能够成为 51 49 考虑这段代码
  • macOS 公证:找不到 altool

    我想开始构建一个公证自动化脚本 但是 当我尝试在终端中使用 xcrun altool 时 出现以下错误 xcrun error unable to find utility altool not a developer tool or in
  • 如何正确引用本地XML Schema文件?

    我在 XML 文件中引用 XML 架构时遇到此问题 我的 XSD 位于此路径中 C environment workspace maven ws ProjectXmlSchema email xsd 但是 当我在 XML 文件中尝试像这样查
  • 服务器标记格式不正确

    这真是太愚蠢了 但却让我快疯了
  • 堆叠 UITableViews 不会在其视图下方传递触摸事件

    我将 3 个 UIView 堆叠在一起 UI表格视图平面视图根视图 TableView 位于顶部 rootView 位于底部 rootView 不可见 因为 TableView 在它上面 我在 rootView 中实现了以下代码 code
  • 错误 TS2707 通用类型“ɵɵDirectiveDeclaration”需要 6 到 8 个类型参数

    安装角度材料并将角度材料导入 app module ts 添加到项目后 我遇到错误 并且到目前为止所有解决方案都不起作用 我的角度为 14 节点为 16 第一个错误 实际上要长得多 Error node modules angular cd
  • 如何使用 Python 从巨大的 Excel 工作表中提取特定行的数据?

    我需要获取其中包含某些关键字 名称 的特定数据行并将它们写入另一个文件 起始文件是 1 5 GB Excel 文件 我不能只是打开它并将其另存为不同的格式 我应该如何使用 python 处理这个问题 我是 xlrd 的作者和维护者 请编辑您
  • 如何提高Python循环速度?

    我有一个包含 370k 记录的数据集 存储在 Pandas Dataframe 中 需要集成 我尝试了多处理 线程 Cpython 和循环展开 但我没有成功 显示的计算时间是 22 小时 任务如下 matplotlib inline fro
  • 开发游戏服务器用什么语言好?

    我只是想知道什么语言是开发支持大量 数千 用户的游戏服务器的不错选择 我涉足Python 但意识到这太麻烦了 因为它不会跨核心产生线程 意味着8个核心服务器 1个核心服务器 我也不太喜欢这种语言 自我 的东西让我感到恶心 我知道 C 就性能
  • 在xamarin forms pcl项目中打开远程pdf的最佳方法

    在适用于 Ios 和 Android 的 xamarin pcl 应用程序中 在服务器上加载 pdf 的最佳方式是什么 是否有一个好的 nuget 或者我们必须编写自定义渲染器 在应用程序中打开 PDF 您有几个选项 iOS 在其 WebV
  • 使用 Cython 将 Python 链接到共享库

    我正在尝试集成用以下语言编写的第三方库C和我的python应用程序使用Cython 我已经为测试编写了所有 python 代码 我无法找到设置此功能的示例 我有一个pyd pyx我手动创建的文件 第三方给了我一个header file h
  • 使用Delphi RTTI获取接口的字符串名称

    我已经证明我可以使用 Delphi 2010 从其 GUID 获取接口的名称 例如 IMyInterface 转换为字符串 IMyInterface 我想在 Delphi 7 中实现此目的 为了兼容性 这可能吗 或者是存在基本的编译器限制
  • 哪种数据结构最适合 VirtualStringTree?

    我想每个曾经使用过Delphi的VirtualStringTree的人都会同意它是一个很棒的控件 它是一个 虚拟 控件 您的数据必须保存在其他地方 所以我在想什么数据结构最适合这样的任务 IMO认为数据结构必须支持层次结构 它必须快速且易于
  • 扩展器的默认控制模板

    有人 可能使用 Blend 可以为我提供 WPF Expander 的工作默认 ControlTemplate 吗 我想做一些细微的修改 但似乎找不到有效模板的来源 提前致谢 我有混合 可以帮助你 这是 Blend 为我生成的内容
  • 根据日期分割数据框

    我正在尝试根据日期将数据框分成两个 此处的相关问题已解决 根据日期将数据帧分成两部分 https stackoverflow com questions 37532098 split dataframe into two on the ba
  • Chrome 语音合成具有较长的文本

    我在 Chrome 33 中尝试使用语音合成 API 时遇到问题 它可以完美地处理较短的文本 但如果我尝试较长的文本 它就会停在中间 一旦停止后 语音合成将无法在 Chrome 中的任何地方工作 直到浏览器重新启动 示例代码 http js