Files
banban/talkingq-url/utils/text_splitter.py
2026-03-24 15:04:36 +08:00

146 lines
5.2 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import re
SENTENCE_ENDINGS = set("。!?!?;:.。\n")
PUNCTUATION_MARKS = set('。!?!?.,;:~…—_\'"""》《)》《<>()[]{}【】\'、~~¡¿äöüßáéíóúüñç\n')
APOSTROPHE_SUFFIXES = {'s', 't', 've', 'll', 're', 'd', 'm'}
LANGUAGE_CONTRACTIONS = {
'fr': ["l'", "d'", "s'", "qu'", "c'", "j'", "n'", "m'", "t'", "jusqu'"],
'de': ["geht's", "gibt's"],
'es': ["el-", "del", "al"],
'ms': ["-lah", "-kah", "-nya"]
}
def is_numbered_list_item(text):
pattern = r"^\s*\d+\.\s"
return bool(re.search(pattern, text))
def split_into_sentences(text):
return _custom_split_sentences(text)
def _custom_split_sentences(text):
text = re.sub(r"([。!?!?;])", r"\1\n", text)
sentences = []
current_sentence = ""
i = 0
while i < len(text):
current_sentence += text[i]
if text[i] in SENTENCE_ENDINGS and not is_special_context(text, i):
if current_sentence.strip():
sentences.append(current_sentence)
current_sentence = ""
i += 1
if current_sentence.strip():
sentences.append(current_sentence)
merged_sentences = []
temp = ""
for s in sentences:
s_stripped = s.strip()
if len(s_stripped) < 5 and not any(p in s for p in "。!?!?"):
temp += s
else:
if temp:
merged_sentences.append(temp + s)
temp = ""
else:
merged_sentences.append(s)
if temp:
merged_sentences.append(temp)
final_sentences = []
for idx, sentence in enumerate(merged_sentences):
sentence_start = sentence.strip()
if idx > 0:
prev_sentence_end = merged_sentences[idx-1].strip()
if (sentence_start.startswith("s ") and prev_sentence_end.endswith("'")) or \
any(sentence_start.startswith(suffix + " ") for suffix in APOSTROPHE_SUFFIXES) and prev_sentence_end.endswith("'"):
final_sentences[-1] += sentence
continue
if any(sentence_start.startswith(contraction) for contraction in LANGUAGE_CONTRACTIONS['fr']):
final_sentences[-1] += sentence
continue
if (any(prev_sentence_end.endswith(contraction) for contraction in LANGUAGE_CONTRACTIONS['de']) or
any(sentence_start.startswith(contraction) for contraction in LANGUAGE_CONTRACTIONS['es']) or
any(prev_sentence_end.endswith(contraction) for contraction in LANGUAGE_CONTRACTIONS['ms'])):
final_sentences[-1] += sentence
continue
if sentence_start.startswith("¿") or sentence_start.startswith("¡"):
final_sentences.append(sentence)
continue
final_sentences.append(sentence)
return final_sentences
def is_special_context(text, pos):
"""判断是否是特殊上下文,不应该在此处断句"""
if text[pos] == "." and pos > 0 and pos < len(text) - 1:
if text[pos - 1].isdigit() and text[pos + 1].isdigit():
return True
if text[pos] == "'" and pos > 0 and pos < len(text) - 1:
if text[pos - 1].isalpha(): # 前面是字母
for suffix in APOSTROPHE_SUFFIXES:
if pos + len(suffix) <= len(text) and text[pos+1:pos+1+len(suffix)] == suffix:
if pos + len(suffix) + 1 >= len(text) or not text[pos+1+len(suffix)].isalpha():
return True
if text[pos] == "." and pos > 0 and pos < len(text) - 2:
if text[pos - 1].isupper() and text[pos + 1].isupper():
return True
if text[pos] == "." and pos > 0 and pos < len(text) - 1:
if not text[pos - 1].isspace() and not text[pos + 1].isspace():
left_context = text[max(0, pos-15):pos]
if "www." in left_context or "http" in left_context or "@" in left_context:
return True
if text[pos] == "." and pos > 0 and pos < len(text) - 1:
if pos + 2 < len(text) and text[pos:pos+3] == "...":
return True
if text[pos] == "'" and pos > 0 and pos < len(text) - 1:
if pos > 1 and text[pos-2:pos+1] in ["l'", "d'", "c'", "j'", "n'", "m'", "t'"]:
return True
if text[pos] == "." and pos > 0:
if pos >= 3 and text[pos-3:pos] in ["bzw", "usw", "etc"]:
return True
if text[pos] in "¿¡" and pos < len(text) - 1:
return True
if text[pos] == "-" and pos > 0 and pos < len(text) - 2:
if text[pos+1:pos+4] in ["lah", "kah", "nya"]:
return True
return False
def should_skip_tts(text_chunk):
"""判断一段文本是否应该跳过TTS处理"""
if not text_chunk.strip():
return True
if is_numbered_list_item(text_chunk) and len(text_chunk.strip()) <= 5:
return True
if all(c in PUNCTUATION_MARKS for c in text_chunk.strip()):
return True
if len(text_chunk.strip()) <= 2 and not any(c.isalnum() for c in text_chunk):
return True
return False