Spaces:
Running
Running
| # Tutorial passo a passo — Safe Bet AI Precision v2 | |
| ## 1. O que esta versão precisa | |
| O projeto roda em **Docker** e não usa GPU nem API de IA. | |
| Obrigatório: | |
| - um Space Docker que possa executar compute; | |
| - token gratuito do football-data.org; | |
| - API key gratuita do The Odds API; | |
| - uma conta no cron-job.org; | |
| - três Secrets no Hugging Face. | |
| Recomendado: | |
| - Dataset privado no Hugging Face para guardar histórico/cache. | |
| --- | |
| # 2. Criar as chaves | |
| ## football-data.org | |
| Crie uma conta e copie seu token. | |
| Secret: | |
| ```text | |
| FOOTBALL_DATA_TOKEN | |
| ``` | |
| ## The Odds API | |
| Crie uma conta e copie sua API key. | |
| Secret: | |
| ```text | |
| ODDS_API_KEY | |
| ``` | |
| ## Segredo do cron | |
| Crie uma senha grande e aleatória, por exemplo com um gerenciador de senhas. | |
| Secret: | |
| ```text | |
| CRON_SECRET | |
| ``` | |
| Não use uma senha curta e não coloque o valor na URL. | |
| --- | |
| # 3. Enviar o projeto para o Space | |
| O Space deve usar SDK Docker. | |
| O `README.md` já possui: | |
| ```yaml | |
| sdk: docker | |
| app_port: 7860 | |
| ``` | |
| Extraia o ZIP e envie **todo o conteúdo da pasta** para a raiz do repositório do Space. | |
| A raiz precisa ficar assim: | |
| ```text | |
| Dockerfile | |
| README.md | |
| requirements.txt | |
| app/ | |
| tests/ | |
| ... | |
| ``` | |
| Não coloque uma pasta extra como: | |
| ```text | |
| safe-bet-ai-v2-precision/safe-bet-ai-v2-precision/app | |
| ``` | |
| O `Dockerfile` deve estar na raiz. | |
| --- | |
| # 4. Secrets no Hugging Face | |
| No Space: | |
| ```text | |
| Settings | |
| → Variables and secrets | |
| → New secret | |
| ``` | |
| Crie exatamente: | |
| ```text | |
| FOOTBALL_DATA_TOKEN | |
| ODDS_API_KEY | |
| CRON_SECRET | |
| ``` | |
| Valores são as chaves criadas anteriormente. | |
| --- | |
| # 5. Variables recomendadas | |
| Em **Variables**: | |
| ```text | |
| ODDS_REGIONS=eu | |
| HISTORY_DAYS=240 | |
| SCAN_HORIZON_HOURS=36 | |
| MIN_SCAN_INTERVAL_MINUTES=180 | |
| MIN_SAFE_SCORE=76 | |
| MIN_PROBABILITY=0.64 | |
| MIN_CONSERVATIVE_PROBABILITY=0.57 | |
| MIN_BOOKMAKERS=3 | |
| MIN_NAME_SCORE=82 | |
| TOP_PICKS_LIMIT=10 | |
| TZ_DISPLAY=America/Sao_Paulo | |
| ``` | |
| Ligas: | |
| ```text | |
| ODDS_SPORT_KEYS=soccer_epl,soccer_efl_champ,soccer_germany_bundesliga,soccer_italy_serie_a,soccer_spain_la_liga,soccer_france_ligue_one,soccer_brazil_campeonato,soccer_netherlands_eredivisie,soccer_portugal_primeira_liga,soccer_uefa_champs_league | |
| ``` | |
| Não acrescente ligas arbitrárias. A versão Precision só aceita ligas com mapeamento explícito para o football-data.org. | |
| --- | |
| # 6. Build | |
| Depois do upload, acompanhe: | |
| ```text | |
| Space → Logs | |
| ``` | |
| O final esperado contém Uvicorn na porta 7860. | |
| Teste: | |
| ```text | |
| https://SEU-USUARIO-SEU-SPACE.hf.space/api/health | |
| ``` | |
| Você deve receber JSON com: | |
| ```json | |
| { | |
| "ok": true, | |
| "ready": true, | |
| "version": "2.2-precision" | |
| } | |
| ``` | |
| Confira também: | |
| ```text | |
| configured.football_data = true | |
| configured.odds_api = true | |
| configured.cron_secret = true | |
| ``` | |
| Se algum estiver `false`, o nome do Secret está errado ou não foi salvo. | |
| --- | |
| # 7. Primeiro scan manual | |
| Use: | |
| ```bash | |
| curl -X POST \ | |
| 'https://SEU-USUARIO-SEU-SPACE.hf.space/api/admin/scan?wait=1' \ | |
| -H 'X-Cron-Secret: SEU_CRON_SECRET' | |
| ``` | |
| ## Atenção no primeiro scan | |
| A versão v2 pode buscar a temporada atual e a anterior quando a amostra atual é pequena. | |
| O football-data.org tem limite gratuito por minuto e o bot respeita esse limite. Por isso o **primeiro bootstrap pode levar cerca de 1–2 minutos ou mais**, dependendo das ligas e retries. | |
| Não interrompa só porque demorou alguns segundos. | |
| Depois abra: | |
| ```text | |
| https://SEU-USUARIO-SEU-SPACE.hf.space/ | |
| ``` | |
| --- | |
| # 8. Como saber se o scan funcionou | |
| Abra: | |
| ```text | |
| /api/state | |
| ``` | |
| Campos importantes: | |
| ```text | |
| status | |
| model_version | |
| summary | |
| picks | |
| radar | |
| tickets | |
| performance | |
| providers | |
| warnings | |
| rejected_preview | |
| ``` | |
| Estados normais: | |
| ```text | |
| status = ok | |
| status = degraded # scan concluído, mas algum provider teve falha parcial | |
| model_version = 2.2-precision | |
| ``` | |
| Se `picks` estiver vazio, veja `radar` e `rejected_preview`. | |
| Um dia sem apostas SAFE não é considerado erro. O `radar` mostra as melhores | |
| leituras não aprovadas, mas elas não entram nos bilhetes nem no histórico. | |
| --- | |
| # 9. Configurar cron-job.org | |
| Crie um job. | |
| ## URL | |
| ```text | |
| https://SEU-USUARIO-SEU-SPACE.hf.space/api/cron/daily | |
| ``` | |
| ## Método | |
| ```text | |
| POST | |
| ``` | |
| ## Horário | |
| Sugestão: | |
| ```text | |
| 08:00 | |
| America/Sao_Paulo | |
| ``` | |
| ## Header | |
| Adicione: | |
| ```text | |
| X-Cron-Secret: SEU_CRON_SECRET | |
| ``` | |
| Não coloque o segredo como query string. | |
| O endpoint responde rapidamente com HTTP `202` e o scan continua dentro do Space. | |
| --- | |
| # 10. Frequência recomendada | |
| Comece com **1 scan completo por dia**. O endpoint de cron também bloqueia repetições muito próximas (`MIN_SCAN_INTERVAL_MINUTES`, padrão 180) para preservar quota. | |
| O projeto consulta uma vez o mercado H2H por liga ativa. A lista gratuita `/sports` é consultada antes para evitar gastar quota com ligas fora de temporada. | |
| Veja a quota restante em: | |
| ```text | |
| /api/state | |
| → providers.odds_api.quota.remaining | |
| ``` | |
| Se a quota estiver baixa, o Quota Guardian deixa de consultar novas ligas. | |
| Não configure cron a cada 5 ou 10 minutos. | |
| --- | |
| # 11. Backup persistente — altamente recomendado | |
| Crie um Dataset privado no Hugging Face, por exemplo: | |
| ```text | |
| SEU_USUARIO/safe-bet-ai-state | |
| ``` | |
| Crie um token com permissão de escrita nesse Dataset. | |
| Adicione Secrets: | |
| ```text | |
| HF_WRITE_TOKEN | |
| HF_DATASET_REPO | |
| ``` | |
| Exemplo de valor: | |
| ```text | |
| HF_DATASET_REPO=SEU_USUARIO/safe-bet-ai-state | |
| ``` | |
| O bot passa a guardar: | |
| ```text | |
| state/state.json | |
| state/history.json | |
| state/matches.json | |
| ``` | |
| O `matches.json` é importante na v2 porque evita reconstruir toda a base histórica após cada reinício. | |
| Se o Dataset não estiver configurado, o bot continua funcionando, mas pode precisar refazer o bootstrap quando o disco local for perdido. | |
| --- | |
| # 12. Painel | |
| Cada seleção mostra: | |
| - Probabilidade final. | |
| - Probabilidade conservadora. | |
| - SafeScore. | |
| - Odd de referência. | |
| - Odd justa. | |
| - Qualidade. | |
| - Confiabilidade. | |
| - Número de casas no consenso. | |
| - Dispersão de mercado. | |
| - Matching de nomes. | |
| - Dixon-Coles/Poisson. | |
| - Elo. | |
| - Forma. | |
| - Calibração forward. | |
| - Edge. | |
| O Radar de Palpites mostra até cinco prognósticos que foram modelados, mas não | |
| passaram por todos os controles. Seus cards sempre aparecem como **EM OBSERVAÇÃO | |
| — NÃO APROVADA** e devem ser usados somente para acompanhar o mercado. | |
| ## Odd Betano | |
| Digite manualmente a odd encontrada na Betano. | |
| O painel calcula: | |
| ```text | |
| EV = probabilidade_estimada × odd_betano - 1 | |
| ``` | |
| A odd de referência das APIs não é tratada como se fosse a odd da sua conta. | |
| --- | |
| # 13. Como o Risk Gate rejeita uma partida | |
| Motivos possíveis: | |
| ```text | |
| histórico insuficiente | |
| matching ambíguo | |
| poucas casas | |
| mercado disperso | |
| qualidade de dados baixa | |
| probabilidade baixa | |
| probabilidade conservadora baixa | |
| modelos divergentes | |
| modelo muito distante do mercado | |
| odd fora da faixa | |
| preço fraco | |
| movimento de mercado contra | |
| seleção mudou desde o scan anterior | |
| SafeScore baixo | |
| ``` | |
| Não reduza os filtros só para gerar mais palpites. | |
| --- | |
| # 14. Bilhetes | |
| O painel tenta criar: | |
| ```text | |
| SAFE alvo ~2.5, até 3 pernas | |
| BALANCEADO alvo ~4.0, até 4 pernas | |
| FREEBET alvo ~10.0, até 4 pernas | |
| ``` | |
| Ele mostra se o alvo realmente foi atingido. | |
| Também mostra probabilidade sob stress quando existem seleções da mesma competição. | |
| A odd 10 não é tratada como “segura”; ela continua tendo risco elevado. | |
| --- | |
| # 15. Forward tracking e calibração | |
| O sistema guarda uma recomendação por evento. | |
| Quando o jogo acaba: | |
| 1. tenta localizar o resultado na competição correta; | |
| 2. verifica ambos os times; | |
| 3. liquida win/loss; | |
| 4. atualiza métricas. | |
| Depois de amostra suficiente da **mesma versão do modelo**, uma calibração fraca pode corrigir probabilidades futuras em no máximo ±5 pontos percentuais. | |
| Isso evita “aprendizado” instável em poucas apostas. | |
| --- | |
| # 16. Métricas | |
| O painel/estado inclui: | |
| ```text | |
| win_rate | |
| roi | |
| profit_units | |
| brier_score | |
| log_loss | |
| ece | |
| calibration_gap | |
| max_drawdown_units | |
| ``` | |
| Não avalie o modelo somente por taxa de acerto. | |
| Uma taxa alta pode existir apenas porque as odds são muito baixas. | |
| --- | |
| # 17. Testes antes de editar | |
| Em uma máquina com Python: | |
| ```bash | |
| pip install -r requirements-dev.txt | |
| python -m compileall -q app tests | |
| pytest -q | |
| ``` | |
| A revisão v2.2 passou: | |
| ```text | |
| 44 passed | |
| ``` | |
| Também foram testados: | |
| ```text | |
| / | |
| /api/health | |
| /api/state | |
| ``` | |
| com HTTP 200. | |
| --- | |
| # 18. Diagnóstico | |
| ## `401 X-Cron-Secret inválido` | |
| Header errado ou Secret diferente. | |
| ## `configuration_error` | |
| FOOTBALL_DATA_TOKEN ou ODDS_API_KEY ausente. | |
| ## primeiro scan demorado | |
| Pode ser o bootstrap histórico respeitando rate limit. | |
| ## zero palpites | |
| Veja o Radar e `rejected_preview`. O Radar informa a melhor leitura de cada jogo, | |
| mas não transforma retorno esperado negativo ou baixa confiança em aposta SAFE. | |
| ## matching ambíguo | |
| Não force o nome. A rejeição existe para impedir mistura entre equipes. | |
| ## quota Odds API baixa | |
| Reduza ligas ou frequência. | |
| ## Space reiniciou | |
| Com Dataset de backup, o cache volta automaticamente. Sem backup, o histórico pode precisar ser reconstruído. | |
| --- | |
| # 19. Regras para manter a precisão | |
| 1. Não transforme SafeScore em probabilidade. | |
| 2. Não force dez seleções. | |
| 3. Não desative o market prior. | |
| 4. Não use `fullTime` para 1X2 de mata-mata quando `regularTime` existir. | |
| 5. Não misture ligas no matching. | |
| 6. Não considere uma única bookmaker como “consenso” no modo padrão. | |
| 7. Não aumente frequência sem acompanhar quota. | |
| 8. Não faça martingale. | |
| 9. Não use scraping da Betano como dependência crítica. | |
| 10. Mantenha `model_version` quando alterar regras estatísticas; ao fazer mudança grande, crie uma nova versão. | |
| 11. Rode os testes depois de cada alteração. | |
| Leia também `PRECISION_REVIEW.md`. | |