개요
'PPT 슬라이드를 자동으로 분석해볼 수 없을까?' 에서 시작된 간단한 토이 프로젝트로 Python 환경에서 다음과 같은 기능을 구현해봤습니다.
사용된 기술 스택 및 dependency 설치
# torch 버전은 본인의 GPU에 맞게 세팅
pip install torch transformers==4.44.0
pip install pdf2image python-pptx comtypes
구현 과정
1. PPT를 PDF로 변환
PPT를 PDF로 변환하는 과정은 comtypes 라이브러리를 이용합니다.
이 라이브러리는 Windows COM(Component Object Model) 인터페이스와 상호 작용할 수 있게 해줍니다.
이를 이용해 Microsoft Office 애플리케이션(Powerpoint, Word, Excel, ...)을 프로그래밍 방식으로 제어할 수 있습니다.
다음 코드는 PPT를 PDF로 변환하는 함수입니다.
import os
from pptx import Presentation
from comtypes import client
from pdf2image import convert_from_path
def ppt_to_pdf(ppt_path, pdf_path):
"""
PPT 파일을 PDF로 변환하는 함수
:param ppt_path: PPT 파일 경로
:param pdf_path: 저장할 PDF 파일 경로
"""
powerpoint = client.CreateObject("Powerpoint.Application")
powerpoint.Visible = 1
print(ppt_path)
presentation = powerpoint.Presentations.Open(ppt_path)
presentation.SaveAs(pdf_path, 32) # 32는 PDF 형식을 나타냅니다
presentation.Close()
powerpoint.Quit()
print(f"PPT 파일이 {pdf_path}로 변환되었습니다.")
이 함수는 다음과 같은 순서로 동작합니다.
- PowerPoint 앱 객체 생성
- 지정된 경로의 PPT 파일을 앱 객체를 통해 로드
- PDF 형식(32)으로 저장
- 로드한 PPT 파일을 닫고, 앱 객체 종료
ppt_path = "경로/파일명.pptx"
pdf_path = "경로/파일명.pdf"
ppt_to_pdf(ppt_path, pdf_path)
이런 형식으로 호출이 가능합니다.
2. PDF를 각각의 이미지로 변환
PDF를 이미지로 변환하는 작업에는 Poppler라는 서드파티 라이브러리와 Python의 pdf2image 모듈이 필요합니다.
Poppler를 Windows에서 사용하기 위해서는 https://github.com/oschwartz10612/poppler-windows/releases/ 에서 최신 릴리즈를 설치하고, 환경변수 등록이 필요합니다.
pip install pdf2image
PDF를 각각의 이미지로 변환하는 함수는 다음과 같습니다.
환경변수를 등록한 경로와 동일하게 poppler_bin_path를 입력하시면 경로의 정확성 여부를 체크할 수 있습니다.
def pdf_to_images(pdf_path, output_folder):
"""
PDF 파일을 1장씩 이미지로 저장하는 함수
:param pdf_path: PDF 파일 경로
:param output_folder: 이미지를 저장할 폴더 경로
:return: 저장된 이미지 파일 경로 리스트
"""
if not os.path.exists(output_folder):
os.makedirs(output_folder)
poppler_bin_path = r"D:\Library\poppler-24.07.0\Library\bin"
if os.path.exists(poppler_bin_path):
print("Poppler 경로가 정확합니다.")
else:
print("Poppler 경로가 잘못되었습니다.")
try:
images = convert_from_path(pdf_path, poppler_path=poppler_bin_path)
image_paths = []
for i, image in enumerate(images):
image_path = os.path.join(output_folder, f"page_{i+1}.png")
image.save(image_path, "PNG")
image_paths.append(image_path)
print(f"{len(image_paths)}개의 이미지가 {output_folder}에 저장되었습니다.")
return image_paths
except PDFInfoNotInstalledError:
print("Poppler가 설치되지 않았거나 PATH에 추가되지 않았습니다.")
except PDFPageCountError:
print("PDF 페이지 수를 확인할 수 없습니다. PDF 파일이 손상되었을 수 있습니다.")
except Exception as e:
print(f"이미지 추출 중 오류 발생: {str(e)}")
return []
3. Vision-Language 모델을 이용한 이미지 해석
Vision-Language (VL) 모델은 컴퓨터 비전과 자연어 처리 기술을 결합한 인공지능 모델입니다.
VL 모델은 이미지를 이해하고 관련된 텍스트를 생성하거나, 텍스트 설명을 바탕으로 이미지를 이해하는 능력을 갖추고 있습니다.
VL 모델은 다음과 같은 주요 특징을 가지고 있습니다.
- 멀티모달 학습 : 이미지 & 텍스트 데이터를 동시에 처리
- 크로스모달 이해 : 이미지 <-> 텍스트 간 관계를 파악
- 다양한 응용 범위 : 이미지 캡션 처리, 시각적 질의응답, 이미지 검색 등
본 프로젝트에서는 'Bllossom/llama-3.1-Korean-Bllossom-Vision-8B' 모델을 사용했습니다.
이 모델은 다음과 같은 특징을 가지고 있습니다:
- 한국어 지원 : 한국어로 이미지 분석 및 설명 생성
- 대규모 언어 모델 : LLaMA 3.1 아키텍처 기반
- 비전 기능 : 이미지 처리 및 이해 능력 포함
- 8B 파라미터 : 비교적 작은 파라미터로 최적의 결과를 도출할 수 있음
실행 함수는 다음과 같습니다.
from transformers import LlavaNextForConditionalGeneration, LlavaNextProcessor
import torch
def analyze_images_with_VL_model(image_paths):
"""
이미지를 Vision-Language 모델을 이용해 분석하는 함수
:param image_paths: 분석할 이미지 파일 경로 리스트
:return: 각 이미지에 대한 분석 결과 리스트
"""
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model = LlavaNextForConditionalGeneration.from_pretrained(
'Bllossom/llama-3.1-Korean-Bllossom-Vision-8B',
)
model = model.half() # FP16 양자화
model = model.half()
model = model.to(device)
processor = LlavaNextProcessor.from_pretrained('Bllossom/llama-3.1-Korean-Bllossom-Vision-8B')
PROMPT = """You are a versatile AI assistant named Bllava, capable of both understanding and generating text as well as interpreting and analyzing images. Your role is to kindly and effectively answer the user's questions, whether they are about text or images, and provide appropriate and helpful responses to all types of queries.
당신은 텍스트를 이해하고 생성하는 것뿐만 아니라 이미지를 해석하고 분석할 수 있는 다재다능한 AI 어시스턴트 블라바입니다. 사용자의 질문이 텍스트에 관한 것이든 이미지에 관한 것이든 친절하고 효과적으로 답변하며, 모든 유형의 질의에 대해 적절하고 유용한 응답을 제공하는 것이 당신의 역할입니다."""
results = []
for image_path in image_paths:
print(image_path)
image = Image.open(image_path).convert('RGB')
instruction = '이미지에 대해서 설명해주세요.'
messages = [
{'role': 'system', 'content': f"{PROMPT}"},
{'role': 'user', 'content': f"<image>\n{instruction}"}
]
chat_messages = processor.tokenizer.apply_chat_template(
messages,
tokenize=False,
add_generation_prompt=True
)
inputs = processor(
chat_messages,
image,
return_tensors='pt',
).to(model.device)
output = model.generate(
**inputs,
max_new_tokens=1024,
)
analysis = processor.tokenizer.decode(output[0], skip_special_tokens=True)
results.append(analysis)
print(f"{image_path} 분석 완료: {analysis}")
return results
4. 최종 테스트
앞서 작성한 모든 코드는 다음과 같습니다.
import os
from comtypes import client
from pdf2image import convert_from_path
from PIL import Image
from transformers import LlavaNextForConditionalGeneration, LlavaNextProcessor
import torch
from pdf2image.exceptions import PDFInfoNotInstalledError, PDFPageCountError
def ppt_to_pdf(ppt_path, pdf_path):
"""
PPT 파일을 PDF로 변환하는 함수
:param ppt_path: PPT 파일 경로
:param pdf_path: 저장할 PDF 파일 경로
"""
powerpoint = client.CreateObject("Powerpoint.Application")
powerpoint.Visible = 1
print(ppt_path)
presentation = powerpoint.Presentations.Open(ppt_path)
presentation.SaveAs(pdf_path, 32) # 32는 PDF 형식을 나타냅니다
presentation.Close()
powerpoint.Quit()
print(f"PPT 파일이 {pdf_path}로 변환되었습니다.")
def pdf_to_images(pdf_path, output_folder):
"""
PDF 파일을 1장씩 이미지로 저장하는 함수
:param pdf_path: PDF 파일 경로
:param output_folder: 이미지를 저장할 폴더 경로
:return: 저장된 이미지 파일 경로 리스트
"""
if not os.path.exists(output_folder):
os.makedirs(output_folder)
poppler_bin_path = r"D:\Library\poppler-24.07.0\Library\bin"
if os.path.exists(poppler_bin_path):
print("Poppler 경로가 정확합니다.")
else:
print("Poppler 경로가 잘못되었습니다.")
try:
images = convert_from_path(pdf_path, poppler_path=poppler_bin_path)
image_paths = []
for i, image in enumerate(images):
image_path = os.path.join(output_folder, f"page_{i+1}.png")
image.save(image_path, "PNG")
image_paths.append(image_path)
print(f"{len(image_paths)}개의 이미지가 {output_folder}에 저장되었습니다.")
return image_paths
except PDFInfoNotInstalledError:
print("Poppler가 설치되지 않았거나 PATH에 추가되지 않았습니다.")
except PDFPageCountError:
print("PDF 페이지 수를 확인할 수 없습니다. PDF 파일이 손상되었을 수 있습니다.")
except Exception as e:
print(f"이미지 추출 중 오류 발생: {str(e)}")
return []
def analyze_images_with_vl_model(image_paths):
"""
이미지를 Vision-Language 모델을 이용해 분석하는 함수
:param image_paths: 분석할 이미지 파일 경로 리스트
:return: 각 이미지에 대한 분석 결과 리스트
"""
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model = LlavaNextForConditionalGeneration.from_pretrained(
'Bllossom/llama-3.1-Korean-Bllossom-Vision-8B',
)
model = model.half() # FP16 양자화
model = model.half()
model = model.to(device)
processor = LlavaNextProcessor.from_pretrained('Bllossom/llama-3.1-Korean-Bllossom-Vision-8B')
PROMPT = """You are a versatile AI assistant named Bllava, capable of both understanding and generating text as well as interpreting and analyzing images. Your role is to kindly and effectively answer the user's questions, whether they are about text or images, and provide appropriate and helpful responses to all types of queries.
당신은 텍스트를 이해하고 생성하는 것뿐만 아니라 이미지를 해석하고 분석할 수 있는 다재다능한 AI 어시스턴트 블라바입니다. 사용자의 질문이 텍스트에 관한 것이든 이미지에 관한 것이든 친절하고 효과적으로 답변하며, 모든 유형의 질의에 대해 적절하고 유용한 응답을 제공하는 것이 당신의 역할입니다."""
results = []
for image_path in image_paths:
print(image_path)
image = Image.open(image_path).convert('RGB')
instruction = '이미지에 대해서 설명해주세요.'
messages = [
{'role': 'system', 'content': f"{PROMPT}"},
{'role': 'user', 'content': f"<image>\n{instruction}"}
]
chat_messages = processor.tokenizer.apply_chat_template(
messages,
tokenize=False,
add_generation_prompt=True
)
inputs = processor(
chat_messages,
image,
return_tensors='pt',
).to(model.device)
output = model.generate(
**inputs,
max_new_tokens=1024,
)
analysis = processor.tokenizer.decode(output[0], skip_special_tokens=True)
results.append(analysis)
print(f"{image_path} 분석 완료: {analysis}")
return results
위 함수들을 순차적으로 실행하는 예제는 다음과 같습니다.
ppt_path = 'test.pptx'
pdf_path = 'test.pdf'
output_folder = 'test/image_output/'
ppt_to_pdf(ppt_path, pdf_path)
pdf_to_images(pdf_path, output_folder)
image_paths = [os.path.join(output_folder, f) for f in os.listdir(output_folder) if f.endswith('.png')]
analysis_results = analyze_images_with_vl_model(image_paths)
테스트에 사용된 슬라이드 이미지는 다음과 같습니다.
이를 Bllossom/llama-3.1-Korean-Bllossom-Vision-8B 모델에 이해시킨 결과는 다음과 같습니다.
이미지는 축구에 대한 광고를 나타내는 광고입니다. 축구 유니폼을 입은 여성이 있는 광고 포스터가 있습니다. 여성은 축구 골대 앞에 서 있으며 배경에는 축구장의 일부로 보이는 잔디밭이 있습니다.
5. 결론
이 프로젝트를 통해 우리는 PPT 슬라이드를 자동으로 분석하는 과정을 구현했습니다. 이 과정은 크게 세 단계로 나눌 수 있습니다: 1.PPT를 PDF로 변환, 2.PDF를 이미지로 변환, 3.Vision-Language 모델을 이용한 이미지 해석입니다.
이 토이 프로젝트는 AI 기술을 실제 업무에 적용하는 좋은 예시가 될 수 있습니다. 앞으로 더욱 발전하는 VL 모델들을 적절히 활용한다면, 문서 분석과 정보 추출 분야에서 좋은 성능을 보일 수 있을 것이라고 생각합니다. 업무 효율성 향상과 새로운 인사이트 도출에 크게 기여할 수 있을 것으로도 기대합니다.
'개발 > AI' 카테고리의 다른 글
헬스케어 질의 응답이 가능한 sLLM 파인튜닝하기 (2) | 2024.10.17 |
---|---|
Llama-3.2-1B-Instruction 모델 파인튜닝하기 (4) | 2024.10.02 |
[공부] 한국어 벡터 임베딩 (0) | 2024.08.14 |
[공부] RAG를 위한 벡터 임베딩 (0) | 2024.08.13 |
[공부] RAG 개념 (1) | 2024.08.12 |