- Remove multi-stage Dockerfile (não compatível com Swarm) - Dockerfile.api: imagem standalone para API FastAPI - Dockerfile.web: imagem standalone para Streamlit - docker-compose.yml: aponta para os Dockerfiles separados - README.md: instruções de build individual + deploy Swarm
210 lines
5.7 KiB
Markdown
210 lines
5.7 KiB
Markdown
# 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 <url-do-repositorio> 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/
|
|
│ ├── ARCHITECTURE.md # Detalhamento técnico
|
|
│ └── API.md # Documentação da API
|
|
└── 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 |