[코드잇 스프린트] 프로젝트#2 log |        Serendipity                                                                                                                                                                                                                                                                                                                                                                                   
Post

[코드잇 스프린트] 프로젝트#2 log

[코드잇 스프린트] 프로젝트#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)으로 나누는 역할.
    • 핵심 도구: LangChainRecursiveCharacterTextSplitter

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 구조를 분석해 텍스트와 표를 추출.

  • 작동 방식:

    1. 파이썬 코드가 터미널 명령어로 리브레오피스를 실행시켜 HWP 파일을 HTML 파일로 변환.
    2. 생성된 HTML 파일을 파이썬으로 읽어들임.
    3. BeautifulSoup으로 HTML 태그(<h1>, <p>, <table> 등)를 분석.
    4. 일반 텍스트는 <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 구축까지의 전 과정을 자동화하는 스크립트.

This post is licensed under CC BY 4.0 by the author.