JeCabrera commited on
Commit
c50c598
verified
1 Parent(s): e6a474e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +171 -331
app.py CHANGED
@@ -2,298 +2,155 @@ 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="", creative_idea=""):
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
- # Fixed number of emails to 5
35
- number_of_emails = 5
36
 
37
- # Incluir las instrucciones del sistema en el prompt principal
38
- system_prompt = f"""You are a world-class direct response copywriter trained by Gary Halbert, Gary Bencivenga, and David Ogilvy.
39
-
40
- You have helped many marketers before me persuade their clients through emotional email sequences.
41
- 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].
42
-
43
- FORMAT RULES:
44
- - Each email must have a clear and attractive subject line
45
- - Include personalized greeting
46
- - The email body must be persuasive and emotional
47
- - Include a clear call to action
48
- - Add a professional signature
49
- - Separate each email with a dividing line
50
-
51
- IMPORTANT ANGLE INSTRUCTIONS:
52
- - The selected angle MUST be applied to EACH email
53
- - The angle modifies HOW the message is expressed, not its structure
54
- - Think of the angle as a "tone overlay" on the content
55
- - The formula provides the structure, the angle provides the style
56
- - Both must work together seamlessly
57
-
58
- FORMAT EXAMPLE:
59
- ---
60
- SUBJECT: [Attractive subject line]
61
-
62
- [Email body with persuasive and emotional content]
63
-
64
- [Clear call to action]
65
-
66
- [Signature]
67
- ---
68
-
69
- IMPORTANT:
70
- - Each email must be unique and memorable
71
- - Avoid clich茅s and generalities
72
- - Maintain a persuasive but credible tone
73
- - Adapt language to the target audience
74
- - Focus on transformative benefits
75
- - Follow the selected angle style while maintaining the structure"""
76
-
77
- # Add creative idea to system prompt if it exists
78
- if creative_idea:
79
- system_prompt += f"""
80
-
81
- CREATIVE CONCEPT:
82
- Use the following creative concept as the central theme for all emails in the sequence:
83
- "{creative_idea}"
84
-
85
- CREATIVE CONCEPT INSTRUCTIONS:
86
- 1. This concept should be the unifying theme across all emails
87
- 2. Use it as a metaphor or analogy throughout the sequence
88
- 3. Develop different aspects of this concept in each email
89
- 4. Make sure the concept naturally connects to the product benefits
90
- 5. The concept should make the emails more memorable and engaging
91
- """
92
-
93
- # Iniciar el prompt con las instrucciones del sistema
94
- email_instruction = f"{system_prompt}\n\n"
95
-
96
- # A帽adir contenido del archivo si existe
97
- if file_content:
98
- email_instruction += f"""
99
- REFERENCE CONTENT:
100
- Carefully analyze the following content as a reference for generating emails:
101
- {file_content[:3000]}
102
-
103
- ANALYSIS INSTRUCTIONS:
104
- 1. Extract key information about the product or service mentioned
105
- 2. Identify the tone, style, and language used
106
- 3. Detect any data about the target audience or customer avatar
107
- 4. Look for benefits, features, or pain points mentioned
108
- 5. Use relevant terms, phrases, or concepts from the content
109
- 6. Maintain consistency with the brand identity or main message
110
- 7. Adapt the emails to resonate with the provided content
111
-
112
- IMPORTANT COMBINATIONS:
113
- """
114
- # Updated conditions for specific input combinations
115
- if product and not target_audience:
116
- 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.
117
- """
118
- elif target_audience and not product:
119
- 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.
120
- """
121
- elif product and target_audience:
122
- 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.
123
- """
124
 
125
- email_instruction += """
126
- IMPORTANT: Naturally integrate the elements found in the content with the selected formula and angle.
127
- """
128
 
129
- # A帽adir instrucciones de 谩ngulo solo si no es "NINGUNO"
130
- if selected_angle != "NINGUNO":
131
- email_instruction += f"""
132
- MAIN ANGLE: {selected_angle}
133
- SPECIFIC ANGLE INSTRUCTIONS:
134
- {angles[selected_angle]["instruction"]}
135
-
136
- IMPORTANT: The angle {selected_angle} must be applied as a "style layer" over the formula structure:
137
- 1. Keep the base structure of the formula intact
138
- 2. Apply the tone and style of the {selected_angle} angle
139
- 3. Ensure each element of the formula reflects the angle
140
- 4. The angle affects "how" it's said, not "what" is said
141
-
142
- SUCCESSFUL EXAMPLES OF THE {selected_angle} ANGLE:
143
- """
144
- for example in angles[selected_angle]["examples"]:
145
- email_instruction += f"- {example}\n"
146
-
147
- # Dentro de la funci贸n, actualizar el prompt para incluir emoci贸n y acci贸n deseada
148
- email_instruction += (
149
- f"\nYour task is to create {number_of_emails} persuasive emails for {target_audience} "
150
- f"that evoke {emotion} and convince them to {desired_action} about {product}. "
151
- )
152
-
153
- if selected_angle != "NINGUNO":
154
- email_instruction += f"IMPORTANT: Each email MUST follow the {selected_angle} angle clearly and consistently.\n\n"
155
-
156
- email_instruction += (
157
- f"Avoid obvious mentions of {product} and focus on generating genuine interest"
158
- )
159
-
160
- if selected_angle != "NINGUNO":
161
- email_instruction += f" using the selected angle"
162
-
163
- email_instruction += ".\n\n"
164
-
165
- email_instruction += (
166
- f"IMPORTANT: Carefully study these examples of the selected formula. "
167
- f"Each example represents the style and structure to follow"
168
- )
169
-
170
- if selected_angle != "NINGUNO":
171
- email_instruction += f", adapted to the {selected_angle} angle"
172
-
173
- email_instruction += ":\n\n"
174
-
175
- # Agregar 5 ejemplos aleatorios de la f贸rmula
176
- random_examples = random.sample(selected_formula['examples'], min(5, len(selected_formula['examples'])))
177
-
178
- email_instruction += "FORMULA EXAMPLES TO FOLLOW:\n"
179
- for i, example in enumerate(random_examples, 1):
180
- email_instruction += f"{i}. {example}\n"
181
-
182
- email_instruction += "\nSPECIFIC INSTRUCTIONS:\n"
183
- email_instruction += "1. Maintain the same structure and length as the previous examples\n"
184
- email_instruction += "2. Use the same tone and writing style\n"
185
- email_instruction += "3. Replicate the phrase construction patterns\n"
186
- email_instruction += "4. Preserve the level of specificity and detail\n"
187
- email_instruction += f"5. Adapt the content for {target_audience} while maintaining the essence of the examples\n\n"
188
-
189
- email_instruction += f"FORMULA TO FOLLOW:\n{selected_formula['description']}\n\n"
190
-
191
- # CORRECTO (con indentaci贸n):
192
- if selected_angle != "NINGUNO":
193
- email_instruction += f"""
194
- FINAL REMINDER:
195
- 1. Follow the structure of the selected formula
196
- 2. Apply the angle as a "style layer"
197
- 3. Maintain coherence between formula and angle
198
- 4. Ensure each email reflects both elements
199
-
200
- GENERATE NOW:
201
- Create {number_of_emails} emails that faithfully follow the style and structure of the examples shown.
202
- """
203
- else:
204
- email_instruction += f"""
205
- GENERATE NOW:
206
- Create {number_of_emails} emails that faithfully follow the style and structure of the examples shown.
207
- """
208
-
209
- # Modificar la forma de enviar el mensaje seg煤n si hay imagen o no
210
- message_parts = [email_instruction]
211
 
212
- # Add the image to the message parts if it exists
213
- if is_image and image_parts:
214
- message_parts.append(image_parts)
215
- instruction_text = "Generate the emails in Spanish following exactly the style of the examples shown, drawing inspiration from the provided image."
216
- else:
217
- instruction_text = "Generate the emails in Spanish following exactly the style of the examples shown."
218
 
219
- # Common instruction for both cases
220
- 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."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
221
 
222
- # Create the chat session with the message parts
223
- chat_session = model.start_chat(
224
- history=[
225
- {
226
- "role": "user",
227
- "parts": message_parts,
228
- },
229
- ]
230
- )
231
 
232
- # Enviar el mensaje con las instrucciones
233
- response = chat_session.send_message(instruction_text)
 
 
 
234
 
235
- return response.text
 
 
 
236
 
237
- # Configurar la interfaz de usuario con Streamlit
238
- st.set_page_config(page_title="Email Composer", layout="wide")
239
 
240
- # Leer el contenido del archivo manual.md
 
 
 
 
241
  with open("manual.md", "r", encoding="utf-8") as file:
242
  manual_content = file.read()
243
-
244
- # Mostrar el contenido del manual en el sidebar
245
  st.sidebar.markdown(manual_content)
246
 
247
- # Load CSS from file
248
- with open("styles/main.css", "r") as f:
249
- css = f.read()
250
-
251
- # Apply the CSS
252
- st.markdown(f"<style>{css}</style>", unsafe_allow_html=True)
253
-
254
- # Centrar el t铆tulo y el subt铆tulo
255
- st.markdown("<h1 style='text-align: center;'>Generador de Emails</h1>", unsafe_allow_html=True)
256
- 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)
257
 
258
- # Crear columnas
259
- col1, col2 = st.columns([1, 2])
260
-
261
- # Columnas de entrada
262
  with col1:
263
- target_audience = st.text_input("驴Qui茅n es tu p煤blico objetivo?", placeholder="Ejemplo: Estudiantes Universitarios")
264
- product = st.text_input("驴Qu茅 producto/servicio est谩s promocionando?", placeholder="Ejemplo: Curso de Ingl茅s")
 
 
265
 
266
- # Add new Creative Idea input field
267
- creative_idea = st.text_area("Idea Creativa", placeholder="Ejemplo: Tu curso es como Netflix: ofrece contenido que engancha y soluciones que la gente realmente quiere ver", height=100)
 
 
268
 
269
- # Only one submit button with a unique key
270
- submit = st.button("Generar Emails", key="generate_emails_button")
271
-
272
- # Crear un 煤nico acorde贸n para f贸rmula, creatividad y 谩ngulo
273
- with st.expander("Personaliza tus emails"):
274
- temperature = st.slider("Creatividad", min_value=0.0, max_value=2.0, value=1.0, step=0.1)
275
-
276
- emotion = st.selectbox(
277
- "驴Qu茅 emoci贸n quieres evocar?",
278
- options=["Curiosidad", "Miedo", "Esperanza", "Entusiasmo", "Confianza", "Urgencia"]
279
- )
280
-
281
- desired_action = st.text_input("Acci贸n deseada", placeholder="Ejemplo: Registrarse para una prueba gratuita")
282
-
283
- selected_formula_key = st.selectbox(
284
- "Selecciona una f贸rmula para tus emails",
285
- options=list(email_formulas.email_formulas.keys()) # Updated reference
286
- )
287
-
288
- # Automatically use the keys from the angles dictionary
289
- # Make sure "NINGUNO" appears first, then the rest alphabetically
290
- angle_keys = ["NINGUNO"] + sorted([key for key in angles.keys() if key != "NINGUNO"])
291
- selected_angle = st.selectbox(
292
- "Selecciona un 谩ngulo para tus emails",
293
- options=angle_keys
294
  )
295
 
296
- # A帽adir cargador de archivos dentro del acorde贸n
297
  uploaded_file = st.file_uploader("馃搫 Archivo o imagen de referencia",
298
  type=['txt', 'pdf', 'docx', 'jpg', 'jpeg', 'png'])
299
 
@@ -309,29 +166,24 @@ with col1:
309
  if file_type == 'txt':
310
  try:
311
  file_content = uploaded_file.read().decode('utf-8')
312
- st.success(f"Archivo TXT cargado correctamente: {uploaded_file.name}")
313
  except Exception as e:
314
  st.error(f"Error al leer el archivo TXT: {str(e)}")
315
  file_content = ""
316
-
317
  elif file_type == 'pdf':
318
  try:
319
- import PyPDF2
320
  pdf_reader = PyPDF2.PdfReader(uploaded_file)
321
  file_content = ""
322
  for page in pdf_reader.pages:
323
  file_content += page.extract_text() + "\n"
324
- st.success(f"Archivo PDF cargado correctamente: {uploaded_file.name}")
325
  except Exception as e:
326
  st.error(f"Error al leer el archivo PDF: {str(e)}")
327
  file_content = ""
328
 
329
  elif file_type == 'docx':
330
  try:
331
- import docx
332
  doc = docx.Document(uploaded_file)
333
  file_content = "\n".join([para.text for para in doc.paragraphs])
334
- st.success(f"Archivo DOCX cargado correctamente: {uploaded_file.name}")
335
  except Exception as e:
336
  st.error(f"Error al leer el archivo DOCX: {str(e)}")
337
  file_content = ""
@@ -339,7 +191,6 @@ with col1:
339
  # Manejar archivos de imagen
340
  elif file_type in ['jpg', 'jpeg', 'png']:
341
  try:
342
- from PIL import Image
343
  image = Image.open(uploaded_file)
344
  image_bytes = uploaded_file.getvalue()
345
  image_parts = {
@@ -347,65 +198,54 @@ with col1:
347
  "data": image_bytes
348
  }
349
  is_image = True
350
- st.image(image, caption="Imagen cargada", use_column_width=True)
351
  except Exception as e:
352
- st.error(f"Error processing image: {str(e)}")
353
  is_image = False
 
 
 
 
 
 
 
 
 
 
 
 
 
354
 
355
- selected_formula = email_formulas.email_formulas[selected_formula_key] # Updated reference
356
-
357
- # Removed the submit button from here
358
- # Mostrar los emails generados
359
- if submit:
360
- # Check if we have a valid combination of inputs
361
- has_file = 'file_content' in locals() and file_content.strip() != ""
362
- has_product = product.strip() != ""
363
- has_audience = target_audience.strip() != ""
364
- has_emotion = 'emotion' in locals() and emotion.strip() != ""
365
- has_action = 'desired_action' in locals() and desired_action.strip() != ""
 
 
366
 
367
- # Valid combinations:
368
- # 1. File + Product (no audience needed)
369
- # 2. File + Audience (no product needed)
370
- # 3. Product + Audience (traditional way)
371
- valid_inputs = (
372
- (has_file and has_product) or
373
- (has_file and has_audience) or
374
- (has_product and has_audience and has_emotion and has_action)
375
- )
376
-
377
- if valid_inputs and selected_formula:
378
- try:
379
- # Use st.spinner instead of col2.spinner
380
- with st.spinner("Creando los emails..."):
381
- # Update the function call to include creative_idea
382
- generated_emails = generate_emails(
383
- target_audience,
384
- product,
385
- temperature,
386
- selected_formula,
387
- selected_angle,
388
- file_content if 'file_content' in locals() else "",
389
- image_parts if 'image_parts' in locals() else None,
390
- is_image if 'is_image' in locals() else False,
391
- emotion,
392
- desired_action,
393
- creative_idea # Add the creative idea parameter
394
- )
395
 
396
- # Display the generated emails in col2
397
- col2.markdown(f"""
398
- <div class="results-container">
399
- <h4>Tus emails persuasivos:</h4>
400
- <p>{generated_emails}</p>
401
- </div>
402
- """, unsafe_allow_html=True)
403
- except ValueError as e:
404
- col2.error(f"Error: {str(e)}")
405
- else:
406
- if not selected_formula:
407
- col2.error("Por favor selecciona una f贸rmula.")
408
- elif not (has_emotion and has_action):
409
- col2.error("Por favor especifica la emoci贸n que quieres evocar y la acci贸n deseada.")
410
- else:
411
- 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.")
 
2
  import streamlit as st
3
  import os
4
  import google.generativeai as genai
5
+ from puv_formulas import puv_formulas
6
+ from styles import apply_styles
7
+ import PyPDF2
8
+ import docx
9
+ from PIL import Image
10
+ import datetime # Add this import for timestamp
11
+
12
+ # Cargar variables de entorno
13
  load_dotenv()
14
 
15
+ # Configurar API de Google Gemini
16
  genai.configure(api_key=os.getenv("GOOGLE_API_KEY"))
17
 
18
+ # Funci贸n para obtener la respuesta del modelo Gemini
19
+ def get_gemini_response(product_service, target_audience, skills, formula_type, temperature, file_content="", image_parts=None):
20
+ # Check if we have at least one source of information
21
+ has_file_content = bool(file_content.strip())
22
+ has_image = image_parts is not None
23
+ has_text_input = target_audience or product_service or skills
 
 
 
 
 
 
 
 
 
 
 
24
 
25
+ if not (has_file_content or has_image or has_text_input):
26
+ return "Debes proporcionar al menos un tipo de informaci贸n: p煤blico objetivo, producto/servicio, habilidades o un archivo de referencia."
27
 
28
+ # If we only have file content but no other inputs, we can proceed
29
+ if (has_file_content or has_image) and not has_text_input:
30
+ # File-only mode
31
+ business_info = "Analyze the provided reference material to extract business information.\n"
32
+ else:
33
+ # Regular mode with validation
34
+ if not target_audience:
35
+ return "El campo de p煤blico objetivo es obligatorio cuando no se proporciona un archivo de referencia completo."
36
+
37
+ if not product_service and not skills:
38
+ return "Debes proporcionar al menos tu producto/servicio o tus habilidades cuando no se proporciona un archivo de referencia completo."
39
+
40
+ # Adjust prompt based on what's provided
41
+ business_info = f"Target Audience: {target_audience}\n"
42
+
43
+ if product_service:
44
+ business_info += f"Product/Service: {product_service}\n"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
 
46
+ if skills:
47
+ business_info += f"My Skills/Expertise: {skills}\n"
 
48
 
49
+ formula = puv_formulas[formula_type]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
 
51
+ # Add file content if available
52
+ reference_info = ""
53
+ if file_content:
54
+ reference_info = f"\nREFERENCE MATERIAL:\n{file_content}\n"
 
 
55
 
56
+ model = genai.GenerativeModel('gemini-2.0-flash')
57
+ full_prompt = f"""
58
+ You are a UVP (Unique Value Proposition) expert. Analyze (internally only, do not output the analysis) the following information:
59
+ BUSINESS INFORMATION:
60
+ {business_info}
61
+ Formula Type: {formula_type}
62
+ {formula["description"]}
63
+ {reference_info}
64
+
65
+ EXAMPLE TO FOLLOW:
66
+ {formula["examples"]}
67
+
68
+ First, analyze (but don't output) these points:
69
+ 1. TARGET AUDIENCE ANALYSIS - Pain Points:
70
+ - What specific frustrations does this audience experience?
71
+ - What are their biggest daily challenges?
72
+ - What emotional problems do they face?
73
+ - What have they tried before that didn't work?
74
+ - What's stopping them from achieving their goals?
75
+
76
+ 2. PRODUCT/SERVICE ANALYSIS - Benefits:
77
+ - What tangible results do clients get?
78
+ - What specific transformation does it offer?
79
+ - What's the unique method or differentiator?
80
+ - What competitive advantages does it have?
81
+ - What emotional benefits does it provide?
82
+
83
+ 3. SKILLS/EXPERTISE ANALYSIS - Credibility:
84
+ - How do these skills directly address the audience's pain points?
85
+ - What unique perspective do these skills bring to the solution?
86
+ - How do these skills enhance the product/service delivery?
87
+ - What credibility elements can be highlighted?
88
+ - How do these skills differentiate from competitors?
89
+
90
+ Based on your internal analysis of the target audience pain points and product benefits (do not include this analysis in the output), create THREE different UVPs in Spanish language following the formula structure provided.
91
+ CRITICAL INSTRUCTIONS:
92
+ - Each UVP must be specific and measurable
93
+ - Focus on the transformation journey
94
+ - Use natural, conversational language
95
+ - Avoid generic phrases and buzzwords
96
+ - Maximum 2 lines per UVP
97
+ - DO NOT include any analysis in the output
98
+ - ONLY output the three UVPs
99
 
100
+ Output EXACTLY in this format (no additional text) in Spanish language:
101
+ 1. [First UVP]
102
+ 2. [Second UVP]
103
+ 3. [Third UVP]
104
+ """
 
 
 
 
105
 
106
+ # Handle text-only or text+image requests
107
+ if image_parts:
108
+ response = model.generate_content([full_prompt, image_parts], generation_config={"temperature": temperature})
109
+ else:
110
+ response = model.generate_content([full_prompt], generation_config={"temperature": temperature})
111
 
112
+ return response.parts[0].text if response and response.parts else "Error generating content."
113
+
114
+ # Configurar la aplicaci贸n Streamlit
115
+ st.set_page_config(page_title="UVP Generator", page_icon="馃挕", layout="wide")
116
 
117
+ # Aplicar estilos
118
+ st.markdown(apply_styles(), unsafe_allow_html=True)
119
 
120
+ # T铆tulo de la app
121
+ st.markdown("<h1>Generador de PUV</h1>", unsafe_allow_html=True)
122
+ st.markdown("<h3>Crea Propuestas 脷nicas de Valor poderosas que atraigan a tus clientes ideales y comuniquen tu valor de manera efectiva.</h3>", unsafe_allow_html=True)
123
+
124
+ # Sidebar manual
125
  with open("manual.md", "r", encoding="utf-8") as file:
126
  manual_content = file.read()
 
 
127
  st.sidebar.markdown(manual_content)
128
 
129
+ # Crear dos columnas
130
+ col1, col2 = st.columns([1, 1])
 
 
 
 
 
 
 
 
131
 
132
+ # Columna izquierda para inputs
 
 
 
133
  with col1:
134
+ product_service = st.text_area(
135
+ "驴Cu谩l es tu producto o servicio?",
136
+ placeholder="Ejemplo: Curso de copywriting con IA, Programa de coaching..."
137
+ )
138
 
139
+ skills = st.text_area(
140
+ "Mis habilidades:",
141
+ placeholder="Ejemplo: Experiencia en marketing digital, certificaci贸n en SEO..."
142
+ )
143
 
144
+ # Move the generate button here, right after skills
145
+ generate_button = st.button("Generar PUV")
146
+
147
+ with st.expander("Opciones avanzadas"):
148
+ target_audience = st.text_area(
149
+ "驴Cu谩l es tu p煤blico objetivo?",
150
+ placeholder="Ejemplo: Coaches que quieren atraer m谩s clientes..."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
151
  )
152
 
153
+ # A帽adir cargador de archivos
154
  uploaded_file = st.file_uploader("馃搫 Archivo o imagen de referencia",
155
  type=['txt', 'pdf', 'docx', 'jpg', 'jpeg', 'png'])
156
 
 
166
  if file_type == 'txt':
167
  try:
168
  file_content = uploaded_file.read().decode('utf-8')
 
169
  except Exception as e:
170
  st.error(f"Error al leer el archivo TXT: {str(e)}")
171
  file_content = ""
172
+
173
  elif file_type == 'pdf':
174
  try:
 
175
  pdf_reader = PyPDF2.PdfReader(uploaded_file)
176
  file_content = ""
177
  for page in pdf_reader.pages:
178
  file_content += page.extract_text() + "\n"
 
179
  except Exception as e:
180
  st.error(f"Error al leer el archivo PDF: {str(e)}")
181
  file_content = ""
182
 
183
  elif file_type == 'docx':
184
  try:
 
185
  doc = docx.Document(uploaded_file)
186
  file_content = "\n".join([para.text for para in doc.paragraphs])
 
187
  except Exception as e:
188
  st.error(f"Error al leer el archivo DOCX: {str(e)}")
189
  file_content = ""
 
191
  # Manejar archivos de imagen
192
  elif file_type in ['jpg', 'jpeg', 'png']:
193
  try:
 
194
  image = Image.open(uploaded_file)
195
  image_bytes = uploaded_file.getvalue()
196
  image_parts = {
 
198
  "data": image_bytes
199
  }
200
  is_image = True
 
201
  except Exception as e:
202
+ st.error(f"Error al procesar la imagen: {str(e)}")
203
  is_image = False
204
+
205
+ formula_type = st.selectbox(
206
+ "F贸rmula PUV:",
207
+ options=list(puv_formulas.keys())
208
+ )
209
+ temperature = st.slider(
210
+ "Nivel de creatividad:",
211
+ min_value=0.0,
212
+ max_value=2.0,
213
+ value=1.0,
214
+ step=0.1,
215
+ help="Valores m谩s altos generan propuestas m谩s creativas pero menos predecibles."
216
+ )
217
 
218
+ with col2:
219
+ if generate_button:
220
+ # Store the response in session state so it persists across reruns
221
+ with st.spinner("Creando tu PUV..."):
222
+ st.session_state.puv_response = get_gemini_response(
223
+ product_service,
224
+ target_audience,
225
+ skills,
226
+ formula_type,
227
+ temperature,
228
+ file_content,
229
+ image_parts
230
+ )
231
 
232
+ # Display the response if it exists in session state (separate from the generate button condition)
233
+ if 'puv_response' in st.session_state:
234
+ st.write("### Propuestas 脷nicas de Valor")
235
+ st.write(st.session_state.puv_response)
236
+
237
+ # Add download button if we have a valid response
238
+ if st.session_state.puv_response and not st.session_state.puv_response.startswith("Error") and not st.session_state.puv_response.startswith("Debes"):
239
+ # Get current timestamp for the filename
240
+ timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
241
 
242
+ # Prepare content for download
243
+ download_content = st.session_state.puv_response
244
+
245
+ # Download button
246
+ st.download_button(
247
+ label="DESCARGAR PUV",
248
+ data=download_content,
249
+ file_name=f"propuestas_unicas_valor_{timestamp}.txt",
250
+ mime="text/plain"
251
+ )