n8n 連携: 期間の作業区間を集め、送信済み・重なりを判定する
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+72
@@ -1258,6 +1258,78 @@ def make_blocks(session, gap_min=N8N_GAP_MIN, min_min=N8N_MIN_MIN, now=None):
|
||||
return out
|
||||
|
||||
|
||||
def default_task_name(folder, title):
|
||||
"""タスク名の初期値: [作業フォルダ名] セッションのタイトル。"""
|
||||
name = Path(str(folder).replace("\\", "/")).name if folder else ""
|
||||
title = one_line(title, 200)
|
||||
return f"[{name}] {title}" if name else title
|
||||
|
||||
|
||||
def collect_blocks(store, project_id, start, end, gap_min=N8N_GAP_MIN, min_min=N8N_MIN_MIN, now=None):
|
||||
"""期間 [start, end] (date, ローカル) に始まる作業区間を集める。project_id が空なら全プロジェクト。"""
|
||||
lo = datetime.combine(start, datetime.min.time()).timestamp()
|
||||
hi = datetime.combine(end + timedelta(days=1), datetime.min.time()).timestamp()
|
||||
projects = store.projects()
|
||||
if project_id:
|
||||
projects = [p for p in projects if p["id"] == project_id]
|
||||
if not projects:
|
||||
raise FileNotFoundError(project_id)
|
||||
out = []
|
||||
for project in projects:
|
||||
for path in store.session_files(project["id"]):
|
||||
if path.stat().st_mtime < lo:
|
||||
continue # 期間より前に書き終わったログは開かない
|
||||
session = store.session(path)
|
||||
if session["startEpoch"] is None or session["startEpoch"] >= hi:
|
||||
continue
|
||||
folder = session.get("cwd") or project["path"]
|
||||
for block in make_blocks(session, gap_min, min_min, now):
|
||||
if not lo <= block["startEpoch"] < hi:
|
||||
continue
|
||||
block.update(
|
||||
{
|
||||
"project": project["id"],
|
||||
"projectPath": folder,
|
||||
"title": session["title"],
|
||||
"taskName": default_task_name(folder, session["title"]),
|
||||
}
|
||||
)
|
||||
out.append(block)
|
||||
out.sort(key=lambda b: b["startEpoch"])
|
||||
return out
|
||||
|
||||
|
||||
def mark_blocks(blocks, rows, deleted_sources, now=None):
|
||||
"""n8n の work_log の行と突き合わせて、送信済み / 削除済み / 重なりを付ける。
|
||||
|
||||
重なりは [開始, 終了) が少しでも重なること (接しているだけは重ならない)。
|
||||
相手は work_log の行 (進行中は終了 = now) と一覧の他の区間。同じ source は除く。
|
||||
"""
|
||||
now = time.time() if now is None else now
|
||||
sent = {r.get("source") for r in rows if r.get("source")}
|
||||
deleted = set(deleted_sources or ())
|
||||
spans = []
|
||||
for row in rows:
|
||||
start = parse_ts(row.get("start_time"))
|
||||
if start is None:
|
||||
continue
|
||||
end = parse_ts(row.get("end_time")) or now
|
||||
spans.append((start, end, {"kind": "row", "id": row.get("id"), "source": row.get("source") or "",
|
||||
"task": row.get("task") or "", "start": iso(start), "end": iso(end)}))
|
||||
for block in blocks:
|
||||
spans.append((block["startEpoch"], block["endEpoch"], {"kind": "block", "source": block["source"],
|
||||
"task": block.get("taskName") or "",
|
||||
"start": block["start"], "end": block["end"]}))
|
||||
for block in blocks:
|
||||
block["sent"] = block["source"] in sent
|
||||
block["deleted"] = not block["sent"] and block["source"] in deleted
|
||||
block["overlaps"] = [
|
||||
info for start, end, info in spans
|
||||
if info["source"] != block["source"] and start < block["endEpoch"] and block["startEpoch"] < end
|
||||
]
|
||||
return blocks
|
||||
|
||||
|
||||
# ---------------------------------------------------------------- HTTP
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user