Spaces:
Sleeping
Sleeping
import openai | |
import whisper | |
import tempfile | |
import gradio as gr | |
from pydub import AudioSegment | |
import fitz # PyMuPDF para manejar PDFs | |
import docx # Para manejar archivos .docx | |
import pandas as pd # Para manejar archivos .xlsx y .csv | |
import os | |
# Cargar las variables de entorno desde el entorno de Hugging Face | |
openai.api_key = os.getenv("OPENAI_API_KEY") | |
# Cargar el modelo Whisper de mayor calidad una vez | |
model = whisper.load_model("large") | |
def preprocess_audio(audio_file): | |
"""Preprocesa el archivo de audio para mejorar la calidad.""" | |
try: | |
audio = AudioSegment.from_file(audio_file) | |
audio = audio.apply_gain(-audio.dBFS + (-20)) | |
with tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") as temp_file: | |
audio.export(temp_file.name, format="mp3") | |
return temp_file.name | |
except Exception as e: | |
return f"Error al preprocesar el archivo de audio: {str(e)}" | |
def transcribir_audio(audio_file): | |
"""Transcribe un archivo de audio.""" | |
try: | |
archivo_path = preprocess_audio(audio_file) if isinstance(audio_file, str) else preprocess_audio(tempfile.NamedTemporaryFile(delete=False, suffix=".mp3", mode='w+b').name) | |
resultado = model.transcribe(archivo_path) | |
return resultado.get("text", "Error en la transcripción") | |
except Exception as e: | |
return f"Error al procesar el archivo de audio: {str(e)}" | |
def leer_documento(documento_path): | |
"""Lee el contenido de un documento PDF, DOCX, XLSX o CSV.""" | |
try: | |
if documento_path.endswith(".pdf"): | |
doc = fitz.open(documento_path) | |
return "\n".join([pagina.get_text() for pagina in doc]) | |
elif documento_path.endswith(".docx"): | |
doc = docx.Document(documento_path) | |
return "\n".join([parrafo.text for parrafo in doc.paragraphs]) | |
elif documento_path.endswith(".xlsx"): | |
return pd.read_excel(documento_path).to_string() | |
elif documento_path.endswith(".csv"): | |
return pd.read_csv(documento_path).to_string() | |
else: | |
return "Tipo de archivo no soportado. Por favor suba un documento PDF, DOCX, XLSX o CSV." | |
except Exception as e: | |
return f"Error al leer el documento: {str(e)}" | |
def generar_noticia(instrucciones, hechos, tamaño, tono, *args): | |
"""Genera una noticia a partir de instrucciones, hechos y transcripciones.""" | |
base_de_conocimiento = {"instrucciones": instrucciones, "hechos": hechos, "contenido_documentos": [], "audio_data": []} | |
num_audios = 5 * 3 # 5 audios * 3 campos (audio, nombre, cargo) | |
audios = args[:num_audios] | |
documentos = args[num_audios:] | |
for documento in documentos: | |
if documento is not None: | |
base_de_conocimiento["contenido_documentos"].append(leer_documento(documento.name)) | |
for i in range(0, len(audios), 3): | |
audio_file, nombre, cargo = audios[i:i+3] | |
if audio_file is not None: | |
base_de_conocimiento["audio_data"].append({"audio": audio_file, "nombre": nombre, "cargo": cargo}) | |
transcripciones_texto, transcripciones_brutas, total_citas_directas = "", "", 0 | |
for idx, data in enumerate(base_de_conocimiento["audio_data"]): | |
if data["audio"] is not None: | |
transcripcion = transcribir_audio(data["audio"]) | |
transcripcion_texto = f'"{transcripcion}" - {data["nombre"]}, {data["cargo"]}' | |
transcripcion_bruta = f'[Audio {idx + 1}]: "{transcripcion}" - {data["nombre"]}, {data["cargo"]}' | |
if total_citas_directas < len(base_de_conocimiento["audio_data"]) * 0.8: | |
transcripciones_texto += transcripcion_texto + "\n" | |
total_citas_directas += 1 | |
else: | |
transcripciones_texto += f'{data["nombre"]} mencionó que {transcripcion}' + "\n" | |
transcripciones_brutas += transcripcion_bruta + "\n\n" | |
contenido_documentos = "\n\n".join(base_de_conocimiento["contenido_documentos"]) | |
prompt_interno = """ | |
Instrucciones para el modelo: | |
- Debes seguir los principios de una noticia: es decir, procura siempre responder las 5 W de una noticia en el primer párrafo (Who?, What?, When?, Where?, Why?). | |
- Asegúrate de que al menos el 80% de las citas sean directas y estén entrecomilladas. | |
- El 20% restante puede ser citas indirectas. | |
- No inventes información nueva. | |
- Sé riguroso con los hechos proporcionados. | |
- Al procesar los documentos cargados, extrae y resalta citas importantes y testimonios textuales de las fuentes. | |
- Al procesar los documentos cargados, extrae y resalta cifras clave. | |
""" | |
prompt = f""" | |
{prompt_interno} | |
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}. | |
Instrucciones: {base_de_conocimiento["instrucciones"]} | |
Hechos: {base_de_conocimiento["hechos"]} | |
Contenido adicional de los documentos: {contenido_documentos} | |
Utiliza las siguientes transcripciones como citas directas e indirectas (sin cambiar ni inventar contenido): | |
{transcripciones_texto} | |
""" | |
try: | |
respuesta = openai.ChatCompletion.create( | |
model="gpt-3.5-turbo", | |
messages=[{"role": "user", "content": prompt}], | |
temperature=0.1 | |
) | |
noticia = respuesta['choices'][0]['message']['content'] | |
return noticia, transcripciones_brutas | |
except Exception as e: | |
return f"Error al generar la noticia: {str(e)}", "" | |
with gr.Blocks() as demo: | |
gr.Markdown("## Generador noticias todo en uno") | |
with gr.Row(): | |
with gr.Column(scale=2): | |
instrucciones = gr.Textbox(label="Instrucciones para la noticia", lines=2) | |
hechos = gr.Textbox(label="Describe los hechos de la noticia", lines=4) | |
tamaño = gr.Number(label="Tamaño del cuerpo de la noticia (en palabras)", value=100) | |
tono = gr.Dropdown(label="Tono de la noticia", choices=["serio", "neutral", "divertido"], value="neutral") | |
with gr.Column(scale=3): | |
inputs_list = [instrucciones, hechos, tamaño, tono] | |
with gr.Tabs(): | |
for i in range(1, 6): | |
with gr.TabItem(f"Audio {i}"): | |
audio = gr.Audio(type="filepath", label=f"Audio {i}") | |
nombre = gr.Textbox(label="Nombre", scale=1) | |
cargo = gr.Textbox(label="Cargo", scale=1) | |
inputs_list.extend([audio, nombre, cargo]) | |
for i in range(1, 6): | |
with gr.TabItem(f"Documento {i}"): | |
documento = gr.File(label=f"Documento {i}", type="filepath", file_count="single") | |
inputs_list.append(documento) | |
gr.Markdown("---") # Separador visual | |
with gr.Row(): | |
transcripciones_output = gr.Textbox(label="Transcripciones", lines=10) | |
gr.Markdown("---") # Separador visual | |
with gr.Row(): | |
generar = gr.Button("Generar noticia") | |
with gr.Row(): | |
noticia_output = gr.Textbox(label="Noticia generada", lines=20) | |
generar.click(fn=generar_noticia, inputs=inputs_list, outputs=[noticia_output, transcripciones_output]) | |
demo.launch(share=True) | |