@creativeorange/azure-text-to-speech 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
package/.eslintrc.js ADDED
@@ -0,0 +1,29 @@
1
+ module.exports = {
2
+ 'env': {
3
+ 'browser': true,
4
+ 'es6': true
5
+ },
6
+ 'extends': [
7
+ 'eslint:recommended',
8
+ 'plugin:@typescript-eslint/eslint-recommended',
9
+ 'google'
10
+ ],
11
+ 'rules': {
12
+ 'max-len': ['error', {'code': 125}],
13
+ 'indent': ['error', 4],
14
+ 'require-jsdoc': ['error', {
15
+ 'require': {
16
+ 'FunctionDeclaration': false,
17
+ 'MethodDefinition': false,
18
+ 'ClassDeclaration': false,
19
+ 'ArrowFunctionExpression': false,
20
+ 'FunctionExpression': false
21
+ }
22
+ }],
23
+ },
24
+ 'parserOptions': {
25
+ 'sourceType': 'module',
26
+ },
27
+ 'parser': '@typescript-eslint/parser',
28
+ "ignorePatterns": ["**/*.html", "**/*.scss"],
29
+ }
@@ -5842,7 +5842,7 @@ class RestMessageAdapter {
5842
5842
  }
5843
5843
  }
5844
5844
  class TextToSpeech {
5845
- constructor(key, region, voice = "male") {
5845
+ constructor(key, region, voice) {
5846
5846
  __publicField(this, "key");
5847
5847
  __publicField(this, "region");
5848
5848
  __publicField(this, "voice");
@@ -5855,45 +5855,25 @@ class TextToSpeech {
5855
5855
  __publicField(this, "player");
5856
5856
  __publicField(this, "synthesizer");
5857
5857
  __publicField(this, "previousWordBoundary");
5858
+ __publicField(this, "interval");
5859
+ __publicField(this, "wordEncounters", []);
5860
+ __publicField(this, "originalHighlightDivInnerHTML", "");
5861
+ __publicField(this, "currentWord", "");
5862
+ __publicField(this, "currentOffset", 0);
5858
5863
  this.key = key;
5859
5864
  this.region = region;
5860
5865
  this.voice = voice;
5861
5866
  }
5862
5867
  async start() {
5863
- setInterval(() => {
5864
- var _a;
5865
- if (this.player !== void 0 && this.highlightDiv) {
5866
- const currentTime = this.player.currentTime;
5867
- let wordBoundary;
5868
- for (const e of this.wordBoundryList) {
5869
- if (currentTime * 1e3 > e.audioOffset / 1e4) {
5870
- wordBoundary = e;
5871
- } else {
5872
- break;
5873
- }
5874
- }
5875
- if (~[".", ",", "!", "?"].indexOf(wordBoundary.text)) {
5876
- wordBoundary = (_a = this.previousWordBoundary) != null ? _a : void 0;
5877
- }
5878
- if (wordBoundary !== void 0) {
5879
- this.previousWordBoundary = wordBoundary;
5880
- this.highlightDiv.innerHTML = this.textToRead.substr(0, wordBoundary.textOffset) + "<span class='co-tts-highlight'>" + wordBoundary.text + "</span>" + this.textToRead.substr(wordBoundary.textOffset + wordBoundary.wordLength);
5881
- } else {
5882
- this.highlightDiv.innerHTML = this.textToRead;
5883
- }
5884
- }
5885
- }, 50);
5886
5868
  await this.registerBindings(document);
5887
5869
  }
5888
- async synthesis() {
5889
- }
5890
5870
  async registerBindings(node) {
5891
- let nodes = node.childNodes;
5871
+ const nodes = node.childNodes;
5892
5872
  for (let i = 0; i < nodes.length; i++) {
5893
5873
  if (!nodes[i]) {
5894
5874
  continue;
5895
5875
  }
5896
- let currentNode = nodes[i];
5876
+ const currentNode = nodes[i];
5897
5877
  if (currentNode.attributes) {
5898
5878
  if (currentNode.attributes.getNamedItem("co-tts.id")) {
5899
5879
  await this.handleIdModifier(currentNode, currentNode.attributes.getNamedItem("co-tts.id"));
@@ -5918,18 +5898,20 @@ class TextToSpeech {
5918
5898
  node.addEventListener("click", async (_) => {
5919
5899
  var _a;
5920
5900
  this.stopPlayer();
5901
+ await this.createInterval();
5921
5902
  this.clickedNode = node;
5922
- let referenceDiv = document.getElementById(attr.value);
5903
+ const referenceDiv = document.getElementById(attr.value);
5923
5904
  if (!referenceDiv) {
5924
5905
  return;
5925
5906
  }
5926
5907
  if (referenceDiv.hasAttribute("co-tts.text") && referenceDiv.getAttribute("co-tts.text") !== "") {
5927
5908
  this.textToRead = (_a = referenceDiv.getAttribute("co-tts.text")) != null ? _a : "";
5928
5909
  } else {
5929
- this.textToRead = referenceDiv.innerText;
5910
+ this.textToRead = referenceDiv.innerHTML;
5930
5911
  }
5931
5912
  if (referenceDiv.hasAttribute("co-tts.highlight")) {
5932
5913
  this.highlightDiv = referenceDiv;
5914
+ this.originalHighlightDivInnerHTML = referenceDiv.innerHTML;
5933
5915
  }
5934
5916
  this.startSynthesizer(node, attr);
5935
5917
  });
@@ -5937,8 +5919,9 @@ class TextToSpeech {
5937
5919
  async handleAjaxModifier(node, attr) {
5938
5920
  node.addEventListener("click", async (_) => {
5939
5921
  this.stopPlayer();
5922
+ await this.createInterval();
5940
5923
  this.clickedNode = node;
5941
- let response = await fetch(attr.value, {
5924
+ const response = await fetch(attr.value, {
5942
5925
  method: `GET`
5943
5926
  });
5944
5927
  this.textToRead = await response.text();
@@ -5948,39 +5931,65 @@ class TextToSpeech {
5948
5931
  async handleDefault(node, attr) {
5949
5932
  node.addEventListener("click", async (_) => {
5950
5933
  this.stopPlayer();
5934
+ await this.createInterval();
5951
5935
  this.clickedNode = node;
5952
5936
  if (node.hasAttribute("co-tts.highlight")) {
5953
5937
  this.highlightDiv = node;
5938
+ this.originalHighlightDivInnerHTML = node.innerHTML;
5954
5939
  }
5955
5940
  if (attr.value === "") {
5956
- this.textToRead = node.innerText;
5941
+ this.textToRead = node.innerHTML;
5957
5942
  } else {
5958
5943
  this.textToRead = attr.value;
5959
5944
  }
5960
5945
  this.startSynthesizer(node, attr);
5961
5946
  });
5962
5947
  }
5948
+ async handleWithoutClick(node, attr) {
5949
+ this.stopPlayer();
5950
+ await this.createInterval();
5951
+ this.clickedNode = node;
5952
+ if (node.hasAttribute("co-tts.highlight")) {
5953
+ this.highlightDiv = node;
5954
+ this.originalHighlightDivInnerHTML = node.innerHTML;
5955
+ }
5956
+ if (attr.value === "") {
5957
+ this.textToRead = node.innerHTML;
5958
+ } else {
5959
+ this.textToRead = attr.value;
5960
+ }
5961
+ this.startSynthesizer(node, attr);
5962
+ }
5963
5963
  async handleStopModifier(node, attr) {
5964
5964
  node.addEventListener("click", async (_) => {
5965
5965
  await this.stopPlayer();
5966
+ document.dispatchEvent(new CustomEvent("COAzureTTSStoppedPlaying", {}));
5966
5967
  });
5967
5968
  }
5968
5969
  async handlePauseModifier(node, attr) {
5969
5970
  node.addEventListener("click", async (_) => {
5971
+ await this.clearInterval();
5970
5972
  await this.player.pause();
5973
+ document.dispatchEvent(new CustomEvent("COAzureTTSPausedPlaying", {}));
5971
5974
  });
5972
5975
  }
5973
5976
  async handleResumeModifier(node, attr) {
5974
5977
  node.addEventListener("click", async (_) => {
5978
+ await this.createInterval();
5975
5979
  await this.player.resume();
5980
+ document.dispatchEvent(new CustomEvent("COAzureTTSResumedPlaying", {}));
5976
5981
  });
5977
5982
  }
5978
5983
  async stopPlayer() {
5984
+ await this.clearInterval();
5979
5985
  if (this.highlightDiv !== void 0) {
5980
- this.highlightDiv.innerHTML = this.textToRead;
5986
+ this.highlightDiv.innerHTML = this.originalHighlightDivInnerHTML;
5981
5987
  }
5982
5988
  this.textToRead = "";
5989
+ this.currentWord = "";
5990
+ this.originalHighlightDivInnerHTML = "";
5983
5991
  this.wordBoundryList = [];
5992
+ this.wordEncounters = [];
5984
5993
  if (this.player !== void 0) {
5985
5994
  this.player.pause();
5986
5995
  }
@@ -5989,27 +5998,30 @@ class TextToSpeech {
5989
5998
  }
5990
5999
  async startSynthesizer(node, attr) {
5991
6000
  this.speechConfig = SpeechConfig.fromSubscription(this.key, this.region);
5992
- if (this.voice === "female") {
5993
- this.speechConfig.speechSynthesisVoiceName = "Microsoft Server Speech Text to Speech Voice (nl-NL, ColetteNeural)";
5994
- } else {
5995
- this.speechConfig.speechSynthesisVoiceName = "Microsoft Server Speech Text to Speech Voice (nl-NL, MaartenNeural)";
5996
- }
5997
- this.speechConfig.speechSynthesisOutputFormat = 8;
6001
+ this.speechConfig.speechSynthesisVoiceName = `Microsoft Server Speech Text to Speech Voice (${this.voice})`;
6002
+ this.speechConfig.speechSynthesisOutputFormat = SpeechSynthesisOutputFormat.Audio24Khz160KBitRateMonoMp3;
5998
6003
  this.player = new SpeakerAudioDestination();
5999
6004
  this.audioConfig = AudioConfig.fromSpeakerOutput(this.player);
6000
6005
  this.synthesizer = new SpeechSynthesizer(this.speechConfig, this.audioConfig);
6001
6006
  this.synthesizer.wordBoundary = (s, e) => {
6002
6007
  this.wordBoundryList.push(e);
6003
6008
  };
6004
- this.player.onAudioEnd = () => {
6009
+ this.player.onAudioEnd = async () => {
6005
6010
  this.stopPlayer();
6006
6011
  if (this.clickedNode.hasAttribute("co-tts.next")) {
6007
- let nextNode = document.getElementById(this.clickedNode.getAttribute("co-tts.next"));
6008
- if (nextNode) {
6012
+ const nextNode = document.getElementById(this.clickedNode.getAttribute("co-tts.next"));
6013
+ if (nextNode && nextNode.attributes.getNamedItem("co-tts.text")) {
6014
+ this.handleWithoutClick(nextNode, nextNode.attributes.getNamedItem("co-tts.text"));
6015
+ } else if (nextNode) {
6009
6016
  nextNode.dispatchEvent(new Event("click"));
6010
6017
  }
6018
+ } else {
6019
+ document.dispatchEvent(new CustomEvent("COAzureTTSFinishedPlaying", {}));
6011
6020
  }
6012
6021
  };
6022
+ this.player.onAudioStart = async () => {
6023
+ document.dispatchEvent(new CustomEvent("COAzureTTSStartedPlaying", {}));
6024
+ };
6013
6025
  this.synthesizer.speakTextAsync(
6014
6026
  this.textToRead,
6015
6027
  () => {
@@ -6022,5 +6034,55 @@ class TextToSpeech {
6022
6034
  }
6023
6035
  );
6024
6036
  }
6037
+ async clearInterval() {
6038
+ clearInterval(this.interval);
6039
+ }
6040
+ async createInterval() {
6041
+ this.interval = setInterval(() => {
6042
+ var _a;
6043
+ if (this.player !== void 0 && this.highlightDiv) {
6044
+ const currentTime = this.player.currentTime;
6045
+ let wordBoundary;
6046
+ for (const e of this.wordBoundryList) {
6047
+ if (currentTime * 1e3 > e.audioOffset / 1e4) {
6048
+ wordBoundary = e;
6049
+ } else {
6050
+ break;
6051
+ }
6052
+ }
6053
+ if (wordBoundary !== void 0) {
6054
+ if (~[".", ",", "!", "?"].indexOf(wordBoundary.text)) {
6055
+ wordBoundary = (_a = this.previousWordBoundary) != null ? _a : void 0;
6056
+ }
6057
+ if (wordBoundary === void 0) {
6058
+ this.highlightDiv.innerHTML = this.originalHighlightDivInnerHTML;
6059
+ } else {
6060
+ if (!this.wordEncounters[wordBoundary.text]) {
6061
+ this.wordEncounters[wordBoundary.text] = 0;
6062
+ }
6063
+ if (this.currentWord !== wordBoundary.text) {
6064
+ this.wordEncounters[wordBoundary.text]++;
6065
+ console.log(this.wordEncounters);
6066
+ this.currentOffset = this.getPosition(
6067
+ this.originalHighlightDivInnerHTML,
6068
+ wordBoundary.text,
6069
+ this.wordEncounters[wordBoundary.text]
6070
+ );
6071
+ this.currentWord = wordBoundary.text;
6072
+ }
6073
+ this.previousWordBoundary = wordBoundary;
6074
+ this.highlightDiv.innerHTML = this.originalHighlightDivInnerHTML.substring(0, this.currentOffset) + "<mark class='co-tts-highlight'>" + wordBoundary.text + "</mark>" + this.originalHighlightDivInnerHTML.substring(this.currentOffset + wordBoundary.wordLength);
6075
+ }
6076
+ } else {
6077
+ this.highlightDiv.innerHTML = this.originalHighlightDivInnerHTML;
6078
+ }
6079
+ }
6080
+ }, 50);
6081
+ }
6082
+ getPosition(string, subString, index) {
6083
+ const regex = new RegExp(`\\b${subString}\\b`, "g");
6084
+ console.log(string.split(regex, index).join(subString), regex, index);
6085
+ return string.split(regex, index).join(subString).length;
6086
+ }
6025
6087
  }
6026
6088
  export { TextToSpeech as default };