본문 바로가기
AI Project

#1. 로컬 LLM 기반 문서 요약기 (On-Device Document Summarizer)

by 으노으뇨 2026. 4. 13.
728x90
반응형
SMALL

1. 글의 목적과 프로젝트 한 줄 소개

본 글은 로컬 PC 환경에서 인터넷 연결 없이 문서를 분석하고, 필요 시 요약 및 오디오 변환까지 수행하는 데스크톱 애플리케이션 AMEVA-Doc-AI의 설계와 구현 내용을 정리한 기술 포트폴리오 문서입니다.

uno-km/AMEVA-Doc-AI: Ollama 기반 오프라인 문서(HWP, Word, Excel 등) 요약 및 PDF 변환 도구

 

GitHub - uno-km/AMEVA-Doc-AI: Ollama 기반 오프라인 문서(HWP, Word, Excel 등) 요약 및 PDF 변환 도구

Ollama 기반 오프라인 문서(HWP, Word, Excel 등) 요약 및 PDF 변환 도구 - uno-km/AMEVA-Doc-AI

github.com

일단 동영상은 유투브를 개설후에 다시 올리겠습니다. 지금은 깃허브 소스만 첨부드립니다.

인터넷 없이 로컬에서 문서를 추출·표준화(PDF)하고, Ollama로 청크 병렬 요약을 스트리밍으로 보여주는 데스크톱 앱입니다. TTS(MP3)와 배터리/리소스 감시, 요약 컨텍스트 기반 Q&A까지 포함해 실사용 흐름을 완결했습니다.

핵심 목표는 다음과 같습니다.

핵심 목표 및 기능

  • 다양한 문서 포맷(HWP/HWPX/DOCX/XLSX/PPTX)에서 텍스트를 안정적으로 추출한다.
  • 추출한 텍스트를 PDF로 변환하여 결과물을 표준화한다.
  • 로컬 LLM(Ollama)을 활용해 문서를 청크 단위로 요약하고, 결과를 다시 PDF로 저장한다.
  • 선택 기능으로 요약 내용을 TTS로 변환하여 MP3 오디오북을 생성한다.
  • 요약 완료 후에는 문서 기반 질의응답(RAG 유사 흐름)을 제공한다.
  • 장시간 작업을 고려해 리소스 모니터링, 스레드 상태 시각화, 예외 처리, 작업 리포팅을 포함한다.

이 프로그램의 사용 시나리오는 아래와 같습니다.

사용 쒸네리오

  • 로컬 환경에서 사내 문서나 민감 문서를 외부로 전송하지 않고 요약이 필요할 때
  • 문서 원문을 사람이 읽기 쉬운 PDF로 재구성하고 싶을 때
  • 요약본을 오디오로 듣고 싶을 때(회의 준비, 이동 중 청취 등)
  • 요약된 문서를 '바탕으로 문서 안에 있는 내용'에 한정된 질의응답이 필요할 때
기술 스택 및 구성 요소
언어 및 UI
Python
PyQt6 기반 데스크톱 UI
문서 파서
docx(python-docx), openpyxl, python-pptx, olefile, zipfile, ElementTree
PDF 생성
Windows 환경에서는 MalgunGothic 폰트 등록을 우선 시도하고, 실패 시 Helvetica로 폴백
reportlab
로컬 LLM 추론
Ollama Python SDK를 통한 스트리밍 요약
로컬 PC에 맞는 모델 설정 및 설치 가능
병렬 처리 및 상태 관리
ThreadPoolExecutor로 청크 요약 병렬화
PyQt Signal/Slot으로 UI에 실시간 스트리밍 반영
TTS
edge-tts CLI 호출

2. 전체 아키텍처 개요(모듈 단위)

1-1. 계층 구조 요약

  •  core: 문서 텍스트 추출 및 PDF 생성 같은 “순수 기능” 계층
  • workers: 파일 처리 파이프라인, 모델 설치/다운로드, 병렬 요약 같은 “비동기 실행” 계층
  • ui: 사용자 입력/상태 표시/로그 스트리밍 등 “사용자 경험” 계층
  • entrypoint: 애플리케이션 실행 진입점

1-2. 모듈 맵(한눈에 보기)

계층파일책임(요약)핵심 포인트
폴더 파일 요약 핵심
core core/document_parser.py 확장자별 텍스트 추출 포맷별 파서 로직 분기
core/pdf_generator.py 텍스트를 PDF로 렌더링 제목/리스트/표 렌더링
workers workers/converter_worker.py 파일 단위 파이프라인 실행 요약 병렬화, 스트리밍 UI 전달
workers/ollama_worker.py Ollama 설치/모델 관리 winget 설치, pull 진행률
ui ui/main_window.py 메인 UI/작업 큐/로그/모니터링 스레드 로그 분리, 작업 중 채팅 제한
ui/model_manager.py 모델 설치/삭제 UI 다운로드 진행률 UI
entrypoint main.py 앱 실행 QApplication + 메인 윈도우

시연 영상

 1. 저용량 문서 (텍스트 800개) 변환 + AI 요약 + TTS 음성요약 - 싱글프로세서이용

--티스토리 동영상 정책으로 업로드실패... 나중에 유투브 채널을 만들고 그것으로 대체하겠습니다...

 

2. 멀티프로세서 이용한 병렬 요약방식

--이또한... 동영상 정책으로 업로드 불가...

 


핵심 기능 정리(면접관 관점)

 

1. 로컬 문서 처리 파이프라인의 완결성

ㅇ 텍스트 추출부터 PDF 표준화 산출물까지 기본 흐름이 끊기지 않도록 구성

ㅇ 요약을 수행하지 않더라도 Converted PDF를 항상 생성하여 최소 산출물 보장

2. 스트리밍 기반 요약 UX

ㅇ 스트리밍 응답을 즉시 UI로 전달하여 대용량 문서에서도 진행 상황 확인 가능

ㅇ 스레드별 로그 뷰 제공으로 장애 지점 파악이 용이

3. 병렬 처리 설계

ㅇ 청크 분할 후 ThreadPoolExecutor 병렬 처리

ㅇ 청크 인덱스 기반 재정렬로 문서 순서 보장

4. 리소스 및 운영 안정성(PoliceWorker)

ㅇ 주기적 상태 점검으로 장시간 작업 안정성 강화

ㅇ 배터리 모드 감지 시 스레드 축소 및 큐 이관 정책 적용

ㅇ 워커 타임아웃 처리로 무한 대기 감소

5. TTS 경로/인코딩 안정화

ㅇ 임시 파일 + 절대 경로 전략으로 한글 경로/인코딩 이슈 감소

ㅇ 출력 경로 정규화로 OS 경로 문제 완화

6. 문서 기반 질의응답(간결한 RAG 흐름)

ㅇ 요약 완료 텍스트를 컨텍스트로 저장

ㅇ 첫 질문에 컨텍스트 강제 주입, 이후 대화 이력 누적

ㅇ 문서 외 내용은 모른다고 답하도록 프롬프트 정책 적용

7. UI 반응성과 작업 스레드 분리

ㅇ QThread 기반 워커 + Signal/Slot로 UI 업데이트 구성

ㅇ 스트리밍 출력은 메인 스레드에 안전하게 반영

8. 산출물 중심 설계

ㅇ Converted PDF, Summary PDF, MP3가 각각 독립 산출물

ㅇ 파일별 체크로 요약 여부 선택 가능, 비용/시간 통제 가능

9. 품질 및 예외 처리 전략

ㅇ 문서 추출 단계 예외발생 시 치명 오류 리포트로 원인을 노출하고 작업을 중지

ㅇ 요약 스트리밍 도중 예외발생 시 해당 워커를 dead 처리하여 UI에 표시 ,다른 워커는 가능한 범위에서 지속 수행

ㅇ TTS 예외는 TTS 실패하더라도 PDF 산출물은 유지(옵션 기능의 실패가 전체 실패로 이어지지 않게 설계)

10. 관측 가능성

ㅇ 처리 시간, 토큰 수, 전력 추정치를 리포트로 남겨 운영 관점의 모니터링

 

 


 자세한 기능별 설명

core 계층

2-1. core/document_parser.py

2-1-1. 역할(Responsibility)

  • ㅇ 파일 확장자별 텍스트 추출 책임을 전담합니다.
  • ㅇ “문서 → 텍스트” 변환에서 UI, 워커 로직과 분리되어 있어 재사용과 유지보수에 유리합니다.

2-1-2. 지원 포맷 및 처리 방식

  •  HWPX
    • zip 기반 패키지 구조를 열고 XML 섹션(Contents/section*)을 순회하며 텍스트 노드를 추출합니다.
  • HWP
    • OLE 문서 구조에서 BodyText 스트림을 찾고 압축 해제 후(스트림 특성에 맞춰) 디코딩 및 정규식 정제로 텍스트를 확보합니다.
  • DOCX
    • 문단 텍스트를 순차 수집하고 표(Table)는 셀 텍스트를 정리해 “마크업 형태”로 유지합니다.
    • 표를 그냥 이어 붙이지 않고 구조를 남겨, 후속 PDF 렌더링에서 가독성이 좋아집니다.
  •  XLSX
    • 시트 단위로 순회하고 행/셀 값을 문자열로 변환하여 라인 단위로 축적합니다.
  • PPTX
    • 슬라이드를 순회하며 텍스트 프레임이 있는 shape의 문장을 수집합니다.

2-1-3. 설계 의도(Why)

  • 후속 단계(요약, PDF 렌더링, TTS)가 안정적으로 동작하려면 “추출 텍스트의 일관성”이 핵심이라 판단했습니다.
  • 포맷별 예외가 많기 때문에 추출 책임을 한 곳에 모아 디버깅 비용을 줄였습니다.

2-2. core/pdf_generator.py

2-2-1. 역할(Responsibility)

  • 추출 텍스트를 PDF로 렌더링합니다.
  • 결과물 표준화를 통해 “문서 뷰어/환경 차이” 영향을 줄입니다.

2-2-2. 렌더링 규칙(텍스트 → PDF)

  • 제목 처리
    • #, ##, ### 패턴을 감지해 글자 크기/강조를 조정합니다.
  • 리스트 처리
    • -, *로 시작하는 줄을 리스트 항목으로 렌더링합니다.
  • 표 처리
    • |로 시작하는 행을 테이블로 인식합니다.
    • 구분선(예: |---|---|)은 건너뛰고 실제 데이터만 표로 구성합니다.
    • 셀 내용은 Paragraph로 감싸 줄바꿈/폭 제한에서 가독성을 확보합니다.

2-2-3. 설계 의도(Why)

  • DOCX/표/리스트가 섞인 문서에서 “구조를 남기는 것”이 요약 품질과 결과물 신뢰도를 높인다고 보았습니다.
  • 폰트는 Windows 환경을 우선 고려하되, 실패 시 기본 폰트로 폴백하여 환경 의존성을 낮췄습니다.

3. workers 계층

3-1. workers/converter_worker.py

3-1-1. 역할(Responsibility)

  • 파일 단위 파이프라인 실행을 담당합니다.
    • 텍스트 추출
    • 기본 PDF 변환
    • 요약(선택)
    • TTS(선택)
    • 리포트 생성 및 UI 갱신

3-1-2. 요약 처리 방식(병렬 + 스트리밍)

  • 청크 분할
    • 원문 텍스트를 일정 크기(기본 1500)로 분할합니다.
    • 분할 시 가능한 줄바꿈 경계를 우선 활용합니다.
  • 청크 분배
    • thread_count에 따라 청크를 그룹으로 나누고 워커별 큐에 넣습니다.
  • 병렬 처리
    • ThreadPoolExecutor로 스레드별 요약 작업을 동시에 수행합니다.
  • 스트리밍 UI 전달
    • Ollama 스트리밍 응답을 받는 즉시 UI에 전달합니다.
    • 스레드별 로그 뷰에서 진행 상황을 분리하여 확인할 수 있습니다.
  • 결과 재조립
    • 청크 인덱스를 기준으로 정렬하여 문서 순서를 유지합니다.
    • 최종 요약 결과를 PDF로 저장합니다.

3-1-3. PoliceWorker(운영 안정성)

  • 장시간 작업 중 리소스/배터리 상태에 대응하기 위해 별도 스레드로 동작합니다.
  • 배터리 모드 감지 시 정책
    • 과도한 동시 실행을 줄이기 위해 특정 스레드를 강제 대기 처리하고
    • 남은 청크를 다른 큐로 이관하여 작업이 멈추지 않게 합니다.
  • 타임아웃 정책
    • 일정 시간 이상 응답이 없는 워커는 dead 처리하여 무한 대기 가능성을 줄입니다.

3-1-4. TTS 안정화(경로/인코딩)

  • edge-tts 호출 시 발생할 수 있는 경로/인코딩 문제를 피하기 위해 다음을 적용했습니다.
  • 입력 텍스트 정제
    • 음성 합성에 방해가 되는 특수문자/마크업 기호를 정규식으로 제거합니다.
  • 임시 파일 전략
    • 임시 텍스트 파일을 “현재 작업 디렉터리의 절대 경로”로 생성합니다.
    • CLI에는 파일 경로를 절대 경로로 넘겨 경로 해석 문제를 줄입니다.
  • 종료 정리
    • 작업 종료 시 임시 파일을 삭제합니다.

3-2. workers/ollama_worker.py

3-2-1. 역할(Responsibility)

  • Ollama 설치/모델 관리 자동화를 담당합니다.
  • UI 프리징 없이 진행되도록 별도 워커로 실행합니다.

3-2-2. 제공 기능

  • 설치 확인 및 설치
    • 미설치 시 winget 기반 설치 흐름을 제공합니다.
  • 모델 목록 조회
    • 설치된 모델 정보를 가져와 UI에 반영합니다.
  • 모델 다운로드(pull)
    • 진행률을 시그널로 전달하여 UI에서 퍼센트로 표시합니다.

4. ui 계층

4-1. ui/main_window.py

4-1-1. 역할(Responsibility)

  • 사용자 입력과 실행 흐름 제어(파일 추가, 저장 경로 선택, 실행 버튼)
  • 작업 큐 관리(체크 상태로 요약 여부 결정)
  • 시스템 모니터링(CPU/RAM/GPU) 표시
  • 로그/스트리밍 표시(전체 로그 + 스레드별 로그 뷰)

4-1-2. 사용자 경험(UX) 정책

  • 진행 상태 가시성
    • 전체 진행 로그와 스레드별 스트리밍 로그를 분리해 “어디서 진행 중인지” 즉시 확인 가능합니다.
  • 작업 중 채팅 제한
    • 요약 작업 중에는 채팅 입력을 제한하고, 완료 후 질의응답을 활성화합니다.
    • 병렬 작업으로 자원 사용이 큰 구간에서 사용자 인터랙션을 제한하여 안정성을 확보합니다.

4-1-3. RAG 유사 질의응답 흐름

  • 요약 완료 텍스트를 컨텍스트로 저장합니다.
  • 첫 질문
    • 컨텍스트를 프롬프트에 강제 주입합니다.
  • 이후 질문
    • 대화 이력을 누적하여 연속 대화가 가능하게 합니다.
  • 안전장치
    • 문서에 없는 내용은 모른다고 답하게 하는 정책을 프롬프트에 포함합니다.

4-2. ui/model_manager.py

4-2-1. 역할(Responsibility)

  • 설치 가능한 모델 목록을 보여주고 설치/삭제를 UI로 제공합니다.
  • 모델 다운로드 진행률을 프로그레스 바로 표시합니다.

5. 진입점(entrypoint)

5-1. main.py

  • QApplication 실행 및 메인 윈도우 구동을 담당합니다.
  • 구조상 UI 외부에서 실행 로직을 분리해두었기 때문에, 향후 CLI 또는 다른 UI로 확장도 가능한 형태입니다.

6. 처리 파이프라인(파일 1개 기준, 실행 순서)

6-1. 1단계: 입력 파일 수집

  • 로컬 파일 선택 또는 URL 기반 다운로드(옵션)
  • 파일별 체크 상태로 “요약 수행 여부”를 결정

6-2. 2단계: 텍스트 추출(DocumentParser)

  • 확장자 기반 분기
  • 추출 실패 시 예외 처리 및 작업 중지(치명 오류 리포트)

6-3. 3단계: 기본 PDF 변환(PDFGenerator)

  • 추출 텍스트를 Converted PDF로 저장
  • 표/리스트/제목 형식을 가능한 유지하여 가독성을 확보

6-4. 4단계: 요약(선택)

  • 원문을 청크로 분할(기본 1500 기준)
  • 스레드 수에 따라 청크를 분배
  • 스레드가 스트리밍 응답을 수신하며 UI에 실시간 전달
  • 완료된 청크 결과를 문서 순서로 재조립
  • AI 요약 보고서 PDF 생성

6-5. 5단계: 오디오북 생성 TTS(선택)

  • 요약 결과를 기반으로 입력 텍스트 구성
  • 정규식으로 특수문자/마크업 등 제거
  • 임시 텍스트 파일을 절대 경로로 생성
  • edge-tts를 CLI로 호출해 MP3 생성
  • 종료 시 임시 파일 삭제

6-6. 6단계: 리포팅 및 후속 기능 활성화

  • 처리 시간, 토큰량, 추정 전력, 산출물 크기/저장 위치를 리포트로 출력
  • 요약 텍스트를 컨텍스트로 저장하고 질의응답 기능 활성화
728x90
반응형
LIST

'AI Project' 카테고리의 다른 글

#1-1. 로컬 LLM 기반 문서 요약 시연 화면 및 영상  (1) 2026.04.20

댓글