Files
marco 5bc68e3627 feat(db): add SQLite database persistence for insights
Implement local database storage to automatically save all sent insights
with metadata including topic, content, AI provider, model, and timestamp.
Add database module with initialization and query functions, integrate
with main job flow, and update documentation with database schema details.
2026-09-03 15:05:45 -03:00

189 lines
7.0 KiB
Python

from dotenv import load_dotenv
import os
import random
import requests
import openai
import schedule
import time
from datetime import datetime
from database import init_db, save_insight
load_dotenv()
TELEGRAM_BOT_TOKEN = os.getenv("TELEGRAM_BOT_TOKEN")
TELEGRAM_CHAT_ID = os.getenv("TELEGRAM_CHAT_ID")
DEFAULT_AI_PROVIDER = os.getenv("DEFAULT_AI_PROVIDER", "openrouter").lower()
DEFAULT_AI_MODEL = os.getenv("DEFAULT_AI_MODEL", "")
OPENROUTER_API_KEY = os.getenv("OPENROUTER_API_KEY")
LLAMACPP_BASE_URL = os.getenv("LLAMACPP_BASE_URL", "http://localhost:8080/v1/")
LLAMACPP_API_KEY = os.getenv("LLAMACPP_API_KEY", "not-needed")
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
LANGUAGE = os.getenv("LANGUAGE", "pt-BR")
MIN_LINES = int(os.getenv("MIN_LINES", "20"))
INTERVAL_MINUTES = int(os.getenv("INTERVAL_MINUTES", "60"))
START_HOUR = int(os.getenv("START_HOUR", "7"))
END_HOUR = int(os.getenv("END_HOUR", "22"))
TOPICS_RAW = os.getenv("TOPICS", "")
DAYS_OF_WEEK_RAW = os.getenv("DAYS_OF_WEEK", "1,2,3,4,5,6,7")
if not TELEGRAM_BOT_TOKEN or TELEGRAM_BOT_TOKEN == "seu_bot_token_aqui":
raise ValueError("TELEGRAM_BOT_TOKEN não configurado no .env")
if not TELEGRAM_CHAT_ID or TELEGRAM_CHAT_ID == "seu_chat_id_aqui":
raise ValueError("TELEGRAM_CHAT_ID não configurado no .env")
if DEFAULT_AI_PROVIDER == "openrouter" and OPENROUTER_API_KEY and OPENROUTER_API_KEY != "sk-or-v1-...":
client = openai.OpenAI(base_url="https://openrouter.ai/api/v1", api_key=OPENROUTER_API_KEY)
elif DEFAULT_AI_PROVIDER == "llamacpp" and LLAMACPP_API_KEY:
client = openai.OpenAI(base_url=LLAMACPP_BASE_URL, api_key=LLAMACPP_API_KEY)
elif DEFAULT_AI_PROVIDER == "openai" and OPENAI_API_KEY:
client = openai.OpenAI(api_key=OPENAI_API_KEY)
elif OPENROUTER_API_KEY and OPENROUTER_API_KEY != "sk-or-v1-...":
client = openai.OpenAI(base_url="https://openrouter.ai/api/v1", api_key=OPENROUTER_API_KEY)
elif LLAMACPP_API_KEY:
client = openai.OpenAI(base_url=LLAMACPP_BASE_URL, api_key=LLAMACPP_API_KEY)
elif OPENAI_API_KEY:
client = openai.OpenAI(api_key=OPENAI_API_KEY)
else:
raise ValueError("Nenhuma chave de IA configurada no .env")
init_db()
CURRENT_PROVIDER = DEFAULT_AI_PROVIDER
TOPICS = [t.strip() for t in TOPICS_RAW.split(",") if t.strip()]
if not TOPICS:
raise ValueError("Nenhum tópico informado no .env (variável TOPICS)")
DAYS_OF_WEEK = [int(d.strip()) for d in DAYS_OF_WEEK_RAW.split(",") if d.strip()]
if not DAYS_OF_WEEK:
DAYS_OF_WEEK = [1, 2, 3, 4, 5, 6, 7]
def is_within_schedule():
now = datetime.now()
return now.isoweekday() in DAYS_OF_WEEK and START_HOUR <= now.hour < END_HOUR
def generate_insight(topic):
prompt = (
f"Você é um assistente especializado em {topic}. "
f"Escreva um insight profundo, prático e motivador sobre {topic} "
f"em português brasileiro ({LANGUAGE}). "
f"O texto deve ter pelo menos {MIN_LINES} linhas, ser original, direto ao ponto e útil para o leitor. "
f"Não utilize marcações markdown como títulos ou negrito excessivo. "
f"Escreva de forma fluida, como se fosse uma orientação prática. "
f"Separe os parágrafos com linhas em branco (duas quebras de linha)."
)
try:
response = client.chat.completions.create(
model=DEFAULT_AI_MODEL,
messages=[
{"role": "system", "content": "Responda sempre em português brasileiro."},
{"role": "user", "content": prompt},
],
temperature=0.7,
max_tokens=4000,
)
content = response.choices[0].message.content
if not content:
return "[Erro ao gerar insight: resposta vazia da API]"
return content.strip()
except Exception as e:
return f"[Erro ao gerar insight: {e}]"
def send_telegram_message(text, topic):
now = datetime.now()
header = (
f"🤖 *Syspanel Insights - by ThorAgentIA*\n"
f"🤖 *https://syspanel.com.br*\n"
f"🕒 {now.strftime('%d/%m/%Y %H:%M:%S')}\n"
f"📌 Assunto: {topic}\n\n"
)
message = header + text
url = f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/sendMessage"
payload = {
"chat_id": TELEGRAM_CHAT_ID,
"text": message,
"parse_mode": "Markdown",
}
try:
if len(message) <= 4096:
response = requests.post(url, json=payload, timeout=30)
response.raise_for_status()
print(f"[{now.strftime('%Y-%m-%d %H:%M:%S')}] Mensagem enviada com sucesso.")
else:
chunks = []
current = header
parts = text.split("\n\n")
for part in parts:
candidate = current + part
if len(candidate) <= 4096:
current = candidate + "\n\n"
else:
chunks.append(current.strip())
current = header + part + "\n\n"
if current.strip():
chunks.append(current.strip())
for idx, chunk in enumerate(chunks, start=1):
chunk_payload = {
"chat_id": TELEGRAM_CHAT_ID,
"text": chunk,
"parse_mode": "Markdown",
}
response = requests.post(url, json=chunk_payload, timeout=30)
response.raise_for_status()
print(f"[{now.strftime('%Y-%m-%d %H:%M:%S')}] Mensagem enviada em {len(chunks)} parte(s).")
except Exception as e:
print(f"[{now.strftime('%Y-%m-%d %H:%M:%S')}] Erro ao enviar mensagem: {e}")
def job():
now = datetime.now()
print(f"\n[{now.strftime('%Y-%m-%d %H:%M:%S')}] Verificando horário...")
if not is_within_schedule():
print(f"[{now.strftime('%Y-%m-%d %H:%M:%S')}] Fora do horário permitido. Pulando envio.")
return
topic = random.choice(TOPICS)
print(f"[{now.strftime('%Y-%m-%d %H:%M:%S')}] Tópico escolhido: {topic}")
print(f"[{now.strftime('%Y-%m-%d %H:%M:%S')}] Gerando insight...")
insight = generate_insight(topic)
try:
save_insight(topic=topic, content=insight, provider=CURRENT_PROVIDER, model=DEFAULT_AI_MODEL)
print(f"[{now.strftime('%Y-%m-%d %H:%M:%S')}] Insight salvo no banco de dados.")
except Exception as e:
print(f"[{now.strftime('%Y-%m-%d %H:%M:%S')}] Erro ao salvar no banco: {e}")
send_telegram_message(insight, topic)
def main():
print("=== ThorAgentIA iniciado ===")
print(f"Provedor: {DEFAULT_AI_PROVIDER} | Modelo: {DEFAULT_AI_MODEL}")
print(f"Horário permitido: {START_HOUR}h às {END_HOUR}h")
print(f"Dias permitidos: {DAYS_OF_WEEK}")
print(f"Intervalo: {INTERVAL_MINUTES} minutos")
print(f"Tópicos disponíveis: {len(TOPICS)}")
for i, t in enumerate(TOPICS, 1):
print(f" {i}. {t}")
print()
schedule.every(INTERVAL_MINUTES).minutes.do(job)
job()
while True:
schedule.run_pending()
time.sleep(1)
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
print("\nThorAgentIA encerrado.")