Files
wehub-resource-sync 41b710f9c7
CI / Frontend checks (push) Failing after 0s
CI / Backend tests (push) Failing after 1s
I18n Documentation Sync / sync-docs (push) Failing after 0s
chore: import upstream snapshot with attribution
2026-07-13 12:28:40 +08:00

262 lines
10 KiB
Python

"""
路径管理器
专门管理项目相关的路径操作
"""
import logging
from pathlib import Path
from typing import Dict, Any, List
logger = logging.getLogger(__name__)
class PathManager:
"""路径管理器,负责项目路径的统一管理"""
def __init__(self, project_id: str, base_dir: str = "data/projects"):
self.project_id = project_id
# 使用绝对路径
project_root = Path(__file__).parent.parent.parent
self.base_dir = project_root / base_dir
self.project_dir = self.base_dir / project_id
# 定义项目目录结构
self.directory_structure = {
"project_dir": self.project_dir,
"metadata_dir": self.project_dir / "metadata",
"raw_dir": self.project_dir / "raw",
"outputs_dir": self.project_dir / "outputs",
"logs_dir": self.project_dir / "logs",
"backups_dir": self.project_dir / "backups",
"temp_dir": self.project_dir / "temp"
}
# 确保目录结构存在
self.ensure_directories()
def ensure_directories(self):
"""确保所有必要的目录存在"""
for dir_name, dir_path in self.directory_structure.items():
dir_path.mkdir(parents=True, exist_ok=True)
logger.debug(f"确保目录存在: {dir_name} -> {dir_path}")
def get_project_paths(self) -> Dict[str, Path]:
"""获取项目相关路径"""
return self.directory_structure.copy()
def get_step_paths(self, step_name: str) -> Dict[str, Path]:
"""
获取步骤相关的路径
Args:
step_name: 步骤名称
Returns:
步骤相关路径
"""
metadata_dir = self.directory_structure["metadata_dir"]
return {
"input_path": metadata_dir / f"{step_name}_input.json",
"output_path": metadata_dir / f"{step_name}_output.json",
"intermediate_dir": metadata_dir / f"{step_name}_intermediate",
"log_path": self.directory_structure["logs_dir"] / f"{step_name}.log"
}
def get_step_input_path(self, step_name: str) -> Path:
"""获取步骤输入文件路径"""
return self.get_step_paths(step_name)["input_path"]
def get_step_output_path(self, step_name: str) -> Path:
"""获取步骤输出文件路径"""
return self.get_step_paths(step_name)["output_path"]
def get_step_intermediate_dir(self, step_name: str) -> Path:
"""获取步骤中间文件目录"""
return self.get_step_paths(step_name)["intermediate_dir"]
def get_step_log_path(self, step_name: str) -> Path:
"""获取步骤日志文件路径"""
return self.get_step_paths(step_name)["log_path"]
def get_backup_path(self, filename: str) -> Path:
"""获取备份文件路径"""
return self.directory_structure["backups_dir"] / filename
def get_temp_path(self, filename: str) -> Path:
"""获取临时文件路径"""
return self.directory_structure["temp_dir"] / filename
def get_config_path(self) -> Path:
"""获取配置文件路径"""
return self.project_dir / "config.yaml"
def get_srt_path(self) -> Path:
"""获取SRT文件路径"""
# 尝试从项目配置中获取SRT文件名
try:
from .config_manager import ProjectConfigManager
config_manager = ProjectConfigManager(self.project_id)
project_config = config_manager.get_project_config()
if project_config and "processing_config" in project_config:
srt_file = project_config["processing_config"].get("srt_file")
if srt_file:
return self.directory_structure["raw_dir"] / srt_file
# 如果配置中没有,尝试查找raw目录中的SRT文件
raw_dir = self.directory_structure["raw_dir"]
srt_files = list(raw_dir.glob("*.srt"))
if srt_files:
return srt_files[0]
return raw_dir / "transcript.srt"
except Exception as e:
logger.warning(f"获取SRT路径失败: {e}")
return self.directory_structure["raw_dir"] / "transcript.srt"
def get_video_path(self) -> Path:
"""获取视频文件路径"""
# 尝试从项目配置中获取视频文件名
try:
from .config_manager import ProjectConfigManager
config_manager = ProjectConfigManager(self.project_id)
project_config = config_manager.get_project_config()
if project_config and "processing_config" in project_config:
video_file = project_config["processing_config"].get("video_file")
if video_file:
return self.directory_structure["raw_dir"] / video_file
# 如果配置中没有,尝试查找raw目录中的视频文件
raw_dir = self.directory_structure["raw_dir"]
video_extensions = [".mp4", ".avi", ".mov", ".mkv", ".flv"]
for ext in video_extensions:
video_files = list(raw_dir.glob(f"*{ext}"))
if video_files:
return video_files[0]
return None
except Exception as e:
logger.warning(f"获取视频路径失败: {e}")
return None
if project_config and "srt_file" in project_config:
srt_filename = project_config["srt_file"]
return self.directory_structure["raw_dir"] / srt_filename
except Exception as e:
logger.warning(f"无法从项目配置获取SRT文件名: {e}")
# 回退到默认文件名
return self.directory_structure["raw_dir"] / "transcript.srt"
def get_prompt_dir(self) -> Path:
"""获取prompt目录路径"""
# 使用绝对路径指向项目根目录的prompt文件夹
project_root = Path(__file__).parent.parent.parent
return project_root / "prompt"
def create_step_directories(self, step_name: str):
"""为特定步骤创建必要的目录"""
step_paths = self.get_step_paths(step_name)
# 创建中间文件目录
step_paths["intermediate_dir"].mkdir(parents=True, exist_ok=True)
# 确保日志目录存在
step_paths["log_path"].parent.mkdir(parents=True, exist_ok=True)
logger.debug(f"为步骤 {step_name} 创建目录结构")
def cleanup_step_files(self, step_name: str, keep_output: bool = True):
"""
清理步骤的临时文件
Args:
step_name: 步骤名称
keep_output: 是否保留输出文件
"""
step_paths = self.get_step_paths(step_name)
# 清理中间文件目录
if step_paths["intermediate_dir"].exists():
import shutil
shutil.rmtree(step_paths["intermediate_dir"])
logger.info(f"已清理步骤 {step_name} 的中间文件")
# 清理输入文件(可选)
if step_paths["input_path"].exists():
step_paths["input_path"].unlink()
logger.debug(f"已清理步骤 {step_name} 的输入文件")
# 清理输出文件(可选)
if not keep_output and step_paths["output_path"].exists():
step_paths["output_path"].unlink()
logger.info(f"已清理步骤 {step_name} 的输出文件")
def get_directory_size(self, dir_path: Path) -> int:
"""获取目录大小(字节)"""
total_size = 0
try:
for file_path in dir_path.rglob("*"):
if file_path.is_file():
total_size += file_path.stat().st_size
except Exception as e:
logger.warning(f"计算目录大小时出错: {dir_path}, 错误: {e}")
return total_size
def get_project_size_info(self) -> Dict[str, Any]:
"""获取项目大小信息"""
size_info = {}
for dir_name, dir_path in self.directory_structure.items():
if dir_path.exists():
size_info[dir_name] = {
"path": str(dir_path),
"size_bytes": self.get_directory_size(dir_path),
"file_count": len(list(dir_path.rglob("*"))) if dir_path.is_dir() else 0
}
else:
size_info[dir_name] = {
"path": str(dir_path),
"size_bytes": 0,
"file_count": 0,
"exists": False
}
return size_info
def validate_paths(self) -> List[str]:
"""验证路径的有效性"""
errors = []
# 检查项目目录是否可写
if not self.project_dir.exists():
try:
self.project_dir.mkdir(parents=True, exist_ok=True)
except Exception as e:
errors.append(f"无法创建项目目录: {self.project_dir}, 错误: {e}")
# 检查各个子目录
for dir_name, dir_path in self.directory_structure.items():
if not dir_path.exists():
try:
dir_path.mkdir(parents=True, exist_ok=True)
except Exception as e:
errors.append(f"无法创建目录 {dir_name}: {dir_path}, 错误: {e}")
elif not dir_path.is_dir():
errors.append(f"路径不是目录: {dir_name} -> {dir_path}")
return errors
def get_relative_path(self, absolute_path: Path) -> str:
"""获取相对于项目目录的路径"""
try:
return str(absolute_path.relative_to(self.project_dir))
except ValueError:
return str(absolute_path)
def get_absolute_path(self, relative_path: str) -> Path:
"""获取绝对路径"""
return self.project_dir / relative_path