#!/usr/bin/env python3 """ASR local para o Italiano Vivo via faster-whisper. O proxy LiteLLM (10.8.0.1:4000) nao aceita partes de audio no chat/completions (qwen omni devolve 400 "Invalid video file" / "provided URL does not appear to be valid"), entao a transcricao roda aqui e o server Node repassa so o texto para o juiz LLM. Uso: python asr_whisper.py [--model small] [--json] Imprime o texto transcrito (ou JSON com segments/timing com --json). Idempotente: baixa o modelo uma vez e usa cache local do HuggingFace. """ import argparse import json import sys def main() -> int: ap = argparse.ArgumentParser(description="Transcricao IT/PT com faster-whisper") ap.add_argument("audio", help="caminho do arquivo de audio (mp3/wav/webm)") ap.add_argument("--model", default="small", help="tiny|base|small|medium (default small)") ap.add_argument("--lang", default=None, help="forcar idioma, ex.: it") ap.add_argument("--json", action="store_true", dest="as_json") args = ap.parse_args() from faster_whisper import WhisperModel model = WhisperModel(args.model, device="cpu", compute_type="int8") segments, info = model.transcribe( args.audio, language=args.lang, beam_size=5, vad_filter=True ) parts = [] seg_list = [] for s in segments: parts.append(s.text.strip()) seg_list.append({"start": round(s.start, 2), "end": round(s.end, 2), "text": s.text.strip()}) text = " ".join(p for p in parts if p).strip() if args.as_json: print(json.dumps({ "text": text, "language": info.language, "language_probability": round(float(info.language_probability), 3), "segments": seg_list, }, ensure_ascii=False)) else: print(text) return 0 if text else 2 if __name__ == "__main__": sys.exit(main())