Tutoriais Técnicos com Código e Implementação
Guias passo a passo com código-fonte para implementar automações reais na sua empresa.
Automatizar a Extração de Faturas em PDF com Make e um Modelo de Visão
Do email à folha de cálculo, com validação antes de gravar: aritmética, dígito de controlo do NIF e deteção de duplicados. O que falhar vai para revisão humana.
1Perceber o que realmente vai processar
Antes de ligar seja o que for, junta trinta faturas reais que tenhas recebido no último mês e olha para elas. É o passo que quase toda a gente salta, e é o que decide se isto funciona. Repara em: quantos fornecedores diferentes há, se cada um usa um modelo próprio, se há faturas digitalizadas em vez de PDF nativo, e se alguma tem várias páginas ou várias moedas. Se forem cinco fornecedores com modelos estáveis, isto corre bem. Se forem quarenta fornecedores, metade em papel digitalizado torto, conta com bastante mais trabalho — e talvez com processar apenas os cinco maiores, que costumam ser 80% do volume.
2Receber as faturas num sítio só
Cria um endereço dedicado — por exemplo `faturas@` — e pede aos fornecedores que enviem para lá. Um filtro que reencaminhe para esse endereço resolve os que continuarem a enviar para o teu email pessoal. No Make, o gatilho é o módulo de email a observar essa caixa, ou o Google Drive a observar uma pasta. Prefere o email: elimina o passo manual de guardar o anexo. Guarda o ficheiro original antes de o processar. Vais precisar dele quando algo correr mal, e a legislação de arquivo em Espanha e Portugal exige conservar o documento, não só os dados extraídos.
3Extrair os campos com um modelo de visão
É aqui que um modelo de linguagem com visão faz o que regras não fazem: lê layouts que nunca viu. Mas só funciona se lhe pedires um formato rígido. Dois cuidados que evitam a maior parte dos problemas. Primeiro, pede JSON com um esquema fixo e diz explicitamente o que fazer quando um campo não existe — sem isso, o modelo inventa. Segundo, põe a temperatura a zero: queres a mesma resposta para a mesma fatura, não criatividade. O prompt abaixo é deliberadamente restritivo. A tentação é pedir "extrai os dados da fatura"; o resultado é inconsistente entre execuções.
{
"model": "gpt-4o",
"temperature": 0,
"response_format": { "type": "json_object" },
"messages": [
{
"role": "system",
"content": "Extrais dados de faturas. Devolves APENAS JSON com este esquema exacto. Quando um campo não existir no documento, devolve null — nunca inventes nem estimes. Valores numéricos sem símbolo de moeda, ponto como separador decimal. Datas em ISO 8601."
},
{
"role": "user",
"content": [
{ "type": "text", "text": "Esquema: {numero_fatura, data_emissao, data_vencimento, fornecedor_nome, fornecedor_nif, base_tributavel, taxa_iva, valor_iva, total, moeda}" },
{ "type": "image_url", "image_url": { "url": "data:application/pdf;base64,{{1.data}}" } }
]
}
]
}4Validar antes de gravar
Nunca gravar o que o modelo devolve sem verificar. Três validações apanham quase tudo. **A aritmética fecha?** Base tributável mais IVA tem de dar o total. Se não der, algum campo foi mal lido. **O NIF é válido?** Tanto o NIF espanhol como o português têm dígito de controlo calculável. Verificá-lo apanha erros de leitura em segundos. **A fatura já foi processada?** O número mais o NIF do fornecedor formam uma chave única. Sem esta verificação, um reenvio do fornecedor duplica o lançamento. O que falhar a validação não é descartado: vai para uma folha separada, para revisão humana. Automatizar não é decidir sem supervisão.
// Módulo de código no fluxo, entre a extracção e a gravação.
const f = JSON.parse(input.jsonDoModelo);
const erros = [];
// 1. A aritmética tem de fechar, com tolerância para arredondamento.
const somado = Number(f.base_tributavel) + Number(f.valor_iva);
if (Math.abs(somado - Number(f.total)) > 0.02) {
erros.push(`total nao bate: ${somado.toFixed(2)} vs ${f.total}`);
}
// 2. Dígito de controlo do NIF espanhol (8 dígitos + letra).
function nifEspanholValido(nif) {
const m = /^(\d{8})([A-Z])$/.exec((nif || '').toUpperCase().trim());
if (!m) return false;
return 'TRWAGMYFPDXBNJZSQVHLCKE'[Number(m[1]) % 23] === m[2];
}
// 3. Campos que nunca podem vir nulos.
for (const campo of ['numero_fatura', 'data_emissao', 'total']) {
if (f[campo] == null) erros.push(`campo em falta: ${campo}`);
}
return { valida: erros.length === 0, erros, dados: f };5Gravar, arquivar e avisar
O destino depende do que já usas. Uma folha de cálculo chega para começar e é mais fácil de auditar do que parece; um sistema de faturação evita o lançamento manual depois. Seja qual for, grava também a ligação ao ficheiro original e a data em que foi processado. Quando alguém perguntar de onde veio um valor daqui a seis meses, é isso que responde. E põe notificação de falha desde o primeiro dia. Um fluxo que falha em silêncio é pior que não ter fluxo nenhum: continuas a acreditar que as faturas estão a ser processadas enquanto deixaram de ser.
6Medir se valeu a pena
Ao fim de um mês, compara com o que mediste antes de começar: quantas faturas entraram, quantas passaram sem intervenção, quantas foram para revisão, e quanto tempo demorou a revisão. Um fluxo que processa 70% sem intervenção já poupa tempo real. Um que manda metade para revisão está a mudar o trabalho de sítio, não a reduzi-lo — e nesse caso o problema está quase sempre nos fornecedores com layouts instáveis, que vale a pena tratar à parte. O custo do modelo por fatura processada é pequeno comparado com o tempo humano, mas confirma-o com a tua fatura do fornecedor, não com estimativas.