bethania_porto_santos/.claude/skills/plano-de-ataque/SKILL.md
lronetto 8b15f2d455 Adiciona skills de Claude Code documentando o aprendizado do gerador de PPTX
- plano-de-ataque: skill de projeto, especifica deste repo (arquivos,
  formato da planilha, coordenadas de pixel da planta, cores)
- pptx-planta-progresso: skill generica/reutilizavel com a metodologia
  (medicao de eixos em pixel, correcao de crop srcRect, duplicacao de
  slide em python-pptx, fidelidade de cor, empacotamento sem dependencias
  para Linux/Windows, validacao sem Office instalado)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-13 10:24:25 +00:00

8.7 KiB

name: plano-de-ataque description: Gera ou atualiza o PPTX "Plano de Ataque" (progresso por quinzena de Geotecnia/Estaqueamento, Infraestrutura/Bloco e Superestrutura/Pilar) deste repositório. Use quando o usuário pedir para regenerar o plano de ataque, atualizar quinzenas com uma planilha nova, mudar as cores/legenda do PPTX, ajustar o mapeamento de pixels de uma planta nova, ou reempacotar os pacotes standalone (dist-linux/dist-windows). Escopo: repositório bethania_porto_santos (raiz do projeto).

Plano de Ataque — PPTX de progresso por quinzena

Este skill resume o que foi aprendido construindo gerar_plano.py: um gerador que pega um PPTX-modelo (1 slide de "uma quinzena") e uma planilha de planejamento, e produz um PPTX com 1 slide por quinzena, pintando cada quadrante da planta conforme o status de cada estrutura naquela data.

Onde as coisas estão

  • gerar_plano.py (raiz) — script-fonte, único arquivo, sem módulos próprios além de openpyxl, python-pptx, lxml.
  • cores.json (raiz) — cores/opacidades/parâmetros de quinzena, editável sem tocar no código (ver seção "Cores" abaixo).
  • dist-linux/ — pacote pronto (executável standalone via PyInstaller) + modelo .pptx + planilha .xlsx de exemplo + LEIA-ME.txt.
  • dist-windows/ — pacote pronto (Python "embeddable" do python.org com as libs já instaladas em python/Lib/site-packages, sem precisar instalar nada) + PlanoDeAtaque.bat + mesmos exemplos + LEIA-ME.txt + um .zip com tudo empacotado.

Fluxo normal de uso (regenerar o PPTX)

  1. Reunir em uma pasta: 1 .json de cores, 1 .pptx modelo (slide 2 = layout de uma quinzena), 1 .xlsx de planejamento.
  2. python3 gerar_plano.py dentro dessa pasta (ou rodar o executável/.bat em dist-linux/dist-windows).
  3. O script AUTO-DETECTA os 3 arquivos pela extensão na própria pasta (não usa nomes fixos) e gera <nome-do-modelo>_ATUALIZADO.pptx.
  4. Se o usuário mandar uma planilha/modelo NOVO por upload, é só copiar para .uploads/ (ou onde estiver rodando), gerar, e comparar visualmente (ver "Como validar" abaixo) antes de entregar.

Modelo de dados da planilha

Aba "Planejamento", dados a partir da linha 4:

  • Coluna B: nome do quadrante, formato "<col1>-<col2>/<linha1>-<linha2>", ex. "10-11/A1-B" (colunas são números 1-48; linhas são rótulos entre D, C, B1, B, A1, A). Regex usado: ^(\d+)-(\d+)/([A-Z0-9]+)-([A-Z0-9]+)$.
  • Colunas C/D: Geotecnia (Início/Término)
  • Colunas E/F: Infraestrutura (Início/Término)
  • Colunas G/H: Superestrutura (Início/Término)

Status por quadrante/estrutura numa data de corte p_end:

  • None (não pintar) se Início vazio ou Início > p_end
  • "concluido" se Término preenchido e Término <= p_end
  • "andamento" caso contrário

Quinzenas

Períodos de 14 dias começando em 2026-12-14 = Quinzena 02 (a planilha não tem atividade antes dessa data — por isso a numeração já começa em 02, não em 01). Esses três parâmetros ficam em cores.json → quinzena e dão para editar sem mexer no código: duracao_dias, data_inicio, numero_inicial.

Cores (cores.json)

Uma seção por estrutura (geotecnia, superestrutura, infraestrutura), cada uma com andamento e concluido, cada um com preenchimento (hex sem #), borda (hex sem #) e alpha_preenchimento (0-100). A legenda do slide sempre usa 100% de opacidade (fiel à cor pedida); o desenho usa o alpha_preenchimento configurado — mais baixo na geotecnia (cobre o quadrante inteiro, não pode esconder a planta) e mais alto nos marcadores de pilar/bloco (são pequenos, não atrapalham).

Regra de ouro ao pedir "mude a cor X pra Y": sempre pedir/usar um print em ALTA resolução da legenda e fazer amostragem de pixel (não confiar em screenshot comprimido/pequeno — já erramos assim uma vez nesta conversa). Amostrar tanto o preenchimento quanto a BORDA (são cores diferentes, e a legenda de referência sempre tem as duas).

Como as camadas são desenhadas (importante para não perder fidelidade)

  • Geotecnia/Estaqueamento: retângulo arredondado cobrindo o quadrante INTEIRO (não um recorte menor).
  • Superestrutura/Pilar e Infraestrutura/Bloco: NÃO são um retângulo proporcional ao quadrante — são marcadores pequenos (quadrado arredondado, marcador_fracao do espaçamento entre colunas) plantados nos 4 VÉRTICES (colunaxlinha) de cada quadrante ativo. Como vértices são compartilhados entre quadrantes vizinhos, dedupe por ponto usando o status mais avançado (concluido > andamento) para não desenhar marcadores duplicados/ sobrepostos no mesmo lugar.

Mapeamento pixel → EMU (a parte mais delicada)

As posições de colunas/linhas da planta (IM1_COLPX, IM2_COLPX, IM1_ROWPX, IM2_ROWPX no script) são constantes medidas a dedo nas imagens do modelo, usando detecção de blobs por soma de pixels escuros por coluna/linha (círculos dos eixos, ver histórico da conversa para o script de medição). Se a planta do modelo mudar, essas constantes têm que ser remedidas — sempre medir direto na imagem que está DE FATO embutida no .pptx (ppt/media/imageN.png dentro do zip), não em uma cópia enviada separadamente por upload: já tivemos um bug de desalinhamento porque as duas não eram pixel-idênticas.

Gotcha crítico: se a imagem no slide tiver um corte aplicado no PowerPoint (<a:srcRect t="..." b="..." l="..." r=".../> dentro do <p:blipFill>), a conversão pixel→EMU tem que descontar esse corte, senão tudo fica deslocado (geralmente para baixo/lado). Sempre checar o XML do <p:pic> de cada imagem do slide-modelo antes de assumir que pixel 0 = canto da imagem exibida. Foi exatamente isso que causou o "a imagem de baixo está deslocada" nesta conversa.

Duplicar slides em python-pptx

Não existe API pública para duplicar slide. A receita usada:

  1. dest = prs.slides.add_slide(source.slide_layout), depois remover os placeholders que a layout injeta.
  2. Para cada relationship de imagem do slide-fonte, dest.part.relate_to(...) para criar a relação equivalente no slide-destino (isso gera um rId novo, que pode não bater com o rId original).
  3. Deep-copy de cada shape do slide-fonte e reescrever os atributos r:embed/r:link diretamente no elemento XML (el.set(qn('r:embed'), novo_rid)), nunca com substituição de texto/regex na string do XML — se o remapeamento de rIds for uma permutação (ex. rId2↔rId3), um replace sequencial de string corrompe os dois (bug real que já apareceu aqui).

Reempacotar os executáveis

  • Linux (dist-linux/PlanoDeAtaque): pip install openpyxl python-pptx lxml pyinstaller e pyinstaller --onefile --name PlanoDeAtaque gerar_plano.py.
  • Windows (dist-windows/): este ambiente não tem Wine nem acesso a uma máquina Windows, então NÃO dá para compilar um .exe de verdade aqui. A solução usada foi montar um Python "portátil": baixar o python-3.11.9-embed-amd64.zip oficial do python.org, habilitar site-packages editando python311._pth (adicionar Lib\site-packages e import site), e usar pip download --platform win_amd64 --python-version 311 --implementation cp --abi cp311 --only-binary=:all: <pacotes> para baixar as wheels certas (mesmo rodando de um Linux — pip download só baixa o arquivo, não executa nada) e extrair (unzip) cada wheel dentro de python/Lib/site-packages. Lançador é um .bat simples chamando python\python.exe gerar_plano.py. Depois de montar, gerar de novo o PlanoDeAtaque_windows.zip (cuidado: gerar o zip DENTRO da própria pasta que está sendo zipada faz o zip se autoincluir — gerar em /tmp e mover para dentro depois).

Como validar antes de entregar

Como não há LibreOffice/PowerPoint disponível neste ambiente para renderizar o .pptx, a validação usada foi:

  1. Integridade: zipfile.testzip() + lxml.etree.fromstring em cada .xml/.rels do pacote.
  2. Reconstrução visual manual: ler off/ext (EMU) de cada <p:pic> e forma colorida do slide via python-pptx, converter para pixels e compor com Pillow (Image.alpha_composite) para gerar um PNG de conferência — é assim que os desalinhamentos e cores erradas foram detectados nesta conversa.

Git neste repositório

Não existe identidade de git configurada globalmente por padrão aqui. Em vez de rodar git config --global (proibido pelas regras de segurança do ambiente), usar override só para o comando do commit: git -c user.name="..." -c user.email="..." commit -m "...". .uploads/ está no .gitignore (são anexos de conversa, não arquivos do projeto) — os artefatos finais que importam ficam em dist-linux/ e dist-windows/.