JeCabrera commited on
Commit
cc63324
·
verified ·
1 Parent(s): 9fd8be4

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +130 -99
app.py CHANGED
@@ -1,9 +1,9 @@
1
  from dotenv import load_dotenv
2
  import streamlit as st
3
  import os
4
- import google.generativeai as genai
 
5
  import random
6
- from streamlit import session_state as state
7
  from formulas import headline_formulas
8
  from angles import angles
9
 
@@ -11,29 +11,53 @@ from angles import angles
11
  load_dotenv()
12
 
13
  # Configurar la API de Google
14
- genai.configure(api_key=os.getenv("GOOGLE_API_KEY"))
15
-
16
- # Fórmulas con ejemplos y explicaciones
17
- # headline_formulas dictionary has been moved to formulas/headline_formulas.py
18
-
19
- def generate_headlines(number_of_headlines, target_audience, product, temperature, selected_formula, selected_angle):
20
- # Crear la configuración del modelo
21
- generation_config = {
22
- "temperature": temperature,
23
- "top_p": 0.65,
24
- "top_k": 360,
25
- "max_output_tokens": 8196,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
  }
27
 
28
- model = genai.GenerativeModel(
29
- model_name="gemini-3-flash-preview",
30
- generation_config=generation_config,
 
 
 
 
31
  )
32
-
33
- # Angle dictionaries have been moved to angles/angle_data.py
34
-
35
- # Incluir las instrucciones del sistema en el prompt principal
36
- 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.
37
 
38
  FORMAT RULES:
39
  - Each headline must start with number and period
@@ -43,51 +67,27 @@ FORMAT RULES:
43
  - Avoid unnecessary : symbols
44
  - Each headline must be a complete and intriguing sentence
45
 
46
- IMPORTANT ANGLE INSTRUCTIONS:
47
- - The selected angle MUST be applied to EVERY headline
48
- - The angle modifies HOW the formula is expressed, not its structure
49
- - Think of the angle as a "tone overlay" on the formula
50
- - The formula provides the structure, the angle provides the style
51
- - Both must work together seamlessly
52
-
53
- FORMAT EXAMPLE:
54
- 1. Titular 1.
55
-
56
- 2. Titular 2.
57
-
58
- 3. Titular 3.
59
-
60
- 4. Titular 4.
61
-
62
- 5. Titular 5.
63
-
64
  IMPORTANT:
65
  - Each headline must be unique and memorable
66
  - Avoid clichés and generalities
67
  - Maintain an intriguing but credible tone
68
  - Adapt speaking language from the audience
69
  - Focus on transformative benefits
70
- - Follow the selected angle style while maintaining formula structure"""
71
 
72
- # Iniciar el prompt con las instrucciones del sistema
73
  headlines_instruction = f"{system_prompt}\n\n"
74
-
75
- # Añadir instrucciones de ángulo solo si no es "NINGUNO"
76
  if selected_angle != "NINGUNO":
77
  headlines_instruction += f"""
78
  ÁNGULO PRINCIPAL: {selected_angle}
79
- INSTRUCCIONES DE ÁNGULO ESPECÍFICAS:
80
- {angles[selected_angle]["instruction"]}
81
 
82
- IMPORTANTE: El ángulo {selected_angle} debe aplicarse como una "capa de estilo" sobre la estructura de la fórmula:
83
- 1. Mantén la estructura base de la fórmula intacta
84
- 2. Aplica el tono y estilo del ángulo {selected_angle}
85
- 3. Asegura que cada elemento de la fórmula refleje el ángulo
86
- 4. El ángulo afecta al "cómo" se dice, no al "qué" se dice
87
 
88
  EJEMPLOS EXITOSOS DEL ÁNGULO {selected_angle}:
89
  """
90
- for example in angles[selected_angle]["examples"]:
91
  headlines_instruction += f"- {example}\n"
92
 
93
  headlines_instruction += (
@@ -95,21 +95,34 @@ EJEMPLOS EXITOSOS DEL ÁNGULO {selected_angle}:
95
  f"que capturen la atención instantáneamente y generen curiosidad sobre {product}. "
96
  )
97
 
 
 
 
 
 
 
98
  if selected_angle != "NINGUNO":
99
- headlines_instruction += f"IMPORTANTE: Cada titular DEBE seguir el ángulo {selected_angle} de manera clara y consistente.\n\n"
 
 
100
 
101
  headlines_instruction += (
102
- f"Evita menciones obvias de {product} y enfócate en despertar interés genuino"
103
  )
104
 
105
  if selected_angle != "NINGUNO":
106
- headlines_instruction += f" usando el ángulo seleccionado"
107
 
108
  headlines_instruction += ".\n\n"
109
 
 
 
 
 
 
110
  headlines_instruction += (
111
- f"IMPORTANTE: Estudia cuidadosamente estos ejemplos de la fórmula seleccionada. "
112
- f"Cada ejemplo representa el estilo y estructura a seguir"
113
  )
114
 
115
  if selected_angle != "NINGUNO":
@@ -117,53 +130,51 @@ EJEMPLOS EXITOSOS DEL ÁNGULO {selected_angle}:
117
 
118
  headlines_instruction += ":\n\n"
119
 
120
- # Agregar 5 ejemplos aleatorios de la fórmula
121
- random_examples = random.sample(selected_formula['examples'], min(5, len(selected_formula['examples'])))
122
 
123
  headlines_instruction += "EJEMPLOS DE LA FÓRMULA A SEGUIR:\n"
124
  for i, example in enumerate(random_examples, 1):
125
  headlines_instruction += f"{i}. {example}\n"
126
 
127
  headlines_instruction += "\nINSTRUCCIONES ESPECÍFICAS:\n"
128
- headlines_instruction += "1. Mantén la misma estructura y longitud que los ejemplos anteriores\n"
129
- headlines_instruction += "2. Usa el mismo tono y estilo de escritura\n"
130
- headlines_instruction += "3. Replica los patrones de construcción de frases\n"
131
- headlines_instruction += "4. Conserva el nivel de especificidad y detalle\n"
132
- headlines_instruction += f"5. Adapta el contenido para {target_audience} manteniendo la esencia de los ejemplos\n\n"
133
 
134
- headlines_instruction += f"FÓRMULA A SEGUIR:\n{selected_formula['description']}\n\n"
135
 
136
- # CORRECTO (con indentación):
137
  if selected_angle != "NINGUNO":
138
  headlines_instruction += f"""
139
- RECORDATORIO FINAL:
140
- 1. Sigue la estructura de la fórmula seleccionada
141
- 2. Aplica el ángulo como una "capa de estilo"
142
- 3. Mantén la coherencia entre fórmula y ángulo
143
- 4. Asegura que cada titular refleje ambos elementos
144
 
145
  GENERA AHORA:
146
- Crea {number_of_headlines} titulares que sigan fielmente el estilo y estructura de los ejemplos mostrados.
147
  """
148
  else:
149
  headlines_instruction += f"""
150
  GENERA AHORA:
151
- Crea {number_of_headlines} titulares que sigan fielmente el estilo y estructura de los ejemplos mostrados.
152
  """
153
 
154
- # Enviar el mensaje al modelo (sin condiciones de imagen)
155
- chat_session = model.start_chat(
156
- history=[
157
- {
158
- "role": "user",
159
- "parts": [headlines_instruction],
160
- },
161
- ]
162
  )
163
- response = chat_session.send_message("Genera los titulares siguiendo exactamente el estilo de los ejemplos mostrados.")
164
-
165
  return response.text
166
 
 
167
  # Configurar la interfaz de usuario con Streamlit
168
  st.set_page_config(page_title="Enchanted Hooks", layout="wide")
169
 
@@ -175,35 +186,53 @@ with open("manual.md", "r", encoding="utf-8") as file:
175
  st.sidebar.markdown(manual_content)
176
 
177
  # Load CSS from file
178
- with open("styles/main.css", "r") as f:
179
  css = f.read()
180
-
181
  # Apply the CSS
182
  st.markdown(f"<style>{css}</style>", unsafe_allow_html=True)
183
 
184
  # Centrar el título y el subtítulo
185
  st.markdown("<h1 style='text-align: center;'>Enchanted Hooks</h1>", unsafe_allow_html=True)
186
- 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)
 
 
 
187
 
188
  # Crear columnas
189
- col1, col2 = st.columns([1, 2])
190
 
191
  # Columnas de entrada
192
  with col1:
193
- target_audience = st.text_input("¿Quién es tu público objetivo?", placeholder="Ejemplo: Estudiantes Universitarios")
194
- product = st.text_input("¿Qué producto tienes en mente?", placeholder="Ejemplo: Curso de Inglés")
195
- number_of_headlines = st.selectbox("Número de Titulares", options=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], index=4)
 
 
 
 
 
 
 
 
 
 
196
 
197
  # Crear un único acordeón para fórmula, creatividad y ángulo
198
  with st.expander("Personaliza tus titulares"):
199
- temperature = st.slider("Creatividad", min_value=0.0, max_value=2.0, value=1.0, step=0.1)
 
 
 
 
 
 
200
 
201
  selected_formula_key = st.selectbox(
202
  "Selecciona una fórmula para tus titulares",
203
  options=list(headline_formulas.keys())
204
  )
205
 
206
- # Automatically use the keys from the angles dictionary
207
  # Make sure "NINGUNO" appears first, then the rest alphabetically
208
  angle_keys = ["NINGUNO"] + sorted([key for key in angles.keys() if key != "NINGUNO"])
209
  selected_angle = st.selectbox(
@@ -218,13 +247,10 @@ with col1:
218
 
219
  # Mostrar los titulares generados
220
  if submit:
221
- # Check if we have valid inputs
222
  has_product = product.strip() != ""
223
  has_audience = target_audience.strip() != ""
224
-
225
- # Valid combination: Product + Audience
226
  valid_inputs = has_product and has_audience
227
-
228
  if valid_inputs and selected_formula:
229
  try:
230
  generated_headlines = generate_headlines(
@@ -232,16 +258,21 @@ if submit:
232
  target_audience,
233
  product,
234
  temperature,
 
235
  selected_formula,
236
  selected_angle
237
  )
238
- col2.markdown(f"""
 
 
239
  <div class="results-container">
240
  <h4>Observa la magia en acción:</h4>
241
  <p>{generated_headlines}</p>
242
  </div>
243
- """, unsafe_allow_html=True)
244
- except ValueError as e:
 
 
245
  col2.error(f"Error: {str(e)}")
246
  else:
247
  if not selected_formula:
 
1
  from dotenv import load_dotenv
2
  import streamlit as st
3
  import os
4
+ from google import genai
5
+ from google.genai import types
6
  import random
 
7
  from formulas import headline_formulas
8
  from angles import angles
9
 
 
11
  load_dotenv()
12
 
13
  # Configurar la API de Google
14
+ client = genai.Client(api_key=os.getenv("GOOGLE_API_KEY"))
15
+
16
+
17
+ def build_headline_context(selected_formula_key, selected_angle, target_audience, product):
18
+ selected_formula = headline_formulas[selected_formula_key]
19
+
20
+ formula_description = selected_formula.get("description", "").strip()
21
+ formula_examples = selected_formula.get("examples", [])
22
+
23
+ random_examples = random.sample(
24
+ formula_examples,
25
+ min(5, len(formula_examples))
26
+ ) if formula_examples else []
27
+
28
+ angle_instruction = ""
29
+ angle_examples = []
30
+
31
+ if selected_angle != "NINGUNO" and selected_angle in angles:
32
+ angle_instruction = angles[selected_angle].get("instruction", "").strip()
33
+ angle_examples = angles[selected_angle].get("examples", [])[:3]
34
+
35
+ extra_guidance = [
36
+ f"Escribe para {target_audience} como personas reales, no como una categoría genérica.",
37
+ f"Piensa en qué desea ese público, qué le frustra, qué objeciones tiene y qué transformación busca en relación con {product}.",
38
+ "No copies literalmente los ejemplos.",
39
+ "Haz que cada titular sea claro, atractivo y creíble.",
40
+ "No dependas de mencionar explícitamente el producto para generar interés."
41
+ ]
42
+
43
+ return {
44
+ "formula_description": formula_description,
45
+ "formula_examples": random_examples,
46
+ "angle_instruction": angle_instruction,
47
+ "angle_examples": angle_examples,
48
+ "extra_guidance": extra_guidance
49
  }
50
 
51
+
52
+ def generate_headlines(number_of_headlines, target_audience, product, temperature, selected_formula_key, selected_formula, selected_angle):
53
+ context = build_headline_context(
54
+ selected_formula_key=selected_formula_key,
55
+ selected_angle=selected_angle,
56
+ target_audience=target_audience,
57
+ product=product
58
  )
59
+
60
+ system_prompt = """You are a world-class copywriter specialized in writing headlines, hooks, and subject lines that capture attention fast and spark curiosity.
 
 
 
61
 
62
  FORMAT RULES:
63
  - Each headline must start with number and period
 
67
  - Avoid unnecessary : symbols
68
  - Each headline must be a complete and intriguing sentence
69
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
70
  IMPORTANT:
71
  - Each headline must be unique and memorable
72
  - Avoid clichés and generalities
73
  - Maintain an intriguing but credible tone
74
  - Adapt speaking language from the audience
75
  - Focus on transformative benefits
76
+ """
77
 
 
78
  headlines_instruction = f"{system_prompt}\n\n"
79
+
 
80
  if selected_angle != "NINGUNO":
81
  headlines_instruction += f"""
82
  ÁNGULO PRINCIPAL: {selected_angle}
83
+ Aplica este ángulo como una capa de estilo sobre la fórmula, sin alterar su estructura base.
 
84
 
85
+ INSTRUCCIONES DE ÁNGULO ESPECÍFICAS:
86
+ {context["angle_instruction"]}
 
 
 
87
 
88
  EJEMPLOS EXITOSOS DEL ÁNGULO {selected_angle}:
89
  """
90
+ for example in context["angle_examples"]:
91
  headlines_instruction += f"- {example}\n"
92
 
93
  headlines_instruction += (
 
95
  f"que capturen la atención instantáneamente y generen curiosidad sobre {product}. "
96
  )
97
 
98
+ headlines_instruction += (
99
+ f"Antes de escribir, determina quién es realmente {target_audience}: "
100
+ f"qué desea, qué le frustra, qué objeciones tiene, qué transformación busca y cómo suele pensar o hablar sobre este problema. "
101
+ f"Usa esa comprensión para que cada titular conecte con su situación de forma natural y relevante.\n\n"
102
+ )
103
+
104
  if selected_angle != "NINGUNO":
105
+ headlines_instruction += (
106
+ f"IMPORTANTE: Cada titular DEBE seguir el ángulo {selected_angle} de manera clara y consistente.\n\n"
107
+ )
108
 
109
  headlines_instruction += (
110
+ f"No dependas de mencionar explícitamente {product} para generar interés genuino"
111
  )
112
 
113
  if selected_angle != "NINGUNO":
114
+ headlines_instruction += " usando el ángulo seleccionado"
115
 
116
  headlines_instruction += ".\n\n"
117
 
118
+ headlines_instruction += "GUÍA ADICIONAL:\n"
119
+ for rule in context["extra_guidance"]:
120
+ headlines_instruction += f"- {rule}\n"
121
+ headlines_instruction += "\n"
122
+
123
  headlines_instruction += (
124
+ "IMPORTANTE: Estudia cuidadosamente estos ejemplos de la fórmula seleccionada. "
125
+ "Cada ejemplo representa el estilo y estructura a seguir"
126
  )
127
 
128
  if selected_angle != "NINGUNO":
 
130
 
131
  headlines_instruction += ":\n\n"
132
 
133
+ random_examples = context["formula_examples"]
 
134
 
135
  headlines_instruction += "EJEMPLOS DE LA FÓRMULA A SEGUIR:\n"
136
  for i, example in enumerate(random_examples, 1):
137
  headlines_instruction += f"{i}. {example}\n"
138
 
139
  headlines_instruction += "\nINSTRUCCIONES ESPECÍFICAS:\n"
140
+ headlines_instruction += "1. Mantén una estructura y longitud similares a las de los ejemplos anteriores\n"
141
+ headlines_instruction += "2. Conserva el nivel de especificidad y detalle\n"
142
+ headlines_instruction += "3. Inspírate en los patrones de construcción sin copiarlos literalmente\n"
143
+ headlines_instruction += "4. Haz que cada titular suene natural para el público objetivo\n"
144
+ headlines_instruction += "5. Asegúrate de que cada titular sea claro, atractivo y creíble\n\n"
145
 
146
+ headlines_instruction += f"FÓRMULA A SEGUIR:\n{context['formula_description']}\n\n"
147
 
 
148
  if selected_angle != "NINGUNO":
149
  headlines_instruction += f"""
150
+ RECORDATORIO FINAL:
151
+ 1. Sigue la estructura de la fórmula seleccionada
152
+ 2. Aplica el ángulo como una capa de estilo
153
+ 3. Mantén la coherencia entre fórmula y ángulo
154
+ 4. Asegura que cada titular refleje ambos elementos
155
 
156
  GENERA AHORA:
157
+ Crea {number_of_headlines} titulares que sigan fielmente la estructura de la fórmula y mantengan la esencia de los ejemplos mostrados.
158
  """
159
  else:
160
  headlines_instruction += f"""
161
  GENERA AHORA:
162
+ Crea {number_of_headlines} titulares que sigan fielmente la estructura de la fórmula y mantengan la esencia de los ejemplos mostrados.
163
  """
164
 
165
+ response = client.models.generate_content(
166
+ model="gemini-2.5-flash-lite",
167
+ contents=headlines_instruction + "\n\nGenera titulares originales que respeten la estructura de la fórmula seleccionada, apliquen el ángulo elegido y mantengan la esencia de los ejemplos sin copiarlos literalmente.",
168
+ config=types.GenerateContentConfig(
169
+ temperature=temperature,
170
+ top_p=0.65,
171
+ max_output_tokens=8196,
172
+ ),
173
  )
174
+
 
175
  return response.text
176
 
177
+
178
  # Configurar la interfaz de usuario con Streamlit
179
  st.set_page_config(page_title="Enchanted Hooks", layout="wide")
180
 
 
186
  st.sidebar.markdown(manual_content)
187
 
188
  # Load CSS from file
189
+ with open("styles/main.css", "r", encoding="utf-8") as f:
190
  css = f.read()
191
+
192
  # Apply the CSS
193
  st.markdown(f"<style>{css}</style>", unsafe_allow_html=True)
194
 
195
  # Centrar el título y el subtítulo
196
  st.markdown("<h1 style='text-align: center;'>Enchanted Hooks</h1>", unsafe_allow_html=True)
197
+ st.markdown(
198
+ "<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>",
199
+ unsafe_allow_html=True
200
+ )
201
 
202
  # Crear columnas
203
+ col1, col2 = st.columns([1, 2])
204
 
205
  # Columnas de entrada
206
  with col1:
207
+ target_audience = st.text_input(
208
+ "¿Quién es tu público objetivo?",
209
+ placeholder="Ejemplo: Estudiantes Universitarios"
210
+ )
211
+ product = st.text_input(
212
+ "¿Qué producto tienes en mente?",
213
+ placeholder="Ejemplo: Curso de Inglés"
214
+ )
215
+ number_of_headlines = st.selectbox(
216
+ "Número de Titulares",
217
+ options=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
218
+ index=4
219
+ )
220
 
221
  # Crear un único acordeón para fórmula, creatividad y ángulo
222
  with st.expander("Personaliza tus titulares"):
223
+ temperature = st.slider(
224
+ "Creatividad",
225
+ min_value=0.0,
226
+ max_value=2.0,
227
+ value=1.0,
228
+ step=0.1
229
+ )
230
 
231
  selected_formula_key = st.selectbox(
232
  "Selecciona una fórmula para tus titulares",
233
  options=list(headline_formulas.keys())
234
  )
235
 
 
236
  # Make sure "NINGUNO" appears first, then the rest alphabetically
237
  angle_keys = ["NINGUNO"] + sorted([key for key in angles.keys() if key != "NINGUNO"])
238
  selected_angle = st.selectbox(
 
247
 
248
  # Mostrar los titulares generados
249
  if submit:
 
250
  has_product = product.strip() != ""
251
  has_audience = target_audience.strip() != ""
 
 
252
  valid_inputs = has_product and has_audience
253
+
254
  if valid_inputs and selected_formula:
255
  try:
256
  generated_headlines = generate_headlines(
 
258
  target_audience,
259
  product,
260
  temperature,
261
+ selected_formula_key,
262
  selected_formula,
263
  selected_angle
264
  )
265
+
266
+ col2.markdown(
267
+ f"""
268
  <div class="results-container">
269
  <h4>Observa la magia en acción:</h4>
270
  <p>{generated_headlines}</p>
271
  </div>
272
+ """,
273
+ unsafe_allow_html=True
274
+ )
275
+ except Exception as e:
276
  col2.error(f"Error: {str(e)}")
277
  else:
278
  if not selected_formula: