feat(13-07): integrate SemanticSegmentationEngine into SRTProcessor

- 添加 enable_semantic_segmentation 参数到 SRTProcessor.__init__
- 启用时使用 SemanticSegmentationEngine,禁用时使用 SemanticSegmenter
- AI 不可用时自动降级到规则分段
- 更新 _generate_markdown() 支持带标题的 VideoSegment 输出
- 调整步骤顺序:先加载元数据,再进行语义分段
- 更新 UnifiedSegmentationStrategy.segment() 返回 List[VideoSegment]
- 添加代理方法到 SemanticSegmentationEngine 以保持向后兼容
- 创建全面的集成测试(9 个测试用例)
- 更新现有语义引擎测试以适配新 API

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-22 00:32:14 +08:00
parent a6c0293c01
commit ef4a660faa
4 changed files with 578 additions and 56 deletions
+51 -13
View File
@@ -56,7 +56,7 @@ class SegmentationStrategy(Protocol):
self,
segments: List,
metadata: dict
) -> List[str]:
) -> List[Union[str, 'VideoSegment']]:
"""对字幕分段进行语义分段
Args:
@@ -64,7 +64,7 @@ class SegmentationStrategy(Protocol):
metadata: 视频元数据(title, duration 等)
Returns:
段落文本列表
分段列表(可以是纯文本列表或 VideoSegment 对象列表)
"""
...
@@ -117,7 +117,7 @@ class UnifiedSegmentationStrategy:
self,
segments: List,
metadata: dict
) -> List[str]:
) -> List['VideoSegment']:
"""对字幕分段进行语义分段
使用统一的 LLM Prompt 进行语义分段,不区分视频类型。
@@ -128,12 +128,17 @@ class UnifiedSegmentationStrategy:
metadata: 视频元数据(title, duration 等)
Returns:
段落文本列表
VideoSegment 对象列表(包含标题和内容)
"""
# AI 不可用,直接使用规则分段
if self.ai_client is None:
logger.info("AI client unavailable, using fallback segmenter")
return self.fallback_segmenter.segment(segments)
# 将规则分段结果转换为 VideoSegment 格式(无标题)
paragraphs = self.fallback_segmenter.segment(segments)
return [
VideoSegment(title=None, content=para, start_index=0, end_index=0)
for para in paragraphs
]
# 合并字幕文本
content = " ".join(seg.text for seg in segments)
@@ -158,15 +163,17 @@ class UnifiedSegmentationStrategy:
fallback_segments=segments
)
# 转换为段落文本
paragraphs = [seg.content for seg in video_segments]
logger.info(f"LLM semantic segmentation: {len(paragraphs)} paragraphs")
return paragraphs
logger.info(f"LLM semantic segmentation: {len(video_segments)} segments")
return video_segments
except Exception as e:
logger.error(f"LLM segmentation failed: {e}, using fallback")
return self.fallback_segmenter.segment(segments)
# 将规则分段结果转换为 VideoSegment 格式(无标题)
paragraphs = self.fallback_segmenter.segment(segments)
return [
VideoSegment(title=None, content=para, start_index=0, end_index=0)
for para in paragraphs
]
def _build_prompt(self, content: str, metadata: dict) -> str:
"""构建语义分段 Prompt
@@ -535,11 +542,42 @@ class SemanticSegmentationEngine:
f"{self.strategy.__class__.__name__}"
)
def _infer_video_type(self, metadata: dict) -> str:
"""从元数据推断视频类型(代理到策略)
Args:
metadata: 视频元数据
Returns:
推断出的视频类型
"""
# 如果策略有 _infer_video_type 方法,使用它
if hasattr(self.strategy, '_infer_video_type'):
return self.strategy._infer_video_type(metadata)
# 否则返回默认类型
return DEFAULT_VIDEO_TYPE
def _build_prompt(self, content: str, metadata: dict) -> str:
"""构建 Prompt(代理到策略)
Args:
content: 字幕内容
metadata: 视频元数据
Returns:
构建好的 Prompt
"""
# 如果策略有 _build_prompt 方法,使用它
if hasattr(self.strategy, '_build_prompt'):
return self.strategy._build_prompt(content, metadata)
# 否则返回基本 prompt
return f"Content: {content}\nMetadata: {metadata}"
def segment(
self,
segments: List,
metadata: dict
) -> List[str]:
) -> List['VideoSegment']:
"""对字幕分段进行语义分段
使用当前配置的策略进行分段。
@@ -549,6 +587,6 @@ class SemanticSegmentationEngine:
metadata: 视频元数据(title, duration 等)
Returns:
段落文本列表
VideoSegment 对象列表(包含标题和内容)
"""
return self.strategy.segment(segments, metadata)