首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >Microsoft Cognitive Services语音保存选项

我已经编写了以下代码,它可以将文本转换为语音并通过扬声器播放。我正在使用Microsoft Cognitive Services。

代码语言:javascript
运行
AI代码解释
复制
<html lang="en">
<head>
  <title>Microsoft Cognitive Services Speech SDK JavaScript Sample for Speech Synthesis</title>
  <meta charset="utf-8" />
  <style>
    body {
      font-family: 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif;
      font-size: 14px;
    }

    table, th, td {
      border: 1px solid #f1f1f1;
      border-collapse: collapse;
    }

    th, td {
      padding: 10px;
    }

    textarea {
      font-family: Arial,sans-serif;
    }

    .mode {
      font-size: 18px;
    }

    .highlight{
      background-color: yellow;
    }

    input:not(disabled) {
      font-weight: bold;
      color: black;
    }

    button {
      padding: 4px 8px;
      background: #0078d4;
      color: #ffffff;
    }

    button:disabled {
      padding: 4px 8px;
      background: #ccc;
      color: #666;
    }

    input[type=radio] {
      position: relative;
      z-index: 1;
    }

    input[type=radio] + label {
      padding: 8px 4px 8px 30px;
      margin-left: -30px;
    }

    input[type=radio]:checked + label {
      background: #0078d4;
      color: #ffffff;
    }
  </style>
</head>
<body>
  <div id="warning">
    <h1 style="font-weight:500;">Speech Speech SDK not found
      (microsoft.cognitiveservices.speech.sdk.bundle.js missing).</h1>
  </div>
  
  <div id="content" style="display:none">
    <table>
      <tr>
        <td></td>
        <td><h1 style="font-weight:500;">Microsoft Cognitive Services</h1></td>
      </tr>
      <tr>
        <td align="right">
          <label for="subscriptionKey">
            <a href="https://docs.microsoft.com/azure/cognitive-services/speech-service/get-started"
               rel="noreferrer noopener"
               target="_blank">Subscription Key</a>
          </label>
        </td>
        <td><input id="subscriptionKey" type="text" size="40" placeholder="YourSubscriptionKey"></td>
      </tr>
      <tr>
        <td align="right"><label for="regionOptions">Region</label></td>
        <td>
<!--          see https://aka.ms/csspeech/region for more details-->
          <select id="regionOptions">
            <option value="uksouth">UK South</option>
          </select>
        </td>
      </tr>
      <tr>
        <td align="right"><label for="voiceOptions">Voice</label></td>
        <td>
          <button id="updateVoiceListButton">Update Voice List</button>
          <select id="voiceOptions" disabled>
            <option>Please update voice list first.</option>
          </select>
        </td>
      </tr>
      <tr>
        <td align="right"><label for="isSSML">Is SSML</label><br></td>
        <td>
          <input type="checkbox" id="isSSML" name="isSSML" value="ssml">
        </td>
      </tr>
      <tr>
        <td align="right"><label for="synthesisText">Text</label></td>
        <td>
          <textarea id="synthesisText" style="display: inline-block;width:500px;height:100px"
                 placeholder="Input text or ssml for synthesis."></textarea>
        </td>
      </tr>
      <tr>
        <td></td>
        <td>
          <button id="startSynthesisAsyncButton">Start synthesis</button>
          <button id="pauseButton">Pause</button>
          <button id="resumeButton">Resume</button>
        </td>
      </tr>
      <tr>
        <td align="right" valign="top"><label for="resultsDiv">Results</label></td>
        <td><textarea id="resultsDiv" readonly style="display: inline-block;width:500px;height:50px"></textarea></td>
      </tr>
      <tr>
        <td align="right" valign="top"><label for="eventsDiv">Events</label></td>
        <td><textarea id="eventsDiv" readonly style="display: inline-block;width:500px;height:200px"></textarea></td>
      </tr>
      <tr>
        <td align="right" valign="top"><label for="highlightDiv">Highlight</label></td>
        <td><div id="highlightDiv" style="display: inline-block;width:800px;"></div></td>
      </tr>
    </table>
  </div>

  <!-- Speech SDK reference sdk. -->
  <script src="microsoft.cognitiveservices.speech.sdk.bundle.js"></script>

  <!-- Speech SDK Authorization token -->
  <script>
  // Note: Replace the URL with a valid endpoint to retrieve
  //       authorization tokens for your subscription.
  var authorizationEndpoint = "token.php";

  function RequestAuthorizationToken() {
    if (authorizationEndpoint) {
      var a = new XMLHttpRequest();
      a.open("GET", authorizationEndpoint);
      a.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
      a.send("");
      a.onload = function() {
          var token = JSON.parse(atob(this.responseText.split(".")[1]));
          serviceRegion.value = token.region;
          authorizationToken = this.responseText;
          subscriptionKey.disabled = true;
          subscriptionKey.value = "using authorization token (hit F5 to refresh)";
          console.log("Got an authorization token: " + token);
      }
    }
  }
  </script>

  <!-- Speech SDK USAGE -->
  <script>
    // On document load resolve the Speech SDK dependency
    function Initialize(onComplete) {
      if (!!window.SpeechSDK) {
        document.getElementById('content').style.display = 'block';
        document.getElementById('warning').style.display = 'none';
        onComplete(window.SpeechSDK);
      }
    }
  </script>

  <!-- Browser Hooks -->
  <script>
    // status fields and start button in UI
    var resultsDiv, eventsDiv;
    var highlightDiv;
    var startSynthesisAsyncButton, pauseButton, resumeButton;
    var updateVoiceListButton;

    // subscription key and region for speech services.
    var subscriptionKey, regionOptions;
    var authorizationToken;
    var voiceOptions, isSsml;
    var SpeechSDK;
    var synthesisText;
    var synthesizer;
    var player;
    var wordBoundaryList = [];

    document.addEventListener("DOMContentLoaded", function () {
      startSynthesisAsyncButton = document.getElementById("startSynthesisAsyncButton");
      updateVoiceListButton = document.getElementById("updateVoiceListButton");
      pauseButton = document.getElementById("pauseButton");
      resumeButton = document.getElementById("resumeButton");
      subscriptionKey = document.getElementById("subscriptionKey");
      regionOptions = document.getElementById("regionOptions");
      resultsDiv = document.getElementById("resultsDiv");
      eventsDiv = document.getElementById("eventsDiv");
      voiceOptions = document.getElementById("voiceOptions");
      isSsml = document.getElementById("isSSML");
      highlightDiv = document.getElementById("highlightDiv");

      setInterval(function () {
        if (player !== undefined) {
          const currentTime = player.currentTime;
          var wordBoundary;
          for (const e of wordBoundaryList) {
            if (currentTime * 1000 > e.audioOffset / 10000) {
              wordBoundary = e;
            } else {
              break;
            }
          }
          if (wordBoundary !== undefined) {
            highlightDiv.innerHTML = synthesisText.value.substr(0, wordBoundary.textOffset) +
                    "<span class='highlight'>" + wordBoundary.text + "</span>" +
                    synthesisText.value.substr(wordBoundary.textOffset + wordBoundary.wordLength);
          } else {
            highlightDiv.innerHTML = synthesisText.value;
          }
        }
      }, 50);

      updateVoiceListButton.addEventListener("click", function () {
        var request = new XMLHttpRequest();
        request.open('GET',
                'https://' + regionOptions.value + ".tts.speech." +
                (regionOptions.value.startsWith("china") ? "azure.cn" : "microsoft.com") +
                        "/cognitiveservices/voices/list", true);
        if (authorizationToken) {
          request.setRequestHeader("Authorization", "Bearer " + authorizationToken);
        } else {
          if (subscriptionKey.value === "" || subscriptionKey.value === "subscription") {
            alert("Please enter your Microsoft Cognitive Services Speech subscription key!");
            return;
          }
          request.setRequestHeader("Ocp-Apim-Subscription-Key", subscriptionKey.value);
        }

        request.onload = function() {
          if (request.status >= 200 && request.status < 400) {
            const response = this.response;
            const neuralSupport = (response.indexOf("JessaNeural") > 0);
            const defaultVoice = neuralSupport ? "JessaNeural" : "JessaRUS";
            let selectId;
            const data = JSON.parse(response);
            voiceOptions.innerHTML = "";
            data.forEach((voice, index) => {
              voiceOptions.innerHTML += "<option value=\"" + voice.Name + "\">" + voice.Name + "</option>";
              if (voice.Name.indexOf(defaultVoice) > 0) {
                selectId = index;
              }
            });
            voiceOptions.selectedIndex = selectId;
            voiceOptions.disabled = false;
          } else {
            window.console.log(this);
            eventsDiv.innerHTML += "cannot get voice list, code: " + this.status + " detail: " + this.statusText + "\r\n";
          }
        };

        request.send()
      });

      pauseButton.addEventListener("click", function () {
        player.pause();
        pauseButton.disabled = true;
        resumeButton.disabled = false;
      });

      resumeButton.addEventListener("click", function () {
        player.resume();
        pauseButton.disabled = false;
        resumeButton.disabled = true;
      });

      startSynthesisAsyncButton.addEventListener("click", function () {
        startSynthesisAsyncButton.disabled = true;
        resultsDiv.innerHTML = "";
        eventsDiv.innerHTML = "";
        wordBoundaryList = [];
        synthesisText = document.getElementById("synthesisText");

        // if we got an authorization token, use the token. Otherwise use the provided subscription key
        var speechConfig;
        if (authorizationToken) {
          speechConfig = SpeechSDK.SpeechConfig.fromAuthorizationToken(authorizationToken, serviceRegion.value);
        } else {
          if (subscriptionKey.value === "" || subscriptionKey.value === "subscription") {
            alert("Please enter your Microsoft Cognitive Services Speech subscription key!");
            return;
          }
          speechConfig = SpeechSDK.SpeechConfig.fromSubscription(subscriptionKey.value, regionOptions.value);
        }

        speechConfig.speechSynthesisVoiceName = voiceOptions.value;
        // The SDK uses Media Source Extensions (https://www.w3.org/TR/media-source/) for playback.
        // Mp3 format is supported in most browsers.
        speechConfig.speechSynthesisOutputFormat = SpeechSDK.SpeechSynthesisOutputFormat.Audio16Khz32KBitRateMonoMp3;
        player = new SpeechSDK.SpeakerAudioDestination();
        player.onAudioEnd = function (_) {
          window.console.log("playback finished");
          eventsDiv.innerHTML += "playback finished" + "\r\n";
          startSynthesisAsyncButton.disabled = false;
          pauseButton.disabled = true;
          resumeButton.disabled = true;
          wordBoundaryList = [];
        };

        var audioConfig  = SpeechSDK.AudioConfig.fromSpeakerOutput(player);
        var audioConfig = AudioConfig.FromWavFileOutput("/var/www/html/unitypst/customfiles/tts/ttsfile.wav");
        
        synthesizer = new SpeechSDK.SpeechSynthesizer(speechConfig, audioConfig);

        // The event synthesizing signals that a synthesized audio chunk is received.
        // You will receive one or more synthesizing events as a speech phrase is synthesized.
        // You can use this callback to streaming receive the synthesized audio.
        synthesizer.synthesizing = function (s, e) {
          window.console.log(e);
          eventsDiv.innerHTML += "(synthesizing) Reason: " + SpeechSDK.ResultReason[e.result.reason] +
                  "Audio chunk length: " + e.result.audioData.byteLength + "\r\n";
        };

        // The synthesis started event signals that the synthesis is started.
        synthesizer.synthesisStarted = function (s, e) {
          window.console.log(e);
          eventsDiv.innerHTML += "(synthesis started)" + "\r\n";
          pauseButton.disabled = false;
        };

        // The event synthesis completed signals that the synthesis is completed.
        synthesizer.synthesisCompleted = function (s, e) {
          console.log(e);
          eventsDiv.innerHTML += "(synthesized)  Reason: " + SpeechSDK.ResultReason[e.result.reason] +
                  " Audio length: " + e.result.audioData.byteLength + "\r\n";
        };

        // The event signals that the service has stopped processing speech.
        // This can happen when an error is encountered.
        synthesizer.SynthesisCanceled = function (s, e) {
          const cancellationDetails = SpeechSDK.CancellationDetails.fromResult(e.result);
          let str = "(cancel) Reason: " + SpeechSDK.CancellationReason[cancellationDetails.reason];
          if (cancellationDetails.reason === SpeechSDK.CancellationReason.Error) {
            str += ": " + e.result.errorDetails;
          }
          window.console.log(e);
          eventsDiv.innerHTML += str + "\r\n";
          startSynthesisAsyncButton.disabled = false;
          pauseButton.disabled = true;
          resumeButton.disabled = true;
        };

        // This event signals that word boundary is received. This indicates the audio boundary of each word.
        // The unit of e.audioOffset is tick (1 tick = 100 nanoseconds), divide by 10,000 to convert to milliseconds.
        synthesizer.wordBoundary = function (s, e) {
          window.console.log(e);
          eventsDiv.innerHTML += "(WordBoundary), Text: " + e.text + ", Audio offset: " + e.audioOffset / 10000 + "ms." + "\r\n";
          wordBoundaryList.push(e);
        };

        const complete_cb = function (result) {
          if (result.reason === SpeechSDK.ResultReason.SynthesizingAudioCompleted) {
            resultsDiv.innerHTML += "synthesis finished";
          } else if (result.reason === SpeechSDK.ResultReason.Canceled) {
            resultsDiv.innerHTML += "synthesis failed. Error detail: " + result.errorDetails;
          }
          window.console.log(result);
          synthesizer.close();
          synthesizer = undefined;
        };
        const err_cb = function (err) {
          startSynthesisAsyncButton.disabled = false;
          phraseDiv.innerHTML += err;
          window.console.log(err);
          synthesizer.close();
          synthesizer = undefined;
        };
        if (isSsml.checked) {
          synthesizer.speakSsmlAsync(synthesisText.value,
                  complete_cb,
                  err_cb);
        } else {
          synthesizer.speakTextAsync(synthesisText.value,
                  complete_cb,
                  err_cb);
        }
      });

      Initialize(function (speechSdk) {
        SpeechSDK = speechSdk;
        startSynthesisAsyncButton.disabled = false;
        pauseButton.disabled = true;
        resumeButton.disabled = true;
        saveButton.disabled = true;

        // in case we have a function for getting an authorization token, call it.
        if (typeof RequestAuthorizationToken === "function") {
          RequestAuthorizationToken();
        }
      });
    });
  </script>
</body>
</html>

我现在要做的是添加选项,将合成的语音数据保存到磁盘,并提示用户下载文件。使用Microsoft Cognitive Services Speech SDK可以实现吗?我应该如何修改代码以支持“保存”或“下载”选项?

EN

回答 1

Stack Overflow用户

发布于 2021-01-26 12:06:48

我们有a sample来展示如何使用Azure Speech SDK在浏览器下保存TTS音频。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65814124

复制
相关文章
671. 循环单词重复加标记
The words are same rotate words if rotate the word to the right by loop, and get another. Count how many different rotate word sets in dictionary.
和蔼的zhxing
2018/09/04
5670
空格还是Tab,编程时使用空格比Tab的工资更高
如果你觉得使用空格还是Tab没什么区别,那就大错特错了。或许你从来没有关注过这个问题,但是我要告诉你的是——使用空格比使用Tab键的工资更高。这可不是危言耸听。
三哥
2018/12/18
8270
word文档尾部空格没有下划线
问题出在兼容性上面了,office版本太多了!解决方法如下: 1.word2003——工具-〉选项-〉兼容性-〉找到“为尾部空格添加下划线”的选项打勾即可 2.word2007——点击左上角的“MS Office按钮”——word选项——高级——兼容性选项——版式选项——为尾部空格添加下划线 3.word2016——文件——选项——高级——兼容性选项——microsoft office 2013-2016——确定 修改后效果:
P轴
2022/11/18
9400
图解LeetCode——1592. 重新排列单词间的空格(难度:简单)
给你一个字符串 text ,该字符串由若干被空格包围的单词组成。每个单词由一个或者多个小写英文字母组成,并且两个单词之间至少存在一个空格。题目测试用例保证 text 至少包含一个单词 。
爪哇缪斯
2023/05/10
2690
图解LeetCode——1592. 重新排列单词间的空格(难度:简单)
C语言之计算字符串最后一个单词的长度,单词以空格隔开
//计算字符串最后一个单词的长度,单词以空格隔开。 #include<stdio.h> #include<string.h> #include<windows.h> int main() { char str[128]; gets(str); int count=0; int len=strlen(str); for(int i=(len-1);i>=0;i--) { if(str[i]!=' ') {
互联网金融打杂
2018/04/03
3.2K0
C语言之计算字符串最后一个单词的长度,单词以空格隔开
睡眠时的局部目标记忆再激活
通过目标记忆再激活(targeted memory reaction,TMR)实现记忆巩固,TMR在睡眠期间重现训练线索或是内容。但是不清楚TMR对睡眠皮层振荡的作用是局部的还是整体的。本文利用嗅觉的独特功能神经解剖学及其同侧刺激处理,在一个脑半球进行局部TMR。在最初就有气味刺激条件下,受试者学习单词与出现在左右视野中的位置间的联系。本文发现在任务训练期间,侧向的时间相关电位表示单半球的记忆过程。在学习后的小睡中,在非快速眼动(non-rapid eye movement,NREM)睡眠中进行气味刺激。在睡眠期间进行局部TMR后,cued半球(与受刺激鼻孔同侧)处理特定单词的记忆得到改善。单侧气味刺激调控局部慢波(slow-wave,SW)功率,即相较于uncued半球,cued半球的区域SW功率增加较慢,且与提示单词的选择记忆呈负相关。另外,在cued半球中,局部TMR改善了慢震荡和睡眠纺锤波间的相位振幅耦合(PAC)。在学习期间没有气味刺激条件下,睡眠期间进行单侧气味刺激,结果表明记忆表现和皮层睡眠振荡间并不存在任何效应。因此,睡眠中TMR通过选择性地促进与局部睡眠振荡相关的特定记忆,而超过了整体活动。
悦影科技
2021/11/11
6520
python读取文件如何去除空格_python读取txt文件时怎么去掉空格
Python读取TXT文件可以通过replace()函数来去除TXT文件中的空格,基本结构:replace(to_replace, value) 前面是需要替换的值,后面是替换后的值。
全栈程序员站长
2022/08/24
6.7K0
标记基因可视化
会根据之前的6个发育时期和4个cluster的tSNE结果,进行一些marker基因的等高线图和热图可视化
生信技能树jimmy
2020/03/30
1.5K1
传参base64时的+号变空格问题
上上周,看到一位老哥找我们组同事联调接口,不知道是什么问题,两人坐一起搞了快1个小时,看起来好像有点复杂。
科技新语
2023/03/28
1.2K0
python中空格的代码_python 空格
比如: print “Hens”, 25 + 30 / 6 print”hens”,25+30/6 一个有空格一个代码之间的空格其实没有什么作用。只是为了增强可读性。 代码不是越集中越好,符合规范的结构,比如让大括号单独成行,反而看起来更加清晰、舒服,是更能避免笔误的好习惯。 虽然,代码可读性是通过设计来实现的。
全栈程序员站长
2022/09/28
3.6K0
web系统中的结构化数据标记
Web 系统的设计要点之一是内容和表示的分离,网站以HTML发布内容,对内容进行操作的服务也只能访问 HTML。随着表现形式各异的设备在大量地增加,也大大增加了网站针对不同表示格式的数量。同时,一些新的个人助理应用,例如google assitant,amazon的Alexa,已经开始为web提供接触用户的新渠道。
半吊子全栈工匠
2021/11/16
1.9K0
web系统中的结构化数据标记
Linux 最小化安装时,是没有 tab 命令补全的,需要自己手动安装。
在执行命令时,如果找到单个匹配项的可执行文件,则一个 tab 就会将可执行命令自动补全。
用户10048459
2022/09/28
2.3K0
选择哪种结构化数据标记
目前主流搜索引擎支持三种类型的结构化数据标记格式:JSON-LD,Microdata,RDFa,我们如何正确选择这三种不同的结构化数据编写方法?谷歌在2015年宣布JSON-LD作为首选方法,这个宣布是非常重要的,因为谷歌之前没有说明偏好哪种结构化数据标记。在没有明确JSON-LD作为首选方法之前,谷歌希望站长在网页上使用可以看得到的标志文本,统称行内标记。
林雍岷
2019/07/03
1.9K0
初学Python:写码时应该缩进使用 tab 还是空格?
在不同的编辑器里tab的长度可能不一致,所以在一个编辑器里用tab设置缩进后,在其它编辑器里看可能缩进就乱了。空格不会出现这个问题,因为空格就占一个字符的位置。
用户2966292
2018/08/30
1.7K0
没有可视化,就没有大数据
《可视化组织》的作者菲尔·西蒙在本文中讨论了数据可视化工具和它们改变商业对话的强大力量。大数据可能导致大的混乱,因此要从混乱中梳理清晰的数据,从而发现商业机会,就变得无比的重要。清晰可见的呈现出数据和发现数据的过程一样重要。通过可视化的工具创建热图、数据关系树图以及空间地理图,能够帮助CEO在几分钟内通过可视化的方式解释一个销售趋势。可视化能够把数据转换成对话。这一课题在菲尔·西蒙的即将出版的新书《大到无法忽视》中也被提及,《可视化组织:数据可视化,大数据,需求更优决策》(Wiley出版社,2014年)也
大数据文摘
2018/05/21
9940
使用 CLIP 对没有标记的图像进行零样本无监督分类
深度图像分类模型通常以监督方式在大型带注释数据集上进行训练。随着更多带注释的数据加入到训练中,模型的性能会提高,但用于监督学习的大规模数据集的标注成本时非常高的,需要专家注释者花费大量时间。为了解决这个问题,人们开始寻找更便宜的标注的标签来源,是否有可能从已经公开的数据中学习高质量的图像分类模型?
deephub
2022/11/11
1.6K0
使用 CLIP 对没有标记的图像进行零样本无监督分类
idea配置Tomcat时没有Artifacts选项
Artifacts是maven中的一个概念,表示某个module要如何打包,例如war exploded、war、jar、ear等等这种打包形式;
全栈程序员站长
2022/11/02
1.5K0
idea配置Tomcat时没有Artifacts选项
每日算法刷题Day7-比较字符串大小,去掉多余的空格,单词替换
一般我们用 strcmp 可比较两个字符串的大小,比较方法为对两个字符串从前往后逐个字符相比较(按 ASCII 码值大小比较),直到出现不同的字符或遇到 \0 为止。
timerring
2022/09/27
1K0
每日算法刷题Day7-比较字符串大小,去掉多余的空格,单词替换
php编译时没有phpize文件的解决办法
php编译时没有phpize文件的解决办法,常码字不易,出精品更难,没有特别幸运,那么请先特别努力,别因为懒惰而失败,还矫情地将原因归于自己倒霉。你必须特别努力,才能显得毫不费力。如果这篇文章能给你带来一点帮助,希望给飞兔小哥哥一键三连,表示支持,谢谢各位小伙伴们。
用户8053452
2021/05/31
1K0
Latex中的空格
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/124692.html原文链接:https://javaforall.cn
全栈程序员站长
2022/07/21
1.2K0

相似问题

如何标记化没有空格分隔符的连续单词?

23

如何在空格中标记化新单词?

26

Elasticserarch如何对空格和特殊单词进行标记化

29

如何标记化(单词)将标点符号分类为空格

22

句子末尾标点符号后面没有空格时的标记化

12
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档