@flexem/chat-box 1.0.11 → 1.0.12
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.
|
@@ -746,13 +746,22 @@ function finishStreamingContent(id, fullContent) {
|
|
|
746
746
|
|
|
747
747
|
streamingComplete = true;
|
|
748
748
|
|
|
749
|
-
//
|
|
749
|
+
// 将剩余内容加入队列(需要分段,避免超过 TTS 限制)
|
|
750
750
|
if (fullContent && fullContent.length > lastPlayedLength) {
|
|
751
751
|
const remaining = fullContent.substring(lastPlayedLength).trim();
|
|
752
752
|
if (remaining) {
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
753
|
+
// 清理文本后再分段,确保每段不超过 150 字符
|
|
754
|
+
const cleanedRemaining = cleanTextForTTS(remaining);
|
|
755
|
+
if (cleanedRemaining) {
|
|
756
|
+
const segments = splitTextIntoSegments(cleanedRemaining, 150);
|
|
757
|
+
console.log('剩余内容分段数:', segments.length);
|
|
758
|
+
segments.forEach((segment) => {
|
|
759
|
+
const index = currentSegmentIndex++;
|
|
760
|
+
console.log('添加剩余内容片段到队列, index:', index, 'length:', segment.length);
|
|
761
|
+
// 注意:这里的 text 已经是清理过的,后续不需要再清理
|
|
762
|
+
textQueue.push({ index, text: segment, preCleaned: true });
|
|
763
|
+
});
|
|
764
|
+
}
|
|
756
765
|
lastPlayedLength = fullContent.length;
|
|
757
766
|
}
|
|
758
767
|
}
|
|
@@ -786,38 +795,61 @@ function processSynthesisQueue() {
|
|
|
786
795
|
const item = textQueue.shift();
|
|
787
796
|
isSynthesizing = true;
|
|
788
797
|
|
|
789
|
-
console.log('开始合成语音, index:', item.index);
|
|
798
|
+
console.log('开始合成语音, index:', item.index, 'preCleaned:', !!item.preCleaned);
|
|
790
799
|
|
|
791
|
-
//
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
return; // 已停止,忽略结果
|
|
797
|
-
}
|
|
800
|
+
// 定义成功和失败回调
|
|
801
|
+
const onSuccess = (res) => {
|
|
802
|
+
if (!isStreamingMode) {
|
|
803
|
+
return; // 已停止,忽略结果
|
|
804
|
+
}
|
|
798
805
|
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
806
|
+
console.log('语音合成完成, index:', item.index);
|
|
807
|
+
// 将合成结果加入音频队列(保持顺序)
|
|
808
|
+
audioQueue.push({ index: item.index, src: res.src });
|
|
809
|
+
// 按 index 排序,确保顺序
|
|
810
|
+
audioQueue.sort((a, b) => a.index - b.index);
|
|
804
811
|
|
|
805
|
-
|
|
812
|
+
isSynthesizing = false;
|
|
806
813
|
|
|
807
|
-
|
|
808
|
-
|
|
814
|
+
// 继续合成下一个
|
|
815
|
+
processSynthesisQueue();
|
|
809
816
|
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
onError: (err) => {
|
|
814
|
-
console.error('语音合成失败, index:', item.index, err);
|
|
815
|
-
isSynthesizing = false;
|
|
817
|
+
// 尝试播放
|
|
818
|
+
playNextAudio();
|
|
819
|
+
};
|
|
816
820
|
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
+
const onError = (err) => {
|
|
822
|
+
console.error('语音合成失败, index:', item.index, err);
|
|
823
|
+
isSynthesizing = false;
|
|
824
|
+
|
|
825
|
+
// 标记该片段合成失败,需要跳过
|
|
826
|
+
// 将一个占位符加入 audioQueue,标记为失败
|
|
827
|
+
audioQueue.push({ index: item.index, src: null, failed: true });
|
|
828
|
+
audioQueue.sort((a, b) => a.index - b.index);
|
|
829
|
+
|
|
830
|
+
// 继续合成下一个
|
|
831
|
+
processSynthesisQueue();
|
|
832
|
+
|
|
833
|
+
// 尝试播放(会跳过失败的片段)
|
|
834
|
+
playNextAudio();
|
|
835
|
+
};
|
|
836
|
+
|
|
837
|
+
// 根据是否预清理过选择合成方式
|
|
838
|
+
if (item.preCleaned) {
|
|
839
|
+
// 已经清理过的文本,直接调用原始 TTS 函数
|
|
840
|
+
textToSpeechRaw({
|
|
841
|
+
content: item.text,
|
|
842
|
+
onSuccess,
|
|
843
|
+
onError
|
|
844
|
+
});
|
|
845
|
+
} else {
|
|
846
|
+
// 未清理的文本,调用会清理和截断的 TTS 函数
|
|
847
|
+
textToSpeech({
|
|
848
|
+
content: item.text,
|
|
849
|
+
onSuccess,
|
|
850
|
+
onError
|
|
851
|
+
});
|
|
852
|
+
}
|
|
821
853
|
}
|
|
822
854
|
|
|
823
855
|
/**
|
|
@@ -854,11 +886,19 @@ function playNextAudio() {
|
|
|
854
886
|
return;
|
|
855
887
|
}
|
|
856
888
|
|
|
857
|
-
//
|
|
889
|
+
// 取出音频
|
|
858
890
|
const audio = audioQueue.splice(audioIndex, 1)[0];
|
|
859
|
-
isPlayingAudio = true;
|
|
860
891
|
nextPlayIndex++;
|
|
861
892
|
|
|
893
|
+
// 如果该片段合成失败,跳过并继续播放下一个
|
|
894
|
+
if (audio.failed) {
|
|
895
|
+
console.log('跳过合成失败的片段, index:', audio.index);
|
|
896
|
+
playNextAudio();
|
|
897
|
+
return;
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
isPlayingAudio = true;
|
|
901
|
+
|
|
862
902
|
console.log('播放语音片段, index:', audio.index);
|
|
863
903
|
|
|
864
904
|
const player = initAudioPlayer();
|