# pdf-toolkit Transforme, otimize e gerencie arquivos PDF com facilidade. - **Interface Web**: Streamlit com upload drag-and-drop e configuração visual - **API REST**: FastAPI com documentação OpenAPI automática em `/docs` - **Autenticação**: API Key via header `X-API-Key` (configurável via env var) - **Docker**: containers prontos para produção via docker-compose - **Operações**: compressão, PDF/A ↔ PDF comum, merge, split, rotação, extração de texto e imagens --- ## 🚀 Começando ### Pré-requisitos - Python 3.12+ - pip - Docker (opcional, para containers) ### Instalação (sem Docker) ```bash git clone pdf-toolkit cd pdf-toolkit pip install -r requirements.txt ``` ### Execução (sem Docker) **Streamlit (interface web):** ```bash streamlit run app.py --server.port 8550 ``` **API REST:** ```bash uvicorn api:app --host 0.0.0.0 --port 8555 --reload ``` Acesse: - Streamlit → http://localhost:8550 - API docs → http://localhost:8555/docs (Swagger) - API docs → http://localhost:8555/redoc (Redoc) --- ## 📋 Operações disponíveis | Operação | CLI | API | Streamlit | |---|---|---|---| | Comprimir PDF | ✅ | POST `/compress` | ✅ | | PDF/A → PDF comum | ✅ | POST `/pdfa-to-regular` | ✅ | | Comprimir mantendo PDF/A | ✅ | POST `/compress-pdfa` | ✅ | | Merge (juntar PDFs) | ✅ | POST `/merge` | ✅ | | Split (extrair páginas) | ✅ | POST `/split` | ✅ | | Extrair páginas específicas | ✅ | POST `/extract-pages` | ✅ | | Rotacionar páginas | ✅ | POST `/rotate` | ✅ | | Extrair texto | ✅ | POST `/extract-text` | ✅ | | Extrair imagens | ✅ | POST `/extract-images` | ✅ | | Inspecionar metadados | ✅ | POST `/inspect` | ✅ | ### Níveis de compressão | Preset | Qualidade | Dimensão máx | Descrição | |---|---|---|---| | `screen` | 30 | 1200px | Agressivo — mínimo tamanho | | `ebook` | 60 | 2000px | Equilibrado — padrão | | `printer` | 85 | 3500px | Leve — alta qualidade | | `prepress` | 95 | 5000px | Mínima perda | --- ## 🧠 Arquitetura ``` pdf-toolkit/ ├── app.py # Interface Streamlit (GUI) ├── api.py # API REST (FastAPI) ├── config.py # Constantes e limites ├── requirements.txt # Dependências ├── core/ │ ├── engine.py # Orquestrador central │ ├── compress.py # Compressão e re-amostragem │ ├── operations.py # Merge, split, rotate, extract │ ├── validators.py # Validação de PDFs │ └── pdfa.py # Detecção e conversão PDF/A ├── scripts/ │ ├── run-web.sh # Inicia Streamlit │ └── run-api.sh # Inicia API ├── tests/ # Testes unitários ├── docs/ │ ├── escopo.md # Especificação de escopo e anti-scope │ ├── fases.md # Roadmap de execução e fases │ ├── ARCHITECTURE.md # Detalhamento técnico │ └── API.md # Documentação da API ├── AGENTS.md # Ponte de contexto para Agentes de IA e Obsidian └── tmp/ # Arquivos temporários (gitignored) ``` ### Decisões técnicas - **pypdf**: manipulação PDF 100% Python, sem dependências binárias - **Pillow**: re-amostragem de imagens com redimensionamento proporcional - **FastAPI**: tipagem automática, validação de entrada, OpenAPI nativo - **Streamlit**: prototipação rápida de GUI sem HTML/JS - **Sem Ghostscript**: mantido leve — pypdf + Pillow cobre ~90% dos casos ### Limitações conhecidas - A compressão re-amostra imagens embutidas; PDFs sem imagens reduzem pouco - A detecção de PDF/A é heurística (via metadados XMP + OutputIntents) - Preview visual de páginas requer `poppler-utils` + `pdf2image` (não incluso) - PDFs criptografados com senha não são suportados --- ## 🔐 Autenticação da API A API suporta autenticação via **API Key** no header `X-API-Key`. ### Configuração Defina a variável de ambiente `PDFTOOLKIT_API_KEY`: ```bash export PDFTOOLKIT_API_KEY="sua-chave-secreta-aqui" ``` Se a variável **não** estiver definida, a API roda sem autenticação (modo desenvolvimento). ### Uso com curl ```bash curl -X POST http://localhost:8555/compress \ -H "X-API-Key: sua-chave-secreta-aqui" \ -F "file=@documento.pdf" \ -o comprimido.pdf ``` ### Endpoints públicos (sem auth) - `GET /` — raiz informativa - `GET /health` — health check --- ## 🐳 Docker ### docker-compose (desenvolvimento local) ```bash cp .env.example .env # configure sua API Key sed -i 's/PDFTOOLKIT_API_KEY=.*/PDFTOOLKIT_API_KEY=minha-chave/' .env docker compose up -d --build # Acesse: # - Streamlit: http://localhost:8550 # - API: http://localhost:8555 # - Swagger: http://localhost:8555/docs ``` ### Build individual para Swarm / registry Cada serviço tem seu próprio `Dockerfile` independente: ```bash # API docker build -t gitea.cmconsultor.com.br/cmconsultor/pdf-toolkit-api:1.0.0 -f Dockerfile.api . docker push gitea.cmconsultor.com.br/cmconsultor/pdf-toolkit-api:1.0.0 # Web docker build -t gitea.cmconsultor.com.br/cmconsultor/pdf-toolkit-web:1.0.0 -f Dockerfile.web . docker push gitea.cmconsultor.com.br/cmconsultor/pdf-toolkit-web:1.0.0 ``` ### Deploy no Docker Swarm ```yaml # pdf-toolkit-stack.yml docker stack deploy -c docker-compose.yml pdf-toolkit ``` Ou use imagens previamente buildadas (recomendado para Swarm): ```bash # Ajuste o docker-compose.yml para usar as imagens do registry docker stack deploy -c docker-compose.yml pdf-toolkit ``` ### Estrutura dos containers Cada container é uma **imagem independente** otimizada para deploy individual: - **`pdf-toolkit-api`**: FastAPI + uvicorn, porta 8555 - **`pdf-toolkit-web`**: Streamlit, porta 8550, depende do serviço `api` - Volume compartilhado `uploads` para arquivos temporários - Healthcheck embutido em ambos os containers --- ## 🧪 Testes ```bash python -m pytest tests/ -v ``` --- ## 📦 Licença MIT