Guilherme Favaron commited on
Commit
d0a511b
·
1 Parent(s): 98b5ba1

Atualizar Listen Lynx com novos modelos GPT-4o e suporte a arquivos grandes

Browse files

- Adicionar modelos gpt-4o-audio-preview e gpt-4o-mini-audio-preview
- Implementar sistema de chunking para arquivos >25MB
- Dividir arquivos grandes em chunks de 20MB
- Junção automática das transcrições
- Melhorar interface com seleção de modelos
- Corrigir bug de transcrição com response_format='text'
- Remover chave da API do .env (usar variáveis secretas do HF Space)

Files changed (2) hide show
  1. .env +2 -0
  2. app.py +145 -17
.env ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ # OpenAI API Key
2
+ # OPENAI_API_KEY será carregada das variáveis secretas do Hugging Face Space
app.py CHANGED
@@ -4,6 +4,7 @@ import gradio as gr
4
  from openai import OpenAI
5
  from pydub import AudioSegment
6
  import tempfile
 
7
 
8
  # Carrega as variáveis de ambiente do arquivo .env
9
  load_dotenv()
@@ -11,35 +12,162 @@ load_dotenv()
11
  # Configura o cliente OpenAI com a chave da API do arquivo .env
12
  client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
13
 
 
 
 
 
 
 
 
 
 
14
  def convert_to_mp3(audio_path):
 
15
  audio = AudioSegment.from_file(audio_path)
16
  mp3_path = tempfile.mktemp(suffix=".mp3")
17
  audio.export(mp3_path, format="mp3")
18
  return mp3_path
19
 
20
- def transcribe_audio(audio_path):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
  try:
22
  # Converter para MP3 se necessário
23
  file_ext = os.path.splitext(audio_path)[1].lower()
24
  if file_ext != ".mp3":
25
  audio_path = convert_to_mp3(audio_path)
26
 
27
- with open(audio_path, "rb") as audio_file:
28
- transcription = client.audio.transcriptions.create(
29
- model="whisper-1",
30
- file=audio_file
31
- )
32
- return transcription.text
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  except Exception as e:
34
- return f"Erro na transcrição: {str(e)}"
 
 
 
 
 
 
 
35
 
36
  # Interface Gradio
37
- iface = gr.Interface(
38
- fn=transcribe_audio,
39
- inputs=gr.Audio(type="filepath"),
40
- outputs="text",
41
- title="Transcrição de Áudio com IA",
42
- description="Faça upload de um arquivo de áudio para transcrevê-lo usando IA avançada."
43
- )
44
-
45
- iface.launch()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
  from openai import OpenAI
5
  from pydub import AudioSegment
6
  import tempfile
7
+ import math
8
 
9
  # Carrega as variáveis de ambiente do arquivo .env
10
  load_dotenv()
 
12
  # Configura o cliente OpenAI com a chave da API do arquivo .env
13
  client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
14
 
15
+ # Constantes para controle de tamanho de arquivo
16
+ MAX_FILE_SIZE_MB = 25
17
+ CHUNK_SIZE_MB = 20
18
+ CHUNK_SIZE_BYTES = CHUNK_SIZE_MB * 1024 * 1024
19
+
20
+ def get_file_size_mb(file_path):
21
+ """Retorna o tamanho do arquivo em MB"""
22
+ return os.path.getsize(file_path) / (1024 * 1024)
23
+
24
  def convert_to_mp3(audio_path):
25
+ """Converte áudio para MP3"""
26
  audio = AudioSegment.from_file(audio_path)
27
  mp3_path = tempfile.mktemp(suffix=".mp3")
28
  audio.export(mp3_path, format="mp3")
29
  return mp3_path
30
 
31
+ def split_audio_by_size(audio_path, max_size_mb=CHUNK_SIZE_MB):
32
+ """Divide o áudio em chunks baseado no tamanho em MB"""
33
+ audio = AudioSegment.from_file(audio_path)
34
+
35
+ # Calcula o tamanho aproximado por milissegundo
36
+ file_size_mb = get_file_size_mb(audio_path)
37
+ duration_ms = len(audio)
38
+ mb_per_ms = file_size_mb / duration_ms
39
+
40
+ # Calcula a duração de cada chunk em milissegundos
41
+ chunk_duration_ms = int(max_size_mb / mb_per_ms)
42
+
43
+ chunks = []
44
+ start = 0
45
+ chunk_num = 0
46
+
47
+ while start < duration_ms:
48
+ end = min(start + chunk_duration_ms, duration_ms)
49
+ chunk = audio[start:end]
50
+
51
+ # Salva o chunk temporariamente
52
+ chunk_path = tempfile.mktemp(suffix=f"_chunk_{chunk_num}.mp3")
53
+ chunk.export(chunk_path, format="mp3")
54
+ chunks.append(chunk_path)
55
+
56
+ start = end
57
+ chunk_num += 1
58
+
59
+ return chunks
60
+
61
+ def transcribe_single_file(audio_path, model="gpt-4o-transcribe"):
62
+ """Transcreve um único arquivo de áudio"""
63
+ try:
64
+ with open(audio_path, "rb") as audio_file:
65
+ transcription = client.audio.transcriptions.create(
66
+ model=model,
67
+ file=audio_file,
68
+ response_format="text"
69
+ )
70
+ return transcription
71
+ except Exception as e:
72
+ return f"Erro na transcrição: {str(e)}"
73
+
74
+ def transcribe_audio(audio_path, model_choice="gpt-4o-transcribe"):
75
+ """Função principal de transcrição com suporte a arquivos grandes"""
76
  try:
77
  # Converter para MP3 se necessário
78
  file_ext = os.path.splitext(audio_path)[1].lower()
79
  if file_ext != ".mp3":
80
  audio_path = convert_to_mp3(audio_path)
81
 
82
+ # Verifica o tamanho do arquivo
83
+ file_size_mb = get_file_size_mb(audio_path)
84
+
85
+ if file_size_mb <= MAX_FILE_SIZE_MB:
86
+ # Arquivo pequeno - transcrição direta
87
+ return transcribe_single_file(audio_path, model_choice)
88
+ else:
89
+ # Arquivo grande - dividir em chunks
90
+ print(f"Arquivo grande detectado ({file_size_mb:.1f}MB). Dividindo em chunks...")
91
+
92
+ chunks = split_audio_by_size(audio_path, CHUNK_SIZE_MB)
93
+ transcriptions = []
94
+
95
+ for i, chunk_path in enumerate(chunks):
96
+ print(f"Transcrevendo chunk {i+1}/{len(chunks)}...")
97
+ chunk_transcription = transcribe_single_file(chunk_path, model_choice)
98
+
99
+ if chunk_transcription.startswith("Erro na transcrição:"):
100
+ return chunk_transcription
101
+
102
+ transcriptions.append(chunk_transcription)
103
+
104
+ # Limpa o arquivo temporário do chunk
105
+ try:
106
+ os.unlink(chunk_path)
107
+ except:
108
+ pass
109
+
110
+ # Junta todas as transcrições
111
+ full_transcription = " ".join(transcriptions)
112
+
113
+ return f"[Arquivo grande processado em {len(chunks)} partes]\n\n{full_transcription}"
114
+
115
  except Exception as e:
116
+ return f"Erro no processamento: {str(e)}"
117
+ finally:
118
+ # Limpa arquivos temporários
119
+ if 'audio_path' in locals() and audio_path != audio_path:
120
+ try:
121
+ os.unlink(audio_path)
122
+ except:
123
+ pass
124
 
125
  # Interface Gradio
126
+ with gr.Blocks(title="Listen Lynx - Transcrição de Áudio Avançada") as iface:
127
+ gr.Markdown("# 🎵 Listen Lynx - Transcrição de Áudio com IA")
128
+ gr.Markdown("Faça upload de arquivos de áudio para transcrevê-los usando os modelos mais avançados da OpenAI. Suporta arquivos grandes (até centenas de MB)!")
129
+
130
+ with gr.Row():
131
+ with gr.Column():
132
+ audio_input = gr.Audio(
133
+ type="filepath",
134
+ label="Arquivo de Áudio"
135
+ )
136
+
137
+ model_choice = gr.Dropdown(
138
+ choices=[
139
+ ("GPT-4o Transcribe (Recomendado)", "gpt-4o-transcribe"),
140
+ ("GPT-4o Mini Transcribe (Mais Rápido)", "gpt-4o-mini-transcribe"),
141
+ ("Whisper-1 (Clássico)", "whisper-1")
142
+ ],
143
+ value="gpt-4o-transcribe",
144
+ label="Modelo de Transcrição",
145
+ info="GPT-4o oferece maior qualidade e correção automática de erros"
146
+ )
147
+
148
+ transcribe_btn = gr.Button("🎯 Transcrever Áudio", variant="primary")
149
+
150
+ with gr.Column():
151
+ output_text = gr.Textbox(
152
+ label="Transcrição",
153
+ placeholder="A transcrição aparecerá aqui...",
154
+ lines=15,
155
+ max_lines=25
156
+ )
157
+
158
+ gr.Markdown("""
159
+ ### 📋 Informações:
160
+ - **Arquivos pequenos** (≤25MB): Processamento direto
161
+ - **Arquivos grandes** (>25MB): Divisão automática em chunks de 20MB
162
+ - **Modelos GPT-4o**: Correção automática de erros e melhor qualidade
163
+ - **Limite de upload**: Sem limite específico (processamento inteligente)
164
+ """)
165
+
166
+ transcribe_btn.click(
167
+ fn=transcribe_audio,
168
+ inputs=[audio_input, model_choice],
169
+ outputs=output_text
170
+ )
171
+
172
+ if __name__ == "__main__":
173
+ iface.launch()