ufpalign / test_api.py
marcosremar2's picture
Fix pandas version compatibility and add comprehensive API test script
317700f
#!/usr/bin/env python3
"""
Script de teste para a API do Montreal Forced Aligner Portuguese
Testa todos os endpoints e funcionalidades da API
"""
import requests
import json
import time
import os
from pathlib import Path
import wave
import numpy as np
from io import BytesIO
# Configuração da API
API_BASE_URL = "http://localhost:7860" # Para teste local
# API_BASE_URL = "https://marcosremar2-ufpalign.hf.space" # Para Hugging Face Spaces
def create_test_audio(filename="test_audio.wav", duration=3, sample_rate=16000):
"""
Cria um arquivo de áudio de teste simples (tom puro).
Para teste real, use um arquivo WAV com fala em português.
"""
t = np.linspace(0, duration, int(sample_rate * duration), False)
# Tom de 440 Hz (Lá)
audio = np.sin(2 * np.pi * 440 * t) * 0.3
# Converter para 16-bit
audio_int16 = (audio * 32767).astype(np.int16)
# Salvar como WAV
with wave.open(filename, 'w') as wav_file:
wav_file.setnchannels(1) # Mono
wav_file.setsampwidth(2) # 16-bit
wav_file.setframerate(sample_rate)
wav_file.writeframes(audio_int16.tobytes())
print(f"✅ Arquivo de áudio de teste criado: {filename}")
return filename
def test_health_check():
"""Testa o endpoint de health check"""
print("\n🔍 Testando Health Check...")
try:
response = requests.get(f"{API_BASE_URL}/health", timeout=10)
if response.status_code == 200:
data = response.json()
print(f"✅ Health Check OK: {data}")
return True
else:
print(f"❌ Health Check falhou: {response.status_code}")
return False
except Exception as e:
print(f"❌ Erro no Health Check: {e}")
return False
def test_models_list():
"""Testa o endpoint de listagem de modelos"""
print("\n🔍 Testando listagem de modelos...")
try:
response = requests.get(f"{API_BASE_URL}/models", timeout=30)
if response.status_code == 200:
data = response.json()
print(f"✅ Modelos disponíveis:")
print(f" Acústicos: {data.get('acoustic_models', [])[:3]}...")
print(f" G2P: {data.get('g2p_models', [])[:3]}...")
return True
else:
print(f"❌ Falha ao listar modelos: {response.status_code}")
return False
except Exception as e:
print(f"❌ Erro ao listar modelos: {e}")
return False
def test_alignment(audio_file=None, text="Esta é uma frase de teste em português"):
"""Testa o endpoint principal de alinhamento"""
print("\n🔍 Testando alinhamento forçado...")
# Usar arquivo de áudio fornecido ou criar um de teste
if audio_file is None:
audio_file = create_test_audio()
if not os.path.exists(audio_file):
print(f"❌ Arquivo de áudio não encontrado: {audio_file}")
return False
try:
# Preparar dados para upload
files = {'audio': open(audio_file, 'rb')}
data = {'text': text}
print(f"📝 Texto: {text}")
print(f"🎵 Áudio: {audio_file}")
print("⏳ Enviando para alinhamento...")
# Fazer requisição
response = requests.post(
f"{API_BASE_URL}/align",
files=files,
data=data,
timeout=300 # 5 minutos
)
files['audio'].close()
if response.status_code == 200:
result = response.json()
print(f"✅ Alinhamento concluído!")
print(f" Arquivo: {result['filename']}")
print(f" Duração: {result['duration']:.2f}s")
print(f" Tiers: {len(result['tiers'])}")
# Mostrar algumas informações dos tiers
for tier in result['tiers']:
print(f" - {tier['name']}: {len(tier['intervals'])} intervalos")
return result
else:
error_data = response.json() if response.headers.get('content-type') == 'application/json' else response.text
print(f"❌ Falha no alinhamento: {response.status_code}")
print(f" Erro: {error_data}")
return False
except Exception as e:
print(f"❌ Erro no alinhamento: {e}")
return False
finally:
# Limpar arquivo de teste se foi criado
if audio_file == "test_audio.wav" and os.path.exists(audio_file):
os.remove(audio_file)
def test_download(filename):
"""Testa o download do arquivo TextGrid"""
print(f"\n🔍 Testando download do TextGrid: {filename}")
try:
# Remover extensão .TextGrid se presente
base_filename = filename.replace('.TextGrid', '')
response = requests.get(f"{API_BASE_URL}/download/{base_filename}", timeout=30)
if response.status_code == 200:
print(f"✅ Download concluído!")
print(f" Tamanho: {len(response.content)} bytes")
print(f" Tipo: {response.headers.get('content-type', 'unknown')}")
# Salvar arquivo localmente para verificação
download_filename = f"downloaded_{base_filename}.TextGrid"
with open(download_filename, 'w', encoding='utf-8') as f:
f.write(response.text)
print(f" Salvo como: {download_filename}")
return True
else:
print(f"❌ Falha no download: {response.status_code}")
return False
except Exception as e:
print(f"❌ Erro no download: {e}")
return False
def test_web_interface():
"""Testa se a interface web está acessível"""
print("\n🔍 Testando interface web...")
try:
response = requests.get(API_BASE_URL, timeout=10)
if response.status_code == 200:
if "MFA Portuguese Alignment" in response.text:
print("✅ Interface web acessível e funcionando")
return True
else:
print("⚠️ Interface web acessível mas conteúdo inesperado")
return False
else:
print(f"❌ Interface web inacessível: {response.status_code}")
return False
except Exception as e:
print(f"❌ Erro na interface web: {e}")
return False
def run_full_test(audio_file=None, text=None):
"""Executa todos os testes da API"""
print("🚀 Iniciando testes completos da API MFA Portuguese")
print(f"🌐 URL base: {API_BASE_URL}")
print("="*60)
results = {}
# Texto padrão em português
if text is None:
text = "Olá, este é um teste de alinhamento forçado para português brasileiro."
# 1. Health Check
results['health'] = test_health_check()
# 2. Interface Web
results['web'] = test_web_interface()
# 3. Listar Modelos
results['models'] = test_models_list()
# 4. Alinhamento Principal
alignment_result = test_alignment(audio_file, text)
results['alignment'] = alignment_result is not False
# 5. Download (se alinhamento foi bem-sucedido)
if alignment_result and isinstance(alignment_result, dict):
results['download'] = test_download(alignment_result['filename'])
else:
results['download'] = False
print("\n⏭️ Pulando teste de download (alinhamento falhou)")
# Relatório final
print("\n" + "="*60)
print("📊 RELATÓRIO FINAL DOS TESTES")
print("="*60)
total_tests = len(results)
passed_tests = sum(1 for result in results.values() if result)
for test_name, result in results.items():
status = "✅ PASSOU" if result else "❌ FALHOU"
print(f"{test_name.upper():12} | {status}")
print("-"*60)
print(f"RESUMO: {passed_tests}/{total_tests} testes passaram")
if passed_tests == total_tests:
print("🎉 Todos os testes passaram! API funcionando perfeitamente.")
return True
else:
print("⚠️ Alguns testes falharam. Verifique os logs acima.")
return False
def test_with_real_audio():
"""
Exemplo de como testar com áudio real.
Substitua pelos seus próprios arquivos.
"""
# Exemplo de uso com arquivo real
audio_file = "exemplo.wav" # Substitua pelo seu arquivo
text = "Transcrição exata do que está sendo falado no áudio"
if os.path.exists(audio_file):
print(f"\n🎯 Testando com áudio real: {audio_file}")
return run_full_test(audio_file, text)
else:
print(f"⚠️ Arquivo {audio_file} não encontrado. Usando áudio de teste.")
return run_full_test()
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser(description="Testa a API do MFA Portuguese")
parser.add_argument("--url", default=API_BASE_URL, help="URL base da API")
parser.add_argument("--audio", help="Arquivo de áudio para teste")
parser.add_argument("--text", help="Texto para alinhamento")
parser.add_argument("--real", action="store_true", help="Tenta usar áudio real")
args = parser.parse_args()
# Atualizar URL se fornecida
API_BASE_URL = args.url
if args.real:
success = test_with_real_audio()
else:
success = run_full_test(args.audio, args.text)
exit(0 if success else 1)