@siact/sime-x-vue 0.0.17 → 0.0.18
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/sime-x-vue.mjs +29 -7
- package/dist/sime-x-vue.mjs.map +1 -1
- package/dist/sime-x-vue.umd.js +29 -7
- package/dist/sime-x-vue.umd.js.map +1 -1
- package/package.json +1 -1
package/dist/sime-x-vue.mjs
CHANGED
|
@@ -1777,8 +1777,27 @@ function useTTS(getVoiceConfig) {
|
|
|
1777
1777
|
let initPromise = null;
|
|
1778
1778
|
let audioCtx = null;
|
|
1779
1779
|
let sentenceBuffer = "";
|
|
1780
|
-
const
|
|
1780
|
+
const SENTENCE_DELIMITERS = /[。!?;\n!?;]/;
|
|
1781
|
+
const LEADING_WEAK_PUNCTUATION = /^[\s,、;:,.!?。]+/;
|
|
1782
|
+
const TRAILING_SENTENCE_PUNCTUATION = /[。!?.!?;;]$/;
|
|
1783
|
+
const findSentenceBoundary = (text) => {
|
|
1784
|
+
for (let i = 0; i < text.length; i++) {
|
|
1785
|
+
const char = text[i];
|
|
1786
|
+
if (SENTENCE_DELIMITERS.test(char)) {
|
|
1787
|
+
return i;
|
|
1788
|
+
}
|
|
1789
|
+
}
|
|
1790
|
+
return -1;
|
|
1791
|
+
};
|
|
1781
1792
|
const stripMarkdown = (text) => text.replace(/```[\s\S]*?```/g, "").replace(/\|[^\n]*\|/g, "").replace(/#{1,6}\s*/g, "").replace(/\*\*(.*?)\*\*/g, "$1").replace(/\*(.*?)\*/g, "$1").replace(/`([^`]*)`/g, "$1").replace(/\[([^\]]*)\]\([^)]*\)/g, "$1").replace(/^[-*+]\s+/gm, "").replace(/^>\s+/gm, "").replace(/\s*\+\s*/g, "加").replace(/\s*-\s*/g, "减").replace(/\s*×\s*/g, "乘").replace(/\s*÷\s*/g, "除").replace(/\s*=\s*/g, "等于").replace(/(\d)\.(\d)/g, "$1点$2").replace(/\n{2,}/g, "。").replace(/\n/g, ",").trim();
|
|
1793
|
+
const normalizeSpeakText = (text, options) => {
|
|
1794
|
+
const clean = stripMarkdown(text).replace(LEADING_WEAK_PUNCTUATION, "").trim();
|
|
1795
|
+
if (!clean) return "";
|
|
1796
|
+
if (options?.isFinalChunk && !TRAILING_SENTENCE_PUNCTUATION.test(clean)) {
|
|
1797
|
+
return `${clean}。`;
|
|
1798
|
+
}
|
|
1799
|
+
return clean;
|
|
1800
|
+
};
|
|
1782
1801
|
const warmUpAudio = () => {
|
|
1783
1802
|
if (!audioCtx || audioCtx.state === "closed") {
|
|
1784
1803
|
try {
|
|
@@ -1847,7 +1866,7 @@ function useTTS(getVoiceConfig) {
|
|
|
1847
1866
|
return initPromise;
|
|
1848
1867
|
};
|
|
1849
1868
|
const speak = async (text) => {
|
|
1850
|
-
const clean =
|
|
1869
|
+
const clean = normalizeSpeakText(text);
|
|
1851
1870
|
if (!clean.trim()) return;
|
|
1852
1871
|
hasPendingAudio.value = true;
|
|
1853
1872
|
const tts = await ensureInstance();
|
|
@@ -1861,17 +1880,20 @@ function useTTS(getVoiceConfig) {
|
|
|
1861
1880
|
const feed = (delta) => {
|
|
1862
1881
|
sentenceBuffer += delta;
|
|
1863
1882
|
while (true) {
|
|
1864
|
-
const
|
|
1865
|
-
if (
|
|
1866
|
-
const sentence = sentenceBuffer.slice(0,
|
|
1867
|
-
sentenceBuffer = sentenceBuffer.slice(
|
|
1883
|
+
const boundaryIndex = findSentenceBoundary(sentenceBuffer);
|
|
1884
|
+
if (boundaryIndex === -1) break;
|
|
1885
|
+
const sentence = sentenceBuffer.slice(0, boundaryIndex + 1).trim();
|
|
1886
|
+
sentenceBuffer = sentenceBuffer.slice(boundaryIndex + 1);
|
|
1868
1887
|
if (sentence.length > 0) speak(sentence);
|
|
1869
1888
|
}
|
|
1870
1889
|
};
|
|
1871
1890
|
const flush = () => {
|
|
1872
1891
|
const remaining = sentenceBuffer.trim();
|
|
1873
1892
|
sentenceBuffer = "";
|
|
1874
|
-
if (remaining.length > 0)
|
|
1893
|
+
if (remaining.length > 0) {
|
|
1894
|
+
const clean = normalizeSpeakText(remaining, { isFinalChunk: true });
|
|
1895
|
+
if (clean) void speak(clean);
|
|
1896
|
+
}
|
|
1875
1897
|
};
|
|
1876
1898
|
const stop = () => {
|
|
1877
1899
|
sentenceBuffer = "";
|