Claude 스킬로 지침서 자동 생성하기 — docx-js + PDF 이미지 추출까지

소개

시도하고자 했던 것

1주차 과제에서는 Airtable MCP를 구성하여 고객 데이터를 활용한 관계형 테이블을 만들었습니다. 2주차는 그 연장선이 아닌, Claude 스킬 활용 자체를 다루었습니다. 마침 실무에서 진행 중이던 서비스 매뉴얼 한국어 표준화 번역 작업이 있었고, 이 반복적인 문서 생성 작업을 Claude 스킬로 구조화하는 것을 2주차 과제로 연결했습니다.

단순히 번역을 계속하는 것이 아니라, 어떻게 하면 Claude가 매번 동일한 품질의 지침서 docx를 자동으로 뽑아낼 수 있을까를 스킬 설계 관점에서 접근했습니다.

그 이유

지침서는 구조가 매우 규칙적입니다. 탈거 → 분해 → 점검 → 조립 → 장착의 흐름, 경고/주의/참고 박스, 좌텍스트+우이미지 2열 레이아웃이 수백 페이지 반복됩니다. 이 구조를 스킬로 정의해두면 챕터 단위로 빠르게 완성본 docx를 뽑을 수 있겠다고 판단했습니다. 한 챕터(22페이지)를 수작업으로 하면 하루 이상 걸리지만, 자동화하면 한 세션 내에 완성할 수 있습니다.


진행 방법

사용 도구: Claude (claude.ai), Node.js + docx-js, Python (Pillow, pdfimages), bash

전체 흐름

PDF 원문 → 이미지 추출(pdfimages) → 번역·표준화 → JS 스크립트 생성
→ docx-js로 .docx 빌드 → validate → 언팩(XML 직접 수정) → 최종 출력

1단계: 스킬 정의

automotive-service-manual 스킬을 먼저 읽혀서 문서 구조·XML 패턴을 파악하게 했습니다.

사용한 프롬프트:

템플릿화 된 내용을 토대로 17번 파일 작업을 진행해주세요.

인수인계 문서(섹션 구조, 확정 용어표, 서식 규칙, 이미지 매핑 JSON)를 함께 첨부하여 컨텍스트를 한 번에 전달했습니다.

2단계: PDF 이미지 자동 추출 및 페이지 매핑

python

# pdfimages로 전체 이미지 추출 후 페이지-이미지 매핑
pdfimages -list 17_Brake.pdf
# 로고(26,923 bytes 이하) 자동 필터링
# 실제 절차 이미지만 페이지별 딕셔너리로 정리
page_images = {
    3:  ['img-003.jpg','img-004.jpg','img-005.jpg','img-006.jpg'],
    4:  ['img-008.jpg','img-009.jpg'],
    # ...
    22: ['img-078.jpg','img-079.jpg'],
}

3단계: 로고 투명 배경 처리

업로드된 로고가 검정 배경(RGB 0,0,0)이었고 이전 코드(R,G,B > 200 흰색 제거)가 작동하지 않았습니다. BFS flood fill로 정확히 해결했습니다.

python

from PIL import Image
import numpy as np
from collections import deque

img = Image.open('EVKMC_로고.png').convert('RGBA')
data = np.array(img)
h, w = data.shape[:2]

is_dark = (data[:,:,0]<40) & (data[:,:,1]<40) & (data[:,:,2]<40)

# 외곽에서 연결된 검정 픽셀만 배경으로 판별
visited = np.zeros((h,w), dtype=bool)
bg_mask = np.zeros((h,w), dtype=bool)
q = deque()
for x in range(w):
    if is_dark[0,x]: q.append((0,x)); visited[0,x]=True
    if is_dark[h-1,x]: q.append((h-1,x)); visited[h-1,x]=True
for y in range(h):
    if is_dark[y,0]: q.append((y,0)); visited[y,0]=True
    if is_dark[y,w-1]: q.append((y,w-1)); visited[y,w-1]=True

while q:
    y,x = q.popleft()
    bg_mask[y,x] = True
    for dy,dx in [(-1,0),(1,0),(0,-1),(0,1)]:
        ny,nx = y+dy, x+dx
        if 0<=ny<h and 0<=nx<w and not visited[ny,nx] and is_dark[ny,nx]:
            visited[ny,nx] = True
            q.append((ny,nx))

result = data.copy()
result[bg_mask, 3] = 0
Image.fromarray(result).save('로고_투명.png')

4단계: docx-js 스크립트로 전체 문서 생성

evkmc_template.js를 기반으로 17장 전체 콘텐츠 스크립트(build_17_.js)를 작성했습니다. 핵심 함수 구조:

javascript

// 색상 박스 (경고/주의/참고 공통)
function makeBox(title, titleColor, bg, borderColor, items) {
  return new Table({
    width: { size: 9926, type: WidthType.DXA }, // 실제 콘텐츠 폭
    columnWidths: [9926],
    rows: [
      titleRow,      // 제목 행
      ...itemRows,   // 항목 행들
    ]
  });
}

// 좌텍스트 + 우이미지 2열 레이아웃
function stepWithImg(textChildren, imgFile, imgW=260, imgH=170) {
  return new Table({
    width: { size: 9926, type: WidthType.DXA },
    columnWidths: [5609, 4317],  // 56.5% : 43.5%
    rows: [new TableRow({ children: [
      new TableCell({ width: { size:5609 }, children: textChildren }),
      new TableCell({ width: { size:4317 }, children: [imageRun] })
    ]})]
  });
}

// 바닥글 로고: floating anchor (텍스트 앞, 페이지 기준 절대 위치)
const logo = new ImageRun({
  data: logoBuffer, type: "png",
  floating: {
    horizontalPosition: {
      relative: HorizontalPositionRelativeFrom.PAGE,
      offset: isOdd ? 6170930 : 629920  // 홀수:우측끝 / 짝수:좌측
    },
    verticalPosition: {
      relative: VerticalPositionRelativeFrom.PARAGRAPH,
      offset: -33338  // 텍스트와 수직 중앙 정렬
    },
    wrap: { type: TextWrappingType.NONE },
    behindDocument: false
  }
});

결과와 배운 점

결과

  • 17번 파일, 22페이지 분량을 docx-js로 완전 자동 생성

  • 경고(빨강)/주의(노랑)/참고(파랑) 색상 박스, 좌텍스트+우이미지 2열, PDF 이미지 57장 삽입 완료

  • NanumGothic 폰트, ~한다/~할 것 문체, 표준 용어 전면 적용

시행착오 3가지

  1. 테이블 폭 오류: 스킬 파일 기준값 9026 DXA를 그대로 썼는데, 실제 문서 여백(좌992+우992)으로 계산하면 콘텐츠 폭이 9926 DXA였습니다. 900 DXA(약 1.6cm) 차이로 표가 페이지 끝까지 닿지 않았습니다. 여백 설정과 콘텐츠 폭을 항상 직접 계산해야 한다는 것을 배웠습니다.

  2. 로고 투명 처리 실패: 처음에 R,G,B > 200 조건으로 흰 배경을 제거하려 했으나, 실제 배경이 검정(0,0,0)이었습니다. 이미지를 열어서 픽셀값을 직접 확인하는 습관이 필요합니다.

  3. 바닥글 홀짝 미작동: evenAndOddHeaders 설정이 settings.xmlfalse로 고정되어 있어 짝수 푸터가 적용되지 않았습니다. docx-js 옵션만으로는 부족하고 settings.xml XML 직접 확인이 필요했습니다.

    빨간색 선과 파란색 선이 있는 선 그래프

    중앙에 빨간색 선이 있는 선의 다이어그램

나만의 꿀팁

Claude에게 "결과물을 생성하지 않습니다"라고 먼저 말하고 분석·계획만 받으면, 긴 스크립트 생성 없이 빠르게 문제를 파악하고 방향을 확정할 수 있습니다. 실제로 3가지 문제를 파악하는 데 이 방법을 활용했습니다. (무한 자동 재생성에 몇번이나 세션을 초과했더랍니다.)

앞으로의 계획

  • 현재 미해결 3가지(홀짝 구분, 로고 수직 정렬, 박스 하단 공백) 수정 후 17장 최종 완성

  • 완성된 build_17_.js 구조를 범용 템플릿으로 추상화하여 나머지 챕터에 적용

  • 챕터 번호·제목·콘텐츠만 바꾸면 동일한 서식으로 다른 챕터도 생성되는 구조 목표

도움이 필요한 부분

  • evenAndOddHeaders 활성화 + settings.xml 자동 패치 방법

  • floating 이미지의 수직 정렬을 줄 높이 기준으로 정확히 맞추는 방법


도움 받은 글

  • Anthropic 공식 docx 스킬 (/mnt/skills/public/docx/SKILL.md)

  • automotive-service-manual 스킬 (/mnt/skills/user/automotive-service-manual/SKILL.md)

  • docx-js 공식 문서 (ImageRun floating 옵션)

뉴스레터 무료 구독

👉 이 게시글도 읽어보세요