step5_llm_diagnoser.py가 생성한 daily_cloud_native_behavior_report.md 마크다운 보고서를 엑셀에 통합하기 가장 좋은 위치는 바로 0. 전사종합요약 시트의 하단 영역(33번 행 이후)입니다.
엑셀의 하나의 커다란 병합 셀에 통째로 글을 밀어 넣으면 텍스트가 잘리는 openpyxl 특유의 버그가 있으므로, 줄 바꿈(Line-by-line) 단위로 엑셀 셀을 동적 병합하며 마크다운 헤더(#) 스타일을 입히는 방식이 시각적으로 가장 깔끔합니다.
수정해야 할 곳은 1) build_sheet_summary 함수 내부와 2) main 실행부 딱 두 곳입니다. 아래 수정 코드를 적용하시면 됩니다.
build_sheet_summary 함수 개조함수 맨 아래쪽(차트 이미지 바인딩 로직 바로 밑)에 마크다운 파일을 읽어와 엑셀 스타일로 파싱 후 인젝션하는 코드를 추가합니다.
# ─── Sheet 0: 전사 종합 요약 ───────────────────────────────
def build_sheet_summary(wb, df_pod, df_ns, infra_tag):
print(f"⏳ [0/9] '0. 전사종합요약' 통합 대시보드 구축 중... ({infra_tag})")
ws = wb.active
ws.title = "0. 전사종합요약"
ws.sheet_view.showGridLines = False
ws.row_dimensions[1].height = 42
# ... (기존 KPI 및 중간 코드들 그대로 유지) ...
set_col_widths(ws, {"A":28,"B":14,"C":14,"D":22,"E":14,"F":14,"G":20,"H":20})
chart_row = 16
add_chart_image(ws, "chart6_status_donut.png", f"A{chart_row}", infra_tag, w=420, h=300)
add_chart_image(ws, "chart5_pareto_ns_waste.png", f"E{chart_row}", infra_tag, w=560, h=300)
# ──────────────────────────────────────────────────────────────────
# 🔥 [신설] 33번 행부터 step5 LLM 정성 진단 마크다운 리포트 라인 단위 주입
# ──────────────────────────────────────────────────────────────────
md_path = Path("daily_cloud_native_behavior_report.md")
if md_path.exists():
print(f" 🤖 [LLM 리포트 임베딩] '{md_path.name}' 파일을 읽어 표지에 바인딩합니다.")
start_text_row = 33
# 타이틀 바 렌더링
ws.cell(row=start_text_row, column=1, value="🤖 사내 LLM 인텔리전스 SRE 아키텍처 정성 진단 의견 (Executive Summary)").font = ft(bold=True, size=11, color=C["white"])
ws.merge_cells(start_row=start_text_row, start_column=1, end_row=start_text_row, end_column=8)
ws.cell(row=start_text_row, column=1).fill = fill(C["purple"])
ws.cell(row=start_text_row, column=1).alignment = left()
ws.row_dimensions[start_text_row].height = 26
current_row = start_text_row + 2
with open(md_path, "r", encoding="utf-8") as f:
for line in f:
clean_line = line.strip()
# 빈 줄 처리
if not clean_line:
ws.row_dimensions[current_row].height = 12
current_row += 1
continue
# 셀 생성 및 가로 전체 병합 (A열부터 H열까지 리포트 영역 지정)
cell = ws.cell(row=current_row, column=1, value=clean_line)
ws.merge_cells(start_row=current_row, start_column=1, end_row=current_row, end_column=8)
# 마크다운 문법 헤더 스타일에 따른 엑셀 폰트 변환 매핑
if clean_line.startswith("#"):
# #, ##, ### 등 헤더 기호 제거 후 타이틀 강조 스타일 적용
parsed_text = clean_line.lstrip("# ").strip()
cell.value = parsed_text
cell.font = ft(bold=True, size=10, color=C["hdr_dark"])
cell.fill = fill(C["summary_bg"])
cell.alignment = left()
ws.row_dimensions[current_row].height = 22
else:
# 일반 본문 텍스트 포맷팅 및 자동 텍스트 줄바꿈 가드레일 작동
cell.font = ft(size=9.5, color="333333")
cell.alignment = Alignment(horizontal="left", vertical="top", wrap_text=True)
# 문장 길이에 따라 엑셀 행 높이 유연 자동 조절
if len(clean_line) > 60:
ws.row_dimensions[current_row].height = 36
else:
ws.row_dimensions[current_row].height = 18
current_row += 1
else:
print(f" ⚠️ [LLM 리포트 누락] 'daily_cloud_native_behavior_report.md' 파일이 루트에 없어 요약을 생략합니다.")
main 함수 연동 체크main() 함수 내부에서 build_sheet_summary를 호출하는 트리거 순서는 기존 구조 그대로 두시면 됩니다. df_pod 스캔 처리가 완료된 뒤 표지를 가장 먼저 빌드하므로, 위 수정 사항이 반영된 상태에서 알아서 루트 디렉토리의 마크다운 소스를 추적하게 됩니다.
# main() 내부 하단 시트 컴파일 시퀀스 레이어 부
wb = Workbook()
# 여기서 수정된 함수가 작동하여 차트 밑에 LLM 리포트 캔버스를 이어서 그립니다.
build_sheet_summary(wb, df_pod, df_ns, infra_tag)
build_sheet_pareto(wb, df_ns, infra_tag)
build_sheet_ns_daily(wb, df_daily_ns, infra_tag)
# ... (이하 후속 시트 빌더 및 MinIO 싱크 파트 유지)
이렇게 구성해 두면 master_sre_pipeline.sh를 실행했을 때 step5가 내놓은 정성 통찰 마크다운을 step6가 파싱하여 리포트 1페이지의 상태 도넛 차트 바로 아래쪽 그리드에 리포팅 리포트 형태로 안전하게 임베딩을 마감합니다.