ESTABILIDADE DO SISTEMA 1
This commit is contained in:
parent
688b6e4a0b
commit
928c0dddfd
Binary file not shown.
Binary file not shown.
@ -35,6 +35,11 @@
|
||||
<main id="top" class="site-main">
|
||||
<section class="hero-section">
|
||||
<div class="container">
|
||||
<div class="text-center mb-5">
|
||||
<a href="{% url 'sequential_generator' %}" class="btn btn-dark btn-lg rounded-pill px-5 shadow-lg border-info" style="background: #0f172a; border-width: 2px;">
|
||||
<i class="bi bi-cpu-fill text-info me-2"></i> ABRIR GERADOR SEQUENCIAL INTELIGENTE IA
|
||||
</a>
|
||||
</div>
|
||||
<div class="row align-items-center g-5">
|
||||
<div class="col-lg-6">
|
||||
<div class="eyebrow">Inteligencia matematica aplicada</div>
|
||||
|
||||
299
core/templates/core/sequential_generator.html
Normal file
299
core/templates/core/sequential_generator.html
Normal file
@ -0,0 +1,299 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container-fluid py-4" style="background: #0f172a; min-height: 100vh; color: #f8fafc;">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-lg-10">
|
||||
<div class="card bg-slate-800 border-0 shadow-lg p-4" style="background: #1e293b; border-radius: 20px;">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<div>
|
||||
<h2 class="display-6 fw-bold mb-0 text-white">Gerador Sequencial Inteligente IA</h2>
|
||||
<p class="text-slate-400">Motor Autônomo de Probabilidades Matemáticas</p>
|
||||
</div>
|
||||
<a href="{% url 'home' %}" class="btn btn-outline-light rounded-pill px-4">Voltar ao Início</a>
|
||||
</div>
|
||||
|
||||
<div class="row g-3 mb-4">
|
||||
<div class="col-md-4">
|
||||
<label class="form-label text-slate-300">Selecione a Loteria:</label>
|
||||
<select id="lottery-select" class="form-select bg-slate-900 text-white border-slate-700 shadow-none">
|
||||
<option value="">--- Selecione ---</option>
|
||||
{% for l in loterias %}
|
||||
<option value="{{ l.name }}">{{ l.get_name_display }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-8 d-flex align-items-end gap-2">
|
||||
<button id="btn-start" class="btn btn-success btn-lg flex-grow-1 rounded-pill fw-bold shadow-sm" disabled>
|
||||
<i class="bi bi-play-fill"></i> INICIAR
|
||||
</button>
|
||||
<button id="btn-pause" class="btn btn-warning btn-lg flex-grow-1 rounded-pill fw-bold shadow-sm d-none">
|
||||
<i class="bi bi-pause-fill"></i> PAUSAR
|
||||
</button>
|
||||
<button id="btn-up" class="btn btn-secondary btn-lg rounded-circle shadow-sm">
|
||||
<i class="bi bi-arrow-up"></i>
|
||||
</button>
|
||||
<button id="btn-down" class="btn btn-secondary btn-lg rounded-circle shadow-sm">
|
||||
<i class="bi bi-arrow-down"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Barra de Stats IA -->
|
||||
<div id="stats-bar" class="row g-2 mb-4 d-none">
|
||||
<div class="col-md-3">
|
||||
<div class="p-3 rounded bg-slate-900 text-center border-start border-success border-4">
|
||||
<small class="d-block text-muted">Sequências Geradas</small>
|
||||
<span id="count-total" class="h4 fw-bold">0</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="p-3 rounded bg-slate-900 text-center border-start border-info border-4">
|
||||
<small class="d-block text-muted">Elite Verde Detectada</small>
|
||||
<span id="count-hot" class="h4 fw-bold">0</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="p-3 rounded bg-slate-900 text-center border-start border-danger border-4">
|
||||
<small class="d-block text-muted">Radar IA: Anulados</small>
|
||||
<span id="count-annulled" class="h4 fw-bold">0</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="p-3 rounded bg-slate-900 text-center border-start border-emerald border-4">
|
||||
<small class="d-block text-muted">IA Radar: Resgatados</small>
|
||||
<span id="count-reclaimed" class="h4 fw-bold">0</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Viewport do Motor -->
|
||||
<div class="generator-viewport p-3 bg-slate-950 rounded-4 shadow-inner" style="background: #020617; min-height: 500px; max-height: 600px; overflow-y: auto; border: 1px solid #334155;">
|
||||
<div id="sequence-container" class="d-flex flex-column gap-3">
|
||||
<div class="text-center text-slate-500 py-5">
|
||||
<i class="bi bi-cpu display-1 mb-3 d-block"></i>
|
||||
<p>Aguardando comando do Motor de IA...</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 p-3 rounded-3 bg-slate-900 border border-slate-800">
|
||||
<h6 class="text-slate-400 small mb-2">Legenda do Motor IA:</h6>
|
||||
<div class="d-flex gap-4 flex-wrap">
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<span class="badge" style="background: linear-gradient(135deg, #198754, #28a745); width: 20px; height: 20px;"></span>
|
||||
<span class="small">Elite Verde (Alta Chance)</span>
|
||||
</div>
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<span class="badge bg-danger" style="width: 20px; height: 20px;"></span>
|
||||
<span class="small">Anulado Frio (Evite)</span>
|
||||
</div>
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<span class="badge reclaimed-pulse" style="background: #10b981; width: 20px; height: 20px; box-shadow: 0 0 10px #10b981;"></span>
|
||||
<span class="small">IA Radar: Resgatado do Anulado</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.bg-slate-800 { background: #1e293b; }
|
||||
.bg-slate-900 { background: #0f172a; }
|
||||
.bg-slate-950 { background: #020617; }
|
||||
.text-slate-300 { color: #cbd5e1; }
|
||||
.text-slate-400 { color: #94a3b8; }
|
||||
.text-slate-500 { color: #64748b; }
|
||||
.border-slate-700 { border-color: #334155; }
|
||||
.border-slate-800 { border-color: #1e293b; }
|
||||
.border-emerald { border-color: #10b981; }
|
||||
|
||||
.reclaimed-pulse {
|
||||
animation: pulse-green 1.5s infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse-green {
|
||||
0% { transform: scale(1); box-shadow: 0 0 0 0 rgba(16, 185, 129, 0.7); }
|
||||
70% { transform: scale(1.1); box-shadow: 0 0 0 10px rgba(16, 185, 129, 0); }
|
||||
100% { transform: scale(1); box-shadow: 0 0 0 0 rgba(16, 185, 129, 0); }
|
||||
}
|
||||
|
||||
.sequence-row {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
justify-content: center;
|
||||
padding: 12px;
|
||||
background: #0f172a;
|
||||
border-radius: 12px;
|
||||
border: 1px solid #1e293b;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.sequence-row:hover {
|
||||
background: #1e293b;
|
||||
transform: translateX(5px);
|
||||
}
|
||||
|
||||
.num-ball {
|
||||
width: 45px;
|
||||
height: 45px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 50%;
|
||||
font-weight: bold;
|
||||
font-size: 1.2rem;
|
||||
background: #334155;
|
||||
color: white;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.num-elite {
|
||||
background: linear-gradient(135deg, #198754, #28a745);
|
||||
box-shadow: 0 0 10px rgba(25, 135, 84, 0.5);
|
||||
}
|
||||
|
||||
.num-annulled {
|
||||
background: #dc3545;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.num-reclaimed {
|
||||
background: #10b981;
|
||||
animation: pulse-green 1.5s infinite;
|
||||
box-shadow: 0 0 15px #10b981;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
let generatorRunning = false;
|
||||
let lotteryData = null;
|
||||
let currentStartNum = 1;
|
||||
let totalGenerated = 0;
|
||||
let countHot = 0;
|
||||
let countAnnulled = 0;
|
||||
let countReclaimed = 0;
|
||||
let animationId = null;
|
||||
|
||||
const container = document.getElementById("sequence-container");
|
||||
const btnStart = document.getElementById("btn-start");
|
||||
const btnPause = document.getElementById("btn-pause");
|
||||
const lotterySelect = document.getElementById("lottery-select");
|
||||
const viewport = document.querySelector(".generator-viewport");
|
||||
|
||||
lotterySelect.addEventListener("change", async (e) => {
|
||||
const key = e.target.value;
|
||||
if (!key) {
|
||||
btnStart.disabled = true;
|
||||
return;
|
||||
}
|
||||
const resp = await fetch(`/api/lottery-info/${key}/`);
|
||||
lotteryData = await resp.json();
|
||||
btnStart.disabled = false;
|
||||
document.getElementById("stats-bar").classList.remove("d-none");
|
||||
resetGenerator();
|
||||
});
|
||||
|
||||
function resetGenerator() {
|
||||
generatorRunning = false;
|
||||
btnStart.classList.remove("d-none");
|
||||
btnPause.classList.add("d-none");
|
||||
container.innerHTML = "";
|
||||
currentStartNum = 1;
|
||||
totalGenerated = 0;
|
||||
countHot = 0;
|
||||
countAnnulled = 0;
|
||||
countReclaimed = 0;
|
||||
updateStats();
|
||||
if (animationId) cancelAnimationFrame(animationId);
|
||||
}
|
||||
|
||||
function updateStats() {
|
||||
document.getElementById("count-total").innerText = totalGenerated.toLocaleString();
|
||||
document.getElementById("count-hot").innerText = countHot.toLocaleString();
|
||||
document.getElementById("count-annulled").innerText = countAnnulled.toLocaleString();
|
||||
document.getElementById("count-reclaimed").innerText = countReclaimed.toLocaleString();
|
||||
}
|
||||
|
||||
function generateChunk() {
|
||||
if (!generatorRunning) return;
|
||||
|
||||
const nToDraw = lotteryData.numbers_to_draw;
|
||||
const maxNum = lotteryData.max_number;
|
||||
|
||||
// Geramos 3 sequências por frame para suavidade
|
||||
for (let i = 0; i < 3; i++) {
|
||||
let sequence = [];
|
||||
for (let j = 0; j < nToDraw; j++) {
|
||||
let val = ((currentStartNum + j - 1) % maxNum) + 1;
|
||||
sequence.push(val);
|
||||
|
||||
// Stats
|
||||
if (lotteryData.reclaimed_numbers.includes(val)) countReclaimed++;
|
||||
else if (lotteryData.elite_greens.includes(val)) countHot++;
|
||||
else if (lotteryData.annulled_numbers.includes(val)) countAnnulled++;
|
||||
}
|
||||
currentStartNum += nToDraw;
|
||||
renderSequence(sequence);
|
||||
totalGenerated++;
|
||||
}
|
||||
|
||||
updateStats();
|
||||
// Auto-scroll para baixo
|
||||
viewport.scrollTop = viewport.scrollHeight;
|
||||
animationId = requestAnimationFrame(generateChunk);
|
||||
}
|
||||
|
||||
function renderSequence(numbers) {
|
||||
const row = document.createElement("div");
|
||||
row.className = "sequence-row";
|
||||
|
||||
numbers.forEach(n => {
|
||||
const ball = document.createElement("div");
|
||||
ball.className = "num-ball";
|
||||
ball.innerText = n.toString().padStart(2, "0");
|
||||
|
||||
if (lotteryData.reclaimed_numbers.includes(n)) {
|
||||
ball.classList.add("num-reclaimed");
|
||||
} else if (lotteryData.elite_greens.includes(n)) {
|
||||
ball.classList.add("num-elite");
|
||||
} else if (lotteryData.annulled_numbers.includes(n)) {
|
||||
ball.classList.add("num-annulled");
|
||||
}
|
||||
|
||||
row.appendChild(ball);
|
||||
});
|
||||
|
||||
// Limita o DOM para performance (mantém as últimas 40)
|
||||
if (container.children.length > 40) {
|
||||
container.removeChild(container.firstChild);
|
||||
}
|
||||
container.appendChild(row);
|
||||
}
|
||||
|
||||
btnStart.addEventListener("click", () => {
|
||||
if (!lotteryData) return;
|
||||
generatorRunning = true;
|
||||
btnStart.classList.add("d-none");
|
||||
btnPause.classList.remove("d-none");
|
||||
generateChunk();
|
||||
});
|
||||
|
||||
btnPause.addEventListener("click", () => {
|
||||
generatorRunning = false;
|
||||
btnPause.classList.add("d-none");
|
||||
btnStart.classList.remove("d-none");
|
||||
if (animationId) cancelAnimationFrame(animationId);
|
||||
});
|
||||
|
||||
document.getElementById("btn-up").addEventListener("click", () => {
|
||||
viewport.scrollBy({ top: -300, behavior: "smooth" });
|
||||
});
|
||||
|
||||
document.getElementById("btn-down").addEventListener("click", () => {
|
||||
viewport.scrollBy({ top: 300, behavior: "smooth" });
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
@ -9,4 +9,6 @@ urlpatterns = [
|
||||
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'),
|
||||
path('gerador-sequencial/', views.sequential_generator, name='sequential_generator'),
|
||||
path('api/lottery-info/<str:lottery_key>/', views.lottery_info_api, name='lottery_info_api'),
|
||||
]
|
||||
|
||||
@ -308,3 +308,53 @@ def live_math(request):
|
||||
except Exception as e:
|
||||
return JsonResponse({"error": str(e)}, status=500)
|
||||
return JsonResponse({"error": "Método inválido"}, status=405)
|
||||
|
||||
def sequential_generator(request):
|
||||
"""Página do Gerador Sequencial Inteligente."""
|
||||
loterias = Lottery.objects.all()
|
||||
return render(request, "core/sequential_generator.html", {"loterias": loterias})
|
||||
|
||||
def lottery_info_api(request, lottery_key):
|
||||
"""Retorna informações de IA para uma loteria específica via JSON."""
|
||||
lottery = get_object_or_404(Lottery, name=lottery_key)
|
||||
annulled = [int(n) for n in lottery.annulled_numbers.split(',') if n]
|
||||
|
||||
# Pegamos os sorteios para o Radar de Reclamação
|
||||
draws_db = DrawResult.objects.filter(lottery=lottery)
|
||||
draw_lists = [[int(n) for n in d.numbers.split(',')] for d in draws_db]
|
||||
|
||||
if not draw_lists:
|
||||
# Mock se vazio
|
||||
frequency = {n: random.randint(1, 10) for n in range(1, lottery.max_number + 1)}
|
||||
else:
|
||||
frequency = Counter(number for draw in draw_lists for number in draw)
|
||||
|
||||
# Lógica de Elite Verde (Top 25% dos disponíveis)
|
||||
available_numbers = [n for n in range(1, lottery.max_number + 1) if n not in annulled]
|
||||
sorted_by_freq = sorted(available_numbers, key=lambda n: frequency.get(n, 0), reverse=True)
|
||||
hot_count = max(6, int(len(available_numbers) * 0.25))
|
||||
elite_greens = sorted_by_freq[:hot_count]
|
||||
|
||||
# IA Radar de Reclamação
|
||||
last_seen_all = {}
|
||||
for i, draw in enumerate(reversed(draw_lists)):
|
||||
for num in draw:
|
||||
if num not in last_seen_all:
|
||||
last_seen_all[num] = i
|
||||
|
||||
reclaimed = []
|
||||
for n in annulled:
|
||||
freq = frequency.get(n, 0)
|
||||
delay = last_seen_all.get(n, len(draw_lists))
|
||||
reclaim_score = (freq * 0.6) + (delay * 0.4)
|
||||
if reclaim_score > (max(frequency.values() or [1]) * 0.8):
|
||||
reclaimed.append(n)
|
||||
|
||||
return JsonResponse({
|
||||
"name": lottery.get_name_display(),
|
||||
"max_number": lottery.max_number,
|
||||
"numbers_to_draw": lottery.numbers_to_draw,
|
||||
"elite_greens": elite_greens,
|
||||
"annulled_numbers": [n for n in annulled if n not in reclaimed],
|
||||
"reclaimed_numbers": reclaimed,
|
||||
})
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user