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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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 };