Files
inspiration-collector/analyzers/first_panorama_v2.py

170 lines
6.1 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 (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()