GuionesWisp / app.py
angldann's picture
Update app.py
efd05e8 verified
import gradio as gr
import os
import tempfile
import shutil
from openai import OpenAI
from docx import Document
import io
import time
def listar_archivos_txt():
"""Lista todos los archivos .txt en el directorio raíz del proyecto."""
archivos = []
try:
# En Hugging Face Spaces, el directorio de trabajo es el root del repositorio
for archivo in os.listdir():
if archivo.endswith('.txt'):
archivos.append(archivo)
except Exception as e:
print(f"Error al listar archivos: {e}")
return archivos
def leer_contenido_archivo(nombre_archivo):
"""Lee el contenido de un archivo de texto."""
try:
with open(nombre_archivo, 'r', encoding='utf-8') as f:
return f.read()
except Exception as e:
print(f"Error al leer archivo {nombre_archivo}: {e}")
return ""
def generar_guion_viral(client, contexto: str, tema: str, empresa: str) -> str:
prompt_guion_video = f"""
Genera un guión totalmente nuevo para "{tema}" para mi empresa, con la metodología de la imagen de Jürgen Metodo Viral Neuroventas + IA.Utiliza el estilo de Jurguen klaric. Asegúrate de que no parezca un infomercial tradicional, sino algo mas natural.
El video debe durar maximo 40 segundos.
Debes darme el guion con los siguientes 6 puntos, lee detenidamente cada indicacion para lograr un video viral y se cumpla el objetivo de ventas.
1. "Patada Voladora" (4 segundos)
Debe contener:
Una afirmación fuerte o polémica
Un dato estadístico real o impactante
Una pregunta con curiosidad + respuesta inmediata
Frase agresiva que sacuda
Esto atrapa al cerebro reptil, genera dopamina por sorpresa y obliga a seguir viendo.
Recuerda activar el miedo
2. Prometer beneficio (3 segundos)
Aquí se responde directamente al dolor que se activó en el hook, prometiendo la transformación.
3. Desarrollo del contenido de valor (23 segundos)
Este bloque debe incluir de 5 a 6 loops emocionales de 5 segundos cada uno:
Cada loop debe:
Usar un verbo de acción
Usar "tú" para que se sienta personal
Despertar un sesgo de confirmación: "esto me representa, esto me sirve"
Invitar a imaginar una escena o beneficio real
Ser un mini "shock de atención" visual o emocional
No es necesario que el "tú" esté siempre al inicio, lo importante es que aparezca dentro del loop para crear conexión personal, lo importante es combinarlo con un verbo de accion
4. Entregar beneficio (4 segundos)
Aquí resumes y amplificas los beneficios tangibles + valores agregados.
Es la prueba emocional de que funciona y vale la pena.
5. Call to Action (3 segundos)
Clave:
Usar un verbo fuerte o un antídoto del miedo.
Ej: "Invierte", "Activa", "Asegura", "Recupera", "Toma control"
Debe pedir la compra directa, no solo "conoce más".
Recuerda inidicar el antido al miedo que activaste en el punto 1
6. Activar algoritmo (2 segundos)
Frases que disparan interacción:
"Guárdalo si lo necesitas"
"Compártelo con un colega"
"Etiqueta al que lo necesita"
"""
response = client.chat.completions.create(
model="gpt-4o-mini",
temperature=1.25,
messages=[
{
"role": "system",
"content": f'''Eres un Bot Consultor experto en guiones virales para videos en redes sociales enfocados en dueños de negocio para la empresa {empresa}. Tu enfoque se basa exclusivamente en los principios de Neuroventas de Jürgen Klaric.
### Instrucciones estrictas:
- Tu única tarea es generar el guión solicitado por el usuario.
- **No debes incluir saludos, introducciones, explicaciones, despedidas ni ofrecer ayuda adicional.**
- No escribas frases como "Aquí tienes el guión", "¿Quieres que te ayude con algo más?", "¿Te gustaría que...?" ni nada similar.
- No uses **negritas**, dobles asteriscos ni encabezados con formato especial.
- El guión debe estar limpio, ordenado, con buena estructura visual, respetando los saltos de línea y párrafos.
- Responde únicamente con el contenido del guión viral, nada más.
Usa el siguiente contexto como referencia obligatoria para generar tu respuesta toma en cuenta el nombre de la empresa, sus beneficios y características, además del público al que tiene como objetivo:
{contexto}
'''
},
{
"role": "user",
"content": prompt_guion_video
}
]
)
return response.choices[0].message.content
def generar_guion_elevenlabs(client, guion_video: str) -> str:
prompt_guion_elevenlabs = "Quiero que me entregues un guión listo para ElevenLabs optimizado sin saltos de párrafo, sin puntos suspensivos y con acento para asegurar la pronunciación correcta. El guion del video que te tienes que basar es el siguiente: "
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{
"role": "system",
"content": '''Eres un Bot Consultor experto en guiones virales para videos en redes sociales enfocados en dueños de negocio. Tu enfoque se basa exclusivamente en los principios de Neuroventas de Jürgen Klaric.
### Instrucciones estrictas:
- Tu única tarea es generar el guión solicitado por el usuario.
- **No debes incluir saludos, introducciones, explicaciones, despedidas ni ofrecer ayuda adicional.**
- No escribas frases como "Aquí tienes el guión", "¿Quieres que te ayude con algo más?", "¿Te gustaría que...?" ni nada similar.
- No uses **negritas**, dobles asteriscos ni encabezados con formato especial.
- El guión debe estar limpio, ordenado, con buena estructura visual, respetando los saltos de línea y párrafos.
- Responde únicamente con el contenido del guión viral, nada más.
'''
},
{
"role": "user",
"content": prompt_guion_elevenlabs + guion_video
}
]
)
return response.choices[0].message.content
def crear_docx(tema, guion_video, guion_elevenlabs):
doc = Document()
doc.add_heading(f'Guión Viral - {tema}', level=1)
doc.add_paragraph(guion_video)
doc.add_heading(f'Guión ElevenLabs - {tema}', level=1)
doc.add_paragraph(guion_elevenlabs)
# Guardar en un objeto BytesIO en lugar de un archivo
doc_io = io.BytesIO()
doc.save(doc_io)
doc_io.seek(0)
return doc_io
# Configurar la API Key de OpenAI
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
def procesar_guiones(fuente_contexto, archivo_contexto, archivo_seleccionado, temas_input, cantidad_por_tema, api_key=OPENAI_API_KEY):
if not api_key:
return None, "Por favor, introduce una clave de API de OpenAI."
# Verificar fuente de contexto
if fuente_contexto == "Upload" and not archivo_contexto:
return None, "Por favor, sube un archivo de contexto."
elif fuente_contexto == "Select" and not archivo_seleccionado:
return None, "Por favor, selecciona un archivo de contexto."
if not temas_input:
return None, "Por favor, especifica al menos un tema."
# Mostrar mensaje de inicio para Hugging Face Space
progress_text = ["🔄 Iniciando proceso de generación de guiones..."]
yield None, "\n".join(progress_text)
try:
# Crear un cliente de OpenAI con la API key proporcionada
client = OpenAI(api_key=api_key)
# Leer el contenido del archivo de contexto según la fuente seleccionada
if fuente_contexto == "Upload":
with open(archivo_contexto.name, 'r', encoding='utf-8') as f:
contexto = f.read()
nombre_archivo = os.path.basename(archivo_contexto.name)
else: # Select
contexto = leer_contenido_archivo(archivo_seleccionado)
nombre_archivo = archivo_seleccionado
progress_text.append(f"Usando archivo de contexto: {nombre_archivo}")
# Dividir los temas por líneas
temas = [tema.strip() for tema in temas_input.split('\n') if tema.strip()]
# Crear un directorio temporal para almacenar los archivos docx
temp_dir = tempfile.mkdtemp()
archivos_generados = []
#Nombre de la empresa a la que se le hacen guiones
nombre_empresa = str(archivo_seleccionado.replace(".txt",""))
# Iterar sobre cada tema y generar la cantidad especificada de guiones
for tema in temas:
progress_text.append(f"Procesando tema: {tema}")
yield None, "\n".join(progress_text)
time.sleep(0.5) # Pequeña pausa para actualizar la UI
for i in range(int(cantidad_por_tema)):
progress_text.append(f" Generando guión {i+1} para '{tema}'")
yield None, "\n".join(progress_text)
# Generar el guión viral
guion_video = generar_guion_viral(client, contexto, tema, nombre_empresa)
# Generar el guión para ElevenLabs
guion_elevenlabs = generar_guion_elevenlabs(client, guion_video)
# Crear el archivo docx en memoria
doc_bytes = crear_docx(tema, guion_video, guion_elevenlabs)
# Guardar el archivo en el directorio temporal
filename = f"{tema.replace(' ', '_')}_guion_{i+1}.docx"
filepath = os.path.join(temp_dir, filename)
with open(filepath, 'wb') as f:
f.write(doc_bytes.getvalue())
archivos_generados.append(filepath)
progress_text.append(f" ✅ Completado guión {i+1} para '{tema}'")
yield archivos_generados, "\n".join(progress_text)
progress_text.append(f"\n✅ Proceso completado. Se generaron {len(archivos_generados)} archivos.")
yield archivos_generados, "\n".join(progress_text)
except Exception as e:
yield None, f"Error: {str(e)}"
def actualizar_visibilidad(opcion):
"""Función para actualizar la visibilidad de los componentes según la opción seleccionada."""
if opcion == "Upload":
return gr.update(visible=True), gr.update(visible=False)
else: # Select
return gr.update(visible=False), gr.update(visible=True)
def crear_interfaz():
with gr.Blocks(title="Generador de Guiones Virales") as app:
gr.Markdown("# 🚀 Generador de Guiones Virales con IA")
gr.Markdown("""
Esta aplicación genera guiones para videos virales y para ElevenLabs basados en el método de Jürgen Klaric.
### Instrucciones:
1. Selecciona o sube un archivo de texto con el contexto
2. Introduce los temas para los guiones (uno por línea)
3. Especifica cuántos guiones deseas por cada tema
4. Haz clic en 'Generar Guiones'
""")
with gr.Row():
with gr.Column(scale=1):
# Selector de fuente de contexto
fuente_contexto = gr.Radio(
["Select", "Upload"],
label="Fuente del archivo de contexto",
value="Select",
info="Selecciona un archivo existente o sube uno nuevo"
)
# Componente para seleccionar archivo existente
archivos_disponibles = listar_archivos_txt()
archivo_seleccionado = gr.Dropdown(
archivos_disponibles,
label="Selecciona un archivo de contexto",
info="Archivos disponibles en el directorio raíz"
)
# Componente para subir archivo
archivo_contexto = gr.File(
label="Sube un archivo de contexto (.txt)",
file_types=[".txt"],
visible=False
)
temas = gr.Textbox(label="Temas (uno por línea)", placeholder="Tema 1\nTema 2\nTema 3", lines=5)
cantidad_por_tema = gr.Number(label="Cantidad de guiones por tema", value=1, minimum=1, maximum=10, step=1)
btn_generar = gr.Button("Generar Guiones", variant="primary")
with gr.Column(scale=1):
output_progress = gr.Textbox(label="Progreso", lines=10)
output_files = gr.Files(label="Guiones Generados")
# Actualizar visibilidad según la opción seleccionada
fuente_contexto.change(
fn=actualizar_visibilidad,
inputs=fuente_contexto,
outputs=[archivo_contexto, archivo_seleccionado]
)
btn_generar.click(
fn=procesar_guiones,
inputs=[fuente_contexto, archivo_contexto, archivo_seleccionado, temas, cantidad_por_tema],
outputs=[output_files, output_progress],
show_progress=True
)
return app
# Crear la aplicación - para Hugging Face Spaces
if __name__ == "__main__":
app = crear_interfaz()
app.launch()