Persist stage context snapshots for run workflows
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -201,8 +201,8 @@
|
|||||||
<div style="width:100%; height:100%; box-sizing:border-box; font-family:'Segoe UI',sans-serif; display:flex; flex-direction:column; gap:12px;">
|
<div style="width:100%; height:100%; box-sizing:border-box; font-family:'Segoe UI',sans-serif; display:flex; flex-direction:column; gap:12px;">
|
||||||
<div class="comparison-summary-card" style="background:#ffffff; border:1px solid #cbd5e1; border-radius:14px; overflow:hidden; box-shadow:0 10px 22px rgba(15,23,42,0.08);">
|
<div class="comparison-summary-card" style="background:#ffffff; border:1px solid #cbd5e1; border-radius:14px; overflow:hidden; box-shadow:0 10px 22px rgba(15,23,42,0.08);">
|
||||||
<div style="padding:12px 14px; background:linear-gradient(135deg,#eff6ff 0%,#dbeafe 100%); border-bottom:1px solid #bfdbfe;">
|
<div style="padding:12px 14px; background:linear-gradient(135deg,#eff6ff 0%,#dbeafe 100%); border-bottom:1px solid #bfdbfe;">
|
||||||
<div style="font-size:11px; font-weight:700; color:#1d4ed8; letter-spacing:0.08em; text-transform:uppercase; margin-bottom:4px;">Comparison</div>
|
<div style="font-size:10.0px; font-weight:700; color:#1d4ed8; letter-spacing:0.08em; text-transform:uppercase; margin-bottom:4px;">Comparison</div>
|
||||||
<div style="font-size:16px; font-weight:800; color:#0f172a;">DX와 BIM 핵심 비교</div>
|
<div style="font-size:10.0px; font-weight:800; color:#0f172a;">DX와 BIM 핵심 비교</div>
|
||||||
</div>
|
</div>
|
||||||
<div style="padding:10px 14px 12px; display:grid; grid-template-columns:80px 1fr; row-gap:8px; column-gap:10px; font-size:10px; line-height:1.45; color:#334155;">
|
<div style="padding:10px 14px 12px; display:grid; grid-template-columns:80px 1fr; row-gap:8px; column-gap:10px; font-size:10px; line-height:1.45; color:#334155;">
|
||||||
<div style="font-weight:800; color:#0f172a;">범위</div><div>DX는 BIM을 포함하는 상위 개념, BIM은 3D 중심 기술</div>
|
<div style="font-weight:800; color:#0f172a;">범위</div><div>DX는 BIM을 포함하는 상위 개념, BIM은 3D 중심 기술</div>
|
||||||
@@ -213,8 +213,8 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style="background:#f8fafc; border:1px solid #cbd5e1; border-radius:14px; padding:14px; box-sizing:border-box;">
|
<div style="background:#f8fafc; border:1px solid #cbd5e1; border-radius:14px; padding:14px; box-sizing:border-box;">
|
||||||
<div style="font-size:11px; font-weight:700; color:#475569; letter-spacing:0.08em; text-transform:uppercase; margin-bottom:6px;">Evidence</div>
|
<div style="font-size:10.0px; font-weight:700; color:#475569; letter-spacing:0.08em; text-transform:uppercase; margin-bottom:6px;">Evidence</div>
|
||||||
<div style="font-size:14px; font-weight:800; color:#0f172a; margin-bottom:8px;">정책 문서에서도 혼용</div>
|
<div style="font-size:10.0px; font-weight:800; color:#0f172a; margin-bottom:8px;">정책 문서에서도 혼용</div>
|
||||||
<div style="font-size:10px; line-height:1.55; color:#475569;">• 스마트 건설 활성화 방안: 디지털화 방향 아래 BIM 전면 도입 제시</div>
|
<div style="font-size:10px; line-height:1.55; color:#475569;">• 스마트 건설 활성화 방안: 디지털화 방향 아래 BIM 전면 도입 제시</div>
|
||||||
<div style="font-size:10px; line-height:1.55; color:#475569;">• 제7차 건설기술진흥 기본계획: DX 추진 방향 아래 BIM 도입 실행 과제 제시</div>
|
<div style="font-size:10px; line-height:1.55; color:#475569;">• 제7차 건설기술진흥 기본계획: DX 추진 방향 아래 BIM 도입 실행 과제 제시</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
513
docs/run-001/05-execution/final_context.json
Normal file
513
docs/run-001/05-execution/final_context.json
Normal file
File diff suppressed because one or more lines are too long
75
docs/run-001/05-execution/stage_0_context.json
Normal file
75
docs/run-001/05-execution/stage_0_context.json
Normal file
File diff suppressed because one or more lines are too long
297
docs/run-001/05-execution/stage_1_5a_context.json
Normal file
297
docs/run-001/05-execution/stage_1_5a_context.json
Normal file
File diff suppressed because one or more lines are too long
474
docs/run-001/05-execution/stage_1_5b_context.json
Normal file
474
docs/run-001/05-execution/stage_1_5b_context.json
Normal file
File diff suppressed because one or more lines are too long
446
docs/run-001/05-execution/stage_1_7_context.json
Normal file
446
docs/run-001/05-execution/stage_1_7_context.json
Normal file
File diff suppressed because one or more lines are too long
175
docs/run-001/05-execution/stage_1a_context.json
Normal file
175
docs/run-001/05-execution/stage_1a_context.json
Normal file
File diff suppressed because one or more lines are too long
175
docs/run-001/05-execution/stage_1b_context.json
Normal file
175
docs/run-001/05-execution/stage_1b_context.json
Normal file
File diff suppressed because one or more lines are too long
479
docs/run-001/05-execution/stage_2_context.json
Normal file
479
docs/run-001/05-execution/stage_2_context.json
Normal file
File diff suppressed because one or more lines are too long
36
docs/run-001/05-execution/stage_2_verification.json
Normal file
36
docs/run-001/05-execution/stage_2_verification.json
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
{
|
||||||
|
"body_bg": {
|
||||||
|
"passed": false,
|
||||||
|
"score": 0.7666666666666666,
|
||||||
|
"errors": [
|
||||||
|
"누락 문장 (7/10):",
|
||||||
|
" - \"* 이로인해 BIM기술의 도입을 DX의 완성으로 오인하거나, DX를 BIM 기술 도입 수준으로 한정하는 인식...\"",
|
||||||
|
" - \"* **[스마트 건설 활성화 방안(2022.07)]**\"",
|
||||||
|
" - \"* 추진과제 : 건설산업 디지털화\"",
|
||||||
|
" - \"* 실행과제 : BIM 전면 도입, BIM 전문인력 양성\"",
|
||||||
|
" - \"* **[제7차 건설기술진흥 기본계획(2023.12)]**\""
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"body_core": {
|
||||||
|
"passed": false,
|
||||||
|
"score": 0.8854166666666666,
|
||||||
|
"errors": [
|
||||||
|
"누락 문장 (11/32):",
|
||||||
|
" - \"| **BIM << DX**(Engineering + Management 통합) | **범위** ...\"",
|
||||||
|
" - \"| **제작 및 운영**(상용 + 전용 40~80개)[Rhino, Sketchup, Blender..] + ...\"",
|
||||||
|
" - \"| **공학 정보 및 콘텐츠 연계에 집중****도면, 수량, 시공계획 등 일식** | **성과품** | **...\"",
|
||||||
|
" - \"| **설계/시공 생산성 혁신**(개념의 재정립) | **활용** | **3D 모델에 의한 일반적 이해 향상...\"",
|
||||||
|
" - \"| **전 생애주기 활용 시스템** | **확장성** | **(설계/시공/운영) 분야별 단절** |\""
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"sidebar": {
|
||||||
|
"passed": true,
|
||||||
|
"score": 1.0,
|
||||||
|
"errors": []
|
||||||
|
},
|
||||||
|
"footer": {
|
||||||
|
"passed": true,
|
||||||
|
"score": 1.0,
|
||||||
|
"errors": []
|
||||||
|
}
|
||||||
|
}
|
||||||
479
docs/run-001/05-execution/stage_3_context.json
Normal file
479
docs/run-001/05-execution/stage_3_context.json
Normal file
File diff suppressed because one or more lines are too long
513
docs/run-001/05-execution/stage_4_context.json
Normal file
513
docs/run-001/05-execution/stage_4_context.json
Normal file
File diff suppressed because one or more lines are too long
@@ -5,7 +5,8 @@ import asyncio
|
|||||||
import json
|
import json
|
||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
DESIGN_AGENT_ROOT = Path(r'D:\\ad-hoc\\kei\\design_agent')
|
|
||||||
|
DESIGN_AGENT_ROOT = Path(r'D:\ad-hoc\kei\design_agent')
|
||||||
if str(DESIGN_AGENT_ROOT) not in sys.path:
|
if str(DESIGN_AGENT_ROOT) not in sys.path:
|
||||||
sys.path.insert(0, str(DESIGN_AGENT_ROOT))
|
sys.path.insert(0, str(DESIGN_AGENT_ROOT))
|
||||||
|
|
||||||
@@ -30,6 +31,7 @@ from src.pipeline_context import (
|
|||||||
)
|
)
|
||||||
from src.renderer import render_slide_from_html
|
from src.renderer import render_slide_from_html
|
||||||
from src.slide_measurer import capture_slide_screenshot, measure_rendered_heights
|
from src.slide_measurer import capture_slide_screenshot, measure_rendered_heights
|
||||||
|
|
||||||
if not hasattr(html_generator, 'SIDEBAR_PROMPT') and hasattr(html_generator, '_LEGACY_SIDEBAR_PROMPT'):
|
if not hasattr(html_generator, 'SIDEBAR_PROMPT') and hasattr(html_generator, '_LEGACY_SIDEBAR_PROMPT'):
|
||||||
html_generator.SIDEBAR_PROMPT = html_generator._LEGACY_SIDEBAR_PROMPT
|
html_generator.SIDEBAR_PROMPT = html_generator._LEGACY_SIDEBAR_PROMPT
|
||||||
if not hasattr(html_generator, 'FOOTER_PROMPT') and hasattr(html_generator, '_LEGACY_FOOTER_PROMPT'):
|
if not hasattr(html_generator, 'FOOTER_PROMPT') and hasattr(html_generator, '_LEGACY_FOOTER_PROMPT'):
|
||||||
@@ -48,10 +50,12 @@ def _load_json(path: Path) -> dict:
|
|||||||
return json.loads(path.read_text(encoding='utf-8-sig'))
|
return json.loads(path.read_text(encoding='utf-8-sig'))
|
||||||
|
|
||||||
|
|
||||||
def _build_context(content: str, base_path: str, stage1a: dict, stage1b: dict) -> PipelineContext:
|
def _write_json(path: Path, data: dict) -> None:
|
||||||
ctx = create_context(content, base_path)
|
path.write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding='utf-8')
|
||||||
|
|
||||||
normalized = normalize_mdx_content(content)
|
|
||||||
|
def _stage_0(ctx: PipelineContext) -> PipelineContext:
|
||||||
|
normalized = normalize_mdx_content(ctx.raw_content)
|
||||||
ctx.normalized = NormalizedContent(
|
ctx.normalized = NormalizedContent(
|
||||||
clean_text=normalized['clean_text'],
|
clean_text=normalized['clean_text'],
|
||||||
title=normalized['title'],
|
title=normalized['title'],
|
||||||
@@ -60,7 +64,11 @@ def _build_context(content: str, base_path: str, stage1a: dict, stage1b: dict) -
|
|||||||
tables=normalized['tables'],
|
tables=normalized['tables'],
|
||||||
sections=normalized['sections'],
|
sections=normalized['sections'],
|
||||||
)
|
)
|
||||||
|
ctx.save_snapshot('stage_0')
|
||||||
|
return ctx
|
||||||
|
|
||||||
|
|
||||||
|
def _stage_1a(ctx: PipelineContext, stage1a: dict) -> PipelineContext:
|
||||||
analysis_raw = stage1a['analysis']
|
analysis_raw = stage1a['analysis']
|
||||||
ctx.analysis = Analysis(
|
ctx.analysis = Analysis(
|
||||||
core_message=analysis_raw['core_message'],
|
core_message=analysis_raw['core_message'],
|
||||||
@@ -68,15 +76,21 @@ def _build_context(content: str, base_path: str, stage1a: dict, stage1b: dict) -
|
|||||||
total_pages=analysis_raw.get('total_pages', 1),
|
total_pages=analysis_raw.get('total_pages', 1),
|
||||||
)
|
)
|
||||||
ctx.page_structure = PageStructure(roles=stage1a['page_structure'])
|
ctx.page_structure = PageStructure(roles=stage1a['page_structure'])
|
||||||
|
ctx.topics = [Topic(**raw) for raw in stage1a['topics']]
|
||||||
|
ctx.save_snapshot('stage_1a')
|
||||||
|
return ctx
|
||||||
|
|
||||||
|
|
||||||
|
def _stage_1b(ctx: PipelineContext, stage1b: dict) -> PipelineContext:
|
||||||
refined_map = {item['topic_id']: item for item in stage1b['concepts']}
|
refined_map = {item['topic_id']: item for item in stage1b['concepts']}
|
||||||
topics = []
|
topics = []
|
||||||
for raw in stage1a['topics']:
|
for raw in ctx.topics:
|
||||||
merged = dict(raw)
|
merged = raw.model_dump()
|
||||||
if raw['id'] in refined_map:
|
if raw.id in refined_map:
|
||||||
merged.update(refined_map[raw['id']])
|
merged.update(refined_map[raw.id])
|
||||||
topics.append(Topic(**merged))
|
topics.append(Topic(**merged))
|
||||||
ctx.topics = topics
|
ctx.topics = topics
|
||||||
|
ctx.save_snapshot('stage_1b')
|
||||||
return ctx
|
return ctx
|
||||||
|
|
||||||
|
|
||||||
@@ -138,6 +152,7 @@ def _stage_1_5a(ctx: PipelineContext) -> PipelineContext:
|
|||||||
})
|
})
|
||||||
ctx.slide_images = slide_images
|
ctx.slide_images = slide_images
|
||||||
ctx.analysis = ctx.analysis.model_copy(update={'image_sizes': image_sizes or {}})
|
ctx.analysis = ctx.analysis.model_copy(update={'image_sizes': image_sizes or {}})
|
||||||
|
ctx.save_snapshot('stage_1_5a')
|
||||||
return ctx
|
return ctx
|
||||||
|
|
||||||
|
|
||||||
@@ -157,6 +172,7 @@ def _stage_1_7(ctx: PipelineContext) -> PipelineContext:
|
|||||||
)
|
)
|
||||||
for role, ref in refs_raw.items()
|
for role, ref in refs_raw.items()
|
||||||
}
|
}
|
||||||
|
ctx.save_snapshot('stage_1_7')
|
||||||
return ctx
|
return ctx
|
||||||
|
|
||||||
|
|
||||||
@@ -184,6 +200,7 @@ def _stage_1_5b(ctx: PipelineContext) -> PipelineContext:
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
ctx.containers = updated
|
ctx.containers = updated
|
||||||
|
ctx.save_snapshot('stage_1_5b')
|
||||||
return ctx
|
return ctx
|
||||||
|
|
||||||
|
|
||||||
@@ -218,7 +235,7 @@ async def _stage_2(ctx: PipelineContext) -> PipelineContext:
|
|||||||
for role, ci in ctx.containers.items()
|
for role, ci in ctx.containers.items()
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
generated, _verification = await generate_with_retry(
|
generated, verification = await generate_with_retry(
|
||||||
content=ctx.raw_content,
|
content=ctx.raw_content,
|
||||||
analysis=analysis_dict,
|
analysis=analysis_dict,
|
||||||
container_specs=container_specs_dict,
|
container_specs=container_specs_dict,
|
||||||
@@ -226,6 +243,16 @@ async def _stage_2(ctx: PipelineContext) -> PipelineContext:
|
|||||||
images=ctx.slide_images,
|
images=ctx.slide_images,
|
||||||
)
|
)
|
||||||
ctx.generated_html = generated
|
ctx.generated_html = generated
|
||||||
|
verification_path = ctx.get_run_dir() / 'stage_2_verification.json'
|
||||||
|
_write_json(verification_path, {
|
||||||
|
area: {
|
||||||
|
'passed': result.passed,
|
||||||
|
'score': result.score,
|
||||||
|
'errors': result.errors,
|
||||||
|
}
|
||||||
|
for area, result in verification.items()
|
||||||
|
})
|
||||||
|
ctx.save_snapshot('stage_2')
|
||||||
return ctx
|
return ctx
|
||||||
|
|
||||||
|
|
||||||
@@ -239,15 +266,17 @@ def _stage_3(ctx: PipelineContext) -> PipelineContext:
|
|||||||
ctx.rendered_html = render_slide_from_html(ctx.generated_html, analysis_dict, ctx.preset)
|
ctx.rendered_html = render_slide_from_html(ctx.generated_html, analysis_dict, ctx.preset)
|
||||||
if ctx.base_path:
|
if ctx.base_path:
|
||||||
ctx.rendered_html = embed_images(ctx.rendered_html, ctx.base_path)
|
ctx.rendered_html = embed_images(ctx.rendered_html, ctx.base_path)
|
||||||
|
ctx.save_snapshot('stage_3')
|
||||||
return ctx
|
return ctx
|
||||||
|
|
||||||
|
|
||||||
def _stage_4_lite(ctx: PipelineContext) -> PipelineContext:
|
def _stage_4(ctx: PipelineContext) -> PipelineContext:
|
||||||
ctx.measurement = measure_rendered_heights(ctx.rendered_html)
|
ctx.measurement = measure_rendered_heights(ctx.rendered_html)
|
||||||
ctx.screenshot_b64 = capture_slide_screenshot(ctx.rendered_html) or ''
|
ctx.screenshot_b64 = capture_slide_screenshot(ctx.rendered_html) or ''
|
||||||
ctx.quality_score = 100 if not any(
|
ctx.quality_score = 100 if not any(
|
||||||
zone.get('overflowed') for zone in ctx.measurement.get('zones', {}).values()
|
zone.get('overflowed') for zone in ctx.measurement.get('zones', {}).values()
|
||||||
) else 60
|
) else 60
|
||||||
|
ctx.save_snapshot('stage_4')
|
||||||
return ctx
|
return ctx
|
||||||
|
|
||||||
|
|
||||||
@@ -264,16 +293,22 @@ async def main() -> None:
|
|||||||
stage1a = _load_json(Path(args.stage1a))
|
stage1a = _load_json(Path(args.stage1a))
|
||||||
stage1b = _load_json(Path(args.stage1b))
|
stage1b = _load_json(Path(args.stage1b))
|
||||||
|
|
||||||
ctx = _build_context(content, args.base_path, stage1a, stage1b)
|
out_dir = Path(args.output_dir)
|
||||||
|
out_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
ctx = create_context(content, args.base_path)
|
||||||
|
ctx.run_dir = str(out_dir)
|
||||||
|
|
||||||
|
ctx = _stage_0(ctx)
|
||||||
|
ctx = _stage_1a(ctx, stage1a)
|
||||||
|
ctx = _stage_1b(ctx, stage1b)
|
||||||
ctx = _stage_1_5a(ctx)
|
ctx = _stage_1_5a(ctx)
|
||||||
ctx = _stage_1_7(ctx)
|
ctx = _stage_1_7(ctx)
|
||||||
ctx = _stage_1_5b(ctx)
|
ctx = _stage_1_5b(ctx)
|
||||||
ctx = await _stage_2(ctx)
|
ctx = await _stage_2(ctx)
|
||||||
ctx = _stage_3(ctx)
|
ctx = _stage_3(ctx)
|
||||||
ctx = _stage_4_lite(ctx)
|
ctx = _stage_4(ctx)
|
||||||
|
|
||||||
out_dir = Path(args.output_dir)
|
|
||||||
out_dir.mkdir(parents=True, exist_ok=True)
|
|
||||||
(out_dir / 'generated_html.json').write_text(
|
(out_dir / 'generated_html.json').write_text(
|
||||||
json.dumps(ctx.generated_html, ensure_ascii=False, indent=2),
|
json.dumps(ctx.generated_html, ensure_ascii=False, indent=2),
|
||||||
encoding='utf-8',
|
encoding='utf-8',
|
||||||
@@ -287,10 +322,11 @@ async def main() -> None:
|
|||||||
ctx.model_dump_json(indent=2, exclude={'screenshot_b64', 'rendered_html'}),
|
ctx.model_dump_json(indent=2, exclude={'screenshot_b64', 'rendered_html'}),
|
||||||
encoding='utf-8',
|
encoding='utf-8',
|
||||||
)
|
)
|
||||||
|
(out_dir / 'final_context.json').write_text(
|
||||||
|
ctx.model_dump_json(indent=2, exclude={'screenshot_b64', 'rendered_html'}),
|
||||||
|
encoding='utf-8',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
asyncio.run(main())
|
asyncio.run(main())
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user