import argparse import logging import os import sys if sys.stdout.encoding.lower() == "gbk": sys.stdout.reconfigure(encoding="utf-8") logging.basicConfig( level=logging.INFO, format="%(asctime)s [%(levelname)s] %(name)s: %(message)s", datefmt="%H:%M:%S", ) logger = logging.getLogger(__name__) def cmd_process(args): from meeting_processor import meeting_processor filepath = args.file if not os.path.exists(filepath): print(f"错误: 文件不存在: {filepath}") sys.exit(1) print(f"正在处理会议文件: {filepath}") vault_path = meeting_processor.process_meeting_file(filepath, force=getattr(args, 'force', False)) if vault_path: print(f"\n✅ 会议处理完成!") print(f"📝 Obsidian 笔记: {vault_path}") print(f"📂 Obsidian Vault: {os.path.dirname(vault_path)}") else: print("\n❌ 会议处理失败") sys.exit(1) def cmd_text(args): from meeting_processor import meeting_processor text = args.text print("正在处理会议文本...") vault_path = meeting_processor.process_meeting_text(text, force=getattr(args, 'force', False)) if vault_path: print(f"\n✅ 会议处理完成!") print(f"📝 Obsidian 笔记: {vault_path}") else: print("\n❌ 会议处理失败") def cmd_query(args): from meeting_processor import meeting_processor question = args.question print(f"🔍 查询: {question}") print("-" * 40) result = meeting_processor.query(question, top_k=args.top_k) if result: print(result) else: print("未找到相关信息") def cmd_stats(args): from meeting_processor import meeting_processor stats = meeting_processor.stats() print("📊 会议记忆系统统计") print("-" * 40) print(f"Obsidian 会议笔记: {stats.get('obsidian_meetings', 0)}") print(f"Obsidian 实体笔记: {stats.get('obsidian_entities', 0)}") print(f"向量索引节点数: {stats.get('vector_index', {}).get('node_count', 0)}") print(f"Vault 路径: {stats.get('vault_path', '')}") def cmd_batch(args): from meeting_processor import meeting_processor import glob as glob_module pattern = args.pattern files = glob_module.glob(pattern, recursive=True) force = getattr(args, 'force', False) if not files: print(f"未匹配到任何文件: {pattern}") sys.exit(1) print(f"找到 {len(files)} 个文件,开始批量处理...") success = 0 for f in files: try: print(f"\n处理: {f}") meeting_processor.process_meeting_file(f, force=force) success += 1 except Exception as e: logger.error(f"处理失败: {f} - {e}") print(f"\n✅ 批量处理完成: {success}/{len(files)} 成功") def cmd_interactive(args=None): from meeting_processor import meeting_processor print("📋 会议纪要长期记忆系统 — 交互模式") print("=" * 50) print("可用命令:") print(" query <问题> 语义查询会议记忆") print(" process <路径> 处理会议文件") print(" stats 查看统计") print(" help 显示帮助") print(" exit/quit 退出") print("=" * 50) while True: try: line = input("\n> ").strip() except (EOFError, KeyboardInterrupt): print() break if not line: continue if line in ("exit", "quit", "q"): break if line == "help": print("可用命令:") print(" query <问题> — 语义查询会议记忆") print(" process <路径> — 处理一个会议markdown文件") print(" stats — 查看系统统计") print(" help — 显示此帮助") print(" exit/quit — 退出") continue if line == "stats": stats = meeting_processor.stats() print(f"📊 会议: {stats.get('obsidian_meetings', 0)} | " f"实体: {stats.get('obsidian_entities', 0)} | " f"向量节点: {stats.get('vector_index', {}).get('node_count', 0)}") continue if line.startswith("process "): filepath = line[8:].strip() if not os.path.exists(filepath): print(f"❌ 文件不存在: {filepath}") continue print(f"正在处理: {filepath}") vault_path = meeting_processor.process_meeting_file(filepath) if vault_path: print(f"✅ 完成: {vault_path}") else: print("❌ 处理失败") continue if line.startswith("query "): question = line[6:].strip() else: question = line print(f"🔍 查询中...", end="", flush=True) result = meeting_processor.query(question, top_k=3) print("\r" + " " * 30 + "\r", end="") if result: print(result[:2000]) if len(result) > 2000: print("... (结果过长已截断)") else: print("未找到相关信息") print("bye!") def main(): parser = argparse.ArgumentParser( description="📋 会议纪要长期记忆系统", formatter_class=argparse.RawDescriptionHelpFormatter, epilog=""" 示例: python main.py process meeting_example.md python main.py query "弱光指标目标值是多少?" python main.py stats python main.py text "今天会议讨论了..." 无参数时进入交互模式。 Powered by LlamaIndex + Obsidian + LLM """, ) subparsers = parser.add_subparsers(dest="command", help="子命令") p_process = subparsers.add_parser("process", help="处理会议 markdown 文件") p_process.add_argument("file", help="会议纪要 markdown 文件路径") p_process.add_argument("-f", "--force", action="store_true", help="重复时自动覆盖,跳过确认") p_text = subparsers.add_parser("text", help="直接输入会议文本") p_text.add_argument("text", help="会议文本内容") p_text.add_argument("-f", "--force", action="store_true", help="重复时自动覆盖,跳过确认") p_query = subparsers.add_parser("query", help="语义查询会议记忆") p_query.add_argument("question", help="查询问题") p_query.add_argument("--top-k", type=int, default=3, help="返回结果数量") p_stats = subparsers.add_parser("stats", help="查看系统统计") p_batch = subparsers.add_parser("batch", help="批量处理会议文件") p_batch.add_argument("pattern", help="文件 glob 模式, 如 'meetings/*.md'") p_batch.add_argument("-f", "--force", action="store_true", help="重复时自动覆盖,跳过确认") args = parser.parse_args() if args.command == "process": cmd_process(args) elif args.command == "text": cmd_text(args) elif args.command == "query": cmd_query(args) elif args.command == "stats": cmd_stats(args) elif args.command == "batch": cmd_batch(args) else: cmd_interactive(args) if __name__ == "__main__": main()