Files
journal_organizer/main.py
T

285 lines
8.5 KiB
Python
Raw Normal View History

"""
日记整理 Agent 主入口
支持命令行调用和外部集成
"""
import argparse
import asyncio
import json
import logging
import sys
from pathlib import Path
from typing import Dict, Any, Optional
import sys
from pathlib import Path
from typing import Dict, Any, Optional
# Handle imports with both relative and absolute paths
try:
from .dependency_manager import get_dependency_manager
from .agent_core import Agent, SkillResult
from .commands.organize_command import OrganizeCommand
except ImportError:
# Fallback to absolute imports when running as script
from dependency_manager import get_dependency_manager
from agent_core import Agent, SkillResult
from commands.organize_command import OrganizeCommand
# Try to import yaml with graceful degradation
dependency_manager = get_dependency_manager()
yaml = dependency_manager.get_module('yaml')
class JournalOrganizerAgent:
"""日记整理 Agent"""
def __init__(self, config_file: Optional[str] = None):
"""
初始化 Agent
Args:
config_file: 配置文件路径
"""
self.logger = logging.getLogger("JournalOrganizerAgent")
self.config = self._load_config(config_file)
self.agent = Agent("JournalOrganizer", self.config)
self._register_commands()
def _load_config(self, config_file: Optional[str] = None) -> Dict[str, Any]:
"""
加载配置文件
Args:
config_file: 配置文件路径
Returns:
配置字典
"""
if config_file and Path(config_file).exists():
config_path = Path(config_file)
with config_path.open("r", encoding="utf-8") as f:
if config_path.suffix in [".yaml", ".yml"]:
return yaml.safe_load(f) or {}
elif config_path.suffix == ".json":
return json.load(f)
# 尝试从默认位置加载
default_paths = [
Path.home() / ".journal_organizer" / "config.yaml",
Path.home() / ".journal_organizer" / "config.json",
Path.cwd() / "config.yaml",
Path.cwd() / "config.json",
]
for path in default_paths:
if path.exists():
self.logger.info(f"从 {path} 加载配置")
with path.open("r", encoding="utf-8") as f:
if path.suffix in [".yaml", ".yml"]:
return yaml.safe_load(f) or {}
else:
return json.load(f)
self.logger.warning("未找到配置文件,使用默认配置")
return {}
def _register_commands(self) -> None:
"""注册所有命令"""
self.agent.register_command(OrganizeCommand())
async def run_command(
self,
command: str,
args: Optional[Dict[str, Any]] = None,
options: Optional[Dict[str, Any]] = None,
) -> SkillResult:
"""
运行命令
Args:
command: 命令名称
args: 命令参数
options: 命令选项
Returns:
SkillResult: 执行结果
"""
return await self.agent.execute_command(command, args, options)
def list_commands(self) -> list:
"""列出所有可用命令"""
return self.agent.list_commands()
def get_command_info(self, command: str) -> Dict[str, Any]:
"""获取命令信息"""
if command in self.agent.commands:
return self.agent.commands[command].get_info()
return {}
def get_all_commands_info(self) -> Dict[str, Any]:
"""获取所有命令信息"""
return self.agent.get_commands_info()
async def main():
"""命令行主函数"""
parser = argparse.ArgumentParser(
description="Obsidian 智能日记整理 Agent",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
示例:
# 整理今天的日记
python -m journal_organizer organize
# 整理指定日期的日记
python -m journal_organizer organize --date 2025-12-31
# 列出所有可用命令
python -m journal_organizer list
# 显示命令帮助
python -m journal_organizer help organize
# 使用指定配置文件
python -m journal_organizer --config /path/to/config.yaml organize
""",
)
parser.add_argument("--config", type=str, help="配置文件路径")
parser.add_argument(
"--log-level",
type=str,
default="INFO",
choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"],
help="日志级别",
)
subparsers = parser.add_subparsers(dest="command", help="命令")
# organize 命令
organize_parser = subparsers.add_parser("organize", help="整理日记")
organize_parser.add_argument("--date", type=str, help="日期 (YYYY-MM-DD)")
organize_parser.add_argument("--vault-path", type=str, help="Obsidian vault 路径")
organize_parser.add_argument(
"--daily-folder", type=str, default="Daily", help="日记文件夹"
)
# list 命令
subparsers.add_parser("list", help="列出所有可用命令")
# help 命令
help_parser = subparsers.add_parser("help", help="显示命令帮助")
help_parser.add_argument("help_command", nargs="?", help="要查看帮助的命令")
# info 命令
subparsers.add_parser("info", help="显示 Agent 信息")
# check-deps 命令
subparsers.add_parser("check-deps", help="检查依赖项状态")
args = parser.parse_args()
# 设置日志
logging.basicConfig(
level=getattr(logging, args.log_level),
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
)
# 初始化 Agent
agent = JournalOrganizerAgent(args.config)
# 处理命令
if not args.command:
parser.print_help()
return
if args.command == "organize":
# 构建参数
organize_args = {}
if args.date:
organize_args["date"] = args.date
if args.vault_path:
organize_args["vault_path"] = args.vault_path
if args.daily_folder:
organize_args["daily_folder"] = args.daily_folder
result = await agent.run_command("organize", organize_args)
print(f"\n{'='*50}")
print("执行结果")
print("=" * 50)
print(result.to_json())
return 0 if result.success else 1
elif args.command == "list":
commands = agent.list_commands()
print("\n可用命令:")
for cmd in commands:
print(f" - {cmd}")
return 0
elif args.command == "help":
if args.help_command:
info = agent.get_command_info(args.help_command)
if info:
print(f"\n命令: {info['name']}")
print(f"描述: {info['description']}")
if info.get("aliases"):
print(f"别名: {', '.join(info['aliases'])}")
print("\nSkills:")
for skill_name, skill_info in info.get("skills", {}).items():
print(f" - {skill_name}: {skill_info['description']}")
else:
print(f"未找到命令: {args.help_command}")
return 1
else:
parser.print_help()
return 0
elif args.command == "info":
info = agent.get_all_commands_info()
print(f"\n{json.dumps(info, ensure_ascii=False, indent=2)}")
return 0
elif args.command == "check-deps":
print("\n🔍 检查依赖项状态...")
print(dependency_manager.get_dependency_status_report())
missing_deps = dependency_manager.get_missing_dependencies()
if missing_deps:
print(f"\n📋 安装说明:")
print(dependency_manager.get_installation_instructions(missing_only=True))
return 1
else:
print(f"\n✅ 所有依赖项都已正确安装!")
return 0
def run_command_sync(
command: str,
args: Optional[Dict[str, Any]] = None,
config_file: Optional[str] = None,
) -> Dict[str, Any]:
"""
同步运行命令(用于外部调用)
Args:
command: 命令名称
args: 命令参数
config_file: 配置文件路径
Returns:
执行结果字典
"""
agent = JournalOrganizerAgent(config_file)
result = asyncio.run(agent.run_command(command, args))
return result.to_dict()
if __name__ == "__main__":
exit_code = asyncio.run(main())
sys.exit(exit_code or 0)