#!/usr/bin/env python3 """AI Voice Editor - Pipeline completo: transcrição + análise acústica → JSON para IA. Uso: python ai_edit.py [--model base] [--lang pt] [--no-diarize] [--output dir] Gera dois arquivos na pasta output (ou ao lado do mídia): _transcript.json — transcrição com timestamps por palavra _voice_timeline.json — timeline de voz com ênfase, pitch, energy, speakers Esses arquivos são a ENTRADA para a IA analisar e gerar o roteiro/edição. """ import argparse import json import sys import time from pathlib import Path def main(): parser = argparse.ArgumentParser(description="Pipeline de análise de voz para IA") parser.add_argument("media", help="Caminho do arquivo de mídia (.mp4, .mov, .wav, etc.)") parser.add_argument("--model", default="base", help="Modelo Whisper (tiny/base/small/medium/large-v3)") parser.add_argument("--lang", default=None, help="Idioma (ex: pt, en). Auto-detect se omitido") parser.add_argument("--hf-token", default=None, help="HuggingFace token para diarização (opcional)") parser.add_argument("--no-diarize", action="store_true", help="Pular diarização de falantes") parser.add_argument("--output", default=None, help="Pasta de saída (padrão: ao lado do mídia)") parser.add_argument("--no-align", action="store_true", help="Pular alinhamento fonético (whisperx)") args = parser.parse_args() media_path = Path(args.media).resolve() if not media_path.is_file(): print(f"ERRO: Arquivo não encontrado: {media_path}", file=sys.stderr) sys.exit(1) # Output dir out_dir = Path(args.output) if args.output else media_path.parent out_dir.mkdir(parents=True, exist_ok=True) stem = media_path.stem # ── Fase 1: Transcrição ────────────────────────────────────────── print(f"[1/2] Transcrevendo {media_path.name} (modelo: {args.model})...") t0 = time.time() # Adiciona code/ ao path para imports do projeto code_dir = Path(__file__).resolve().parent sys.path.insert(0, str(code_dir)) from fcpxml.transcribe import transcribe def transcribe_progress(pct): bar_len = 30 filled = int(bar_len * pct) bar = "█" * filled + "░" * (bar_len - filled) print(f"\r [{bar}] {pct*100:.0f}%", end="", flush=True) transcript = transcribe( str(media_path), model_size=args.model, language=args.lang, progress_cb=transcribe_progress, align=not args.no_align, ) print() # newline after progress bar if transcript is None: print("ERRO: Transcrição falhou. Verifique se faster-whisper está instalado:", file=sys.stderr) print(" uv pip install faster-whisper", file=sys.stderr) sys.exit(1) print(f" → {len(transcript.get('words', []))} palavras, " f"{len(transcript.get('segments', []))} segmentos, " f"idioma: {transcript.get('language', '?')}") # Salva transcrição transcript_path = out_dir / f"{stem}_transcript.json" transcript_path.write_text(json.dumps(transcript, indent=2, ensure_ascii=False), encoding="utf-8") print(f" → Salvo: {transcript_path}") # ── Fase 2: Análise de voz (timeline) ──────────────────────────── print(f"\n[2/2] Analisando voz (pitch, energia, ênfase)...") t1 = time.time() from fcpxml.voice_timeline import build_voice_timeline def voice_progress(fraction, stage): print(f"\r {stage} ({fraction*100:.0f}%)", end="", flush=True) hf_token = None if args.no_diarize else args.hf_token timeline = build_voice_timeline( str(media_path), transcript, hf_token=hf_token, progress_cb=voice_progress, ) print() # Salva voice timeline timeline_path = out_dir / f"{stem}_voice_timeline.json" timeline_path.write_text(json.dumps(timeline, indent=2, ensure_ascii=False), encoding="utf-8") print(f" → Salvo: {timeline_path}") # ── Resumo ─────────────────────────────────────────────────────── elapsed = time.time() - t0 summary = timeline.get("summary", {}) layers = timeline.get("layers", {}) n_words = len(transcript.get("words", [])) n_segments = len(transcript.get("segments", [])) n_speakers = len(timeline.get("speakers", [])) duration = transcript.get("duration", 0) print(f"\n{'='*50}") print(f" ARQUIVOS GERADOS:") print(f" {transcript_path}") print(f" {timeline_path}") print(f"\n RESUMO:") print(f" Duração: {duration:.1f}s ({duration/60:.1f}min)") print(f" Palavras: {n_words}") print(f" Segmentos: {n_segments}") print(f" Falantes: {n_speakers}") print(f" Camadas: transcript={layers.get('transcript')}, " f"acoustics={layers.get('acoustics')}, " f"diarization={layers.get('diarization')}") print(f" Tempo: {elapsed:.1f}s") print(f"{'='*50}") print(f"\n→ Pronto! Agora peça à IA para analisar o voice timeline e gerar o roteiro.") if __name__ == "__main__": main()