From 24c53fb469596c7248a99598368f9ca604824795 Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Fri, 20 Feb 2026 01:16:05 +0000 Subject: [PATCH] Autosave: 20260220-011604 --- core/__pycache__/models.cpython-311.pyc | Bin 3488 -> 3623 bytes core/__pycache__/urls.cpython-311.pyc | Bin 1315 -> 1543 bytes core/__pycache__/views.cpython-311.pyc | Bin 33208 -> 49879 bytes .../views.cpython-311.pyc.140359459233328 | 0 core/migrations/0003_alter_lottery_name.py | 18 ++ .../0003_alter_lottery_name.cpython-311.pyc | Bin 0 -> 1154 bytes core/models.py | 5 + core/templates/core/full_report.html | 136 +++++++++ core/templates/core/results_ia.html | 72 ++++- core/templates/core/sequential_generator.html | 13 +- core/urls.py | 2 + core/views.py | 287 ++++++++++++++++-- 12 files changed, 484 insertions(+), 49 deletions(-) create mode 100644 core/__pycache__/views.cpython-311.pyc.140359459233328 create mode 100644 core/migrations/0003_alter_lottery_name.py create mode 100644 core/migrations/__pycache__/0003_alter_lottery_name.cpython-311.pyc create mode 100644 core/templates/core/full_report.html diff --git a/core/__pycache__/models.cpython-311.pyc b/core/__pycache__/models.cpython-311.pyc index 1003669f61fc993ce34613be0007b966c2820458..8a5c19b95d3aa644b7457b86b068698d2e5bbf49 100644 GIT binary patch delta 371 zcmZ1=ytY!6@Ot&~oGILXN6Z0|?Z*hjem_Tu! zl+48Vl+^g*{GyW7Djt{2M1_=8g8=j3*-cy3paMpF>sHu)o$ z4x`CrIqoEgs2N1Gn_ENK6T}n%5z-(+5Jd2U2zwZzIr$p*Rz~~DJv=%JvojyN=J-Q{R0Cg U(UI1Z^ARNe1tDoL`3bKx0IzX000000 diff --git a/core/__pycache__/urls.cpython-311.pyc b/core/__pycache__/urls.cpython-311.pyc index 717d172b25eb6217c498d4158291b555602a0345..34dcb8b6bd84d01b79d37b1b1d6cbdc02128d800 100644 GIT binary patch delta 343 zcmZ3?)y|{7oR^o20SMSPP0xJG%)sy%#DM_;DC6^`jq0t86F0E(OQtes@xi21q$Vy9 z)szMb@xz5=*03!D8nYURAt0S6N+3lxm_bu+^ESpF#`-GNqSWHjoRY+p{9^r-{PMh< z{KOP}o6NittDO9jlGLKg_{?4kme%&qSTzk zlKi5~eEnP8X{9+i@kOZx`9&punu52uQ?e5C()0C7i*kyKKu#%Q0}-qY43iU>?b(Zj zKs@2ebC?6Tq<~CDATAEu{Ebz86`1udw)jkmTiOYTyRJA_<^D01mBS*#H0l delta 109 zcmZqYSCI_+ja!CM{G6He2>gJU!vWx;BM7jBy8n{8QNDL?r0FIp%uK)l5 diff --git a/core/__pycache__/views.cpython-311.pyc b/core/__pycache__/views.cpython-311.pyc index 40277495febcb258436940c9d8f2e313e84ae804..625c65c7253e83f18ecfab0efd3801e3d8eccf46 100644 GIT binary patch delta 16675 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 D;5^Ff delta 5090 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 diff --git a/core/__pycache__/views.cpython-311.pyc.140359459233328 b/core/__pycache__/views.cpython-311.pyc.140359459233328 new file mode 100644 index 0000000..e69de29 diff --git a/core/migrations/0003_alter_lottery_name.py b/core/migrations/0003_alter_lottery_name.py new file mode 100644 index 0000000..cc424a2 --- /dev/null +++ b/core/migrations/0003_alter_lottery_name.py @@ -0,0 +1,18 @@ +# Generated by Django 5.2.7 on 2026-02-19 22:09 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0002_lottery_ai_predictions_lottery_analysis_window'), + ] + + operations = [ + migrations.AlterField( + model_name='lottery', + name='name', + field=models.CharField(choices=[('mega_sena', 'Mega-Sena'), ('quina', 'Quina'), ('dupla_sena', 'Dupla Sena'), ('lotomania', 'Lotomania'), ('lotofacil', 'Lotofácil'), ('timemania', 'Timemania'), ('dia_de_sorte', 'Dia de Sorte'), ('federal', 'Federal'), ('super_sete', 'Super Sete'), ('maismilionaria', '+Milionária')], max_length=50, unique=True), + ), + ] diff --git a/core/migrations/__pycache__/0003_alter_lottery_name.cpython-311.pyc b/core/migrations/__pycache__/0003_alter_lottery_name.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..76a3f81061fb70cb42fd5f63a8a46f4336f37cf7 GIT binary patch literal 1154 zcmZuvy-yTD6rb7K-Mif!M$t&6xe$Y#9~^;}m>3Bf1QK(^m}@4(&fMLc`*F1 z#bXV@`5b^f#1O+i3UCVtM$5p+K(7%qJ|kA*xK}DBeFyaG%4?OF*+g~gREO(^as$zk zG!ao4D?5l7_hYY^sYhq%oUZ}cLmag*LoI{h4sMkU#LZqI3YKP?v3up=9MnO~{Dzsu z?1S=683&b{K2)nP2ZXuGSuPZTJkyILSF_X8(=)`6l7!1GLIvqd&V-k%zNSO!Z^a@e z8zN-UhAI#9l^N22*IlUQ1iV8@%tN~EECYPr1PHvfo{Eqv>zy9-p|G^?4-?&ajcdb9 z2Z}}k4Fy%sQUP^k&9|v1{8V3`4z&;W!PT)u1bjGWwSd4^nV^Jm5=S!O+tqnNYmC>L z+Jk7h%^8=}SLKBP0M3omK9{fo$ak9>gRVULRzO7@2p{f|Ns5I44UsJI)@;-Tx@is zfH%^$G)&S4-{fAJM6$6F$&YcLdc2_&>Za+{S+$2~(}F0{!?_NcwHs9*WGP_t4umBV^8>_k&+EkC9FWCnUCbXuM}3Fxvi wH#q7S@(H*Y{`ftZtb{R!J>dEgn*8_6>?*c1^sm` literal 0 HcmV?d00001 diff --git a/core/models.py b/core/models.py index d82b5f3..131f1b2 100644 --- a/core/models.py +++ b/core/models.py @@ -17,6 +17,11 @@ class Lottery(models.Model): ('dupla_sena', 'Dupla Sena'), ('lotomania', 'Lotomania'), ('lotofacil', 'Lotofácil'), + ('timemania', 'Timemania'), + ('dia_de_sorte', 'Dia de Sorte'), + ('federal', 'Federal'), + ('super_sete', 'Super Sete'), + ('maismilionaria', '+Milionária'), ] name = models.CharField(max_length=50, choices=LOTTERY_TYPES, unique=True) min_number = models.IntegerField(default=1) diff --git a/core/templates/core/full_report.html b/core/templates/core/full_report.html new file mode 100644 index 0000000..5870235 --- /dev/null +++ b/core/templates/core/full_report.html @@ -0,0 +1,136 @@ +{% extends "base.html" %} + +{% block content %} +
+
+
+ + +
+
+

+ Relatório IA Global +

+

Análise Probabilística de Todos os Jogos Gerados em Tempo Real

+
+
+
+ ATUALIZADO: {{ current_time|date:"H:i:s" }} +
+
+ + + Voltar ao Supercomputador + +
+
+
+ +
+ {% for item in reports %} +
+
+
+

+ {{ item.lottery.get_name_display }} +

+ Concurso {{ item.last_concurso }} +
+
+
+ +
+
+ Índice de Precisão IA +
+
+ + + + +
+

{{ item.prob_index }}%

+
+
+
+

Baseado em {{ item.total_analyzed }} sorteios históricos

+
+
+ + +
+
+ Números de Elite do Funil: +
+
+ {% for n in item.elite_numbers %} +
+ {{ n }} +
+ {% endfor %} +
+
+
+ TENDÊNCIA QUENTE (TOP 5) + +
+
+ {% for n, freq in item.hot_top %} +
+
{{ n }}
+
{{ freq }}x
+
+ {% endfor %} +
+
+
+
+
+ +
+
+ {% empty %} +
+

Nenhum dado processado ainda. Inicie o Supercomputador para gerar o relatório.

+
+ {% endfor %} +
+ + +
+

+ + Este relatório é gerado através de processamento assíncrono e análise matemática pura. + As probabilidades são recalculadas a cada novo acesso. +

+
+
+
+
+ + +{% endblock %} diff --git a/core/templates/core/results_ia.html b/core/templates/core/results_ia.html index 4fc503f..5feefd8 100644 --- a/core/templates/core/results_ia.html +++ b/core/templates/core/results_ia.html @@ -1,4 +1,4 @@ -{% extends 'core/base.html' %} +{% extends 'base.html' %} {% load static %} {% block content %} @@ -33,9 +33,9 @@ {% if item.last_result %}
{% for n in item.last_numbers %} -
- {{ n|stringformat:"02d" }} +
+ {{ n }}
{% endfor %}
@@ -96,8 +96,8 @@
{% for num, freq in item.stats.most_common %} - - {{ num|stringformat:"02d" }} + + {{ num }} {% endfor %}
@@ -108,8 +108,8 @@
{% for stat in item.stats.most_delayed %} - - {{ stat.number|stringformat:"02d" }} ({{ stat.delay }}c) + + {{ stat.number }} ({{ stat.delay }}c) {% endfor %}
@@ -128,6 +128,47 @@
+ +
+
+
+
+ FUNIL DE ELITE AUTOMÁTICO +
+

Anulação automática de baixa probabilidade ativa

+
+ PRECISÃO MÁXIMA +
+ + {% if item.funnel_numbers %} +
+ {% for n in item.funnel_numbers %} +
+ {{ n }} +
+ {% endfor %} +
+ +
+ + + BAIXAR TXT + + +
+ {% else %} +

+ Filtrando números em tempo real... +

+ {% endif %} +
+
@@ -143,10 +184,10 @@ {% if item.predicted_numbers %}
{% for n in item.predicted_numbers %} -
- {{ n|stringformat:"02d" }} + {{ n }}
{% endfor %}
@@ -195,10 +236,17 @@ box-shadow: 0 0 15px rgba(16, 185, 129, 0.4); transition: transform 0.2s, box-shadow 0.2s; } - .ball-pred:hover { + .shadow-glow-gold { + box-shadow: 0 0 15px rgba(234, 179, 8, 0.4); + transition: transform 0.2s, box-shadow 0.2s; + } + .ball-pred:hover, .ball-elite:hover { transform: scale(1.15); box-shadow: 0 0 25px rgba(16, 185, 129, 0.7); } + .ball-elite:hover { + box-shadow: 0 0 25px rgba(234, 179, 8, 0.7); + } .card { transition: transform 0.3s; } diff --git a/core/templates/core/sequential_generator.html b/core/templates/core/sequential_generator.html index 4fc8007..1c7525e 100644 --- a/core/templates/core/sequential_generator.html +++ b/core/templates/core/sequential_generator.html @@ -18,6 +18,9 @@
IA NARRANDO
+ + ABRIR RELATÓRIO + Sair do Sistema
@@ -119,10 +122,10 @@
FUNIL DE ANULAÇÃO
- 0 / 31 + 0 / 60
-

Selecione até 31 números para o Supercomputador ignorar totalmente nas sequências.

+

Selecione até 60 números para o Supercomputador ignorar totalmente nas sequências.

Selecione o jogo acima
@@ -220,7 +223,7 @@ let detectedHits = []; // { type, sequence, hits } let animationId = null; let annulledFunnel = new Set(); - const MAX_FUNNEL = 31; + const MAX_FUNNEL = 60; const synth = window.speechSynthesis; let voiceEnabled = true; @@ -293,7 +296,7 @@ annulledFunnel.delete(i); } else { if (annulledFunnel.size >= MAX_FUNNEL) { - speak("Limite do funil atingido. Máximo de 31 dezenas."); + speak("Limite do funil atingido. Máximo de 60 dezenas."); return; } ball.classList.add("active"); @@ -436,7 +439,7 @@ generatorRunning = true; btnStart.classList.add("d-none"); btnPause.classList.remove("d-none"); - speak("Motor Sequencial Iniciado. Aplicando Funil de Trinta e uma Dezenas."); + speak("Motor Sequencial Iniciado. Aplicando Funil de Sessenta Dezenas."); generateChunk(); }); diff --git a/core/urls.py b/core/urls.py index c8cf561..3829068 100644 --- a/core/urls.py +++ b/core/urls.py @@ -12,4 +12,6 @@ urlpatterns = [ path('gerador-sequencial/', views.sequential_generator, name='sequential_generator'), path('api/lottery-info//', views.lottery_info_api, name='lottery_info_api'), path('resultados/', views.lottery_results, name='lottery_results'), + path('resultados/download//', views.download_funnel, name='download_funnel'), + path('supercomputador/relatorio/', views.full_report, name='full_report'), ] diff --git a/core/views.py b/core/views.py index 6972e5e..9e52477 100644 --- a/core/views.py +++ b/core/views.py @@ -372,6 +372,11 @@ def sync_results(): 'dupla_sena': 'duplasena', 'lotomania': 'lotomania', 'lotofacil': 'lotofacil', + 'timemania': 'timemania', + 'dia_de_sorte': 'diadesorte', + 'federal': 'federal', + 'super_sete': 'supersete', + 'maismilionaria': 'maismilionaria', } for lottery in loterias: @@ -391,9 +396,13 @@ def sync_results(): date_str = data.get('data') draw_date = datetime.strptime(date_str, "%d/%m/%Y").date() - # Processa os números (garante ordenação e limpeza) + # Processa os números (preserva zeros à esquerda para Federal/Super Sete) numbers_list = data.get('dezenas', []) - numbers_str = ",".join([str(int(n)) for n in numbers_list]) + # Se for Federal ou Super Sete, mantemos a formatação original (zeros à esquerda) + if lottery.name in ['federal', 'super_sete']: + numbers_str = ",".join([str(n).zfill(5 if lottery.name == 'federal' else 1) for n in numbers_list]) + else: + numbers_str = ",".join([str(int(n)) for n in numbers_list]) DrawResult.objects.create( lottery=lottery, @@ -405,13 +414,75 @@ def sync_results(): except Exception as e: print(f"Erro ao sincronizar {lottery.name}: {e}") +from django.http import JsonResponse, HttpResponse +import json + +def download_funnel(request, lottery_id): + """Gera um arquivo TXT com a elite do funil para download.""" + lottery = get_object_or_404(Lottery, id=lottery_id) + all_draws = DrawResult.objects.filter(lottery=lottery).order_by('-draw_number') + + if not all_draws.exists(): + return HttpResponse("Ainda não há dados para gerar o funil.") + + # Repete a lógica do funil para garantir sincronia total + current_draw = all_draws.first() + all_numbers_flat = [] + for d in all_draws: + all_numbers_flat.extend([n.strip() for n in d.numbers.split(',')]) + + frequency = Counter(all_numbers_flat) + last_seen = {} + for i, d in enumerate(all_draws): + for n in d.numbers.split(','): + n = n.strip() + if n not in last_seen: last_seen[n] = i + + if lottery.name == 'federal': + available = [str(i).zfill(5) for i in range(100000)] + elif lottery.name == 'super_sete': + available = [str(i) for i in range(10)] + else: + available = [str(i).zfill(2) for i in range(1, lottery.max_number + 1)] + + last_nums = [n.strip() for n in current_draw.numbers.split(',')] + funnel_scores = [] + for n in available: + if n in last_nums: continue + score = (frequency.get(n, 0) * 0.6) + (last_seen.get(n, all_draws.count()) * 0.4) + funnel_scores.append((n, score)) + + funnel_scores.sort(key=lambda x: x[1], reverse=True) + elite = [x[0] for x in funnel_scores[:lottery.numbers_to_draw]] + elite.sort() + + content = f"--- SUPERCOMPUTADOR IA V4.0 ---\n" + content += f"FUNIL DE PROBABILIDADES: {lottery.get_name_display()}\n" + content += f"DATA: {datetime.now().strftime('%d/%m/%Y %H:%M')}\n" + content += f"PRÓXIMO CONCURSO: {current_draw.draw_number + 1}\n" + content += f"-------------------------------\n" + content += f"NÚMEROS DE ELITE: {' - '.join(elite)}\n" + content += f"-------------------------------\n" + content += f"Use com responsabilidade matemática.\n" + + response = HttpResponse(content, content_type='text/plain') + filename = f"funil_{lottery.name}_{current_draw.draw_number + 1}.txt" + response['Content-Disposition'] = f'attachment; filename="{filename}"' + return response + def lottery_results(request): """Central de Resultados com Lógica de Análise Estatística Profunda IA V4.0.""" - # Tenta sincronizar novos resultados ao acessar a página - try: - sync_results() - except: - pass + # Otimização: Só sincroniza se passaram mais de 10 minutos desde o último sorteio salvo + # ou se o banco estiver muito vazio, para evitar lentidão no carregamento. + last_sync = request.session.get('last_sync_time') + now_ts = timezone.now().timestamp() + + if not last_sync or (now_ts - last_sync) > 600: # 10 minutos + try: + sync_results() + request.session['last_sync_time'] = now_ts + except: + pass loterias = Lottery.objects.all() results_data = [] @@ -422,61 +493,148 @@ def lottery_results(request): last_draws = all_draws[:10] if all_draws.exists(): - current_draw = all_draws[0] - current_numbers = [int(n) for n in current_draw.numbers.split(',')] + current_draw = all_draws.first() + current_numbers_raw = current_draw.numbers.split(',') + current_numbers = [] + for n in current_numbers_raw: + if lottery.name == 'federal': + current_numbers.append(n.zfill(5)) + elif lottery.name == 'super_sete': + current_numbers.append(n) + else: + current_numbers.append(str(int(n)).zfill(2)) # --- MOTOR DE ANÁLISE ESTATÍSTICA --- all_numbers_flat = [] for d in all_draws: - all_numbers_flat.extend([int(n) for n in d.numbers.split(',')]) + all_numbers_flat.extend([n.strip() for n in d.numbers.split(',')]) frequency = Counter(all_numbers_flat) + + # Cálculo de Atraso (Delay) - Movido para cima para evitar erros no Funil + last_seen = {} + for i, d in enumerate(all_draws): + nums = [n.strip() for n in d.numbers.split(',')] + for n in nums: + if n not in last_seen: + last_seen[n] = i + + # --- NOVO: FUNIL DE PROBABILIDADES AUTOMÁTICO IA V4.0 --- + # O Funil anula números automaticamente até encontrar a elite matemática + available_for_funnel = [] + if lottery.name == 'federal': + # Para Federal, o funil gera bilhetes de elite + available_for_funnel = [str(i).zfill(5) for i in range(100000)] + elif lottery.name == 'super_sete': + available_for_funnel = [str(i) for i in range(10)] + else: + available_for_funnel = [str(i).zfill(2) for i in range(1, lottery.max_number + 1)] + + # 1. Anula números do último sorteio (Filtro de Repetição) + last_nums = [n.strip() for n in current_draw.numbers.split(',')] + funnel_step1 = [n for n in available_for_funnel if n not in last_nums] + + # 2. Ranking de Probabilidade (Frequência + Atraso) + funnel_scores = [] + max_analyzed = all_draws.count() + for n in funnel_step1: + freq = frequency.get(n, 0) + delay = last_seen.get(n, max_analyzed) + # Score: 60% peso para frequência, 40% para tempo sem sair + score = (freq * 0.6) + (delay * 0.4) + funnel_scores.append((n, score)) + + # 3. Anulação Automática: Ordena e pega apenas a elite + funnel_scores.sort(key=lambda x: x[1], reverse=True) + + # Para a elite, queremos exatamente o número de dezenas do jogo (ou 6 para Mega) + elite_count = lottery.numbers_to_draw + funnel_elite = [x[0] for x in funnel_scores[:elite_count]] + funnel_elite.sort() + + # Formatação visual para o template + funnel_display = [] + for n in funnel_elite: + if lottery.name == 'federal': funnel_display.append(n.zfill(5)) + elif lottery.name == 'super_sete': funnel_display.append(n) + else: funnel_display.append(n.zfill(2)) + # Top 10 mais frequentes - most_common = frequency.most_common(10) + most_common = [] + for num, freq in frequency.most_common(10): + if lottery.name == 'federal': + most_common.append((num.zfill(5), freq)) + elif lottery.name == 'super_sete': + most_common.append((num, freq)) + else: + most_common.append((num.zfill(2), freq)) # Cálculo de Atraso (Delay) last_seen = {} for i, d in enumerate(all_draws): - nums = [int(n) for n in d.numbers.split(',')] + nums = [n.strip() for n in d.numbers.split(',')] for n in nums: if n not in last_seen: - last_seen[n] = i # i é o número de concursos atrás + last_seen[n] = i # Pegar as 5 dezenas mais atrasadas delays = [] - for n in range(1, lottery.max_number + 1): - delays.append({'number': n, 'delay': last_seen.get(n, len(all_draws))}) + if lottery.name == 'federal': + # Para federal, analisamos os números que já saíram nos prêmios + keys = list(frequency.keys()) + for n in keys: + delays.append({'number': n.zfill(5), 'delay': last_seen.get(n, len(all_draws))}) + elif lottery.name == 'super_sete': + for n in range(10): + delays.append({'number': str(n), 'delay': last_seen.get(str(n), len(all_draws))}) + else: + for n in range(1, lottery.max_number + 1): + num_str = str(n).zfill(2) + delays.append({'number': num_str, 'delay': last_seen.get(num_str, len(all_draws))}) most_delayed = sorted(delays, key=lambda x: x['delay'], reverse=True)[:5] # Equilíbrio Par/Ímpar do último sorteio - evens = len([n for n in current_numbers if n % 2 == 0]) - odds = len(current_numbers) - evens + evens = len([n for n in current_numbers_raw if int(n) % 2 == 0]) + odds = len(current_numbers_raw) - evens # --- Lógica de Determinação Matemática V4.0 --- - random.seed(sum(current_numbers) + current_draw.draw_number) + # (Simplificada para suportar Federal e Super Sete de forma coerente) + random.seed(sum([int(n) for n in current_numbers_raw]) + current_draw.draw_number) predicted_numbers = [] - k_inheritance = max(1, len(current_numbers)//3) - inheritance = random.sample(current_numbers, k=k_inheritance) - for n in inheritance: - shift = random.choice([-1, 0, 1]) - new_n = n + shift - if 1 <= new_n <= lottery.max_number and new_n not in predicted_numbers: - predicted_numbers.append(new_n) - available = [n for n in range(1, lottery.max_number + 1) if n not in predicted_numbers] - while len(predicted_numbers) < lottery.numbers_to_draw: - next_n = random.choice(available) - predicted_numbers.append(next_n) - available.remove(next_n) - - predicted_numbers.sort() + if lottery.name == 'federal': + # Predição para Federal: 5 novos bilhetes baseados em tendência + for _ in range(5): + pred = str(random.randint(0, 99999)).zfill(5) + predicted_numbers.append(pred) + elif lottery.name == 'super_sete': + # 7 colunas (0-9) + for _ in range(7): + predicted_numbers.append(str(random.randint(0, 9))) + else: + k_inheritance = max(1, len(current_numbers_raw)//3) + inheritance = random.sample([int(n) for n in current_numbers_raw], k=k_inheritance) + for n in inheritance: + shift = random.choice([-1, 0, 1]) + new_n = n + shift + if 1 <= new_n <= lottery.max_number and str(new_n).zfill(2) not in predicted_numbers: + predicted_numbers.append(str(new_n).zfill(2)) + + available = [str(n).zfill(2) for n in range(1, lottery.max_number + 1) if str(n).zfill(2) not in predicted_numbers] + while len(predicted_numbers) < lottery.numbers_to_draw: + next_n = random.choice(available) + predicted_numbers.append(next_n) + available.remove(next_n) + predicted_numbers.sort() results_data.append({ 'lottery': lottery, 'last_result': current_draw, 'last_numbers': current_numbers, 'predicted_numbers': predicted_numbers, + 'funnel_numbers': funnel_display, + 'funnel_raw': ",".join(funnel_elite), 'next_draw_number': current_draw.draw_number + 1, 'history': last_draws, 'stats': { @@ -497,3 +655,68 @@ def lottery_results(request): "results": results_data, "current_time": timezone.now() }) + +def full_report(request): + """Gera um relatório completo de probabilidades de todas as loterias em uma página dedicada.""" + loterias = Lottery.objects.all() + report_data = [] + + for lottery in loterias: + all_draws = DrawResult.objects.filter(lottery=lottery).order_by('-draw_number') + + if all_draws.exists(): + current_draw = all_draws.first() + + # Cálculo de Frequência + all_numbers_flat = [] + for d in all_draws: + all_numbers_flat.extend([n.strip() for n in d.numbers.split(',')]) + frequency = Counter(all_numbers_flat) + + # Cálculo de Atraso (Delay) + last_seen = {} + for i, d in enumerate(all_draws): + for n in d.numbers.split(','): + n = n.strip() + if n not in last_seen: last_seen[n] = i + + # Construção do Funil de Elite para o Relatório + if lottery.name == 'federal': + available = [str(i).zfill(5) for i in range(100000)] + elif lottery.name == 'super_sete': + available = [str(i) for i in range(10)] + else: + available = [str(i).zfill(2) for i in range(1, lottery.max_number + 1)] + + last_nums = [n.strip() for n in current_draw.numbers.split(',')] + funnel_scores = [] + max_analyzed = all_draws.count() + + for n in available: + if n in last_nums: continue + freq = frequency.get(n, 0) + delay = last_seen.get(n, max_analyzed) + score = (freq * 0.6) + (delay * 0.4) + funnel_scores.append((n, score)) + + funnel_scores.sort(key=lambda x: x[1], reverse=True) + elite = [x[0] for x in funnel_scores[:lottery.numbers_to_draw]] + elite.sort() + + # Probabilidade Matemática (Baseada no Score do Top 1) + top_score = funnel_scores[0][1] if funnel_scores else 0 + prob_index = min(99.9, (top_score / (max(frequency.values() or [1]) * 1.5)) * 100) + + report_data.append({ + 'lottery': lottery, + 'last_concurso': current_draw.draw_number, + 'elite_numbers': elite, + 'prob_index': round(prob_index, 2), + 'total_analyzed': max_analyzed, + 'hot_top': frequency.most_common(5) + }) + + return render(request, "core/full_report.html", { + "reports": report_data, + "current_time": timezone.now() + })