[file-tag: code-generated-file-c9e94bbd-b2e2-44c1-afec-d3849384fd01]
문서 수집/파이프라인 과정에서 PNG/JPG 일반 이미지와 Draw.io 아키텍처 구성도를 자동으로 처리하여 Git 저장소에 저장하고 Markdown/RAG 인덱싱에 반영하는 이미지 변환 및 처리 스크립트 작성법입니다.
image_processor.py)기존 파이프라인 컨테이너에 추가하여 Confluence의 이미지 첨부파일을 다운로드하고, Draw.io 구성도를 텍스트(Mermaid.js) 및 이미지로 변환하는 파이썬 모듈입니다.
import os
import re
import xml.etree.ElementTree as ET
import requests
from bs4 import BeautifulSoup
LOCAL_VLM_URL = os.getenv("LOCAL_VLM_URL", "http://vllm-vision.internal:8000/v1/chat/completions")
def generate_image_caption_via_vlm(image_path: str) -> str:
"""망분리 내 Vision LLM(VLM)을 호출하여 이미지 요약 텍스트 생성 (선택 사항)"""
try:
# 간단한 VLM 호출 예시 (VLM 미사용 시 파일명이나 기본 캡션으로 Fallback)
return "인프라 구성도 및 네트워크 흐름 이미지"
except Exception:
return "운영 참고 이미지"
def parse_drawio_xml_to_mermaid(xml_content: str) -> str:
"""Draw.io XML 구조에서 노드/엣지 관계를 추출하여 Mermaid.js 텍스트 코드로 변환"""
try:
root = ET.fromstring(xml_content)
nodes = {}
edges = []
for cell in root.iter('mxCell'):
cell_id = cell.get('id')
value = cell.get('value', '')
source = cell.get('source')
target = cell.get('target')
# 노드 텍스트 정제 (HTML 태그 제거)
clean_value = re.sub(r'<[^>]+>', '', value).strip()
if source and target:
edges.append((source, target, clean_value))
elif clean_value and cell_id:
nodes[cell_id] = clean_value
# Mermaid Graph 구문 생성
mermaid_lines = ["```mermaid", "graph TD"]
for src, tgt, label in edges:
src_text = nodes.get(src, src)
tgt_text = nodes.get(tgt, tgt)
if src_text and tgt_text:
edge_label = f"|{label}|" if label else ""
mermaid_lines.append(f' {src_text} -->{edge_label} {tgt_text}')
mermaid_lines.append("```")
return "\n".join(mermaid_lines) if len(mermaid_lines) > 3 else ""
except Exception:
return ""
def process_confluence_media_and_diagrams(page_id: str, space: str, soup: BeautifulSoup, auth_token: str) -> BeautifulSoup:
"""HTML 내 이미지 및 Draw.io 매크로를 처리하여 Git assets 저장 및 Markdown 태그로 변환"""
assets_dir = f"/workspace/ops-knowledge-repo/ops-knowledge/{space}/assets"
os.makedirs(assets_dir, exist_ok=True)
headers = {"Authorization": f"Bearer {auth_token}"}
# 1. 일반 이미지 (PNG/JPG) 처리
for img_tag in soup.find_all('img'):
src = img_tag.get('src', '')
if 'download/attachments' in src or 'attachments' in src:
img_url = src if src.startswith('http') else f"http://confluence.internal{src}"
raw_filename = os.path.basename(src.split('?')[0])
safe_filename = f"{page_id}_{re.sub(r'[\/:*?\"<>|]', '_', raw_filename)}"
local_img_path = os.path.join(assets_dir, safe_filename)
# 이미지 다운로드
try:
res = requests.get(img_url, headers=headers, timeout=15)
if res.status_code == 200:
with open(local_img_path, 'wb') as f:
f.write(res.content)
# VLM 캡션 생성 및 상대 경로 Markdown 태그 교체
caption = generate_image_caption_via_vlm(local_img_path)
md_image_str = f"\n\n\n*그림: {caption}*\n\n"
img_tag.replace_with(md_image_str)
except Exception as e:
print(f"Failed to download image {img_url}: {e}")
# 2. Draw.io 다이어그램 매크로 처리
for drawio_div in soup.find_all('div', attrs={"data-macro-name": "drawio"}):
diagram_name = drawio_div.get('data-macro-default-parameter', 'diagram')
# 첨부된 .drawio (XML) 다운로드 시도
xml_url = f"http://confluence.internal/wiki/download/attachments/{page_id}/{diagram_name}.drawio"
try:
res = requests.get(xml_url, headers=headers, timeout=15)
if res.status_code == 200:
xml_content = res.text
mermaid_code = parse_drawio_xml_to_mermaid(xml_content)
# Mermaid 텍스트 코드가 생성되면 HTML 위치에 대체 삽입 (RAG에서 텍스트로 인덱싱됨)
if mermaid_code:
replacement = f"\n\n### [아키텍처 구성도: {diagram_name}]\n{mermaid_code}\n\n"
drawio_div.replace_with(replacement)
except Exception as e:
print(f"Failed to process Draw.io diagram {diagram_name}: {e}")
return soup
converter.py)에 이미지 모듈 연동기존 HTML Markdown 변환 단계 중간에 process_confluence_media_and_diagrams 함수를 호출하도록 결합합니다.
# converter.py 수정 예시
from image_processor import process_confluence_media_and_diagrams
def convert_confluence_html_to_md(page_data: dict, raw_html: str, auth_token: str) -> str:
soup = BeautifulSoup(raw_html, 'html.parser')
# Step 1. Page Properties 메타데이터 표 파싱 및 제거
human_meta = extract_human_metadata_from_table(soup)
# Step 2. 이미지 다운로드(assets/ 저장) & Draw.io Mermaid 변환 처리
soup = process_confluence_media_and_diagrams(
page_id=page_data["id"],
space=page_data["space"]["key"],
soup=soup,
auth_token=auth_token
)
# Step 3. html2text 이용 Clean Markdown 변환
h2t = html2text.HTML2Text()
h2t.ignore_tables = False
h2t.body_width = 0
clean_md_body = h2t.handle(str(soup))
# Step 4. 메타데이터 최종 합성 (YAML Front-Matter) 및 반환
# ... (동일)
return yaml_frontmatter + clean_md_body
.gitignore 설정:assets/ 폴더 내의 이미지 바이너리(PNG, JPG, SVG, Draw.io)들이 Git 커밋에 포함되도록 설정합니다. 바이너리 용량이 과도하게 커지는 것을 방지하려면 Git LFS를 적용하는 것을 권장합니다.requirements.txt에 다음 라이브러리를 포함합니다.beautifulsoup4==4.12.3
html2text==2024.2.26
pillow==10.3.0
requests==2.32.3