111 lines
4.1 KiB
Python
111 lines
4.1 KiB
Python
import aiohttp
|
|
import json
|
|
from typing import Optional, Tuple, Any
|
|
from datetime import datetime
|
|
import logging
|
|
from storage import StorageHandler
|
|
import asyncio
|
|
|
|
logger = logging.getLogger("GROQHandler")
|
|
logger.setLevel(logging.DEBUG)
|
|
handler = logging.StreamHandler()
|
|
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
|
handler.setFormatter(formatter)
|
|
logger.addHandler(handler)
|
|
|
|
async def test_groq_key(key: str) -> bool:
|
|
"""Teste se uma chave GROQ é válida e está funcionando."""
|
|
url = "https://api.groq.com/openai/v1/models"
|
|
headers = {"Authorization": f"Bearer {key}"}
|
|
|
|
try:
|
|
async with aiohttp.ClientSession() as session:
|
|
async with session.get(url, headers=headers) as response:
|
|
if response.status == 200:
|
|
data = await response.json()
|
|
return bool(data.get("data"))
|
|
return False
|
|
except Exception as e:
|
|
logger.error(f"Erro ao testar chave GROQ: {e}")
|
|
return False
|
|
|
|
async def validate_transcription_response(response_text: str) -> bool:
|
|
"""Valide se a resposta da transcrição é significativa."""
|
|
try:
|
|
cleaned_text = response_text.strip()
|
|
return len(cleaned_text) >= 10
|
|
except Exception as e:
|
|
logger.error(f"Erro ao validar resposta da transcrição: {e}")
|
|
return False
|
|
|
|
async def get_working_groq_key(storage: StorageHandler) -> Optional[str]:
|
|
"""Obtenha uma chave GROQ funcional do pool disponível."""
|
|
keys = storage.get_groq_keys()
|
|
|
|
for _ in range(len(keys)):
|
|
key = storage.get_next_groq_key()
|
|
if not key:
|
|
continue
|
|
|
|
penalized_until = storage.get_penalized_until(key)
|
|
if penalized_until and penalized_until > datetime.utcnow():
|
|
continue
|
|
|
|
if await test_groq_key(key):
|
|
return key
|
|
else:
|
|
storage.penalize_key(key, penalty_duration=300)
|
|
|
|
storage.add_log("ERROR", "Nenhuma chave GROQ funcional disponível.")
|
|
return None
|
|
|
|
async def handle_groq_request(
|
|
url: str,
|
|
headers: dict,
|
|
data: Any,
|
|
storage: StorageHandler,
|
|
is_form_data: bool = False
|
|
) -> Tuple[bool, dict, str]:
|
|
"""Lida com requisições para a API GROQ com suporte a retries e rotação de chaves."""
|
|
max_retries = len(storage.get_groq_keys())
|
|
|
|
for attempt in range(max_retries):
|
|
try:
|
|
storage.add_log("DEBUG", "Iniciando tentativa de requisição para GROQ", {
|
|
"url": url,
|
|
"is_form_data": is_form_data,
|
|
"attempt": attempt + 1
|
|
})
|
|
|
|
async with aiohttp.ClientSession() as session:
|
|
if is_form_data:
|
|
async with session.post(url, headers=headers, data=data) as response:
|
|
response_data = await response.json()
|
|
if response.status == 200 and response_data.get("text"):
|
|
return True, response_data, ""
|
|
else:
|
|
async with session.post(url, headers=headers, json=data) as response:
|
|
response_data = await response.json()
|
|
if response.status == 200 and response_data.get("choices"):
|
|
return True, response_data, ""
|
|
|
|
error_msg = response_data.get("error", {}).get("message", "")
|
|
|
|
if "organization_restricted" in error_msg or "invalid_api_key" in error_msg:
|
|
new_key = await get_working_groq_key(storage)
|
|
if new_key:
|
|
headers["Authorization"] = f"Bearer {new_key}"
|
|
await asyncio.sleep(1)
|
|
continue
|
|
|
|
return False, response_data, error_msg
|
|
|
|
except Exception as e:
|
|
storage.add_log("ERROR", "Erro na requisição", {"error": str(e)})
|
|
if attempt < max_retries - 1:
|
|
await asyncio.sleep(1)
|
|
continue
|
|
return False, {}, f"Request failed: {str(e)}"
|
|
|
|
storage.add_log("ERROR", "Todas as chaves GROQ falharam.")
|
|
return False, {}, "All GROQ keys exhausted." |