Otimizando o Currículo em Tempo Real: Como Criei um Bot no Telegram com LLMs e Puppeteer
Uma análise sobre arquitetura orientada a eventos, separação de conceitos e otimização de custos usando DeepSeek-v4-Flash e OpenRouter.
Se você está ativamente procurando uma vaga de estágio ou emprego na área de tecnologia, certamente já se deparou com o temido ATS (Applicant Tracking System). Esses sistemas de recrutamento automatizados filtram currículos usando algoritmos de correspondência de palavras-chave e alinhamento semântico com as descrições das vagas. Como estudantes de Engenharia de Computação se aproximando do mercado de trabalho, enfrentamos um duplo problema: os filtros de ATS exigem a personalização do nosso currículo para cada candidatura a fim de destacar as experiências relevantes, mas fazer isso manualmente é uma tarefa exaustiva, demorada e propensa a erros de formatação.
Para automatizar esse pipeline de customização de forma prática, desenvolvi um bot no Telegram em tempo real e orientado a eventos. A ideia arquitetural central é tratar o currículo como um documento JSON estruturado (a camada de dados), a descrição da vaga como texto não estruturado (a camada de consulta) e o PDF de saída como uma visualização compilada (a camada de apresentação). Ao separar essas camadas, criamos um compilador modular e reproduzível que executa a tradução semântica por meio de IA e a compilação do layout via Puppeteer.
Seguindo princípios de arquitetura de software limpa, o projeto construído em TypeScript e Node.js foi estruturado com uma separação clara de responsabilidades no diretório src/. A camada de configurações (src/config.ts) lida com a inicialização dos clientes de API, como o Telegraf para o bot do Telegram e a integração com o gateway do OpenRouter, além de gerenciar as variáveis de ambiente. A camada de serviços é dividida em src/services/ai.ts, que faz a interface com a API de inferência e gerencia as instruções do sistema e esquemas de JSON, e src/services/pdf.ts, que compila os templates HTML/CSS em PDFs e gerencia o ciclo de vida do navegador headless.
Além dos serviços, criamos uma camada de utilitários (src/utils/skills.ts) que recebe as tags brutas e não estruturadas geradas pela LLM e as mapeia para domínios de engenharia pré-definidos, como Linguagens, Bancos de Dados, Backend e DevOps. Para a segurança dos dados, as informações pessoais são separadas no arquivo myResume.json e em um template baseResume.json. Os detalhes do currículo pessoal permanecem no arquivo gitignored, protegendo informações de identificação pessoal (PII) de entrarem no controle de versão e mantendo o código da aplicação modular.
Como o Telegram é uma interface sem estado (stateless), o bot gerencia o progresso da sessão através de um mapa temporário na memória do servidor (userSessions). Quando o usuário envia o comando /adapt [descrição da vaga], o bot salva a descrição e solicita ao usuário que selecione o idioma de destino por meio de botões de teclado inline. Essa máquina de estados mantém o fluxo interativo e extremamente leve, eliminando a necessidade de conexões com banco de dados para sessões de curtíssima duração.
Uma vez disparado o callback do idioma, o serviço de IA monta um prompt estruturado contendo os dados brutos do currículo do usuário e a descrição da vaga, instruindo o modelo a agir como um recrutador experiente de elite. O modelo realiza uma análise de densidade de palavras-chave na descrição da vaga e reformula as realizações profissionais usando o método STAR (Situação, Tarefa, Ação e Resultado), injetando métricas e verbos de ação fortes (como 'otimizou consultas de banco de dados... reduzindo a latência em 50%'). Fundamentalmente, a IA retorna o resultado estritamente no mesmo formato do JSON original, garantindo que possamos analisá-lo com segurança.
O JSON adaptado gerado pelo modelo é então mesclado com as informações de contato básicas — as quais a LLM não tem permissão para alterar para evitar alucinações — e enviado ao serviço de PDF. O template é desenvolvido em HTML/CSS utilizando regras rígidas de estilização. Para resolver o gargalo de processamento e memória ao abrir um novo navegador a cada requisição, implementamos o padrão de projeto Singleton no arquivo pdf.ts. Um único navegador Puppeteer é instanciado de forma preguiçosa (lazy) sob demanda, e cada requisição abre apenas abas leves (browser.newPage()) que são fechadas imediatamente após a geração do PDF. Também utilizamos diretivas CSS como @page e page-break-inside: avoid para impor os limites do formato A4 e evitar quebras de layout indesejadas.
Um ponto crucial ao desenvolver projetos de IA com orçamento de estudante são os custos de consumo de API. Modelos proprietários robustos como o GPT-4o da OpenAI ($2.50 por milhão de tokens de entrada, $10.00 por milhão de tokens de saída) ou o Claude 3.5 Sonnet da Anthropic ($3.00 na entrada, $15.00 na saída) tornam-se proibitivos em escala. Por esse motivo, integramos o gateway do OpenRouter para avaliar diferentes modelos e optamos pelo DeepSeek-v4-Flash, que oferece excelente qualidade de escrita semântica e aderência à estrutura do JSON esperado por uma fração microscópica do preço: apenas $0.07 por milhão de tokens de entrada e $0.21 por milhão na saída.
Para colocar essa diferença financeira em perspectiva, podemos realizar uma análise quantitativa de custos para uma única execução. O processo consome cerca de 2.500 tokens para o currículo JSON base e parâmetros do prompt, 1.000 tokens para a descrição da vaga e 500 tokens para as instruções do sistema, somando aproximadamente 4.000 tokens de entrada. O JSON adaptado de saída representa cerca de 1.500 tokens. Rodar esse fluxo no GPT-4o custaria 1,0 centavo de dólar para entrada (4.000 $2.50/1M) e 1,5 centavos para saída (1.500 $10.00/1M), totalizando 2,5 centavos de dólar por execução. No DeepSeek-v4-Flash, o custo de entrada é $0.00028 (4.000 $0.07/1M) e o de saída é $0.000315 (1.500 $0.21/1M), totalizando $0.000595.
Isso representa uma economia fantástica de aproximadamente 97,6% por execução. Para um estudante que candidata-se a 100 vagas e otimiza seu currículo para cada uma delas, o uso do GPT-4o custaria $2.50, enquanto o DeepSeek-v4-Flash custaria meros $0.06. Essa disparidade econômica viabiliza o projeto de maneira sustentável e escalável para quem está buscando emprego com orçamento limitado.
A arquitetura do bot também trouxe aprendizados valiosos sobre trade-offs de engenharia. Optar por sessões em memória evitou a latência e custos de hospedagem de bancos de dados (como MongoDB ou PostgreSQL) para sessões que duram apenas alguns segundos, aceitando o pequeno risco de perda de estado ativo caso o servidor reinicie. Da mesma forma, escolher o Puppeteer com templates HTML/CSS em vez de bibliotecas nativas de PDF como o PDFKit aumentou o tamanho da imagem de implantação do container em 150MB para incluir o Chromium, mas eliminou a necessidade de posicionar coordenadas de texto manualmente, permitindo construir currículos dinâmicos e responsivos com layouts estáveis.
A criação deste bot provou que o desenvolvimento moderno de sistemas com inteligência artificial exige muito mais do que saber criar prompts. Desenhar arquiteturas desacopladas e orientadas a eventos, aplicar padrões de projetos para reuso de recursos pesados e realizar análises frias e matemáticas dos custos de API são as verdadeiras bases para construir soluções de produção sustentáveis. Você pode conferir o código-fonte completo e os detalhes de implementação no GitHub sob a licença MIT!