255 lines
7.3 KiB
Python
255 lines
7.3 KiB
Python
"""
|
|||
|
|
对话式 Agent 的命令行入口
|
||
|
|
支持交互式对话
|
||
|
|
"""
|
||
|
|
|
||
|
|
import argparse
|
||
|
|
import asyncio
|
||
|
|
import logging
|
||
|
|
import sys
|
||
|
|
from typing import Dict, Any, Optional, List
|
||
|
|
|
||
|
|
from typing import Dict, Any, Optional, List
|
||
|
|
|
||
|
|
# Handle imports with both relative and absolute paths
|
||
|
|
try:
|
||
|
|
from .main import JournalOrganizerAgent
|
||
|
|
from .conversation import ConversationalAgent
|
||
|
|
except ImportError:
|
||
|
|
# Fallback to absolute imports when running as script
|
||
|
|
from main import JournalOrganizerAgent
|
||
|
|
from conversation import ConversationalAgent
|
||
|
|
|
||
|
|
|
||
|
|
class ChatInterface:
|
||
|
|
"""对话式 Agent 的命令行界面"""
|
||
|
|
|
||
|
|
def __init__(self, config_file: Optional[str] = None) -> None:
|
||
|
|
"""
|
||
|
|
初始化聊天界面
|
||
|
|
|
||
|
|
Args:
|
||
|
|
config_file: 配置文件路径
|
||
|
|
"""
|
||
|
|
self.logger: logging.Logger = logging.getLogger("ChatInterface")
|
||
|
|
|
||
|
|
# 初始化 Agent
|
||
|
|
self.journal_agent: JournalOrganizerAgent = JournalOrganizerAgent(config_file)
|
||
|
|
self.conversational_agent: ConversationalAgent = ConversationalAgent(
|
||
|
|
self.journal_agent.agent, self.journal_agent.config
|
||
|
|
)
|
||
|
|
|
||
|
|
async def run_interactive(self) -> None:
|
||
|
|
"""
|
||
|
|
运行交互式对话
|
||
|
|
"""
|
||
|
|
print(f"\n{'='*60}")
|
||
|
|
print("Obsidian 智能日记整理 Agent - 对话模式")
|
||
|
|
print(f"{'='*60}\n")
|
||
|
|
|
||
|
|
# 显示欢迎消息
|
||
|
|
welcome_msg = await self.conversational_agent.initialize()
|
||
|
|
print(f"\n🤖 助手: {welcome_msg}\n")
|
||
|
|
|
||
|
|
# 交互循环
|
||
|
|
while True:
|
||
|
|
try:
|
||
|
|
# 获取用户输入
|
||
|
|
user_input: str = input("👤 您: ").strip()
|
||
|
|
|
||
|
|
if not user_input:
|
||
|
|
continue
|
||
|
|
|
||
|
|
# 处理特殊命令
|
||
|
|
if user_input.lower() in ["exit", "quit", "退出"]:
|
||
|
|
print("\n👋 再见!\n")
|
||
|
|
break
|
||
|
|
|
||
|
|
if user_input.lower() in ["help", "帮助"]:
|
||
|
|
self._show_help()
|
||
|
|
continue
|
||
|
|
|
||
|
|
if user_input.lower() in ["history", "历史"]:
|
||
|
|
self._show_history()
|
||
|
|
continue
|
||
|
|
|
||
|
|
if user_input.lower() in ["status", "状态"]:
|
||
|
|
self._show_status()
|
||
|
|
continue
|
||
|
|
|
||
|
|
if user_input.lower() in ["clear", "清除"]:
|
||
|
|
self.conversational_agent.clear_history()
|
||
|
|
print("\n✓ 对话历史已清除\n")
|
||
|
|
continue
|
||
|
|
|
||
|
|
# 处理用户消息
|
||
|
|
print("\n⏳ 处理中...\n")
|
||
|
|
response = await self.conversational_agent.chat(user_input)
|
||
|
|
|
||
|
|
# 显示响应
|
||
|
|
print(f"🤖 助手: {response.message}")
|
||
|
|
|
||
|
|
# 显示建议
|
||
|
|
if response.suggestions:
|
||
|
|
print("\n💡 您可以尝试:")
|
||
|
|
for i, suggestion in enumerate(response.suggestions, 1):
|
||
|
|
print(f" {i}. {suggestion}")
|
||
|
|
|
||
|
|
print()
|
||
|
|
|
||
|
|
except KeyboardInterrupt:
|
||
|
|
print("\n\n👋 再见!\n")
|
||
|
|
break
|
||
|
|
|
||
|
|
except Exception as e:
|
||
|
|
self.logger.error(f"错误: {str(e)}", exc_info=True)
|
||
|
|
print(f"\n❌ 发生错误: {str(e)}\n")
|
||
|
|
|
||
|
|
async def run_single_query(self, query: str) -> None:
|
||
|
|
"""
|
||
|
|
运行单个查询
|
||
|
|
|
||
|
|
Args:
|
||
|
|
query: 用户查询
|
||
|
|
"""
|
||
|
|
# 初始化
|
||
|
|
await self.conversational_agent.initialize()
|
||
|
|
|
||
|
|
# 处理查询
|
||
|
|
response = await self.conversational_agent.chat(query)
|
||
|
|
|
||
|
|
# 输出结果
|
||
|
|
output_data: Dict[str, Any] = {
|
||
|
|
"message": response.message,
|
||
|
|
"status": response.status,
|
||
|
|
"suggestions": response.suggestions,
|
||
|
|
"metadata": response.metadata,
|
||
|
|
}
|
||
|
|
print(json.dumps(output_data, ensure_ascii=False, indent=2))
|
||
|
|
|
||
|
|
def _show_help(self) -> None:
|
||
|
|
"""
|
||
|
|
显示帮助信息
|
||
|
|
"""
|
||
|
|
help_text = """
|
||
|
|
🆘 可用命令:
|
||
|
|
|
||
|
|
对话命令:
|
||
|
|
- 直接输入您的需求,例如: "整理今天的日记"
|
||
|
|
- "分析本周的主题"
|
||
|
|
- "导出月度总结"
|
||
|
|
|
||
|
|
系统命令:
|
||
|
|
- help / 帮助 显示此帮助信息
|
||
|
|
- history / 历史 显示对话历史
|
||
|
|
- status / 状态 显示当前状态
|
||
|
|
- clear / 清除 清除对话历史
|
||
|
|
- exit / quit / 退出 退出程序
|
||
|
|
|
||
|
|
示例对话:
|
||
|
|
👤 您: 帮我整理一下昨天的日记
|
||
|
|
🤖 助手: 好的,我来帮您整理昨天的日记...
|
||
|
|
|
||
|
|
👤 您: 分析一下这周的主题
|
||
|
|
🤖 助手: 这周的主题主要集中在...
|
||
|
|
"""
|
||
|
|
print(help_text)
|
||
|
|
|
||
|
|
def _show_history(self) -> None:
|
||
|
|
"""
|
||
|
|
显示对话历史
|
||
|
|
"""
|
||
|
|
history: List[
|
||
|
|
Dict[str, str]
|
||
|
|
] = self.conversational_agent.get_conversation_history()
|
||
|
|
|
||
|
|
if not history:
|
||
|
|
print("\n📭 对话历史为空\n")
|
||
|
|
return
|
||
|
|
|
||
|
|
print("\n📜 对话历史:\n")
|
||
|
|
for msg in history:
|
||
|
|
role: str = "👤 您" if msg["role"] == "user" else "🤖 助手"
|
||
|
|
content: str = msg["content"]
|
||
|
|
if len(content) > 100:
|
||
|
|
content = f"{content[:100]}..."
|
||
|
|
print(f"{role}: {content}")
|
||
|
|
print()
|
||
|
|
|
||
|
|
def _show_status(self) -> None:
|
||
|
|
"""
|
||
|
|
显示当前状态
|
||
|
|
"""
|
||
|
|
summary: Dict[str, Any] = self.conversational_agent.get_state_summary()
|
||
|
|
|
||
|
|
print("\n📊 当前状态:\n")
|
||
|
|
print(f"总消息数: {summary['total_messages']}")
|
||
|
|
print(f"总任务数: {summary['stats']['total_tasks']}")
|
||
|
|
print(f"成功任务: {summary['stats']['successful_tasks']}")
|
||
|
|
print(f"失败任务: {summary['stats']['failed_tasks']}")
|
||
|
|
|
||
|
|
if summary["current_task"]:
|
||
|
|
print(f"\n当前任务: {summary['current_task']['command']}")
|
||
|
|
print(f"状态: {summary['current_task']['status']}")
|
||
|
|
|
||
|
|
print()
|
||
|
|
|
||
|
|
|
||
|
|
async def main() -> Optional[int]:
|
||
|
|
"""
|
||
|
|
主函数
|
||
|
|
"""
|
||
|
|
parser: argparse.ArgumentParser = argparse.ArgumentParser(
|
||
|
|
description="Obsidian 智能日记整理 Agent - 对话模式",
|
||
|
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||
|
|
epilog="""
|
||
|
|
示例:
|
||
|
|
# 启动交互式对话
|
||
|
|
python -m journal_organizer.chat_main
|
||
|
|
|
||
|
|
# 处理单个查询
|
||
|
|
python -m journal_organizer.chat_main --query "整理今天的日记"
|
||
|
|
|
||
|
|
# 使用指定配置文件
|
||
|
|
python -m journal_organizer.chat_main --config /path/to/config.yaml
|
||
|
|
""",
|
||
|
|
)
|
||
|
|
|
||
|
|
parser.add_argument("--config", type=str, help="配置文件路径")
|
||
|
|
|
||
|
|
parser.add_argument("--query", type=str, help="单个查询(不进入交互模式)")
|
||
|
|
|
||
|
|
parser.add_argument(
|
||
|
|
"--log-level",
|
||
|
|
type=str,
|
||
|
|
default="INFO",
|
||
|
|
choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"],
|
||
|
|
help="日志级别",
|
||
|
|
)
|
||
|
|
|
||
|
|
args: argparse.Namespace = parser.parse_args()
|
||
|
|
|
||
|
|
# 设置日志
|
||
|
|
logging.basicConfig(
|
||
|
|
level=getattr(logging, args.log_level),
|
||
|
|
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
||
|
|
)
|
||
|
|
|
||
|
|
# 初始化聊天界面
|
||
|
|
chat: ChatInterface = ChatInterface(args.config)
|
||
|
|
|
||
|
|
# 运行
|
||
|
|
if args.query:
|
||
|
|
# 单个查询模式
|
||
|
|
await chat.run_single_query(args.query)
|
||
|
|
else:
|
||
|
|
# 交互模式
|
||
|
|
await chat.run_interactive()
|
||
|
|
|
||
|
|
return None
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
exit_code: Optional[int] = asyncio.run(main())
|
||
|
|
sys.exit(exit_code or 0)
|