JeCabrera commited on
Commit
87732b3
·
verified ·
1 Parent(s): 8264e91

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +349 -349
app.py CHANGED
@@ -1,349 +1,349 @@
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
-
10
- # Cargar las variables de entorno
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, file_content="", image_parts=None, is_image=False):
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-2.0-flash",
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
40
- - One headline per line
41
- - No explanations or categories
42
- - Add a line break between each headline
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 contenido del archivo si existe
76
- if file_content:
77
- headlines_instruction += f"""
78
- REFERENCE CONTENT:
79
- Carefully analyze the following content as a reference for generating headlines:
80
- {file_content[:3000]}
81
-
82
- ANALYSIS INSTRUCTIONS:
83
- 1. Extract key information about the product or service mentioned
84
- 2. Identify the tone, style, and language used
85
- 3. Detect any data about the target audience or customer avatar
86
- 4. Look for benefits, features, or pain points mentioned
87
- 5. Use relevant terms, phrases, or concepts from the content
88
- 6. Maintain consistency with the brand identity or main message
89
- 7. Adapt the headlines to resonate with the provided content
90
-
91
- IMPORTANT COMBINATIONS:
92
- """
93
- # Check different combinations of inputs
94
- if product and target_audience:
95
- headlines_instruction += f"""- You have both product ({product}) and target audience ({target_audience}): Create headlines that connect this specific product with this specific audience, using insights from the document to strengthen the connection.
96
- """
97
- elif product:
98
- headlines_instruction += f"""- You have product ({product}) but no specific target audience: Extract audience information from the document to determine who would benefit most from this product, then create targeted headlines.
99
- """
100
- elif target_audience:
101
- headlines_instruction += f"""- You have target audience ({target_audience}) but no specific product: Identify products or services from the document that would appeal to this audience, then create headlines focused on their needs.
102
- """
103
-
104
- headlines_instruction += """
105
- IMPORTANT: Naturally integrate the elements found in the content with the selected formula and angle.
106
- """
107
-
108
- # Añadir instrucciones de ángulo solo si no es "NINGUNO"
109
- if selected_angle != "NINGUNO":
110
- headlines_instruction += f"""
111
- ÁNGULO PRINCIPAL: {selected_angle}
112
- INSTRUCCIONES DE ÁNGULO ESPECÍFICAS:
113
- {angles[selected_angle]["instruction"]}
114
-
115
- IMPORTANTE: El ángulo {selected_angle} debe aplicarse como una "capa de estilo" sobre la estructura de la fórmula:
116
- 1. Mantén la estructura base de la fórmula intacta
117
- 2. Aplica el tono y estilo del ángulo {selected_angle}
118
- 3. Asegura que cada elemento de la fórmula refleje el ángulo
119
- 4. El ángulo afecta al "cómo" se dice, no al "qué" se dice
120
-
121
- EJEMPLOS EXITOSOS DEL ÁNGULO {selected_angle}:
122
- """
123
- for example in angles[selected_angle]["examples"]:
124
- headlines_instruction += f"- {example}\n"
125
-
126
- headlines_instruction += (
127
- f"\nTu tarea es crear {number_of_headlines} titulares irresistibles para {target_audience} "
128
- f"que capturen la atención instantáneamente y generen curiosidad sobre {product}. "
129
- )
130
-
131
- if selected_angle != "NINGUNO":
132
- headlines_instruction += f"IMPORTANTE: Cada titular DEBE seguir el ángulo {selected_angle} de manera clara y consistente.\n\n"
133
-
134
- headlines_instruction += (
135
- f"Evita menciones obvias de {product} y enfócate en despertar interés genuino"
136
- )
137
-
138
- if selected_angle != "NINGUNO":
139
- headlines_instruction += f" usando el ángulo seleccionado"
140
-
141
- headlines_instruction += ".\n\n"
142
-
143
- headlines_instruction += (
144
- f"IMPORTANTE: Estudia cuidadosamente estos ejemplos de la fórmula seleccionada. "
145
- f"Cada ejemplo representa el estilo y estructura a seguir"
146
- )
147
-
148
- if selected_angle != "NINGUNO":
149
- headlines_instruction += f", adaptados al ángulo {selected_angle}"
150
-
151
- headlines_instruction += ":\n\n"
152
-
153
- # Agregar 5 ejemplos aleatorios de la fórmula
154
- random_examples = random.sample(selected_formula['examples'], min(5, len(selected_formula['examples'])))
155
-
156
- headlines_instruction += "EJEMPLOS DE LA FÓRMULA A SEGUIR:\n"
157
- for i, example in enumerate(random_examples, 1):
158
- headlines_instruction += f"{i}. {example}\n"
159
-
160
- headlines_instruction += "\nINSTRUCCIONES ESPECÍFICAS:\n"
161
- headlines_instruction += "1. Mantén la misma estructura y longitud que los ejemplos anteriores\n"
162
- headlines_instruction += "2. Usa el mismo tono y estilo de escritura\n"
163
- headlines_instruction += "3. Replica los patrones de construcción de frases\n"
164
- headlines_instruction += "4. Conserva el nivel de especificidad y detalle\n"
165
- headlines_instruction += f"5. Adapta el contenido para {target_audience} manteniendo la esencia de los ejemplos\n\n"
166
-
167
- headlines_instruction += f"FÓRMULA A SEGUIR:\n{selected_formula['description']}\n\n"
168
-
169
- # CORRECTO (con indentación):
170
- if selected_angle != "NINGUNO":
171
- headlines_instruction += f"""
172
- RECORDATORIO FINAL:
173
- 1. Sigue la estructura de la fórmula seleccionada
174
- 2. Aplica el ángulo como una "capa de estilo"
175
- 3. Mantén la coherencia entre fórmula y ángulo
176
- 4. Asegura que cada titular refleje ambos elementos
177
-
178
- GENERA AHORA:
179
- Crea {number_of_headlines} titulares que sigan fielmente el estilo y estructura de los ejemplos mostrados.
180
- """
181
- else:
182
- headlines_instruction += f"""
183
- GENERA AHORA:
184
- Crea {number_of_headlines} titulares que sigan fielmente el estilo y estructura de los ejemplos mostrados.
185
- """
186
-
187
- # Modificar la forma de enviar el mensaje según si hay imagen o no
188
- if is_image and image_parts:
189
- chat_session = model.start_chat(
190
- history=[
191
- {
192
- "role": "user",
193
- "parts": [
194
- headlines_instruction,
195
- image_parts
196
- ],
197
- },
198
- ]
199
- )
200
- response = chat_session.send_message("Genera los titulares siguiendo exactamente el estilo de los ejemplos mostrados, inspirándote en la imagen proporcionada.")
201
- else:
202
- chat_session = model.start_chat(
203
- history=[
204
- {
205
- "role": "user",
206
- "parts": [headlines_instruction],
207
- },
208
- ]
209
- )
210
- response = chat_session.send_message("Genera los titulares siguiendo exactamente el estilo de los ejemplos mostrados.")
211
-
212
- return response.text
213
-
214
- # Configurar la interfaz de usuario con Streamlit
215
- st.set_page_config(page_title="Enchanted Hooks", layout="wide")
216
-
217
- # Leer el contenido del archivo manual.md
218
- with open("manual.md", "r", encoding="utf-8") as file:
219
- manual_content = file.read()
220
-
221
- # Mostrar el contenido del manual en el sidebar
222
- st.sidebar.markdown(manual_content)
223
-
224
- # Load CSS from file
225
- with open("styles/main.css", "r") as f:
226
- css = f.read()
227
-
228
- # Apply the CSS
229
- st.markdown(f"<style>{css}</style>", unsafe_allow_html=True)
230
-
231
- # Centrar el título y el subtítulo
232
- st.markdown("<h1 style='text-align: center;'>Enchanted Hooks</h1>", unsafe_allow_html=True)
233
- 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)
234
-
235
- # Crear columnas
236
- col1, col2 = st.columns([1, 2])
237
-
238
- # Columnas de entrada
239
- with col1:
240
- target_audience = st.text_input("¿Quién es tu público objetivo?", placeholder="Ejemplo: Estudiantes Universitarios")
241
- product = st.text_input("¿Qué producto tienes en mente?", placeholder="Ejemplo: Curso de Inglés")
242
- number_of_headlines = st.selectbox("Número de Titulares", options=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], index=4)
243
-
244
- # Crear un único acordeón para fórmula, creatividad y ángulo
245
- with st.expander("Personaliza tus titulares"):
246
- temperature = st.slider("Creatividad", min_value=0.0, max_value=2.0, value=1.0, step=0.1)
247
-
248
- selected_formula_key = st.selectbox(
249
- "Selecciona una fórmula para tus titulares",
250
- options=list(headline_formulas.keys())
251
- )
252
-
253
- # Automatically use the keys from the angles dictionary
254
- # Make sure "NINGUNO" appears first, then the rest alphabetically
255
- angle_keys = ["NINGUNO"] + sorted([key for key in angles.keys() if key != "NINGUNO"])
256
- selected_angle = st.selectbox(
257
- "Selecciona el ángulo para tus titulares",
258
- options=angle_keys
259
- )
260
-
261
- # Añadir cargador de archivos dentro del acordeón
262
- uploaded_file = st.file_uploader("📄 Archivo o imagen de referencia",
263
- type=['txt', 'pdf', 'docx', 'jpg', 'jpeg', 'png'])
264
-
265
- file_content = ""
266
- is_image = False
267
- image_parts = None
268
-
269
- if uploaded_file is not None:
270
- file_type = uploaded_file.name.split('.')[-1].lower()
271
-
272
- # Manejar archivos de texto
273
- if file_type in ['txt', 'pdf', 'docx']:
274
- if file_type == 'txt':
275
- try:
276
- file_content = uploaded_file.read().decode('utf-8')
277
- st.success(f"Archivo TXT cargado correctamente: {uploaded_file.name}")
278
- except Exception as e:
279
- st.error(f"Error al leer el archivo TXT: {str(e)}")
280
- file_content = ""
281
-
282
- elif file_type == 'pdf':
283
- try:
284
- import PyPDF2
285
- pdf_reader = PyPDF2.PdfReader(uploaded_file)
286
- file_content = ""
287
- for page in pdf_reader.pages:
288
- file_content += page.extract_text() + "\n"
289
- st.success(f"Archivo PDF cargado correctamente: {uploaded_file.name}")
290
- except Exception as e:
291
- st.error(f"Error al leer el archivo PDF: {str(e)}")
292
- file_content = ""
293
-
294
- elif file_type == 'docx':
295
- try:
296
- import docx
297
- doc = docx.Document(uploaded_file)
298
- file_content = "\n".join([para.text for para in doc.paragraphs])
299
- st.success(f"Archivo DOCX cargado correctamente: {uploaded_file.name}")
300
- except Exception as e:
301
- st.error(f"Error al leer el archivo DOCX: {str(e)}")
302
- file_content = ""
303
-
304
- # Manejar archivos de imagen
305
- elif file_type in ['jpg', 'jpeg', 'png']:
306
- try:
307
- from PIL import Image
308
- image = Image.open(uploaded_file)
309
- image_bytes = uploaded_file.getvalue()
310
- image_parts = {
311
- "mime_type": uploaded_file.type,
312
- "data": image_bytes
313
- }
314
- is_image = True
315
- st.image(image, caption="Imagen cargada", use_column_width=True)
316
- except Exception as e:
317
- st.error(f"Error al procesar la imagen: {str(e)}")
318
- is_image = False
319
-
320
- selected_formula = headline_formulas[selected_formula_key]
321
-
322
- # Botón de enviar
323
- submit = st.button("Generar Titulares")
324
-
325
- # Mostrar los titulares generados
326
- if submit:
327
- if target_audience and product and selected_formula:
328
- try:
329
- generated_headlines = generate_headlines(
330
- number_of_headlines,
331
- target_audience,
332
- product,
333
- temperature,
334
- selected_formula,
335
- selected_angle,
336
- file_content if 'file_content' in locals() else "",
337
- image_parts if 'image_parts' in locals() else None,
338
- is_image if 'is_image' in locals() else False
339
- )
340
- col2.markdown(f"""
341
- <div class="results-container">
342
- <h4>Observa la magia en acción:</h4>
343
- <p>{generated_headlines}</p>
344
- </div>
345
- """, unsafe_allow_html=True)
346
- except ValueError as e:
347
- col2.error(f"Error: {str(e)}")
348
- else:
349
- col2.error("Por favor, proporciona el público objetivo, el producto y selecciona una fórmula.")
 
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
+
10
+ # Cargar las variables de entorno
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, file_content="", image_parts=None, is_image=False):
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-2.0-flash",
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
40
+ - One headline per line
41
+ - No explanations or categories
42
+ - Add a line break between each headline
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 contenido del archivo si existe
76
+ if file_content:
77
+ headlines_instruction += f"""
78
+ REFERENCE CONTENT:
79
+ Carefully analyze the following content as a reference for generating headlines:
80
+ {file_content[:3000]}
81
+
82
+ ANALYSIS INSTRUCTIONS:
83
+ 1. Extract key information about the product or service mentioned
84
+ 2. Identify the tone, style, and language used
85
+ 3. Detect any data about the target audience or customer avatar
86
+ 4. Look for benefits, features, or pain points mentioned
87
+ 5. Use relevant terms, phrases, or concepts from the content
88
+ 6. Maintain consistency with the brand identity or main message
89
+ 7. Adapt the headlines to resonate with the provided content
90
+
91
+ IMPORTANT COMBINATIONS:
92
+ """
93
+ # Updated conditions for specific input combinations
94
+ if product and not target_audience:
95
+ headlines_instruction += f"""- FILE + PRODUCT: You have a reference document and product ({product}). Create headlines that highlight this specific product's benefits and features using insights from the document. Extract audience information from the document to better target the headlines.
96
+ """
97
+ elif target_audience and not product:
98
+ headlines_instruction += f"""- FILE + TARGET AUDIENCE: You have a reference document and target audience ({target_audience}). Create headlines tailored to this specific audience using language and concepts from the document. Identify products or services from the document that would appeal to this audience.
99
+ """
100
+ elif product and target_audience:
101
+ headlines_instruction += f"""- PRODUCT + TARGET AUDIENCE: You have both product ({product}) and target audience ({target_audience}). Create headlines that connect this specific product with this specific audience, using insights from the document to strengthen the connection.
102
+ """
103
+
104
+ headlines_instruction += """
105
+ IMPORTANT: Naturally integrate the elements found in the content with the selected formula and angle.
106
+ """
107
+
108
+ # Añadir instrucciones de ángulo solo si no es "NINGUNO"
109
+ if selected_angle != "NINGUNO":
110
+ headlines_instruction += f"""
111
+ ÁNGULO PRINCIPAL: {selected_angle}
112
+ INSTRUCCIONES DE ÁNGULO ESPECÍFICAS:
113
+ {angles[selected_angle]["instruction"]}
114
+
115
+ IMPORTANTE: El ángulo {selected_angle} debe aplicarse como una "capa de estilo" sobre la estructura de la fórmula:
116
+ 1. Mantén la estructura base de la fórmula intacta
117
+ 2. Aplica el tono y estilo del ángulo {selected_angle}
118
+ 3. Asegura que cada elemento de la fórmula refleje el ángulo
119
+ 4. El ángulo afecta al "cómo" se dice, no al "qué" se dice
120
+
121
+ EJEMPLOS EXITOSOS DEL ÁNGULO {selected_angle}:
122
+ """
123
+ for example in angles[selected_angle]["examples"]:
124
+ headlines_instruction += f"- {example}\n"
125
+
126
+ headlines_instruction += (
127
+ f"\nTu tarea es crear {number_of_headlines} titulares irresistibles para {target_audience} "
128
+ f"que capturen la atención instantáneamente y generen curiosidad sobre {product}. "
129
+ )
130
+
131
+ if selected_angle != "NINGUNO":
132
+ headlines_instruction += f"IMPORTANTE: Cada titular DEBE seguir el ángulo {selected_angle} de manera clara y consistente.\n\n"
133
+
134
+ headlines_instruction += (
135
+ f"Evita menciones obvias de {product} y enfócate en despertar interés genuino"
136
+ )
137
+
138
+ if selected_angle != "NINGUNO":
139
+ headlines_instruction += f" usando el ángulo seleccionado"
140
+
141
+ headlines_instruction += ".\n\n"
142
+
143
+ headlines_instruction += (
144
+ f"IMPORTANTE: Estudia cuidadosamente estos ejemplos de la fórmula seleccionada. "
145
+ f"Cada ejemplo representa el estilo y estructura a seguir"
146
+ )
147
+
148
+ if selected_angle != "NINGUNO":
149
+ headlines_instruction += f", adaptados al ángulo {selected_angle}"
150
+
151
+ headlines_instruction += ":\n\n"
152
+
153
+ # Agregar 5 ejemplos aleatorios de la fórmula
154
+ random_examples = random.sample(selected_formula['examples'], min(5, len(selected_formula['examples'])))
155
+
156
+ headlines_instruction += "EJEMPLOS DE LA FÓRMULA A SEGUIR:\n"
157
+ for i, example in enumerate(random_examples, 1):
158
+ headlines_instruction += f"{i}. {example}\n"
159
+
160
+ headlines_instruction += "\nINSTRUCCIONES ESPECÍFICAS:\n"
161
+ headlines_instruction += "1. Mantén la misma estructura y longitud que los ejemplos anteriores\n"
162
+ headlines_instruction += "2. Usa el mismo tono y estilo de escritura\n"
163
+ headlines_instruction += "3. Replica los patrones de construcción de frases\n"
164
+ headlines_instruction += "4. Conserva el nivel de especificidad y detalle\n"
165
+ headlines_instruction += f"5. Adapta el contenido para {target_audience} manteniendo la esencia de los ejemplos\n\n"
166
+
167
+ headlines_instruction += f"FÓRMULA A SEGUIR:\n{selected_formula['description']}\n\n"
168
+
169
+ # CORRECTO (con indentación):
170
+ if selected_angle != "NINGUNO":
171
+ headlines_instruction += f"""
172
+ RECORDATORIO FINAL:
173
+ 1. Sigue la estructura de la fórmula seleccionada
174
+ 2. Aplica el ángulo como una "capa de estilo"
175
+ 3. Mantén la coherencia entre fórmula y ángulo
176
+ 4. Asegura que cada titular refleje ambos elementos
177
+
178
+ GENERA AHORA:
179
+ Crea {number_of_headlines} titulares que sigan fielmente el estilo y estructura de los ejemplos mostrados.
180
+ """
181
+ else:
182
+ headlines_instruction += f"""
183
+ GENERA AHORA:
184
+ Crea {number_of_headlines} titulares que sigan fielmente el estilo y estructura de los ejemplos mostrados.
185
+ """
186
+
187
+ # Modificar la forma de enviar el mensaje según si hay imagen o no
188
+ if is_image and image_parts:
189
+ chat_session = model.start_chat(
190
+ history=[
191
+ {
192
+ "role": "user",
193
+ "parts": [
194
+ headlines_instruction,
195
+ image_parts
196
+ ],
197
+ },
198
+ ]
199
+ )
200
+ response = chat_session.send_message("Genera los titulares siguiendo exactamente el estilo de los ejemplos mostrados, inspirándote en la imagen proporcionada.")
201
+ else:
202
+ chat_session = model.start_chat(
203
+ history=[
204
+ {
205
+ "role": "user",
206
+ "parts": [headlines_instruction],
207
+ },
208
+ ]
209
+ )
210
+ response = chat_session.send_message("Genera los titulares siguiendo exactamente el estilo de los ejemplos mostrados.")
211
+
212
+ return response.text
213
+
214
+ # Configurar la interfaz de usuario con Streamlit
215
+ st.set_page_config(page_title="Enchanted Hooks", layout="wide")
216
+
217
+ # Leer el contenido del archivo manual.md
218
+ with open("manual.md", "r", encoding="utf-8") as file:
219
+ manual_content = file.read()
220
+
221
+ # Mostrar el contenido del manual en el sidebar
222
+ st.sidebar.markdown(manual_content)
223
+
224
+ # Load CSS from file
225
+ with open("styles/main.css", "r") as f:
226
+ css = f.read()
227
+
228
+ # Apply the CSS
229
+ st.markdown(f"<style>{css}</style>", unsafe_allow_html=True)
230
+
231
+ # Centrar el título y el subtítulo
232
+ st.markdown("<h1 style='text-align: center;'>Enchanted Hooks</h1>", unsafe_allow_html=True)
233
+ 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)
234
+
235
+ # Crear columnas
236
+ col1, col2 = st.columns([1, 2])
237
+
238
+ # Columnas de entrada
239
+ with col1:
240
+ target_audience = st.text_input("¿Quién es tu público objetivo?", placeholder="Ejemplo: Estudiantes Universitarios")
241
+ product = st.text_input("¿Qué producto tienes en mente?", placeholder="Ejemplo: Curso de Inglés")
242
+ number_of_headlines = st.selectbox("Número de Titulares", options=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], index=4)
243
+
244
+ # Crear un único acordeón para fórmula, creatividad y ángulo
245
+ with st.expander("Personaliza tus titulares"):
246
+ temperature = st.slider("Creatividad", min_value=0.0, max_value=2.0, value=1.0, step=0.1)
247
+
248
+ selected_formula_key = st.selectbox(
249
+ "Selecciona una fórmula para tus titulares",
250
+ options=list(headline_formulas.keys())
251
+ )
252
+
253
+ # Automatically use the keys from the angles dictionary
254
+ # Make sure "NINGUNO" appears first, then the rest alphabetically
255
+ angle_keys = ["NINGUNO"] + sorted([key for key in angles.keys() if key != "NINGUNO"])
256
+ selected_angle = st.selectbox(
257
+ "Selecciona el ángulo para tus titulares",
258
+ options=angle_keys
259
+ )
260
+
261
+ # Añadir cargador de archivos dentro del acordeón
262
+ uploaded_file = st.file_uploader("📄 Archivo o imagen de referencia",
263
+ type=['txt', 'pdf', 'docx', 'jpg', 'jpeg', 'png'])
264
+
265
+ file_content = ""
266
+ is_image = False
267
+ image_parts = None
268
+
269
+ if uploaded_file is not None:
270
+ file_type = uploaded_file.name.split('.')[-1].lower()
271
+
272
+ # Manejar archivos de texto
273
+ if file_type in ['txt', 'pdf', 'docx']:
274
+ if file_type == 'txt':
275
+ try:
276
+ file_content = uploaded_file.read().decode('utf-8')
277
+ st.success(f"Archivo TXT cargado correctamente: {uploaded_file.name}")
278
+ except Exception as e:
279
+ st.error(f"Error al leer el archivo TXT: {str(e)}")
280
+ file_content = ""
281
+
282
+ elif file_type == 'pdf':
283
+ try:
284
+ import PyPDF2
285
+ pdf_reader = PyPDF2.PdfReader(uploaded_file)
286
+ file_content = ""
287
+ for page in pdf_reader.pages:
288
+ file_content += page.extract_text() + "\n"
289
+ st.success(f"Archivo PDF cargado correctamente: {uploaded_file.name}")
290
+ except Exception as e:
291
+ st.error(f"Error al leer el archivo PDF: {str(e)}")
292
+ file_content = ""
293
+
294
+ elif file_type == 'docx':
295
+ try:
296
+ import docx
297
+ doc = docx.Document(uploaded_file)
298
+ file_content = "\n".join([para.text for para in doc.paragraphs])
299
+ st.success(f"Archivo DOCX cargado correctamente: {uploaded_file.name}")
300
+ except Exception as e:
301
+ st.error(f"Error al leer el archivo DOCX: {str(e)}")
302
+ file_content = ""
303
+
304
+ # Manejar archivos de imagen
305
+ elif file_type in ['jpg', 'jpeg', 'png']:
306
+ try:
307
+ from PIL import Image
308
+ image = Image.open(uploaded_file)
309
+ image_bytes = uploaded_file.getvalue()
310
+ image_parts = {
311
+ "mime_type": uploaded_file.type,
312
+ "data": image_bytes
313
+ }
314
+ is_image = True
315
+ st.image(image, caption="Imagen cargada", use_column_width=True)
316
+ except Exception as e:
317
+ st.error(f"Error al procesar la imagen: {str(e)}")
318
+ is_image = False
319
+
320
+ selected_formula = headline_formulas[selected_formula_key]
321
+
322
+ # Botón de enviar
323
+ submit = st.button("Generar Titulares")
324
+
325
+ # Mostrar los titulares generados
326
+ if submit:
327
+ if target_audience and product and selected_formula:
328
+ try:
329
+ generated_headlines = generate_headlines(
330
+ number_of_headlines,
331
+ target_audience,
332
+ product,
333
+ temperature,
334
+ selected_formula,
335
+ selected_angle,
336
+ file_content if 'file_content' in locals() else "",
337
+ image_parts if 'image_parts' in locals() else None,
338
+ is_image if 'is_image' in locals() else False
339
+ )
340
+ col2.markdown(f"""
341
+ <div class="results-container">
342
+ <h4>Observa la magia en acción:</h4>
343
+ <p>{generated_headlines}</p>
344
+ </div>
345
+ """, unsafe_allow_html=True)
346
+ except ValueError as e:
347
+ col2.error(f"Error: {str(e)}")
348
+ else:
349
+ col2.error("Por favor, proporciona el público objetivo, el producto y selecciona una fórmula.")