feat: initial commit of Sistema do Mestre application
Add complete Flask web application with Telegram bot integration, multiple AI provider support (llama.cpp, OpenRouter, z.ai, StepFun), extensive order banks for BDSM-themed gameplay, automated cron scheduling, and responsive web UI with inference parameter controls.
This commit is contained in:
Executable
+265
@@ -0,0 +1,265 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Sistema de envio automático de Ordens do Mestre para o Telegram.
|
||||
Lê a agenda diária, mapeia horário → categoria e envia ordens
|
||||
contextuais em intervalos variados.
|
||||
"""
|
||||
import logging
|
||||
import os
|
||||
import random
|
||||
import sys
|
||||
import time
|
||||
from datetime import datetime
|
||||
|
||||
import requests
|
||||
|
||||
# Importado com alias para nao colidir com o wrapper local de mesmo nome
|
||||
# (gerar_ordem_dinamica) definido mais abaixo neste modulo.
|
||||
from dados import gerar_ordem_dinamica as gerar_ordem_dinamica_dados, gerar_ordem_sozinho_completa
|
||||
from dados_plug import banco_plug
|
||||
from dados_picantes import banco_picantes
|
||||
from ia_llamacpp import (
|
||||
estado_revisao_cron_ativo,
|
||||
revisar_ordem_ia,
|
||||
servidor_disponivel,
|
||||
)
|
||||
|
||||
# ── Logging ──
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format="%(asctime)s [%(levelname)s] %(message)s",
|
||||
datefmt="%Y-%m-%d %H:%M:%S",
|
||||
)
|
||||
logger = logging.getLogger("ordem_mestre")
|
||||
|
||||
# ── Telegram ──
|
||||
BOT_TOKEN = os.environ.get("TELEGRAM_BOT_TOKEN", "")
|
||||
CHAT_ID = os.environ.get("TELEGRAM_CHAT_ID", "")
|
||||
|
||||
if not BOT_TOKEN or not CHAT_ID:
|
||||
logger.error("TELEGRAM_BOT_TOKEN e TELEGRAM_CHAT_ID devem estar definidos no .env")
|
||||
sys.exit(1)
|
||||
|
||||
TELEGRAM_API = f"https://api.telegram.org/bot{BOT_TOKEN}/sendMessage"
|
||||
|
||||
|
||||
def enviar_telegram(texto):
|
||||
"""Envia uma mensagem de texto para o Telegram com timestamp."""
|
||||
agora = datetime.now().strftime("%d/%m/%Y %H:%M")
|
||||
texto_completo = f"{texto}\n\n📅 {agora}"
|
||||
try:
|
||||
resp = requests.post(TELEGRAM_API, json={
|
||||
"chat_id": CHAT_ID,
|
||||
"text": texto_completo,
|
||||
"parse_mode": "HTML",
|
||||
}, timeout=15)
|
||||
if resp.status_code != 200:
|
||||
logger.warning("Telegram retornou %s: %s", resp.status_code, resp.text[:200])
|
||||
else:
|
||||
logger.info("Mensagem enviada ao Telegram.")
|
||||
except requests.RequestException as exc:
|
||||
logger.error("Falha ao enviar Telegram: %s", exc)
|
||||
|
||||
|
||||
def revisar_com_ia_se_ativo(texto, tipo="ordem"):
|
||||
"""Devolve *texto* possivelmente reescrito pela IA antes do envio.
|
||||
|
||||
Quando o recurso "IA revisa o Cron" está ativado (pelo painel web), a IA
|
||||
analisa e reescreve a ordem escolhida. Em qualquer falha (recurso
|
||||
desligado, IA offline, resposta vazia ou erro) a ordem original é
|
||||
devolvida intacta, de forma que nenhuma ordem agendada deixe de ser
|
||||
enviada.
|
||||
"""
|
||||
if not estado_revisao_cron_ativo():
|
||||
return texto
|
||||
try:
|
||||
if not servidor_disponivel():
|
||||
logger.warning("🧠 Revisão de cron ativa, mas a IA está offline. "
|
||||
"Enviando ordem original.")
|
||||
return texto
|
||||
logger.info("🧠 IA está analisando e reescrevendo a ordem %s...", tipo)
|
||||
revisada = revisar_ordem_ia(texto)
|
||||
if revisada and revisada.strip():
|
||||
logger.info("✅ Ordem %s reescrita pela IA.", tipo)
|
||||
return revisada.strip()
|
||||
logger.warning("IA retornou resposta vazia; enviando ordem original.")
|
||||
except Exception as exc: # noqa: BLE001
|
||||
logger.error("Falha ao revisar ordem com a IA: %s. Enviando original.", exc)
|
||||
return texto
|
||||
|
||||
|
||||
# ── Agenda ──
|
||||
AGENDA = [
|
||||
("06:00", "07:30", "☀️ Matinal", ["banco_sozinho_masturbacao", "banco_sozinho_vibracao"]),
|
||||
("07:30", "10:00", "💻 Home Office", ["banco_estudos_auto_ditadas"]),
|
||||
("10:00", "11:30", "🧹 Doméstico", ["banco_trabalhos_domesticos"]),
|
||||
("11:30", "13:00", "🧹 Doméstico", ["banco_trabalhos_domesticos"]),
|
||||
("13:00", "16:00", "💻 Home Office", ["banco_estudos_auto_ditadas"]),
|
||||
("16:00", "19:00", "📚 Estudos", ["banco_estudos_auto_ditadas"]),
|
||||
("19:00", "19:30", "🚿 Banho", ["banco_banho"]),
|
||||
("19:30", "20:30", "🧹 Doméstico", ["banco_trabalhos_domesticos"]),
|
||||
("20:30", "22:00", "📚 Estudos / Áudio-books", ["banco_estudos_auto_ditadas"]),
|
||||
("22:00", "06:00", "🌙 Noturna", ["banco_sozinho_edging"]),
|
||||
]
|
||||
|
||||
BANCOS_CATEGORIA = {}
|
||||
|
||||
|
||||
def _carregar_bancos():
|
||||
"""Carrega os bancos de dados sob demanda."""
|
||||
from dados import (
|
||||
banco_sozinho_masturbacao, banco_sozinho_vibracao,
|
||||
banco_sozinho_exposicao, banco_sozinho_humilhacao,
|
||||
banco_sozinho_plug, banco_sozinho_edging,
|
||||
banco_trabalhos_domesticos,
|
||||
banco_estudos_auto_ditadas,
|
||||
banco_banho,
|
||||
)
|
||||
|
||||
BANCOS_CATEGORIA.update({
|
||||
"banco_sozinho_masturbacao": banco_sozinho_masturbacao,
|
||||
"banco_sozinho_vibracao": banco_sozinho_vibracao,
|
||||
"banco_sozinho_exposicao": banco_sozinho_exposicao,
|
||||
"banco_sozinho_humilhacao": banco_sozinho_humilhacao,
|
||||
"banco_sozinho_plug": banco_sozinho_plug,
|
||||
"banco_sozinho_edging": banco_sozinho_edging,
|
||||
"banco_trabalhos_domesticos": banco_trabalhos_domesticos,
|
||||
"banco_estudos_auto_ditadas": banco_estudos_auto_ditadas,
|
||||
"banco_banho": banco_banho,
|
||||
})
|
||||
|
||||
|
||||
def categoria_atual():
|
||||
"""Retorna a categoria com base no horário atual."""
|
||||
agora = datetime.now()
|
||||
hora_min = agora.hour * 100 + agora.minute
|
||||
for inicio, fim, cat, _ in AGENDA:
|
||||
h_ini = int(inicio[:2]) * 100 + int(inicio[3:])
|
||||
h_fim = int(fim[:2]) * 100 + int(fim[3:])
|
||||
if h_ini <= h_fim:
|
||||
if h_ini <= hora_min < h_fim:
|
||||
return cat
|
||||
else:
|
||||
if hora_min >= h_ini or hora_min < h_fim:
|
||||
return cat
|
||||
return "☀️ Matinal"
|
||||
|
||||
|
||||
def bancos_para_categoria(cat_nome):
|
||||
"""Retorna os bancos de dados associados a uma categoria."""
|
||||
for _, _, cat, bancos_nomes in AGENDA:
|
||||
if cat == cat_nome:
|
||||
bancos = []
|
||||
for nome in bancos_nomes:
|
||||
b = BANCOS_CATEGORIA.get(nome)
|
||||
if b:
|
||||
bancos.append(b)
|
||||
return bancos
|
||||
return []
|
||||
|
||||
|
||||
def gerar_ordem_contextual():
|
||||
"""Gera uma ordem baseada na categoria do horário atual."""
|
||||
cat = categoria_atual()
|
||||
bancos = bancos_para_categoria(cat)
|
||||
if bancos:
|
||||
banco = random.choice(bancos)
|
||||
return f"🔥 ORDEM DO MESTRE [{cat}]\n\n{random.choice(banco)}"
|
||||
return f"🔥 ORDEM DO MESTRE [{cat}]\n\n{gerar_ordem_sozinho_completa()}"
|
||||
|
||||
|
||||
def gerar_ordem_plug():
|
||||
"""Pega uma ordem aleatória do banco de plugs."""
|
||||
cat = categoria_atual()
|
||||
ordem = random.choice(banco_plug)
|
||||
return f"🔌 ORDEM DE PLUG [{cat}]\n\n{ordem}"
|
||||
|
||||
|
||||
def gerar_ordem_picante():
|
||||
"""Pega uma ordem aleatória do banco de picantes."""
|
||||
cat = categoria_atual()
|
||||
ordem = random.choice(banco_picantes)
|
||||
return f"🔥 ORDEM PICANTE [{cat}]\n\n{ordem}"
|
||||
|
||||
|
||||
def gerar_ordem_dinamica():
|
||||
"""Gera uma ordem dinâmica aleatória (wrapper com cabeçalho de categoria)."""
|
||||
cat = categoria_atual()
|
||||
ordem = gerar_ordem_dinamica_dados()
|
||||
return f"⚡ ORDEM DINÂMICA [{cat}]\n\n{ordem}"
|
||||
|
||||
|
||||
# ── Timers ──
|
||||
ultimo_envio = {
|
||||
"contextual": 0,
|
||||
"plug": 0,
|
||||
"picante": 0,
|
||||
"dinamica": 0,
|
||||
}
|
||||
|
||||
|
||||
def deve_enviar(tipo, intervalo_min, intervalo_max=None):
|
||||
"""Verifica se passou tempo suficiente desde o último envio."""
|
||||
agora = time.time()
|
||||
if intervalo_max:
|
||||
intervalo = random.randint(intervalo_min, intervalo_max)
|
||||
else:
|
||||
intervalo = intervalo_min
|
||||
if agora - ultimo_envio[tipo] >= intervalo:
|
||||
ultimo_envio[tipo] = agora
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def loop_principal():
|
||||
"""Loop infinito que envia ordens nos intervalos definidos."""
|
||||
logger.info("🧠 Sistema de Ordens do Mestre iniciado.")
|
||||
logger.info("Bot: @hermesjogo1000")
|
||||
logger.info("Intervalos: contextual 10-40min | plug 45min | picante 15min | dinâmica 20min")
|
||||
enviar_telegram("🧠 SISTEMA DE ORDENS DO MESTRE ATIVADO.\n"
|
||||
"Ordens automáticas serão enviadas conforme sua agenda diária.")
|
||||
|
||||
_carregar_bancos()
|
||||
|
||||
while True:
|
||||
try:
|
||||
agora = time.time()
|
||||
|
||||
# ── Ordens picantes: a cada 15 min ──
|
||||
if deve_enviar("picante", 15 * 60):
|
||||
texto = gerar_ordem_picante()
|
||||
logger.info("Enviando ordem picante...")
|
||||
enviar_telegram(revisar_com_ia_se_ativo(texto, "picante"))
|
||||
|
||||
# ── Ordens dinâmicas: a cada 20 min ──
|
||||
if deve_enviar("dinamica", 20 * 60):
|
||||
texto = gerar_ordem_dinamica()
|
||||
logger.info("Enviando ordem dinâmica...")
|
||||
enviar_telegram(revisar_com_ia_se_ativo(texto, "dinâmica"))
|
||||
|
||||
# ── Ordens de plug: a cada 45 min ──
|
||||
if deve_enviar("plug", 45 * 60):
|
||||
texto = gerar_ordem_plug()
|
||||
logger.info("Enviando ordem de plug...")
|
||||
enviar_telegram(revisar_com_ia_se_ativo(texto, "plug"))
|
||||
|
||||
# ── Ordens contextuais (normais): 10-40 min ──
|
||||
if deve_enviar("contextual", 10 * 60, 40 * 60):
|
||||
texto = gerar_ordem_contextual()
|
||||
logger.info("Enviando ordem contextual (%s)...", categoria_atual())
|
||||
enviar_telegram(revisar_com_ia_se_ativo(texto, "contextual"))
|
||||
|
||||
# Dorme 30 segundos antes de verificar novamente
|
||||
time.sleep(30)
|
||||
|
||||
except KeyboardInterrupt:
|
||||
logger.info("Sistema encerrado pelo usuário.")
|
||||
enviar_telegram("⏹ SISTEMA DE ORDENS DO MESTRE DESATIVADO.")
|
||||
break
|
||||
except Exception as exc:
|
||||
logger.exception("Erro no loop principal: %s", exc)
|
||||
time.sleep(60)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
loop_principal()
|
||||
Reference in New Issue
Block a user