Files
openclaw-config/workspace-resume/weekly-reports/import_md_to_db.py
T

107 lines
4.7 KiB
Python
Raw 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.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""从 weekly-reports/2026/*.md(标准格式)重建 SQLite 周报数据。
对已存在的 (year,week,project) 记录执行 UPSERT(先删后插),保证与归档文件一致。
"""
import glob
import os
import re
import sqlite3
BASE = "/home/yangxuan/.openclaw/workspace-resume/weekly-reports"
ARCHIVE_DIR = os.path.join(BASE, "2026")
DB = os.path.join(BASE, "weekly_reports.db")
WEEKDAY_MAP = {"周一": 1, "周二": 2, "周三": 3, "周四": 4, "周五": 5, "周六": 6, "周日": 7}
def parse_md(path):
"""解析标准格式 Markdown,返回 dict"""
with open(path, encoding="utf-8") as f:
text = f.read()
title_m = re.search(r"^#\s*((?:G5|G6))\s*开发周报\s*\(2026-W(\d{2})\)", text, re.M)
project = title_m.group(1) if title_m else "G5"
week = int(title_m.group(2)) if title_m else None
start = end = None
m = re.search(r"\*\*日期范围:\*\*\s*(\d{4}-\d{2}-\d{2})\s*~\s*(\d{4}-\d{2}-\d{2})", text)
if m:
start, end = m.group(1), m.group(2)
main_task = ""
m = re.search(r"主要任务:\s*(.+)", text)
if m:
main_task = m.group(1).strip()
days = []
cur_weekday = None
probs = []
in_prob = False
for line in text.splitlines():
dm = re.match(r"^(周一|周二|周三|周四|周五|周六|周日)((\d{4}-\d{2}-\d{2})", line)
if dm:
cur_weekday = WEEKDAY_MAP[dm.group(1)]
days.append({"weekday": cur_weekday, "date": dm.group(2), "items": []})
in_prob = False
continue
if line.strip().startswith("## 存在问题"):
in_prob = True
continue
if line.strip().startswith("## "):
in_prob = False
continue
if line.strip().startswith("- ") or line.strip().startswith(" - "):
item = re.sub(r"^\s*-\s*", "", line).strip()
if not item:
continue
if in_prob and item not in ("无", "暂无"):
probs.append(item)
elif days:
days[-1]["items"].append(item)
return {"project": project, "week": week, "start": start, "end": end,
"main_task": main_task, "days": days, "problems": probs}
def main():
conn = sqlite3.connect(DB)
cur = conn.cursor()
files = sorted(glob.glob(os.path.join(ARCHIVE_DIR, "2026-W*-周报.md")))
total = 0
# 清空 2026 年全部周报(含级联明细/问题),用归档文件全量重建,保证一致
cur.execute("DELETE FROM weekly_report_daily WHERE report_id IN (SELECT id FROM weekly_reports WHERE year=2026)")
cur.execute("DELETE FROM weekly_report_problems WHERE report_id IN (SELECT id FROM weekly_reports WHERE year=2026)")
cur.execute("DELETE FROM weekly_reports WHERE year=2026")
for path in files:
data = parse_md(path)
if data["week"] is None or not data["start"]:
print(f"⏭ 跳过(无法解析):{os.path.basename(path)}")
continue
wnum = data["week"]
# 先删除已有 (year, week, project) 记录(含级联明细/问题)
cur.execute(
"DELETE FROM weekly_reports WHERE year=? AND week_number=? AND project=?",
(2026, wnum, data["project"]))
cur.execute(
"""INSERT INTO weekly_reports
(year, week_number, start_date, end_date, project, main_task, has_problems, file_path, word_count)
VALUES (?,?,?,?,?,?,?,?,?)""",
(2026, wnum, data["start"], data["end"], data["project"], data["main_task"],
len(data["problems"]) > 0, path, len(data["main_task"])))
rid = cur.lastrowid
for d in data["days"]:
cur.execute(
"INSERT INTO weekly_report_daily (report_id, day_of_week, work_date, work_items) VALUES (?,?,?,?)",
(rid, d["weekday"], d["date"], "\n".join(d["items"])))
for p in data["problems"]:
cur.execute(
"INSERT INTO weekly_report_problems (report_id, problem_description) VALUES (?,?)",
(rid, p))
total += 1
print(f"✅ W{wnum:02d} ({data['project']}) | {data['start']}~{data['end']} | "
f"天{len(data['days'])} 问题{len(data['problems'])}")
conn.commit()
print(f"\n完成:共入库 {total} 份周报")
# 统计
print("\n=== 数据库现况 ===")
for row in cur.execute(
"SELECT week_number, project, start_date, end_date, main_task, has_problems FROM weekly_reports WHERE year=2026 ORDER BY week_number"):
print(f" W{row[0]:02d} | {row[1]} | {row[2]}~{row[3]} | 问题{row[5]} | {row[4][:28]}")
conn.close()
if __name__ == "__main__":
main()