daily folder structure: each date gets its own directory

This commit is contained in:
Beast
2026-06-13 09:48:49 +08:00
parent 75dbbee7cc
commit a921c40dba
8 changed files with 581 additions and 131 deletions

159
analyzers/first_panorama.py Normal file
View File

@ -0,0 +1,159 @@
"""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()