d6ab413dcd
CI/CD Pipeline / Deploy Staging (push) Has been skipped
CI/CD Pipeline / Staging E2E Tests (push) Has been skipped
CI/CD Pipeline / Build Production Runtime Images (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Failing after 47h57m37s
CI/CD Pipeline / Validate Code Quality And Tests (push) Failing after 47h57m37s
- 新增 text_splitter.py: 长文本智能分段(句子边界 + 短段合并) - 新增 audio_merger.py: FFmpeg concat 音频合并器 - workflow.py: 分段合成完整流程(同步合并 / 异步轮询 / 失败处理) - tts_synthesis.py: 新增 process_tts_segment_synthesis Celery 任务 - tts.py: 路由层自动识别分段任务并分发到对应 Celery task - 23 个单元测试全部通过,P0 回归测试无退化
71 lines
2.0 KiB
Python
71 lines
2.0 KiB
Python
"""长文本分段工具 — P1 长文本分段合成。
|
|
|
|
将超过阈值的文本按句子边界分段,供 CosyVoice 并发合成后合并。
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
# 中文句子结束符(含全角/半角)
|
|
_SENTENCE_ENDS = frozenset("。!?;\n.!?;")
|
|
|
|
|
|
def split_text(text: str, max_chars: int = 500) -> list[str]:
|
|
"""将文本分段,每段不超过 max_chars 个字符。
|
|
|
|
优先在句子边界(句号、问号、感叹号、换行符)处分段。
|
|
若单个句子超过 max_chars,则在逗号等次级标点处拆分。
|
|
若仍超长,则硬切。
|
|
|
|
Args:
|
|
text: 待分段文本
|
|
max_chars: 每段最大字符数
|
|
|
|
Returns:
|
|
分段列表,每段 ≤ max_chars。文本为空时返回空列表。
|
|
"""
|
|
text = text.strip()
|
|
if not text:
|
|
return []
|
|
if len(text) <= max_chars:
|
|
return [text]
|
|
|
|
segments: list[str] = []
|
|
current = ""
|
|
|
|
for char in text:
|
|
current += char
|
|
if char in _SENTENCE_ENDS and len(current) >= 50:
|
|
# 句子边界且长度合理,切段
|
|
segments.append(current.strip())
|
|
current = ""
|
|
elif len(current) >= max_chars:
|
|
# 达到上限,强制切段
|
|
segments.append(current.strip())
|
|
current = ""
|
|
|
|
if current.strip():
|
|
segments.append(current.strip())
|
|
|
|
# 合并过短的段(< 50 字符且不是最后一段),减少 API 调用次数
|
|
merged: list[str] = []
|
|
buffer = ""
|
|
for seg in segments:
|
|
if buffer:
|
|
combined = buffer + seg
|
|
if len(combined) <= max_chars:
|
|
buffer = combined
|
|
continue
|
|
merged.append(buffer)
|
|
buffer = ""
|
|
if len(seg) < 50:
|
|
buffer = seg
|
|
else:
|
|
merged.append(seg)
|
|
if buffer:
|
|
if merged and len(merged[-1]) + len(buffer) <= max_chars:
|
|
merged[-1] = merged[-1] + buffer
|
|
else:
|
|
merged.append(buffer)
|
|
|
|
return [s for s in merged if s]
|