🚀 Auto-deploy: BotVPS atualizado em 24/03/2026 11:50:13
This commit is contained in:
75
bot_logic.py
75
bot_logic.py
@@ -8,10 +8,9 @@ from orchestrator import (
|
|||||||
handle_message_async, orchestrate_async, format_confirmation_message,
|
handle_message_async, orchestrate_async, format_confirmation_message,
|
||||||
format_completion_message, execute_step_async
|
format_completion_message, execute_step_async
|
||||||
)
|
)
|
||||||
from ai_agent import query_agent
|
from ai_agent import query_agent_async
|
||||||
import speech_recognition as sr
|
from audio_handler import transcribe_audio, text_to_speech
|
||||||
from pydub import AudioSegment
|
from config import get_config
|
||||||
from gtts import gTTS
|
|
||||||
|
|
||||||
# Configuração de logging
|
# Configuração de logging
|
||||||
logging.basicConfig(
|
logging.basicConfig(
|
||||||
@@ -24,14 +23,12 @@ TOKEN = os.getenv("TELEGRAM_BOT_TOKEN")
|
|||||||
ALLOWED_CHAT_ID = os.getenv("TELEGRAM_CHAT_ID")
|
ALLOWED_CHAT_ID = os.getenv("TELEGRAM_CHAT_ID")
|
||||||
|
|
||||||
def synthesize_audio(text: str) -> str:
|
def synthesize_audio(text: str) -> str:
|
||||||
|
"""Wrapper para a síntese de voz centralizada."""
|
||||||
try:
|
try:
|
||||||
texto_limpo = re.sub(r'[*`#]', '', text)
|
filename = text_to_speech(text)
|
||||||
filepath = "/tmp/reply_audio.mp3"
|
return os.path.join("/tmp", filename)
|
||||||
tts = gTTS(text=texto_limpo[:500], lang='pt-br', slow=False)
|
|
||||||
tts.save(filepath)
|
|
||||||
return filepath
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"TTS Error: {e}")
|
logger.error(f"TTS Error: {e}")
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
async def auth_check(update: Update) -> bool:
|
async def auth_check(update: Update) -> bool:
|
||||||
@@ -42,10 +39,41 @@ async def auth_check(update: Update) -> bool:
|
|||||||
|
|
||||||
async def handle_text(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
async def handle_text(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||||
if not await auth_check(update): return
|
if not await auth_check(update): return
|
||||||
|
|
||||||
user_msg = update.message.text
|
|
||||||
chat_id = update.message.chat_id
|
|
||||||
await update.message.reply_chat_action(action="typing")
|
await update.message.reply_chat_action(action="typing")
|
||||||
|
await process_logic(update, context, update.message.text)
|
||||||
|
|
||||||
|
async def handle_voice(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||||
|
if not await auth_check(update): return
|
||||||
|
|
||||||
|
await update.message.reply_chat_action(action="record_voice")
|
||||||
|
|
||||||
|
# Baixa o arquivo de voz do Telegram
|
||||||
|
voice_file = await context.bot.get_file(update.message.voice.file_id)
|
||||||
|
ogg_path = f"/tmp/{update.message.voice.file_id}.ogg"
|
||||||
|
await voice_file.download_to_drive(ogg_path)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Transcreve (STT)
|
||||||
|
text = transcribe_audio(ogg_path)
|
||||||
|
if not text:
|
||||||
|
await update.message.reply_text("Não consegui entender o áudio.")
|
||||||
|
return
|
||||||
|
|
||||||
|
await update.message.reply_text(f"🎤 Entendi: \"{text}\"")
|
||||||
|
|
||||||
|
# Processa como se fosse texto (reutiliza handle_text logic)
|
||||||
|
# Gambiarra rápida: cria um objeto Update fake ou chama a lógica diretamente
|
||||||
|
# Melhor: extrair a lógica de handle_text para uma função pura
|
||||||
|
await process_logic(update, context, text, is_voice=True)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Erro Voz: {e}")
|
||||||
|
await update.message.reply_text(f"Erro ao processar voz: {e}")
|
||||||
|
finally:
|
||||||
|
if os.path.exists(ogg_path): os.remove(ogg_path)
|
||||||
|
|
||||||
|
async def process_logic(update: Update, context: ContextTypes.DEFAULT_TYPE, user_msg: str, is_voice: bool = False):
|
||||||
|
chat_id = update.message.chat_id
|
||||||
|
|
||||||
# 1. COMANDOS DIRETOS
|
# 1. COMANDOS DIRETOS
|
||||||
if user_msg.startswith('/') and user_msg.split()[0] in ['/status', '/tools', '/sync']:
|
if user_msg.startswith('/') and user_msg.split()[0] in ['/status', '/tools', '/sync']:
|
||||||
@@ -78,19 +106,24 @@ async def handle_text(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
|||||||
reply = format_confirmation_message(result)
|
reply = format_confirmation_message(result)
|
||||||
else:
|
else:
|
||||||
reply = format_completion_message(result)
|
reply = format_completion_message(result)
|
||||||
await update.message.reply_text(reply)
|
|
||||||
else:
|
else:
|
||||||
# Fallback AI Agent
|
# Fallback AI Agent
|
||||||
from config import get_config
|
|
||||||
from ai_agent import query_agent_async
|
|
||||||
cfg = get_config()
|
cfg = get_config()
|
||||||
|
# No Telegram, ainda não estamos mantendo histórico complexo no bot_data (pode ser futuro)
|
||||||
reply = await query_agent_async(user_msg, override_provider=cfg.get("active_provider"))
|
reply = await query_agent_async(user_msg, override_provider=cfg.get("active_provider"))
|
||||||
await update.message.reply_text(reply)
|
|
||||||
|
|
||||||
async def handle_voice(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
# Envia resposta (Texto)
|
||||||
if not await auth_check(update): return
|
# Remove o bloco <REFINED> se houver, pois no Telegram polui
|
||||||
await update.message.reply_text("Processando aúdio...")
|
reply_clean = re.sub(r'<REFINED>.*?</REFINED>', '', reply, flags=re.DOTALL).strip()
|
||||||
await update.message.reply_text("Comando de voz recebido (STT não configurado neste passo).")
|
await update.message.reply_text(reply_clean)
|
||||||
|
|
||||||
|
# Se foi por voz, responde por voz também
|
||||||
|
if is_voice:
|
||||||
|
audio_path = synthesize_audio(reply_clean)
|
||||||
|
if audio_path and os.path.exists(audio_path):
|
||||||
|
with open(audio_path, 'rb') as voice:
|
||||||
|
await update.message.reply_voice(voice)
|
||||||
|
os.remove(audio_path)
|
||||||
|
|
||||||
def get_telegram_app():
|
def get_telegram_app():
|
||||||
if not TOKEN:
|
if not TOKEN:
|
||||||
|
|||||||
Reference in New Issue
Block a user