
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 PythonPyQt6 기반 데스크톱 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단계: 리포팅 및 후속 기능 활성화
- 처리 시간, 토큰량, 추정 전력, 산출물 크기/저장 위치를 리포트로 출력
- 요약 텍스트를 컨텍스트로 저장하고 질의응답 기능 활성화
'AI Project' 카테고리의 다른 글
| #1-1. 로컬 LLM 기반 문서 요약 시연 화면 및 영상 (1) | 2026.04.20 |
|---|
댓글