"""First panorama analysis - reads entire Obsidian vault and generates AI analysis (v2).""" import logging import os import sys import subprocess from datetime import datetime, timezone, timedelta sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from tools.config import load_secrets, get_output_dir from tools.llm import DeepSeekClient logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(name)s: %(message)s") logger = logging.getLogger(__name__) TZ_BEIJING = timezone(timedelta(hours=8)) PROJECT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) VAULT_DIR = "/home/ubuntu/obsidian-vault" PANORAMA_PROMPT = """你是一个私人思考伙伴。现在,用户将他的整个 Obsidian 文库交给你。 你的任务:读完这个文库的目录结构和关键内容,写一篇全景分析文章。 核心原则: 1. **不要缩写,不要分类表,不要空话。** 2. **引用原文。** 分析中必须引用或精炼复述用户的原文。 3. **融会贯通。** 不按目录逐条罗列,而是找出贯穿的主题。 4. **有实质内容。** 说清楚你看出了什么模式,用户自己可能没有意识到什么。 5. **标题要诗意。** 这是一篇有仪式感的文章。 重要:全文不少于7000字(中文汉字)。宁可写长不可简略。 文库有602篇笔记,素材充足,请充分利用。 输出格式:纯 Markdown。 文章结构参考: ### 序章 ### 上卷:你是谁 ### 中卷:你的系统此时的样子 ### 下卷:从这里你可以走向哪里 ### 尾声""" def build_vault_overview(): """Build a structured overview of the vault with more content.""" if not os.path.exists(VAULT_DIR): return "Obsidian vault not found at " + VAULT_DIR lines = [] lines.append("## 文库目录结构") lines.append("") for d in sorted(os.listdir(VAULT_DIR)): dpath = os.path.join(VAULT_DIR, d) if not os.path.isdir(dpath) or d.startswith("."): continue count = 0 for root, dirs, files in os.walk(dpath): for f in files: if f.endswith(".md"): count += 1 lines.append("- " + d + ":" + str(count) + "篇") # List first few files for root, dirs, files in os.walk(dpath): for f in sorted(files)[:5]: if f.endswith(".md"): lines.append(" - " + f) break lines.append("") lines.append("---") lines.append("") # Read more sections with more files sections_to_read = [ ("01 写作/随笔", 5), ("03 日志/日省录", 2), ("03 日志/交易日志", 2), ("03 日志/散步杂记", 1), ("00 Inbox", 8), ("05 投资交易", 8), ("02 阅读学习/微信读书阅读摘录", 5), ("07 时间容器", 3), ] for section, max_files in sections_to_read: section_path = os.path.join(VAULT_DIR, section) if not os.path.exists(section_path): continue lines.append("## 来自 " + section) lines.append("") files = [f for f in os.listdir(section_path) if f.endswith(".md")] files.sort() for fname in files[:max_files]: fpath = os.path.join(section_path, fname) try: with open(fpath, "r", encoding="utf-8", errors="ignore") as f: content = f.read() if content.startswith("---"): idx = content.find("---", 3) if idx != -1: content = content[idx + 3:].strip() if len(content) > 1500: content = content[:1500] + "...\n[截断,全文" + str(len(content)) + "字]" lines.append("### " + fname) lines.append("") lines.append(content) lines.append("") except Exception as e: lines.append("### " + fname + " (error: " + str(e) + ")") lines.append("") return "\n".join(lines) def git_push(): """Commit and push to Gitea.""" try: subprocess.run(["git", "add", "ai-insights/daily/"], cwd=PROJECT_DIR, capture_output=True, timeout=15) result = subprocess.run(["git", "status", "--porcelain", "ai-insights/"], cwd=PROJECT_DIR, capture_output=True, text=True, timeout=10) if not result.stdout.strip(): logger.info("No changes to commit") return True date_str = datetime.now(TZ_BEIJING).strftime("%Y-%m-%d %H:%M") subprocess.run(["git", "commit", "-m", "panorama v2 " + date_str], cwd=PROJECT_DIR, capture_output=True, timeout=15) subprocess.run(["git", "push", "origin", "main"], cwd=PROJECT_DIR, capture_output=True, timeout=30) logger.info("Pushed to Gitea") return True except Exception as e: logger.error("git push error: %s", e) return False def main(): secrets = load_secrets() llm = DeepSeekClient( api_key=secrets["deepseek_api_key"], model=secrets.get("deepseek_model", "deepseek-chat"), temperature=0.6 ) logger.info("Building vault overview...") overview = build_vault_overview() logger.info("Vault overview built: %d chars", len(overview)) user_prompt = "以下是我的完整 Obsidian 文库(602篇笔记),请基于所有素材写一篇不少于7000字的全景分析:\n\n" + overview logger.info("Calling DeepSeek API for panorama analysis v2...") result = llm.ask(system_prompt=PANORAMA_PROMPT, user_prompt=user_prompt) now = datetime.now(TZ_BEIJING) content = "---\ndate: " + now.strftime("%Y-%m-%d") + "\ntype: panorama\ntags: [全景分析, 文库初析, v2]\n---\n\n" content += result output_dir = get_output_dir("daily") filename = "02_千川赴海_全景分析_v2.md" filepath = os.path.join(output_dir, filename) with open(filepath, "w", encoding="utf-8") as f: f.write(content) logger.info("Written: %s (%d chars)", filepath, len(result)) print("Done: " + filepath + " (" + str(len(result)) + " chars)") git_push() if __name__ == "__main__": main()