diff --git a/core/templates/core/sequential_generator.html b/core/templates/core/sequential_generator.html index 7d1d75a..3d11aa9 100644 --- a/core/templates/core/sequential_generator.html +++ b/core/templates/core/sequential_generator.html @@ -1,96 +1,122 @@ {% extends "base.html" %} {% block content %} -
+
-
-
-
+
+
+ + +
-

Gerador Sequencial Inteligente IA

-

Motor Autônomo de Probabilidades Matemáticas

+

+ Supercomputador IA v4.0 +

+

Análise Matemática Autônoma em Tempo Real

- Voltar ao Início -
- -
-
- - -
-
- - - - +
+
+ IA NARRANDO +
+ Sair do Sistema
- -
-
-
- Sequências Geradas - 0 +
+ +
+
+
+ + +
+
+ + +
+ + +
+
-
-
-
- Elite Verde Detectada - 0 -
-
-
-
- Radar IA: Anulados - 0 -
-
-
-
- IA Radar: Resgatados - 0 -
-
-
- -
-
-
- -

Aguardando comando do Motor de IA...

+ +
+
+
+
+

SISTEMA EM STANDBY

+

Selecione uma loteria para carregar o Funil de Probabilidades

+
+
+
+ + +
+
+
+ SEQUÊNCIAS + 0 +
+
+
+
+ ELITE VERDE + 0 +
+
+
+
+ IA RADAR + 0 +
+
-
-
-
Legenda do Motor IA:
-
-
- - Elite Verde (Alta Chance) + +
+ +
+
+ ANALISADOR DE ELITE +
+
+
Aguardando Processamento...
+
-
- - Anulado Frio (Evite) + + +
+
+
FUNIL DE ANULAÇÃO
+ 0 / 31 +
+
+

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

+
+ +
Selecione o jogo acima
+
+
-
- - IA Radar: Resgatado do Anulado + + +
+
Logs do Supercomputador:
+
+ > Sistema Inicializado...
+ > Aguardando entrada de dados... +
@@ -100,70 +126,66 @@
@@ -173,29 +195,110 @@ let currentStartNum = 1; let totalGenerated = 0; let countHot = 0; - let countAnnulled = 0; let countReclaimed = 0; let animationId = null; + let annulledFunnel = new Set(); + const MAX_FUNNEL = 31; - const container = document.getElementById("sequence-container"); + const synth = window.speechSynthesis; + let voiceEnabled = true; + + function speak(text) { + if (!voiceEnabled || !synth) return; + synth.cancel(); // Para a fala anterior para não encavalar + const utter = new SpeechSynthesisUtterance(text); + utter.lang = 'pt-BR'; + utter.rate = 1.1; + + // Tenta pegar voz feminina + const voices = synth.getVoices(); + const femaleVoice = voices.find(v => v.name.includes('Maria') || v.name.includes('Google português do Brasil')); + if (femaleVoice) utter.voice = femaleVoice; + + utter.onstart = () => document.getElementById("voice-indicator").classList.remove("d-none"); + utter.onend = () => document.getElementById("voice-indicator").classList.add("d-none"); + + const log = document.getElementById("voice-log"); + log.innerHTML += `> IA: ${text}
`; + log.scrollTop = log.scrollHeight; + + synth.speak(utter); + } + + const lotterySelect = document.getElementById("lottery-select"); + const funnelGrid = document.getElementById("funnel-grid"); + const funnelCountLabel = document.getElementById("funnel-count"); const btnStart = document.getElementById("btn-start"); const btnPause = document.getElementById("btn-pause"); - const lotterySelect = document.getElementById("lottery-select"); + const container = document.getElementById("sequence-container"); const viewport = document.querySelector(".generator-viewport"); + const elitePanel = document.getElementById("elite-panel"); lotterySelect.addEventListener("change", async (e) => { const key = e.target.value; - if (!key) { - btnStart.disabled = true; - return; - } + if (!key) return; + + speak(`Iniciando análise para ${key}. Carregando base de dados histórica.`); const resp = await fetch(`/api/lottery-info/${key}/`); lotteryData = await resp.json(); + + setupFunnel(lotteryData.max_number); + updateElitePanel(); btnStart.disabled = false; document.getElementById("stats-bar").classList.remove("d-none"); resetGenerator(); }); + function setupFunnel(max) { + funnelGrid.innerHTML = ""; + annulledFunnel.clear(); + updateFunnelLabel(); + + for (let i = 1; i <= max; i++) { + const ball = document.createElement("div"); + ball.className = "funnel-ball"; + ball.innerText = i.toString().padStart(2, "0"); + + // Pré-carrega os anulados do banco, se houver espaço + if (lotteryData.annulled_numbers.includes(i) && annulledFunnel.size < MAX_FUNNEL) { + ball.classList.add("active"); + annulledFunnel.add(i); + } + + ball.onclick = () => { + if (ball.classList.contains("active")) { + ball.classList.remove("active"); + annulledFunnel.delete(i); + } else { + if (annulledFunnel.size >= MAX_FUNNEL) { + speak("Limite do funil atingido. Máximo de 31 dezenas."); + return; + } + ball.classList.add("active"); + annulledFunnel.add(i); + } + updateFunnelLabel(); + }; + funnelGrid.appendChild(ball); + } + } + + function updateFunnelLabel() { + funnelCountLabel.innerText = `${annulledFunnel.size} / ${MAX_FUNNEL}`; + } + + function updateElitePanel() { + elitePanel.innerHTML = ""; + lotteryData.elite_greens.slice(0, 10).forEach(n => { + const ball = document.createElement("div"); + ball.className = "num-ball num-elite mb-2"; + ball.style.width = "42px"; + ball.style.height = "42px"; + ball.innerText = n.toString().padStart(2, "0"); + elitePanel.appendChild(ball); + }); + } + function resetGenerator() { generatorRunning = false; btnStart.classList.remove("d-none"); @@ -204,7 +307,6 @@ currentStartNum = 1; totalGenerated = 0; countHot = 0; - countAnnulled = 0; countReclaimed = 0; updateStats(); if (animationId) cancelAnimationFrame(animationId); @@ -213,7 +315,6 @@ 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(); } @@ -223,26 +324,38 @@ 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++) { + for (let i = 0; i < 2; i++) { let sequence = []; - for (let j = 0; j < nToDraw; j++) { - let val = ((currentStartNum + j - 1) % maxNum) + 1; + let safetyCounter = 0; + + while (sequence.length < nToDraw && safetyCounter < 200) { + let val = ((currentStartNum - 1) % maxNum) + 1; + currentStartNum++; + safetyCounter++; + + // Pula se estiver no FUNIL + if (annulledFunnel.has(val)) continue; + 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++; + + if (sequence.length === nToDraw) { + renderSequence(sequence); + totalGenerated++; + } } updateStats(); - // Auto-scroll para baixo viewport.scrollTop = viewport.scrollHeight; + + // Voz aleatória a cada 1000 gerações + if (totalGenerated % 1000 === 0 && totalGenerated > 0) { + speak(`Processadas ${totalGenerated} combinações. Elite detectada em ${countHot} pontos.`); + } + animationId = requestAnimationFrame(generateChunk); } @@ -259,17 +372,11 @@ 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); - } + if (container.children.length > 30) container.removeChild(container.firstChild); container.appendChild(row); } @@ -278,6 +385,7 @@ generatorRunning = true; btnStart.classList.add("d-none"); btnPause.classList.remove("d-none"); + speak("Motor Sequencial Iniciado. Aplicando Funil de Trinta e uma Dezenas."); generateChunk(); }); @@ -285,15 +393,11 @@ generatorRunning = false; btnPause.classList.add("d-none"); btnStart.classList.remove("d-none"); + speak("Motor pausado pelo operador."); 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" }); - }); + document.getElementById("btn-up").addEventListener("click", () => viewport.scrollBy({ top: -300, behavior: "smooth" })); + document.getElementById("btn-down").addEventListener("click", () => viewport.scrollBy({ top: 300, behavior: "smooth" })); {% endblock %}