중국어 전문 PDF 보고서 생성
🚨 사용자 두 번의 교정으로 얻은 교훈 (2026-08-20, 최우선 순위, 재발 금지)
- 컴팩트 레이아웃**: "약간의 내용으로 한 페이지를 채우는 것"을 엄격히 금지합니다. 각 챕터에 PageBreak를 추가하여 페이지 수를 늘리는 것을 금지합니다. 표지 뒤에만 PageBreak를 하나 추가하고 본문은 자연스럽게 흐르도록 합니다. 이전 6페이지 분량의 내용을 4페이지로 압축해야 합니다.
- 큰 글꼴 (모바일에서 읽을 수 있어야 함, 고객이 모바일로 봄): 본문 ≥16pt, 표 ≥15pt, H2 ≥17pt, H1 ≥21pt, 제목 ≥30pt. 14pt 본문 / 12pt 표는 너무 작아 고객이 모바일에서 볼 수 없으며, 사용자가 즉시 지적합니다.
- 이 두 가지는 memory의 레이아웃 표준에도 명시되어 있지만, 실행 시 여전히 14pt/12pt를 사용하고 각 챕터를 분리하는 경향이 있습니다. 스크립트 생성 전에 반드시 글꼴 크기 상수와 PageBreak 수를 자체 점검하십시오.
⭐ 전체 레이아웃 표준 (2026-08-18 사용자 확정, PDF/Word 공통)
이 레이아웃 논리는 표준입니다. 이후 모든 PDF 및 Word 문서는 이를 참조하여 실행합니다.
- A4 세로(210×297mm) — 가로/다른 크기 사용 금지
- 큰 글꼴, 모바일에서 읽기 가능: 본문 ≥14pt, 표 ≥12.5pt, H1 ≥20pt, 제목 ≥32pt
- 표 자동 줄 바꿈 및 넘침 방지: 셀은 Paragraph + wordWrap="CJK" 사용
- 페이지 내용 균형: 강제 페이지 나누기 사용 금지, KeepTogether로 지능적으로 블록화, 생성 후 각 페이지의 문자 수 확인 (표지/마지막 페이지 제외, 각 페이지는 균형을 이루어야 함)
- 컴팩트 레이아웃: 여백 18-20mm, 표 패딩 3-4, 줄 간격 컴팩트, 직접 인쇄 가능
Word 문서도 동일한 로직 적용: A4 세로, 본문 ≥12-14pt, 표 열 너비 자동 조정 및 넘침 방지, 페이지 균형.
트리거 조건
- 사용자/고객이 "결론을 PDF로 만들어 주세요", "PDF로 올려 주세요", "타당성 조사 보고서 주세요", "결론을 만들어서 보내 주세요"라고 요청할 때
- 전문적인 레이아웃의 중국어 분석 보고서(표지 + 표 + 바닥글 + 핵심 결론 상자)를 납품해야 할 때
- 참고 예시: 궈쉰 로봇 실사 보고서 (5페이지, 02-프로젝트 성과/궈쉰 로봇 프로젝트 타당성 실사 및 분석 보고서.pdf)
환경 및 설치
- hermes venv 인터프리터 사용:
python - 최초 설치:
$V -m pip install reportlab(로컬에 5.0.0 이미 설치됨) - 글꼴: Windows 시스템 기본 Microsoft YaHei, 글꼴 파일 다운로드 불필요
C:/Windows/Fonts/msyh.ttc(일반, subfontIndex=0)C:/Windows/Fonts/msyhbd.ttc(굵게)C:/Windows/Fonts/msyhl.ttc(가는체)
표준 작업 흐름
- ⚠️ 납품 철칙 (2026-09-02 사용자 명시, 최우선 순위): PDF 생성 후 반드시
MEDIA:를 사용하여 Feishu 채팅방으로 전송해야 합니다. 절대 지식 베이스에만 저장하거나, 경로만 제공하거나, 요점만 전달해서는 안 됩니다. 사용자 원문: "PDF 문서는 Feishu 채팅방으로 보내 주세요. 그렇지 않으면 어떻게 제가 볼 수 있겠어요? 이것은 철칙처럼 만들어야 합니다."- 사용자가 모바일에서 보려면 Feishu 메시지의 파일을 클릭해야 볼 수 있습니다.
02-프로젝트 성과/에 저장하는 것은 백업일 뿐, 납품이 아닙니다. - 납품 형식:
<출력 디렉토리>/<파일명>.pdf(절대 경로). - PDF 발송 후 핵심 결론 요점 첨부 (30초 버전). 먼저 Feishu로 보내고, 나중에 지식 베이스에 저장하여 복기합니다.
- 사용자가 모바일에서 보려면 Feishu 메시지의 파일을 클릭해야 볼 수 있습니다.
- 내용 가져오기: session_search로 과거 분석 내용 검색 — 사용자는 종종 첨부 파일에 대해 "결론을 PDF로 만들어 주세요"라고 응답합니다. 먼저 이전에 제공한 판단/실사 내용을 찾아서 다시 작성하지 않도록 합니다.
- 스크립트 작성:
templates/reportlab_chinese_template.py를 복사하고 내용 영역(표지 텍스트, 챕터, 표 데이터)만 교체합니다. - 생성: python 실행 → Obsidian
Hermes작업성과/02-프로젝트성과/에 출력 (파일명: <주제>프로젝트타당성실사및분석보고서.pdf) - 검증: pymupdf로 열어 get_text로 읽고, 페이지 수 / 중국어 렌더링 / 마지막 페이지 결론 존재 여부 확인
- 납품:
MEDIA:D:\...pdf경로 + 핵심 결론 요점 (30초 버전) 응답, 불필요한 설명 금지
⭐ 색상 철칙 (2026-09-02 사용자 확정, 희신의 금/토 — 최우선 순위)
사용자는 희신(喜神)이 금(金)과 토(土)이고, 기신(忌神)은 수(水, 파랑/검정)와 화(火, 빨강/보라)입니다. 모든 PDF는 금토 계열 색상을 사용해야 하며, 파란색 사용을 금지합니다. 색상 변수는 아래 palette를 참조하십시오.
- 챕터 대제목 H1: 금속 금색 배경 + 흰색 글자 (
backColor=#C9A227,textColor=white,borderPadding=(6,8,6,8)) — 금색 배경에 흰색 글자, 파란색 글자가 아님. - 표 헤더: 금속 금색 배경 + 흰색 글자 (
header_bg=#C9A227,FONTNAME=MSYHBD) — 금색 배경에 흰색 글자. - 본문: 순수 검정
#1f1f1f. - 부제 / 구분선: 진한 토금색
#B8860B(빨간색 제거). - 코드 블록: 토금색
#8a6d1f(파란색 제거). - 얼룩말 무늬: 연한 베이지 금색
#FBF3DE(따뜻한 톤, 회색/흰색 아님). - 그리드 라인: 연한 토금색
#D9C9A3.
금색 계열 palette (reportlab 용)
C_DARK=colors.HexColor("#1f1f1f") # 본문, 거의 검정
C_RED=colors.HexColor("#B8860B") # 강조/부제-진한 토금색
C_BLUE=colors.HexColor("#C9A227") # 표 헤더/제목 배경-금속 금색
C_LGRAY=colors.HexColor("#FBF3DE") # 얼룩말 무늬-연한 베이지 금색
C_MGRAY=colors.HexColor("#D9C9A3") # 그리드 라인-연한 토금색
C_WHITE=colors.white
인라인 강조
S_CODE=st(..., textColor=colors.HexColor("#8a6d1f")); 인라인<span color='#B8860B'>(#c0392b빨간색 사용 금지).
레이아웃 요점 (템플릿에 이미 캡슐화됨)
- 표지 페이지: 큰 제목 + 금색 부제 + 날짜/출처 + 핵심 결론 상자 (진한 토금색 배경 흰색 글자 표)
- 본문: H1 챕터 (금속 금색 배경 흰색 글자 MSYHBD 21pt) + H2 소절 (17pt) + 본문 15pt (2026-08-18 사용자 지시: 모바일에서 읽을 수 있어야 하며, 글꼴 크기가 커야 함)
- 표:
make_table()표 헤더 금속 금색 배경 흰색 글자 + 얼룩말 무늬 (ROWBACKGROUNDS) + grid + repeatRows=1, 표 글꼴 크기 13pt - 바닥글: onPage 콜백으로 보고서 이름 + 페이지 번호 그림
- 강조: Paragraph는
<b>/<span color='#B8860B'>인라인 태그 지원 - 긴 보고서 챕터 구분: PageBreak로 표지와 본문 구분
⚠️ 글꼴 크기 철칙 (2026-08-18 사용자 강조): PDF는 모바일에서 보기 위한 것이므로, 본문 ≥15pt, 표 ≥13pt, H1 ≥21pt, 제목 ≥34pt. 원본 템플릿의 10.5pt/9.3pt는 너무 작아 모바일에서 볼 수 없습니다. 모든 새 보고서는 큰 글꼴을 사용해야 합니다. 글꼴이 커져 페이지 수가 늘어나는 것은 정상입니다 (예: 5페이지 → 8페이지).
⭐ 지능형 레이아웃 철칙 (2026-08-18 사용자 강조, 인쇄 친화적) 페이지 내용은 반드시 균형을 이루어야 함 — 어떤 페이지는 200자, 어떤 페이지는 800자가 되어서는 안 됩니다. 방법:
- PageBreak 적게 사용: 표지 뒤에만 강제 페이지 나누기, 본문은 자연스럽게 흐르도록 함
- KeepTogether로 "제목+내용" 묶기:
keep(H2 제목, 표/단락)으로 표가 두 페이지로 나뉘거나 제목이 페이지 하단에 홀로 남는 것을 방지 - 표지는 별도 페이지: 표지 요소 + PageBreak 하나
- 각 챕터는 소절로 자연스럽게 구분: H2 제목 + 표/요점, 각 챕터마다 강제 페이지 전환 금지
- 균형도 검증: 생성 후 pymupdf로 각 페이지의 문자 수 확인 — 정상적인 보고서는 표지/마지막 페이지를 제외한 각 페이지의 문자 수가 비슷해야 함 (예: 600-900자), 차이가 크면 조정 필요
- 컴팩트 레이아웃: 여백 20mm/16mm (너무 크지 않게), 표 패딩 4-5, 줄 간격 leading=22 (14pt 본문), 빈 공간 낭비 최소화
함정 (PITFALLS)
- ⛔ 양쪽 정렬(TA_JUSTIFY) 금지 — 글자 간격이 넓어짐 (2026-09-03 사용자가 가장 신경 쓰는 모바일 가독성 문제): reportlab의
TA_JUSTIFY는 중국어 단락에서 각 줄을 강제로 오른쪽 경계까지 늘려서, 한 줄에 글자가 적을 때 글자 간격이 매우 넓어져 보기 흉해집니다. 모든 본문/목록/단락은TA_LEFT왼쪽 정렬을 사용해야 합니다.- 오류:
b=dict(..., alignment=TA_JUSTIFY, ...) - 올바름:
b=dict(..., alignment=TA_LEFT, ...) - 점검: 본문/목록 스타일이
st()를 상속하고alignment=TA_JUSTIFY이면 반드시 왼쪽 정렬로 변경해야 합니다.
- 오류:
- ⛔ 표지 내용이 넘쳐 빈 페이지 생성 (2026-09-03): 표지 요소(메인 제목+부제+설명+핵심 한마디)는 반드시 모두 1페이지 내에 포함되어야 하며, 절대 표지 내용이 2페이지로 밀려나 "한두 줄의 텍스트+큰 빈 공간"을 형성해서는 안 됩니다. 표지 내용이 너무 많으면 긴 서문을 삭제하고 목록 간격을 압축하여 1페이지 내에 완료되도록 합니다. 각 챕터 사이에는 표지 뒤의 PageBreak 하나만 유지하고 본문은 자연스럽게 흐르도록 합니다.
- ⛔ 글꼴 크기/여백은 함께 조정해야 함: 글꼴 크기를 키운 후에는 여백을 함께 좁혀야 (본 세션 22mm→17mm) 각 페이지에 더 많은 내용을 담을 수 있고 고립 페이지가 발생하지 않습니다. 17pt 본문 + 17mm 여백이 실제 측정된 균형점입니다. 표 글꼴 크기는 14.5pt.
- ⛔ KeepTogether로 "사용자 정의 정렬된 작은 표"를 감싸면 페이지 높이 오판 → 고립 페이지 (2026-09-06 실제 측정): KeepTogether로 "제목+본문+사용자 정의 두 열 정렬 표(field_table)"+가격을 감싸면 reportlab이 해당 블록의 높이를 부정확하게 추정하여 전체 블록을 다음 페이지로 밀어내는 경우가 많아, 이전 페이지에는 "알림 문장/표 마지막 행"만 남아 수십 자의 고립 페이지가 됩니다 (본 세션 2페이지는 76자에 불과). 수정: ① 첫 화면 "서비스 목록+서문"은 KeepTogether로 전체 head_block을 감싸고 표 글꼴 크기/줄 간격을 압축하여 1페이지 내에 완료되도록 합니다. ② 자체 블록 렌더링 후 pymupdf로 페이지별 문자 수를 확인하고, <120자인 페이지는 고립 페이지로 간주하여 즉시 이전 페이지 표를 압축하거나 불필요한 알림 문장을 삭제합니다.
- 구분 (2026-09-10 실제 측정): "표 자체"만 감싸는 것은 정확하며 해야 할 일입니다. "제목+본문+표+가격" 큰 블록을 감쌀 때만 오판하기 쉽습니다. 표 팩토리 함수가 통일적으로
return KeepTogether(t)(표 전체가 페이지를 넘지 않음)를 반환하고, 표지 뒤에 PageBreak 하나만 유지하는 것과 함께 사용하면, 실제로 7페이지 (5페이지는 77자에 불과)를 6페이지로 수정하고 각 페이지를 301/451/548/407/551/240자로 만들 수 있습니다. 표가 페이지 분할로 잘려 나간 1-2행이 한 페이지를 독점하는 것이 고립 페이지의 가장 큰 원인입니다. "특정 페이지에 표 헤더/마지막 행만 있다"는 것을 발견하면 먼저 이 문제를 확인하십시오.
- 구분 (2026-09-10 실제 측정): "표 자체"만 감싸는 것은 정확하며 해야 할 일입니다. "제목+본문+표+가격" 큰 블록을 감쌀 때만 오판하기 쉽습니다. 표 팩토리 함수가 통일적으로
- ⛔ 두 열 "라벨+내용" 정렬 표의 라벨 열이 너무 좁으면 안 됨 — 중국어 라벨이 줄 바꿈되어 고립된 글자가 됨 (2026-09-06): "할 수 있는 것/얼마나 깊이 하는지/무엇을 얻을 수 있는지"를 표시하는 두 열 정렬 표에서 라벨 열이 너무 좁으면 (예: 32mm), "무엇을 얻을 수 있는지"가 "무엇을 얻을 수 있"+"는지"로 줄 바꿈되어 고립된 글자가 매우 보기 흉합니다. 수정: 라벨 열 너비는 가장 긴 라벨이 한 줄에 들어갈 수 있는 너비 (약 40mm)보다 커야 하거나, 라벨을 짧게 변경합니다 ("무엇을 얻을 수 있는지" → "무엇을 얻는가").
- ⛔ 긴 문장 끝의 마침표(。)가 단독으로 줄 바꿈되어 고립된 구두점이 됨 (2026-09-06): "얼마나 깊이 하는지/무엇을 가져오는지"와 같은 긴 필드에서, 문장 끝의 마침표가 줄 바꿈될 때 다음 줄의 시작 부분으로 밀려납니다. 수정: 필드 값이 길고 줄 바꿈 위험이 있을 때 끝 마침표를 제거하거나 (또는 짧은 문장을 회피), 차라리 마침표가 없어도 고립된 점을 남기지 않습니다.
- ⛔ "맞춤형 스킬"은 정확한 표현을 사용해야 함 (2026-09-06 사용자 수정): "맞춤/주문 제작 skills"을 "예약 작업"으로 잘못 표기하지 마십시오. 고객용 버전은 통일적으로 "전문 스킬 맞춤 제작"을 사용하고 구어체로 "스킬 = AI가 따라 할 수 있는 구체적인 능력"이라고 설명합니다 (enterprise-ai-service-blueprint 참조).
.ttc글꼴은 반드시subfontIndex=0을 사용해야 하며, 그렇지 않으면 오류가 발생하거나 깨집니다.- 굵게 표시하려면 MSYHBD를 등록하고 fontName을 설정해야 합니다.
<b>태그는 굵은 글꼴이 등록되지 않으면 조용히 굵게 표시되지 않습니다. <>이스케이프는 두 가지 경우를 구분해야 함 (2026-09-10 실제 측정 함정): 본문의 있는 그대로의 꺾쇠 괄호 (예: "정밀도 <10mm")만</>로 이스케이프합니다. 반면<b>,<span color=...>는 인라인 태그이므로 Paragraph에 원래대로 전달되어야 효과가 있습니다.- ⛔ 치명적인 작성법: 셀 텍스트를 무조건
.replace('<','<')로 전체 이스케이프 → 표의 굵게 표시가 그대로<b>글자로 인쇄됨 (본 세션 2페이지 전체 열이<b>지원 항목…으로 인쇄되어 납품 직전에 발견됨). - ✅ 올바름: 표 셀은 있는 그대로의
&만 이스케이프 (v.replace('&','&')), 인라인 태그는 유지; 내용에 있는 있는 그대로의 꺾쇠 괄호는 호출자가 직접<를 작성합니다. - 자체 점검: 납품 전에 전체 텍스트를 검사하여,
'<b>' in text또는'</b>' in text가 참이면 태그가 텍스트로 렌더링된 것이므로 make_table의 이스케이프를 반드시 다시 확인해야 합니다.
- ⛔ 치명적인 작성법: 셀 텍스트를 무조건
- 표 열 너비의 합 ≤ A4 사용 가능 너비 (210mm - 좌우 여백), 그렇지 않으면 넘쳐서 줄 바꿈이 보기 흉해짐
- 표 중국어 넘침 (2026-08-18 중요 수정): reportlab의 Table에 긴 중국어를 직접 넣으면 자동으로 줄 바꿈되지 않고 오른쪽으로 넘칩니다! 반드시 Paragraph로 셀을 감싸야 하며 +
wordWrap="CJK"를 사용해야 합니다. make_table에 이미_cell_style()처리가 내장되어 있습니다. 모든 셀은 자동으로 줄 바꿈됩니다. 검증: pymupdf로get_text('words')의 x2가 콘텐츠 영역 오른쪽 경계를 넘는지 확인합니다.- 임계값은 실제 여백에 따라 계산해야 하며 540pt로 고정하면 안 됨 (2026-09-10 실제 측정): 오른쪽 경계 =
A4[0] - rightMargin(A4 너비 595.3pt; 16mm 여백 → 549.9pt, 17mm → 547pt). 540으로 고정하면 정상적인 줄 바꿈을 넘침으로 잘못 보고하여 쓸데없는 수고를 하게 됩니다. - 바닥글은 반드시 제외: onPage로 그린 "N 페이지"는 항상 콘텐츠 영역을 벗어나므로, 판정 시 텍스트로 필터링해야 합니다 (예:
w[4] != '页'). 그렇지 않으면 매번 거짓 경보가 발생합니다. - 판정 예시:
[w for w in page.get_text('words') if w[2] > page.rect.width - rightMargin + 1 and w[4] != '页']
- 임계값은 실제 여백에 따라 계산해야 하며 540pt로 고정하면 안 됨 (2026-09-10 실제 측정): 오른쪽 경계 =
- A4 세로 철칙 (사용자 강조): 모든 PDF는 A4 세로 (210×297mm)여야 합니다. pagesize=A4가 기본적으로 세로이므로 landscape로 변경하지 마십시오.
- 납품 전에 반드시 pymupdf로 한 번 검증 (페이지 수/중국어/깨짐/넘침 없음) — 검증 통과 후에야 발송
- ⛔ 생성 스크립트 작성 시 Python 문자열은 항상 작은따옴표로 구분 (2026-09-10 실제 측정): 도구 체인이 중국어 따옴표 “ ”를 반각
"로 정규화할 수 있습니다. 문자열 외부에 큰따옴표를 사용하면 본문의 따옴표가 리터럴을 조기에 종료하여SyntaxError: invalid character '+' (U+FF0B)와 같은 오류가 발생합니다 (오류 지점이 전각 문자 불법처럼 보이지만 실제 원인은 따옴표 잘림으로, 디버깅 방향을 잘못 잡게 할 수 있음). 본문의 중국어 따옴표는「」로 바꾸거나 전체 문자열을'...'로 감쌉니다. - ⛔ 절대 "쓰면서 동시에 읽기"로 같은 파일을 열지 마십시오:
open(f,'w').write(open(f,encoding='utf-8').read() + add)는 먼저 파일을 0바이트로 자른 후 읽기 때문에 원본 내용이 모두 사라지고 추가된 부분만 남게 됩니다 (본 세션 지식 베이스 노트가 13KB에서 3.8KB로 줄어들어 거의 불완전한 문서를 제출할 뻔했습니다). 내용을 추가할 때는 먼저txt = open(f).read()로 변수에 저장한 후open(f,'w').write(txt + add)를 실행하거나, patch 도구를 직접 사용하여 수정합니다. - 파일 >100KB는 일반적으로 정상입니다 (포함된 글꼴 하위 집합).
검증 명령어
$V -c "import pymupdf; d=pymupdf.open(r'D:\...\보고서.pdf'); print(len(d)); print(d[0].get_text()[:120]); print('마지막 페이지에 결론 포함:', '결론' in d[-1].get_text())"
연관
- 내용 프레임워크:
feasibility-study-writing,dual-lens-business-analysis(이중 렌즈 분석으로 보고서 작성 전에 먼저 로드할 것) - 보고서 검토 철칙: 엄격한 보고서 작성 전에
report-reflection-review실행 - PPT 시나리오:
ultimate-ppt-master - 템플릿:
templates/reportlab_chinese_template.py(구);templates/reportlab_gold_template.py(권장): 금색 계열 + 왼쪽 정렬 + 17pt 큰 글자 + 17mm 컴팩트 여백 + 고립 페이지 없음.make_table()의 인라인 태그 처리 수정 완료 (표 셀 내<b>/<span>이 이제 실제로 적용되며, 더 이상 텍스트 그대로 이스케이프되지 않음).