Improve slide quality loop and refresh run-001 output

This commit is contained in:
2026-04-02 13:57:20 +09:00
parent 40ad9ce2f0
commit a0c157d3f7
25 changed files with 1722 additions and 1486 deletions

View File

@@ -78,7 +78,7 @@ def validate_outputs(generated: dict, measurement: dict) -> tuple[str, list[str]
failures.append("Verify-ImageRef")
actions.append("이미지/도해 참조 문구 `DX와 핵심기술간 상호관계`를 숨김 영역이 아닌 가시 블록으로 유지한다.")
comparison_visible = (COMPARISON_MARKER in body_html or COMPARISON_MARKER in sidebar_html) and all(key in visible_text for key in COMPARE_KEYS)
comparison_visible = (COMPARISON_MARKER in body_html) and all(key in visible_text for key in COMPARE_KEYS)
if not comparison_visible:
failures.append("Verify-ComparisonVisible")
actions.append("비교 핵심 4축(범위, 프로세스, 성과품, 확장성)을 화면에 바로 보이는 요약 블록으로 강제한다.")
@@ -87,6 +87,10 @@ def validate_outputs(generated: dict, measurement: dict) -> tuple[str, list[str]
failures.append("Verify-DesignStructure")
actions.append("핵심 관계를 설명하는 시각적 관계도 블록을 본문 중심 구조로 유지한다.")
if "왜 다시 정리해야 하는가" not in visible_text:
failures.append("Verify-DesignNarrative")
actions.append("문제 제기와 핵심 판단을 분리한 슬라이드형 서두를 구성한다.")
if failures:
return "revise", sorted(set(failures)), list(dict.fromkeys(actions))
return "pass", [], []
@@ -149,6 +153,45 @@ def write_step_comment(path: Path, body: str) -> None:
path.write_text(body, encoding="utf-8")
def read_text_if_exists(path: Path) -> str:
return path.read_text(encoding="utf-8-sig") if path.exists() else ""
def summarize_markdown_lines(text: str, limit: int = 8) -> list[str]:
lines: list[str] = []
for raw in text.splitlines():
line = raw.strip()
if not line or line.startswith('#'):
continue
line = re.sub(r'^[-*]\s*', '', line)
line = re.sub(r'^\d+\.\s*', '', line)
if not line:
continue
if len(line) > 120:
line = compact_text(line, max(96, int(len(line) * 0.8)))
lines.append(line)
if len(lines) >= limit:
break
return lines
def build_step_comment(title: str, artifact_path: Path, lines: list[str], verdict: str = "pass") -> str:
bullet_text = "\n".join(f"- {line}" for line in lines) if lines else "- ??? ???."
return f"""?? ??
- {title} ???? ???? ??? ???.
- ??? ??: `{artifact_path.as_posix()}`
?? ??
{bullet_text}
KPI / ?? ??
- ??: {verdict}
?? ?? ???
- `{artifact_path.as_posix()}`
"""
def post_comment_if_configured(repo: str, issue_number: int, body_file: Path) -> None:
base_url = os.getenv("GITEA_URL", "").strip()
token = os.getenv("GITEA_TOKEN", "").strip()
@@ -166,6 +209,13 @@ def compact_text(text: str, max_len: int) -> str:
return (cut or normalized[:max_len]).rstrip(" ,.;:") + "..."
def preserve_80_percent(text: str, floor: int = 80, ceiling: int = 180) -> int:
normalized = re.sub(r"\s+", " ", text).strip()
if not normalized:
return floor
return max(floor, min(ceiling, int(len(normalized) * 0.8)))
def ensure_phrase(base: str, phrase: str) -> str:
if phrase in base:
return base
@@ -261,10 +311,10 @@ def apply_retry_plan_to_stage1b(stage1b_path: Path, retry_plan: dict[str, Any],
concept["summary"] = "결론: BIM은 건설산업 DX를 수행하는 과정의 가장 기초가 되는 일부분이다."
concept["expression_hint"] = ensure_phrase(hint, "footer 또는 결론 배너에서 문장을 축약하지 말고 그대로 강하게 노출한다.")
elif strategy == "compress_visible_copy":
concept["summary"] = compact_text(summary, 60)
concept["summary"] = compact_text(summary, preserve_80_percent(summary, floor=80, ceiling=180))
concept["expression_hint"] = ensure_phrase(hint, "문장 수를 줄이고 핵심 명사구 위주로 압축하되, 핵심 메시지는 유지한다.")
elif strategy == "reduce_density_and_split_visibility":
concept["summary"] = compact_text(summary, 70)
concept["summary"] = compact_text(summary, preserve_80_percent(summary, floor=90, ceiling=200))
concept["expression_hint"] = ensure_phrase(hint, "표현 밀도를 낮추고, 장문 설명 대신 짧은 bullet/card 구조로 나눈다.")
write_json(stage1b_path, data)
@@ -301,6 +351,27 @@ def main() -> None:
5: comments_dir / "step-5.md",
6: comments_dir / "step-6.md",
}
step_artifacts = {
1: run_dir / "01-input" / "input-review.md",
2: run_dir / "02-kei-interpretation" / "kei-interpretation.md",
3: run_dir / "03-structure" / "content-structure.md",
4: run_dir / "04-plan" / "execution-plan.md",
}
step_titles = {
1: "Step 1 ?? ??",
2: "Step 2 ?? ??",
3: "Step 3 ??? ???",
4: "Step 4 ?? ??",
}
for step_no in (1, 2, 3, 4):
artifact_path = step_artifacts[step_no]
artifact_text = read_text_if_exists(artifact_path)
lines = summarize_markdown_lines(artifact_text, limit=8)
body = build_step_comment(step_titles[step_no], artifact_path.relative_to(repo_root), lines, verdict="pass")
write_step_comment(step_comment_bodies[step_no], body)
if step_no - 1 < len(issue_numbers):
post_comment_if_configured(args.repo_slug, issue_numbers[step_no - 1], step_comment_bodies[step_no])
for iteration in range(1, args.max_iterations + 1):
cmd = [
@@ -379,6 +450,11 @@ KPI / 판정 결과
generated = read_json(generated_path)
measurement = read_json(measurement_path)
status, failures, actions = validate_outputs(generated, measurement)
final_html_text = final_html_path.read_text(encoding="utf-8")
if 'width:100%; height:28px' in final_html_text:
status = "revise"
failures = sorted(set(failures + ["Verify-RenderedSidebarBadge"]))
actions = list(dict.fromkeys(actions + ["?? ? ? ?? ???? ??? ???? ??? ?? ?? sidebar ?? ??? ? ???? grid/fixed-width ???? ?????."]))
retry_plan = None
if status != "pass" and iteration < args.max_iterations: