meeting_memory/main.py

226 lines
7.1 KiB
Python

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()