Skip to content

fix: extrai parágrafos de resumo estruturado (sec por subseção) - #1333

Open
Rossi-Luciano wants to merge 1 commit into
scieloorg:masterfrom
Rossi-Luciano:fix/pdf-structured-abstract-empty
Open

fix: extrai parágrafos de resumo estruturado (sec por subseção)#1333
Rossi-Luciano wants to merge 1 commit into
scieloorg:masterfrom
Rossi-Luciano:fix/pdf-structured-abstract-empty

Conversation

@Rossi-Luciano

@Rossi-Luciano Rossi-Luciano commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

O que esse PR faz?

Corrige a issue #1332: quando um artigo tem resumo estruturado (subseções tipo Introduction/Methods/Results, cada uma dentro de sua própria <sec>), o resumo saía vazio no PDF gerado — só o cabeçalho "ABSTRACT"/"RESUMO" aparecia, indo direto para "Keywords".

extract_abstract_data e extract_trans_abstract_data (packtools/sps/formats/pdf/pipeline/xml.py) usavam node.findall('p'), que só localiza <p> filho direto do elemento <abstract>/<trans-abstract>. Num resumo estruturado, os <p> ficam um nível mais fundo (dentro de <sec>), então a extração retornava lista vazia.

Adiciona _extract_abstract_paragraphs(node), um helper recursivo que percorre <p> e <sec> em qualquer profundidade, incluindo o <title> de cada <sec> como rótulo (o texto fonte já vem com o :, ex. "Methods:") — preserva a estrutura do resumo no texto final em vez de apagar a divisão entre subseções. Reaproveitado nas duas funções, que tinham exatamente o mesmo bug.

Onde a revisão poderia começar?

packtools/sps/formats/pdf/pipeline/xml.py_extract_abstract_paragraphs (helpers privados) e os dois pontos que passaram a chamá-la: extract_abstract_data e extract_trans_abstract_data.

Como este poderia ser testado manualmente?

python -m packtools.sps.formats.pdf_generator \
  -i <artigo-com-resumo-estruturado>.xml \
  -l layout.docx \
  -o saida.pdf \
  --libreoffice-binary libreoffice

Conferir o RESUMO/ABSTRACT na página 1.

Algum cenário de contexto que queira dar?

Achado por acaso revisando visualmente o corpus de teste de 26 artigos reais (layout_examples_rafael/corpus/), enquanto validava outro fix (afiliação duplicada). Confirmei a causa raiz e a abrangência antes de abrir a issue #1332: 6 de 26 artigos (23%) tinham resumo vazio por esse motivo — a10.xml (RESUMO em português também vazio), a11.xml, a14.xml, a17.xml, a20.xml, a28.xml. Não é um caso raro nem exclusivo de uma área (saúde e administração/negócios ambos afetados).

Screenshots

issue1332_before_after

Quais são os tickets relevantes?

Corrige #1332.

Referências

N/A


Segurança da informação (NSI.04)

Seção obrigatória. Marque as opções aplicáveis e justifique quando necessário. Referência: NSI.04 - Norma de Desenvolvimento Seguro.

Este PR manipula dados sensíveis ou pessoais (LGPD)?

  • Sim — descreva os controles de proteção aplicados (criptografia, mascaramento, anonimização, etc.):
  • Não

Este PR altera autenticação, autorização, controle de acesso ou gerenciamento de sessão?

  • Sim — descreva o que mudou e por quê:
  • Não

Este PR introduz, atualiza ou remove dependências de terceiros?

  • Sim — as novas dependências foram verificadas no SBOM/Trivy sem vulnerabilidades críticas/altas em aberto?
    • Verificado e aprovado
    • Pendente / vulnerabilidade aceita com justificativa:
  • Não

Este PR foi validado pelo pipeline de segurança (SonarQube / Trivy)?

  • Sim — link do job:
  • Não aplicável a este PR (justifique): mudança isolada de extração de texto a partir do próprio XML do artigo, sem I/O externo ou entrada não confiável

Este PR concatena, monta ou executa comandos SQL, HTML ou JavaScript a partir de entrada externa?

  • Sim — confirme que há sanitização/parametrização (prepared statements, escaping, etc.):
  • Não

Este PR expõe novos endpoints, telas ou serviços?

  • Sim — HTTPS obrigatório está garantido e o acesso segue o princípio de menor privilégio?
  • Não

Algum segredo, senha, chave ou token está sendo adicionado ao código-fonte?

  • Não, nenhum segredo foi commitado
  • Sim (bloquear merge e corrigir antes de prosseguir)

🤖 Generated with Claude Code

https://claude.ai/code/session_01X8r2LRJ3PGTT9vLaPtb373

Corrige a issue scieloorg#1332: extract_abstract_data e extract_trans_abstract_data
usavam node.findall('p'), que so acha <p> filho DIRETO de <abstract>/
<trans-abstract>. Um resumo estruturado (subsecoes tipo Introduction/
Methods/Results, cada uma sua propria <sec><title>...</title><p>...</p>
</sec>) tem os <p> um nivel mais fundo, entao a extracao retornava
content vazio - o PDF mostrava so o cabecalho "ABSTRACT"/"RESUMO" e ia
direto pra "Keywords", sem nenhum texto de resumo.

Adiciona _extract_abstract_paragraphs(node), helper recursivo que
percorre <p> e <sec> em qualquer profundidade, incluindo o <title> de
cada <sec> como rotulo (ja vem com o ":" da propria fonte, ex.:
"Methods:"), preservando a estrutura do resumo em vez de so concatenar
tudo. Reaproveitado nas duas funcoes, que tinham o mesmo bug.

Confirmado contra o corpus real de 26 artigos: 6 (23%) tinham resumo
vazio por esse motivo (a10, a11, a14, a17, a20, a28) - a10 tinha o
RESUMO em portugues vazio tambem. Todos os 6 corrigidos; os outros 20
(resumo simples, sem <sec>) continuam identicos.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X8r2LRJ3PGTT9vLaPtb373
# Private helpers
# -----------------

def _extract_abstract_paragraphs(node):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Boa.

if p is not None:
abstract.append(''.join(p.itertext()).strip())
data['content'] = ' '.join(abstract)
data['content'] = ' '.join(_extract_abstract_paragraphs(node_abstract))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A extração agora preenche corretamente o resumo estruturado, mas no a10, por exemplo, esse mesmo conteúdo também entra novamente pelo extract_body_data(), que percorre xml_tree.findall('.//sec') e, portanto, inclui as de e . No resultado, “Background: A staggering 99%…” e “Contexto: Um número impressionante…” aparecem no resumo e outra vez como corpo. Precisamos restringir a extração do corpo às seções do principal. Veja como ficou:

Página 1:

Image

Página 2:

Image

Página 3:

Image

@pitangainnovare pitangainnovare left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A correção preenche os resumos estruturados que antes ficavam vazios, mas encontrei dois problemas na saída final que precisam ser tratados antes da aprovação.

No a10.xml, o conteúdo do ABSTRACT e do RESUMO passa a aparecer duas vezes. O PR agora extrai corretamente as <sec> internas do <abstract> e do <trans-abstract>, mas extract_body_data() continua usando xml_tree.findall('.//sec'). Com isso, ela também considera como corpo as seções pertencentes aos resumos.

No DOCX gerado pelo HEAD deste PR, por exemplo, “Background: A staggering 99%…” aparece uma vez no ABSTRACT e novamente como seção do corpo. O mesmo ocorre com “Contexto: Um número impressionante…” no RESUMO, além das demais seções Objective/Objetivo, Methods/Métodos, Results/Resultados e Conclusion/Conclusão.

Acredito que extract_body_data() deva percorrer somente as <sec> do <body> principal.

Também há um problema dos títulos de seções sem pontuação. A implementação pressupõe que todo <sec><title> já possui dois-pontos, mas isso não ocorre em parte do corpus. Em a11.xml, por exemplo, o XML contém <title>Objetivo</title>, e a saída fica “Objetivo descrever...”, enquanto o PDF publicado apresenta “Objetivo: descrever...”. O mesmo padrão aparece também em a17.xml e a20.xml. A formatação poderia, como solução, acrescentar um separador quando o título não trouxer pontuação final, sem duplicá-lo quando o XML já tiver :.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants