Spaces:
Sleeping
Sleeping
from dotenv import load_dotenv | |
import streamlit as st | |
import os | |
import google.generativeai as genai | |
import random | |
import datetime | |
from streamlit import session_state as state | |
from angles import angles | |
from formulas.webinar_formulas import webinar_formulas | |
from formulas.webinar_name_formulas import webinar_name_formulas | |
from formulas.angles_webinar_names import angles_webinar_names | |
# Cargar las variables de entorno | |
load_dotenv() | |
# Configurar la API de Google | |
genai.configure(api_key=os.getenv("GOOGLE_API_KEY")) | |
# Create a reusable function for the UI input section | |
def create_input_section(col, audience_key, product_key, formula_options, formula_key): | |
audience = col.text_input("驴Qui茅n es tu p煤blico objetivo?", placeholder="Ejemplo: Emprendedores digitales", key=audience_key) | |
product = col.text_input("驴Sobre qu茅 tema es tu webinar?", placeholder="Ejemplo: Marketing en redes sociales", key=product_key) | |
selected_formula_key = col.selectbox( | |
"Selecciona un framework de webinar" if "script" in audience_key else "Selecciona una f贸rmula para tus nombres de webinar", | |
options=list(formula_options.keys()), | |
key=formula_key | |
) | |
return audience, product, selected_formula_key | |
# Create a reusable function for generation and display | |
def generate_and_display(col, generator_func, audience, product, temperature, selected_formula, **kwargs): | |
if validate_inputs(audience, product): | |
try: | |
with col: | |
with st.spinner("Generando contenido...", show_time=True): | |
# Extract only the parameters that the generator function accepts | |
if generator_func.__name__ == "generate_webinar_script": | |
generated_content = generator_func( | |
audience=audience, | |
topic=product, | |
temperature=temperature, | |
selected_formula=selected_formula | |
) | |
else: | |
generated_content = generator_func( | |
audience=audience, | |
topic=product, | |
temperature=temperature, | |
selected_formula=selected_formula, | |
**kwargs | |
) | |
# For webinar scripts, add download buttons | |
if "script" in kwargs.get("content_type", ""): | |
timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S") | |
st.download_button( | |
label="DESCARGAR GUION DE MI WEBINAR", | |
data=generated_content, | |
file_name=f"guion_webinar_{timestamp}.md", | |
mime="text/markdown", | |
key="download_top" | |
) | |
st.subheader("Tu " + ("gui贸n de webinar:" if "script" in kwargs.get("content_type", "") else "nombres de webinar:")) | |
st.markdown(generated_content) | |
# Add bottom download button for scripts | |
if "script" in kwargs.get("content_type", ""): | |
st.download_button( | |
label="DESCARGAR GUION DE MI WEBINAR", | |
data=generated_content, | |
file_name=f"guion_webinar_{timestamp}.md", | |
mime="text/markdown", | |
key="download_bottom" | |
) | |
except ValueError as e: | |
col.error(f"Error: {str(e)}") | |
else: | |
col.error("Por favor, proporciona el p煤blico objetivo y el tema del webinar.") | |
# Funci贸n para crear la configuraci贸n del modelo (evita duplicaci贸n) | |
def create_model_config(temperature): | |
return { | |
"temperature": temperature, | |
"top_p": 0.65, | |
"top_k": 360, | |
"max_output_tokens": 8196, | |
} | |
# Funci贸n para inicializar el modelo | |
def initialize_model(temperature): | |
config = create_model_config(temperature) | |
return genai.GenerativeModel( | |
model_name="gemini-2.0-flash", | |
generation_config=config, | |
) | |
# Refactored model interaction function to reduce duplication | |
def generate_content(prompt_instructions, temperature): | |
model = initialize_model(temperature) | |
chat_session = model.start_chat( | |
history=[ | |
{ | |
"role": "user", | |
"parts": [prompt_instructions], | |
}, | |
] | |
) | |
response = chat_session.send_message("Generate the content following exactly the provided instructions. All content must be in Spanish.") | |
return response.text | |
# Funci贸n para generar nombres de webinars | |
def generate_webinar_names(number_of_names, target_audience, product, temperature, selected_formula, selected_angle=None): | |
# Incluir las instrucciones del sistema en el prompt principal | |
system_prompt = """You are a world-class copywriter, with expertise in crafting compelling webinar titles that immediately capture the audience's attention and drive registrations. | |
FORMAT RULES: | |
- Each webinar name must start with number and period | |
- One webinar name per line | |
- No explanations or categories | |
- Add a line break between each name | |
- Avoid unnecessary : symbols | |
- Each webinar name must be a complete and intriguing title | |
- WRITE ALL WEBINAR NAMES IN SPANISH | |
FORMAT EXAMPLE: | |
1. Nombre del Webinar 1. | |
2. Nombre del Webinar 2. | |
3. Nombre del Webinar 3. | |
4. Nombre del Webinar 4. | |
5. Nombre del Webinar 5. | |
IMPORTANT: | |
- Each webinar name must be unique and memorable | |
- Avoid clich茅s and generalities | |
- Maintain an intriguing but credible tone | |
- Adapt speaking language from the audience | |
- Focus on transformative benefits | |
- Follow the selected formula structure | |
- WRITE ALL WEBINAR NAMES IN SPANISH""" | |
# Iniciar el prompt con las instrucciones del sistema | |
webinar_names_instruction = f"{system_prompt}\n\n" | |
# A帽adir instrucciones de 谩ngulo solo si no es "NINGUNO" y se proporcion贸 un 谩ngulo | |
if selected_angle and selected_angle != "NINGUNO": | |
webinar_names_instruction += f""" | |
MAIN ANGLE: {selected_angle} | |
SPECIFIC ANGLE INSTRUCTIONS: | |
{angles_webinar_names[selected_angle]["instruction"]} | |
IMPORTANT: The {selected_angle} angle should be applied as a "style layer" over the formula structure: | |
1. Keep the base structure of the formula intact | |
2. Apply the tone and style of the {selected_angle} angle | |
3. Ensure that each element of the formula reflects the angle | |
4. The angle affects "how" it is said, not "what" is said | |
SUCCESSFUL EXAMPLES OF THE {selected_angle} ANGLE: | |
""" | |
for example in angles_webinar_names[selected_angle]["examples"]: | |
webinar_names_instruction += f"- {example}\n" | |
# Instrucciones espec铆ficas para la tarea | |
webinar_names_instruction += ( | |
f"\nYour task is to create {number_of_names} irresistible webinar names for {target_audience} " | |
f"that instantly capture attention and generate registrations for a webinar about {product}. " | |
f"Focus on awakening genuine interest and communicating the value they will get by registering." | |
f"\n\n" | |
f"IMPORTANT: Carefully study these examples of the selected formula. " | |
f"Each example represents the style and structure to follow" | |
f":\n\n" | |
) | |
# Agregar ejemplos aleatorios de la f贸rmula (keeping examples in Spanish) | |
random_examples = random.sample(selected_formula['examples'], min(5, len(selected_formula['examples']))) | |
webinar_names_instruction += "EXAMPLES OF THE FORMULA TO FOLLOW:\n" | |
for i, example in enumerate(random_examples, 1): | |
webinar_names_instruction += f"{i}. {example}\n" | |
# Instrucciones espec铆ficas (translated to English) | |
webinar_names_instruction += "\nSPECIFIC INSTRUCTIONS:\n" | |
webinar_names_instruction += "1. Maintain the same structure and length as the previous examples\n" | |
webinar_names_instruction += "2. Use the same tone and writing style\n" | |
webinar_names_instruction += "3. Replicate the phrase construction patterns\n" | |
webinar_names_instruction += "4. Preserve the level of specificity and detail\n" | |
webinar_names_instruction += f"5. Adapt the content for {target_audience} while maintaining the essence of the examples\n\n" | |
webinar_names_instruction += f"FORMULA TO FOLLOW:\n{selected_formula['description']}\n\n" | |
webinar_names_instruction += f""" | |
GENERATE NOW: | |
Create {number_of_names} webinar names that faithfully follow the style and structure of the examples shown. | |
""" | |
# Enviar el mensaje al modelo | |
# Use the common generate_content function | |
return generate_content(webinar_names_instruction, temperature) | |
def generate_webinar_script(audience, topic, temperature, selected_formula): | |
model = initialize_model(temperature) | |
# Incluir las instrucciones del sistema en el prompt principal | |
system_prompt = f"""You are a collaborative team of world-class experts working together to create an exceptional webinar script that converts audience into customers. | |
THE EXPERT TEAM: | |
1. MASTER WEBINAR STRATEGIST: | |
- Expert in webinar frameworks and conversion strategies | |
- Trained in the Perfect Webinar methodology by Russell Brunson | |
- Ensures the script follows the selected framework structure precisely | |
- Focuses on strategic placement of key conversion elements | |
2. ELITE DIRECT RESPONSE COPYWRITER: | |
- Trained by Gary Halbert, Gary Bencivenga, and David Ogilvy | |
- Creates compelling hooks, stories, and persuasive elements | |
- Crafts irresistible calls to action that drive conversions | |
- Ensures the language resonates with the target audience | |
3. AUDIENCE PSYCHOLOGY SPECIALIST: | |
- Expert in understanding audience motivations and objections | |
- Creates content that builds genuine connection and trust | |
- Identifies and addresses hidden fears and desires | |
- Ensures the content feels personal and relevant | |
4. STORYTELLING MASTER: | |
- Creates compelling narratives that illustrate key points | |
- Develops relatable examples and case studies | |
- Ensures stories support the transformation being offered | |
- Makes complex concepts accessible through narrative | |
5. WEBINAR ENGAGEMENT EXPERT: | |
- Specializes in maintaining audience attention throughout | |
- Creates interactive elements and engagement hooks | |
- Develops compelling transitions between sections | |
- Ensures the webinar flows naturally and keeps interest high | |
AUDIENCE UNDERSTANDING: | |
You understand how real people interact with webinar content: | |
- They quickly lose interest if the content feels generic or corporate | |
- They only stay engaged when the content feels personal and sparks genuine curiosity | |
- They respond to messages that seem delivered by a real person, not a corporation | |
- They engage with content that hooks them from the first line and maintains interest throughout | |
FORMAT RULES: | |
- Create a complete webinar script with clear sections and subsections | |
- Include specific talking points for each section | |
- Write in a conversational, engaging tone | |
- Include persuasive elements and calls to action | |
- Follow the selected webinar framework structure exactly | |
- WRITE THE ENTIRE SCRIPT IN SPANISH | |
- DO NOT include any introductory text or explanations about the script | |
- Start directly with the webinar content | |
IMPORTANT: | |
- The script must be comprehensive and ready to use | |
- Include specific examples and stories relevant to the topic | |
- Maintain a persuasive but authentic tone | |
- Adapt language to match the target audience | |
- Focus on transformative benefits and clear value proposition | |
- Follow the selected formula structure precisely | |
- WRITE THE ENTIRE SCRIPT IN SPANISH | |
- DO NOT include phrases like "Aqu铆 tienes un guion completo" or any other meta-commentary | |
COLLABORATIVE PROCESS: | |
As a team of experts, you will: | |
1. Analyze the framework '{selected_formula['description']}' to understand its core principles | |
2. Identify how to best adapt this framework for {audience} learning about {topic} | |
3. Determine the most effective storytelling opportunities within the framework | |
4. Create persuasive language that resonates with {audience} | |
5. Ensure the script maintains engagement throughout | |
6. Adapt the content to be accessible to beginners while still valuable to experienced individuals | |
7. Follow the exact structure provided in the framework | |
Each expert will contribute their specialized knowledge to create a cohesive, compelling script that: | |
- Follows the exact structure of the selected framework | |
- Engages the audience from start to finish | |
- Addresses audience pain points and desires | |
- Presents {topic} in a clear, compelling way | |
- Drives conversions through strategic calls to action""" | |
# Iniciar el prompt con las instrucciones del sistema | |
webinar_script_instruction = f"{system_prompt}\n\n" | |
# Instrucciones espec铆ficas para la tarea | |
webinar_script_instruction += ( | |
f"\nYour task is to create a complete webinar script IN SPANISH for {audience} " | |
f"about {topic} that is persuasive and converts the audience into customers. " | |
f"The script must follow exactly the structure of the framework '{selected_formula['description']}' " | |
f"and must include all the necessary elements for a successful webinar." | |
f"\n\n" | |
) | |
# Estructura del webinar | |
webinar_script_instruction += "WEBINAR STRUCTURE TO FOLLOW:\n" | |
for i, step in enumerate(selected_formula['structure'], 1): | |
webinar_script_instruction += f"{i}. {step}\n" | |
# Ejemplos de webinars exitosos | |
webinar_script_instruction += "\n\nEXAMPLES OF SUCCESSFUL WEBINARS WITH THIS STRUCTURE:\n" | |
for i, example in enumerate(selected_formula['examples'], 1): | |
webinar_script_instruction += f"{i}. {example}\n" | |
# Instrucciones espec铆ficas | |
webinar_script_instruction += f""" | |
SPECIFIC INSTRUCTIONS: | |
1. Create a complete script that follows exactly the provided structure | |
2. Include persuasive elements and clear calls to action | |
3. Adapt the language and examples specifically for {audience} | |
4. Focus on the transformative benefits of {topic} | |
5. Include relevant stories and examples that reinforce your points | |
6. Use a conversational but professional tone | |
7. Make sure each section fulfills its specific purpose in the framework | |
8. IMPORTANT: Write the entire script in Spanish | |
GENERATE NOW: | |
Create a complete webinar script following faithfully the structure of the selected framework. | |
""" | |
# Enviar el mensaje al modelo | |
chat_session = model.start_chat( | |
history=[ | |
{ | |
"role": "user", | |
"parts": [webinar_script_instruction], | |
}, | |
] | |
) | |
response = chat_session.send_message("Generate the webinar script IN NEUTRAL SPANISH following exactly the provided structure. All content must be in neutral Spanish (not Spain Spanish).") | |
return response.text | |
# Funci贸n para validar entradas (evita duplicaci贸n) | |
def validate_inputs(audience, product): | |
has_audience = audience.strip() != "" | |
has_product = product.strip() != "" | |
return has_audience and has_product | |
# Update the load_css function comment to be more descriptive | |
def load_css(): | |
css_path = "styles/styles.css" | |
if os.path.exists(css_path): | |
try: | |
with open(css_path, "r") as f: | |
st.markdown(f"<style>{f.read()}</style>", unsafe_allow_html=True) | |
except Exception as e: | |
st.warning(f"Error al cargar el archivo CSS: {str(e)}") | |
else: | |
st.warning(f"No se encontr贸 el archivo CSS en {css_path}") | |
# Create a reusable function for custom buttons | |
# At the top of your file, define the styles dictionary | |
styles = { | |
"button": """ | |
<style> | |
div.stButton > button:first-child { | |
background-color: #FF4B4B; | |
color: white; | |
font-weight: bold; | |
padding: 0.5rem 1rem; | |
border-radius: 0.5rem; | |
border: none; | |
transition: all 0.3s; | |
} | |
div.stButton > button:hover { | |
background-color: #FF2525; | |
transform: translateY(-2px); | |
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); | |
} | |
</style> | |
""", | |
"download_button": """ | |
<style> | |
div.stDownloadButton > button:first-child { | |
background-color: #4CAF50; | |
color: white; | |
font-weight: bold; | |
padding: 0.5rem 1rem; | |
border-radius: 0.5rem; | |
border: none; | |
transition: all 0.3s; | |
} | |
div.stDownloadButton > button:hover { | |
background-color: #45a049; | |
transform: translateY(-2px); | |
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); | |
} | |
</style> | |
""" | |
} | |
# Then modify your create_custom_button function to be much simpler: | |
def create_custom_button(label, button_key): | |
# Apply the button style once at the beginning of your app | |
# (You can move this to your main app code if you prefer) | |
st.markdown(styles["button"], unsafe_allow_html=True) | |
# Just return a regular Streamlit button | |
return st.button(label, key=button_key) | |
# Modify the page config section to include the CSS loading | |
st.set_page_config(page_title="Perfect Webinar Framework", layout="wide") | |
load_css() | |
# Leer el contenido del archivo manual.md | |
with open("manual.md", "r", encoding="utf-8") as file: | |
manual_content = file.read() | |
# Mostrar el contenido del manual en el sidebar | |
st.sidebar.markdown(manual_content) | |
# Crear pesta帽as para la interfaz | |
tab1, tab2 = st.tabs(["Guiones de Webinar", "Nombres de Webinar"]) | |
# Primera pesta帽a - Generador de Guiones de Webinar | |
with tab1: | |
tab1.subheader("Script Webinar") | |
# Crear columnas para la interfaz | |
col1, col2 = tab1.columns([1, 2]) | |
# Columna de entrada usando la funci贸n reutilizable | |
with col1: | |
webinar_script_audience, webinar_script_product, selected_webinar_formula_key = create_input_section( | |
col1, | |
"webinar_script_audience", | |
"webinar_script_product", | |
webinar_formulas, | |
"webinar_formula" | |
) | |
# Usar la funci贸n reutilizable para crear el bot贸n personalizado | |
submit_webinar_script = create_custom_button("Generar Gui贸n de Webinar", "generate_webinar_script") | |
# Opciones avanzadas | |
with st.expander("Personaliza tu gui贸n de webinar"): | |
webinar_script_temperature = st.slider("Creatividad", min_value=0.0, max_value=2.0, value=1.0, step=0.1, key="webinar_script_temp") | |
selected_webinar_formula = webinar_formulas[selected_webinar_formula_key] | |
# Generar y mostrar el gui贸n usando la funci贸n reutilizable | |
if submit_webinar_script: | |
generate_and_display( | |
col2, | |
generate_webinar_script, | |
webinar_script_audience, | |
webinar_script_product, | |
webinar_script_temperature, | |
selected_webinar_formula, | |
content_type="script" | |
) | |
# Segunda pesta帽a - Generador de Nombres de Webinar | |
with tab2: | |
tab2.subheader("Nombres de Webinar") | |
# Crear columnas para la interfaz | |
col1, col2 = tab2.columns([1, 2]) | |
# Columna de entrada usando la funci贸n reutilizable | |
with col1: | |
webinar_name_audience, webinar_name_product, selected_webinar_name_formula_key = create_input_section( | |
col1, | |
"webinar_name_audience", | |
"webinar_name_product", | |
webinar_name_formulas, | |
"webinar_name_formula" | |
) | |
number_of_names = st.selectbox("N煤mero de nombres", options=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], index=4, key="number_of_names") | |
# Usar la funci贸n reutilizable para crear el bot贸n personalizado | |
submit_webinar_names = create_custom_button("Generar Nombres de Webinar", "generate_webinar_names") | |
# Opciones avanzadas | |
with st.expander("Personaliza tus nombres de webinar"): | |
webinar_name_temperature = st.slider("Creatividad", min_value=0.0, max_value=2.0, value=1.0, step=0.1, key="webinar_name_temp") | |
# Configurar opciones de 谩ngulo | |
angle_keys = ["NINGUNO"] + sorted([key for key in angles_webinar_names.keys() if key != "NINGUNO"]) | |
selected_angle = st.selectbox( | |
"Selecciona el 谩ngulo para tus nombres", | |
options=angle_keys, | |
key="webinar_name_angle" | |
) | |
selected_webinar_name_formula = webinar_name_formulas[selected_webinar_name_formula_key] | |
# Generar y mostrar los nombres usando la funci贸n reutilizable | |
if submit_webinar_names: | |
generate_and_display( | |
col2, | |
generate_webinar_names, | |
webinar_name_audience, | |
webinar_name_product, | |
webinar_name_temperature, | |
selected_webinar_name_formula, | |
content_type="names", | |
number_of_names=number_of_names, | |
selected_angle=selected_angle if selected_angle != "NINGUNO" else None | |
) | |
if validate_inputs(webinar_name_audience, webinar_name_product): | |
try: | |
with col2: | |
with st.spinner("Generando tus nombres de webinar...", show_time=True): | |
generated_webinar_names = generate_webinar_names( | |
number_of_names, | |
webinar_name_audience, | |
webinar_name_product, | |
webinar_name_temperature, | |
selected_webinar_name_formula, | |
selected_angle if selected_angle != "NINGUNO" else None | |
) | |
st.subheader("Tus nombres de webinar:") | |
st.markdown(generated_webinar_names) | |
except ValueError as e: | |
col2.error(f"Error: {str(e)}") | |
else: | |
col2.error("Por favor, proporciona el p煤blico objetivo y el tema del webinar.") | |