个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证Rotas a pé e de carro em São Paulo que equilibram tempo e exposição a ocorrências criminais registradas (SSP-SP).
翻译准备中
取自仓库 README
正在加载完整 README。
查看完整 README ↗Rotas a pé, de bicicleta ou de carro em São Paulo que equilibram tempo de deslocamento e exposição a ocorrências criminais registradas pela SSP-SP.
Para cada trajeto, o SampaNav calcula até três opções e mostra quanto cada uma reduz a exposição em troca de quanto tempo a mais:
| Perfil | Peso do risco (α) | Para quem |
|---|---|---|
| Mais rápida | 0 | menor tempo, sem considerar risco |
| Equilibrada | 2 | compromisso entre tempo e exposição |
| Mais segura | 6 | menor exposição, aceitando desvios maiores |
Alternativas que não reduzem a exposição em pelo menos 5% são descartadas, e o app diz quando nenhum desvio vale a pena. A rota selecionada é colorida trecho a trecho pelo risco, e a camada de calor mostra o risco por região em cada período do dia.
Capturas geradas com o backend real e os dados de setembro/2024 a agosto/2026
(660 mil ocorrências), sobre o mapa do OpenFreeMap usado no app. Para regerar:
tools/screenshots.
A interface usa a linguagem da sinalização do Metrô de São Paulo: cada perfil de rota é
uma linha numerada, e o passo a passo aparece como uma sequência de estações. As cores
das linhas nunca representam risco; o risco segue a escala própria, do verde ao vermelho.
Detalhes em docs/IDENTIDADE.md.
Rotas
Navegação
Uso no dia a dia
Leia antes de usar ou apresentar os resultados.
.xlsx):
https://www.ssp.sp.gov.br/estatistica/consultas. Cada ano ocupa cerca de
126 a 196 MB.flowchart LR
subgraph Offline["Pipeline mensal (GitHub Actions)"]
SSP[("SSP-SP<br>planilhas .xlsx")] --> R[build_risk<br>grade H3 de risco]
GS[("GeoSampa<br>iluminação")] --> R
OSM[("OpenStreetMap<br>via OSMnx")] --> G[build_graph<br>grafos a pé e de carro]
R --> G
G --> V{validate_data}
V -- ok --> REL[("GitHub Release<br>sampanav-data.tar.gz")]
end
REL -- docker build --> API
subgraph Render["API (Render, 512 MB)"]
API[FastAPI + igraph<br>Dijkstra por perfil]
end
subgraph Vercel["Frontend (Vercel)"]
FE[HTML/CSS/JS sem build<br>MapLibre + h3-js]
end
FE -- "HTTPS /api" --> API
API -- geocodificação --> PH[("Photon")]
1 + 0,3 · (1 − luz), em que luz é a densidade de postes do GeoSampa (0 a 1).tempo × (1 + α · risco). A exposição de
uma rota é Σ comprimento × risco, em km equivalentes. Penalidades mais fortes (r², r³)
foram testadas e geravam rotas mais longas sem reduzir a exposição total.O contrato completo entre as partes (formatos de dados, esquema da API, regras de
risco) está em docs/ARQUITETURA.md.
| Métrica | Valor |
|---|---|
| Ocorrências no modelo | 660 mil (set/2024 a ago/2026) |
| Memória da API com os três modos | ~330 MB (limite do plano: 512 MB) |
| Carga dos grafos | ~1 s em CPU comum |
| Tempo de cálculo (3 perfis) | 60 a 300 ms; até ~700 ms em 20 km a pé com parada |
Resposta de /api/routes (gzip) | 2 a 21 KB |
| Testes | 136 no backend, 65 unitários no frontend, smoke test no navegador |
Execute os comandos na raiz do projeto:
uv sync
uv run python -m pipeline.download_ssp --years 2024 2025 2026
uv run python -m pipeline.build_risk
uv run python -m pipeline.build_graph
uv run uvicorn backend.app.main:app --reload
uv sync instala por padrão os grupos pipeline e dev. Os pontos de iluminação
do GeoSampa são baixados pelo build_risk e cacheados em data/raw/.
Depois, abra http://localhost:8000 no navegador. O uvicorn usa a porta 8000 por padrão.
Refazer só o risco, depois de reconstruir o modelo de risco, sem reprocessar
o OSM (reutiliza graph_{mode}.npz já existente):
uv run python -m pipeline.build_graph --risk-only
Testes e lint (os mesmos rodam no CI):
uv run ruff check .
uv run pytest
Testes do frontend (Node 22, sem dependências) e smoke test no navegador, em modo mock:
node --test 'frontend/tests/unit/*.test.mjs'
node frontend/tests/smoke/smoke.mjs # com o frontend servido em localhost:8000 e Playwright instalado
Capturas de tela do README: tools/screenshots/run.sh <pasta_dos_dados> sobe a
API com os dados, desenha o mapa base, captura as cenas e otimiza as imagens em
docs/img/ (detalhes em tools/screenshots/README.md).
Desenvolvimento só do frontend: abra http://localhost:8000/?mock=1. Nesse
modo, frontend/js/api.js usa respostas falsas de frontend/js/mock.js em vez
de chamar a API, o que permite trabalhar na interface sem os dados processados.
Todos os endpoints ficam sob o prefixo /api. O formato detalhado de cada um
está em docs/ARQUITETURA.md, seção 5.
GET /api/health: status do servidor e tamanho dos grafos carregados.GET /api/meta: metadados do modelo de risco, perfis e períodos disponíveis.GET /api/geocode?q=...: busca de endereços dentro de São Paulo.GET /api/reverse?lat=...&lon=...: endereço mais próximo de um ponto (ou null).POST /api/routes: calcula as rotas entre origem e destino (com via opcional), para
um modo (walk, drive ou bike) e período. Cada rota traz steps (manobras),
exposure_by_period e level_by_period.GET /api/risk?bbox=...&mode=...&period=...: células H3 com risco, para a camada de calor.Três serviços gratuitos:
frontend/ (vercel.json, sem build). A URL
da API fica em frontend/config.js (apiBase, hoje https://sampanav-api.onrender.com); em
localhost o app usa a mesma origem (dev local).Dockerfile e render.yaml) no plano free,
com 512 MB de RAM. Dorme após 15 min sem uso e leva cerca de 1 a 2 min para acordar.
As origens permitidas vêm de ALLOWED_ORIGINS./api/routes, 60 em /api/geocode, 120 em /api/risk; acima disso, 429 com
Retry-After). Os cálculos de rota rodam um por vez; se a fila passar de 20 s, a API
responde 503 e o frontend tenta de novo. Variáveis: SAMPANAV_RATE_ROUTES,
SAMPANAV_RATE_GEOCODE, SAMPANAV_RATE_RISK (0 desliga) e
SAMPANAV_ROUTE_QUEUE_TIMEOUT (segundos). Cada rota gera uma linha de log com modo,
período, distância e tempos de cálculo e de fila, sem coordenadas.pipeline/package_data.py gera sampanav-data.tar.gz
(grafos, risco e metadados) e sampanav-inputs.tar.gz (pontos de iluminação). O
Dockerfile baixa o sampanav-data.tar.gz da Release mais recente durante o build.pipeline/validate_data.py: volume mínimo, queda máxima de 30% frente à Release
anterior, data mais recente que não regride, risco entre 0 e 1 em todos os modos e
períodos) e só então publica nova Release. Com o segredo
opcional RENDER_DEPLOY_HOOK_URL, também dispara o deploy no Render.main e em pull requests roda ruff check e pytest, os testes
unitários do frontend, o docker build da imagem e um smoke test com Playwright no modo mock.Depois do deploy, siga o guia pós-deploy: ligar o frontend à API, conferir CORS e o limite por IP, e configurar a atualização mensal.
Dados: gere os pacotes e publique a primeira Release.
uv run python -m pipeline.package_data
gh release create data-AAAA-MM-DD data/dist/sampanav-data.tar.gz data/dist/sampanav-inputs.tar.gz --latest
Render: em New → Blueprint, escolha o repositório (ele usa o render.yaml).
Preencha ALLOWED_ORIGINS com a URL da Vercel, sem barra no final. Se ainda não
a tiver, ajuste a variável depois do passo 3.
Vercel: importe o repositório (o vercel.json já aponta para frontend/) e
defina apiBase em frontend/config.js, com a URL do Render (ex.:
https://sampanav-api.onrender.com).
Opcional: em Settings → Secrets and variables → Actions, crie
RENDER_DEPLOY_HOOK_URL com a deploy hook do serviço no Render.
SampaNav/
├── pyproject.toml, uv.lock # projeto Python único (uv)
├── Dockerfile, render.yaml # deploy da API (Render)
├── vercel.json # deploy do frontend (Vercel)
├── .github/workflows/ # ci.yml e data-refresh.yml (mensal)
├── docs/
│ ├── ARQUITETURA.md # contrato entre pipeline, API e frontend
│ ├── LICENCAS-DADOS.md # licenças e atribuições dos dados
│ ├── GUIA-POS-DEPLOY.md # checklist depois do deploy
│ └── img/ # capturas usadas neste README
├── tools/screenshots/ # gera as capturas com dados reais (Playwright)
├── pipeline/ # scripts offline
│ ├── config.py # pesos, categorias, períodos, caminhos e parâmetros v2
│ ├── download_ssp.py # baixa as planilhas da SSP-SP
│ ├── build_risk.py # ocorrências -> grade H3 de risco
│ ├── footfall.py # proxy de movimento pela malha a pé
│ ├── lighting.py # pontos de iluminação (GeoSampa) -> densidade H3
│ ├── evaluate.py # diagnóstico do modelo de risco
│ ├── validate_data.py # checagens antes de publicar a Release
│ ├── build_graph.py # rede OSM + risco -> grafos por modo
│ └── package_data.py # empacota os dados para a Release
├── backend/
│ ├── app/
│ │ ├── main.py # FastAPI; também serve o frontend em /
│ │ ├── routing.py # carga dos grafos e cálculo de rotas
│ │ ├── steps.py # manobras e instruções em português
│ │ ├── geocode.py # proxy para o Photon, com bbox de SP
│ │ └── ratelimit.py # limite de requisições por IP
│ └── tests/
├── frontend/ # HTML, CSS e JS estáticos, sem build
│ ├── index.html
│ ├── config.js # apiBase (URL da API em produção)
│ ├── img/, css/ # logo e estilos
│ └── js/
│ ├── api.js # chamadas à API (ou mock, com ?mock=1)
│ ├── mock.js # respostas falsas para desenvolvimento
│ ├── map.js # mapa, rotas e camada de calor
│ ├── ui.js # painel, busca, cartões de rota e recentes
│ ├── nav.js # navegação com GPS
│ ├── navui.js # banner de navegação
│ ├── icons.js # ícones das manobras
│ ├── speech.js # instruções faladas
│ ├── gpx.js # exportação em GPX
│ ├── history.js, urlstate.js # histórico local e estado na URL
│ ├── pwa.js # registro do service worker e aviso de versão nova
│ ├── format.js, main.js
│ ├── sw.js, manifest.webmanifest # PWA
│ └── tests/ # testes unitários (node --test) e smoke test
└── data/ # gitignored
├── raw/ # planilhas da SSP, OSM e pontos de iluminação
├── processed/ # saídas do pipeline (parquet, npz, json)
└── dist/ # pacotes para a Release
O código está sob a licença MIT (veja LICENSE). Os dados de terceiros
(OpenStreetMap, SSP-SP, GeoSampa, Photon, OpenFreeMap) seguem as próprias licenças e
exigências de atribuição, descritas em docs/LICENCAS-DADOS.md.
O histórico de versões está em CHANGELOG.md.
O SampaNav nasceu de um protótipo desenvolvido em hackathon (DustNav), feito pela equipe original do projeto. A versão atual é uma reescrita focada em roteamento com dados criminais reais de São Paulo.