Initial project setup: Obsidian intelligent journal organizer
- Add core agent architecture with Command + Skill pattern - Implement Claude API integration for content analysis - Add Obsidian REST API integration for vault operations - Create conversational interface (v2.0) with natural language processing - Add comprehensive configuration management and validation - Include project documentation and developer guides - Set up testing framework with unit, integration, and property tests - Add Kiro specs for Claude API configuration and code quality improvements - Configure project steering files for development guidelines
This commit is contained in:
@@ -0,0 +1,284 @@
|
||||
"""
|
||||
日记整理 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)
|
||||
Reference in New Issue
Block a user