Construir um sistema para converter documentos como Word ou PDF em representações vetoriais que inteligência artificial compreende é um desafio comum. Modelos de linguagem não interpretam formatos binários brutos de forma eficiente. Este guia apresenta um sistema completo para processar documentos, extrair texto limpo e gerar embeddings semânticos utilizando o modelo gte-base-zh.
Preparação do Ambiente e Biblioteacs
Primeiro, configure o ambiente Python com as dependências necessárias. Crie um diretório chamado source_docs para armazenar seus arquivos .docx e .pdf.
pip install python-docx PyPDF2 sentence-transformers
O python-docx manipula documentos Word, o PyPDF2 lê PDFs, e o sentence-transformers fornece a infraestrutura para modelos de embeddings, incluindo o gte-base-zh. Este modelo é otimizado para chinês e gera vetores de 768 dimensões que capturam o significado semântico do texto.
Módulo de Extração de Texto
Crie funções para extrair texto de diferentes formatos.
from docx import Document
import PyPDF2
import os
def read_docx_content(path):
"""Extrai parágrafos de um arquivo .docx."""
try:
doc = Document(path)
content_parts = [p.text for p in doc.paragraphs if p.text.strip()]
return " ".join(content_parts)
except Exception as err:
print(f"Falha ao processar {path}: {err}")
return ""
def read_pdf_content(path):
"""Extrai texto de todas as páginas de um PDF."""
text_buffer = ""
try:
with open(path, "rb") as pdf_file:
reader = PyPDF2.PdfReader(pdf_file)
for page in reader.pages:
extracted = page.extract_text()
if extracted:
text_buffer += extracted + " "
except Exception as err:
print(f"Erro no PDF {path}: {err}")
return text_buffer
def process_single_document(doc_path):
"""Roteador que chama a função de extração adequada."""
file_extension = os.path.splitext(doc_path)[1].lower()
if file_extension == ".docx":
return read_docx_content(doc_path)
elif file_extension == ".pdf":
return read_pdf_content(doc_path)
return ""
Etapa de Limpeza e Segmentação do Texto
O textto bruto precisa ser normalizado e dividido em trechos gerenciáveis para o modelo.
import re
def sanitize_text(raw_text):
"""Remove caracteres especiais e normaliza espaços em branco."""
if not raw_text:
return ""
cleaned = re.sub(r'[\x00-\x1f\x7f-\x9f]', '', raw_text)
cleaned = re.sub(r'\s+', ' ', cleaned).strip()
return cleaned
def chunk_text_semantically(text, max_chars=512, overlap_chars=50):
"""Divide o texto em segmentos, preservando frases quando possível."""
if len(text) <= max_chars:
return [text]
# Divide por sentenças primeiro
sentences = re.split(r'(?<=[。!?;\.\?!;])', text)
chunks = []
current_chunk = ""
for sentence in sentences:
sentence = sentence.strip()
if not sentence:
continue
if len(current_chunk) + len(sentence) <= max_chars:
current_chunk += sentence + " "
else:
if current_chunk:
chunks.append(current_chunk.strip())
# Inicia novo chunk com sobreposição do anterior
overlap_text = current_chunk[-overlap_chars:] if overlap_chars > 0 else ""
current_chunk = overlap_text + sentence + " "
if current_chunk:
chunks.append(current_chunk.strip())
return chunks if chunks else [text[:max_chars]]
def prepare_document_chunks(folder_path):
"""Processa todos os documentos em uma pasta e retorna chunks limpos."""
all_chunks = []
metadata = []
for filename in os.listdir(folder_path):
full_path = os.path.join(folder_path, filename)
if not os.path.isfile(full_path):
continue
ext = os.path.splitext(filename)[1].lower()
if ext not in ['.docx', '.pdf']:
continue
print(f"Processando: {filename}")
raw_text = process_single_document(full_path)
clean_text = sanitize_text(raw_text)
document_chunks = chunk_text_semantic(clean_text)
for idx, chunk in enumerate(document_chunks):
all_chunks.append(chunk)
metadata.append({
"file": filename,
"chunk_id": idx,
"length": len(chunk)
})
print(f"Total de chunks gerados: {len(all_chunks)}")
return all_chunks, metadata
Geração de Embeddings com GTE-Base-ZH
Com os chunks preparados, use o modelo gte-base-zh para convertê-los em representações vetoriais.
from sentence_transformers import SentenceTransformer
import numpy as np
def compute_text_embeddings(text_list, model_identifier="thenlper/gte-base-zh"):
"""Converte uma lista de strings em um array numpy de embeddings."""
device = "cuda" if torch.cuda.is_available() else "cpu"
print(f"Dispositivo de computação: {device}")
transformer_model = SentenceTransformer(model_identifier, device=device)
# O método encode processa em lotes e normaliza automaticamente
vector_matrix = transformer_model.encode(
text_list,
batch_size=64,
show_progress_bar=True,
convert_to_numpy=True,
normalize_embeddings=True
)
print(f"Dimensão dos embeddings: {vector_matrix.shape}")
return vector_matrix
Execução do Sistema Completo
Integre todos os componentes em um fluxo contínuo que gera os artefatos finais.
import pickle
def run_document_conversion_pipeline(input_dir, output_prefix="doc_vectors"):
"""Pipeline principal que orquestra todo o processo."""
# Etapa 1: Preparar chunks dos documentos
print("Fase 1: Extração e segmentação")
doc_chunks, chunk_info = prepare_document_chunks(input_dir)
if not doc_chunks:
print("Nenhum conteúdo extraído. Verifique os documentos de entrada.")
return
# Etapa 2: Gerar vetores
print("\nFase 2: Geração de embeddings")
embeddings_array = compute_text_embeddings(doc_chunks)
# Etapa 3: Salvar resultados
print("\nFase 3: Persistência dos dados")
# Salva os chunks e metadados
chunks_path = f"{output_prefix}_chunks.pkl"
with open(chunks_path, "wb") as f:
pickle.dump({"texts": doc_chunks, "info": chunk_info}, f)
# Salva os vetores
vectors_path = f"{output_prefix}_vectors.npy"
np.save(vectors_path, embeddings_array)
print(f"Arquivos gerados:")
print(f" - {chunks_path}")
print(f" - {vectors_path}")
return embeddings_array, chunk_info
# Configuração e execução
DOCUMENT_FOLDER = "source_docs"
if __name__ == "__main__":
vectors, metadata = run_document_conversion_pipeline(DOCUMENT_FOLDER)
# Exemplo de como carregar e usar os resultados
loaded_vectors = np.load("doc_vectors_vectors.npy")
print(f"Vetores carregados com shape: {loaded_vectors.shape}")
Aplicações dos Vetores Resultantes
Os vetores gerados podem ser utilizados em diversos cenários de inteligência artificial. Para busca semântica, calcule a similaridade de cosseno entre o vetor de uma consulta e os vetores dos chunks para recuperar trechos relevantes. Esses embeddings também podem ser indexados em bancos de dados vetoriais como Pinecone ou Milvus para consultas eficientes em larga escala. Em sistemas RAG (Geração Aumentada por Recuperação), os chunks mais relevantes fornecem contexto preciso para modelos de linguagem, reduzindo alucinações e melhorando a factualidade das respostas.
A arquitetura modular deste sistema permite extensões, como suporte a formatos adicionais (PPTX, TXT), uso de segmentadores baseados em NLP para fronteiras semânticas mais precisas, ou experimentação com diferentes modelos de embeddings conforme a aplicação específica.