O que vamos fazer aqui?Extraindo conteúdo de arquivos TXT e MarkdownExtraindo texto de arquivos PDF (extract_pdf)Extraindo texto de arquivos DOCX (extract_docx)Extraindo texto de arquivos HTML (extract_html)Despachando a extração de texto de forma segura no pipeline RAG
No RAG, você nunca embeda arquivos (.pdf, .docx, etc.).
Você embeda texto puro.
Portanto, antes de chunking e embeddings, precisamos:
- Abrir o arquivo físico
- Extrair o texto corretamente (dependendo do tipo)
- Retornar texto limpo
⚠️ Garantir que nenhum dado de outro usuário entre no processo
Aqui nós vamos criar o arquivo rag/services/extraction.py que vai ter as seguintes funções:
extract_txt(path)extract_md(path)
Essas funções servem para ler o conteúdo de arquivos de texto simples (.txt e .md) e retornar todo o texto em formato de string, já pronto para ser processado em etapas seguintes do pipeline (como chunking e geração de embeddings).
Vamos começar definindo a função extract_txt(path: Path):
def extract_txt(path: Path) -> str:
...- 🔹 O que essa função faz?
- Lê todo o conteúdo de um arquivo
.txt - Retorna esse conteúdo como texto puro
- Lê todo o conteúdo de um arquivo
- 🔹 Quais parâmetros ela recebe?
- path (obrigatório)
- Tipo: Path (pathlib.Path)
- Representa o caminho físico do arquivo no sistema
- path (obrigatório)
- 🔹 O que ela retorna?
- Tipo:
str - Uma string contendo todo o texto do arquivo
- Tipo:
Continuando, agora nós vamos retornar esse texto:
from pathlib import Path
def extract_txt(path: Path) -> str:
return path.read_text(
encoding="utf-8",
errors="ignore"
)- 🔹 O que esse bloco faz?
- Abre o arquivo apontado por
path - Lê todo o conteúdo como texto
- Retorna o texto imediatamente
- Abre o arquivo apontado por
Seguindo a mesma lógica agora vamos implementar a função extract_md(path: Path):
def extract_md(path: Path) -> str:
return path.read_text(
encoding="utf-8",
errors="ignore"
)A função
extract_pdf()é responsável por ler um arquivo PDF página por página e extrair todo o texto possível, retornando esse conteúdo como uma única string.
NOTE:
Ela é usada no pipeline RAG quando o tipo de arquivo identificado é .pdf, permitindo que documentos PDF — que não são texto puro — possam ser transformados em texto indexável.
Porém, antes de começar a implementar essa função, primeiro nós vamos instalar a biblioteca pdfplumber:
poetry add pdfplumber@latestAgora, vamos atualizar os arquivos de dependências:
task exportdevtask exportprodÓtimo, agora partindo para a implementação vamos importar a biblioteca pdfplumber e definir a função extract_pdf(path: Path):
import pdfplumber
def extract_pdf(path):
...Continuando, agora nós vamos criar uma lista vazia para armazenar os textos das páginas:
def extract_pdf(path):
text_parts = []- 🔹 O que isso faz?
- Cria uma lista vazia para armazenar:
- o texto extraído de cada página
- Cria uma lista vazia para armazenar:
- 🔹 Por que usar uma lista?
- Strings são imutáveis em Python
- Acumular em
lista + join()é:- mais eficiente
- mais limpo
- mais performático
Agora, nós vamos utilizar pdfplumber.open(path) com with para abrir o PDF:
def extract_pdf(path):
text_parts = []
with pdfplumber.open(path) as pdf:
...- 🔹 O que isso faz?
- Abre o arquivo PDF usando um context manager
- Garante que o arquivo será fechado corretamente
- Função utilizada:
pdfplumber.open(path)- O que faz?
- Abre um arquivo PDF para leitura
- Quais parâmetros recebe?
path- Caminho do arquivo PDF
- O que retorna?
- Um objeto PDF do pdfplumber
- O que faz?
Ótimo, sabendo que dentro desse bloco (with) nós teremos o PDF aberto, vamos iterar página por página:
def extract_pdf(path):
...
with pdfplumber.open(path) as pdf:
for page in pdf.pages:- 🔹 O que isso faz?
- Percorre todas as páginas do PDF
- 🔹 Atributo utilizado:
pdf.pages- O que é?
- Uma lista de objetos
Page - Cada
Pagerepresenta:- uma página individual do PDF
- Uma lista de objetos
- O que é?
Mas o que fazer em cada página lida?
Então, em cada página nós vamos:
- Extrair o texto da página atual:
page_text = page.extract_text()
- Verificar se o texto extraído tem conteúdo, ou seja é diferente de
None:if page_text- Se ele for
True, então adicionar o conteúdo na lista:text_parts.append(page_text)
- Se
page_textforNone, não adicionaremos nada na listatext_parts.
- Se ele for
Nosso código ficará assim:
def extract_pdf(path):
text_parts = []
with pdfplumber.open(path) as pdf:
for page in pdf.pages:
page_text = page.extract_text()
if page_text:
text_parts.append(page_text)Por fim, vamos retornar nossa lista, porém, juntando todos os textos das páginas separando por uma quebra de linha (\n):
def extract_pdf(path):
...
return "\n".join(text_parts)A função
extract_docx()é responsável por ler documentos do Microsoft Word (.docx) e extrair todo o texto contido nos parágrafos, retornando esse conteúdo como uma string única.
NOTE:
Ela permite que arquivos .docx, muito comuns em ambientes corporativos, possam ser indexados e utilizados no pipeline RAG, assim como PDFs e arquivos de texto.
Porém, antes de começar a implementar essa função, primeiro nós vamos instalar a biblioteca python-docx:
poetry add python-docx@latestAgora, vamos atualizar os arquivos de dependências:
task exportdevtask exportprodÓtimo, agora partindo para a implementação vamos importar o módulo Document e definir a função extract_docx(path):
def extract_docx(path):- 🔹 O que essa função faz?
- Abre um arquivo
.docx - Extrai o texto de todos os parágrafos
- Ignora parágrafos vazios
- Retorna o texto consolidado
- Abre um arquivo
- 🔹 O que ela retorna?
- Uma
strcom todo o texto do documento - Cada parágrafo separado por uma quebra de linha
(\n)
- Uma
Agora, nós vamos utilizar a função Document(path) para abrir o documento:
def extract_docx(path):
"""Extract text from a DOCX file."""
document = Document(path)- 🔹 O que essa linha faz?
- Carrega o arquivo
.docxem memória
- Carrega o arquivo
- 🔹 Função utilizada:
Document()- O que faz?
- Abre e interpreta um arquivo
.docx
- Abre e interpreta um arquivo
- Quais parâmetros recebe?
path- Caminho do arquivo
- O que retorna?
- Um objeto
Document, representando o documento Word
- Um objeto
- O que faz?
Continuando, agora nós vamos criar uma list comprehension para:
- Percorre todos os parágrafos do documento
- Extrai apenas o texto (
p.text) - Ignora parágrafos vazios
def extract_docx(path):
"""Extract text from a DOCX file."""
document = Document(path)
paragraphs = [p.text for p in document.paragraphs if p.text]Por fim, nós vamos juntar todos os parágrafos em uma string, separando-os por uma quebra de linha (\n) e enviar como retorno:
def extract_docx(path):
"""Extract text from a DOCX file."""
document = Document(path)
paragraphs = [p.text for p in document.paragraphs if p.text]
return "\n".join(paragraphs)A função
extract_html()é responsável por ler um arquivo HTML, remover elementos que não representam conteúdo textual relevante (como scripts e estilos) e extrair apenas o texto visível, retornando tudo como uma string limpa.
Porém, antes de começar a implementar essa função, primeiro nós vamos instalar a biblioteca beautifulsoup4:
poetry add beautifulsoup4@latestAgora, vamos atualizar os arquivos de dependências:
task exportdevtask exportprodÓtimo, agora partindo para a implementação vamos importar a biblioteca BeautifulSoup e definir a função extract_html(path: Path):
from bs4 import BeautifulSoup
def extract_html(path):
...Continuando, agora nós vamos ler todo o arquivo HTML como texto e ignorar caracteres inválidos:
def extract_html(path):
html = path.read_text(
encoding="utf-8",
errors="ignore"
)- 🔹 Função utilizada:
Path.read_text()- O que faz?
- Lê o conteúdo de um arquivo de texto
- Quais parâmetros recebe?
encoding="utf-8"- Codificaçãoerrors="ignore"- Ignora erros
- O que retorna?
- Uma
strcom o conteúdo do arquivo
- Uma
- O que faz?
NOTE:
📌 Essa abordagem garante robustez contra HTMLs malformados ou com encoding inconsistente.
Continuando, agora nós vamos converter o HTML em um objeto BeautifulSoup, que nada mais é que uma estrutura navegável de elementos HTML:
def extract_html(path):
...
soup = BeautifulSoup(
html,
"html.parser"
)- 🔹 Função utilizada:
BeautifulSoup()- O que faz?
- Analisa o HTML e cria uma árvore de nós
- Quais parâmetros recebe?
markup (str)→ HTML brutoparser (str)→ "html.parser"
- O que retorna?
- Um objeto BeautifulSoup
- O que faz?
Agora, nós vamos remover tags HTML que nós consideramos irrelevantes, como scripts e estilos:
def extract_html(path):
...
for tag in soup(["script", "style"]):
tag.decompose()- 🔹 O que esse bloco faz?
- Localiza todas as tags
<script>e<style> - Remove completamente essas tags da árvore
- Localiza todas as tags
soup(["script", "style"])- O que faz?
- Busca todas as tags com esses nomes
- Quais parâmetros recebe?
- Uma lista de nomes de tags
- O que retorna?
- Uma lista de elementos encontrados
- O que faz?
tag.decompose()- O que faz?
- Remove a tag e todo o seu conteúdo da árvore
- Quais parâmetros recebe?
- Nenhum
- O que retorna?
None
- O que faz?
NOTE:
📌 Isso evita que códigos JavaScript, regras de CSS entrem no texto indexado.
Agora, nós vamos:
- Extrair todo o texto visível do HTML
- Separar por blocos de texto com quebras de linha (
\n) - Por fim, enviar como retorno da função
def extract_html(path):
...
return soup.get_text(separator="\n")- 🔹 Função utilizada:
soup.get_text()- O que faz?
- Coleta todo o texto da árvore HTML
- Quais parâmetros recebe?
separator="\n"- Define como os blocos de texto serão separados
- O que retorna?
- Uma
strcom o texto final
- Uma
- O que faz?
A função
extract_text()é o ponto central de extração de conteúdo textual no pipeline RAG.
- Ela recebe um arquivo já autorizado
- Decide qual extractor usar com base no tipo do arquivo
- Devolve o texto bruto pronto para chunking e embeddings.
Vamos começar:
- Definindo uma função chamada
extract_text() - Importando os módulos/funções que vamos usar
from pathlib import Path
def extract_text(file_info):
...Agora, nós vamos converter o caminho absoluto (string) do arquivo recebido (file_info) em um objeto Path que irá facilitar operações de leitura de arquivos:
def extract_text(file_info):
file_path = Path(file_info["absolute_path"])- 🔹 Função utilizada:
Path()- O que faz?
- Cria um objeto de caminho de arquivo
- Quais parâmetros recebe?
- Uma string representando o caminho
- O que retorna?
- Um objeto
pathlib.Path
- Um objeto
- O que faz?
Agora, nós vamos pegar a extensão do arquivo:
NOTE:
📌 Essa padronização foi garantida anteriormente porget_file_type().
def extract_text(file_info):
...
file_type = file_info["file_type"]Agora, nós vamos criar vários ifs (dispatcher) para decidir qual tipo de arquivo vamos extrair:
def extract_text(file_info):
...
if file_type == ".txt":
return extract_txt(file_path)
if file_type == ".pdf":
return extract_pdf(file_path)
if file_type == ".docx":
return extract_docx(file_path)
if file_type == ".md":
return extract_md(file_path)
if file_type == ".html":
return extract_html(file_path)E se for passado um tipo que nós não validamos ainda?
Nesse, caso nós vamos precisar lançar uma exceção para isso:
def extract_text(file_info):
...
raise ValueError(f"Tipo de arquivo não suportado: {file_type}")- 🔹 O que isso faz?
- Interrompe a execução se o tipo não for reconhecido
- Evita:
- comportamentos inesperados
- leitura de formatos não previstos
Rodrigo Leite da Silva - rodrigols89