Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ jobs:

- name: Start API
run: |
mkdir -p output
uvicorn main:app --host 0.0.0.0 --port 8000 &
sleep 5
- name: Check API health
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ report-generator-demo/frontend/dist/
.env
node_modules/
frontend/dist/
frontend/node_modules
report/ssr-dist/
report/node_modules/
*.lock
Expand Down
174 changes: 113 additions & 61 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,99 +1,151 @@
# report-generator-demo
# Automatic Reporting

Projeto com duas partes:
Sistema de geração de relatórios PDF para o Data Nordeste. Combina dados de CSVs com textos descritivos do Google Docs e renderiza relatórios visuais em PDF.

- **API em FastAPI** para gerar relatórios do Data Nordeste.
- **Frontend em React + Vite** para escolher macrotema e cidade e disparar o relatório.
## Arquitetura

## Estrutura
```
Browser (React SPA)
FastAPI (Python) ──────► Node.js (React SSR)
│ │
│ ▼
│ HTML renderizado
▼ │
WeasyPrint │
│ │
▼ │
PDF ◄─────────────────────┘
```

- **Python/FastAPI**: processa dados, gerencia CSV, Docs, gráficos
- **React SSR**: renderiza HTML da capa e conteúdo via `renderToStaticMarkup`
- **WeasyPrint**: converte HTML em PDF

- `main.py` — API FastAPI
- `citys.txt` — lista de cidades usadas no frontend
- `demografia.csv` — base de dados do relatório
- `output/` — arquivos HTML/PDF e gráficos gerados
- `frontend/` — interface web
## Stack

- **Backend**: FastAPI (Python 3.11+)
- **Frontend**: React + Vite
- **PDF**: WeasyPrint + React SSR
- **Build**: npm workspaces (monorepo)

## Requisitos

- Python 3.10+
- Python 3.11+
- Node.js 18+
- npm

## Instalação da API

Dentro da pasta `report-generator-demo`:
## Quick start

```bash
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
# Ativar ambiente virtual e rodar
source .venv/bin/activate && ./build.sh
```

## Como executar a API
Isso instala dependências Python e JS, builda o SSR e o frontend, e sobe os servidores.

## Componentes do build

```bash
uvicorn main:app --reload --host 0.0.0.0 --port 8000
pip install -r requirements.txt # Python deps
npm install # Node deps
npm run build -w report # Build React SSR → report/ssr-dist/
npm run build -w frontend # Build SPA → frontend/dist/
```

Se quiser usar um Google Docs específico como texto-base do relatório:
## Como rodar

```bash
export DATANE_DOCS_URL="https://docs.google.com/document/d/SEU_DOC_ID/edit"
source .venv/bin/activate && ./build.sh
```

Se essa variável não for definida, a API usa o documento padrão já configurado no `main.py`.
O `build.sh` inicia:
- Servidor SSR (Node.js) na porta 3001
- API FastAPI na porta 8000

## Instalação do frontend
## Endpoints da API

Dentro da pasta `report-generator-demo/frontend`:
| Método | URL | Descrição |
|--------|-----|-----------|
| GET | `/cities` | Lista de cidades |
| GET | `/macrotemas` | Lista de macrotemas |
| GET | `/relatorios` | Relatórios gerados |
| GET | `/relatorio/{cidade}?macrotema={tema}` | Gera relatório |
| DELETE | `/relatorios/{arquivo}` | Remove relatório |

```bash
yarn install
```
## Macrotemas

## Como executar o frontend
- `todos` — Todos os temas concatenados
- `demografia` — Demografia
- `educacao` — Educação
- `saude` — Saúde
- `economia-renda` — Economia e Renda
- `saneamento` — Saneamento
- `hidraulica` — Segurança Hídrica

```bash
yarn dev
```

O frontend abre normalmente em `http://localhost:5173`.
## Estrutura de diretórios

Se quiser, também funciona:

```bash
yarn start
```
/
├── main.py # FastAPI app
├── reports.py # Lógica de geração (orquestrador)
├── config.py # Configurações e variáveis de ambiente
├── plotting.py # Gráficos matplotlib
├── frontend/ # SPA React (interface)
│ └── src/App.jsx
├── report/ # React SSR (renderização PDF)
│ └── src/components/ # Cover, Report, Brand, etc.
├── utils/
│ ├── cover.py # Monta objeto "cover" para o React
│ ├── renderer.py # Converte markdown Docs → HTML
│ ├── ssr.py # Chama Node.js para renderizar
│ ├── docs.py # Baixa Google Docs
│ ├── cities.py # Filtro e список cidades
│ ├── macrotemas.py # Config dos temas
│ └── maps.py # Mapas (Contentful ou gerado)
├── docs/
│ └── ARCHITECTURE.md # Documentação da arquitetura
└── output/ # Relatórios gerados (.html + .pdf)
```

## Como usar

1. Rode a API.
2. Rode o frontend.
3. Abra o frontend no navegador.
4. Clique em **Gerar relatório**.
5. Escolha o macrotema e a cidade.
6. Clique em **Gerar relatório** novamente para abrir o relatório.
### Resumo das etapas

Por enquanto, o macrotema é apenas visual no formulário; a API recebe apenas a cidade.
| Etapa | O que acontece |
|-------|----------------|
| 1 | Carrega CSV do tema selecionado (pandas) |
| 2 | Filtra linhas pela cidade informada |
| 3 | Gera gráficos matplotlib (só se demografia) |
| 4 | Busca texto no Google Docs (com cache) |
| 5 | Extrai seções marcadas (##resumo_tema, etc.) |
| 6 | Preenche cover com métricas, score, indicadores |
| 7 | Converte markdown dos Docs em HTML |
| 8 | React SSR renderiza HTML final |
| 9 | Salva HTML, PDF gerado em background |

## O que a API faz

Quando você acessa `/relatorio/{cidade}`:
## Variáveis de ambiente

1. lê o CSV `demografia.csv`;
2. procura a cidade informada, com ou sem UF;
3. busca o texto-base no Google Docs;
4. renderiza o HTML do relatório;
5. gera gráfico de população por sexo;
6. salva os arquivos em `output/`;
7. devolve o HTML no navegador.
```bash
# URLs dos CSVs (por tema)
DEMOGRAFIA_CSV_URL, EDUCACAO_CSV_URL, SAUDE_CSV_URL, etc.

## Exemplo de uso direto da API
# URLs dos Docs (por tema)
DEMOGRAFIA_DOCS_URL, EDUCACAO_DOCS_URL, etc.

- `http://127.0.0.1:8000/docs`
- `http://127.0.0.1:8000/relatorio/Caruaru%20(PE)`
# Contentful (mapas)
CONTENTFUL_SPACE_ID, CONTENTFUL_ACCESS_TOKEN
```

## Arquivos importantes do frontend
## Docker

- `frontend/src/App.jsx` — tela principal
- `frontend/src/styles.css` — estilos da interface
- `frontend/package.json` — scripts do frontend
```bash
docker build -t automatic-reporting .
docker run -p 8000:8000 automatic-reporting
```
7 changes: 7 additions & 0 deletions build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/bin/bash
pip install -r requirements.txt
npm install
npm run build -w report
npm run build -w frontend
pkill -f "node report/ssr-dist/server.js"
node report/ssr-dist/server.js & uvicorn main:app --reload
79 changes: 0 additions & 79 deletions config.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,86 +35,7 @@ def get_config_value(name: str) -> str | None:
SANEAMENTO_DOCS_URL = get_config_value("SANEAMENTO_DOCS_URL")
HIDRAULICA_DOCS_URL = get_config_value("HIDRAULICA_DOCS_URL")

MACROTEMAS = {
"demografia": {
"nome": "Demografia",
"docs_url": DEMOGRAFIA_DOCS_URL,
"docs_env": "DEMOGRAFIA_DOCS_URL",
"csv_url": DEMOGRAFIA_CSV_URL,
"csv_env": "DEMOGRAFIA_CSV_URL",
},
"educacao": {
"nome": "Educação",
"docs_url": EDUCACAO_DOCS_URL,
"docs_env": "EDUCACAO_DOCS_URL",
"csv_url": EDUCACAO_CSV_URL,
"csv_env": "EDUCACAO_CSV_URL",
},
"saude": {
"nome": "Saúde",
"docs_url": SAUDE_DOCS_URL,
"docs_env": "SAUDE_DOCS_URL",
"csv_url": SAUDE_CSV_URL,
"csv_env": "SAUDE_CSV_URL",
},
"economia-renda": {
"nome": "Economia e Renda",
"docs_url": ECONOMIA_RENDA_DOCS_URL,
"docs_env": "ECONOMIA_RENDA_DOCS_URL",
"csv_url": ECONOMIA_RENDA_CSV_URL,
"csv_env": "ECONOMIA_RENDA_CSV_URL",
},
"saneamento": {
"nome": "Saneamento",
"docs_url": SANEAMENTO_DOCS_URL,
"docs_env": "SANEAMENTO_DOCS_URL",
"csv_url": SANEAMENTO_CSV_URL,
"csv_env": "SANEAMENTO_CSV_URL",
},
"hidraulica": {
"nome": "Hidráulica",
"docs_url": HIDRAULICA_DOCS_URL,
"docs_env": "HIDRAULICA_DOCS_URL",
"csv_url": HIDRAULICA_CSV_URL,
"csv_env": "HIDRAULICA_CSV_URL",
},
}

MACROTEMA_SECOES = {
"demografia": {
"numero": "01",
"titulo": "Demografia",
"aliases": ["demografia"],
},
"educacao": {
"numero": "02",
"titulo": "Educação",
"aliases": ["educacao", "educação"],
},
"saude": {
"numero": "03",
"titulo": "Saúde",
"aliases": ["saude", "saúde"],
},
"economia-renda": {
"numero": "04",
"titulo": "Economia e Renda",
"aliases": ["economia", "economia e renda"],
},
"saneamento": {
"numero": "05",
"titulo": "Infraestrutura e Saneamento",
"aliases": ["saneamento", "infraestrutura e saneamento"],
},
"hidraulica": {
"numero": "06",
"titulo": "Segurança Hídrica",
"aliases": ["hidraulica", "hidráulica", "seguranca hidrica", "segurança hídrica"],
},
}

OUTPUT_DIR = BASE_DIR / "output"
CITIES_FILE = BASE_DIR / "citys.txt"

def resolve_csv_source(source: str | None, env_name: str = "CSV_URL") -> str | Path:
if not source:
Expand Down
Loading
Loading