- Requisitos de Hardware e Configuração Base
O modelo Qwen3-ASR-1.7B é uma solução de reconhecimento de fala de ponta a ponta projetada para execução estritamente offline. Devido à sua arquitetura de 1,7 bilhão de parâmetros, a inferência exige recursos computacionais específicos e não é compatível com processamento via CPU ou arquiteturas de GPU defasadas.
1.1 Especificações de GPU e Memória
Para garantir a estabilidade da inferência e evitar erros de estouro de memória (OOM), o ambiente deve atender aos seguintes critérios mínimos:
- Arquitetura da GPU: NVIDIA Ampere ou superior (ex: A10, A100, V100, RTX 3090, RTX 4090).
- Capacidade de VRAM: Mínimo absoluto de 16GB. Recomenda-se 24GB para acomodar o carregamento dos pesos (aproximadamente 5,5GB), cache de ativação (cerca de 6GB) e processamento de arquivos de áudio mais longos.
Dispositivos com 12GB de VRAM falharão ao processar áudios superiores a 30 segundos, enquanto configurações com 16GB suportarão a carga, mas limitarão a concorrência de requisições.
1.2 Compatibilidade de Imagens e Ambiente
A imagem do modelo ins-asr-1.7b-v1 depende estritamente de uma imagem base específica para funcionar corretamente. A configuração obrigatória é:
- Imagem Base:
insbase-cuda124-pt250-dual-v7 - Toolchain: CUDA 12.4 (incompatível com versões 11.x ou 12.2).
- Framwork: PyTorch 2.5.0 pré-compilado para CUDA 12.4.
- Arquitetura de Serviço: Dual (FastAPI para API REST e Gradio para interface Web).
Versões anteriores (v0) carecem de detecção automática de VAD (Voice Activity Detection) para poda de silêncio, e variantes CPU não possuem suporte para os pesos do modelo.
- Provisionamento e Validação do Serviço
2.1 Inicialização da Instância
Ao provisionar a instância no ambiente de containers ou nuvem, configure os seguintes parâmetros:
- Selecione a imagem
ins-asr-1.7b-v1. - Defina uma instância GPU com no mínimo 16GB de VRAM.
- Aloque pelo menos 100GB de disco para o sistema, pesos do modelo e logs.
- Desative a atribuição automática de IP público se o ambiente for estritamente privado.
Após o status da instância indicar "Em execução", o serviço não estará imediatamente disponível. O carregamento dos pesos na VRAM leva entre 15 e 20 segundos. Monitore via terminal com nvidia-smi; a alocação de memória deve estabilizar em aproximadamente 11GB antes que o serviço aceite conexões.
2.2 Acesso à Interface Web (Gradio)
A interface gráfica para testes manuais é exposta na porta 7860. O acesso pode ser realizado via:
- Proxy HTTP reverso do painel de controle (recomendado).
- Acesso direto:
http://<IP_DA_INSTANCIA>:7860(utilizando HTTP, não HTTPS).
Caso a página não carregue, verifique se a porta 7860 está liberada nas regras de firewall/security group e confirme a execução do processo Gradio via ps aux | grep gradio.
2.3 Validação Funcional
Para confirmar a integridade do serviço, execute os seguintes testes na interface:
-
Seleção de Idioma: Verifique se as opções
auto,zh,en,ja,koeyueestão renderizadas corretamente. -
Ingestão de Áudio: Faça o upload de um arquivo WAV (16kHz, mono, <10s). O waveform deve ser exibido.
-
Inferência: Acione o processamento. O resultado deve retornar o idioma detectado e a transcrição textual com pontuação adequada.
-
Integração Programática via API REST
Para integração em pipelines de produção, o serviço expõe um endpoint FastAPI na porta 7861. A API exige o envio do arquivo de áudio em formato binário (multipart/form-data) e não aceita codificação base64 ou URLs remotas.
3.1 Requisição Síncrona para Arquivo Único
O script abaixo utiliza a biblioteca httpx para realizar a requisição, incluindo tipagem estática e tratamento de exceções robusto.
import httpx
from pathlib import Path
from typing import Optional, Dict
def transcrever_audio_local(
caminho_audio: str,
endereco_ip: str,
idioma_alvo: str = "auto"
) -> Optional[Dict]:
endpoint = f"http://{endereco_ip}:7861/asr"
arquivo = Path(caminho_audio)
if not arquivo.exists():
raise FileNotFoundError(f"Arquivo de áudio não localizado: {caminho_audio}")
payload = {"language": idioma_alvo}
with open(arquivo, "rb") as f_stream:
arquivos = {"audio_file": (arquivo.name, f_stream, "audio/wav")}
try:
with httpx.Client(timeout=45.0) as cliente:
resposta = cliente.post(endpoint, data=payload, files=arquivos)
resposta.raise_for_status()
return resposta.json()
except httpx.HTTPStatusError as erro_http:
print(f"Falha na requisição HTTP: {erro_http.response.status_code} - {erro_http.response.text}")
except httpx.TimeoutException:
print("A requisição excedeu o tempo limite de processamento.")
except Exception as erro_geral:
print(f"Erro inesperado na comunicação: {erro_geral}")
return None
if __name__ == "__main__":
resultado = transcrever_audio_local("audio_teste.wav", "192.168.1.50", "zh")
if resultado:
print(f"Idioma: {resultado.get('language')} | Texto: {resultado.get('text')}")
3.2 Processamento em Lote com Controle de Concorrência
Para processar múltiplos arquivos sem causar OOM na GPU, utiliza-se programação assíncrona com um semáforo para limitar a concorrência máxima a duas requisições simultâneas.
import asyncio
import httpx
from pathlib import Path
from typing import List, Dict
async def processar_lote_assincrono(
lista_arquivos: List[str],
endereco_ip: str,
concorrencia_maxima: int = 2
) -> Dict[str, str]:
semaforo = asyncio.Semaphore(concorrencia_maxima)
resultados_finais = {}
async def enviar_requisicao(caminho: str, cliente: httpx.AsyncClient):
async with semaforo:
url = f"http://{endereco_ip}:7861/asr"
nome_arq = Path(caminho).name
with open(caminho, "rb") as f:
dados = {"language": "auto"}
arquivos = {"audio_file": (nome_arq, f, "audio/wav")}
try:
resp = await cliente.post(url, data=dados, files=arquivos, timeout=60.0)
resp.raise_for_status()
resultados_finais[caminho] = resp.json().get("text", "")
except Exception as e:
resultados_finais[caminho] = f"Falha: {str(e)}"
async with httpx.AsyncClient() as cliente_http:
tarefas = [enviar_requisicao(f, cliente_http) for f in lista_arquivos]
await asyncio.gather(*tarefas)
return resultados_finais
# Exemplo de execução
if __name__ == "__main__":
arquivos_wav = [str(p) for p in Path("./audios").glob("*.wav")]
transcrições = asyncio.run(processar_lote_assincrono(arquivos_wav, "192.168.1.50"))
for arq, texto in transcrições.items():
print(f"{arq}: {texto[:50]}...")
- Solução de Problemas e Erros Frequentes
4.1 Incompatibilidade de Formato de Áudio
Sintoma: A API retorna erro ou resultado vazio ao receber arquivos MP3 ou M4A.
Causa: O pipeline de pré-processamento do modelo exige estritamente arquivos WAV com codificação PCM, mono e taxa de amostragem de 16kHz.
Correção: Utilize o ffmpeg para padronizar os arquivos antes do envio:
ffmpeg -i entrada.mp3 -ar 16000 -ac 1 -acodec pcm_s16le saida.wav
4.2 Transcrição Truncada ou Caracteres Corrompidos
Sintoma: O texto de saída contém caracteres inválidos ou é interrompido abruptamente.
Causa: Cabeçalho do arquivo WAV corrompido ou taxa de amostragem incorreta (ex: 44.1kHz).
Diagnóstico: Execute file arquivo.wav no terminal. A saída deve indicar 16 bit, mono 16000 Hz.
Correção: Force a reamostragem e reconstrução do cabeçalho:
ffmpeg -i corrompido.wav -ar 16000 -ac 1 -acodec pcm_s16le -f wav corrigido.wav
4.3 Interface Web Indisponível (502 ou Tela Branca)
Sintoma: O navegador exibe erro 502 Bad Gateway ao acessar a porta 7860.
Procedimento de Diagnóstico:
- Teste a conectividade interna:
curl http://localhost:7860. Se retornar HTML, o problema é de rede/firewall. - Verifique o status da API:
curl http://localhost:7861/asr. Deve retornar{"detail":"Method Not Allowed"}. - Confirme a alocação de VRAM via
nvidia-smi. Se o uso estiver abaixo de 5GB, o carregamento dos pesos falhou; reinicie o container ou execute o script de inicialização manualmente.