File size: 9,476 Bytes
8056e64
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25e4a50
8056e64
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25e4a50
 
 
 
 
8056e64
25e4a50
8056e64
 
 
 
 
25e4a50
 
8056e64
 
 
25e4a50
8056e64
 
25e4a50
8056e64
 
 
25e4a50
8056e64
 
 
 
25e4a50
 
8056e64
 
 
25e4a50
8056e64
 
 
25e4a50
8056e64
 
25e4a50
8056e64
 
 
25e4a50
 
 
 
 
 
8056e64
25e4a50
8056e64
25e4a50
8056e64
 
25e4a50
 
 
 
 
 
 
 
8056e64
 
 
25e4a50
 
8056e64
 
25e4a50
8056e64
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25e4a50
 
8056e64
 
25e4a50
 
8056e64
 
 
 
25e4a50
 
 
8056e64
 
 
 
 
 
 
 
25e4a50
 
 
8056e64
 
 
 
 
 
25e4a50
 
8056e64
 
 
 
 
 
 
 
 
25e4a50
8056e64
 
 
 
 
 
 
 
 
 
 
 
25e4a50
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
from dotenv import load_dotenv
import streamlit as st
import os
import google.generativeai as genai
import random
from streamlit import session_state as state
from formulas import headline_formulas
from angles import angles

# Cargar las variables de entorno
load_dotenv()

# Configurar la API de Google
genai.configure(api_key=os.getenv("GOOGLE_API_KEY"))

# Fórmulas con ejemplos y explicaciones
# headline_formulas dictionary has been moved to formulas/headline_formulas.py

def generate_headlines(number_of_headlines, target_audience, product, temperature, selected_formula, selected_angle):
    # Crear la configuración del modelo
    generation_config = {
        "temperature": temperature,
        "top_p": 0.65,
        "top_k": 360,
        "max_output_tokens": 8196,
    }

    model = genai.GenerativeModel(
        model_name="gemini-2.0-flash",
        generation_config=generation_config,
    )
    
    # Angle dictionaries have been moved to angles/angle_data.py
    
    # Incluir las instrucciones del sistema en el prompt principal
    system_prompt = f"""You are a world-class copywriter, with expertise in crafting hooks, headlines, and subject lines that immediately capture the reader's attention, prompting them to open the email or continue reading.

FORMAT RULES:
- Each headline must start with number and period
- One headline per line
- No explanations or categories
- Add a line break between each headline
- Avoid unnecessary : symbols
- Each headline must be a complete and intriguing sentence

IMPORTANT ANGLE INSTRUCTIONS:
- The selected angle MUST be applied to EVERY headline
- The angle modifies HOW the formula is expressed, not its structure
- Think of the angle as a "tone overlay" on the formula
- The formula provides the structure, the angle provides the style
- Both must work together seamlessly

FORMAT EXAMPLE:
1. Titular 1.

2. Titular 2.

3. Titular 3.

4. Titular 4.

5. Titular 5.

IMPORTANT:
- Each headline 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 angle style while maintaining formula structure"""

    # Iniciar el prompt con las instrucciones del sistema
    headlines_instruction = f"{system_prompt}\n\n"
    
    # Añadir instrucciones de ángulo solo si no es "NINGUNO"
    if selected_angle != "NINGUNO":
        headlines_instruction += f"""
ÁNGULO PRINCIPAL: {selected_angle}
INSTRUCCIONES DE ÁNGULO ESPECÍFICAS:
{angles[selected_angle]["instruction"]}

IMPORTANTE: El ángulo {selected_angle} debe aplicarse como una "capa de estilo" sobre la estructura de la fórmula:
1. Mantén la estructura base de la fórmula intacta
2. Aplica el tono y estilo del ángulo {selected_angle}
3. Asegura que cada elemento de la fórmula refleje el ángulo
4. El ángulo afecta al "cómo" se dice, no al "qué" se dice

EJEMPLOS EXITOSOS DEL ÁNGULO {selected_angle}:
"""
        for example in angles[selected_angle]["examples"]:
            headlines_instruction += f"- {example}\n"

    headlines_instruction += (
        f"\nTu tarea es crear {number_of_headlines} titulares irresistibles para {target_audience} "
        f"que capturen la atención instantáneamente y generen curiosidad sobre {product}. "
    )

    if selected_angle != "NINGUNO":
        headlines_instruction += f"IMPORTANTE: Cada titular DEBE seguir el ángulo {selected_angle} de manera clara y consistente.\n\n"

    headlines_instruction += (
        f"Evita menciones obvias de {product} y enfócate en despertar interés genuino"
    )

    if selected_angle != "NINGUNO":
        headlines_instruction += f" usando el ángulo seleccionado"

    headlines_instruction += ".\n\n"

    headlines_instruction += (
        f"IMPORTANTE: Estudia cuidadosamente estos ejemplos de la fórmula seleccionada. "
        f"Cada ejemplo representa el estilo y estructura a seguir"
    )

    if selected_angle != "NINGUNO":
        headlines_instruction += f", adaptados al ángulo {selected_angle}"

    headlines_instruction += ":\n\n"

    # Agregar 5 ejemplos aleatorios de la fórmula
    random_examples = random.sample(selected_formula['examples'], min(5, len(selected_formula['examples'])))

    headlines_instruction += "EJEMPLOS DE LA FÓRMULA A SEGUIR:\n"
    for i, example in enumerate(random_examples, 1):
        headlines_instruction += f"{i}. {example}\n"

    headlines_instruction += "\nINSTRUCCIONES ESPECÍFICAS:\n"
    headlines_instruction += "1. Mantén la misma estructura y longitud que los ejemplos anteriores\n"
    headlines_instruction += "2. Usa el mismo tono y estilo de escritura\n"
    headlines_instruction += "3. Replica los patrones de construcción de frases\n"
    headlines_instruction += "4. Conserva el nivel de especificidad y detalle\n"
    headlines_instruction += f"5. Adapta el contenido para {target_audience} manteniendo la esencia de los ejemplos\n\n"

    headlines_instruction += f"FÓRMULA A SEGUIR:\n{selected_formula['description']}\n\n"

    # CORRECTO (con indentación):
    if selected_angle != "NINGUNO":
        headlines_instruction += f"""
    RECORDATORIO FINAL:
    1. Sigue la estructura de la fórmula seleccionada
    2. Aplica el ángulo como una "capa de estilo"
    3. Mantén la coherencia entre fórmula y ángulo
    4. Asegura que cada titular refleje ambos elementos

GENERA AHORA:
Crea {number_of_headlines} titulares que sigan fielmente el estilo y estructura de los ejemplos mostrados.
"""
    else:
        headlines_instruction += f"""
GENERA AHORA:
Crea {number_of_headlines} titulares que sigan fielmente el estilo y estructura de los ejemplos mostrados.
"""

    # Enviar el mensaje al modelo (sin condiciones de imagen)
    chat_session = model.start_chat(
        history=[
            {
                "role": "user",
                "parts": [headlines_instruction],
            },
        ]
    )
    response = chat_session.send_message("Genera los titulares siguiendo exactamente el estilo de los ejemplos mostrados.")
    
    return response.text

# Configurar la interfaz de usuario con Streamlit
st.set_page_config(page_title="Enchanted Hooks", layout="wide")

# 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)

# Load CSS from file
with open("styles/main.css", "r") as f:
    css = f.read()
    
# Apply the CSS
st.markdown(f"<style>{css}</style>", unsafe_allow_html=True)

# Centrar el título y el subtítulo
st.markdown("<h1 style='text-align: center;'>Enchanted Hooks</h1>", unsafe_allow_html=True)
st.markdown("<h4 style='text-align: center;'>Imagina poder conjurar títulos que no solo informan, sino que encantan. Esta app es tu varita mágica en el mundo del copywriting, transformando cada concepto en un titular cautivador que deja a todos deseando más.</h4>", unsafe_allow_html=True)

# Crear columnas
col1, col2 = st.columns([1, 2])  

# Columnas de entrada
with col1:
    target_audience = st.text_input("¿Quién es tu público objetivo?", placeholder="Ejemplo: Estudiantes Universitarios")
    product = st.text_input("¿Qué producto tienes en mente?", placeholder="Ejemplo: Curso de Inglés")
    number_of_headlines = st.selectbox("Número de Titulares", options=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], index=4)

    # Crear un único acordeón para fórmula, creatividad y ángulo
    with st.expander("Personaliza tus titulares"):
        temperature = st.slider("Creatividad", min_value=0.0, max_value=2.0, value=1.0, step=0.1)

        selected_formula_key = st.selectbox(
            "Selecciona una fórmula para tus titulares",
            options=list(headline_formulas.keys())
        )

        # Automatically use the keys from the angles dictionary
        # Make sure "NINGUNO" appears first, then the rest alphabetically
        angle_keys = ["NINGUNO"] + sorted([key for key in angles.keys() if key != "NINGUNO"])
        selected_angle = st.selectbox(
            "Selecciona el ángulo para tus titulares",
            options=angle_keys
        )

    selected_formula = headline_formulas[selected_formula_key]

    # Botón de enviar
    submit = st.button("Generar Titulares")

# Mostrar los titulares generados
if submit:
    # Check if we have valid inputs
    has_product = product.strip() != ""
    has_audience = target_audience.strip() != ""
    
    # Valid combination: Product + Audience
    valid_inputs = has_product and has_audience
    
    if valid_inputs and selected_formula:
        try:
            generated_headlines = generate_headlines(
                number_of_headlines,
                target_audience,
                product,
                temperature,
                selected_formula,
                selected_angle
            )
            col2.markdown(f"""
                <div class="results-container">
                    <h4>Observa la magia en acción:</h4>
                    <p>{generated_headlines}</p>
                </div>
            """, unsafe_allow_html=True)
        except ValueError as e:
            col2.error(f"Error: {str(e)}")
    else:
        if not selected_formula:
            col2.error("Por favor, selecciona una fórmula.")
        else:
            col2.error("Por favor, proporciona el público objetivo y el producto.")