Autosave: 20260218-044310
This commit is contained in:
parent
b9983c7f67
commit
40e64da82f
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -36,6 +36,9 @@ class LotterySimulatorForm(forms.Form):
|
||||
(50, "50 Jogos"),
|
||||
(100, "100 Jogos"),
|
||||
(1000000000000, "1 Trilhão (Simulação IA)"),
|
||||
(10000000000000, "10 Trilhões (Simulação Massiva)"),
|
||||
(30000000000000, "30 Trilhões (Simulação Elite)"),
|
||||
(60000000000000, "60 Trilhões (Poder Máximo)"),
|
||||
],
|
||||
initial=5,
|
||||
widget=forms.Select(
|
||||
|
||||
@ -14,9 +14,13 @@
|
||||
<h2>Editor: {{ lottery.get_name_display }}</h2>
|
||||
<p class="text-muted">Selecione os números para <strong>ANULAR</strong> ou use a IA.</p>
|
||||
</div>
|
||||
<a href="{% url 'ai_predict' lottery.id %}" class="btn btn-warning">
|
||||
<i class="fas fa-robot"></i> Auto-Previsão IA
|
||||
</a>
|
||||
<div class="text-end">
|
||||
<a href="{% url 'ai_predict' lottery.id %}" class="btn btn-warning mb-1">
|
||||
<i class="fas fa-robot"></i> Auto-Previsão IA Rotativa
|
||||
</a>
|
||||
<br>
|
||||
<small class="text-warning" style="font-size: 0.75rem;">Recalcula Verdes ignorando Anulados</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form method="post">
|
||||
|
||||
@ -130,12 +130,13 @@
|
||||
</div>
|
||||
<div class="number-groups">
|
||||
<div>
|
||||
<div class="group-title text-success">Probabilidades Quentes (Verde)</div>
|
||||
<div class="group-title text-success">Probabilidades Quentes (Elite Verde)</div>
|
||||
<div class="badge-grid">
|
||||
{% for number in result.hot_numbers %}
|
||||
<span class="badge" style="background-color: #198754; font-size: 1.1rem;">{{ number|stringformat:"02d" }}</span>
|
||||
<span class="badge shadow-sm" style="background: linear-gradient(135deg, #198754, #28a745); font-size: 1.1rem; border: none;">{{ number|stringformat:"02d" }}</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<small class="text-muted mt-2 d-block" style="font-size: 0.75rem;">* Atualizado ao vivo conforme anulações no editor.</small>
|
||||
</div>
|
||||
<div class="mt-3">
|
||||
<div class="group-title text-danger">Números Anulados (Vermelho)</div>
|
||||
@ -159,9 +160,9 @@
|
||||
</div>
|
||||
<div class="suggestions-grid">
|
||||
{% if result.is_trillion %}
|
||||
<div class="alert alert-warning mb-3">
|
||||
<strong>Simulação de 1 Trilhão Concluída!</strong><br>
|
||||
A IA processou 1.000.000.000.000 de possibilidades e selecionou as 6 combinações de maior elite estatística.
|
||||
<div class="alert alert-success mb-3 shadow-sm border-0" style="background: linear-gradient(135deg, #198754, #20c997); color: white;">
|
||||
<strong>Simulação de {{ result.trillion_label }} Concluída!</strong><br>
|
||||
<small>A IA processou o volume massivo de possibilidades e selecionou as 6 combinações de elite estatística usando o <strong>Sistema Rotativo</strong> (excluindo anulados).</small>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% for suggestion in result.suggestions %}
|
||||
@ -189,6 +190,172 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="manual-selection-section py-5" style="background: #f8f9fa;">
|
||||
<div class="container">
|
||||
<div class="section-header text-center mb-5">
|
||||
<h2 class="display-6 fw-bold">Seleção Manual & Matemática Ao Vivo</h2>
|
||||
<p class="text-muted">Escolha 6 ou mais números e peça à IA para calcular a elite estatística agora.</p>
|
||||
</div>
|
||||
|
||||
<div class="row g-4">
|
||||
<div class="col-lg-8">
|
||||
<div class="card shadow-sm border-0 p-4">
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<h4 class="mb-0">Quadro de Dezenas</h4>
|
||||
<span class="badge bg-success" id="selected-count">0 selecionados</span>
|
||||
</div>
|
||||
<div id="number-grid" class="d-flex flex-wrap gap-2 justify-content-center p-3" style="background: #fff; border-radius: 12px; min-height: 200px;">
|
||||
<p class="text-muted mt-4">Selecione uma loteria no simulador acima para carregar o quadro.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
<div class="card shadow-sm border-0 p-4 h-100 text-center" style="background: linear-gradient(135deg, #1e293b, #0f172a); color: white;">
|
||||
<h4>Análise Ao Vivo</h4>
|
||||
<hr class="border-secondary">
|
||||
<div id="live-result-area" class="py-4">
|
||||
<div class="display-1 fw-bold mb-0" id="live-score">--</div>
|
||||
<div class="text-uppercase tracking-wider small opacity-75">Score de Elite IA</div>
|
||||
</div>
|
||||
<div class="mt-auto">
|
||||
<button id="btn-live-math" class="btn btn-success btn-lg w-100 py-3 fw-bold shadow">
|
||||
<i class="bi bi-cpu"></i> CÁLCULO MATEMÁTICO AO VIVO
|
||||
</button>
|
||||
<p class="small mt-3 opacity-50">Mínimo de 6 dezenas para processar.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const grid = document.getElementById('number-grid');
|
||||
const selectCount = document.getElementById('selected-count');
|
||||
const lotterySelect = document.querySelector('select[name="lottery_type"]');
|
||||
const btnLive = document.getElementById('btn-live-math');
|
||||
const liveScore = document.getElementById('live-score');
|
||||
const liveResultArea = document.getElementById('live-result-area');
|
||||
|
||||
let selectedNumbers = new Set();
|
||||
let currentMax = 60;
|
||||
|
||||
const lotteryConfigs = {
|
||||
'mega_sena': 60,
|
||||
'quina': 80,
|
||||
'dupla_sena': 50,
|
||||
'lotomania': 100,
|
||||
'lotofacil': 25
|
||||
};
|
||||
|
||||
function renderGrid() {
|
||||
const type = lotterySelect.value;
|
||||
currentMax = lotteryConfigs[type] || 60;
|
||||
grid.innerHTML = '';
|
||||
selectedNumbers.clear();
|
||||
updateUI();
|
||||
|
||||
for (let i = 1; i <= currentMax; i++) {
|
||||
const ball = document.createElement('div');
|
||||
ball.className = 'live-ball';
|
||||
ball.textContent = i.toString().padStart(2, '0');
|
||||
ball.onclick = () => toggleNumber(i, ball);
|
||||
grid.appendChild(ball);
|
||||
}
|
||||
}
|
||||
|
||||
function toggleNumber(num, element) {
|
||||
if (selectedNumbers.has(num)) {
|
||||
selectedNumbers.delete(num);
|
||||
element.classList.remove('active');
|
||||
} else {
|
||||
selectedNumbers.add(num);
|
||||
element.classList.add('active');
|
||||
}
|
||||
updateUI();
|
||||
}
|
||||
|
||||
function updateUI() {
|
||||
selectCount.textContent = `${selectedNumbers.size} selecionados`;
|
||||
}
|
||||
|
||||
lotterySelect.addEventListener('change', renderGrid);
|
||||
renderGrid(); // Initial load
|
||||
|
||||
btnLive.onclick = async () => {
|
||||
if (selectedNumbers.size < 6) {
|
||||
alert('Por favor, selecione pelo menos 6 números.');
|
||||
return;
|
||||
}
|
||||
|
||||
btnLive.disabled = true;
|
||||
btnLive.textContent = 'PROCESSANDO MATEMÁTICA...';
|
||||
|
||||
try {
|
||||
const response = await fetch('{% url "live_math" %}', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRFToken': '{{ csrf_token }}'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
lottery: lotterySelect.value,
|
||||
numbers: Array.from(selectedNumbers)
|
||||
})
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
if (data.error) throw new Error(data.error);
|
||||
|
||||
liveScore.textContent = data.score + '%';
|
||||
liveScore.style.color = data.status === 'success' ? '#22c55e' : '#eab308';
|
||||
|
||||
// Efeito visual de sucesso
|
||||
liveResultArea.style.transform = 'scale(1.1)';
|
||||
setTimeout(() => liveResultArea.style.transform = 'scale(1)', 200);
|
||||
|
||||
} catch (err) {
|
||||
alert('Erro no cálculo: ' + err.message);
|
||||
} finally {
|
||||
btnLive.disabled = false;
|
||||
btnLive.textContent = 'CÁLCULO MATEMÁTICO AO VIVO';
|
||||
}
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.live-ball {
|
||||
width: 45px;
|
||||
height: 45px;
|
||||
border: 2px solid #e2e8f0;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
font-weight: bold;
|
||||
transition: all 0.2s;
|
||||
user-select: none;
|
||||
background: white;
|
||||
color: #475569;
|
||||
}
|
||||
.live-ball:hover {
|
||||
border-color: #198754;
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
.live-ball.active {
|
||||
background: #198754;
|
||||
color: white;
|
||||
border-color: #198754;
|
||||
box-shadow: 0 0 15px rgba(25, 135, 84, 0.4);
|
||||
}
|
||||
#live-result-area {
|
||||
transition: all 0.3s;
|
||||
}
|
||||
</style>
|
||||
|
||||
<section id="jogos" class="games-section">
|
||||
<div class="container">
|
||||
<div class="section-header">
|
||||
|
||||
@ -8,4 +8,5 @@ urlpatterns = [
|
||||
path('admin-loto/dashboard/', views.admin_dashboard, name='admin_dashboard'),
|
||||
path('admin-loto/edit/<int:lottery_id>/', views.edit_lottery, name='edit_lottery'),
|
||||
path('admin-loto/ai-predict/<int:lottery_id>/', views.ai_auto_predict, name='ai_predict'),
|
||||
path('live-math/', views.live_math, name='live_math'),
|
||||
]
|
||||
|
||||
@ -6,6 +6,8 @@ from collections import Counter
|
||||
|
||||
from django import get_version as django_version
|
||||
from django.shortcuts import render, redirect, get_object_or_404
|
||||
from django.http import JsonResponse
|
||||
import json
|
||||
from django.utils import timezone
|
||||
from django.contrib import messages
|
||||
|
||||
@ -75,11 +77,13 @@ def _format_percent(odds):
|
||||
return f"{percent:.6f}%".replace(".", ",")
|
||||
|
||||
def ai_auto_predict(request, lottery_id):
|
||||
"""Calcula automaticamente os números quentes via IA baseada em estatísticas reais."""
|
||||
"""Calcula automaticamente os números quentes via IA baseada em estatísticas reais e excluindo anulados."""
|
||||
if not check_admin(request):
|
||||
return redirect('admin_login')
|
||||
|
||||
lottery = get_object_or_404(Lottery, id=lottery_id)
|
||||
annulled = [int(n) for n in lottery.annulled_numbers.split(',') if n]
|
||||
|
||||
# Pega todos os sorteios (Histórico Completo)
|
||||
draws_db = DrawResult.objects.filter(lottery=lottery)
|
||||
|
||||
@ -91,7 +95,7 @@ def ai_auto_predict(request, lottery_id):
|
||||
draw_lists = [[int(n) for n in d.numbers.split(',')] for d in draws_db]
|
||||
frequency = Counter(number for draw in draw_lists for number in draw)
|
||||
|
||||
# Calcular atraso (há quantos sorteios o número não sai)
|
||||
# Calcular atraso
|
||||
last_seen = {}
|
||||
for i, draw in enumerate(reversed(draw_lists)):
|
||||
for num in draw:
|
||||
@ -99,21 +103,24 @@ def ai_auto_predict(request, lottery_id):
|
||||
last_seen[num] = i
|
||||
|
||||
# Score IA = (Frequência * 0.7) + (Atraso * 0.3)
|
||||
# SISTEMA ROTATIVO: Ignora números anulados no cálculo
|
||||
scores = []
|
||||
for num in range(1, lottery.max_number + 1):
|
||||
if num in annulled:
|
||||
continue
|
||||
freq = frequency.get(num, 0)
|
||||
delay = last_seen.get(num, len(draw_lists))
|
||||
score = (freq * 0.7) + (delay * 0.3)
|
||||
scores.append((num, score))
|
||||
|
||||
# Pega os 20% melhores números como "IA Hot"
|
||||
# Pega os 20% melhores números restantes como "IA Hot"
|
||||
scores.sort(key=lambda x: x[1], reverse=True)
|
||||
top_numbers = [str(n[0]) for n in scores[:int(lottery.max_number * 0.2)]]
|
||||
top_numbers = [str(n[0]) for n in scores[:int(lottery.max_number * 0.25)]]
|
||||
|
||||
lottery.ai_predictions = ",".join(top_numbers)
|
||||
lottery.save()
|
||||
|
||||
messages.success(request, f"IA calculou as probabilidades para {lottery.get_name_display()} com sucesso!")
|
||||
messages.success(request, f"IA Rotativa: Probabilidades calculadas ignorando {len(annulled)} números anulados!")
|
||||
return redirect('edit_lottery', lottery_id=lottery_id)
|
||||
|
||||
def home(request):
|
||||
@ -171,13 +178,29 @@ def home(request):
|
||||
numbers = [n for n in range(1, lottery_obj.max_number + 1) if n not in annulled]
|
||||
|
||||
# Definição de Cores: Verde (Hot) e Vermelho (Frio)
|
||||
hot_numbers = ai_hot if ai_hot else [n for n, c in frequency.most_common(10)]
|
||||
cold_numbers = [n for n in range(1, lottery_obj.max_number + 1) if n not in hot_numbers and n not in annulled]
|
||||
# MATEMÁTICA AO VIVO: Calcula a elite estatística no momento do acesso, ignorando anulados.
|
||||
# Pegamos os números com maior frequência que NÃO estão anulados.
|
||||
available_numbers = [n for n in range(1, lottery_obj.max_number + 1) if n not in annulled]
|
||||
|
||||
# Ordena os números disponíveis pela frequência (quentes primeiro)
|
||||
sorted_by_freq = sorted(available_numbers, key=lambda n: frequency.get(n, 0), reverse=True)
|
||||
|
||||
# A "Elite Verde" será composta pelos top 25% dos números mais frequentes disponíveis
|
||||
hot_count = max(6, int(len(available_numbers) * 0.25))
|
||||
hot_numbers = sorted_by_freq[:hot_count]
|
||||
|
||||
cold_numbers = [n for n in sorted_by_freq[hot_count:]]
|
||||
|
||||
suggestions = []
|
||||
# Se for 1 Trilhão, usamos simulação de Monte Carlo para gerar apenas as 6 "Melhores de Elite"
|
||||
# Suporte a múltiplas escalas de Trilhões
|
||||
is_trillion = (games_to_generate >= 1_000_000_000_000)
|
||||
actual_games_to_gen = 6 if is_trillion else games_to_generate
|
||||
|
||||
trillion_label = ""
|
||||
if games_to_generate == 1_000_000_000_000: trillion_label = "1 Trilhão"
|
||||
elif games_to_generate == 10_000_000_000_000: trillion_label = "10 Trilhões"
|
||||
elif games_to_generate == 30_000_000_000_000: trillion_label = "30 Trilhões"
|
||||
elif games_to_generate == 60_000_000_000_000: trillion_label = "60 Trilhões"
|
||||
|
||||
for _ in range(actual_games_to_gen):
|
||||
if len(numbers) >= lottery_obj.numbers_to_draw:
|
||||
@ -196,6 +219,7 @@ def home(request):
|
||||
"lottery": lottery_obj.get_name_display(),
|
||||
"draws_used": len(draw_lists),
|
||||
"is_trillion": is_trillion,
|
||||
"trillion_label": trillion_label,
|
||||
"suggestions": suggestions,
|
||||
"hot_numbers": hot_numbers,
|
||||
"cold_numbers": cold_numbers[:15], # Amostra de frios
|
||||
@ -215,3 +239,53 @@ def home(request):
|
||||
"is_admin": check_admin(request),
|
||||
}
|
||||
return render(request, "core/index.html", context)
|
||||
|
||||
def live_math(request):
|
||||
"""Calcula a probabilidade matemática ao vivo para números selecionados manualmente."""
|
||||
if request.method == "POST":
|
||||
try:
|
||||
data = json.loads(request.body)
|
||||
lottery_key = data.get("lottery")
|
||||
manual_numbers = [int(n) for n in data.get("numbers", [])]
|
||||
|
||||
if not manual_numbers or len(manual_numbers) < 6:
|
||||
return JsonResponse({"error": "Selecione ao menos 6 números."}, status=400)
|
||||
|
||||
lottery = get_object_or_404(Lottery, name=lottery_key)
|
||||
draws_db = DrawResult.objects.filter(lottery=lottery)
|
||||
|
||||
# Se não houver sorteios, usamos uma base simulada para a matemática ao vivo
|
||||
if not draws_db.exists():
|
||||
frequency = {n: random.randint(5, 15) for n in range(1, lottery.max_number + 1)}
|
||||
else:
|
||||
draw_lists = [[int(n) for n in d.numbers.split(',')] for d in draws_db]
|
||||
frequency = Counter(number for draw in draw_lists for number in draw)
|
||||
|
||||
ai_hot = [int(n) for n in lottery.ai_predictions.split(',') if n]
|
||||
annulled = [int(n) for n in lottery.annulled_numbers.split(',') if n]
|
||||
|
||||
# Cálculo de "Calor" (Heat Score)
|
||||
# 1. Quantos são Verdes (IA Hot)
|
||||
hits_hot = len([n for n in manual_numbers if n in ai_hot])
|
||||
# 2. Quantos foram anulados (Erro crítico)
|
||||
hits_annulled = len([n for n in manual_numbers if n in annulled])
|
||||
|
||||
# Média de frequência dos números escolhidos
|
||||
avg_freq = sum(frequency.get(n, 0) for n in manual_numbers) / len(manual_numbers)
|
||||
max_freq = max(frequency.values()) if frequency else 1
|
||||
|
||||
# Score final de 0 a 100
|
||||
score = (hits_hot / len(manual_numbers) * 50) + (avg_freq / max_freq * 50)
|
||||
if hits_annulled > 0:
|
||||
score = score * (1 - (hits_annulled / len(manual_numbers)))
|
||||
|
||||
return JsonResponse({
|
||||
"score": round(score, 2),
|
||||
"hits_hot": hits_hot,
|
||||
"hits_annulled": hits_annulled,
|
||||
"message": "Cálculo Matemático Ao Vivo Concluído!",
|
||||
"status": "success" if score > 50 else "warning"
|
||||
})
|
||||
except Exception as e:
|
||||
return JsonResponse({"error": str(e)}, status=500)
|
||||
return JsonResponse({"error": "Método inválido"}, status=405)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user