vicmanmkt commited on
Commit
3d8050d
·
verified ·
1 Parent(s): 10ba768

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +326 -105
app.py CHANGED
@@ -6,223 +6,425 @@ import google.generativeai as genai
6
  import time
7
  import tempfile
8
  from PIL import Image
 
9
 
10
  class PDFTranscriberGradio:
11
  def __init__(self):
12
  self.temp_files = []
 
 
 
13
 
14
  def get_selected_model(self, model_choice):
15
  """Retorna o ID do modelo selecionado"""
16
  return model_choice.split(" - ")[0].strip()
17
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
  def convert_pdf_page_to_image(self, pdf_document, page_number):
19
  """Converte uma página do PDF em imagem e salva temporariamente"""
20
- page = pdf_document[page_number]
21
- pix = page.get_pixmap(matrix=fitz.Matrix(2, 2))
22
- img_data = pix.tobytes("png")
23
-
24
- # Criar arquivo temporário com nome único baseado no timestamp
25
- temp_filename = f'page_{page_number}_{int(time.time()*1000)}.png'
26
- temp_path = os.path.join(tempfile.gettempdir(), temp_filename)
27
-
28
- with open(temp_path, 'wb') as temp_file:
29
- temp_file.write(img_data)
30
-
31
- # Adicionar à lista de arquivos temporários
32
- self.temp_files.append(temp_path)
33
- return temp_path
 
 
 
 
 
 
 
34
 
35
  def analyze_page_with_gemini(self, image_path, page_num, model_name, temperature, top_p, top_k):
36
  """Analisa uma página usando o modelo Gemini selecionado"""
37
  try:
38
- # Carregar a imagem
39
  img = Image.open(image_path)
 
40
 
41
  # Configurar o modelo Gemini
42
  model = genai.GenerativeModel(model_name)
43
 
44
- # Criar prompt
45
- prompt = """Analise esta página do documento em detalhes. Por favor, inclua:
46
- 1. Conteúdo textual e sua organização
47
- 2. Layout e estrutura visual
48
- 3. Elementos gráficos, tabelas ou imagens
49
- 4. Informações importantes ou destaques
50
- 5. Formatação e estilo do documento"""
 
 
 
 
51
 
52
- # Gerar resposta
53
- response = model.generate_content([prompt, img], generation_config={
54
  'temperature': temperature,
55
- 'max_output_tokens': 4096,
56
  'top_p': top_p,
57
  'top_k': int(top_k),
58
- })
59
 
60
- # Fechar a imagem explicitamente
 
 
 
 
 
 
61
  img.close()
62
 
 
63
  return response.text
64
 
65
  except Exception as e:
66
- return f"Erro ao analisar página {page_num}: {str(e)}"
 
 
67
 
68
  def cleanup_temp_files(self):
69
- """Limpa todos os arquivos temporários"""
 
70
  for temp_file in self.temp_files:
71
  try:
72
  if os.path.exists(temp_file):
73
- # Tentar várias vezes em caso de arquivo em uso
74
- for _ in range(3):
75
  try:
76
  os.unlink(temp_file)
 
77
  break
78
  except PermissionError:
79
  time.sleep(0.5)
 
 
 
 
80
  except Exception as e:
81
- print(f"Aviso: Não foi possível remover arquivo temporário {temp_file}: {e}")
 
82
  self.temp_files = []
 
83
 
84
  def extract_text_from_pdf(self, pdf_path):
 
85
  try:
86
  doc = fitz.open(pdf_path)
87
- text = ""
88
- for page in doc:
89
- text += page.get_text()
90
- return text
 
 
 
 
 
 
 
 
 
91
  except Exception as e:
92
  raise Exception(f"Erro ao extrair texto do PDF: {str(e)}")
93
 
94
  def process_pdf(self, pdf_file, api_key, model_choice, temperature, top_p, top_k):
95
- status_updates = ["Iniciando processamento..."]
 
96
  yield "\n".join(status_updates), None, None
97
 
98
  try:
99
  # Verificar se o arquivo foi fornecido
100
  if pdf_file is None:
101
- raise Exception("Nenhum arquivo enviado")
102
-
103
- # Configurar API Gemini
 
 
 
 
 
 
 
 
 
 
 
 
 
 
104
  if not api_key or api_key.strip() == "":
105
- raise Exception("API Key não fornecida")
106
- genai.configure(api_key=api_key)
 
 
107
 
108
  # Obter o modelo selecionado
109
  model_name = self.get_selected_model(model_choice)
 
 
110
 
111
  # Abrir o PDF
112
- # Gradio retorna um objeto NamedString, precisamos usar o caminho do arquivo
113
- doc = fitz.open(pdf_file.name)
114
 
115
- # Extrair texto tradicional
116
- status_updates.append("Extraindo texto do PDF...")
117
  yield "\n".join(status_updates), None, None
118
 
119
- text_content = ""
120
- for page in doc:
121
- text_content += page.get_text()
122
 
123
- # Analisar cada página como imagem
124
- status_updates.append("Analisando páginas como imagens...")
 
 
125
  yield "\n".join(status_updates), None, None
126
 
127
  page_analyses = []
128
 
129
- for page_num in range(len(doc)):
130
- status_updates.append(f"Processando página {page_num + 1} de {len(doc)}...")
131
  yield "\n".join(status_updates), None, None
132
 
133
- image_path = self.convert_pdf_page_to_image(doc, page_num)
134
- analysis = self.analyze_page_with_gemini(
135
- image_path,
136
- page_num + 1,
137
- model_name,
138
- temperature,
139
- top_p,
140
- top_k
141
- )
142
- page_analyses.append(f"\n=== Análise da Página {page_num + 1} ===\n{analysis}")
143
-
144
- # Combinar resultados
145
- final_output = "=== CONTEÚDO TEXTUAL ===\n\n"
146
- final_output += text_content
147
- final_output += "\n\n=== ANÁLISE VISUAL DAS PÁGINAS ===\n"
148
- final_output += "\n".join(page_analyses)
149
-
150
- # Gerar nome para arquivo de saída
151
- output_filename = f"analise_pdf_{int(time.time())}.txt"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
152
  output_path = os.path.join(tempfile.gettempdir(), output_filename)
153
 
154
- # Salvar resultado
155
  with open(output_path, 'w', encoding='utf-8') as f:
156
  f.write(final_output)
157
 
158
- status_updates.append(f"Análise completa! Arquivo salvo temporariamente.")
 
159
 
160
- # Retornar o conteúdo e o caminho do arquivo para download
161
  yield "\n".join(status_updates), final_output, output_path
162
 
163
  except Exception as e:
164
- error_msg = f"Erro: {str(e)}"
165
  status_updates.append(error_msg)
 
166
  yield "\n".join(status_updates), None, None
167
 
168
  finally:
169
- # Limpar arquivos temporários
170
  self.cleanup_temp_files()
171
 
172
  def create_interface(self):
173
- with gr.Blocks(title="Transcritor de PDF com Gemini API") as interface:
174
- gr.Markdown("# Transcritor de PDF com Gemini API")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
175
 
176
  with gr.Row():
177
- with gr.Column():
178
- api_key = gr.Textbox(label="API Key Gemini", type="password")
179
- pdf_file = gr.File(label="Arquivo PDF", file_types=[".pdf"])
180
 
181
- with gr.Row():
182
- model_choice = gr.Dropdown(
183
- label="Modelo",
184
- choices=[
185
- "gemini-2.0-flash-exp - Última geração (Experimental)",
186
- "gemini-1.5-flash - Rápido e versátil",
187
- "gemini-1.5-flash-8b - Alto volume",
188
- "gemini-1.5-pro - Raciocínio complexo"
189
- ],
190
- value="gemini-1.5-pro - Raciocínio complexo"
191
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
192
 
193
  with gr.Row():
194
  temperature = gr.Slider(
195
- label="Temperatura",
196
  minimum=0.0,
197
  maximum=1.0,
198
  step=0.1,
199
- value=0.4
 
200
  )
201
 
202
  with gr.Row():
203
  top_p = gr.Slider(
204
- label="Top P",
205
  minimum=0.0,
206
  maximum=1.0,
207
  step=0.1,
208
- value=0.8
 
209
  )
210
 
211
  top_k = gr.Slider(
212
- label="Top K",
213
  minimum=1,
214
  maximum=40,
215
  step=1,
216
- value=32
 
217
  )
218
 
219
- process_button = gr.Button("Transcrever e Analisar")
 
 
 
 
220
 
221
- with gr.Column():
222
- status_output = gr.Textbox(label="Status", lines=10)
223
- result_output = gr.Textbox(label="Resultado", lines=20)
224
- file_output = gr.File(label="Download do Resultado")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
225
 
 
226
  process_button.click(
227
  fn=self.process_pdf,
228
  inputs=[pdf_file, api_key, model_choice, temperature, top_p, top_k],
@@ -230,12 +432,31 @@ class PDFTranscriberGradio:
230
  show_progress=True
231
  )
232
 
 
 
 
 
 
 
 
 
 
 
 
 
233
  return interface
234
 
235
  def run(self):
 
236
  interface = self.create_interface()
237
- interface.launch()
 
 
 
 
 
238
 
 
239
  if __name__ == "__main__":
240
  app = PDFTranscriberGradio()
241
  app.run()
 
6
  import time
7
  import tempfile
8
  from PIL import Image
9
+ import logging
10
 
11
  class PDFTranscriberGradio:
12
  def __init__(self):
13
  self.temp_files = []
14
+ # Configurar logging para debug
15
+ logging.basicConfig(level=logging.INFO)
16
+ self.logger = logging.getLogger(__name__)
17
 
18
  def get_selected_model(self, model_choice):
19
  """Retorna o ID do modelo selecionado"""
20
  return model_choice.split(" - ")[0].strip()
21
 
22
+ def validate_pdf_file(self, file_path):
23
+ """Valida se o arquivo é um PDF usando múltiplos métodos"""
24
+ try:
25
+ self.logger.info(f"Validando arquivo: {file_path}")
26
+
27
+ # Método 1: Verificar se o arquivo existe
28
+ if not os.path.exists(file_path):
29
+ return False, "Arquivo não encontrado"
30
+
31
+ # Método 2: Verificar tamanho do arquivo
32
+ file_size = os.path.getsize(file_path)
33
+ if file_size == 0:
34
+ return False, "Arquivo está vazio"
35
+
36
+ # Método 3: Tentar abrir com PyMuPDF
37
+ try:
38
+ doc = fitz.open(file_path)
39
+ if doc.page_count > 0:
40
+ doc.close()
41
+ return True, f"PDF válido com {doc.page_count} página(s)"
42
+ else:
43
+ return False, "PDF não contém páginas"
44
+ except Exception as e:
45
+ self.logger.warning(f"PyMuPDF falhou: {e}")
46
+
47
+ # Método 4: Verificar header do arquivo
48
+ try:
49
+ with open(file_path, 'rb') as f:
50
+ header = f.read(8)
51
+ if header.startswith(b'%PDF-'):
52
+ return True, "PDF detectado por header (pode ter problemas estruturais)"
53
+ except Exception as e:
54
+ self.logger.warning(f"Verificação de header falhou: {e}")
55
+
56
+ return False, "Arquivo não é um PDF válido ou está corrompido"
57
+
58
+ except Exception as e:
59
+ return False, f"Erro na validação: {str(e)}"
60
+
61
  def convert_pdf_page_to_image(self, pdf_document, page_number):
62
  """Converte uma página do PDF em imagem e salva temporariamente"""
63
+ try:
64
+ page = pdf_document[page_number]
65
+ # Usar matriz de alta resolução para melhor qualidade
66
+ pix = page.get_pixmap(matrix=fitz.Matrix(2, 2))
67
+ img_data = pix.tobytes("png")
68
+
69
+ # Criar arquivo temporário com nome único
70
+ temp_filename = f'page_{page_number}_{int(time.time()*1000)}_{os.getpid()}.png'
71
+ temp_path = os.path.join(tempfile.gettempdir(), temp_filename)
72
+
73
+ with open(temp_path, 'wb') as temp_file:
74
+ temp_file.write(img_data)
75
+
76
+ # Adicionar à lista de arquivos temporários para limpeza posterior
77
+ self.temp_files.append(temp_path)
78
+ self.logger.info(f"Página {page_number} convertida para: {temp_path}")
79
+ return temp_path
80
+
81
+ except Exception as e:
82
+ self.logger.error(f"Erro ao converter página {page_number}: {e}")
83
+ raise Exception(f"Erro ao converter página {page_number}: {str(e)}")
84
 
85
  def analyze_page_with_gemini(self, image_path, page_num, model_name, temperature, top_p, top_k):
86
  """Analisa uma página usando o modelo Gemini selecionado"""
87
  try:
88
+ # Carregar e verificar a imagem
89
  img = Image.open(image_path)
90
+ self.logger.info(f"Analisando página {page_num} com modelo {model_name}")
91
 
92
  # Configurar o modelo Gemini
93
  model = genai.GenerativeModel(model_name)
94
 
95
+ # Prompt otimizado para transcrição detalhada
96
+ prompt = """Analise esta página do documento PDF em detalhes. Forneça uma transcrição completa e organizada incluindo:
97
+
98
+ 1. **TEXTO COMPLETO**: Transcreva todo o texto visível, mantendo a formatação e organização original
99
+ 2. **ESTRUTURA DO DOCUMENTO**: Descreva títulos, subtítulos, parágrafos, listas, etc.
100
+ 3. **ELEMENTOS VISUAIS**: Descreva tabelas, gráficos, imagens, logotipos ou elementos gráficos
101
+ 4. **FORMATAÇÃO**: Mencione textos em negrito, itálico, cores especiais, tamanhos de fonte diferentes
102
+ 5. **LAYOUT**: Descreva como o conteúdo está organizado na página (colunas, seções, etc.)
103
+ 6. **INFORMAÇÕES IMPORTANTES**: Destaque dados relevantes, números, datas, nomes, certificações, etc.
104
+
105
+ Seja preciso e detalhado na transcrição do texto."""
106
 
107
+ # Configuração de geração otimizada
108
+ generation_config = {
109
  'temperature': temperature,
110
+ 'max_output_tokens': 8192, # Aumentado para respostas mais completas
111
  'top_p': top_p,
112
  'top_k': int(top_k),
113
+ }
114
 
115
+ # Gerar resposta
116
+ response = model.generate_content(
117
+ [prompt, img],
118
+ generation_config=generation_config
119
+ )
120
+
121
+ # Fechar a imagem explicitamente para liberar memória
122
  img.close()
123
 
124
+ self.logger.info(f"Análise da página {page_num} concluída")
125
  return response.text
126
 
127
  except Exception as e:
128
+ error_msg = f"Erro ao analisar página {page_num}: {str(e)}"
129
+ self.logger.error(error_msg)
130
+ return error_msg
131
 
132
  def cleanup_temp_files(self):
133
+ """Limpa todos os arquivos temporários criados durante o processamento"""
134
+ cleaned_count = 0
135
  for temp_file in self.temp_files:
136
  try:
137
  if os.path.exists(temp_file):
138
+ # Tentar remover o arquivo com retry em caso de uso
139
+ for attempt in range(3):
140
  try:
141
  os.unlink(temp_file)
142
+ cleaned_count += 1
143
  break
144
  except PermissionError:
145
  time.sleep(0.5)
146
+ except Exception as e:
147
+ self.logger.warning(f"Tentativa {attempt + 1} falhou para {temp_file}: {e}")
148
+ if attempt == 2: # Última tentativa
149
+ break
150
  except Exception as e:
151
+ self.logger.warning(f"Erro ao remover arquivo temporário {temp_file}: {e}")
152
+
153
  self.temp_files = []
154
+ self.logger.info(f"Limpeza concluída: {cleaned_count} arquivos removidos")
155
 
156
  def extract_text_from_pdf(self, pdf_path):
157
+ """Extrai texto diretamente do PDF usando PyMuPDF"""
158
  try:
159
  doc = fitz.open(pdf_path)
160
+ text_content = ""
161
+
162
+ for page_num in range(len(doc)):
163
+ page = doc[page_num]
164
+ page_text = page.get_text()
165
+ if page_text.strip(): # Só adiciona se a página tiver texto
166
+ text_content += f"\n=== PÁGINA {page_num + 1} - TEXTO EXTRAÍDO ===\n"
167
+ text_content += page_text
168
+ text_content += "\n" + "="*50 + "\n"
169
+
170
+ doc.close()
171
+ return text_content if text_content.strip() else "Nenhum texto extraível encontrado no PDF"
172
+
173
  except Exception as e:
174
  raise Exception(f"Erro ao extrair texto do PDF: {str(e)}")
175
 
176
  def process_pdf(self, pdf_file, api_key, model_choice, temperature, top_p, top_k):
177
+ """Função principal para processar o PDF"""
178
+ status_updates = ["🔄 Iniciando processamento do PDF..."]
179
  yield "\n".join(status_updates), None, None
180
 
181
  try:
182
  # Verificar se o arquivo foi fornecido
183
  if pdf_file is None:
184
+ raise Exception("❌ Nenhum arquivo foi enviado")
185
+
186
+ # Obter o caminho do arquivo
187
+ file_path = pdf_file.name if hasattr(pdf_file, 'name') else pdf_file
188
+
189
+ status_updates.append(f"📁 Arquivo recebido: {os.path.basename(file_path)}")
190
+ yield "\n".join(status_updates), None, None
191
+
192
+ # Validar o arquivo PDF
193
+ is_valid, validation_msg = self.validate_pdf_file(file_path)
194
+ if not is_valid:
195
+ raise Exception(f"❌ {validation_msg}")
196
+
197
+ status_updates.append(f"✅ {validation_msg}")
198
+ yield "\n".join(status_updates), None, None
199
+
200
+ # Verificar API Key
201
  if not api_key or api_key.strip() == "":
202
+ raise Exception("❌ API Key do Gemini não fornecida")
203
+
204
+ # Configurar API Gemini
205
+ genai.configure(api_key=api_key.strip())
206
 
207
  # Obter o modelo selecionado
208
  model_name = self.get_selected_model(model_choice)
209
+ status_updates.append(f"🤖 Modelo selecionado: {model_name}")
210
+ yield "\n".join(status_updates), None, None
211
 
212
  # Abrir o PDF
213
+ doc = fitz.open(file_path)
214
+ total_pages = len(doc)
215
 
216
+ status_updates.append(f"📄 PDF aberto: {total_pages} página(s) encontrada(s)")
 
217
  yield "\n".join(status_updates), None, None
218
 
219
+ # Extrair texto tradicional primeiro
220
+ status_updates.append("📝 Extraindo texto diretamente do PDF...")
221
+ yield "\n".join(status_updates), None, None
222
 
223
+ extracted_text = self.extract_text_from_pdf(file_path)
224
+
225
+ # Analisar cada página como imagem com IA
226
+ status_updates.append("🔍 Iniciando análise visual com IA...")
227
  yield "\n".join(status_updates), None, None
228
 
229
  page_analyses = []
230
 
231
+ for page_num in range(total_pages):
232
+ status_updates.append(f"🖼️ Processando página {page_num + 1} de {total_pages}...")
233
  yield "\n".join(status_updates), None, None
234
 
235
+ try:
236
+ # Converter página para imagem
237
+ image_path = self.convert_pdf_page_to_image(doc, page_num)
238
+
239
+ # Analisar com Gemini
240
+ analysis = self.analyze_page_with_gemini(
241
+ image_path,
242
+ page_num + 1,
243
+ model_name,
244
+ temperature,
245
+ top_p,
246
+ top_k
247
+ )
248
+
249
+ page_analyses.append(f"\n{'='*60}\n📄 ANÁLISE DETALHADA DA PÁGINA {page_num + 1}\n{'='*60}\n{analysis}")
250
+
251
+ except Exception as e:
252
+ error_analysis = f"❌ Erro ao processar página {page_num + 1}: {str(e)}"
253
+ page_analyses.append(f"\n{'='*60}\n📄 PÁGINA {page_num + 1} - ERRO\n{'='*60}\n{error_analysis}")
254
+
255
+ # Fechar o documento
256
+ doc.close()
257
+
258
+ # Combinar todos os resultados
259
+ status_updates.append("📋 Compilando resultado final...")
260
+ yield "\n".join(status_updates), None, None
261
+
262
+ final_output = f"""{'='*80}
263
+ 🔍 TRANSCRIÇÃO COMPLETA DO PDF
264
+ {'='*80}
265
+
266
+ 📄 ARQUIVO: {os.path.basename(file_path)}
267
+ 🤖 MODELO USADO: {model_name}
268
+ 📊 TOTAL DE PÁGINAS: {total_pages}
269
+ ⏰ PROCESSADO EM: {time.strftime('%Y-%m-%d %H:%M:%S')}
270
+
271
+ {'='*80}
272
+ 📝 TEXTO EXTRAÍDO DIRETAMENTE
273
+ {'='*80}
274
+ {extracted_text}
275
+
276
+ {'='*80}
277
+ 🔍 ANÁLISE VISUAL DETALHADA POR IA
278
+ {'='*80}
279
+ {chr(10).join(page_analyses)}
280
+
281
+ {'='*80}
282
+ ✅ PROCESSAMENTO CONCLUÍDO
283
+ {'='*80}
284
+ """
285
+
286
+ # Salvar resultado em arquivo
287
+ output_filename = f"transcricao_pdf_{int(time.time())}.txt"
288
  output_path = os.path.join(tempfile.gettempdir(), output_filename)
289
 
 
290
  with open(output_path, 'w', encoding='utf-8') as f:
291
  f.write(final_output)
292
 
293
+ status_updates.append("✅ Processamento concluído com sucesso!")
294
+ status_updates.append(f"💾 Arquivo salvo: {output_filename}")
295
 
296
+ # Retornar resultado final
297
  yield "\n".join(status_updates), final_output, output_path
298
 
299
  except Exception as e:
300
+ error_msg = f"❌ ERRO: {str(e)}"
301
  status_updates.append(error_msg)
302
+ self.logger.error(error_msg)
303
  yield "\n".join(status_updates), None, None
304
 
305
  finally:
306
+ # Sempre limpar arquivos temporários
307
  self.cleanup_temp_files()
308
 
309
  def create_interface(self):
310
+ """Cria a interface Gradio"""
311
+ with gr.Blocks(
312
+ title="Transcritor de PDF com Gemini AI",
313
+ theme=gr.themes.Soft(),
314
+ css="""
315
+ .gradio-container {
316
+ max-width: 1200px !important;
317
+ margin: auto;
318
+ }
319
+ """
320
+ ) as interface:
321
+
322
+ gr.Markdown("""
323
+ # 🔍 Transcritor de PDF com Gemini AI
324
+
325
+ **Ferramenta avançada para transcrição e análise de documentos PDF**
326
+
327
+ ✨ **Recursos:**
328
+ - 📝 Extração de texto nativo do PDF
329
+ - 🖼️ Análise visual inteligente com IA
330
+ - 📊 Descrição de tabelas, gráficos e elementos visuais
331
+ - 💾 Download do resultado completo
332
+
333
+ ⚠️ **Requisitos:**
334
+ - API Key válida do Google Gemini AI
335
+ - Arquivo PDF (máximo recomendado: 20 páginas)
336
+ """)
337
 
338
  with gr.Row():
339
+ with gr.Column(scale=1):
340
+ gr.Markdown("### ⚙️ Configurações")
 
341
 
342
+ api_key = gr.Textbox(
343
+ label="🔑 API Key Gemini",
344
+ type="password",
345
+ placeholder="Insira sua API key do Google Gemini AI",
346
+ info="Obtenha em: https://ai.google.dev/"
347
+ )
348
+
349
+ pdf_file = gr.File(
350
+ label="📄 Arquivo PDF",
351
+ file_types=[".pdf"],
352
+ info="Selecione o arquivo PDF para transcrever"
353
+ )
354
+
355
+ model_choice = gr.Dropdown(
356
+ label="🤖 Modelo Gemini",
357
+ choices=[
358
+ "gemini-2.0-flash-exp - Última geração (Experimental)",
359
+ "gemini-1.5-flash - Rápido e versátil",
360
+ "gemini-1.5-flash-8b - Alto volume",
361
+ "gemini-1.5-pro - Raciocínio complexo"
362
+ ],
363
+ value="gemini-1.5-pro - Raciocínio complexo",
364
+ info="Escolha o modelo mais adequado para sua necessidade"
365
+ )
366
+
367
+ gr.Markdown("#### 🎛️ Parâmetros Avançados")
368
 
369
  with gr.Row():
370
  temperature = gr.Slider(
371
+ label="🌡️ Temperatura",
372
  minimum=0.0,
373
  maximum=1.0,
374
  step=0.1,
375
+ value=0.1,
376
+ info="Controla a criatividade (0.0 = mais preciso)"
377
  )
378
 
379
  with gr.Row():
380
  top_p = gr.Slider(
381
+ label="🎯 Top P",
382
  minimum=0.0,
383
  maximum=1.0,
384
  step=0.1,
385
+ value=0.9,
386
+ info="Controla a diversidade das respostas"
387
  )
388
 
389
  top_k = gr.Slider(
390
+ label="🔢 Top K",
391
  minimum=1,
392
  maximum=40,
393
  step=1,
394
+ value=40,
395
+ info="Número de tokens considerados"
396
  )
397
 
398
+ process_button = gr.Button(
399
+ "🚀 Transcrever e Analisar",
400
+ variant="primary",
401
+ size="lg"
402
+ )
403
 
404
+ with gr.Column(scale=2):
405
+ gr.Markdown("### 📊 Resultados")
406
+
407
+ status_output = gr.Textbox(
408
+ label="📋 Status do Processamento",
409
+ lines=8,
410
+ max_lines=15,
411
+ info="Acompanhe o progresso em tempo real"
412
+ )
413
+
414
+ result_output = gr.Textbox(
415
+ label="📄 Transcrição Completa",
416
+ lines=20,
417
+ max_lines=30,
418
+ show_copy_button=True,
419
+ info="Resultado completo da transcrição"
420
+ )
421
+
422
+ file_output = gr.File(
423
+ label="💾 Download do Resultado",
424
+ info="Baixe o arquivo completo da transcrição"
425
+ )
426
 
427
+ # Conectar o botão à função
428
  process_button.click(
429
  fn=self.process_pdf,
430
  inputs=[pdf_file, api_key, model_choice, temperature, top_p, top_k],
 
432
  show_progress=True
433
  )
434
 
435
+ gr.Markdown("""
436
+ ### 💡 Dicas de Uso
437
+
438
+ 1. **API Key**: Obtenha gratuitamente em [Google AI Studio](https://ai.google.dev/)
439
+ 2. **Qualidade**: PDFs com texto nativo produzem melhores resultados
440
+ 3. **Tamanho**: Para PDFs grandes (>20 páginas), considere dividir em partes
441
+ 4. **Modelos**:
442
+ - **Gemini 1.5 Pro**: Melhor para análise complexa
443
+ - **Gemini 1.5 Flash**: Mais rápido para documentos simples
444
+ 5. **Parâmetros**: Use temperatura baixa (0.1-0.3) para maior precisão
445
+ """)
446
+
447
  return interface
448
 
449
  def run(self):
450
+ """Inicia a aplicação"""
451
  interface = self.create_interface()
452
+ interface.launch(
453
+ server_name="0.0.0.0",
454
+ server_port=7860,
455
+ share=False,
456
+ show_error=True
457
+ )
458
 
459
+ # Ponto de entrada da aplicação
460
  if __name__ == "__main__":
461
  app = PDFTranscriberGradio()
462
  app.run()