# Gerado por IA import asyncio import json import urllib.request from datetime import datetime from telegram import Update from telegram.ext import ( ApplicationBuilder, ContextTypes, CommandHandler, MessageHandler, filters, ) from config import settings, _silenced_agents from context_manager import get_context_summary, append_to_context, load_daily_context from ai_agent import AIAgent, SYSTEM_PROMPT_TEMPLATE from orchestrator_shared import _orchestrator_ref import aiohttp agent_registry: dict[str, AIAgent] = {} # ---------- helpers HTTP ---------- def _http_get(url: str, headers: dict | None = None, timeout: int = 30) -> dict: req = urllib.request.Request(url, headers=headers or {}) with urllib.request.urlopen(req, timeout=timeout) as resp: return json.loads(resp.read()) def _http_post(url: str, payload: dict, headers: dict | None = None, timeout: int = 60) -> dict: data = json.dumps(payload).encode("utf-8") req = urllib.request.Request(url, data=data, headers=headers or {"Content-Type": "application/json"}) with urllib.request.urlopen(req, timeout=timeout) as resp: return json.loads(resp.read()) # ---------- util ---------- async def _send_telegram(text: str) -> None: url = f"https://api.telegram.org/bot{settings.TELEGRAM_BOT_TOKEN}/sendMessage" payload = {"chat_id": settings.TELEGRAM_CHAT_ID, "text": text, "parse_mode": "HTML"} try: async with aiohttp.ClientSession() as session: async with session.post(url, json=payload, timeout=aiohttp.ClientTimeout(total=15)) as resp: if resp.status != 200: body = await resp.text() print(f"[Telegram] HTTP {resp.status}: {body[:120]}") except Exception as exc: print(f"[Telegram] Erro ao enviar mensagem: {exc}") # ---------- comandos ---------- async def cmd_start(update: Update, context: ContextTypes.DEFAULT_TYPE): msg = ( "MultiAgentsAI iniciado!\n" f"Agentes ativos: {len(agent_registry)}\n" f"{', '.join(a.name for a in agent_registry.values())}\n" "Os agentes estao conversando automaticamente.\n" "Comandos:\n" "/status - Status do sistema\n" "/historico - Ultimas mensagens de hoje\n" "/agentes - Lista de agentes\n" "/participar [mensagem] - Enviar mensagem como usuario\n" "/pausar /continuar - Pausar/retomar agentes" ) await _send_telegram(msg) async def cmd_status(update: Update, context: ContextTypes.DEFAULT_TYPE): total = len(load_daily_context()) paused = _orchestrator_ref.paused if _orchestrator_ref else False msg = ( "Status MultiAgentsAI\n" f"Agentes ativos: {len(agent_registry)}\n" f"Mensagens hoje: {total}\n" f"Delay: {settings.CONVERSATION_DELAY}s\n" f"Pausado: {'Sim' if paused else 'Nao'}" ) await _send_telegram(msg) async def cmd_historico(update: Update, context: ContextTypes.DEFAULT_TYPE): summary = get_context_summary(30) await _send_telegram(f"Historico de hoje:\n\n{summary}") async def cmd_agentes(update: Update, context: ContextTypes.DEFAULT_TYPE): lines = ["Agentes registrados:"] for a in agent_registry.values(): lines.append(f" - {a.name} ({a.model})") await _send_telegram("\n".join(lines)) async def cmd_participar(update: Update, context: ContextTypes.DEFAULT_TYPE): text = " ".join(context.args) if context.args else "" if not text: await _send_telegram("Uso: /participar [sua mensagem aqui]") return user_msg = f"[Usuario] {text}" append_to_context("Usuario", user_msg) await _send_telegram(f"Voce: {text}") # Recarrega historico DIRETAMENTE do SQLite para garantir que a msg do usuario esteja la from database import get_today_messages messages = get_today_messages() history = "\n".join(f"[{m['agent_name']}] {m['message']}" for m in messages[-settings.MAX_CONTEXT_MESSAGES:]) other_agents = [a.name for a in agent_registry.values() if a.name != "Usuario"] for agent in agent_registry.values(): if agent.name == "Usuario": continue reply = await agent.generate_response(history, other_agents) if not reply.startswith("[Erro"): append_to_context(agent.name, reply) await _send_telegram(f"{agent.name}: {reply}") async def cmd_pausar(update: Update, context: ContextTypes.DEFAULT_TYPE): if _orchestrator_ref: _orchestrator_ref.paused = True await _send_telegram("Agentes pausados.") async def cmd_continuar(update: Update, context: ContextTypes.DEFAULT_TYPE): if _orchestrator_ref: _orchestrator_ref.paused = False await _send_telegram("Agentes retomados.") async def cmd_help(update: Update, context: ContextTypes.DEFAULT_TYPE): await _send_telegram( "Comandos disponiveis:\n" "/start - Iniciar\n" "/status - Status do sistema\n" "/historico - Historico de hoje\n" "/agentes - Lista de agentes\n" "/participar [msg] - Enviar mensagem\n" "/pausar - Pausar agentes\n" "/continuar - Retomar agentes\n" "/modelos - Lista modelos gratuitos do OpenRouter\n" "/testar [modelo] - Testa se um modelo esta funcionando\n" "/tema [assunto] - Define um tema para a conversa\n" "/limparchat - Limpa o historico de hoje\n" "/agente [nome] [msg] - Envia msg para um agente especifico\n" "/estatisticas - Estatisticas do banco de dados\n" "/buscar [termo] - Busca mensagens no historico\n" "/delay [s] - Altera o delay entre mensagens\n" "/idioma [codigo] - Altera o idioma (ex: pt_BR, en_US)\n" "/silenciar [nome] - Silencia/desilencia um agente\n" "/help - Esta ajuda" ) # =================================================================== # Novos comandos # =================================================================== async def cmd_modelos(update: Update, context: ContextTypes.DEFAULT_TYPE): """Lista todos os modelos gratuitos disponiveis no OpenRouter.""" await _send_telegram("Buscando modelos gratuitos no OpenRouter...") try: data = _http_get( f"{settings.OPENROUTER_BASE_URL}/models", headers={"Authorization": f"Bearer {settings.OPENROUTER_API_KEY}"}, timeout=30, ) free = [m for m in data.get("data", []) if ":free" in m.get("id", "")] free.sort(key=lambda m: m.get("context_length", 0), reverse=True) if not free: await _send_telegram("Nenhum modelo gratuito encontrado.") return lines = [f"Modelos gratuitos ({len(free)}):"] for m in free[:20]: ctx = m.get("context_length", "?") lines.append(f" - {m['id']} (ctx={ctx})") if len(free) > 20: lines.append(f" ... e mais {len(free) - 20} modelos.") await _send_telegram("\n".join(lines)) except Exception as exc: await _send_telegram(f"Erro: {exc}") async def cmd_testar(update: Update, context: ContextTypes.DEFAULT_TYPE): """Testa se um modelo esta funcionando: /testar openai/gpt-4o:free""" args = context.args if not args: await _send_telegram("Uso: /testar [modelo]\nExemplo: /testar nvidia/nemotron-3.5-lightning:free") return model = " ".join(args) await _send_telegram(f"Testando modelo: {model}...") try: data = _http_post( f"{settings.OPENROUTER_BASE_URL}/chat/completions", {"model": model, "messages": [{"role": "user", "content": "OK"}], "max_tokens": 20}, headers={ "Authorization": f"Bearer {settings.OPENROUTER_API_KEY}", "Content-Type": "application/json", "HTTP-Referer": "https://multiagentsai.local", "X-Title": "MultiAgentsAI", }, timeout=65, ) choices = data.get("choices", []) if choices and (choices[0].get("message") or {}).get("content", "").strip(): await _send_telegram(f"OK - {model}\n{choices[0]['message']['content'][:100]}") else: await _send_telegram(f"FALHOU - {model}\nResposta vazia (finish_reason={choices[0].get('finish_reason','?') if choices else '?'})") except urllib.error.HTTPError as exc: body = exc.read().decode("utf-8", errors="replace")[:200] await _send_telegram(f"FALHOU - {model}\nHTTP {exc.code}: {body}") except Exception as exc: await _send_telegram(f"Erro: {exc}") async def cmd_tema(update: Update, context: ContextTypes.DEFAULT_TYPE): """Define um tema/foco para a conversa: /tema futuro da IA""" text = " ".join(context.args) if context.args else "" if not text: await _send_telegram("Uso: /tema [assunto]\nExemplo: /tema O futuro da IA na medicina") return append_to_context("Usuario", f"[Usuario] Vamos conversar sobre: {text}") # Recarrega historico do SQLite diretamente from database import get_today_messages msgs = get_today_messages() history = "\n".join(f"[{m['agent_name']}] {m['message']}" for m in msgs[-settings.MAX_CONTEXT_MESSAGES:]) others = [a.name for a in agent_registry.values() if a.name != "Usuario"] await _send_telegram(f"Novo tema definido: {text}") for agent in agent_registry.values(): if agent.name == "Usuario": continue reply = await agent.generate_response(history, others) if not reply.startswith("[Erro"): append_to_context(agent.name, reply) await _send_telegram(f"{agent.name}: {reply}") async def cmd_limparchat(update: Update, context: ContextTypes.DEFAULT_TYPE): """Limpa o historico de hoje (JSON + SQLite).""" import os as _os path = _os.path.join(settings.CONTEXTS_DIR, f"conversas_{datetime.utcnow().strftime('%Y-%m-%d')}.json") removed = 0 if _os.path.exists(path): _os.remove(path) removed += 1 try: import sqlite3 conn = sqlite3.connect(settings.DB_PATH) today = datetime.utcnow().strftime("%Y-%m-%d") cur = conn.execute("DELETE FROM conversations WHERE date = ?", (today,)) removed += cur.rowcount conn.commit() conn.close() except Exception: pass await _send_telegram(f"Chat limpo!\n{removed} registros removidos.") async def cmd_agente(update: Update, context: ContextTypes.DEFAULT_TYPE): """Envia uma mensagem para um agente especifico: /agente AI Agent 1 ola""" args = context.args if len(args) < 2: await _send_telegram("Uso: /agente [nome] [mensagem]\nExemplo: /agente AI Agent 1 ola, tudo bem?") return agent_name = args[0] msg_text = " ".join(args[1:]) agent = agent_registry.get(agent_name) if not agent: nomes = ", ".join(agent_registry.keys()) await _send_telegram(f"Agente nao encontrado.\nAgentes disponiveis: {nomes}") return append_to_context("Usuario", f"[Usuario -> {agent_name}] {msg_text}") msgs = load_daily_context() history = "\n".join(f"[{m['agent_name']}] {m['message']}" for m in msgs[-settings.MAX_CONTEXT_MESSAGES:]) others = [a.name for a in agent_registry.values() if a.name not in (agent_name, "Usuario")] reply = await agent.generate_response(history, others) if not reply.startswith("[Erro"): append_to_context(agent.name, reply) await _send_telegram(f"{agent.name}: {reply}") else: await _send_telegram(reply) async def cmd_estatisticas(update: Update, context: ContextTypes.DEFAULT_TYPE): """Mostra estatisticas do banco de dados.""" try: import sqlite3 conn = sqlite3.connect(settings.DB_PATH) conn.row_factory = sqlite3.Row total = conn.execute("SELECT COUNT(*) FROM conversations").fetchone()[0] today = datetime.utcnow().strftime("%Y-%m-%d") today_count = conn.execute("SELECT COUNT(*) FROM conversations WHERE date = ?", (today,)).fetchone()[0] agents_stats = conn.execute( "SELECT agent_name, COUNT(*) as cnt FROM conversations WHERE date = ? GROUP BY agent_name ORDER BY cnt DESC", (today,), ).fetchall() conn.close() lines = [ "Estatisticas", f"Total de mensagens (todos os dias): {total}", f"Mensagens hoje: {today_count}", "", "Por agente (hoje):", ] if agents_stats: for r in agents_stats: lines.append(f" - {r['agent_name']}: {r['cnt']}") else: lines.append(" Nenhuma mensagem hoje.") await _send_telegram("\n".join(lines)) except Exception as exc: await _send_telegram(f"Erro: {exc}") async def cmd_buscar(update: Update, context: ContextTypes.DEFAULT_TYPE): """Busca mensagens no historico: /buscar IA""" args = context.args if not args: await _send_telegram("Uso: /buscar [termo]") return termo = " ".join(args).lower() try: import sqlite3 conn = sqlite3.connect(settings.DB_PATH) conn.row_factory = sqlite3.Row rows = conn.execute( "SELECT agent_name, message, created_at FROM conversations WHERE LOWER(message) LIKE ? ORDER BY id DESC LIMIT 20", (f"%{termo}%",), ).fetchall() conn.close() if not rows: await _send_telegram(f"Nenhuma mensagem encontrada com '{termo}'.") return lines = [f"Resultados para '{termo}' ({len(rows)}):"] for r in rows: snippet = r["message"][:120].replace("<", "<").replace(">", ">") lines.append(f" [{r['agent_name']}] {snippet}") await _send_telegram("\n".join(lines)) except Exception as exc: await _send_telegram(f"Erro: {exc}") async def cmd_delay(update: Update, context: ContextTypes.DEFAULT_TYPE): """Altera o delay entre mensagens: /delay 60""" args = context.args if not args: await _send_telegram(f"Delay atual: {settings.CONVERSATION_DELAY}s\nUso: /delay [segundos]") return try: segundos = int(args[0]) if segundos < 5: await _send_telegram("O delay minimo e de 5 segundos.") return if _orchestrator_ref: _orchestrator_ref._delay_override = segundos await _send_telegram(f"Delay alterado para {segundos}s.") except ValueError: await _send_telegram("Valor invalido. Use: /delay 30") async def cmd_idioma(update: Update, context: ContextTypes.DEFAULT_TYPE): """Altera o idioma das conversas: /idioma en_US""" args = context.args if not args: await _send_telegram(f"Idioma atual: {settings.CONVERSATION_LANGUAGE}\nUso: /idioma [codigo]\nEx: /idioma pt_BR /idioma en_US") return codigo = args[0] # Atualiza em tempo de execucao from ai_agent import SYSTEM_PROMPT_TEMPLATE settings.CONVERSATION_LANGUAGE = codigo for agent in agent_registry.values(): agent.system_prompt = SYSTEM_PROMPT_TEMPLATE.format(name=agent.name, language=codigo) await _send_telegram(f"Idioma alterado para {codigo}.") async def cmd_silenciar(update: Update, context: ContextTypes.DEFAULT_TYPE): """Silencia ou desilencia um agente: /silenciar AI Agent 2""" args = context.args if not args: nomes = ", ".join(agent_registry.keys()) silenciados = ", ".join(_silenced_agents) or "nenhum" await _send_telegram( f"Agentes silenciados: {silenciados}\n" f"Uso: /silenciar [nome]\n" f"Agentes disponiveis: {nomes}" ) return nome = " ".join(args) if nome not in agent_registry: nomes = ", ".join(agent_registry.keys()) await _send_telegram(f"Agente '{nome}' nao encontrado.\nDisponiveis: {nomes}") return if nome in _silenced_agents: _silenced_agents.discard(nome) await _send_telegram(f"{nome} desilenciado — voltara a participar das conversas.") else: _silenced_agents.add(nome) await _send_telegram(f"{nome} silenciado — nao participara mais das conversas automaticas.") # ---------- inicializacao ---------- def build_bot() -> tuple: from telegram.ext import ApplicationBuilder app = ApplicationBuilder().token(settings.TELEGRAM_BOT_TOKEN).build() app.add_handler(CommandHandler("start", cmd_start)) app.add_handler(CommandHandler("status", cmd_status)) app.add_handler(CommandHandler("historico", cmd_historico)) app.add_handler(CommandHandler("agentes", cmd_agentes)) app.add_handler(CommandHandler("participar", cmd_participar)) app.add_handler(CommandHandler("pausar", cmd_pausar)) app.add_handler(CommandHandler("continuar", cmd_continuar)) app.add_handler(CommandHandler("modelos", cmd_modelos)) app.add_handler(CommandHandler("testar", cmd_testar)) app.add_handler(CommandHandler("tema", cmd_tema)) app.add_handler(CommandHandler("limparchat", cmd_limparchat)) app.add_handler(CommandHandler("agente", cmd_agente)) app.add_handler(CommandHandler("estatisticas", cmd_estatisticas)) app.add_handler(CommandHandler("buscar", cmd_buscar)) app.add_handler(CommandHandler("delay", cmd_delay)) app.add_handler(CommandHandler("idioma", cmd_idioma)) app.add_handler(CommandHandler("silenciar", cmd_silenciar)) app.add_handler(CommandHandler("help", cmd_help)) return app