Geração de Relatórios Profissionais em PDF (Chinês)
🚨 Lições Aprendidas com Correções do Usuário (2026-08-20, Prioridade Máxima, Proibido Repetir)
- Layout Compacto: É proibido adicionar quebras de página desnecessárias para encher o relatório. Apenas uma quebra de página após a capa; o conteúdo deve fluir naturalmente. Anteriormente, 6 páginas foram comprimidas em 4.
- Fonte Grande (Legível no Celular): Corpo do texto ≥ 16pt, tabelas ≥ 15pt, H2 ≥ 17pt, H1 ≥ 21pt, título ≥ 30pt. Tamanhos menores (14pt/12pt) são inaceitáveis para visualização em dispositivos móveis.
- Antes de gerar o script, verifique as constantes de tamanho de fonte e a quantidade de quebras de página.
⭐ Padrão de Formatação Geral (2026-08-18, Definido pelo Usuário, Válido para PDF/Word)
Esta lógica de formatação é o padrão para todos os documentos PDF e Word:
- A4 Retrato (210×297mm) – não use paisagem ou outros tamanhos.
- Fonte Grande, Legível no Celular: Corpo ≥ 14pt, Tabela ≥ 12.5pt, H1 ≥ 20pt, Título ≥ 32pt.
- Quebra de Linha Inteligente em Tabelas: Use
Paragraph+wordWrap="CJK"nas células. - Conteúdo Equilibrado por Página: Sem quebras de página forçadas; use
KeepTogetherpara blocos inteligentes. Após a geração, verifique o número de caracteres por página (exceto capa/rodapé). - Layout Compacto: Margens de 18-20mm, padding de tabela 3-4, espaçamento compacto, pronto para impressão.
Documentos Word seguem a mesma lógica: A4 retrato, corpo ≥ tamanho 12-14pt, tabelas com largura adaptável, páginas equilibradas.
Condições de Ativação
- O usuário/cliente solicita "transformar a conclusão em PDF", "enviar o PDF", "relatório de viabilidade", "fazer a conclusão e enviar".
- É necessário entregar um relatório de análise chinês com formatação profissional (capa + tabelas + rodapé + caixa de conclusão principal).
- Exemplo de referência: Relatório de Due Diligence da Guoxun Robot (5 páginas,
02-成果/国巡机器人项目可行性尽调与分析报告.pdf).
Ambiente e Instalação
- Use o interpretador
hermes venv:python - Instalação inicial:
$V -m pip install reportlab(já instalado, versão 5.0.0) - Fonte: Microsoft YaHei nativa do Windows, não é necessário baixar arquivos de fonte
C:/Windows/Fonts/msyh.ttc(regular, subfontIndex=0)C:/Windows/Fonts/msyhbd.ttc(negrito)C:/Windows/Fonts/msyhl.ttc(fino)
Fluxo de Trabalho Padrão
- ⚠️ Regra de Ouro de Entrega (2026-09-02, Prioridade Máxima): Após gerar o PDF, deve enviá-lo no chat do Feishu via
MEDIA:. Nunca apenas salvar na base de conhecimento / fornecer o caminho / enviar apenas os pontos principais. Palavras do usuário: "O PDF deve ser enviado aqui no chat do Feishu, senão como vou vê-lo? Isso tem que virar uma regra de ferro."- O usuário vê no celular; só consegue acessar clicando no arquivo na mensagem do Feishu. Salvar em
02-成果/é apenas backup, não é entrega. - Formato de entrega:
<seu_diretório_saída>/<nome_arquivo>.pdf(caminho absoluto). - Após enviar o PDF, anexe os pontos principais da conclusão (versão de 30 segundos). Primeiro envie no Feishu, depois salve na base de conhecimento para revisão.
- O usuário vê no celular; só consegue acessar clicando no arquivo na mensagem do Feishu. Salvar em
- Obter Conteúdo: Use
session_searchpara consultar análises anteriores – o usuário frequentemente responde a anexos com "transformar a conclusão em PDF". Primeiro recupere o conteúdo de análises/due diligence anteriores, não reescreva. - Escrever Script: Copie
templates/reportlab_chinese_template.pye substitua apenas a área de conteúdo (texto da capa, capítulos, dados da tabela). - Gerar: Execute
python→ Salve a saída emHermes工作成果/02-项目成果/(nome:<tema>项目可行性尽调与分析报告.pdf). - Validar: Use
pymupdfpara abrir, ler comget_text, confirmar número de páginas / renderização chinesa / existência da conclusão na última página. - Entregar: Responda com o caminho
MEDIA:D:\...pdf+ pontos principais da conclusão (versão de 30 segundos), sem enrolação.
⭐ Regra de Ouro de Cores (2026-09-02, Definida pelo Usuário, Cores Favoráveis: Ouro/Terra – Prioridade Máxima)
O usuário tem ouro e terra como elementos favoráveis, e evita água (azul/preto) e fogo (vermelho/roxo). Todos os PDFs devem usar a paleta de ouro e terra. É proibido usar azul. As variáveis de cor estão na paleta abaixo.
- Título de Capítulo H1: Fundo ouro metálico + texto branco (
backColor=#C9A227,textColor=white,borderPadding=(6,8,6,8)) – fundo ouro, texto branco, não texto azul. - Cabeçalho de Tabela: Fundo ouro metálico + texto branco (
header_bg=#C9A227,FONTNAME=MSYHBD). - Corpo do Texto: Preto puro
#1f1f1f. - Subtítulo / Linha Divisória: Ouro terra escuro
#B8860B(sem vermelho). - Bloco de Código: Ouro terra
#8a6d1f(sem azul). - Listras Alternadas: Bege ouro claro
#FBF3DE(tom quente, não cinza/branco). - Linhas de Grade: Ouro terra claro
#D9C9A3.
Paleta Dourada (para reportlab)
C_DARK=colors.HexColor("#1f1f1f") # Corpo do texto (quase preto)
C_RED=colors.HexColor("#B8860B") # Ênfase/Subtítulo – ouro terra escuro
C_BLUE=colors.HexColor("#C9A227") # Fundo de cabeçalho/título – ouro metálico
C_LGRAY=colors.HexColor("#FBF3DE") # Listras alternadas – bege ouro claro
C_MGRAY=colors.HexColor("#D9C9A3") # Linhas de grade – ouro terra claro
C_WHITE=colors.white
Ênfase inline:
S_CODE=st(..., textColor=colors.HexColor("#8a6d1f")); inline<span color='#B8860B'>(não usar#c0392bvermelho).
Pontos de Formatação (Já Incorporados no Template)
- Capa: Título grande + subtítulo dourado + data/fonte + caixa de conclusão principal (fundo ouro terra escuro, texto branco).
- Corpo do Texto: H1 capítulo (fundo ouro metálico, texto branco MSYHBD 21pt) + H2 seção (17pt) + corpo do texto 15pt (2026-08-18 instrução do usuário: legível no celular, fonte grande).
- Tabelas:
make_table()cabeçalho fundo ouro metálico + texto branco + listras alternadas (ROWBACKGROUNDS) + grid + repeatRows=1, fonte da tabela 13pt. - Rodapé: Callback
onPagepara desenhar o nome do relatório + número da página. - Ênfase:
Paragraphsuporta<b>/<span color='#B8860B'>para marcação inline. - Relatórios Longos: Seções separadas por
PageBreakentre capa e corpo do texto.
⚠️ Regra de Ouro de Tamanho de Fonte (2026-08-18, enfatizada pelo usuário): O PDF é para ser visto no celular, corpo ≥ 15pt, tabela ≥ 13pt, H1 ≥ 21pt, título ≥ 34pt. O template original com 10.5pt/9.3pt é muito pequeno, ilegível no celular – todos os novos relatórios devem usar fonte grande. O aumento de páginas devido ao tamanho maior é normal (ex.: 5 páginas → 8 páginas).
⭐ Regra de Ouro de Layout Inteligente (2026-08-18, enfatizada pelo usuário, amigável para impressão) O conteúdo da página deve ser equilibrado – não pode ter uma página com apenas 200 caracteres e outra com 800. Método:
- Use PageBreak com moderação: Apenas uma quebra de página após a capa; o corpo do texto flui naturalmente.
- Use KeepTogether para envolver "título + conteúdo":
keep(título H2, tabela/parágrafo)para evitar que a tabela seja dividida entre páginas ou que o título fique isolado no final da página. - Capa em página separada: Elementos da capa + um PageBreak.
- Cada capítulo usa seções naturais: Título H2 + tabela/pontos principais, sem forçar quebra de página por capítulo.
- Verifique o equilíbrio: Após a geração, use pymupdf para verificar o número de caracteres por página – em relatórios normais, exceto capa/rodapé, as páginas devem ter números próximos (ex.: 600-900 caracteres). Diferenças muito grandes exigem ajustes.
- Layout Compacto: Margens de 20mm/16mm (não muito grandes), padding de tabela 4-5, espaçamento leading=22 (corpo 14pt), reduzindo desperdício de espaço.
Armadilhas (PITFALLS)
- ⛔ Proibido usar TA_JUSTIFY – espaçamento entre caracteres fica alargado (2026-09-03, problema de legibilidade no celular mais importante para o usuário):
TA_JUSTIFYdo reportlab força cada linha a esticar até a borda direita, resultando em espaçamento excessivo e feio quando a linha tem poucos caracteres. Todos os parágrafos/listas/corpo do texto devem usarTA_LEFT(alinhamento à esquerda).- Errado:
b=dict(..., alignment=TA_JUSTIFY, ...) - Correto:
b=dict(..., alignment=TA_LEFT, ...) - Verificação: Se os estilos de corpo/lista herdarem
st()comalignment=TA_JUSTIFY, mude para alinhamento à esquerda.
- Errado:
- ⛔ Conteúdo da capa vaza para página em branco (2026-09-03): Todos os elementos da capa (título principal + subtítulo + descrição + frase principal) devem caber na página 1. Nunca permita que o conteúdo da capa seja empurrado para a página 2, resultando em "pouco texto + grande espaço em branco". Se o conteúdo da capa for muito extenso, remova introduções longas e comprima espaçamentos de lista para que caiba em 1 página. Mantenha apenas um PageBreak após a capa; o corpo do texto flui naturalmente.
- ⛔ Ajuste sincronizado de tamanho de fonte/margens: Ao aumentar o tamanho da fonte, as margens devem ser reduzidas (nesta sessão, de 22mm para 17mm) para que cada página comporte mais conteúdo, evitando páginas órfãs. Corpo 17pt + margem 17mm é o ponto de equilíbrio testado; fonte da tabela 14.5pt.
- ⛔ KeepTogether envolvendo "tabela pequena com alinhamento personalizado" pode causar erro de altura → página órfã (2026-09-06, testado): Ao usar KeepTogether para envolver "título + corpo + tabela de duas colunas com alinhamento (field_table)" + preço, a estimativa de altura do reportlab para este bloco é imprecisa, muitas vezes empurrando todo o bloco para a próxima página, deixando na página anterior apenas "frase de dica" / "linha final da tabela" – resultando em dezenas de caracteres órfãos (nesta sessão, a página 2 tinha apenas 76 caracteres). Correção: ① Para o bloco inicial "tabela de serviços + introdução", use KeepTogether para envolver todo o
head_blocke comprima o tamanho da fonte da tabela/espaçamento para garantir que caiba na página 1; ② Após a renderização, use pymupdf para verificar o número de caracteres por página; páginas com <120 caracteres são órfãs – comprima imediatamente a tabela da página anterior / remova frases de dica extras.- Distinção (2026-09-10, testado): Envolver apenas a "tabela em si" é preciso e recomendado; envolver "título + corpo + tabela + preço" em um bloco grande é que causa erros. Faça a função de fábrica de tabelas retornar
return KeepTogether(t)(tabela inteira não quebra entre páginas), combinada com manter apenas um PageBreak após a capa. Testado: reduziu de 7 páginas (página 5 com apenas 77 caracteres) para 6 páginas, com 301/451/548/407/551/240 caracteres por página. Quebra de tabela entre páginas, com 1-2 linhas isoladas em uma página, é a causa número 1 de páginas órfãs; se encontrar "apenas cabeçalho / última linha" em uma página, verifique isso primeiro.
- Distinção (2026-09-10, testado): Envolver apenas a "tabela em si" é preciso e recomendado; envolver "título + corpo + tabela + preço" em um bloco grande é que causa erros. Faça a função de fábrica de tabelas retornar
- ⛔ Coluna de rótulo em tabela de duas colunas "rótulo + conteúdo" não pode ser muito estreita – rótulos chineses quebram em caracteres isolados (2026-09-06): Ao usar tabela de duas colunas para "o que pode fazer / até onde vai / o que você obtém", se a coluna de rótulo for muito estreita (ex.: 32mm), "o que você obtém" pode quebrar em "o que você ob" + "tém", resultando em caracteres isolados muito feios. Correção: A largura da coluna de rótulo deve ser > que a maior palavra inteira (cerca de 40mm), ou encurte o rótulo ("o que você obtém" → "benefícios").
- ⛔ O ponto final no final de frases longas pode quebrar sozinho em uma nova linha (2026-09-06): Em campos longos como "até onde vai / benefícios", o ponto final no final da frase pode ser jogado para o início da próxima linha. Correção: Quando o valor do campo for longo e houver risco de quebra, remova o ponto final (ou use frases curtas). É melhor não ter ponto final do que deixar um ponto órfão.
- ⛔ "Habilidade personalizada" deve usar terminologia correta (2026-09-06, corrigido pelo usuário): Não escreva "personalização / criação de skills" como "tarefa agendada". A versão para o cliente deve usar "personalização de skill exclusivo" e explicar coloquialmente "skill = uma capacidade específica que a IA pode executar" (veja
enterprise-ai-service-blueprint). - Fontes
.ttcdevem usarsubfontIndex=0, caso contrário, erro ou caracteres ilegíveis. - O negrito requer registro de MSYHBD e configuração de
fontName– a tag<b>sem registro de fonte negrito não aplica negrito. - A escapada de
<e>deve ser tratada em duas situações (2026-09-10, testado na prática): Apenas os sinais de menor/maior literais no corpo do texto (como "precisão < 10mm") devem ser escapados para</>; enquanto<b>,<span color=...>são tags inline e devem ser passadas como estão para oParagraphpara funcionar.- ⛔ Código errado: Escapar todos os
<como<no texto da célula → o negrito na tabela será exibido literalmente como<b>texto(nesta sessão, uma coluna inteira na página 2 foi impressa como<b>destaque nominal…, só descoberto antes da entrega). - ✅ Correto: Apenas escape
&literal (v.replace('&','&')) nas células da tabela; mantenha as tags inline. Os sinais de menor/maior literais devem ser escritos como<pelo chamador. - Autoverificação: Antes da entrega, verifique se
'<b>' in textou'</b>' in texté verdadeiro – se sim, as tags estão sendo renderizadas como texto, e a escapada emmake_tabledeve ser corrigida.
- ⛔ Código errado: Escapar todos os
- A soma das larguras das colunas da tabela deve ser ≤ largura útil do A4 (210mm - margens laterais), caso contrário, o texto transborda e fica feio.
- Vazamento de texto chinês em tabelas (2026-08-18, correção importante): A
Tabledo reportlab ao colocar texto chinês longo não quebra linha automaticamente, vazando para a direita! Use obrigatoriamenteParagraphpara envolver as células +wordWrap="CJK". Já incorporado emmake_tablecom_cell_style()– todas as células quebram linha automaticamente. Verificação: Use pymupdf para verificar se ox2deget_text('words')ultrapassa a borda direita da área de conteúdo.- O limite deve ser calculado com base na margem real, não fixo em 540pt (2026-09-10, testado): Borda direita =
A4[0] - rightMargin(largura A4 = 595.3pt; margem 16mm → 549.9pt, 17mm → 547pt). Fixar em 540pt gera falsos positivos para quebra de linha normal, causando retrabalho desnecessário. - Deve excluir o rodapé: O "página N" desenhado por
onPagesempre excede a área de conteúdo. Ao verificar, filtre o texto (ex.:w[4] != '页'), caso contrário, sempre haverá alarmes falsos. - Exemplo de verificação:
[w in page.get_text('words') if w[2] > page.rect.width - rightMargin + 1 and w[4] != '页']
- O limite deve ser calculado com base na margem real, não fixo em 540pt (2026-09-10, testado): Borda direita =
- Regra de Ouro A4 Retrato (enfatizada pelo usuário): Todos os PDFs devem ser A4 retrato (210×297mm).
pagesize=A4é retrato por padrão; não altere para paisagem. - Antes da entrega, use pymupdf para validar (número de páginas / renderização chinesa / sem vazamento) – só envie após validação.
- ⛔ Ao escrever o script de geração, use sempre aspas simples para delimitar strings Python (2026-09-10, testado): A cadeia de ferramentas pode normalizar aspas chinesas “ ” para aspas duplas retas
". Se a string externa usar aspas duplas, as aspas no corpo do texto fecharão o literal prematuramente → causandoSyntaxError: invalid character '+' (U+FF0B)(o erro parece apontar para caracteres fullwidth inválidos, mas a causa real é o truncamento de aspas, enganando a investigação). Use「」para aspas chinesas no corpo do texto, ou envolva toda a string com'...'. - ⛔ Nunca leia e escreva o mesmo arquivo simultaneamente:
open(f,'w').write(open(f,encoding='utf-8').read() + add)trunca o arquivo para 0 bytes antes de ler, resultando na perda total do conteúdo original e apenas o trecho adicionado (nesta sessão, uma nota na base de conhecimento encolheu de 13KB para 3.8KB). Ao anexar conteúdo, primeiro leiatxt = open(f).read()em uma variável, depois escrevaopen(f,'w').write(txt + add); ou use uma ferramenta de patch. - Arquivos > 100KB são geralmente normais (com subconjunto de fonte incorporado).
Comando de Validação
$V -c "import pymupdf; d=pymupdf.open(r'D:\...\报告.pdf'); print(len(d)); print(d[0].get_text()[:120]); print('Última página contém conclusão:', '结论' in d[-1].get_text())"
Relacionados
- Estrutura de conteúdo:
feasibility-study-writing,dual-lens-business-analysis(carregar antes de gerar relatório de análise binocular) - Regras de ouro de revisão de relatório: Execute
report-reflection-reviewantes de finalizar o relatório rigoroso - Cenário de PPT:
ultimate-ppt-master - Templates:
templates/reportlab_chinese_template.py(antigo);<b>templates/reportlab_gold_template.py(recomendado): Paleta dourada + alinhamento à esquerda + corpo 17pt + margem compacta de 17mm + sem páginas órfãs. Já corrigido o tratamento de tags inline emmake_table()(tags<b>/<span>em células de tabela agora funcionam de verdade, não são mais escapadas como texto literal).