A otimização de processos que envolvem a análise de documentos complexos e a subsequente interação com assistentes de inteligência artificial é um desafio comum em muitos ambientes de trabalho. O cenário tradicional de manipulação manual de informações, extração de dados e reintrodução em sistemas de IA pode ser demorado e propenso a erros. Este artigo explora como a integração de ferramentas especializadas em compreensão documental, como o Youtu-Parsing, com assistentes de IA, exemplificado pelo Nanbeige (operando na porta 7861), pode revolucionar essa dinâmica, criando um fluxo de trabalho automatizado e altamente eficiente.
- A Base: Ferramentas Essenciais para Automação
1.1. Youtu-Parsing: Compreensão Multimodal de Documentos
O Youtu-Parsing transcende a funcionalidade de um simples sistema OCR (Reconhecimento Óptico de Caracteres). Ele atua como um motor avançado de compreensão documental multimodal, capaz de interpretar uma vasta gama de formatos e elementos presentes em documentos. Sua principal capacidade é transformar dados visuais não estruturados em informações que podem ser processadas e compreendidas por máquinas.
Principais Atributos:
- Análise Holística de Conteúdo: Identifica e extrai texto, tabelas, fórmulas matemáticas, gráficos, selos e até mesmo escrita manual.
- Localização Precisa: Fornece coordenadas exatas para cada elemento reconhecido na imagem, permitindo contextualização espacial.
- Saída Estruturada: Converte o conteúdo em formatos como Markdown ou JSON, ideais para sistemas de Geração Aumentada por Recuperação (RAG) e outros modelos de IA.
- Processamento Otimizado: Utiliza técnicas de paralelização para acelerar a análise, superando métodos convencionais.
Após a configuração, o acesso via navegador (geralmente em
http://seu_servidor_IP:7860) revela uma interface intuitiva. É possível carregar imagens individualmente, arrastar e soltar arquivos, ou até mesmo colar do clipboard. Para processamento em massa, a plataforma suporta o upload de múltiplos documentos simultaneamente, consolidando os resultados.
1.2. Nanbeige: O Assistente de IA Flexível
O Nanbeige, acessível na porta 7861, é um assistente de IA robusto, projetado para uma variedade de tarefas como geração de texto, desenvolvimento de código e análise de dados. Sua eficácia é, no entanto, limitada quando se trata de documentos em formatos não estruturados, como PDFs brutos ou imagens sem tratamento prévio. Nesses casos, a extração de tabelas pode resultar em dados ilegíveis, gráficos são igonrados e fórmulas matemáticas permanecem não reconhecidas. É precisamente aqui que o Youtu-Parsing agrega valor crítico, fornecendo dados estruturados que o Nanbeige pode consumir e processar eficientemente.
- Arquitetando a Integração: Um Fluxo de Trabalho Coeso
A meta é criar um pipeline onde o Youtu-Parsing e o Nanbeige trabalhem em conjunto, transformando um documento visual em uma análise inteligente.
Documento (Imagem/PDF) → Youtu-Parsing (Análise e Estruturação) → Dados Estruturados → Nanbeige (Processamento AI) → Resultado Final
Nesse modelo, o Youtu-Parsing converte a informação visual em Markdown ou JSON, que é então alimentada ao Nanbeige para tarefas como sumarização, análise profunda ou geração de respostas a perguntas.
- Implementação Prática: Construindo o Sistema Integrado
3.1. Preparação do Ambiente
Certifique-se de que ambos os serviços estão ativos e operacionais. Um comando de verificação pode ser:
# Status do Youtu-Parsing
sudo systemctl status youtu-parsing # ou supervisorctl status youtu-parsing
# Status do Nanbeige
sudo systemctl status nanbeige # ou supervisorctl status nanbeige
Ambos devem indicar status de RUNNING. O Youtu-Parsing deve estar na porta 7860 e o Nanbeige na 7861.
3.2. Script de Orquestração em Python
Desenvolver um script Python é o meio ideal para coordenar a comunicação entre as duas ferramentas.
import requests
import json
import os
from pathlib import Path
class FluxoDocumentalAI:
def __init__(self, url_analise="http://localhost:7860", url_assistente="http://localhost:7861"):
self.url_analise = url_analise
self.url_assistente = url_assistente
def analisar_documento(self, caminho_imagem):
"""Usa Youtu-Parsing para extrair dados do documento."""
with open(caminho_imagem, 'rb') as arquivo_img:
arquivos = {'file': arquivo_img}
resposta = requests.post(f"{self.url_analise}/parse", files=arquivos)
if resposta.status_code == 200:
return resposta.json()
else:
raise Exception(f"Falha na análise do documento: {resposta.text}")
def processar_com_assistente(self, dados_estruturados, tipo_tarefa="sumarizar"):
"""Envia os dados estruturados ao Nanbeige para processamento."""
instrucoes_tarefa = {
"sumarizar": "Crie um resumo conciso do conteúdo do documento a seguir:\n\n",
"analisar": "Analise os dados e tendências principais neste documento:\n\n",
"questoes": "Com base no documento, prepare-se para responder perguntas:\n\n",
"extrair": "Extraia informações-chave, pontos principais e conclusões do texto:\n\n"
}
conteudo_para_assistente = ""
if isinstance(dados_estruturados, dict) and 'markdown' in dados_estruturados:
conteudo_para_assistente = dados_estruturados['markdown']
else:
conteudo_para_assistente = str(dados_estruturados)
prompt_final = instrucoes_tarefa.get(tipo_tarefa, instrucoes_tarefa["sumarizar"]) + conteudo_para_assistente
# Chamada à API do Nanbeige
carga_util = {
"prompt": prompt_final,
"max_tokens": 1200,
"temperature": 0.6
}
resposta_ai = requests.post(f"{self.url_assistente}/api/generate",
json=carga_util,
headers={"Content-Type": "application/json"})
if resposta_ai.status_code == 200:
return resposta_ai.json().get('response', 'Nenhuma resposta do AI.')
else:
raise Exception(f"Falha no processamento pelo assistente: {resposta_ai.text}")
def executar_pipeline(self, caminho_imagem, tarefa="sumarizar"):
"""Executa a sequência completa de análise e processamento."""
print(f"Iniciando processamento para: {caminho_imagem}")
# Etapa 1: Análise documental
print("1. Analisando documento com Youtu-Parsing...")
dados_processados = self.analisar_documento(caminho_imagem)
print("✓ Análise concluída.")
# Etapa 2: Processamento com assistente AI
print(f"2. Processando com Nanbeige ({tarefa})...")
resultado_ai = self.processar_com_assistente(dados_processados, tarefa)
print("✓ Processamento AI finalizado.")
return {
"dados_brutos_analisados": dados_processados,
"resultado_assistente": resultado_ai
}
if __name__ == "__main__":
processador = FluxoDocumentalAI()
# Exemplo de uso com um único documento
try:
resultado_final = processador.executar_pipeline("documento_exemplo.png", tarefa="sumarizar")
print("\nResultado da Sumarização:\n", resultado_final["resultado_assistente"])
except Exception as e:
print(f"Erro no pipeline: {e}")
# Exemplo de processamento em lote (descomente para usar)
# pasta_documentos = Path("meus_documentos/")
# for arquivo_img in pasta_documentos.glob("*.jpg"):
# print(f"Processando {arquivo_img.name}...")
# processador.executar_pipeline(str(arquivo_img), tarefa="analisar")
3.3. Interface Web Simples com Flask
Para uma interação mais amigável, uma interface web pode ser construída utilizando Flask.
from flask import Flask, render_template, request, jsonify
import requests
import base64
app_integracao = Flask(__name__)
@app_integracao.route('/')
def pagina_inicial():
return render_template('index.html')
@app_integracao.route('/processar_doc', methods=['POST'])
def processar_documento_web():
arquivo_imagem_upload = request.files['documento_usuario']
# Etapa 1: Chamar Youtu-Parsing
arquivos_envio = {'file': (arquivo_imagem_upload.filename, arquivo_imagem_upload.read(), arquivo_imagem_upload.content_type)}
resposta_analise = requests.post('http://localhost:7860/parse', files=arquivos_envio)
if resposta_analise.status_code != 200:
return jsonify({'erro': 'Falha na análise do documento'}), 500
dados_extraidos = resposta_analise.json()
# Etapa 2: Chamar Nanbeige com base na tarefa do usuário
tarefa_selecionada = request.form.get('tarefa_ai', 'sumarizar')
prompts_personalizados = {
'sumarizar': 'Por favor, gere um resumo dos pontos essenciais deste documento:\n\n',
'analisar': 'Analise este documento para identificar dados cruciais e tendências:\n\n',
'questoes': 'Usando o conteúdo abaixo, prepare-se para responder a perguntas:\n\n',
'traduzir': 'Traduza o seguinte documento para português:\n\n'
}
prompt_completo = prompts_personalizados.get(tarefa_selecionada, prompts_personalizados['sumarizar'])
if 'markdown' in dados_extraidos:
prompt_completo += dados_extraidos['markdown']
else:
prompt_completo += str(dados_extraidos)
# Envio para Nanbeige
payload_nanbeige = {
'prompt': prompt_completo,
'max_tokens': 1800,
'temperature': 0.65
}
resposta_assistente = requests.post('http://localhost:7861/api/generate',
json=payload_nanbeige,
headers={'Content-Type': 'application/json'})
if resposta_assistente.status_code == 200:
resultado_final_ai = resposta_assistente.json().get('response', 'Nenhum resultado AI disponível.')
return jsonify({
'sucesso': True,
'conteudo_analisado': dados_extraidos.get('markdown', str(dados_extraidos)),
'resultado_ai': resultado_final_ai,
'tarefa': tarefa_selecionada
})
else:
return jsonify({'erro': 'Falha no processamento pelo assistente de IA'}), 500
if __name__ == '__main__':
app_integracao.run(host='0.0.0.0', port=5000, debug=True)
O template HTML correspondente (templates/index.html) seria:
<html lang="pt-BR">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Plataforma de Documentos Inteligente</title>
<style>
body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; max-width: 1200px; margin: 25px auto; padding: 20px; background-color: #f7f9fc; color: #333; }
h1, h2, h3 { color: #2c3e50; }
.grid-container { display: grid; grid-template-columns: 1fr 1fr; gap: 30px; margin-top: 20px; }
.upload-card, .result-card { background-color: #ffffff; border-radius: 8px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08); padding: 25px; }
.task-options { margin: 20px 0; }
.task-option-item { margin-right: 15px; display: inline-block; }
label { margin-left: 5px; }
input[type="file"] { margin-bottom: 20px; padding: 10px; border: 1px solid #ced4da; border-radius: 4px; display: block; width: calc(100% - 22px); }
button { background-color: #007bff; color: white; padding: 12px 25px; border: none; border-radius: 5px; cursor: pointer; font-size: 16px; transition: background-color 0.3s ease; }
button:hover { background-color: #0056b3; }
.result-display { border: 1px solid #e0e0e0; padding: 15px; margin-top: 20px; min-height: 350px; background-color: #fdfdfe; border-radius: 5px; overflow-y: auto; max-height: 500px; white-space: pre-wrap; word-wrap: break-word; }
.loading-indicator { display: none; text-align: center; margin: 25px; color: #555; }
.error-message { color: red; font-weight: bold; }
</style>
</head>
<body>
<h1>Plataforma Inteligente de Processamento de Documentos</h1>
<p>Carregue um documento e deixe a IA fazer o trabalho pesado de análise.</p>
<div class="grid-container">
<div class="upload-card">
<h2>Carregar Documento</h2>
<form id="uploadFormWeb">
<input type="file" id="documento_usuario" accept="image/*, .pdf" required>
<div class="task-options">
<h3>Selecione a Tarefa de IA:</h3>
<div class="task-option-item">
<input type="radio" id="sumarizar" name="tarefa_ai" value="sumarizar" checked>
<label for="sumarizar">Resumo Documental</label>
</div>
<div class="task-option-item">
<input type="radio" id="analisar" name="tarefa_ai" value="analisar">
<label for="analisar">Análise de Dados</label>
</div>
<div class="task-option-item">
<input type="radio" id="questoes" name="tarefa_ai" value="questoes">
<label for="questoes">Preparar Q&A</label>
</div>
<div class="task-option-item">
<input type="radio" id="traduzir" name="tarefa_ai" value="traduzir">
<label for="traduzir">Tradução</label>
</div>
</div>
<button type="submit">Iniciar Processamento</button>
</form>
<div class="loading-indicator" id="loadingState">
<p>Processando, aguarde...</p>
<p><em>Análise do Documento → Processamento de IA → Geração de Resultado</em></p>
</div>
</div>
<div class="result-card">
<h2>Resultado do Processamento</h2>
<div class="result-display" id="displayArea">
<p>O resultado do processamento aparecerá aqui.</p>
</div>
</div>
</div>
<script>
document.getElementById('uploadFormWeb').addEventListener('submit', async (e) => {
e.preventDefault();
const dadosForm = new FormData();
dadosForm.append('documento_usuario', document.getElementById('documento_usuario').files[0]);
dadosForm.append('tarefa_ai', document.querySelector('input[name="tarefa_ai"]:checked').value);
document.getElementById('loadingState').style.display = 'block';
document.getElementById('displayArea').innerHTML = '<p>Processando...</p>';
try {
const resp = await fetch('/processar_doc', {
method: 'POST',
body: dadosForm
});
const resultadoJson = await resp.json();
if (resultadoJson.sucesso) {
document.getElementById('displayArea').innerHTML = `
<h3>Resultado da IA (${resultadoJson.tarefa}):</h3>
<div style="background: #e9ecef; padding: 15px; border-radius: 5px; margin-bottom: 20px;">
${resultadoJson.resultado_ai.replace(/\n/g, '<br>')}
</div>
<h3>Conteúdo Analisado (Pré-AI):</h3>
<div style="background: #f8f9fa; padding: 15px; border-radius: 5px; max-height: 150px; overflow-y: auto;">
${resultadoJson.conteudo_analisado.substring(0, 1500)}... <!-- Limitar para visualização -->
</div>
`;
} else {
document.getElementById('displayArea').innerHTML = `<p class="error-message">Erro no processamento: ${resultadoJson.erro}</p>`;
}
} catch (error) {
document.getElementById('displayArea').innerHTML = `<p class="error-message">Falha na requisição: ${error.message}</p>`;
} finally {
document.getElementById('loadingState').style.display = 'none';
}
});
</script>
</body>
</html>
- Otimização e Robustez do Sistema
4.1. Processamento Paralelo para Desempenho
Para lidar com grandes volumes de documentos, o processamento em paralelo é crucial. O uso de concurrent.futures em Python permite executar tarefas de análise e IA simultaneamente.
import concurrent.futures
from pathlib import Path
def processar_lote_documentos(pasta_entrada, pasta_saida, numero_workers=4):
"""Processa múltiplos documentos em paralelo."""
pipeline_lote = FluxoDocumentalAI()
arquivos_entrada = list(Path(pasta_entrada).glob("*.jpg")) + \
list(Path(pasta_entrada).glob("*.png")) + \
list(Path(pasta_entrada).glob("*.pdf")) # Adicionando PDFs
print(f"Iniciando processamento em lote para {len(arquivos_entrada)} documentos.")
with concurrent.futures.ThreadPoolExecutor(max_workers=numero_workers) as executor:
tarefas_futuras = {executor.submit(pipeline_lote.executar_pipeline, str(arq), "sumarizar"): arq.name for arq in arquivos_entrada}
for futuro in concurrent.futures.as_completed(tarefas_futuras):
nome_arquivo = tarefas_futuras[futuro]
try:
resultado_lote = futuro.result()
caminho_saida = Path(pasta_saida) / f"{nome_arquivo}_resumo.md"
with open(caminho_saida, 'w', encoding='utf-8') as f_out:
f_out.write(f"# Resumo do Documento: {nome_arquivo}\n\n")
f_out.write(f"## Sumário Gerado por AI\n{resultado_lote['resultado_assistente']}\n\n")
f_out.write(f"## Conteúdo Original Analisado\n{resultado_lote['dados_brutos_analisados'].get('markdown', 'N/A')}")
print(f"✓ Processado e salvo: {nome_arquivo}")
except Exception as e:
print(f"✗ Falha ao processar {nome_arquivo}: {str(e)}")
# Exemplo de uso:
# processar_lote_documentos("docs_para_processar", "resultados_processamento")
4.2. Tratamento de Erros com Retentativas
Para aumentar a robustez do sistema contra falhas temporárias, implementar um mecanismo de retentativa é essencial.
import time
from functools import wraps
def tentar_novamente(max_tentativas=3, atraso_seg=2):
"""Decorador para retentativas em caso de falha."""
def decorador_retentativa(func):
@wraps(func)
def envoltorio(*args, **kwargs):
for tentativa in range(max_tentativas):
try:
return func(*args, **kwargs)
except Exception as ex:
if tentativa == max_tentativas - 1:
raise
print(f"Tentativa {tentativa + 1} falhou, re-tentando em {atraso_seg}s: {str(ex)}")
time.sleep(atraso_seg)
return None # Nunca deve ser alcançado se max_tentativas > 0
return envoltorio
return decorador_retentativa
class PipelineDocumentalRobusto(FluxoDocumentalAI):
@tentar_novamente(max_tentativas=4, atraso_seg=3)
def analisar_documento(self, caminho_imagem):
"""Método de análise com retentativas."""
return super().analisar_documento(caminho_imagem)
@tentar_novamente(max_tentativas=4, atraso_seg=3)
def processar_com_assistente(self, dados_estruturados, tipo_tarefa="sumarizar"):
"""Método de processamento AI com retentativas."""
return super().processar_com_assistente(dados_estruturados, tipo_tarefa)
# Uso: pipeline_robusto = PipelineDocumentalRobusto()
# resultado_confiavel = pipeline_robusto.executar_pipeline("documento_critico.jpg")
4.3. Cache de Resultados para Eficiência
Para evitar reprocessar documentos idênticos, a implementação de um sistema de cache é benéfica.
import hashlib
import pickle
from pathlib import Path
class PipelineDocumentalCache(FluxoDocumentalAI):
def __init__(self, diretorio_cache=".cache_docs", *args, **kwargs):
super().__init__(*args, **kwargs)
self.diretorio_cache = Path(diretorio_cache)
self.diretorio_cache.mkdir(exist_ok=True)
def gerar_chave_cache(self, caminho_arquivo, tarefa_atual):
"""Cria uma chave única para o cache baseada no hash do arquivo e na tarefa."""
with open(caminho_arquivo, 'rb') as f_hash:
hash_arquivo = hashlib.md5(f_hash.read()).hexdigest()
return f"{hash_arquivo}_{tarefa_atual}"
def executar_pipeline(self, caminho_imagem, tarefa="sumarizar"):
"""Executa o pipeline, utilizando cache quando disponível."""
chave_cache = self.gerar_chave_chave(caminho_imagem, tarefa)
arquivo_cache = self.diretorio_cache / f"{chave_cache}.pkl"
if arquivo_cache.exists():
print(f"Carregando resultado do cache para: {caminho_imagem}")
with open(arquivo_cache, 'rb') as f_cache:
return pickle.load(f_cache)
print(f"Processando e armazenando em cache: {caminho_imagem}")
resultado_processamento = super().executar_pipeline(caminho_imagem, tarefa)
with open(arquivo_cache, 'wb') as f_cache:
pickle.dump(resultado_processamento, f_cache)
return resultado_processamento
# Uso: pipeline_cache = PipelineDocumentalCache()
# resultado_cacheado = pipeline_cache.executar_pipeline("relatorio.pdf", tarefa="analisar")
- Cenários de Aplicação
5.1. Pesquisa Acadêmica Acelerada
Ao lidar com vastas quantidades de artigos científicos, a leitura manual para extração de informações pode ser exaustiva. Este sistema permite converter PDFs de pesquisa em imagens, analisá-las em lote com o Youtu-Parsing, e então usar o Nanbeige para gerar resumos e destacar descobertas cruciais em minutos, em vez de horas.
5.2. Análise de Relatórios Financeiros
Relatórios financeiros frequentemente contêm tabelas complexas e gráficos. O sistema pode processar imagens desses relatórios, garantindo que o Youtu-Parsing identifique precisamente todos os dados tabulares, inclusive células mescladas. Com esses dados estruturados, o Nanbeige pode ser solicitado a "avaliar a saúde financeira da empresa e identificar riscos ocultos", fornecendo insights detalhados e apontando anomalias.
5.3. Revisão de Contratos Automatizada
Documentos contratuais longos e detalhados podem ser submetidos à plataforma. O Youtu-Parsing extrairá cláusulas, assinaturas e anotações. O Nanbeige, em seguida, pode sumarizar termos chave, obrigações e direitos. Um pedido como "identifique cláusulas desfavoráveis para o comprador" pode resultar em uma lista precisa de pontos de atenção e sugestões para negociação.