@creativeorange/azure-text-to-speech 2.1.1 → 2.2.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/dist/co-azure-tts.es.js +158 -0
- package/dist/co-azure-tts.umd.js +7 -7
- package/package.json +1 -1
- package/src/TextToSpeech.ts +192 -0
package/dist/co-azure-tts.es.js
CHANGED
|
@@ -8457,6 +8457,9 @@ class TextToSpeech {
|
|
|
8457
8457
|
__publicField(this, "wordBoundaryOffset", 0);
|
|
8458
8458
|
__publicField(this, "prevTextOffset", 0);
|
|
8459
8459
|
__publicField(this, "url", "");
|
|
8460
|
+
__publicField(this, "prefetchedAudio", /* @__PURE__ */ new Map());
|
|
8461
|
+
__publicField(this, "prefetchPromises", /* @__PURE__ */ new Map());
|
|
8462
|
+
__publicField(this, "activePrefetchedAudioUrl", "");
|
|
8460
8463
|
this.key = key;
|
|
8461
8464
|
this.region = region;
|
|
8462
8465
|
this.voice = voice;
|
|
@@ -8469,14 +8472,17 @@ class TextToSpeech {
|
|
|
8469
8472
|
}
|
|
8470
8473
|
setVoice(voice) {
|
|
8471
8474
|
this.voice = voice;
|
|
8475
|
+
this.clearPrefetchedAudio();
|
|
8472
8476
|
return this;
|
|
8473
8477
|
}
|
|
8474
8478
|
setRate(rate) {
|
|
8475
8479
|
this.rate = rate;
|
|
8480
|
+
this.clearPrefetchedAudio();
|
|
8476
8481
|
return this;
|
|
8477
8482
|
}
|
|
8478
8483
|
setPitch(pitch) {
|
|
8479
8484
|
this.pitch = pitch;
|
|
8485
|
+
this.clearPrefetchedAudio();
|
|
8480
8486
|
return this;
|
|
8481
8487
|
}
|
|
8482
8488
|
async registerBindings(node) {
|
|
@@ -8627,6 +8633,10 @@ class TextToSpeech {
|
|
|
8627
8633
|
if (this.player !== void 0) {
|
|
8628
8634
|
this.player.pause();
|
|
8629
8635
|
}
|
|
8636
|
+
if (this.activePrefetchedAudioUrl !== "") {
|
|
8637
|
+
URL.revokeObjectURL(this.activePrefetchedAudioUrl);
|
|
8638
|
+
this.activePrefetchedAudioUrl = "";
|
|
8639
|
+
}
|
|
8630
8640
|
this.player = void 0;
|
|
8631
8641
|
this.highlightDiv = void 0;
|
|
8632
8642
|
this.prevTextOffset = 0;
|
|
@@ -8645,6 +8655,9 @@ class TextToSpeech {
|
|
|
8645
8655
|
this.stopPlayer();
|
|
8646
8656
|
if (this.clickedNode.hasAttribute("co-tts.next")) {
|
|
8647
8657
|
const nextNode = document.getElementById(this.clickedNode.getAttribute("co-tts.next"));
|
|
8658
|
+
if (nextNode && await this.playPrefetchedNode(nextNode)) {
|
|
8659
|
+
return;
|
|
8660
|
+
}
|
|
8648
8661
|
if (nextNode && nextNode.attributes.getNamedItem("co-tts.text")) {
|
|
8649
8662
|
this.handleWithoutClick(nextNode, nextNode.attributes.getNamedItem("co-tts.text"));
|
|
8650
8663
|
} else if (nextNode) {
|
|
@@ -8657,6 +8670,7 @@ class TextToSpeech {
|
|
|
8657
8670
|
this.player.onAudioStart = async () => {
|
|
8658
8671
|
document.dispatchEvent(new CustomEvent("COAzureTTSStartedPlaying", {}));
|
|
8659
8672
|
};
|
|
8673
|
+
this.prefetchNextNode(this.clickedNode);
|
|
8660
8674
|
this.synthesizer.speakSsmlAsync(
|
|
8661
8675
|
this.buildSSML(this.textToRead),
|
|
8662
8676
|
() => {
|
|
@@ -8669,6 +8683,150 @@ class TextToSpeech {
|
|
|
8669
8683
|
}
|
|
8670
8684
|
);
|
|
8671
8685
|
}
|
|
8686
|
+
getNodeText(node, attr) {
|
|
8687
|
+
var _a;
|
|
8688
|
+
if (attr && attr.value !== "") {
|
|
8689
|
+
return attr.value;
|
|
8690
|
+
}
|
|
8691
|
+
if (node.hasAttribute("co-tts.text") && node.getAttribute("co-tts.text") !== "") {
|
|
8692
|
+
return (_a = node.getAttribute("co-tts.text")) != null ? _a : "";
|
|
8693
|
+
}
|
|
8694
|
+
return node.innerText;
|
|
8695
|
+
}
|
|
8696
|
+
getPrefetchKey(node, text) {
|
|
8697
|
+
return [
|
|
8698
|
+
node.id,
|
|
8699
|
+
text,
|
|
8700
|
+
this.voice,
|
|
8701
|
+
this.rate,
|
|
8702
|
+
this.pitch,
|
|
8703
|
+
this.url
|
|
8704
|
+
].join("|");
|
|
8705
|
+
}
|
|
8706
|
+
clearPrefetchedAudio() {
|
|
8707
|
+
this.prefetchedAudio.forEach((prefetch) => {
|
|
8708
|
+
if (prefetch.url) {
|
|
8709
|
+
URL.revokeObjectURL(prefetch.url);
|
|
8710
|
+
}
|
|
8711
|
+
});
|
|
8712
|
+
this.prefetchedAudio.clear();
|
|
8713
|
+
this.prefetchPromises.clear();
|
|
8714
|
+
}
|
|
8715
|
+
async prefetchNextNode(node) {
|
|
8716
|
+
var _a;
|
|
8717
|
+
if (!node || !node.hasAttribute("co-tts.next")) {
|
|
8718
|
+
return;
|
|
8719
|
+
}
|
|
8720
|
+
const nextNode = document.getElementById(node.getAttribute("co-tts.next"));
|
|
8721
|
+
if (!nextNode) {
|
|
8722
|
+
return;
|
|
8723
|
+
}
|
|
8724
|
+
const attr = (_a = nextNode.attributes.getNamedItem("co-tts.text")) != null ? _a : nextNode.attributes.getNamedItem("co-tts");
|
|
8725
|
+
const text = this.getNodeText(nextNode, attr);
|
|
8726
|
+
if (text === "") {
|
|
8727
|
+
return;
|
|
8728
|
+
}
|
|
8729
|
+
const key = this.getPrefetchKey(nextNode, text);
|
|
8730
|
+
if (this.prefetchedAudio.has(key) || this.prefetchPromises.has(key)) {
|
|
8731
|
+
return;
|
|
8732
|
+
}
|
|
8733
|
+
const speechConfig = SpeechConfig.fromSubscription(this.key, this.region);
|
|
8734
|
+
speechConfig.speechSynthesisVoiceName = `Microsoft Server Speech Text to Speech Voice (${this.voice})`;
|
|
8735
|
+
speechConfig.speechSynthesisOutputFormat = SpeechSynthesisOutputFormat.Audio24Khz160KBitRateMonoMp3;
|
|
8736
|
+
const synthesizer = new SpeechSynthesizer(speechConfig, null);
|
|
8737
|
+
const wordBoundryList = [];
|
|
8738
|
+
synthesizer.wordBoundary = (s, e) => {
|
|
8739
|
+
wordBoundryList.push(e);
|
|
8740
|
+
};
|
|
8741
|
+
const prefetchPromise = new Promise((resolve) => {
|
|
8742
|
+
synthesizer.speakSsmlAsync(
|
|
8743
|
+
this.buildSSML(text),
|
|
8744
|
+
(result) => {
|
|
8745
|
+
synthesizer.close();
|
|
8746
|
+
if (!(result == null ? void 0 : result.audioData)) {
|
|
8747
|
+
resolve(null);
|
|
8748
|
+
return;
|
|
8749
|
+
}
|
|
8750
|
+
const blob = new Blob([result.audioData], { type: "audio/mpeg" });
|
|
8751
|
+
const url = URL.createObjectURL(blob);
|
|
8752
|
+
const prefetch = {
|
|
8753
|
+
key,
|
|
8754
|
+
nodeId: nextNode.id,
|
|
8755
|
+
text,
|
|
8756
|
+
url,
|
|
8757
|
+
wordBoundryList
|
|
8758
|
+
};
|
|
8759
|
+
this.prefetchedAudio.set(key, prefetch);
|
|
8760
|
+
resolve(prefetch);
|
|
8761
|
+
},
|
|
8762
|
+
() => {
|
|
8763
|
+
synthesizer.close();
|
|
8764
|
+
resolve(null);
|
|
8765
|
+
}
|
|
8766
|
+
);
|
|
8767
|
+
}).finally(() => {
|
|
8768
|
+
this.prefetchPromises.delete(key);
|
|
8769
|
+
});
|
|
8770
|
+
this.prefetchPromises.set(key, prefetchPromise);
|
|
8771
|
+
}
|
|
8772
|
+
async playPrefetchedNode(node) {
|
|
8773
|
+
var _a, _b, _c;
|
|
8774
|
+
const attr = (_a = node.attributes.getNamedItem("co-tts.text")) != null ? _a : node.attributes.getNamedItem("co-tts");
|
|
8775
|
+
const text = this.getNodeText(node, attr);
|
|
8776
|
+
const key = this.getPrefetchKey(node, text);
|
|
8777
|
+
const prefetch = (_b = this.prefetchedAudio.get(key)) != null ? _b : await this.prefetchPromises.get(key);
|
|
8778
|
+
if (!prefetch) {
|
|
8779
|
+
return false;
|
|
8780
|
+
}
|
|
8781
|
+
this.prefetchedAudio.delete(key);
|
|
8782
|
+
this.clickedNode = node;
|
|
8783
|
+
this.textToRead = prefetch.text;
|
|
8784
|
+
this.wordBoundryList = prefetch.wordBoundryList;
|
|
8785
|
+
this.wordEncounters = [];
|
|
8786
|
+
this.previousWordBoundary = void 0;
|
|
8787
|
+
this.prevTextOffset = 0;
|
|
8788
|
+
this.currentWord = "";
|
|
8789
|
+
this.currentOffset = 0;
|
|
8790
|
+
this.wordBoundaryOffset = 0;
|
|
8791
|
+
if (node.hasAttribute("co-tts.highlight")) {
|
|
8792
|
+
if (((_c = node.attributes.getNamedItem("co-tts.highlight")) == null ? void 0 : _c.value) !== "") {
|
|
8793
|
+
const newReferenceDiv = document.getElementById(node.attributes.getNamedItem("co-tts.highlight").value);
|
|
8794
|
+
this.highlightDiv = newReferenceDiv;
|
|
8795
|
+
if (newReferenceDiv !== null) {
|
|
8796
|
+
this.originalHighlightDivInnerHTML = newReferenceDiv.innerHTML;
|
|
8797
|
+
}
|
|
8798
|
+
} else {
|
|
8799
|
+
this.highlightDiv = node;
|
|
8800
|
+
this.originalHighlightDivInnerHTML = node.innerHTML;
|
|
8801
|
+
}
|
|
8802
|
+
}
|
|
8803
|
+
await this.createInterval();
|
|
8804
|
+
const audio = new Audio(prefetch.url);
|
|
8805
|
+
this.activePrefetchedAudioUrl = prefetch.url;
|
|
8806
|
+
this.player = audio;
|
|
8807
|
+
audio.addEventListener("play", () => {
|
|
8808
|
+
document.dispatchEvent(new CustomEvent("COAzureTTSStartedPlaying", {}));
|
|
8809
|
+
}, { once: true });
|
|
8810
|
+
audio.addEventListener("ended", async () => {
|
|
8811
|
+
this.stopPlayer();
|
|
8812
|
+
if (this.clickedNode.hasAttribute("co-tts.next")) {
|
|
8813
|
+
const nextNode = document.getElementById(this.clickedNode.getAttribute("co-tts.next"));
|
|
8814
|
+
if (nextNode && await this.playPrefetchedNode(nextNode)) {
|
|
8815
|
+
return;
|
|
8816
|
+
}
|
|
8817
|
+
if (nextNode && nextNode.attributes.getNamedItem("co-tts.text")) {
|
|
8818
|
+
this.handleWithoutClick(nextNode, nextNode.attributes.getNamedItem("co-tts.text"));
|
|
8819
|
+
} else if (nextNode) {
|
|
8820
|
+
nextNode.dispatchEvent(new Event("click"));
|
|
8821
|
+
}
|
|
8822
|
+
} else {
|
|
8823
|
+
document.dispatchEvent(new CustomEvent("COAzureTTSFinishedPlaying", {}));
|
|
8824
|
+
}
|
|
8825
|
+
}, { once: true });
|
|
8826
|
+
this.prefetchNextNode(node);
|
|
8827
|
+
await audio.play();
|
|
8828
|
+
return true;
|
|
8829
|
+
}
|
|
8672
8830
|
async clearInterval() {
|
|
8673
8831
|
clearInterval(this.interval);
|
|
8674
8832
|
}
|