habulaj commited on
Commit
819dfd1
·
verified ·
1 Parent(s): cfa7b66

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +87 -53
app.py CHANGED
@@ -699,76 +699,110 @@ def groq_json_to_srt(data):
699
 
700
  return srt_output
701
 
702
- from srt_utils import apply_netflix_style_filter
703
 
704
  async def get_groq_srt_base(url: str, language: Optional[str] = None, temperature: Optional[float] = 0.4):
705
  """
706
  Helper para gerar SRT base usando Groq (dando suporte a filtro Netflix).
707
  Retorna (srt_filtered, srt_word_level)
 
708
  """
709
  if not url:
710
  raise HTTPException(status_code=400, detail="URL é obrigatória para processamento Groq")
711
 
712
- # Preparar requisição para Groq (Multipart via URL)
713
- groq_url = "https://api.groq.com/openai/v1/audio/transcriptions"
714
- headers = {
715
- "Authorization": f"Bearer {GROQ_API_KEY}"
716
- }
717
-
718
- files = {
719
- "model": (None, "whisper-large-v3"),
720
- "url": (None, url),
721
- "temperature": (None, str(temperature)),
722
- "timestamp_granularities[]": (None, "word"),
723
- "response_format": (None, "verbose_json")
724
- }
725
-
726
- if language and language in GROQ_SUPPORTED_LANGUAGES:
727
- files["language"] = (None, language)
728
- else:
729
- # Se language não for suportado ou None, não envia (auto-detect)
730
- if language:
731
- print(f"⚠️ Linguagem '{language}' não suportada ou código inválido. Enviando sem language.")
732
 
733
- print(f"🧠 [Groq] Enviando URL para processamento (whisper-large-v3)...")
 
 
 
 
734
 
735
- max_retries = 3
736
- for attempt in range(max_retries):
737
- try:
738
- response_groq = requests.post(groq_url, headers=headers, files=files, timeout=300)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
739
 
740
- if response_groq.status_code == 200:
741
- result = response_groq.json()
742
- break
743
 
744
- # Check for specific "context deadline exceeded" or 5xx errors
745
- error_msg = response_groq.text.lower()
746
- is_deadline_error = "context deadline exceeded" in error_msg
747
- is_server_error = response_groq.status_code >= 500
748
 
749
- if (is_deadline_error or is_server_error) and attempt < max_retries - 1:
750
- wait_time = 2 * (attempt + 1)
751
- print(f"⚠️ Erro transiente Groq ({response_groq.status_code}): {error_msg[:100]}... Tentando novamente em {wait_time}s...")
752
- await asyncio.sleep(wait_time)
753
-
754
- # Reset files pointer if needed (though for URL it's fine, but if we sent file-like obj we'd need seek(0))
755
- # Since we send tuples with strings/None, we don't need to reset anything for 'files' dict here.
756
- continue
757
-
758
- raise HTTPException(status_code=response_groq.status_code, detail=f"Erro Groq: {response_groq.text}")
759
 
760
- except requests.RequestException as e:
761
- if attempt < max_retries - 1:
762
- print(f"⚠️ Erro de conexão Groq: {e}. Retentando...")
763
- await asyncio.sleep(2)
764
- continue
765
- raise HTTPException(status_code=500, detail=f"Erro de conexão com Groq: {str(e)}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
766
 
767
-
768
- # Converter para SRT (Word Level)
 
 
 
 
 
 
 
 
 
769
  srt_word = groq_json_to_srt(result)
770
-
771
- # Aplicar filtro Netflix (Merge e Fix Overlaps)
772
  srt_filtered = apply_netflix_style_filter(srt_word)
773
 
774
  return srt_filtered, srt_word
 
699
 
700
  return srt_output
701
 
702
+ from srt_utils import apply_netflix_style_filter, process_audio_for_transcription
703
 
704
  async def get_groq_srt_base(url: str, language: Optional[str] = None, temperature: Optional[float] = 0.4):
705
  """
706
  Helper para gerar SRT base usando Groq (dando suporte a filtro Netflix).
707
  Retorna (srt_filtered, srt_word_level)
708
+ Agora faz download e pré-processamento do áudio localmente para melhorar qualidade.
709
  """
710
  if not url:
711
  raise HTTPException(status_code=400, detail="URL é obrigatória para processamento Groq")
712
 
713
+ # 1. Baixar arquivo
714
+ print(f"⬇️ [Groq] Baixando arquivo para pré-processamento...")
715
+ try:
716
+ response = download_file_with_retry(url)
717
+ except Exception as e:
718
+ print(f"⚠️ Falha ao baixar arquivo para Groq: {e}")
719
+ raise HTTPException(status_code=400, detail=f"Falha ao baixar arquivo: {e}")
 
 
 
 
 
 
 
 
 
 
 
 
 
720
 
721
+ # Salvar temp
722
+ content_type = response.headers.get('content-type', '').lower()
723
+ ext = '.mp3' # Default fallback
724
+ if 'video' in content_type: ext = '.mp4'
725
+ elif 'audio' in content_type: ext = '.mp3'
726
 
727
+ temp_input = tempfile.NamedTemporaryFile(delete=False, suffix=ext)
728
+ try:
729
+ for chunk in response.iter_content(chunk_size=8192):
730
+ if chunk:
731
+ temp_input.write(chunk)
732
+ temp_input.close()
733
+
734
+ # 2. Pré-processar (Remover ruído, filtrar voz, etc)
735
+ print(f"🔊 [Groq] Pré-processando áudio (Isolamento de voz + Highpass/Lowpass)...")
736
+ processed_file_path = process_audio_for_transcription(temp_input.name)
737
+
738
+ # 3. Enviar para Groq
739
+ groq_url = "https://api.groq.com/openai/v1/audio/transcriptions"
740
+ headers = {
741
+ "Authorization": f"Bearer {GROQ_API_KEY}"
742
+ }
743
+
744
+ # Abrir arquivo processado
745
+ with open(processed_file_path, "rb") as f:
746
+ files = {
747
+ "model": (None, "whisper-large-v3"),
748
+ "file": ("audio.mp3", f, "audio/mpeg"), # Mandar como file
749
+ "temperature": (None, str(temperature)),
750
+ "timestamp_granularities[]": (None, "word"),
751
+ "response_format": (None, "verbose_json")
752
+ }
753
 
754
+ if language and language in GROQ_SUPPORTED_LANGUAGES:
755
+ files["language"] = (None, language)
 
756
 
757
+ print(f"🧠 [Groq] Enviando ÁUDIO PROCESSADO para API...")
 
 
 
758
 
759
+ max_retries = 3
760
+ result = None
 
 
 
 
 
 
 
 
761
 
762
+ for attempt in range(max_retries):
763
+ try:
764
+ # Precisamos resetar o ponteiro do arquivo se for retry?
765
+ # O requests deve ler tudo. Se falhar, na proxima tentativa, o 'f' ja foi lido.
766
+ # Mover seek(0) é importante.
767
+ f.seek(0)
768
+
769
+ response_groq = requests.post(groq_url, headers=headers, files=files, timeout=300)
770
+
771
+ if response_groq.status_code == 200:
772
+ result = response_groq.json()
773
+ break
774
+
775
+ error_msg = response_groq.text.lower()
776
+ is_deadline = "context deadline exceeded" in error_msg
777
+ is_server = response_groq.status_code >= 500
778
+
779
+ if (is_deadline or is_server) and attempt < max_retries - 1:
780
+ wait_time = 2 * (attempt + 1)
781
+ print(f"⚠️ Erro transiente Groq ({response_groq.status_code}). Retentando em {wait_time}s...")
782
+ await asyncio.sleep(wait_time)
783
+ continue
784
+
785
+ raise HTTPException(status_code=response_groq.status_code, detail=f"Erro Groq: {response_groq.text}")
786
+
787
+ except requests.RequestException as e:
788
+ if attempt < max_retries - 1:
789
+ print(f"⚠️ Erro conexão Groq. Retentando...")
790
+ await asyncio.sleep(2)
791
+ continue
792
+ raise HTTPException(status_code=500, detail=f"Erro conexão Groq: {e}")
793
 
794
+ finally:
795
+ # Cleanup
796
+ if os.path.exists(temp_input.name):
797
+ try: os.unlink(temp_input.name)
798
+ except: pass
799
+ # Se process_audio criou um arquivo novo (com sufixo .processed.mp3)
800
+ if 'processed_file_path' in locals() and processed_file_path != temp_input.name and os.path.exists(processed_file_path):
801
+ try: os.unlink(processed_file_path)
802
+ except: pass
803
+
804
+ # Converter para SRT
805
  srt_word = groq_json_to_srt(result)
 
 
806
  srt_filtered = apply_netflix_style_filter(srt_word)
807
 
808
  return srt_filtered, srt_word