Files
inspiration-collector/analyzers/first_panorama.py

160 lines
5.9 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""First panorama analysis - reads entire Obsidian vault and generates AI analysis."""
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. **标题要诗意。** 这是一篇有仪式感的文章——第一次,有人完整阅读了另一个人的思想合集。
输出格式:纯 Markdown。
文章结构参考:
### 序章
### 上卷:你是谁
### 中卷:你的系统此时的样子
### 下卷:从这里你可以走向哪里
### 尾声
文库有602篇笔记主题涵盖投资交易101篇、阅读学习189篇、日记日志128篇、工作37篇、平台配置59篇、写作21篇、时间容器22篇等。"""
def build_vault_overview():
"""Build a structured overview of the vault."""
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) + "")
lines.append("")
lines.append("---")
lines.append("")
sections_to_read = [
("01 写作/随笔", 3),
("03 日志/日省录", 2),
("03 日志/交易日志", 2),
("00 Inbox", 5),
("05 投资交易", 5),
("02 阅读学习/微信读书阅读摘录", 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) > 1200:
content = content[:1200] + "...\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 " + 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 文库,请认真阅读并写一篇全景分析文章:\n\n" + overview
logger.info("Calling DeepSeek API for panorama analysis...")
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: [全景分析, 文库初析]\n---\n\n"
content += result
output_dir = get_output_dir("daily")
filename = "01_千川赴海_全景分析_AI版.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()