fix: 修复命令行工具

This commit is contained in:
root
2025-07-12 13:44:57 +08:00
parent 81035caf0e
commit 31de1e5a4d
30 changed files with 2728 additions and 1755 deletions

View File

@@ -0,0 +1,15 @@
#!/usr/bin/env python3
"""
Scene Detection Workflows
场景检测工作流
导出所有工作流类
"""
from .workflow_manager import SceneDetectionWorkflowManager
from .workflow_nodes import WorkflowNodes
__all__ = [
"SceneDetectionWorkflowManager",
"WorkflowNodes"
]

View File

@@ -0,0 +1,176 @@
#!/usr/bin/env python3
"""
Workflow Manager
工作流管理器
"""
import time
from pathlib import Path
from typing import Dict, Any, Optional, Literal
from python_core.utils.logger import logger
from python_core.utils.jsonrpc_enhanced import EnhancedJSONRPCResponse
from ..types import SceneDetectionWorkflowState, DetectorType, OutputFormat
from .workflow_nodes import WorkflowNodes
class SceneDetectionWorkflowManager:
"""场景检测工作流管理器"""
def __init__(self):
self.nodes = WorkflowNodes()
self.workflow = None
def create_detection_workflow(self):
"""创建检测工作流"""
try:
from langgraph.graph import StateGraph, END
# 创建状态图
workflow = StateGraph(SceneDetectionWorkflowState)
# 添加节点
workflow.add_node("validate", self.nodes.validate_input)
workflow.add_node("extract_info", self.nodes.extract_video_info)
workflow.add_node("detect", self.nodes.detect_scenes)
workflow.add_node("analyze", self.nodes.analyze_with_ai)
workflow.add_node("finalize", self.nodes.finalize_results)
workflow.add_node("error", self.nodes.handle_error)
# 设置入口点
workflow.set_entry_point("validate")
# 添加条件边
workflow.add_conditional_edges(
"validate",
self._route_next_step,
{
"extract_info": "extract_info",
"error": "error"
}
)
workflow.add_conditional_edges(
"extract_info",
self._route_next_step,
{
"detect": "detect",
"error": "error"
}
)
workflow.add_conditional_edges(
"detect",
self._route_next_step,
{
"analyze": "analyze",
"error": "error"
}
)
workflow.add_conditional_edges(
"analyze",
self._route_next_step,
{
"finalize": "finalize",
"error": "error"
}
)
# 结束节点
workflow.add_edge("finalize", END)
workflow.add_edge("error", END)
# 编译工作流
self.workflow = workflow.compile()
return self.workflow
except ImportError:
logger.error("❌ LangGraph未安装无法创建工作流")
return None
except Exception as e:
logger.error(f"❌ 创建工作流失败: {e}")
return None
def _route_next_step(self, state: SceneDetectionWorkflowState) -> Literal["extract_info", "detect", "analyze", "finalize", "error"]:
"""路由下一步"""
if state.errors:
return "error"
elif state.current_stage == "validated":
return "extract_info"
elif state.current_stage == "info_extracted":
return "detect"
elif state.current_stage == "scenes_detected":
return "analyze"
elif state.current_stage in ["ai_analyzed", "analysis_skipped", "analysis_failed"]:
return "finalize"
else:
return "error"
def detect_with_workflow(self, video_path: Path, detector_type: DetectorType = DetectorType.CONTENT,
threshold: float = 30.0, min_scene_length: float = 1.0,
output_path: Optional[Path] = None, output_format: OutputFormat = OutputFormat.JSON,
enable_ai_analysis: bool = True, request_id: Optional[str] = None) -> Dict[str, Any]:
"""使用LangGraph工作流进行场景检测"""
# 创建工作流
workflow = self.create_detection_workflow()
if not workflow:
raise Exception("无法创建工作流")
# 初始化状态
initial_state = SceneDetectionWorkflowState(
video_path=str(video_path),
detector_type=detector_type.value,
threshold=threshold,
min_scene_length=min_scene_length,
output_path=str(output_path) if output_path else None,
output_format=output_format.value,
enable_ai_analysis=enable_ai_analysis,
request_id=request_id,
enable_jsonrpc=request_id is not None # 如果有request_id就启用JSON-RPC
)
# 执行工作流
config = {"configurable": {"thread_id": f"detection_{int(time.time())}"}}
try:
final_state = workflow.invoke(initial_state, config)
# 如果是JSON-RPC模式结果已经通过JSON-RPC发送了
if request_id is not None:
# JSON-RPC模式结果已经在工作流节点中发送
# 这里返回简化的状态信息供内部使用
return {
"jsonrpc_mode": True,
"request_id": request_id,
"workflow_state": final_state.get("current_stage"),
"final_result_sent": True
}
else:
# 非JSON-RPC模式返回完整结果
return {
"detection_result": final_state.get("detection_result"),
"ai_analysis": final_state.get("ai_analysis"),
"video_info": final_state.get("video_info"),
"workflow_state": final_state.get("current_stage"),
"errors": final_state.get("errors", [])
}
except Exception as e:
error_msg = f"工作流执行失败: {e}"
# 如果是JSON-RPC模式发送错误响应
if request_id is not None:
handler = EnhancedJSONRPCResponse(request_id)
handler.error(-32603, error_msg, {"exception": str(e)})
return {
"jsonrpc_mode": True,
"request_id": request_id,
"error_sent": True,
"error": error_msg
}
else:
# 非JSON-RPC模式抛出异常
logger.error(f"{error_msg}")
raise

View File

@@ -0,0 +1,242 @@
#!/usr/bin/env python3
"""
Workflow Nodes
工作流节点定义
"""
from pathlib import Path
from typing import Dict, Any
from dataclasses import asdict
from python_core.utils.logger import logger
from python_core.utils.jsonrpc_enhanced import ProgressLevel
from ..types import SceneDetectionWorkflowState, DetectorType
from ..services import SceneDetectorService, VideoInfoService, AIAnalysisService
class WorkflowNodes:
"""工作流节点集合"""
def __init__(self):
self.detector_service = SceneDetectorService()
self.video_info_service = VideoInfoService()
self.ai_analysis_service = AIAnalysisService()
def validate_input(self, state: SceneDetectionWorkflowState) -> Dict[str, Any]:
"""验证输入参数"""
state.send_progress("validate", "🔍 验证输入参数...", ProgressLevel.INFO)
video_path = Path(state.video_path)
errors = []
# 验证文件存在
if not video_path.exists():
errors.append(f"视频文件不存在: {video_path}")
state.send_progress("validate", f"❌ 文件不存在: {video_path}", ProgressLevel.ERROR)
# 验证文件格式
if video_path.suffix.lower() not in self.detector_service.supported_formats:
errors.append(f"不支持的文件格式: {video_path.suffix}")
state.send_progress("validate", f"❌ 不支持的格式: {video_path.suffix}", ProgressLevel.ERROR)
# 验证参数范围
if not (0 <= state.threshold <= 100):
errors.append(f"阈值超出范围 (0-100): {state.threshold}")
state.send_progress("validate", f"❌ 阈值超出范围: {state.threshold}", ProgressLevel.ERROR)
if state.min_scene_length < 0:
errors.append(f"最小场景长度不能为负数: {state.min_scene_length}")
state.send_progress("validate", f"❌ 最小场景长度无效: {state.min_scene_length}", ProgressLevel.ERROR)
if not errors:
state.send_progress("validate", "✅ 输入参数验证通过", ProgressLevel.SUCCESS)
return {
"current_stage": "validated" if not errors else "error",
"progress": 1,
"errors": errors
}
def extract_video_info(self, state: SceneDetectionWorkflowState) -> Dict[str, Any]:
"""提取视频信息"""
state.send_progress("extract_info", "📊 提取视频信息...", ProgressLevel.INFO)
try:
video_info = self.video_info_service.extract_video_info(Path(state.video_path))
state.send_progress("extract_info",
f"📹 视频信息: {video_info['resolution']}, {video_info['fps']:.2f}fps, {video_info['duration']:.2f}s",
ProgressLevel.SUCCESS,
{"video_info": video_info}
)
return {
"current_stage": "info_extracted",
"progress": 2,
"video_info": video_info
}
except Exception as e:
error_msg = f"提取视频信息失败: {e}"
state.send_progress("extract_info", f"{error_msg}", ProgressLevel.ERROR)
return {
"current_stage": "error",
"errors": state.errors + [error_msg]
}
def detect_scenes(self, state: SceneDetectionWorkflowState) -> Dict[str, Any]:
"""执行场景检测"""
state.send_progress("detect", "🎯 执行场景检测...", ProgressLevel.INFO)
try:
result = self.detector_service.detect_scenes(
Path(state.video_path),
DetectorType(state.detector_type),
state.threshold,
state.min_scene_length
)
state.send_progress("detect",
f"✅ 检测完成: {result.total_scenes} 个场景,耗时 {result.detection_time:.2f}",
ProgressLevel.SUCCESS,
{
"total_scenes": result.total_scenes,
"detection_time": result.detection_time,
"total_duration": result.total_duration
}
)
return {
"current_stage": "scenes_detected",
"progress": 3,
"detection_result": result,
"processed_scenes": result.scenes
}
except Exception as e:
error_msg = f"场景检测失败: {e}"
state.send_progress("detect", f"{error_msg}", ProgressLevel.ERROR)
return {
"current_stage": "error",
"errors": state.errors + [error_msg]
}
def analyze_with_ai(self, state: SceneDetectionWorkflowState) -> Dict[str, Any]:
"""AI分析场景结果"""
if not self.ai_analysis_service.ai_enabled or not state.enable_ai_analysis:
state.send_progress("analyze", "⚠️ AI分析已禁用跳过此步骤", ProgressLevel.WARNING)
return {
"current_stage": "analysis_skipped",
"progress": 4,
"ai_analysis": "AI分析已禁用"
}
state.send_progress("analyze", "🧠 AI分析场景结果...", ProgressLevel.INFO)
try:
state.send_progress("analyze", "🤖 正在调用AI分析服务...", ProgressLevel.INFO)
analysis = self.ai_analysis_service.analyze_detection_result(
state.detection_result,
state.video_info
)
state.send_progress("analyze", "✅ AI分析完成", ProgressLevel.SUCCESS,
{"analysis_length": len(analysis)})
return {
"current_stage": "ai_analyzed",
"progress": 4,
"ai_analysis": analysis
}
except Exception as e:
error_msg = f"AI分析失败: {e}"
state.send_progress("analyze", f"⚠️ {error_msg}", ProgressLevel.WARNING)
return {
"current_stage": "analysis_failed",
"progress": 4,
"ai_analysis": error_msg
}
def finalize_results(self, state: SceneDetectionWorkflowState) -> Dict[str, Any]:
"""整理最终结果"""
state.send_progress("finalize", "📋 整理最终结果...", ProgressLevel.INFO)
# 保存结果(如果指定了输出路径)
if state.output_path and state.detection_result:
try:
from ..utils import ResultSaver
from ..types import OutputFormat
output_path = Path(state.output_path)
output_format = OutputFormat(state.output_format)
saver = ResultSaver()
saver.save_results(state.detection_result, output_path, output_format)
state.send_progress("finalize", f"💾 结果已保存到: {output_path}", ProgressLevel.SUCCESS)
except Exception as e:
state.send_progress("finalize", f"⚠️ 保存结果失败: {e}", ProgressLevel.WARNING)
# 准备最终结果
final_result = {
"success": True,
"workflow_state": "completed",
"detection_result": None,
"ai_analysis": state.ai_analysis,
"video_info": state.video_info,
"errors": state.errors or []
}
# 序列化检测结果
if state.detection_result:
final_result["detection_result"] = {
"success": state.detection_result.success,
"filename": state.detection_result.filename,
"detector_type": state.detection_result.detector_type,
"threshold": state.detection_result.threshold,
"total_scenes": state.detection_result.total_scenes,
"total_duration": state.detection_result.total_duration,
"detection_time": state.detection_result.detection_time,
"scenes": [asdict(scene) for scene in state.detection_result.scenes],
"error": state.detection_result.error
}
state.send_progress("finalize", "🎉 工作流执行完成", ProgressLevel.SUCCESS, {
"total_scenes": state.detection_result.total_scenes if state.detection_result else 0,
"workflow_stage": "completed"
})
# 发送最终结果到JSON-RPC客户端
state.send_final_result(final_result)
return {
"current_stage": "completed",
"progress": 5,
"final_result": final_result
}
def handle_error(self, state: SceneDetectionWorkflowState) -> Dict[str, Any]:
"""处理错误"""
error_msg = "; ".join(state.errors) if state.errors else "未知错误"
# 发送错误进度
state.send_progress("error", f"❌ 工作流错误: {error_msg}", ProgressLevel.ERROR)
# 准备错误结果
error_result = {
"success": False,
"workflow_state": "failed",
"error": error_msg,
"errors": state.errors or [],
"detection_result": None,
"ai_analysis": None,
"video_info": state.video_info
}
# 发送错误结果到JSON-RPC客户端
state.send_error_result(-32603, f"工作流执行失败: {error_msg}", error_result)
return {
"current_stage": "failed",
"error_result": error_result
}