log.py 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445
  1. """阅读日志服务 —— 论文阅读时间记录、阅读日历数据生成与统计."""
  2. from __future__ import annotations
  3. import datetime as _dt, sqlite3, time
  4. from ...utils.common import exec_sql
  5. def ensure_tables(db_path: str) -> None:
  6. exec_sql(db_path,
  7. """CREATE TABLE IF NOT EXISTS paper_reading_sessions (
  8. id INTEGER PRIMARY KEY AUTOINCREMENT,
  9. paper_id INTEGER NOT NULL, duration_sec INTEGER NOT NULL,
  10. day_key TEXT NOT NULL, created_at INTEGER NOT NULL)""",
  11. "CREATE INDEX IF NOT EXISTS idx_prs_day ON paper_reading_sessions(day_key, created_at)",
  12. "CREATE INDEX IF NOT EXISTS idx_prs_paper ON paper_reading_sessions(paper_id, created_at)")
  13. def append_session(db_path: str, *, paper_id: int, duration_sec: int, client_ts: int | None = None) -> None:
  14. if not db_path or int(duration_sec or 0) <= 0:
  15. return
  16. ensure_tables(db_path)
  17. dur = min(int(duration_sec), 86400)
  18. ts = int(client_ts) if client_ts else int(time.time())
  19. day = _dt.datetime.fromtimestamp(ts).strftime("%Y-%m-%d")
  20. conn = sqlite3.connect(db_path)
  21. try:
  22. conn.execute("INSERT INTO paper_reading_sessions(paper_id,duration_sec,day_key,created_at) VALUES(?,?,?,?)",
  23. (int(paper_id), dur, day, int(time.time())))
  24. conn.commit()
  25. finally:
  26. conn.close()
  27. def list_daily_aggregate(db_path: str, *, days: int = 180) -> list[dict[str, int | str]]:
  28. if not db_path:
  29. return []
  30. ensure_tables(db_path)
  31. d = max(7, min(int(days or 180), 366))
  32. start = _dt.datetime.fromtimestamp(int(time.time()) - (d - 1) * 86400).strftime("%Y-%m-%d")
  33. conn = sqlite3.connect(db_path)
  34. conn.row_factory = sqlite3.Row
  35. try:
  36. rows = conn.execute(
  37. "SELECT day_key, SUM(duration_sec) AS seconds, COUNT(*) AS sessions FROM paper_reading_sessions WHERE day_key>=? GROUP BY day_key ORDER BY day_key",
  38. (start,)).fetchall()
  39. return [{"date": r["day_key"], "seconds": int(r["seconds"] or 0), "sessions": int(r["sessions"] or 0)} for r in rows]
  40. finally:
  41. conn.close()