[코드잇 스프린트] 프로젝트#2 log
🟣 project 시작
- 기간: 25.09.11 ~
2025-09-11 Thu
미팅#1
⚪ 역할분배
- PM: 추후
- Data: 전수현
- Generator: ??
- Retriever: ??
⚪ EDA
PyPDF2,pyhwp
⚪ run_basic_cleaning.py
2025-09-15 Mon
(1) PDF → 텍스트 추출
- PyMuPDF, pdfminer 같은 툴 사용.
- OCR 필요할 경우 Tesseract 적용.
- 출력: 페이지 단위 텍스트 JSON.
(2) 전처리
- 불필요한 요소 제거: 목차, 중복된 header/footer, 페이지 넘버, 쓸모없는 whitespace.
- 표/숫자 처리: 예산 금액, 날짜, 제출기한 등은 parsing 규칙 추가(tabula-py로 table 추출).
- 메타데이터 정리: 기관명, 공고일자, 마감일자 등 JSON에 정규화(날짜 ISO, 통화 단위).
(3) 청크화 (Chunking)
- 긴 문서를 retrieval-friendly하게 분리.
- 설정: 400 tokens, stride 100 → 문맥 손실 최소화.
- 각 청크에 문서ID, 페이지, 청크번호 metadata 저장 (출처 추적 필수).
(4) 라벨링 지원
- 30~50개 문서에 대해 핵심 필드(annotation) 수작업❗ → 평가용 정답셋 구축.
- 라벨 포맷: JSONL (문서id, 필드명, 텍스트 span).
1
pdf,hwp → 텍스트 추출(.txt) → 전처리(cleaning) → 청크화(chunking) → Meta data(JSON, csv)
** 파이프라인 모듈 정리**
FileLoader(파일 로더):- 역할:
data/raw/files폴더에서hwp,pdf파일을 읽어 순수 텍스트(raw text)를 추출하는 역할. - 핵심 코드: 우리가 이미 완성한
extract_text_from_pdf(),get_hwp_text_robust()
- 역할:
TextCleaner(텍스트 클리너):- 역할: 추출된 순수 텍스트에서 불필요한 제어 코드, 깨진 문자, 과도한 공백 등을 제거하는 역할.
- 핵심 코드: `clean_text_advanced().py
MetadataInjector(메타데이터 결합기):- 역할: 정제된 텍스트에
data_list.xlsx파일에 있는 메타데이터(사업명, 사업 금액 등)를 결합하는 역할.
- 역할: 정제된 텍스트에
TextSplitter(텍스트 분할기, Chunker):- 역할: 메타데이터까지 결합된 긴 텍스트를 LLM과 Vector DB가 처리하기 좋은 작은 조각(chunk)으로 나누는 역할.
- 핵심 도구:
LangChain의RecursiveCharacterTextSplitter
2. Retriever 파트에게 전달해야 할 최종 파일
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[
{
"content": "A 프로젝트의 사업 개요는 다음과 같다...",
"metadata": {
"source_filename": "A_프로젝트_제안서.hwp",
"project_name": "A 프로젝트",
"budget": 100000000,
"organization": "기관1"
}
},
{
"content": "...사업의 추진 배경 및 필요성은...",
"metadata": {
"source_filename": "A_프로젝트_제안서.hwp",
"project_name": "A 프로젝트",
"budget": 100000000,
"organization": "기관1"
}
}
]
2025-09-17 Tue
메타 데이터 구조 전략 수립
(1) 기본 구조 (The Simple & Flat)
1
2
3
4
5
6
7
8
9
10
{
"content": "A 프로젝트의 사업 개요는 다음과 같다...",
"metadata": {
"project_name": "A 프로젝트",
"organization": "기관1",
"budget": 100000000,
"deadline": "2024-10-15",
"source_filename": "A_프로젝트_제안서.hwp"
}
}
- 장점: 구현이 가장 간단하고 빠르다.
- 단점: 같은 문서에서 나온 모든 chunk는 완전히 동일한 메타데이터를 갖게 됨. “사업 개요” 섹션의 chunk인지, “제안 요청 내용” 섹션의 chunk인지 구분할 수 없음
(2) 계층 구조 (The Hierarchical)
1
2
3
4
5
6
7
8
9
10
11
12
{
"content": "본 사업의 추진 배경은 최근 AI 기술의 발전과...",
"metadata": {
"project_name": "A 프로젝트",
"organization": "기관1",
"budget": 100000000,
"source_filename": "A_프로젝트_제안서.hwp",
"section_h1": "Ⅰ. 사업 안내",
"section_h2": "2. 추진배경 및 필요성",
"page_number": 1
}
}
장점: 1) 정교한 검색 가능: 구체적인 검색이 가능. 2) 풍부한 답변 생성: LLM이 “A 프로젝트의 ‘추진 배경’ 섹션에 따르면…” 과 같이 훨씬 맥락에 맞는 답변을 생성할 수 있음.
단점: 전처리 단계에서 목차/소제목을 인식하는 로직을 개발해야 해서 구현 난이도가 조금 올라감.
(3) 요약 추가 구조 (The Semantic Summary)
1
2
3
4
5
6
7
8
9
{
"content": "본 사업의 추진 배경은 최근 AI 기술의 발전과...",
"metadata": {
"project_name": "A 프로젝트",
"organization": "기관1",
"section_h2": "2. 추진배경 및 필요성",
"chunk_summary": "이 chunk는 AI 기술 발전으로 인한 사업의 필요성과 배경을 설명함."
}
}
장점: 검색 성능 극대화: Retriever가 긴 원문 대신 짧고 의미가 응축된 요약문을 먼저 보고 1차 검색을 수행할 수 있음, 검색 속도와 정확도가 크게 향상. 고급 RAG에서 쓰인다고 한다.
단점: 복잡도 및 비용 증가: 수천 개의 모든 chunk에 대해 요약 모델을 한번 더 실행해야 하므로 전처리 시간과 비용이 증가.
2025-09-22 Mon
🟣 데이터 처리: 전수현
1. 데이터 추출 파트
HWP 파일에서 깨끗한 텍스트를 안정적으로 추출하는 게 이번 데이터 처리 파트의 가장 중요하고 어려운 과정.
텍스트 추출 전략 수립
(1) HWP -> HTML: 리브레 오피스 라이브러리 (2) HWP -> PDF: PDF 변환 후 OCR/파서 적용 (3) 혼합 방식: 텍스트 hwp5txt, 테이블 camelot (4) HWP 직접 추출: 공식 SDK / hwpctrl 활용
등.. 아이디어 수집 및 실험 필요
방법 1: HWP 전문 변환기(리브레오피스) 활용
HWP를 단순 txt가 아닌 HTML로 변환해서 구조적 정보를 최대한 살림
전략: 파이썬으로 리브레오피스(LibreOffice)를 제어해 HWP를 HTML로 변환한 뒤, 파이썬의
BeautifulSoup라이브러리로 HTML 구조를 분석해 텍스트와 표를 추출.작동 방식:
- 파이썬 코드가 터미널 명령어로 리브레오피스를 실행시켜 HWP 파일을 HTML 파일로 변환.
- 생성된 HTML 파일을 파이썬으로 읽어들임.
BeautifulSoup으로 HTML 태그(<h1>,<p>,<table>등)를 분석.- 일반 텍스트는
<p>태그에서, 표 데이터는<table>태그에서 구조적으로 추출.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
import subprocess from bs4 import BeautifulSoup from pathlib import Path def hwp_to_structured_text(hwp_path: Path): # 1. HWP -> HTML 변환 subprocess.run(['libreoffice', '--headless', '--convert-to', 'html', str(hwp_path)], capture_output=True) html_path = hwp_path.with_suffix('.html') if not html_path.exists(): return "HTML 변환 실패" # 2. BeautifulSoup으로 HTML 파싱 soup = BeautifulSoup(html_path.read_text(encoding='utf-8'), 'html.parser') # 3. 표(table)를 Markdown 형식으로 변환 (예시) for table in soup.find_all('table'): # ... (테이블 파싱 로직) ... # 4. 전체 텍스트 반환 return soup.get_text()
이미지는 별도 파일로 추출되지만, 이미지 안의 텍스트(OCR)는 처리하지 못함.
방법2 : TBD
추후 파트 담당과 상의 후 실험 및 개별 파일 확인 시작
개발할 핵심 코드: src/ 폴더 이번 프로젝트 폴더에
src/loaders/:
pdf_loader.py, hwp_loader.py: 우리가 함께 디버깅하며 완성한, 각 파일 형식에서 텍스트를 안정적으로 추출하는 코드를 여기에 각각 정리
csv_loader.py: data_list.csv 같은 메타데이터 파일을 읽어오는 코드가 들어갈 곳
src/preprocessing/
clean_text.py: HWP 파일에서 나온 제어 코드나 불필요한 공백 등을 제거하거나 노이즈 제거하는 모듈
chunking.py: 정제된 텍스트에 메타데이터를 결합하고, LangChain의 TextSplitter 등을 사용해 의미 있는 단위로 쪼개는 코드
src/pipelines/build_index.py:
이 파이프라인은 데이터 로딩 → 전처리 → 임베딩 → 벡터DB 구축까지의 전 과정을 자동화하는 스크립트.