fix
This commit is contained in:
@@ -13,10 +13,11 @@ from rich.console import Console
|
||||
from rich.table import Table
|
||||
|
||||
from python_core.scene_detection import (
|
||||
SceneDetector,
|
||||
DetectorType,
|
||||
SceneDetector,
|
||||
DetectorType,
|
||||
OutputFormat
|
||||
)
|
||||
from python_core.scene_detection.single_scene_detector import SingleSceneDetector
|
||||
from python_core.utils.logger import logger
|
||||
|
||||
scene_detect = typer.Typer(help="场景检测工具 - 重构版")
|
||||
@@ -231,5 +232,212 @@ def _display_batch_results_table(tasks):
|
||||
console.print(table)
|
||||
|
||||
|
||||
@scene_detect.command("single")
|
||||
def single_detect_and_split(
|
||||
video_path: str = typer.Argument(..., help="视频文件路径"),
|
||||
output_dir: Optional[str] = typer.Option(None, "--output", "-o", help="输出目录"),
|
||||
detector_type: str = typer.Option("content", "--detector", "-d", help="检测器类型 (content/threshold/adaptive)"),
|
||||
threshold: float = typer.Option(30.0, "--threshold", "-t", help="检测阈值 (0-100)"),
|
||||
min_scene_length: float = typer.Option(1.0, "--min-length", "-l", help="最小场景长度(秒)"),
|
||||
output_format: str = typer.Option("json", "--format", "-f", help="输出格式 (json/csv/txt)"),
|
||||
ai_analysis: bool = typer.Option(False, "--ai/--no-ai", help="启用/禁用AI分析"),
|
||||
video_splitting: bool = typer.Option(True, "--split/--no-split", help="启用/禁用视频切分"),
|
||||
use_advanced_split: bool = typer.Option(True, "--advanced/--traditional", help="使用高效批量切分/传统逐个切分"),
|
||||
split_quality: int = typer.Option(23, "--quality", "-q", help="切分质量 (CRF值, 18-28)"),
|
||||
split_preset: str = typer.Option("fast", "--preset", help="编码预设 (ultrafast/fast/medium/slow)"),
|
||||
max_duration: float = typer.Option(2.0, "--max-duration", "-m", help="最大视频时长限制(秒),超过将二次切分"),
|
||||
verbose: bool = typer.Option(False, "--verbose", "-v", help="详细输出")
|
||||
):
|
||||
"""单个视频文件的场景检测和切分"""
|
||||
|
||||
try:
|
||||
console.print(f"🎬 [bold blue]单个视频场景检测和切分[/bold blue]")
|
||||
console.print(f"📁 视频文件: {video_path}")
|
||||
|
||||
# 验证输入参数
|
||||
try:
|
||||
detector_type_enum = DetectorType(detector_type)
|
||||
output_format_enum = OutputFormat(output_format)
|
||||
except ValueError as e:
|
||||
console.print(f"[red]❌ 参数错误: {e}[/red]")
|
||||
raise typer.Exit(1)
|
||||
|
||||
# 创建检测器
|
||||
detector = SingleSceneDetector()
|
||||
|
||||
# 验证视频文件
|
||||
validation_result = detector.validate_video(video_path)
|
||||
if not validation_result["valid"]:
|
||||
console.print(f"[red]❌ 视频文件验证失败: {validation_result['error']}[/red]")
|
||||
raise typer.Exit(1)
|
||||
|
||||
console.print(f"✅ 视频文件验证通过")
|
||||
console.print(f"📊 文件大小: {validation_result['file_size']:,} 字节")
|
||||
|
||||
# 执行处理
|
||||
result = detector.detect_and_split(
|
||||
video_path=video_path,
|
||||
output_dir=output_dir,
|
||||
detector_type=detector_type_enum,
|
||||
threshold=threshold,
|
||||
min_scene_length=min_scene_length,
|
||||
output_format=output_format_enum,
|
||||
enable_ai_analysis=ai_analysis,
|
||||
enable_video_splitting=video_splitting,
|
||||
use_advanced_split=use_advanced_split,
|
||||
split_quality=split_quality,
|
||||
split_preset=split_preset,
|
||||
max_video_duration=max_duration
|
||||
)
|
||||
|
||||
# 显示结果
|
||||
if result["success"]:
|
||||
console.print(f"\n✅ [bold green]处理完成![/bold green]")
|
||||
console.print(f"📊 处理统计:")
|
||||
console.print(f" 视频文件: {Path(result['video_path']).name}")
|
||||
console.print(f" 输出目录: {result['output_dir']}")
|
||||
console.print(f" 处理时间: {result['processing_time']:.1f}s")
|
||||
console.print(f" 场景数量: {result['total_scenes']}")
|
||||
console.print(f" 切分片段: {result['total_segments']}")
|
||||
|
||||
# 显示详细结果表格
|
||||
if result.get("split_results") and verbose:
|
||||
table = Table(title="切分结果详情")
|
||||
table.add_column("片段", style="cyan")
|
||||
table.add_column("输出文件", style="green")
|
||||
table.add_column("时长", style="yellow")
|
||||
table.add_column("文件大小", style="blue")
|
||||
table.add_column("状态", style="magenta")
|
||||
|
||||
for split_result in result["split_results"]:
|
||||
status = "✅ 成功" if split_result["success"] else f"❌ {split_result.get('error', '失败')}"
|
||||
file_size = f"{split_result['file_size']:,} B" if split_result['file_size'] > 0 else "0 B"
|
||||
duration = f"{split_result['duration']:.2f}s"
|
||||
filename = Path(split_result['output_path']).name
|
||||
|
||||
table.add_row(
|
||||
str(split_result['scene_index'] + 1),
|
||||
filename,
|
||||
duration,
|
||||
file_size,
|
||||
status
|
||||
)
|
||||
|
||||
console.print(table)
|
||||
else:
|
||||
console.print(f"\n[red]❌ 处理失败: {result.get('error', '未知错误')}[/red]")
|
||||
raise typer.Exit(1)
|
||||
|
||||
except Exception as e:
|
||||
console.print(f"\n[red]❌ 单个视频处理失败: {str(e)}[/red]")
|
||||
raise typer.Exit(1)
|
||||
|
||||
|
||||
@scene_detect.command("import")
|
||||
def import_to_project(
|
||||
video_path: str = typer.Argument(..., help="视频文件路径"),
|
||||
project_id: str = typer.Argument(..., help="项目ID"),
|
||||
project_directory: str = typer.Argument(..., help="项目目录路径"),
|
||||
tags: Optional[str] = typer.Option(None, "--tags", "-t", help="素材标签,用逗号分隔"),
|
||||
detector_type: str = typer.Option("content", "--detector", "-d", help="检测器类型"),
|
||||
threshold: float = typer.Option(30.0, "--threshold", help="检测阈值"),
|
||||
min_scene_length: float = typer.Option(1.0, "--min-length", help="最小场景长度(秒)"),
|
||||
split_quality: int = typer.Option(23, "--quality", "-q", help="切分质量"),
|
||||
split_preset: str = typer.Option("fast", "--preset", help="编码预设"),
|
||||
max_duration: float = typer.Option(2.0, "--max-duration", "-m", help="最大视频时长限制(秒)"),
|
||||
verbose: bool = typer.Option(False, "--verbose", "-v", help="详细输出")
|
||||
):
|
||||
"""导入单个视频到项目素材库"""
|
||||
|
||||
try:
|
||||
console.print(f"📦 [bold blue]导入视频到项目素材库[/bold blue]")
|
||||
console.print(f"📁 视频文件: {video_path}")
|
||||
console.print(f"🎯 项目ID: {project_id}")
|
||||
console.print(f"📂 项目目录: {project_directory}")
|
||||
|
||||
# 解析标签
|
||||
material_tags = []
|
||||
if tags:
|
||||
material_tags = [tag.strip() for tag in tags.split(",") if tag.strip()]
|
||||
console.print(f"🏷️ 素材标签: {', '.join(material_tags)}")
|
||||
|
||||
# 验证输入参数
|
||||
try:
|
||||
detector_type_enum = DetectorType(detector_type)
|
||||
except ValueError as e:
|
||||
console.print(f"[red]❌ 参数错误: {e}[/red]")
|
||||
raise typer.Exit(1)
|
||||
|
||||
# 创建检测器
|
||||
detector = SingleSceneDetector()
|
||||
|
||||
# 验证视频文件
|
||||
validation_result = detector.validate_video(video_path)
|
||||
if not validation_result["valid"]:
|
||||
console.print(f"[red]❌ 视频文件验证失败: {validation_result['error']}[/red]")
|
||||
raise typer.Exit(1)
|
||||
|
||||
# 验证项目目录
|
||||
project_dir_path = Path(project_directory)
|
||||
if not project_dir_path.exists():
|
||||
console.print(f"[red]❌ 项目目录不存在: {project_directory}[/red]")
|
||||
raise typer.Exit(1)
|
||||
|
||||
console.print(f"✅ 验证通过,开始导入...")
|
||||
|
||||
# 执行导入
|
||||
result = detector.import_to_project(
|
||||
video_path=video_path,
|
||||
project_id=project_id,
|
||||
project_directory=project_directory,
|
||||
material_tags=material_tags,
|
||||
detector_type=detector_type_enum,
|
||||
threshold=threshold,
|
||||
min_scene_length=min_scene_length,
|
||||
split_quality=split_quality,
|
||||
split_preset=split_preset,
|
||||
max_video_duration=max_duration
|
||||
)
|
||||
|
||||
# 显示结果
|
||||
if result["success"]:
|
||||
console.print(f"\n✅ [bold green]导入完成![/bold green]")
|
||||
console.print(f"📊 导入统计:")
|
||||
console.print(f" 视频文件: {Path(result['video_path']).name}")
|
||||
console.print(f" 处理时间: {result['processing_time']:.1f}s")
|
||||
console.print(f" 场景数量: {result['total_scenes']}")
|
||||
console.print(f" 导入片段: {result['total_segments']}")
|
||||
console.print(f" 项目目录: {result['output_dir']}")
|
||||
|
||||
# 显示详细结果
|
||||
if result.get("split_results") and verbose:
|
||||
table = Table(title="导入素材详情")
|
||||
table.add_column("片段", style="cyan")
|
||||
table.add_column("时长", style="yellow")
|
||||
table.add_column("文件大小", style="blue")
|
||||
table.add_column("状态", style="magenta")
|
||||
|
||||
for split_result in result["split_results"]:
|
||||
status = "✅ 已导入" if split_result["success"] else f"❌ {split_result.get('error', '失败')}"
|
||||
file_size = f"{split_result['file_size']:,} B" if split_result['file_size'] > 0 else "0 B"
|
||||
duration = f"{split_result['duration']:.2f}s"
|
||||
|
||||
table.add_row(
|
||||
str(split_result['scene_index'] + 1),
|
||||
duration,
|
||||
file_size,
|
||||
status
|
||||
)
|
||||
|
||||
console.print(table)
|
||||
else:
|
||||
console.print(f"\n[red]❌ 导入失败: {result.get('error', '未知错误')}[/red]")
|
||||
raise typer.Exit(1)
|
||||
|
||||
except Exception as e:
|
||||
console.print(f"\n[red]❌ 项目导入失败: {str(e)}[/red]")
|
||||
raise typer.Exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
scene_detect()
|
||||
Reference in New Issue
Block a user