CamiloVega's picture
Update app.py
5c9c26c verified
raw
history blame
8.36 kB
import os
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
from google.colab import userdata # Importa userdata de google.colab
import requests
from bs4 import BeautifulSoup
# Configura tu clave API de OpenAI usando Google Colab userdata
#openai.api_key = userdata.get('OPENAI_API_KEY')
# 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 leer_url(url):
"""Lee el contenido de una URL."""
try:
response = requests.get(url)
response.raise_for_status()
soup = BeautifulSoup(response.content, 'html.parser')
return soup.get_text()
except Exception as e:
return f"Error al leer la URL: {str(e)}"
def generar_noticia(instrucciones, hechos, tamaño, tono, urls, *args):
"""Genera una noticia a partir de instrucciones, hechos, URLs, documentos y transcripciones."""
base_de_conocimiento = {"instrucciones": instrucciones, "hechos": hechos, "contenido_documentos": [], "audio_data": [], "contenido_urls": []}
num_audios = 5 * 3 # 5 audios * 3 campos (audio, nombre, cargo)
audios = args[:num_audios]
documentos = args[num_audios:]
for url in urls.split():
if url:
base_de_conocimiento["contenido_urls"].append(leer_url(url))
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"])
contenido_urls = "\n\n".join(base_de_conocimiento["contenido_urls"])
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 gancho de 15 palabras (el gancho es lo que se conoce en inglés como hook, información adicional que complementa el título), 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}
Contenido adicional de las URLs: {contenido_urls}
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")
urls = gr.Textbox(label="URLs (separadas por espacio)", lines=2)
with gr.Column(scale=3):
inputs_list = [instrucciones, hechos, tamaño, tono, urls]
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 borrador")
with gr.Row():
noticia_output = gr.Textbox(label="Borrador generado", lines=20)
generar.click(fn=generar_noticia, inputs=inputs_list, outputs=[noticia_output, transcripciones_output])
demo.launch(share=True)