Phase P~S 전체 작업물: 검증 스크립트, 블록 템플릿, 설계 문서, 코드 수정
포함 내용: - Phase P/Q/R/S 설계 문서 (IMPROVEMENT-PHASE-*.md) - 영역별 검증 스크립트 (scripts/verify_*.py, test_*.py) - 블록 템플릿 추가 (cards, emphasis 변형) - 코드 수정: block_search, content_editor, design_director, slide_measurer - catalog.yaml 블록 목록 업데이트 - CLAUDE.md, PROGRESS.md, README.md 업데이트 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
369
scripts/test_hybrid.py
Normal file
369
scripts/test_hybrid.py
Normal file
@@ -0,0 +1,369 @@
|
||||
"""하이브리드 시뮬레이션: 기존 블록 활용 + 필요 시 변형/조합.
|
||||
|
||||
블록 사용 현황:
|
||||
- card-icon-desc: 목표 3카드 ← 기존 블록 그대로
|
||||
- dark-bullet-list: 변형 — 불릿 대신 Before→After 구조 (CSS만 추가)
|
||||
- table-simple-striped: 주체별 효과 ← 기존 블록 그대로
|
||||
- banner-gradient: 결론 ← 기존 블록 그대로
|
||||
- 섹션 구분: divider-text 스타일 활용
|
||||
|
||||
블록 사용률: ~70% 기존 블록 + ~30% 변형/자유
|
||||
"""
|
||||
from __future__ import annotations
|
||||
import asyncio, json, sys, base64
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).parent.parent
|
||||
sys.path.insert(0, str(ROOT))
|
||||
|
||||
HYBRID_HTML = """<!DOCTYPE html>
|
||||
<html lang="ko">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>하이브리드 — DX 시행 목표 및 기대 효과</title>
|
||||
<style>
|
||||
@import url('https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.9/dist/web/variable/pretendardvariable-dynamic-subset.min.css');
|
||||
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
|
||||
.slide {
|
||||
width: 1280px; height: 720px; overflow: hidden;
|
||||
background: #ffffff;
|
||||
font-family: 'Pretendard Variable', sans-serif;
|
||||
color: #1e293b;
|
||||
font-size: 13px;
|
||||
line-height: 1.6;
|
||||
word-break: keep-all;
|
||||
display: grid;
|
||||
grid-template-areas: 'header header' 'body sidebar' 'footer footer';
|
||||
grid-template-columns: 65fr 35fr;
|
||||
grid-template-rows: auto 1fr auto;
|
||||
gap: 16px;
|
||||
padding: 36px 40px 24px;
|
||||
}
|
||||
|
||||
/* ── 슬라이드 제목 (기존 base.css) ── */
|
||||
.slide-title {
|
||||
grid-area: header;
|
||||
font-size: 28px;
|
||||
font-weight: 900;
|
||||
color: #1e293b;
|
||||
border-bottom: 3px solid #2563eb;
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
/* ── Body ── */
|
||||
.area-body {
|
||||
grid-area: body;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* ── Sidebar ── */
|
||||
.area-sidebar {
|
||||
grid-area: sidebar;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
border-left: 1px solid #e2e8f0;
|
||||
padding-left: 20px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* ── Footer ── */
|
||||
.area-footer {
|
||||
grid-area: footer;
|
||||
}
|
||||
|
||||
/* ════════════════════════════════════════
|
||||
블록 1: card-icon-desc (기존 블록 100% 재사용)
|
||||
목표 3카드
|
||||
════════════════════════════════════════ */
|
||||
.block-card-icon {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(var(--ci-count, 3), 1fr);
|
||||
gap: 16px;
|
||||
}
|
||||
.cid-card {
|
||||
text-align: center;
|
||||
padding: 14px 12px;
|
||||
background: #f8fafc;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #e2e8f0;
|
||||
}
|
||||
.cid-icon {
|
||||
font-size: 2rem;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.cid-title {
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
color: #1e293b;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
.cid-desc {
|
||||
font-size: 11px;
|
||||
color: #475569;
|
||||
line-height: 1.6;
|
||||
white-space: pre-line;
|
||||
}
|
||||
|
||||
/* ════════════════════════════════════════
|
||||
블록 2: dark-bullet-list 변형 — Before→After 구조
|
||||
기존 dark-bullet-list의 색상/배경/radius 그대로 사용
|
||||
불릿 대신 label + before + after 구조로 변형
|
||||
════════════════════════════════════════ */
|
||||
.block-dark-bullets {
|
||||
background: linear-gradient(135deg, #1e293b 0%, #0f172a 100%);
|
||||
border-radius: 8px;
|
||||
padding: 14px 20px;
|
||||
color: #ffffff;
|
||||
}
|
||||
.db-title {
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
margin-bottom: 8px;
|
||||
color: #93c5fd;
|
||||
}
|
||||
/* 변형: Before→After 그리드 */
|
||||
.db-changes {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 6px;
|
||||
}
|
||||
.db-change {
|
||||
background: rgba(255,255,255,0.06);
|
||||
border-radius: 6px;
|
||||
padding: 8px 10px;
|
||||
border-left: 3px solid #60a5fa;
|
||||
}
|
||||
.db-change-label {
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
color: #93c5fd;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
.db-change-before {
|
||||
font-size: 10px;
|
||||
color: #94a3b8;
|
||||
text-decoration: line-through;
|
||||
}
|
||||
.db-change-after {
|
||||
font-size: 11px;
|
||||
color: #e2e8f0;
|
||||
font-weight: 500;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
/* ════════════════════════════════════════
|
||||
블록 3: divider-text (기존 블록 100% 재사용)
|
||||
════════════════════════════════════════ */
|
||||
.block-divider-text {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
padding: 8px 0;
|
||||
}
|
||||
.dt-line {
|
||||
flex: 1;
|
||||
height: 1px;
|
||||
background: #cbd5e1;
|
||||
}
|
||||
.dt-text {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: #64748b;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* ════════════════════════════════════════
|
||||
블록 4: table-simple-striped (기존 블록 100% 재사용)
|
||||
주체별 기대효과
|
||||
════════════════════════════════════════ */
|
||||
.block-table-striped table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
font-size: 12px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
.block-table-striped thead th {
|
||||
background: #1e293b;
|
||||
color: #ffffff;
|
||||
font-weight: 700;
|
||||
padding: 8px 12px;
|
||||
text-align: left;
|
||||
font-size: 12px;
|
||||
}
|
||||
.block-table-striped tbody td {
|
||||
padding: 7px 12px;
|
||||
border-bottom: 1px solid #e2e8f0;
|
||||
white-space: pre-line;
|
||||
color: #334155;
|
||||
font-size: 11px;
|
||||
}
|
||||
.block-table-striped tbody tr:nth-child(even) {
|
||||
background: #f8fafc;
|
||||
}
|
||||
.block-table-striped tbody td:first-child {
|
||||
font-weight: 600;
|
||||
color: #1e293b;
|
||||
}
|
||||
|
||||
/* ════════════════════════════════════════
|
||||
블록 5: banner-gradient (기존 블록 100% 재사용)
|
||||
결론
|
||||
════════════════════════════════════════ */
|
||||
.block-banner-grad {
|
||||
background: linear-gradient(135deg, #006aff 0%, #00aaff 100%);
|
||||
border-radius: 8px;
|
||||
padding: 14px 30px;
|
||||
text-align: center;
|
||||
color: #ffffff;
|
||||
}
|
||||
.bg-text {
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
/* ════════════════════════════════════════
|
||||
섹션 타이틀 (기존 디자인 토큰 활용)
|
||||
════════════════════════════════════════ */
|
||||
.section-label {
|
||||
font-size: 13px;
|
||||
font-weight: 900;
|
||||
color: #2563eb;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="slide">
|
||||
<div class="slide-title">DX 시행 목표 및 기대 효과</div>
|
||||
|
||||
<div class="area-body">
|
||||
<!-- 블록 1: card-icon-desc (기존 블록 그대로) → 목표 3카드 -->
|
||||
<div class="section-label">DX를 통한 궁극적 목표</div>
|
||||
<div class="block-card-icon" style="--ci-count: 3">
|
||||
<div class="cid-card">
|
||||
<div class="cid-icon">🛡️</div>
|
||||
<div class="cid-title">안전과 품질</div>
|
||||
<div class="cid-desc">설계-시공-운영 전 과정에서 디지털로 검증하여 안전성 확보
|
||||
하자 최소화로 고품질 성과물 제공</div>
|
||||
</div>
|
||||
<div class="cid-card">
|
||||
<div class="cid-icon">⚡</div>
|
||||
<div class="cid-title">생산성 향상</div>
|
||||
<div class="cid-desc">Analogue → Digital 프로세스 전환
|
||||
비용 절감, 기간 단축, 인력투입 최소화로 부가가치 제고</div>
|
||||
</div>
|
||||
<div class="cid-card">
|
||||
<div class="cid-icon">🤝</div>
|
||||
<div class="cid-title">소통과 신뢰</div>
|
||||
<div class="cid-desc">협업 강화로 의사소통 효율 증진
|
||||
3D 모델·데이터 기반 검증으로 오류 최소화 및 Claim 예방</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 블록 2: dark-bullet-list 변형 → 프로세스 변화 4가지 (Before→After) -->
|
||||
<div class="block-dark-bullets">
|
||||
<div class="db-title">업무 수행 과정(Process)의 변화</div>
|
||||
<div class="db-changes">
|
||||
<div class="db-change">
|
||||
<div class="db-change-label">생산 방식</div>
|
||||
<div class="db-change-before">수작업 의존의 반복 업무</div>
|
||||
<div class="db-change-after">→ SW를 활용한 체계화된 방식으로 전환</div>
|
||||
</div>
|
||||
<div class="db-change">
|
||||
<div class="db-change-label">인지·검토</div>
|
||||
<div class="db-change-before">2D 도면 해석 중심</div>
|
||||
<div class="db-change-after">→ 3D 모델 기반의 직관적 인지·검토 체계</div>
|
||||
</div>
|
||||
<div class="db-change">
|
||||
<div class="db-change-label">협업 구조</div>
|
||||
<div class="db-change-before">개별 문서 중심 협업</div>
|
||||
<div class="db-change-after">→ 데이터 통합 기반 정보 공유·관리 환경</div>
|
||||
</div>
|
||||
<div class="db-change">
|
||||
<div class="db-change-label">검증·대응</div>
|
||||
<div class="db-change-before">사후 대응 중심 문제 처리</div>
|
||||
<div class="db-change-after">→ 사전 검증 중심의 예방적 업무 방식</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="area-sidebar">
|
||||
<!-- 블록 3: divider-text (기존 블록 그대로) -->
|
||||
<div class="block-divider-text">
|
||||
<div class="dt-line"></div>
|
||||
<div class="dt-text">주체별 기대효과</div>
|
||||
<div class="dt-line"></div>
|
||||
</div>
|
||||
|
||||
<!-- 블록 4: table-simple-striped (기존 블록 그대로) -->
|
||||
<div class="block-table-striped">
|
||||
<table>
|
||||
<thead>
|
||||
<tr><th>주체</th><th>기대효과</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td>발주처</td><td>품질 향상, 비용·기간 절감, 투명한 관리</td></tr>
|
||||
<tr><td>설계사</td><td>오류 감소, 설계 품질 제고, 재작업 최소화</td></tr>
|
||||
<tr><td>시공사</td><td>공정 최적화, 안전 강화, 현장 생산성 향상</td></tr>
|
||||
<tr><td>감리·CM</td><td>실시간 모니터링, 데이터 기반 의사결정</td></tr>
|
||||
<tr><td>유지관리</td><td>디지털 트윈 기반 예방 정비, 자산 관리 효율화</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 블록 5: banner-gradient (기존 블록 그대로) → 결론 -->
|
||||
<div class="area-footer">
|
||||
<div class="block-banner-grad">
|
||||
<div class="bg-text">고품질의 성과품, 비용 절감, 시간 단축, 의사소통에 도움이 안 되면 DX가 아니다</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>"""
|
||||
|
||||
|
||||
async def main():
|
||||
from src.slide_measurer import measure_rendered_heights, capture_slide_screenshot
|
||||
|
||||
out_dir = ROOT / "data" / "runs" / "hybrid_simulation"
|
||||
out_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
m = await asyncio.to_thread(measure_rendered_heights, HYBRID_HTML)
|
||||
s = await asyncio.to_thread(capture_slide_screenshot, HYBRID_HTML)
|
||||
|
||||
(out_dir / "hybrid.html").write_text(HYBRID_HTML, encoding="utf-8")
|
||||
if s:
|
||||
(out_dir / "hybrid_screenshot.png").write_bytes(base64.b64decode(s))
|
||||
|
||||
slide = m.get("slide", {})
|
||||
print(f"slide: {slide.get('scrollHeight', 0)}px / 720px {'✅' if not slide.get('overflowed') else '❌'}")
|
||||
|
||||
print(f"""
|
||||
블록 사용 현황:
|
||||
card-icon-desc → 목표 3카드 (기존 블록 100%)
|
||||
dark-bullet-list → 프로세스 변화 (기존 색상/구조 + Before→After 변형)
|
||||
divider-text → 섹션 구분 (기존 블록 100%)
|
||||
table-simple-striped → 주체별 기대효과 (기존 블록 100%)
|
||||
banner-gradient → 결론 (기존 블록 100%)
|
||||
|
||||
블록 활용률: 4/5 기존 블록 그대로 + 1/5 변형
|
||||
결과: {out_dir}/hybrid_screenshot.png
|
||||
""")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import logging
|
||||
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s", datefmt="%H:%M:%S")
|
||||
logging.getLogger("selenium").setLevel(logging.WARNING)
|
||||
logging.getLogger("urllib3").setLevel(logging.WARNING)
|
||||
asyncio.run(main())
|
||||
Reference in New Issue
Block a user