CamiloVega commited on
Commit
f5c99c2
verified
1 Parent(s): 0219df1

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +373 -0
app.py ADDED
@@ -0,0 +1,373 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import openai
2
+
3
+ import whisper
4
+
5
+ import tempfile
6
+
7
+ import gradio as gr
8
+
9
+ from pydub import AudioSegment
10
+
11
+ import fitz # PyMuPDF para manejar PDFs
12
+
13
+ import docx # Para manejar archivos .docx
14
+
15
+ import pandas as pd # Para manejar archivos .xlsx y .csv
16
+
17
+
18
+
19
+ # Configura tu clave API de OpenAI
20
+
21
+ openai.api_key = "sk-proj-oa7IsWQdSibP9urkzepFT3BlbkFJ9L9tXiDZpjgPikmAhtQP"
22
+
23
+
24
+
25
+ # Cargar el modelo Whisper de mayor calidad
26
+
27
+ model = whisper.load_model("large")
28
+
29
+
30
+
31
+ def preprocess_audio(audio_file):
32
+
33
+ """Preprocesa el archivo de audio para mejorar la calidad."""
34
+
35
+ try:
36
+
37
+ audio = AudioSegment.from_file(audio_file)
38
+
39
+ # Normaliza el audio al -20 dBFS
40
+
41
+ audio = audio.apply_gain(-audio.dBFS + (-20))
42
+
43
+ # Exporta el audio procesado a un archivo temporal
44
+
45
+ with tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") as temp_file:
46
+
47
+ audio.export(temp_file.name, format="mp3")
48
+
49
+ return temp_file.name
50
+
51
+ except Exception as e:
52
+
53
+ return f"Error al preprocesar el archivo de audio: {str(e)}"
54
+
55
+
56
+
57
+ def transcribir_audio(audio_file):
58
+
59
+ """Transcribe un archivo de audio."""
60
+
61
+ try:
62
+
63
+ if isinstance(audio_file, str):
64
+
65
+ archivo_path = preprocess_audio(audio_file)
66
+
67
+ else:
68
+
69
+ with tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") as temp_file:
70
+
71
+ temp_file.write(audio_file.read())
72
+
73
+ temp_file.flush()
74
+
75
+ archivo_path = preprocess_audio(temp_file.name)
76
+
77
+ resultado = model.transcribe(archivo_path)
78
+
79
+ return resultado.get("text", "Error en la transcripci贸n")
80
+
81
+ except Exception as e:
82
+
83
+ return f"Error al procesar el archivo de audio: {str(e)}"
84
+
85
+
86
+
87
+ def leer_documento(documento_path):
88
+
89
+ """Lee el contenido de un documento PDF, DOCX, XLSX o CSV."""
90
+
91
+ try:
92
+
93
+ # Identificar el tipo de archivo
94
+
95
+ if documento_path.endswith(".pdf"):
96
+
97
+ doc = fitz.open(documento_path)
98
+
99
+ texto_completo = ""
100
+
101
+ for pagina in doc:
102
+
103
+ texto_completo += pagina.get_text()
104
+
105
+ return texto_completo
106
+
107
+ elif documento_path.endswith(".docx"):
108
+
109
+ doc = docx.Document(documento_path)
110
+
111
+ texto_completo = "\n".join([parrafo.text for parrafo in doc.paragraphs])
112
+
113
+ return texto_completo
114
+
115
+ elif documento_path.endswith(".xlsx"):
116
+
117
+ df = pd.read_excel(documento_path)
118
+
119
+ texto_completo = df.to_string()
120
+
121
+ return texto_completo
122
+
123
+ elif documento_path.endswith(".csv"):
124
+
125
+ df = pd.read_csv(documento_path)
126
+
127
+ texto_completo = df.to_string()
128
+
129
+ return texto_completo
130
+
131
+ else:
132
+
133
+ return "Tipo de archivo no soportado. Por favor suba un documento PDF, DOCX, XLSX o CSV."
134
+
135
+ except Exception as e:
136
+
137
+ return f"Error al leer el documento: {str(e)}"
138
+
139
+
140
+
141
+ def generar_noticia(instrucciones, hechos, tama帽o, tono, *args):
142
+
143
+ """Genera una noticia a partir de instrucciones, hechos y transcripciones."""
144
+
145
+ base_de_conocimiento = {
146
+
147
+ "instrucciones": instrucciones,
148
+
149
+ "hechos": hechos,
150
+
151
+ "contenido_documentos": [],
152
+
153
+ "audio_data": []
154
+
155
+ }
156
+
157
+
158
+
159
+ # Recolecta los documentos y el audio desde los argumentos
160
+
161
+ num_audios = 5 * 3 # 5 audios * 3 campos (audio, nombre, cargo)
162
+
163
+ audios = args[:num_audios]
164
+
165
+ documentos = args[num_audios:]
166
+
167
+
168
+
169
+ # Leer el contenido de los documentos si se han subido
170
+
171
+ for documento in documentos:
172
+
173
+ if documento is not None:
174
+
175
+ contenido_doc = leer_documento(documento.name)
176
+
177
+ print(f"Contenido del documento {documento.name}: {contenido_doc}")
178
+
179
+ base_de_conocimiento["contenido_documentos"].append(contenido_doc)
180
+
181
+
182
+
183
+ # Recolecta datos de cada archivo de audio
184
+
185
+ for i in range(0, len(audios), 3):
186
+
187
+ audio_file, nombre, cargo = audios[i:i+3]
188
+
189
+ if audio_file is not None:
190
+
191
+ base_de_conocimiento["audio_data"].append({"audio": audio_file, "nombre": nombre, "cargo": cargo})
192
+
193
+
194
+
195
+ transcripciones_texto = ""
196
+
197
+ transcripciones_brutas = ""
198
+
199
+ total_citas_directas = 0
200
+
201
+
202
+
203
+ # Transcribe y compila las transcripciones
204
+
205
+ for idx, data in enumerate(base_de_conocimiento["audio_data"]):
206
+
207
+ if data["audio"] is not None:
208
+
209
+ transcripcion = transcribir_audio(data["audio"])
210
+
211
+ transcripcion_texto = f'"{transcripcion}" - {data["nombre"]}, {data["cargo"]}'
212
+
213
+ transcripcion_bruta = f'[Audio {idx + 1}]: "{transcripcion}" - {data["nombre"]}, {data["cargo"]}'
214
+
215
+
216
+
217
+ # Decidir si usar cita directa o indirecta
218
+
219
+ if total_citas_directas < len(base_de_conocimiento["audio_data"]) * 0.8:
220
+
221
+ transcripciones_texto += transcripcion_texto + "\n"
222
+
223
+ total_citas_directas += 1
224
+
225
+ else:
226
+
227
+ transcripciones_texto += f'{data["nombre"]} mencion贸 que {transcripcion}' + "\n"
228
+
229
+
230
+
231
+ transcripciones_brutas += transcripcion_bruta + "\n\n"
232
+
233
+
234
+
235
+ print(f"Transcripci贸n bruta [Audio {idx + 1}]: {transcripcion_bruta}")
236
+
237
+ print(f"Transcripciones brutas acumuladas: {transcripciones_brutas}")
238
+
239
+
240
+
241
+ contenido_documentos = "\n\n".join(base_de_conocimiento["contenido_documentos"])
242
+
243
+
244
+
245
+ # Prompt adicional para instrucciones internas
246
+
247
+ prompt_interno = """
248
+
249
+ Instrucciones para el modelo:
250
+
251
+ - Aseg煤rate de que al menos el 80% de las citas sean directas y est茅n entrecomilladas.
252
+
253
+ - El 20% restante puede ser citas indirectas.
254
+
255
+ - No inventes informaci贸n nueva.
256
+
257
+ - S茅 riguroso con los hechos proporcionados.
258
+
259
+ - Al procesar los documentos cargados, extrae y resalta citas importantes y testimonios textuales de las fuentes.
260
+
261
+ - Al procesar los documentos cargados, extrae y resalta cifras clave.
262
+
263
+ """
264
+
265
+
266
+
267
+ # Compila el prompt para OpenAI
268
+
269
+ prompt = f"""
270
+
271
+ {prompt_interno}
272
+
273
+ Escribe una noticia con la siguiente informaci贸n, incluyendo un t铆tulo, un sumario de 20 palabras, y el cuerpo del contenido cuyo tama帽o es {tama帽o} palabras. El tono debe ser {tono}.
274
+
275
+ Instrucciones: {base_de_conocimiento["instrucciones"]}
276
+
277
+ Hechos: {base_de_conocimiento["hechos"]}
278
+
279
+ Contenido adicional de los documentos: {contenido_documentos}
280
+
281
+ Utiliza las siguientes transcripciones como citas directas e indirectas (sin cambiar ni inventar contenido):
282
+
283
+ {transcripciones_texto}
284
+
285
+ """
286
+
287
+
288
+
289
+ try:
290
+
291
+ respuesta = openai.ChatCompletion.create(
292
+
293
+ model="gpt-3.5-turbo",
294
+
295
+ messages=[{"role": "user", "content": prompt}],
296
+
297
+ temperature=0.1 # Bajamos la temperatura para mayor rigurosidad
298
+
299
+ )
300
+
301
+ noticia = respuesta['choices'][0]['message']['content']
302
+
303
+ return noticia, transcripciones_brutas
304
+
305
+ except Exception as e:
306
+
307
+ return f"Error al generar la noticia: {str(e)}", ""
308
+
309
+
310
+
311
+ with gr.Blocks() as demo:
312
+
313
+ gr.Markdown("## Chatbot de noticias")
314
+
315
+ with gr.Row():
316
+
317
+ with gr.Column(scale=2):
318
+
319
+ instrucciones = gr.Textbox(label="Instrucciones para la noticia", lines=2)
320
+
321
+ hechos = gr.Textbox(label="Describe los hechos de la noticia", lines=4)
322
+
323
+ tama帽o = gr.Number(label="Tama帽o del cuerpo de la noticia (en palabras)", value=100)
324
+
325
+ tono = gr.Dropdown(label="Tono de la noticia", choices=["serio", "neutral", "divertido"], value="neutral")
326
+
327
+ with gr.Column(scale=3):
328
+
329
+ inputs_list = [instrucciones, hechos, tama帽o, tono]
330
+
331
+ with gr.Tabs():
332
+
333
+ for i in range(1, 6):
334
+
335
+ with gr.TabItem(f"Audio {i}"):
336
+
337
+ audio = gr.Audio(type="filepath", label=f"Audio {i}")
338
+
339
+ nombre = gr.Textbox(label="Nombre", scale=1)
340
+
341
+ cargo = gr.Textbox(label="Cargo", scale=1)
342
+
343
+ inputs_list.extend([audio, nombre, cargo])
344
+
345
+ for i in range(1, 6):
346
+
347
+ with gr.TabItem(f"Documento {i}"):
348
+
349
+ documento = gr.File(label=f"Documento {i}", type="filepath", file_count="single")
350
+
351
+ inputs_list.append(documento)
352
+
353
+
354
+
355
+ with gr.Row():
356
+
357
+ generar = gr.Button("Generar noticia")
358
+
359
+ with gr.Row():
360
+
361
+ noticia_output = gr.Textbox(label="Noticia generada", lines=20)
362
+
363
+ with gr.Row():
364
+
365
+ transcripciones_output = gr.Textbox(label="Transcripciones brutas de los audios", lines=10)
366
+
367
+
368
+
369
+ generar.click(fn=generar_noticia, inputs=inputs_list, outputs=[noticia_output, transcripciones_output])
370
+
371
+
372
+
373
+ demo.launch(share=True)