transcrevezap/services.py
Fábio Cavalcanti fede0057e5 ajuste prompt
2024-12-18 16:11:04 -03:00

267 lines
11 KiB
Python

import aiohttp
import base64
import aiofiles
from fastapi import HTTPException
from config import settings, logger, redis_client
from storage import StorageHandler
import os
import json
import tempfile
# Inicializa o storage handler
storage = StorageHandler()
async def convert_base64_to_file(base64_data):
"""Converte dados base64 em arquivo temporário"""
try:
storage.add_log("DEBUG", "Iniciando conversão de base64 para arquivo")
audio_data = base64.b64decode(base64_data)
with tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") as temp_file:
temp_file.write(audio_data)
audio_file_path = temp_file.name
storage.add_log("DEBUG", "Arquivo temporário criado", {
"path": audio_file_path
})
return audio_file_path
except Exception as e:
storage.add_log("ERROR", "Erro na conversão base64", {
"error": str(e),
"type": type(e).__name__
})
raise
async def summarize_text_if_needed(text):
"""Resumir texto usando a API GROQ"""
storage.add_log("DEBUG", "Iniciando processo de resumo", {
"text_length": len(text)
})
url_completions = "https://api.groq.com/openai/v1/chat/completions"
headers = {
"Authorization": f"Bearer {settings.GROQ_API_KEY}",
"Content-Type": "application/json",
}
json_data = {
"messages": [{
"role": "user",
"content": f"""
Entenda o contexto desse áudio e faça um resumo super enxuto sobre o que se trata.
Esse áudio foi enviado pelo whatsapp, de alguém, para Fabio.
Escreva APENAS o resumo do áudio como se fosse você que estivesse enviando
essa mensagem! Não cumprimente, não de oi, não escreva nada antes nem depois
do resumo, responda apenas um resumo enxuto do que foi falado no áudio.
IMPORTANTE: Não faça esse resumo como se fosse um áudio que uma terceira
pessoa enviou, não diga coisas como 'a pessoa está falando...' etc.
Escreva o resumo com base nessa mensagem do áudio,
como se você estivesse escrevendo esse resumo e enviando em
texto pelo whatsapp de forma impessoal: {text}""",
}],
"model": "llama-3.3-70b-versatile",
}
try:
async with aiohttp.ClientSession() as session:
storage.add_log("DEBUG", "Enviando requisição para API GROQ")
async with session.post(url_completions, headers=headers, json=json_data) as summary_response:
if summary_response.status == 200:
summary_result = await summary_response.json()
summary_text = summary_result["choices"][0]["message"]["content"]
storage.add_log("INFO", "Resumo gerado com sucesso", {
"original_length": len(text),
"summary_length": len(summary_text)
})
return summary_text
else:
error_text = await summary_response.text()
storage.add_log("ERROR", "Erro na API GROQ", {
"error": error_text,
"status": summary_response.status
})
raise Exception(f"Erro ao resumir o texto: {error_text}")
except Exception as e:
storage.add_log("ERROR", "Erro no processo de resumo", {
"error": str(e),
"type": type(e).__name__
})
raise
async def transcribe_audio(audio_source, apikey=None):
"""Transcreve áudio usando a API GROQ"""
storage.add_log("INFO", "Iniciando processo de transcrição")
url = "https://api.groq.com/openai/v1/audio/transcriptions"
groq_headers = {"Authorization": f"Bearer {settings.GROQ_API_KEY}"}
try:
async with aiohttp.ClientSession() as session:
# Se o audio_source for uma URL
if isinstance(audio_source, str) and audio_source.startswith('http'):
storage.add_log("DEBUG", "Baixando áudio da URL", {
"url": audio_source
})
download_headers = {"apikey": apikey} if apikey else {}
async with session.get(audio_source, headers=download_headers) as response:
if response.status != 200:
error_text = await response.text()
storage.add_log("ERROR", "Erro no download do áudio", {
"status": response.status,
"error": error_text
})
raise Exception(f"Erro ao baixar áudio: {error_text}")
audio_data = await response.read()
with tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") as temp_file:
temp_file.write(audio_data)
audio_source = temp_file.name
storage.add_log("DEBUG", "Áudio salvo temporariamente", {
"path": audio_source
})
# Preparar dados para transcrição
data = aiohttp.FormData()
data.add_field('file', open(audio_source, 'rb'), filename='audio.mp3')
data.add_field('model', 'whisper-large-v3')
data.add_field('language', 'pt')
storage.add_log("DEBUG", "Enviando áudio para transcrição")
async with session.post(url, headers=groq_headers, data=data) as response:
if response.status == 200:
result = await response.json()
message = result.get("text", "")
storage.add_log("INFO", "Transcrição concluída com sucesso", {
"text_length": len(message)
})
is_summary = False
if len(message) > 1000:
storage.add_log("DEBUG", "Texto longo detectado, iniciando resumo", {
"text_length": len(message)
})
is_summary = True
message = await summarize_text_if_needed(message)
return message, is_summary
else:
error_text = await response.text()
storage.add_log("ERROR", "Erro na transcrição", {
"error": error_text,
"status": response.status
})
raise Exception(f"Erro na transcrição: {error_text}")
except Exception as e:
storage.add_log("ERROR", "Erro no processo de transcrição", {
"error": str(e),
"type": type(e).__name__
})
raise
finally:
# Limpar arquivos temporários
if isinstance(audio_source, str) and os.path.exists(audio_source):
os.unlink(audio_source)
async def send_message_to_whatsapp(server_url, instance, apikey, message, remote_jid, message_id):
"""Envia mensagem via WhatsApp"""
storage.add_log("DEBUG", "Preparando envio de mensagem", {
"remote_jid": remote_jid,
"instance": instance
})
url = f"{server_url}/message/sendText/{instance}"
headers = {"apikey": apikey}
try:
# Tentar enviar na V1
body = get_body_message_to_whatsapp_v1(message, remote_jid)
storage.add_log("DEBUG", "Tentando envio no formato V1")
result = await call_whatsapp(url, body, headers)
# Se falhar, tenta V2
if not result:
storage.add_log("DEBUG", "Formato V1 falhou, tentando formato V2")
body = get_body_message_to_whatsapp_v2(message, remote_jid, message_id)
await call_whatsapp(url, body, headers)
storage.add_log("INFO", "Mensagem enviada com sucesso", {
"remote_jid": remote_jid
})
except Exception as e:
storage.add_log("ERROR", "Erro no envio da mensagem", {
"error": str(e),
"type": type(e).__name__,
"remote_jid": remote_jid
})
raise
def get_body_message_to_whatsapp_v1(message, remote_jid):
"""Formata mensagem no formato V1"""
return {
"number": remote_jid,
"options": {"delay": 1200, "presence": "composing", "linkPreview": False},
"textMessage": {"text": message},
}
def get_body_message_to_whatsapp_v2(message, remote_jid, message_id):
"""Formata mensagem no formato V2"""
return {
"number": remote_jid,
"text": message,
"quoted": {"key": {"remoteJid": remote_jid, "fromMe": False, "id": message_id}},
}
async def call_whatsapp(url, body, headers):
"""Realiza chamada à API do WhatsApp"""
try:
async with aiohttp.ClientSession() as session:
storage.add_log("DEBUG", "Enviando requisição para WhatsApp", {
"url": url
})
async with session.post(url, json=body, headers=headers) as response:
if response.status not in [200, 201]:
error_text = await response.text()
storage.add_log("ERROR", "Erro na API do WhatsApp", {
"status": response.status,
"error": error_text
})
return False
storage.add_log("DEBUG", "Requisição bem-sucedida")
return True
except Exception as e:
storage.add_log("ERROR", "Erro na chamada WhatsApp", {
"error": str(e),
"type": type(e).__name__
})
return False
async def get_audio_base64(server_url, instance, apikey, message_id):
"""Obtém áudio em Base64 via API do WhatsApp"""
storage.add_log("DEBUG", "Obtendo áudio base64", {
"message_id": message_id,
"instance": instance
})
url = f"{server_url}/chat/getBase64FromMediaMessage/{instance}"
headers = {"apikey": apikey}
body = {"message": {"key": {"id": message_id}}, "convertToMp4": False}
try:
async with aiohttp.ClientSession() as session:
async with session.post(url, json=body, headers=headers) as response:
if response.status in [200, 201]:
result = await response.json()
storage.add_log("INFO", "Áudio base64 obtido com sucesso")
return result.get("base64", "")
else:
error_text = await response.text()
storage.add_log("ERROR", "Erro ao obter áudio base64", {
"status": response.status,
"error": error_text
})
raise HTTPException(status_code=500, detail="Falha ao obter áudio em base64")
except Exception as e:
storage.add_log("ERROR", "Erro na obtenção do áudio base64", {
"error": str(e),
"type": type(e).__name__,
"message_id": message_id
})
raise