JeCabrera commited on
Commit
75bb700
·
verified ·
1 Parent(s): ec626de

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +390 -390
app.py CHANGED
@@ -1,390 +1,390 @@
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 email_formulas # Updated import statement
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
- # email_formulas dictionary has been moved to formulas/email_formulas.py
18
-
19
- # Cambiar el nombre de la función
20
- def generate_emails(number_of_emails, target_audience, product, temperature, selected_formula, selected_angle, file_content="", image_parts=None, is_image=False, emotion="", desired_action=""):
21
- # Crear la configuración del modelo
22
- generation_config = {
23
- "temperature": temperature,
24
- "top_p": 0.65,
25
- "top_k": 360,
26
- "max_output_tokens": 8196,
27
- }
28
-
29
- model = genai.GenerativeModel(
30
- model_name="gemini-2.0-flash",
31
- generation_config=generation_config,
32
- )
33
-
34
- # Angle dictionaries have been moved to angles/angle_data.py
35
-
36
- # Incluir las instrucciones del sistema en el prompt principal
37
- system_prompt = f"""You are a world-class direct response copywriter trained by Gary Halbert, Gary Bencivenga, and David Ogilvy.
38
-
39
- You have helped many marketers before me persuade their clients through emotional email sequences.
40
- Your task is to create email sequences that make my [buyer persona] feel [emotion] about my [product/service] and convince them to register/take [desired action].
41
-
42
- FORMAT RULES:
43
- - Each email must have a clear and attractive subject line
44
- - Include personalized greeting
45
- - The email body must be persuasive and emotional
46
- - Include a clear call to action
47
- - Add a professional signature
48
- - Separate each email with a dividing line
49
-
50
- IMPORTANT ANGLE INSTRUCTIONS:
51
- - The selected angle MUST be applied to EACH email
52
- - The angle modifies HOW the message is expressed, not its structure
53
- - Think of the angle as a "tone overlay" on the content
54
- - The formula provides the structure, the angle provides the style
55
- - Both must work together seamlessly
56
-
57
- FORMAT EXAMPLE:
58
- ---
59
- SUBJECT: [Attractive subject line]
60
-
61
- [Email body with persuasive and emotional content]
62
-
63
- [Clear call to action]
64
-
65
- [Signature]
66
- ---
67
-
68
- IMPORTANT:
69
- - Each email must be unique and memorable
70
- - Avoid clichés and generalities
71
- - Maintain a persuasive but credible tone
72
- - Adapt language to the target audience
73
- - Focus on transformative benefits
74
- - Follow the selected angle style while maintaining the structure"""
75
-
76
- # Iniciar el prompt con las instrucciones del sistema
77
- email_instruction = f"{system_prompt}\n\n"
78
-
79
- # Añadir contenido del archivo si existe
80
- if file_content:
81
- email_instruction += f"""
82
- REFERENCE CONTENT:
83
- Carefully analyze the following content as a reference for generating emails:
84
- {file_content[:3000]}
85
-
86
- ANALYSIS INSTRUCTIONS:
87
- 1. Extract key information about the product or service mentioned
88
- 2. Identify the tone, style, and language used
89
- 3. Detect any data about the target audience or customer avatar
90
- 4. Look for benefits, features, or pain points mentioned
91
- 5. Use relevant terms, phrases, or concepts from the content
92
- 6. Maintain consistency with the brand identity or main message
93
- 7. Adapt the emails to resonate with the provided content
94
-
95
- IMPORTANT COMBINATIONS:
96
- """
97
- # Updated conditions for specific input combinations
98
- if product and not target_audience:
99
- email_instruction += f"""- FILE + PRODUCT: You have a reference document and product ({product}). Create emails that highlight this specific product's benefits and features using insights from the document. Extract audience information from the document to better target the emails.
100
- """
101
- elif target_audience and not product:
102
- email_instruction += f"""- FILE + TARGET AUDIENCE: You have a reference document and target audience ({target_audience}). Create emails 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.
103
- """
104
- elif product and target_audience:
105
- email_instruction += f"""- PRODUCT + TARGET AUDIENCE: You have both product ({product}) and target audience ({target_audience}). Create emails that connect this specific product with this specific audience, using insights from the document to strengthen the connection.
106
- """
107
-
108
- email_instruction += """
109
- IMPORTANT: Naturally integrate the elements found in the content with the selected formula and angle.
110
- """
111
-
112
- # Añadir instrucciones de ángulo solo si no es "NINGUNO"
113
- if selected_angle != "NINGUNO":
114
- email_instruction += f"""
115
- MAIN ANGLE: {selected_angle}
116
- SPECIFIC ANGLE INSTRUCTIONS:
117
- {angles[selected_angle]["instruction"]}
118
-
119
- IMPORTANT: The angle {selected_angle} must be applied as a "style layer" over the formula structure:
120
- 1. Keep the base structure of the formula intact
121
- 2. Apply the tone and style of the {selected_angle} angle
122
- 3. Ensure each element of the formula reflects the angle
123
- 4. The angle affects "how" it's said, not "what" is said
124
-
125
- SUCCESSFUL EXAMPLES OF THE {selected_angle} ANGLE:
126
- """
127
- for example in angles[selected_angle]["examples"]:
128
- email_instruction += f"- {example}\n"
129
-
130
- # Dentro de la función, actualizar el prompt para incluir emoción y acción deseada
131
- email_instruction += (
132
- f"\nYour task is to create {number_of_emails} persuasive emails for {target_audience} "
133
- f"that evoke {emotion} and convince them to {desired_action} about {product}. "
134
- )
135
-
136
- if selected_angle != "NINGUNO":
137
- email_instruction += f"IMPORTANT: Each email MUST follow the {selected_angle} angle clearly and consistently.\n\n"
138
-
139
- email_instruction += (
140
- f"Avoid obvious mentions of {product} and focus on generating genuine interest"
141
- )
142
-
143
- if selected_angle != "NINGUNO":
144
- email_instruction += f" using the selected angle"
145
-
146
- email_instruction += ".\n\n"
147
-
148
- email_instruction += (
149
- f"IMPORTANT: Carefully study these examples of the selected formula. "
150
- f"Each example represents the style and structure to follow"
151
- )
152
-
153
- if selected_angle != "NINGUNO":
154
- email_instruction += f", adapted to the {selected_angle} angle"
155
-
156
- email_instruction += ":\n\n"
157
-
158
- # Agregar 5 ejemplos aleatorios de la fórmula
159
- random_examples = random.sample(selected_formula['examples'], min(5, len(selected_formula['examples'])))
160
-
161
- email_instruction += "FORMULA EXAMPLES TO FOLLOW:\n"
162
- for i, example in enumerate(random_examples, 1):
163
- email_instruction += f"{i}. {example}\n"
164
-
165
- email_instruction += "\nSPECIFIC INSTRUCTIONS:\n"
166
- email_instruction += "1. Maintain the same structure and length as the previous examples\n"
167
- email_instruction += "2. Use the same tone and writing style\n"
168
- email_instruction += "3. Replicate the phrase construction patterns\n"
169
- email_instruction += "4. Preserve the level of specificity and detail\n"
170
- email_instruction += f"5. Adapt the content for {target_audience} while maintaining the essence of the examples\n\n"
171
-
172
- email_instruction += f"FORMULA TO FOLLOW:\n{selected_formula['description']}\n\n"
173
-
174
- # CORRECTO (con indentación):
175
- if selected_angle != "NINGUNO":
176
- email_instruction += f"""
177
- FINAL REMINDER:
178
- 1. Follow the structure of the selected formula
179
- 2. Apply the angle as a "style layer"
180
- 3. Maintain coherence between formula and angle
181
- 4. Ensure each email reflects both elements
182
-
183
- GENERATE NOW:
184
- Create {number_of_emails} emails that faithfully follow the style and structure of the examples shown.
185
- """
186
- else:
187
- email_instruction += f"""
188
- GENERATE NOW:
189
- Create {number_of_emails} emails that faithfully follow the style and structure of the examples shown.
190
- """
191
-
192
- # Modificar la forma de enviar el mensaje según si hay imagen o no
193
- if is_image and image_parts:
194
- chat_session = model.start_chat(
195
- history=[
196
- {
197
- "role": "user",
198
- "parts": [
199
- email_instruction,
200
- image_parts
201
- ],
202
- },
203
- ]
204
- )
205
- response = chat_session.send_message("Genera los emails en español siguiendo exactamente el estilo de los ejemplos mostrados, inspirándote en la imagen proporcionada. No incluyas explicaciones, solo los emails. IMPORTANTE: No incluyas saludos como 'Hola [Nombre]' y asegúrate que las postdatas (P.D.) tengan el mismo tamaño de texto que el cuerpo del email.")
206
- else:
207
- chat_session = model.start_chat(
208
- history=[
209
- {
210
- "role": "user",
211
- "parts": [email_instruction],
212
- },
213
- ]
214
- )
215
- response = chat_session.send_message("Genera los emails en español siguiendo exactamente el estilo de los ejemplos mostrados. No incluyas explicaciones, solo los emails. IMPORTANTE: No incluyas saludos como 'Hola [Nombre]' y asegúrate que las postdatas (P.D.) tengan el mismo tamaño de texto que el cuerpo del email.")
216
-
217
- return response.text
218
-
219
- # Configurar la interfaz de usuario con Streamlit
220
- st.set_page_config(page_title="Email Composer", layout="wide")
221
-
222
- # Leer el contenido del archivo manual.md
223
- with open("manual.md", "r", encoding="utf-8") as file:
224
- manual_content = file.read()
225
-
226
- # Mostrar el contenido del manual en el sidebar
227
- st.sidebar.markdown(manual_content)
228
-
229
- # Load CSS from file
230
- with open("styles/main.css", "r") as f:
231
- css = f.read()
232
-
233
- # Apply the CSS
234
- st.markdown(f"<style>{css}</style>", unsafe_allow_html=True)
235
-
236
- # Centrar el título y el subtítulo
237
- st.markdown("<h1 style='text-align: center;'>Generador de Emails</h1>", unsafe_allow_html=True)
238
- st.markdown("<h4 style='text-align: center;'>Transforma tu marketing con emails persuasivos que convierten. Esta aplicación es tu arma secreta para crear emails emocionales de respuesta directa que impulsan a la acción.</h4>", unsafe_allow_html=True)
239
-
240
- # Crear columnas
241
- col1, col2 = st.columns([1, 2])
242
-
243
- # Columnas de entrada
244
- with col1:
245
- target_audience = st.text_input("¿Quién es tu público objetivo?", placeholder="Ejemplo: Estudiantes Universitarios")
246
- product = st.text_input("¿Qué producto/servicio estás promocionando?", placeholder="Ejemplo: Curso de Inglés")
247
- number_of_emails = st.selectbox("Número de Emails", options=[1, 2, 3, 4, 5], index=2)
248
-
249
- # Moved the submit button here, right after number_of_emails
250
- submit = st.button("Generar Emails")
251
-
252
- # Crear un único acordeón para fórmula, creatividad y ángulo
253
- with st.expander("Personaliza tus emails"):
254
- temperature = st.slider("Creatividad", min_value=0.0, max_value=2.0, value=1.0, step=0.1)
255
-
256
- emotion = st.selectbox(
257
- "¿Qué emoción quieres evocar?",
258
- options=["Curiosidad", "Miedo", "Esperanza", "Entusiasmo", "Confianza", "Urgencia"]
259
- )
260
-
261
- desired_action = st.text_input("Acción deseada", placeholder="Ejemplo: Registrarse para una prueba gratuita")
262
-
263
- selected_formula_key = st.selectbox(
264
- "Selecciona una fórmula para tus emails",
265
- options=list(email_formulas.email_formulas.keys()) # Updated reference
266
- )
267
-
268
- # Automatically use the keys from the angles dictionary
269
- # Make sure "NINGUNO" appears first, then the rest alphabetically
270
- angle_keys = ["NINGUNO"] + sorted([key for key in angles.keys() if key != "NINGUNO"])
271
- selected_angle = st.selectbox(
272
- "Selecciona un ángulo para tus emails",
273
- options=angle_keys
274
- )
275
-
276
- # Añadir cargador de archivos dentro del acordeón
277
- uploaded_file = st.file_uploader("📄 Archivo o imagen de referencia",
278
- type=['txt', 'pdf', 'docx', 'jpg', 'jpeg', 'png'])
279
-
280
- file_content = ""
281
- is_image = False
282
- image_parts = None
283
-
284
- if uploaded_file is not None:
285
- file_type = uploaded_file.name.split('.')[-1].lower()
286
-
287
- # Manejar archivos de texto
288
- if file_type in ['txt', 'pdf', 'docx']:
289
- if file_type == 'txt':
290
- try:
291
- file_content = uploaded_file.read().decode('utf-8')
292
- st.success(f"Archivo TXT cargado correctamente: {uploaded_file.name}")
293
- except Exception as e:
294
- st.error(f"Error al leer el archivo TXT: {str(e)}")
295
- file_content = ""
296
-
297
- elif file_type == 'pdf':
298
- try:
299
- import PyPDF2
300
- pdf_reader = PyPDF2.PdfReader(uploaded_file)
301
- file_content = ""
302
- for page in pdf_reader.pages:
303
- file_content += page.extract_text() + "\n"
304
- st.success(f"Archivo PDF cargado correctamente: {uploaded_file.name}")
305
- except Exception as e:
306
- st.error(f"Error al leer el archivo PDF: {str(e)}")
307
- file_content = ""
308
-
309
- elif file_type == 'docx':
310
- try:
311
- import docx
312
- doc = docx.Document(uploaded_file)
313
- file_content = "\n".join([para.text for para in doc.paragraphs])
314
- st.success(f"Archivo DOCX cargado correctamente: {uploaded_file.name}")
315
- except Exception as e:
316
- st.error(f"Error al leer el archivo DOCX: {str(e)}")
317
- file_content = ""
318
-
319
- # Manejar archivos de imagen
320
- elif file_type in ['jpg', 'jpeg', 'png']:
321
- try:
322
- from PIL import Image
323
- image = Image.open(uploaded_file)
324
- image_bytes = uploaded_file.getvalue()
325
- image_parts = {
326
- "mime_type": uploaded_file.type,
327
- "data": image_bytes
328
- }
329
- is_image = True
330
- st.image(image, caption="Imagen cargada", use_column_width=True)
331
- except Exception as e:
332
- st.error(f"Error processing image: {str(e)}")
333
- is_image = False
334
-
335
- selected_formula = email_formulas.email_formulas[selected_formula_key] # Updated reference
336
-
337
- # Removed the submit button from here
338
- # Mostrar los emails generados
339
- if submit:
340
- # Check if we have a valid combination of inputs
341
- has_file = 'file_content' in locals() and file_content.strip() != ""
342
- has_product = product.strip() != ""
343
- has_audience = target_audience.strip() != ""
344
- has_emotion = 'emotion' in locals() and emotion.strip() != ""
345
- has_action = 'desired_action' in locals() and desired_action.strip() != ""
346
-
347
- # Valid combinations:
348
- # 1. File + Product (no audience needed)
349
- # 2. File + Audience (no product needed)
350
- # 3. Product + Audience (traditional way)
351
- valid_inputs = (
352
- (has_file and has_product) or
353
- (has_file and has_audience) or
354
- (has_product and has_audience and has_emotion and has_action)
355
- )
356
-
357
- if valid_inputs and selected_formula:
358
- try:
359
- # Update the function call to include emotion and desired_action
360
- generated_emails = generate_emails(
361
- number_of_emails,
362
- target_audience,
363
- product,
364
- temperature,
365
- selected_formula,
366
- selected_angle,
367
- file_content if 'file_content' in locals() else "",
368
- image_parts if 'image_parts' in locals() else None,
369
- is_image if 'is_image' in locals() else False,
370
- emotion,
371
- desired_action
372
- )
373
-
374
- # Remove the inline CSS since we've moved it to main.css
375
-
376
- col2.markdown(f"""
377
- <div class="results-container">
378
- <h4>Tus emails persuasivos:</h4>
379
- <p>{generated_emails}</p>
380
- </div>
381
- """, unsafe_allow_html=True)
382
- except ValueError as e:
383
- col2.error(f"Error: {str(e)}")
384
- else:
385
- if not selected_formula:
386
- col2.error("Por favor selecciona una fórmula.")
387
- elif not (has_emotion and has_action):
388
- col2.error("Por favor especifica la emoción que quieres evocar y la acción deseada.")
389
- else:
390
- col2.error("Por favor proporciona al menos una de estas combinaciones: archivo + producto, archivo + público objetivo, o producto + público objetivo + emoción + acción deseada.")
 
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 email_formulas # Updated import statement
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
+ # email_formulas dictionary has been moved to formulas/email_formulas.py
18
+
19
+ # Cambiar el nombre de la función
20
+ def generate_emails(number_of_emails, target_audience, product, temperature, selected_formula, selected_angle, file_content="", image_parts=None, is_image=False, emotion="", desired_action=""):
21
+ # Crear la configuración del modelo
22
+ generation_config = {
23
+ "temperature": temperature,
24
+ "top_p": 0.65,
25
+ "top_k": 360,
26
+ "max_output_tokens": 8196,
27
+ }
28
+
29
+ model = genai.GenerativeModel(
30
+ model_name="gemini-2.0-flash",
31
+ generation_config=generation_config,
32
+ )
33
+
34
+ # Angle dictionaries have been moved to angles/angle_data.py
35
+
36
+ # Incluir las instrucciones del sistema en el prompt principal
37
+ system_prompt = f"""You are a world-class direct response copywriter trained by Gary Halbert, Gary Bencivenga, and David Ogilvy.
38
+
39
+ You have helped many marketers before me persuade their clients through emotional email sequences.
40
+ Your task is to create email sequences that make my [buyer persona] feel [emotion] about my [product/service] and convince them to register/take [desired action].
41
+
42
+ FORMAT RULES:
43
+ - Each email must have a clear and attractive subject line
44
+ - Include personalized greeting
45
+ - The email body must be persuasive and emotional
46
+ - Include a clear call to action
47
+ - Add a professional signature
48
+ - Separate each email with a dividing line
49
+
50
+ IMPORTANT ANGLE INSTRUCTIONS:
51
+ - The selected angle MUST be applied to EACH email
52
+ - The angle modifies HOW the message is expressed, not its structure
53
+ - Think of the angle as a "tone overlay" on the content
54
+ - The formula provides the structure, the angle provides the style
55
+ - Both must work together seamlessly
56
+
57
+ FORMAT EXAMPLE:
58
+ ---
59
+ SUBJECT: [Attractive subject line]
60
+
61
+ [Email body with persuasive and emotional content]
62
+
63
+ [Clear call to action]
64
+
65
+ [Signature]
66
+ ---
67
+
68
+ IMPORTANT:
69
+ - Each email must be unique and memorable
70
+ - Avoid clichés and generalities
71
+ - Maintain a persuasive but credible tone
72
+ - Adapt language to the target audience
73
+ - Focus on transformative benefits
74
+ - Follow the selected angle style while maintaining the structure"""
75
+
76
+ # Iniciar el prompt con las instrucciones del sistema
77
+ email_instruction = f"{system_prompt}\n\n"
78
+
79
+ # Añadir contenido del archivo si existe
80
+ if file_content:
81
+ email_instruction += f"""
82
+ REFERENCE CONTENT:
83
+ Carefully analyze the following content as a reference for generating emails:
84
+ {file_content[:3000]}
85
+
86
+ ANALYSIS INSTRUCTIONS:
87
+ 1. Extract key information about the product or service mentioned
88
+ 2. Identify the tone, style, and language used
89
+ 3. Detect any data about the target audience or customer avatar
90
+ 4. Look for benefits, features, or pain points mentioned
91
+ 5. Use relevant terms, phrases, or concepts from the content
92
+ 6. Maintain consistency with the brand identity or main message
93
+ 7. Adapt the emails to resonate with the provided content
94
+
95
+ IMPORTANT COMBINATIONS:
96
+ """
97
+ # Updated conditions for specific input combinations
98
+ if product and not target_audience:
99
+ email_instruction += f"""- FILE + PRODUCT: You have a reference document and product ({product}). Create emails that highlight this specific product's benefits and features using insights from the document. Extract audience information from the document to better target the emails.
100
+ """
101
+ elif target_audience and not product:
102
+ email_instruction += f"""- FILE + TARGET AUDIENCE: You have a reference document and target audience ({target_audience}). Create emails 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.
103
+ """
104
+ elif product and target_audience:
105
+ email_instruction += f"""- PRODUCT + TARGET AUDIENCE: You have both product ({product}) and target audience ({target_audience}). Create emails that connect this specific product with this specific audience, using insights from the document to strengthen the connection.
106
+ """
107
+
108
+ email_instruction += """
109
+ IMPORTANT: Naturally integrate the elements found in the content with the selected formula and angle.
110
+ """
111
+
112
+ # Añadir instrucciones de ángulo solo si no es "NINGUNO"
113
+ if selected_angle != "NINGUNO":
114
+ email_instruction += f"""
115
+ MAIN ANGLE: {selected_angle}
116
+ SPECIFIC ANGLE INSTRUCTIONS:
117
+ {angles[selected_angle]["instruction"]}
118
+
119
+ IMPORTANT: The angle {selected_angle} must be applied as a "style layer" over the formula structure:
120
+ 1. Keep the base structure of the formula intact
121
+ 2. Apply the tone and style of the {selected_angle} angle
122
+ 3. Ensure each element of the formula reflects the angle
123
+ 4. The angle affects "how" it's said, not "what" is said
124
+
125
+ SUCCESSFUL EXAMPLES OF THE {selected_angle} ANGLE:
126
+ """
127
+ for example in angles[selected_angle]["examples"]:
128
+ email_instruction += f"- {example}\n"
129
+
130
+ # Dentro de la función, actualizar el prompt para incluir emoción y acción deseada
131
+ email_instruction += (
132
+ f"\nYour task is to create {number_of_emails} persuasive emails for {target_audience} "
133
+ f"that evoke {emotion} and convince them to {desired_action} about {product}. "
134
+ )
135
+
136
+ if selected_angle != "NINGUNO":
137
+ email_instruction += f"IMPORTANT: Each email MUST follow the {selected_angle} angle clearly and consistently.\n\n"
138
+
139
+ email_instruction += (
140
+ f"Avoid obvious mentions of {product} and focus on generating genuine interest"
141
+ )
142
+
143
+ if selected_angle != "NINGUNO":
144
+ email_instruction += f" using the selected angle"
145
+
146
+ email_instruction += ".\n\n"
147
+
148
+ email_instruction += (
149
+ f"IMPORTANT: Carefully study these examples of the selected formula. "
150
+ f"Each example represents the style and structure to follow"
151
+ )
152
+
153
+ if selected_angle != "NINGUNO":
154
+ email_instruction += f", adapted to the {selected_angle} angle"
155
+
156
+ email_instruction += ":\n\n"
157
+
158
+ # Agregar 5 ejemplos aleatorios de la fórmula
159
+ random_examples = random.sample(selected_formula['examples'], min(5, len(selected_formula['examples'])))
160
+
161
+ email_instruction += "FORMULA EXAMPLES TO FOLLOW:\n"
162
+ for i, example in enumerate(random_examples, 1):
163
+ email_instruction += f"{i}. {example}\n"
164
+
165
+ email_instruction += "\nSPECIFIC INSTRUCTIONS:\n"
166
+ email_instruction += "1. Maintain the same structure and length as the previous examples\n"
167
+ email_instruction += "2. Use the same tone and writing style\n"
168
+ email_instruction += "3. Replicate the phrase construction patterns\n"
169
+ email_instruction += "4. Preserve the level of specificity and detail\n"
170
+ email_instruction += f"5. Adapt the content for {target_audience} while maintaining the essence of the examples\n\n"
171
+
172
+ email_instruction += f"FORMULA TO FOLLOW:\n{selected_formula['description']}\n\n"
173
+
174
+ # CORRECTO (con indentación):
175
+ if selected_angle != "NINGUNO":
176
+ email_instruction += f"""
177
+ FINAL REMINDER:
178
+ 1. Follow the structure of the selected formula
179
+ 2. Apply the angle as a "style layer"
180
+ 3. Maintain coherence between formula and angle
181
+ 4. Ensure each email reflects both elements
182
+
183
+ GENERATE NOW:
184
+ Create {number_of_emails} emails that faithfully follow the style and structure of the examples shown.
185
+ """
186
+ else:
187
+ email_instruction += f"""
188
+ GENERATE NOW:
189
+ Create {number_of_emails} emails that faithfully follow the style and structure of the examples shown.
190
+ """
191
+
192
+ # Modificar la forma de enviar el mensaje según si hay imagen o no
193
+ if is_image and image_parts:
194
+ chat_session = model.start_chat(
195
+ history=[
196
+ {
197
+ "role": "user",
198
+ "parts": [
199
+ email_instruction,
200
+ image_parts
201
+ ],
202
+ },
203
+ ]
204
+ )
205
+ response = chat_session.send_message("Genera los emails en español siguiendo exactamente el estilo de los ejemplos mostrados, inspirándote en la imagen proporcionada. No incluyas explicaciones, solo los emails. IMPORTANTE: No incluyas saludos como 'Hola [Nombre]' y asegúrate que las postdatas (P.D.) sean más pequeñas y discretas que el cuerpo principal del email, usando un formato más ligero.")
206
+ else:
207
+ chat_session = model.start_chat(
208
+ history=[
209
+ {
210
+ "role": "user",
211
+ "parts": [email_instruction],
212
+ },
213
+ ]
214
+ )
215
+ response = chat_session.send_message("Genera los emails en español siguiendo exactamente el estilo de los ejemplos mostrados. No incluyas explicaciones, solo los emails. IMPORTANTE: No incluyas saludos como 'Hola [Nombre]' y asegúrate que las postdatas (P.D.) sean más pequeñas y discretas que el cuerpo principal del email, usando un formato más ligero.")
216
+
217
+ return response.text
218
+
219
+ # Configurar la interfaz de usuario con Streamlit
220
+ st.set_page_config(page_title="Email Composer", layout="wide")
221
+
222
+ # Leer el contenido del archivo manual.md
223
+ with open("manual.md", "r", encoding="utf-8") as file:
224
+ manual_content = file.read()
225
+
226
+ # Mostrar el contenido del manual en el sidebar
227
+ st.sidebar.markdown(manual_content)
228
+
229
+ # Load CSS from file
230
+ with open("styles/main.css", "r") as f:
231
+ css = f.read()
232
+
233
+ # Apply the CSS
234
+ st.markdown(f"<style>{css}</style>", unsafe_allow_html=True)
235
+
236
+ # Centrar el título y el subtítulo
237
+ st.markdown("<h1 style='text-align: center;'>Generador de Emails</h1>", unsafe_allow_html=True)
238
+ st.markdown("<h4 style='text-align: center;'>Transforma tu marketing con emails persuasivos que convierten. Esta aplicación es tu arma secreta para crear emails emocionales de respuesta directa que impulsan a la acción.</h4>", unsafe_allow_html=True)
239
+
240
+ # Crear columnas
241
+ col1, col2 = st.columns([1, 2])
242
+
243
+ # Columnas de entrada
244
+ with col1:
245
+ target_audience = st.text_input("¿Quién es tu público objetivo?", placeholder="Ejemplo: Estudiantes Universitarios")
246
+ product = st.text_input("¿Qué producto/servicio estás promocionando?", placeholder="Ejemplo: Curso de Inglés")
247
+ number_of_emails = st.selectbox("Número de Emails", options=[1, 2, 3, 4, 5], index=2)
248
+
249
+ # Moved the submit button here, right after number_of_emails
250
+ submit = st.button("Generar Emails")
251
+
252
+ # Crear un único acordeón para fórmula, creatividad y ángulo
253
+ with st.expander("Personaliza tus emails"):
254
+ temperature = st.slider("Creatividad", min_value=0.0, max_value=2.0, value=1.0, step=0.1)
255
+
256
+ emotion = st.selectbox(
257
+ "¿Qué emoción quieres evocar?",
258
+ options=["Curiosidad", "Miedo", "Esperanza", "Entusiasmo", "Confianza", "Urgencia"]
259
+ )
260
+
261
+ desired_action = st.text_input("Acción deseada", placeholder="Ejemplo: Registrarse para una prueba gratuita")
262
+
263
+ selected_formula_key = st.selectbox(
264
+ "Selecciona una fórmula para tus emails",
265
+ options=list(email_formulas.email_formulas.keys()) # Updated reference
266
+ )
267
+
268
+ # Automatically use the keys from the angles dictionary
269
+ # Make sure "NINGUNO" appears first, then the rest alphabetically
270
+ angle_keys = ["NINGUNO"] + sorted([key for key in angles.keys() if key != "NINGUNO"])
271
+ selected_angle = st.selectbox(
272
+ "Selecciona un ángulo para tus emails",
273
+ options=angle_keys
274
+ )
275
+
276
+ # Añadir cargador de archivos dentro del acordeón
277
+ uploaded_file = st.file_uploader("📄 Archivo o imagen de referencia",
278
+ type=['txt', 'pdf', 'docx', 'jpg', 'jpeg', 'png'])
279
+
280
+ file_content = ""
281
+ is_image = False
282
+ image_parts = None
283
+
284
+ if uploaded_file is not None:
285
+ file_type = uploaded_file.name.split('.')[-1].lower()
286
+
287
+ # Manejar archivos de texto
288
+ if file_type in ['txt', 'pdf', 'docx']:
289
+ if file_type == 'txt':
290
+ try:
291
+ file_content = uploaded_file.read().decode('utf-8')
292
+ st.success(f"Archivo TXT cargado correctamente: {uploaded_file.name}")
293
+ except Exception as e:
294
+ st.error(f"Error al leer el archivo TXT: {str(e)}")
295
+ file_content = ""
296
+
297
+ elif file_type == 'pdf':
298
+ try:
299
+ import PyPDF2
300
+ pdf_reader = PyPDF2.PdfReader(uploaded_file)
301
+ file_content = ""
302
+ for page in pdf_reader.pages:
303
+ file_content += page.extract_text() + "\n"
304
+ st.success(f"Archivo PDF cargado correctamente: {uploaded_file.name}")
305
+ except Exception as e:
306
+ st.error(f"Error al leer el archivo PDF: {str(e)}")
307
+ file_content = ""
308
+
309
+ elif file_type == 'docx':
310
+ try:
311
+ import docx
312
+ doc = docx.Document(uploaded_file)
313
+ file_content = "\n".join([para.text for para in doc.paragraphs])
314
+ st.success(f"Archivo DOCX cargado correctamente: {uploaded_file.name}")
315
+ except Exception as e:
316
+ st.error(f"Error al leer el archivo DOCX: {str(e)}")
317
+ file_content = ""
318
+
319
+ # Manejar archivos de imagen
320
+ elif file_type in ['jpg', 'jpeg', 'png']:
321
+ try:
322
+ from PIL import Image
323
+ image = Image.open(uploaded_file)
324
+ image_bytes = uploaded_file.getvalue()
325
+ image_parts = {
326
+ "mime_type": uploaded_file.type,
327
+ "data": image_bytes
328
+ }
329
+ is_image = True
330
+ st.image(image, caption="Imagen cargada", use_column_width=True)
331
+ except Exception as e:
332
+ st.error(f"Error processing image: {str(e)}")
333
+ is_image = False
334
+
335
+ selected_formula = email_formulas.email_formulas[selected_formula_key] # Updated reference
336
+
337
+ # Removed the submit button from here
338
+ # Mostrar los emails generados
339
+ if submit:
340
+ # Check if we have a valid combination of inputs
341
+ has_file = 'file_content' in locals() and file_content.strip() != ""
342
+ has_product = product.strip() != ""
343
+ has_audience = target_audience.strip() != ""
344
+ has_emotion = 'emotion' in locals() and emotion.strip() != ""
345
+ has_action = 'desired_action' in locals() and desired_action.strip() != ""
346
+
347
+ # Valid combinations:
348
+ # 1. File + Product (no audience needed)
349
+ # 2. File + Audience (no product needed)
350
+ # 3. Product + Audience (traditional way)
351
+ valid_inputs = (
352
+ (has_file and has_product) or
353
+ (has_file and has_audience) or
354
+ (has_product and has_audience and has_emotion and has_action)
355
+ )
356
+
357
+ if valid_inputs and selected_formula:
358
+ try:
359
+ # Update the function call to include emotion and desired_action
360
+ generated_emails = generate_emails(
361
+ number_of_emails,
362
+ target_audience,
363
+ product,
364
+ temperature,
365
+ selected_formula,
366
+ selected_angle,
367
+ file_content if 'file_content' in locals() else "",
368
+ image_parts if 'image_parts' in locals() else None,
369
+ is_image if 'is_image' in locals() else False,
370
+ emotion,
371
+ desired_action
372
+ )
373
+
374
+ # Remove the inline CSS since we've moved it to main.css
375
+
376
+ col2.markdown(f"""
377
+ <div class="results-container">
378
+ <h4>Tus emails persuasivos:</h4>
379
+ <p>{generated_emails}</p>
380
+ </div>
381
+ """, unsafe_allow_html=True)
382
+ except ValueError as e:
383
+ col2.error(f"Error: {str(e)}")
384
+ else:
385
+ if not selected_formula:
386
+ col2.error("Por favor selecciona una fórmula.")
387
+ elif not (has_emotion and has_action):
388
+ col2.error("Por favor especifica la emoción que quieres evocar y la acción deseada.")
389
+ else:
390
+ col2.error("Por favor proporciona al menos una de estas combinaciones: archivo + producto, archivo + público objetivo, o producto + público objetivo + emoción + acción deseada.")