#!/usr/bin/env python3 """ 批量生成 session 对话摘要。 使用 Claude API 为每个对话文件生成 50-400 字的中文摘要。 摘要规则: - 列出本次对话完成的所有功能点/任务 - 包含关键技术细节:文件路径、模块名、数据库表、API 端点等 - bug 修复要说明原因和方案 - 不写过程性描述,只写结果 - 内容太短或无实质内容的,写"无实质内容" """ import os import json import sys from pathlib import Path from dotenv import load_dotenv import anthropic # 加载环境变量 load_dotenv() from _env_paths import ensure_repo_root ensure_repo_root() # 初始化 Anthropic 客户端 client = anthropic.Anthropic(api_key=os.environ.get("ANTHROPIC_API_KEY")) # 路径配置 SESSION_DIR = Path("export/session_summaries") OUTPUT_DIR = SESSION_DIR / "out" OUTPUT_DIR.mkdir(exist_ok=True) SYSTEM_PROMPT = """你是一个专业的技术对话分析师。你的任务是为 AI 编程助手与开发者的对话生成简洁的中文摘要。 摘要规则: 1. 列出本次对话完成的所有功能点/任务(一个对话可能完成多个) 2. 包含关键技术细节:文件路径、模块名、数据库表、API 端点等 3. bug 修复要说明原因和方案 4. 不写过程性描述("用户说..."),只写结果 5. 内容太短或无实质内容的,写"无实质内容" 6. 字数控制在 50-400 字之间 示例摘要: "修复 ETL DWD_LOAD_FROM_ODS 的 SCD2 时区问题(Asia/Shanghai → UTC 遗漏),影响 dwd.dim_member。新增 quality/row_count_check.py 质检规则。涉及:tasks/dwd_load.py、scd/merge.py。" 请直接输出摘要,不要添加任何前缀或解释。""" def generate_summary(content: str) -> str: """使用 Claude 生成摘要""" try: message = client.messages.create( model="claude-3-5-sonnet-20241022", max_tokens=500, system=SYSTEM_PROMPT, messages=[ { "role": "user", "content": f"请为以下对话生成摘要:\n\n{content}", } ], ) return message.content[0].text.strip() except Exception as e: print(f"生成摘要失败: {e}", file=sys.stderr) return f"生成失败: {str(e)}" def process_file(input_path: Path) -> bool: """处理单个文件,返回是否成功""" output_path = OUTPUT_DIR / input_path.name # 如果输出文件已存在,跳过 if output_path.exists(): print(f"✓ 已存在: {input_path.name}") return True try: # 读取输入文件 with open(input_path, "r", encoding="utf-8") as f: content = f.read() # 生成摘要 summary = generate_summary(content) # 写入输出文件 with open(output_path, "w", encoding="utf-8") as f: f.write(summary) print(f"✓ 完成: {input_path.name}") return True except Exception as e: print(f"✗ 错误 {input_path.name}: {e}", file=sys.stderr) return False def main(): """主函数""" # 获取所有 .txt 文件(跳过 _manifest.json 和以 _ 开头的文件) files = sorted( [ f for f in SESSION_DIR.glob("*.txt") if not f.name.startswith("_") and f.name != "_manifest.json" ] ) if not files: print("未找到要处理的文件") return print(f"找到 {len(files)} 个文件") # 处理文件 success_count = 0 for i, file_path in enumerate(files, 1): if process_file(file_path): success_count += 1 # 每处理 10 个文件打印进度 if i % 10 == 0: print(f"进度: {i}/{len(files)}") print(f"\n完成: {success_count}/{len(files)} 个文件") if __name__ == "__main__": main()