첨부용 전처리기
Genos 는 크게 적재용(내부), 적재용(외부), 적재용(규정), 첨부용 4가지 유형의 전처리기 (document parser)를 지원합니다. 여기서는 첨부용 Intelligent Doc Parser - text 추출형 전처리기의 코드 원형에 대해서 설명합니다.

여기서는 Genos 첨부용 문서 파서의 전처리 파이프라인 내 주요 구성 요소에 대한 코드 중심의 설명을 제공합니다. 코드 조각과 함께 각 부분의 기능을 이해함으로써, 특정 요구 사항 및 문서 유형에 맞게 문서 처리 프로세스를 보다 효과적으로 조정할 수 있습니다.
🔧 공통 구성요소
GenOSVectorMetaBuilder 및 GenOSVectorMeta
GenOSVectorMetaBuilder 및 GenOSVectorMetaGenOSVectorMetaBuilder는 각 청크에 대한 상세 메타데이터 객체인 GenOSVectorMeta를 단계적으로 생성하는 역할을 합니다.
GenOSVectorMeta (Pydantic 모델)
먼저, 최종적으로 생성될 메타데이터의 구조를 정의하는 Pydantic 모델입니다.
Python
설명:
BaseModel을 상속받아 Pydantic 모델로 정의됩니다. 이는 데이터 유효성 검사 및 직렬화/역직렬화를 용이하게 합니다.Config.extra = 'allow': 모델에 정의되지 않은 추가 필드가 입력 데이터에 존재하더라도 오류를 발생시키지 않고 허용합니다. (Pydantic V2에서는model_config = ConfigDict(extra='allow')형태로 사용)각 필드는 청크의 메타데이터 항목을 나타냅니다.
text: 청크의 텍스트 내용.n_char,n_word,n_line: 문자 수, 단어 수, 줄 수.e_page,i_page,i_chunk_on_page,n_chunk_of_page: 페이지 내에서의 청크 위치 정보.i_chunk_on_doc,n_chunk_of_doc: 문서 전체에서의 청크 위치 정보.n_page: 문서의 총 페이지 수.reg_date: 처리 등록 시간.bboxes: 페이지 내 해당 청크의 경계 상자 (JSON 문자열 형태).chunk_bboxes: 청크를 구성하는 각DocItem의 상세 경계 상자 정보 리스트.media_files: 청크 내 포함된 미디어 파일(이미지) 정보 리스트.
사용자 정의 포인트:
고객사에서 필요한 추가적인 메타데이터 항목이 있다면, 이
GenOSVectorMeta모델에 새로운 필드를 추가로 정의할 수 있습니다.필드 타입을 보다 엄격하게 정의하거나 (예:
Optional[str]), 기본값을 설정하거나, 유효성 검사 로직을 추가할 수 있습니다.
GenOSVectorMetaBuilder 클래스 및 주요 메서드
GenOSVectorMeta 객체를 생성하는 빌더 클래스입니다.
Python
설명:
__init__: 빌더 내부의 모든 속성들을 초기화합니다. 이 속성들은GenOSVectorMeta의 필드들과 대부분 일치합니다.set_text: 청크의 텍스트를 설정하고, 문자 수, 단어 수, 줄 수를 계산하여 내부 속성에 저장합니다.set_page_info: 페이지 번호, 페이지 내 청크 인덱스, 페이지 내 총 청크 수를 설정합니다.set_chunk_index: 문서 전체에서의 청크 인덱스를 설정합니다.set_global_metadata:DocumentProcessor.compose_vectors에서 전달받은global_metadata딕셔너리의 값들을 빌더의 해당 속성에 할당합니다. 빌더 내에global_metadata의 키와 동일한 이름의 속성이 있어야 값이 할당됩니다.set_chunk_bboxes: 청크를 구성하는 모든DocItem들의 상세한 경계 상자 정보를 추출하여 리스트로 저장합니다. 각 항목은 페이지 번호, 정규화된 좌표(0~1 값),DocItem의 타입 및 참조 ID를 포함합니다. 정규화된 좌표는 페이지 크기에 상대적인 위치를 나타내므로, 다양한 크기의 페이지에서도 일관되게 위치를 표현할 수 있습니다.set_media_files: 청크 내에PictureItem(이미지)이 포함되어 있다면, 해당 이미지의 파일 이름, 타입("image"), 참조 ID를 추출하여 리스트로 저장합니다.build: 지금까지set_...메서드들을 통해 빌더 내부에 축적된 모든 속성값들을 사용하여 최종적으로GenOSVectorMetaPydantic 모델 객체를 생성하고 반환합니다.
사용자 정의 포인트:
GenOSVectorMeta모델에 새로운 필드를 추가했다면, 이 빌더에도 해당 필드를 위한 내부 속성과set_...메서드를 추가해야 합니다.build메서드에서GenOSVectorMeta객체를 생성할 때 새로 추가된 필드도 인자로 전달하도록 수정해야 합니다.특정 필드값을 설정하기 전에 추가적인 가공 로직(예: 날짜 형식 변환, 특정 코드값 매핑 등)이 필요하다면 해당
set_...메서드 내부에 구현할 수 있습니다.
공통 문서 로더
HwpLoader
HwpLoaderhwp 파일을 로드하고 변환하는 데 사용됩니다. HWP 파일을 XHTML로 변환한 후 PDF로 저장하고, 최종적으로 PyMuPDFLoader를 사용하여 문서 내용을 로드합니다.
Python
설명:
HwpLoader: HWP 파일을 로드하고 변환하는 데 사용되는 클래스입니다. HWP 파일을 XHTML로 변환한 후 PDF로 저장하고, 최종적으로 PyMuPDFLoader를 사용하여 문서 내용을 로드합니다.
TextLoader
TextLoader텍스트 파일을 로드하고 변환하는 데 사용됩니다. 다양한 인코딩을 지원하며, PDF로 변환할 수 있는 기능을 포함하고 있습니다.
Python
설명:
TextLoader: 텍스트 파일을 로드하고 변환하는 데 사용되는 클래스입니다. 다양한 인코딩을 지원하며, PDF로 변환할 수 있는 기능을 포함하고 있습니다.
TabularLoader
TabularLoader표 형식의 데이터를 로드하고 변환하는 데 사용됩니다. CSV, Excel 등 다양한 형식의 표 데이터를 지원합니다.
Python
설명:
check_sql_dtypes: 데이터프레임의 각 열에 대한 SQL 데이터 유형을 확인하고, 필요한 경우 형 변환을 수행합니다.process_data_rows: 데이터 행을 처리하고, 필요한 경우 변환을 수행합니다.load_csv_documents: CSV 문서를 로드하고, 필요한 전처리를 수행합니다.load_xlsx_documents: Excel 문서를 로드하고, 필요한 전처리를 수행합니다.return_vectormeta_format: 현재 데이터의 메타 정보를 벡터 형식으로 변환하여 반환합니다.
AudioLoader
AudioLoaderAudioLoader 클래스는 오디오 파일을 로드하고, 청크로 분할하며, 각 청크에 대한 텍스트를 전사하는 기능을 제공합니다.
Python
설명:
AudioLoader: 오디오 파일을 로드하고, 청크로 분할하며, 각 청크에 대한 텍스트를 전사하는 기능을 제공합니다.split_file_as_chunks: 오디오 파일을 지정된 길이의 청크로 분할합니다.transcribe_audio: 분할된 오디오 청크를 전사하여 텍스트로 변환합니다.return_vectormeta_format: 전사된 텍스트를 벡터 메타 형식으로 변환하여 반환합니다.
HWPX
HWPXHWPX 클래스는 HWPX 형식의 문서를 로드하고, 필요한 전처리를 수행하는 기능을 제공합니다. HierarchicalChunker, HybridChunker, HwpxProcessor 등의 구성 요소를 사용하여 문서를 청크로 분할하고, 각 청크에 대한 메타데이터를 생성합니다.
``HierarchicalChunker및HybridChunker`
HierarchicalChunker는 문서를 계층적으로 청크로 나누는 역할을 하며, HybridChunker는 토큰 제한을 고려하여 섹션별 청크를 분할하고 병합하는 고급 청커입니다.
Python
HwpxProcessor
HwpxProcessor 클래스는 HWPX 형식의 문서를 처리하는 데 필요한 다양한 기능을 제공합니다. 이 클래스는 문서의 청크를 생성하고, 메타데이터를 구성하며, 최종적으로 벡터 형태로 변환하는 작업을 수행합니다.
Python
설명:
get_paths: 주어진 파일 경로에 대한 아티팩트 디렉토리와 참조 경로를 반환합니다.get_media_files: 주어진 문서에서 미디어 파일의 경로를 추출합니다.safe_join: 주어진 iterable의 요소를 안전하게 연결하여 문자열로 반환합니다.load_documents: 주어진 파일 경로에서 문서를 로드합니다.split_documents: 로드된 문서를 의미 있는 작은 단위(청크)로 분할합니다.chunker: HybridChunker = HybridChunker(): 문서를 청크로 나누기 위해HybridChunker인스턴스를 생성합니다.HybridChunker는 내부적으로 계층적 구조(Hierarchical)와 의미론적 분할(Semantic, 주석 처리된semchunk의존성 부분에서 유추)을 결합하여 문서를 분할합니다.max_tokens는 각 청크의 최대 토큰 수를 제한합니다.merge_peers는 인접한 청크들을 병합할지 여부를 결정합니다.
chunks: List[DocChunk] = list(chunker.chunk(dl_doc=documents, **kwargs)):chunker의chunk메서드를 호출하여DoclingDocument를DocChunk객체들의 리스트로 변환합니다.**kwargs는 청킹 과정에 필요한 추가 옵션을 전달하는 데 사용될 수 있습니다 .for chunk in chunks: self.page_chunk_counts[chunk.meta.doc_items[0].prov[0].page_no] += 1: 각 청크가 어떤 페이지에서 왔는지 파악하여self.page_chunk_counts딕셔너리에 페이지별 청크 수를 기록합니다. 이는 추후 메타데이터 생성 시 활용됩니다. (chunk.meta.doc_items[0].prov[0].page_no는 청크를 구성하는 첫번째 문서 아이템의 첫번째 출처 정보에서 페이지 번호를 가져옵니다.)
compose_vectors: 분할된 청크들에 대해 메타데이터를 생성하고 최종적인 벡터(딕셔너리 형태) 리스트를 구성합니다. 이 부분이 고객사별 요구사항을 반영하는 부분이며 매우 중요합니다.__call__: 문서 처리를 수행하는 메서드입니다.document: DoclingDocument = self.load_documents(file_path, **kwargs):load_documents메서드를 호출하여 입력된file_path의 문서를 로드합니다.**kwargs는 사용자가 입력 UI 를 통해서 지정하거나, 혹은 수집기가 수집단에서 지정한 정보를 전달합니다.artifacts_dir, reference_path = self.get_paths(file_path): 문서의 아티팩트 디렉토리와 참조 경로를 가져옵니다.document = document._with_pictures_refs(image_dir=artifacts_dir, reference_path=reference_path):DoclingDocument객체 내의 그림(PictureItem)들이 실제 파일로 저장될 위치(image_dir)와 참조 경로(reference_path)를 설정하여, 그림 객체가 실제 파일 경로를 참조하도록 업데이트합니다.PdfPipelineOptions에서generate_picture_images = True로 설정된 경우,docling라이브러리가 내부적으로 이 경로에 이미지들을 저장하고, 이 메서드를 통해 문서 객체 내의 참조를 업데이트합니다.chunks: List[DocChunk] = self.split_documents(document, **kwargs): 업데이트된document객체를split_documents메서드에 전달하여 청크 리스트를 얻습니다.text가 있는 item이 없을 때 document에 임의의 text item 추가합니다.
vectors = [] ...:만약 생성된 청크가 1개 이상이면 (
len(chunks) >= 1),compose_vectors메서드를 호출하여 최종 메타데이터 벡터 리스트를 생성합니다.청크가 하나도 없으면
GenosServiceException을 발생시켜 오류 상황임을 알립니다.return vectors: 생성된 벡터 리스트를 반환합니다.
📂 공통 전처리 흐름
DocumentProcessor
DocumentProcessorDocumentProcessor 클래스는 Genos 의 전처리기가 호출되는 관문입니다. 내부 구성을 보면, 문서를 로드, 변환, 분할하고 각 부분에 대한 메타데이터를 구성하는 핵심 요소입니다.
__init__ (초기화)
DocumentProcessor 인스턴스가 생성될 때 호출되는 초기화 메서드입니다. 여기서 문서 처리 파이프라인의 주요 설정들이 정의됩니다.
Python
설명:
self.page_chunk_counts = defaultdict(int): 페이지별로 생성된 청크의 수를 저장하기 위한 딕셔너리입니다.self.hwpx_processor = HwpxProcessor(): HWPX 문서 처리를 위한 프로세서입니다.
get_loader
문서 변환에 사용할 변환기를 설정하는 함수입니다.
Python
설명:
각 확장자에 맞는 로더를 반환합니다.
convert_to_pdf, convert_md_to_pdf
문서를 PDF로 변환하는 메서드입니다.
Python
설명:
convert_to_pdf:주어진 파일 경로에 있는 문서를 PDF로 변환합니다.
LibreOffice의 명령줄 도구를 사용하여 변환을 수행합니다.
convert_md_to_pdf:Markdown 파일을 PDF로 변환하는 메서드입니다.
load_documents
문서 파일을 로드하여 문서 객체 리스트를 생성하는 메서드입니다.
Python
설명:
loader = self.get_loader(file_path): 파일 경로에 맞는 로더를 가져옵니다.documents = loader.load(): 로더를 사용하여 문서 파일을 로드합니다.return documents: 로드된 문서 객체 리스트를 반환합니다.
split_documents
로드된 문서를 의미 있는 작은 단위(청크)로 분할합니다.
Python
설명:
text_splitter = RecursiveCharacterTextSplitter(**kwargs): 문서를 의미 있는 작은 단위로 분할하기 위해RecursiveCharacterTextSplitter인스턴스를 생성합니다. 이 클래스는 재귀적으로 문서를 분할하여 각 청크의 내용을 최대한 유지합니다.chunks = text_splitter.split_documents(documents):text_splitter의split_documents메서드를 호출하여 문서를 청크로 분할합니다.chunks = [chunk for chunk in chunks if chunk.page_content]: 페이지 콘텐츠가 있는 청크만 필터링합니다.if not chunks: raise Exception('Empty document'): 청크가 비어있으면 예외를 발생시킵니다.for chunk in chunks: page = chunk.metadata.get('page', 0); self.page_chunk_counts[page] += 1: 각 청크의 페이지 정보를 기반으로 페이지별 청크 수를 업데이트합니다.return chunks: 최종 청크 리스트를 반환합니다.
compose_vectors
분할된 청크들에 대해 메타데이터를 생성하고 최종적인 벡터(딕셔너리 형태) 리스트를 구성합니다. 이 부분이 고객사별 요구사항을 반영하는 부분이며 매우 중요합니다.
Python
설명:
한국은행 기록물의 메타데이타 Mapping 예
global_metadata: 문서 전체에 공통적으로 적용될 메타데이터를 딕셔너리로 구성합니다.n_chunk_of_doc=len(chunks): 문서 내 총 청크 수.n_page=max([chunk.metadata.get('page', 0) for chunk in chunks]): 문서의 총 페이지 수.reg_date: 현재 시간을 ISO 형식의 문자열로 등록일로 사용합니다.
루프 (
for chunk_idx, chunk in enumerate(chunks):): 각 청크를 순회하며 메타데이터를 생성합니다.page = chunk.metadata.get('page', 0): 현재 청크의 시작 페이지 번호를 가져옵니다.text = chunk.page_content: 청크의 실제 텍스트 내용을 가져옵니다.global_metadata['chunk_bboxes'] = json.dumps(merge_overlapping_bboxes(...): 청크의 경계 상자 정보를 병합하여 JSON 문자열로 저장합니다.vectors.append(...): 생성된GenOSVectorMetaPydantic 모델 객체를vectors리스트에 추가합니다.
페이지 변경 감지 로직:
current_page와chunk_index_on_page를 사용하여 페이지가 바뀔 때마다 페이지 내 청크 인덱스를 0으로 초기화합니다.
__call__
DocumentProcessor 인스턴스를 GenOS 에서 호출할때의 진입점으로, 함수처럼 호출했을 때 실행되는 메인 로직입니다. 문서 처리의 전체 흐름을 담당합니다.
Python
설명:
ext = os.path.splitext(file_path)[-1].lower(): 파일 경로에서 확장자를 추출하고 소문자로 변환합니다. 확장자에 따라서 적합한 처리 로직을 선택하기 위함입니다.if ext in ('.wav', '.mp3', '.m4a'):: 오디오 파일인 경우, 오디오 전용 처리 로직을 수행합니다.tmp_path = "./tmp_audios_{}".format(os.path.basename(file_path).split('.')[0]): 오디오 파일을 임시로 저장할 디렉토리 경로를 생성합니다. 이 디렉토리는 오디오 청크를 저장하는 데 사용됩니다.if not os.path.exists(tmp_path): os.makedirs(tmp_path): 임시 디렉토리가 존재하지 않으면 생성합니다.loader = AudioLoader(...):AudioLoader인스턴스를 생성하여 오디오 파일을 처리합니다. 여기서req_url과req_data는 음성 인식 모델에 대한 요청 정보를 포함합니다.vectors = loader.return_vectormeta_format(): 오디오 파일을 처리하고 벡터 메타데이터 형식으로 변환된 결과를 얻습니다.await assert_cancelled(request): 요청이 취소되었는지 확인합니다. 취소된 경우 예외를 발생시킵니다.subprocess.run(['rm', '-r', tmp_path], check=True): 임시 오디오 청크 디렉토리를 삭제하여 정리합니다.return vectors: 생성된 벡터 메타데이터를 반환합니다.
elif ext in ('.csv', '.xlsx'):: CSV 또는 XLSX 파일인 경우, 표 형식 전용 처리 로직을 수행합니다.loader = TabularLoader(file_path, ext):TabularLoader인스턴스를 생성하여 표 형식 파일을 처리합니다.vectors = loader.return_vectormeta_format(): 표 형식 파일을 처리하고 벡터 메타데이터 형식으로 변환된 결과를 얻습니다.await assert_cancelled(request): 요청이 취소되었는지 확인합니다. 취소된 경우 예외를 발생시킵니다.return vectors: 생성된 벡터 메타데이터를 반환합니다.
elif ext == '.hwp': ...: HWP 파일인 경우, HWP 전용 처리 로직을 수행합니다.documents: list[Document] = self.load_documents(file_path, **kwargs): HWP 파일을 로드하여 문서 객체 리스트를 생성합니다.await assert_cancelled(request): 요청이 취소되었는지 확인합니다. 취소된 경우 예외를 발생시킵니다.chunks: list[Document] = self.split_documents(documents, **kwargs): 문서 객체를 청크 단위로 분할합니다.await assert_cancelled(request): 요청이 취소되었는지 확인합니다. 취소된 경우 예외를 발생시킵니다.vectors: list[dict] = self.compose_vectors(file_path, chunks, **kwargs): 청크를 기반으로 벡터 메타데이터를 생성합니다.return vectors: 생성된 벡터 메타데이터를 반환합니다.
elif ext == '.hwpx': ...: HWPX 파일인 경우, HWPX 전용 처리 로직을 수행합니다.return await self.hwpx_processor(request, file_path, **kwargs):HwpxProcessor인스턴스를 호출하여 HWPX 파일을 처리하고 벡터 메타데이터를 반환합니다.
else: ...: 그 외의 파일 형식인 경우, 일반적인 문서 처리 로직을 수행합니다.documents: list[Document] = self.load_documents(file_path, **kwargs): 문서 파일을 로드하여 문서 객체 리스트를 생성합니다.await assert_cancelled(request): 요청이 취소되었는지 확인합니다. 취소된 경우 예외를 발생시킵니다.chunks: list[Document] = self.split_documents(documents, **kwargs): 문서 객체를 청크 단위로 분할합니다.await assert_cancelled(request): 요청이 취소되었는지 확인합니다. 취소된 경우 예외를 발생시킵니다.vectors: list[dict] = self.compose_vectors(file_path, chunks, **kwargs): 청크를 기반으로 벡터 메타데이터를 생성합니다.return vectors: 생성된 벡터 메타데이터를 반환합니다.
사용자 정의 포인트:
**kwargs활용:__call__메서드에 전달되는**kwargs는 내부적으로load_documents,split_documents,compose_vectors로 전파될 수 있으므로, 문서 처리 전 과정에 걸쳐 동적인 설정을 주입하는 통로로 활용될 수 있습니다. 예를 들어, API 요청으로부터 특정 파라미터를 받아kwargs로 전달하고, 이 값을 기반으로PdfPipelineOptions의 일부를 변경하거나compose_vectors에서 특정 메타데이터를 추가/제외하는 등의 로직을 구현할 수 있습니다.
✨ 사용자 정의 포인트
메타 필드 확장:
GenOSVectorMeta와Builder클래스에 필드 추가페이지 처리 로직 수정:
set_page_info파라미터 조정청크 분할 커스터마이징:
HybridChunker파라미터 기준값 수정문자열 변환:
NaN,None등 값은 전처리 단계에서 빈 문자열 처리
✅ 유지보수 팁
Pydantic
extra='allow'설정으로 필드 변경이 유연하게 허용됨Builder 패턴을 사용하여 필드 설정 오류를 방지하고 유지보수를 단순화
이와 같이 코드 조각과 함께 설명을 보면서 DocumentProcessor와 GenOSVectorMetaBuilder의 작동 방식과 사용자 정의 지점을 파악하시면, 요구사항에 맞게 전처리 파이프라인을 효과적으로 수정하고 확장하실 수 있을 것입니다.
Was this helpful?