Sistema de Transformação de Documentos Não Estruturados em Vetores com GTE-Base-ZH

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.

Tags: gte-base-zh Sentence-Transformers processamento-de-documentos embeddings python-docx

Publicado em 8-8 22:10