JeCabrera commited on
Commit
aeb54c4
·
verified ·
1 Parent(s): 4a99a9b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +148 -104
app.py CHANGED
@@ -4,8 +4,13 @@ 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()
@@ -139,26 +144,24 @@ SUCCESSFUL EXAMPLES OF THE {selected_angle} ANGLE:
139
 
140
  # Usar la variable angle_instructions para determinar si hay un ángulo seleccionado
141
  if angle_instructions:
142
- email_instruction += f"IMPORTANT: Each email MUST follow the {selected_angle} angle clearly and consistently.\n\n"
143
 
144
- email_instruction += (
145
- f"Avoid obvious mentions of {product} and focus on generating genuine interest"
146
- )
147
-
148
- if angle_instructions:
149
- email_instruction += f" using the selected angle"
150
-
151
- email_instruction += ".\n\n"
152
 
153
- # Agregar ejemplos de la fórmula
154
- examples_to_use = selected_formula['examples'][:min(2, len(selected_formula['examples']))] # Reduced to only 2 examples
155
 
156
- email_instruction += "FORMULA EXAMPLES TO STUDY (ONLY FOR STRUCTURE, NOT CONTENT):\n"
157
- for i, example in enumerate(examples_to_use, 1):
158
  email_instruction += f"{i}. {example}\n"
159
-
160
- # Añadir advertencia crítica con emoji para llamar la atención
161
- email_instruction += "\n⚠️ WARNING: DO NOT COPY THESE EXAMPLES. Create completely original content with different stories, scenarios and language. The examples are ONLY for understanding the structure.\n"
 
 
 
 
 
162
 
163
  # Añadir instrucciones específicas sobre la temperatura creativa
164
  email_instruction += f"\nCREATIVITY LEVEL: {temperature}. Higher values mean more creative and original content.\n\n"
@@ -166,59 +169,73 @@ SUCCESSFUL EXAMPLES OF THE {selected_angle} ANGLE:
166
  email_instruction += f"FORMULA TO FOLLOW:\n{selected_formula['description']}\n\n"
167
 
168
  # Consolidar las instrucciones finales en un solo bloque
169
- final_instructions = [
170
- "Follow the logical structure but not the exact wording",
171
- "Be creative and original with your content",
172
- "Maintain the sequence flow between emails"
173
- ]
174
 
175
- # Añadir instrucciones específicas para el ángulo si es necesario
176
  if selected_angle != "NINGUNO":
177
- final_instructions.extend([
178
  "Apply the angle as a 'style layer'",
179
  "Maintain coherence between formula and angle",
180
  "Ensure each email reflects both elements"
181
  ])
182
 
183
  email_instruction += "\nFINAL REMINDER:\n"
184
- for i, instruction in enumerate(final_instructions, 1):
185
- email_instruction += f"{i}. {instruction}\n"
 
 
186
 
187
- # Simplify the final instruction to clearly specify 5 emails
188
- email_instruction += f"\nGENERATE NOW:\nCreate 5 CREATIVE emails that follow the logical structure but with original content.\n"
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 only the STRUCTURE of the examples, but with completely original content, drawing inspiration from the provided image."
197
- else:
198
- instruction_text = "Generate the emails in Spanish following only the STRUCTURE of the examples, but with completely original content and stories."
199
-
200
- # Simplificar las instrucciones finales para evitar redundancia
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
  # Define the clean_response_text function before it's used
219
  def clean_response_text(text):
220
  """Remove extra spaces and normalize whitespace in the response text"""
221
- import re
222
  # Replace multiple newlines with just two
223
  text = re.sub(r'\n{3,}', '\n\n', text)
224
  # Remove leading/trailing whitespace
@@ -243,18 +260,24 @@ st.markdown("""
243
  """, unsafe_allow_html=True)
244
 
245
  # Leer el contenido del archivo manual.md
246
- with open("manual.md", "r", encoding="utf-8") as file:
247
- manual_content = file.read()
248
-
249
- # Mostrar el contenido del manual en el sidebar
250
- st.sidebar.markdown(manual_content)
 
 
 
251
 
252
  # Load CSS from file
253
- with open("styles/main.css", "r") as f:
254
- css = f.read()
255
-
256
- # Apply the CSS
257
- st.markdown(f"<style>{css}</style>", unsafe_allow_html=True)
 
 
 
258
 
259
  # Centrar el título y el subtítulo
260
  st.markdown("<h1 style='text-align: center;'>Generador de Emails</h1>", unsafe_allow_html=True)
@@ -263,6 +286,11 @@ st.markdown("<h4 style='text-align: center;'>Transforma tu marketing con emails
263
  # Crear columnas
264
  col1, col2 = st.columns([1, 2])
265
 
 
 
 
 
 
266
  # Columnas de entrada
267
  with col1:
268
  target_audience = st.text_input("¿Quién es tu público objetivo?", placeholder="Ejemplo: Estudiantes Universitarios")
@@ -369,26 +397,43 @@ with col1:
369
  selected_formula = email_formulas.email_formulas[selected_formula_key] # Updated reference
370
 
371
  # Removed the submit button from here
372
- # Mostrar los emails generados
373
- if submit:
374
- # Check if we have a valid combination of inputs
375
- has_file = 'file_content' in locals() and file_content.strip() != ""
 
 
376
  has_product = product.strip() != ""
377
  has_audience = target_audience.strip() != ""
378
- has_emotion = 'emotion' in locals() and emotion.strip() != ""
379
- has_action = 'desired_action' in locals() and desired_action.strip() != ""
380
 
381
- # Valid combinations:
382
- # 1. File + Product (no audience needed)
383
- # 2. File + Audience (no product needed)
384
- # 3. Product + Audience (traditional way)
385
- valid_inputs = (
386
- (has_file and has_product) or
387
- (has_file and has_audience) or
388
- (has_product and has_audience and has_emotion and has_action)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
389
  )
390
 
391
- if valid_inputs and selected_formula:
392
  try:
393
  # Use spinner within col2 context
394
  with col2:
@@ -400,44 +445,43 @@ if submit:
400
  temperature,
401
  selected_formula,
402
  selected_angle,
403
- file_content if 'file_content' in locals() else "",
404
- image_parts if 'image_parts' in locals() else None,
405
- is_image if 'is_image' in locals() else False,
406
  emotion,
407
  desired_action,
408
  creative_idea # Add the creative idea parameter
409
  )
410
 
411
- # Clean the response text to remove extra spaces
412
- generated_emails = clean_response_text(generated_emails)
413
-
414
- # Display the generated emails in col2 (still within col2 context)
415
- st.markdown(f"""
416
- <div class="results-container">
417
- <h4>Tus emails persuasivos:</h4>
418
- <p>{generated_emails}</p>
419
- </div>
420
- """, unsafe_allow_html=True)
421
-
422
- # Add download button (styling is in styles/main.css)
423
- import datetime
424
-
425
- # Get current timestamp for the filename
426
- timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
427
-
428
- # Download button
429
- st.download_button(
430
- label="DESCARGAR EMAILS",
431
- data=generated_emails,
432
- file_name=f"emails_persuasivos_{timestamp}.txt",
433
- mime="text/plain"
434
- )
435
- except ValueError as e:
 
436
  col2.error(f"Error: {str(e)}")
437
  else:
438
  if not selected_formula:
439
  col2.error("Por favor selecciona una fórmula.")
440
- elif not (has_emotion and has_action):
441
- col2.error("Por favor especifica la emoción que quieres evocar y la acción deseada.")
442
  else:
443
- 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.")
 
4
  import google.generativeai as genai
5
  import random
6
  from streamlit import session_state as state
7
+ from formulas import email_formulas
8
  from angles import angles
9
+ import re
10
+ import datetime
11
+ import PyPDF2
12
+ import docx
13
+ from PIL import Image
14
 
15
  # Cargar las variables de entorno
16
  load_dotenv()
 
144
 
145
  # Usar la variable angle_instructions para determinar si hay un ángulo seleccionado
146
  if angle_instructions:
147
+ email_instruction += f"IMPORTANT: Each email MUST follow the {selected_angle} angle clearly and consistently."
148
 
149
+ email_instruction += "\n\n"
 
 
 
 
 
 
 
150
 
151
+ # Agregar 5 ejemplos aleatorios de la fórmula
152
+ random_examples = random.sample(selected_formula['examples'], min(5, len(selected_formula['examples'])))
153
 
154
+ email_instruction += "FORMULA EXAMPLES TO FOLLOW:\n"
155
+ for i, example in enumerate(random_examples, 1):
156
  email_instruction += f"{i}. {example}\n"
157
+
158
+ # Añadir instrucciones específicas sobre cómo seguir los ejemplos
159
+ email_instruction += "\nSPECIFIC INSTRUCTIONS:\n"
160
+ email_instruction += "1. Maintain the same structure and length as the previous examples\n"
161
+ email_instruction += "2. Use the same tone and writing style\n"
162
+ email_instruction += "3. Replicate the phrase construction patterns\n"
163
+ email_instruction += "4. Preserve the level of specificity and detail\n"
164
+ email_instruction += f"5. Adapt the content for {target_audience} while maintaining the essence of the examples\n\n"
165
 
166
  # Añadir instrucciones específicas sobre la temperatura creativa
167
  email_instruction += f"\nCREATIVITY LEVEL: {temperature}. Higher values mean more creative and original content.\n\n"
 
169
  email_instruction += f"FORMULA TO FOLLOW:\n{selected_formula['description']}\n\n"
170
 
171
  # Consolidar las instrucciones finales en un solo bloque
172
+ final_reminder = ["Follow the structure of the selected formula"]
 
 
 
 
173
 
174
+ # Add angle-specific instructions only if an angle is selected
175
  if selected_angle != "NINGUNO":
176
+ final_reminder.extend([
177
  "Apply the angle as a 'style layer'",
178
  "Maintain coherence between formula and angle",
179
  "Ensure each email reflects both elements"
180
  ])
181
 
182
  email_instruction += "\nFINAL REMINDER:\n"
183
+ for i, reminder in enumerate(final_reminder, 1):
184
+ email_instruction += f"{i}. {reminder}\n"
185
+
186
+ email_instruction += "\nGENERATE NOW:\nCreate 5 emails that faithfully follow the style and structure of the examples shown.\n"
187
 
 
 
 
188
  # Modificar la forma de enviar el mensaje según si hay imagen o no
189
  message_parts = [email_instruction]
190
 
191
+ # Build instruction text more clearly with conditional components
192
+ instruction_components = ["Generate the emails in Spanish following exactly the style and structure of the examples shown."]
193
+
194
  # Add the image to the message parts if it exists
195
  if is_image and image_parts:
196
  message_parts.append(image_parts)
197
+ instruction_components.append("drawing inspiration from the provided image.")
 
 
 
 
 
198
 
199
+ # Add final instruction
200
+ instruction_components.append("Do not include explanations, only the emails.")
 
 
 
 
 
 
 
201
 
202
+ # Join all instruction components with proper spacing
203
+ instruction_text = " ".join(instruction_components)
204
 
205
+ # Create the chat session with the message parts
206
+ try:
207
+ chat_session = model.start_chat(
208
+ history=[
209
+ {
210
+ "role": "user",
211
+ "parts": message_parts,
212
+ },
213
+ ]
214
+ )
215
+
216
+ # Enviar el mensaje con las instrucciones
217
+ response = chat_session.send_message(instruction_text)
218
+
219
+ return response.text
220
+ except genai.types.generation_types.StopCandidateException as e:
221
+ # Handle content filtering/safety issues
222
+ error_message = f"La generación se detuvo debido a restricciones de contenido: {str(e)}"
223
+ st.error(error_message)
224
+ return f"Error: {error_message}"
225
+ except genai.types.generation_types.BlockedPromptException as e:
226
+ # Handle blocked prompt issues
227
+ error_message = f"El prompt fue bloqueado por políticas de contenido: {str(e)}"
228
+ st.error(error_message)
229
+ return f"Error: {error_message}"
230
+ except Exception as e:
231
+ # Handle general API errors
232
+ error_message = f"Error al comunicarse con la API de Google: {str(e)}"
233
+ st.error(error_message)
234
+ return f"Error: {error_message}"
235
 
236
  # Define the clean_response_text function before it's used
237
  def clean_response_text(text):
238
  """Remove extra spaces and normalize whitespace in the response text"""
 
239
  # Replace multiple newlines with just two
240
  text = re.sub(r'\n{3,}', '\n\n', text)
241
  # Remove leading/trailing whitespace
 
260
  """, unsafe_allow_html=True)
261
 
262
  # Leer el contenido del archivo manual.md
263
+ manual_path = "manual.md"
264
+ if os.path.exists(manual_path):
265
+ with open(manual_path, "r", encoding="utf-8") as file:
266
+ manual_content = file.read()
267
+ # Mostrar el contenido del manual en el sidebar
268
+ st.sidebar.markdown(manual_content)
269
+ else:
270
+ st.sidebar.warning("Manual file not found.")
271
 
272
  # Load CSS from file
273
+ css_path = "styles/main.css"
274
+ if os.path.exists(css_path):
275
+ with open(css_path, "r") as f:
276
+ css = f.read()
277
+ # Apply the CSS
278
+ st.markdown(f"<style>{css}</style>", unsafe_allow_html=True)
279
+ else:
280
+ st.warning("CSS file not found.")
281
 
282
  # Centrar el título y el subtítulo
283
  st.markdown("<h1 style='text-align: center;'>Generador de Emails</h1>", unsafe_allow_html=True)
 
286
  # Crear columnas
287
  col1, col2 = st.columns([1, 2])
288
 
289
+ # Initialize these variables at the top level before the UI components
290
+ file_content = ""
291
+ is_image = False
292
+ image_parts = None
293
+
294
  # Columnas de entrada
295
  with col1:
296
  target_audience = st.text_input("¿Quién es tu público objetivo?", placeholder="Ejemplo: Estudiantes Universitarios")
 
397
  selected_formula = email_formulas.email_formulas[selected_formula_key] # Updated reference
398
 
399
  # Removed the submit button from here
400
+ # Define a function to validate inputs
401
+ def validate_inputs(file_content, product, target_audience, emotion, desired_action):
402
+ """
403
+ Validates input combinations and returns a tuple of (is_valid, error_message)
404
+ """
405
+ has_file = file_content.strip() != "" if file_content else False
406
  has_product = product.strip() != ""
407
  has_audience = target_audience.strip() != ""
408
+ has_emotion = emotion.strip() != "" if emotion else False
409
+ has_action = desired_action.strip() != "" if desired_action else False
410
 
411
+ # Check for valid combinations
412
+ if has_file and has_product:
413
+ return True, "" # File + Product is valid
414
+ elif has_file and has_audience:
415
+ return True, "" # File + Audience is valid
416
+ elif has_product and has_audience and has_emotion and has_action:
417
+ return True, "" # Product + Audience + Emotion + Action is valid
418
+
419
+ # If we get here, no valid combination was found
420
+ if not (has_emotion and has_action):
421
+ return False, "Por favor especifica la emoción que quieres evocar y la acción deseada."
422
+ else:
423
+ return False, "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."
424
+
425
+ # Mostrar los emails generados
426
+ if submit:
427
+ # Validate inputs using the new function
428
+ is_valid, error_message = validate_inputs(
429
+ file_content,
430
+ product,
431
+ target_audience,
432
+ emotion,
433
+ desired_action
434
  )
435
 
436
+ if is_valid and selected_formula:
437
  try:
438
  # Use spinner within col2 context
439
  with col2:
 
445
  temperature,
446
  selected_formula,
447
  selected_angle,
448
+ file_content,
449
+ image_parts,
450
+ is_image,
451
  emotion,
452
  desired_action,
453
  creative_idea # Add the creative idea parameter
454
  )
455
 
456
+ # Check if the response starts with "Error:"
457
+ if generated_emails.startswith("Error:"):
458
+ st.error(generated_emails)
459
+ else:
460
+ # Clean the response text to remove extra spaces
461
+ generated_emails = clean_response_text(generated_emails)
462
+
463
+ # Display the generated emails in col2 (still within col2 context)
464
+ st.markdown(f"""
465
+ <div class="results-container">
466
+ <h4>Tus emails persuasivos:</h4>
467
+ <p>{generated_emails}</p>
468
+ </div>
469
+ """, unsafe_allow_html=True)
470
+
471
+ # Get current timestamp for the filename
472
+ timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
473
+
474
+ # Download button
475
+ st.download_button(
476
+ label="DESCARGAR EMAILS",
477
+ data=generated_emails,
478
+ file_name=f"emails_persuasivos_{timestamp}.txt",
479
+ mime="text/plain"
480
+ )
481
+ except Exception as e:
482
  col2.error(f"Error: {str(e)}")
483
  else:
484
  if not selected_formula:
485
  col2.error("Por favor selecciona una fórmula.")
 
 
486
  else:
487
+ col2.error(error_message)