JeCabrera commited on
Commit
604a7ff
·
verified ·
1 Parent(s): c5f1eed

Update app.py

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