PMFlow/backend/app/services/task_brief/mixin_seed_history.py

116 lines
4.3 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.

from __future__ import annotations
from .shared import *
class TaskBriefSeedHistoryMixin:
@staticmethod
def _extract_markdown_section_lines(content: str, *, heading: str) -> list[str]:
target = f"## {heading}".lower()
lines = content.splitlines()
in_section = False
collected: list[str] = []
for raw in lines:
line = raw.strip()
if line.lower().startswith("## "):
if line.lower() == target:
in_section = True
continue
if in_section:
break
if in_section and line:
collected.append(line)
return collected
@staticmethod
def _extract_markdown_meta_value(content: str, *, key: str) -> str | None:
prefix = f"- {key}:"
for raw in content.splitlines():
line = raw.strip()
if line.startswith(prefix):
return line.split(":", 1)[1].strip() or None
return None
@classmethod
def _normalize_generated_at(cls, raw_generated: str | None, fallback: datetime) -> str:
if not raw_generated:
return fallback.isoformat()
for fmt in ("%Y-%m-%d %H:%M:%S %z",):
try:
return datetime.strptime(raw_generated, fmt).isoformat()
except Exception:
pass
try:
return datetime.fromisoformat(raw_generated).isoformat()
except Exception:
return raw_generated
@classmethod
def _load_seed_history(cls) -> tuple[list[dict[str, Any]], list[dict[str, Any]]]:
docs_dir = cls._project_root() / "docs/task_briefs"
if not docs_dir.exists():
return [], []
briefs: list[dict[str, Any]] = []
runs: list[dict[str, Any]] = []
for file_path in sorted(docs_dir.glob("task_brief_*.md")):
try:
content = file_path.read_text(encoding="utf-8")
except Exception:
continue
if not content.strip():
continue
stem = "".join(ch for ch in file_path.stem if ch.isalnum() or ch in {"_", "-"})
brief_id = f"brief_seed_{stem}"[:64]
run_id = f"run_seed_{stem}"[:64]
fallback_time = datetime.fromtimestamp(file_path.stat().st_mtime)
generated_at = cls._normalize_generated_at(
cls._extract_markdown_meta_value(content, key="Generated At"),
fallback=fallback_time,
)
title = "导入任务包"
for line in content.splitlines():
if line.strip().startswith("# "):
title = line.strip()[2:].strip() or title
break
changed_section = cls._extract_markdown_section_lines(content, heading="Changed Files")
changed_files = [line[2:].strip() for line in changed_section if line.startswith("- ") and line[2:].strip()]
scope_section = cls._extract_markdown_section_lines(content, heading="Scope")
scope_items = [line[2:].strip() if line.startswith("- ") else line for line in scope_section]
scope_summary = ";".join([item for item in scope_items if item][:2]).strip()
if not scope_summary:
scope_summary = "从 docs/task_briefs 自动导入"
run = {
"id": run_id,
"brief_id": brief_id,
"title": title,
"template_id": DEFAULT_TEMPLATE_ID,
"template_name": DEFAULT_TEMPLATE_NAME,
"generated_at": generated_at,
"generated_by": 0,
"status": "imported",
"changed_files": changed_files,
"scope_summary": scope_summary,
}
brief = {
"id": brief_id,
"title": title,
"status": "ready",
"created_at": generated_at,
"updated_at": generated_at,
"latest_run_id": run_id,
"template_id": DEFAULT_TEMPLATE_ID,
"template_name": DEFAULT_TEMPLATE_NAME,
"summary": scope_summary,
"content": content.strip(),
"changed_files": changed_files,
}
runs.append(run)
briefs.append(brief)
return briefs, runs