JeCabrera commited on
Commit
50d1b2d
verified
1 Parent(s): f740823

Upload 23 files

Browse files
Files changed (2) hide show
  1. app.py +361 -361
  2. prompts/faq.txt +13 -2
app.py CHANGED
@@ -1,362 +1,362 @@
1
- from dotenv import load_dotenv
2
- import streamlit as st
3
- import os
4
- import google.generativeai as genai
5
- import datetime
6
- from streamlit import session_state as state
7
-
8
- # Cargar las variables de entorno
9
- load_dotenv()
10
-
11
- # Configurar la API de Google
12
- genai.configure(api_key=os.getenv("GOOGLE_API_KEY"))
13
-
14
- def initialize_model(temperature=1.0):
15
- return genai.GenerativeModel(
16
- model_name="gemini-2.0-flash",
17
- generation_config={"temperature": temperature}
18
- )
19
-
20
- def initialize_session_state():
21
- """Initialize all session state variables."""
22
- defaults = {
23
- 'sections': {
24
- 'content': {}, # Store generated content
25
- 'context': {}, # Store context for other sections
26
- 'metadata': {} # Store JSON metadata
27
- },
28
- 'inputs': {
29
- 'audience': '',
30
- 'product': '',
31
- 'offer': ''
32
- }
33
- }
34
-
35
- for var, default in defaults.items():
36
- if var not in st.session_state:
37
- st.session_state[var] = default
38
-
39
- initialize_session_state()
40
-
41
- def generate_content(prompt, temperature=1.0):
42
- model = initialize_model(temperature)
43
-
44
- response = model.generate_content(prompt)
45
- result = response.text
46
-
47
- try:
48
- import json
49
- import re
50
-
51
- json_pattern = r'```json\s*(.*?)\s*```|(\{[\s\S]*"character"[\s\S]*\})'
52
- json_match = re.search(json_pattern, result, re.DOTALL)
53
-
54
- if json_match:
55
- json_str = json_match.group(1) if json_match.group(1) else json_match.group(2)
56
-
57
- json_data = json.loads(json_str.strip())
58
-
59
- st.session_state.sections['metadata'] = json_data
60
-
61
- metadata_fields = ['character', 'pain_points', 'emotional_triggers', 'obstacles', 'failed_solutions']
62
- for field in metadata_fields:
63
- if field in json_data:
64
- st.session_state.sections['metadata'][field] = json_data[field]
65
-
66
- result = re.sub(json_pattern, '', result, flags=re.DOTALL).strip()
67
- except Exception as e:
68
- print(f"Error processing JSON metadata: {str(e)}")
69
-
70
- return result
71
-
72
- def display_generated_content(column, content, key_prefix, section_name="secci贸n"):
73
- """Display generated content with download buttons at top and bottom."""
74
- if not content:
75
- return
76
-
77
- clean_section_name = section_name.split(" (")[0].lower() if " (" in section_name else section_name.lower()
78
-
79
- timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
80
- filename = f"sales_page_{key_prefix.replace('_', '-')}_{timestamp}.txt"
81
-
82
- column.download_button(
83
- label=f"Descargar secci贸n de {clean_section_name} de la Sale Page",
84
- data=content,
85
- file_name=filename,
86
- mime="text/plain",
87
- key=f"{key_prefix}_top_download"
88
- )
89
-
90
- column.markdown("### Contenido generado:")
91
- column.markdown(content)
92
-
93
- column.download_button(
94
- label=f"Descargar secci贸n de {clean_section_name} de la Sale Page",
95
- data=content,
96
- file_name=filename,
97
- mime="text/plain",
98
- key=f"{key_prefix}_bottom_download"
99
- )
100
-
101
- def validate_inputs(audience, product):
102
- """Validate that required inputs are provided."""
103
- return audience.strip() != "" and product.strip() != ""
104
-
105
- st.set_page_config(layout="wide")
106
- st.title("Generador de P谩ginas de Ventas")
107
-
108
- # Load custom CSS from the styles folder
109
- def load_css(css_file):
110
- with open(css_file, 'r') as f:
111
- css = f.read()
112
- st.markdown(f'<style>{css}</style>', unsafe_allow_html=True)
113
-
114
- # Load the CSS file
115
- css_path = os.path.join(os.path.dirname(__file__), "styles", "styles.css")
116
- load_css(css_path)
117
-
118
- # Create two columns for layout with adjusted widths (40% left, 60% right)
119
- col1, col2 = st.columns([4, 6])
120
-
121
- with col1:
122
- st.subheader("Configuraci贸n")
123
-
124
- # Input fields
125
- sales_page_audience = st.text_input("P煤blico objetivo:",
126
- help="Describe a qui茅n va dirigida tu p谩gina de ventas")
127
-
128
- sales_page_product = st.text_input("Producto/Servicio:",
129
- help="Describe el producto o servicio que est谩s vendiendo")
130
-
131
- sales_page_offer = st.text_area("Oferta espec铆fica (opcional):",
132
- help="Detalles espec铆ficos de tu oferta, como precio, bonos, etc.")
133
-
134
- # Add to the section selection list
135
- sales_page_section = st.selectbox(
136
- "Secci贸n a generar:",
137
- [
138
- "Above the Fold (Encabezado)",
139
- "Problem (Problema)",
140
- "Solution & Benefits (Soluci贸n y Beneficios)",
141
- "Authority (Autoridad)",
142
- "Offer & Bonus (Oferta y Bonus)",
143
- "Social Proof (Prueba Social)",
144
- "Offer Summary (Resumen de Oferta)",
145
- "Guarantees (Garant铆as)",
146
- "FAQ (Preguntas Frecuentes)",
147
- "Closing (Cierre)"
148
- ]
149
- )
150
-
151
- sales_page_temperature = st.slider(
152
- "Creatividad:",
153
- min_value=0.0,
154
- max_value=1.0,
155
- value=0.7,
156
- step=0.1,
157
- help="Valores m谩s altos = m谩s creatividad, valores m谩s bajos = m谩s consistencia"
158
- )
159
-
160
- # Now create the submit button
161
- submit_sales_page = st.button("Generar Secci贸n", key="generate_sales_page")
162
-
163
- # First define all generator functions
164
- def load_prompt_template(filename):
165
- """Load a prompt template from the prompts directory."""
166
- if not filename:
167
- raise ValueError("Filename cannot be None")
168
-
169
- prompt_path = os.path.join(os.path.dirname(__file__), "prompts", filename)
170
- with open(prompt_path, "r", encoding="utf-8") as file:
171
- return file.read()
172
-
173
- def create_base_prompt(template_name, audience, product, offer=None, extra_params=None):
174
- """Create base prompt with context for all sections."""
175
- prompt_template = load_prompt_template(template_name)
176
- prompt = f"{prompt_template}\n\nAUDIENCE: {audience}\nPRODUCT/SERVICE: {product}"
177
-
178
- if offer:
179
- prompt += f"\nOFFER{'_DETAILS' if 'offer' in template_name else ''}: {offer}"
180
-
181
- if extra_params:
182
- for key, value in extra_params.items():
183
- prompt += f"\n{key}: {value}"
184
-
185
- return prompt
186
-
187
- def update_section_context(section_name, content):
188
- """Update the context for a section after it's generated."""
189
- section_key = normalize_section_key(section_name)
190
-
191
- # Store in content dictionary
192
- if 'content' not in st.session_state.sections:
193
- st.session_state.sections['content'] = {}
194
- st.session_state.sections['content'][section_key] = content
195
-
196
- # Store in context dictionary with timestamp
197
- if 'context' not in st.session_state.sections:
198
- st.session_state.sections['context'] = {}
199
-
200
- st.session_state.sections['context'][section_key] = {
201
- 'content': content,
202
- 'timestamp': datetime.datetime.now().isoformat()
203
- }
204
-
205
- def get_relevant_context(current_section):
206
- """Get relevant context based on current section"""
207
- context = {}
208
-
209
- section_key = normalize_section_key(current_section)
210
-
211
- if section_key == 'above_the_fold':
212
- return context
213
-
214
- specific_relationships = {
215
- 'problem': ['above_the_fold'],
216
- 'solution_&_benefits': ['problem'],
217
- 'authority': ['problem', 'solution_&_benefits'],
218
- 'offer_&_bonus': ['solution_&_benefits', 'problem'],
219
- 'social_proof': ['offer_&_bonus', 'solution_&_benefits'],
220
- 'offer_summary': ['offer_&_bonus', 'solution_&_benefits'],
221
- 'guarantees': ['offer_&_bonus', 'social_proof'],
222
- 'faq': ['offer_&_bonus', 'guarantees', 'problem'],
223
- 'closing': ['offer_&_bonus', 'guarantees', 'problem', 'solution_&_benefits']
224
- }
225
-
226
- section_order = [
227
- "above_the_fold",
228
- "problem",
229
- "solution_&_benefits",
230
- "authority",
231
- "offer_&_bonus",
232
- "social_proof",
233
- "offer_summary",
234
- "guarantees",
235
- "faq",
236
- "closing"
237
- ]
238
-
239
- # First, add specific relationships if they exist
240
- if section_key in specific_relationships:
241
- for rel_section in specific_relationships[section_key]:
242
- if rel_section in st.session_state.sections['context']:
243
- context[rel_section] = st.session_state.sections['context'][rel_section]['content']
244
-
245
- # Then, for any section after "above_the_fold", add previous sections as context
246
- if section_key in section_order:
247
- current_index = section_order.index(section_key)
248
- if current_index > 0:
249
- for prev_section in section_order[:current_index][-3:]:
250
- if prev_section in st.session_state.sections['context'] and prev_section not in context:
251
- context[prev_section] = st.session_state.sections['context'][prev_section]['content']
252
-
253
- return context
254
-
255
- # Funci贸n auxiliar para normalizar nombres de secciones
256
- def normalize_section_key(section_name):
257
- """Convierte nombres de secci贸n a formato de clave normalizado."""
258
- # Extraer solo la parte en ingl茅s antes del par茅ntesis
259
- if " (" in section_name:
260
- section_name = section_name.split(" (")[0]
261
- return section_name.replace(" ", "_").lower()
262
-
263
- def generate_section(section_name, audience, product, temperature=0.7, offer=None):
264
- """Base generator function for all sections."""
265
- template_map = {
266
- "above_the_fold": "above_the_fold.txt",
267
- "problem": "problem.txt",
268
- "solution_&_benefits": "solution_benefits.txt",
269
- "authority": "authority.txt",
270
- "offer_&_bonus": "offer_bonus.txt",
271
- "social_proof": "social_proof.txt",
272
- "offer_summary": "offer_summary.txt",
273
- "guarantees": "guarantees.txt",
274
- "faq": "faq.txt",
275
- "closing": "closing.txt"
276
- }
277
-
278
- section_key = normalize_section_key(section_name)
279
- template_name = template_map.get(section_key)
280
-
281
- # Verificaci贸n m谩s detallada para depuraci贸n
282
- if not template_name:
283
- # Mostrar todas las claves disponibles para ayudar en la depuraci贸n
284
- available_keys = ", ".join(template_map.keys())
285
- raise ValueError(f"No template found for section: '{section_name}' (normalized key: '{section_key}'). Available keys: {available_keys}")
286
-
287
- # Verificar que el archivo de plantilla existe
288
- prompt_path = os.path.join(os.path.dirname(__file__), "prompts", template_name)
289
- if not os.path.exists(prompt_path):
290
- raise FileNotFoundError(f"Template file not found: {prompt_path}")
291
-
292
- extra_params = {}
293
-
294
- # Add context for sections that need it
295
- context = get_relevant_context(section_name)
296
- if context:
297
- extra_params['CONTEXT'] = context
298
-
299
- # Special handling for specific sections
300
- if section_key == 'faq':
301
- extra_params['LANGUAGE'] = 'Spanish'
302
- elif section_key == 'closing':
303
- extra_params['ADDITIONAL_INSTRUCTIONS'] = """
304
- - Generate content directly in Spanish
305
- - Do not include labels like 'BINARY CHOICE', 'FINAL REMINDER', etc.
306
- - Do not include comments or observations in any language
307
- - Do not include technical notes or instructions
308
- - Write the closing text naturally and fluidly"""
309
-
310
- prompt = create_base_prompt(template_name, audience, product, offer, extra_params)
311
- content = generate_content(prompt, temperature)
312
-
313
- # Update context after generation
314
- update_section_context(section_name, content)
315
-
316
- return content
317
-
318
- section_functions = {
319
- section_name: lambda audience, product, temperature=0.7, offer=None, section=section_name: generate_section(section, audience, product, temperature, offer)
320
- for section_name in [
321
- "Above the Fold (Encabezado)",
322
- "Problem (Problema)",
323
- "Solution & Benefits (Soluci贸n y Beneficios)",
324
- "Authority (Autoridad)",
325
- "Offer & Bonus (Oferta y Bonus)",
326
- "Social Proof (Prueba Social)",
327
- "Offer Summary (Resumen de Oferta)",
328
- "Guarantees (Garant铆as)",
329
- "FAQ (Preguntas Frecuentes)",
330
- "Closing (Cierre)"
331
- ]
332
- }
333
-
334
- if submit_sales_page:
335
- if validate_inputs(sales_page_audience, sales_page_product):
336
- try:
337
- st.session_state.inputs.update({
338
- 'audience': sales_page_audience,
339
- 'product': sales_page_product,
340
- 'offer': sales_page_offer
341
- })
342
-
343
- with col2:
344
- with st.spinner("Generando secci贸n de p谩gina de ventas...", show_time=True):
345
- generator_func = section_functions[sales_page_section]
346
- generated_content = generator_func(
347
- audience=sales_page_audience,
348
- product=sales_page_product,
349
- temperature=sales_page_temperature,
350
- offer=sales_page_offer if sales_page_offer.strip() else None
351
- )
352
-
353
- display_generated_content(col2, generated_content, "sales_page_section", sales_page_section)
354
-
355
- except Exception as e:
356
- st.error(f"Error al generar la secci贸n: {str(e)}")
357
- else:
358
- st.warning("Por favor, completa los campos de p煤blico objetivo y producto/servicio.")
359
- else:
360
- section_key = normalize_section_key(sales_page_section)
361
- if section_key in st.session_state.sections['content']:
362
  display_generated_content(col2, st.session_state.sections['content'][section_key], "sales_page_section", sales_page_section)
 
1
+ from dotenv import load_dotenv
2
+ import streamlit as st
3
+ import os
4
+ import google.generativeai as genai
5
+ import datetime
6
+ from streamlit import session_state as state
7
+
8
+ # Cargar las variables de entorno
9
+ load_dotenv()
10
+
11
+ # Configurar la API de Google
12
+ genai.configure(api_key=os.getenv("GOOGLE_API_KEY"))
13
+
14
+ def initialize_model(temperature=1.0):
15
+ return genai.GenerativeModel(
16
+ model_name="gemini-2.0-flash",
17
+ generation_config={"temperature": temperature}
18
+ )
19
+
20
+ def initialize_session_state():
21
+ """Initialize all session state variables."""
22
+ defaults = {
23
+ 'sections': {
24
+ 'content': {}, # Store generated content
25
+ 'context': {}, # Store context for other sections
26
+ 'metadata': {} # Store JSON metadata
27
+ },
28
+ 'inputs': {
29
+ 'audience': '',
30
+ 'product': '',
31
+ 'offer': ''
32
+ }
33
+ }
34
+
35
+ for var, default in defaults.items():
36
+ if var not in st.session_state:
37
+ st.session_state[var] = default
38
+
39
+ initialize_session_state()
40
+
41
+ def generate_content(prompt, temperature=1.0):
42
+ model = initialize_model(temperature)
43
+
44
+ response = model.generate_content(prompt)
45
+ result = response.text
46
+
47
+ try:
48
+ import json
49
+ import re
50
+
51
+ json_pattern = r'```json\s*(.*?)\s*```|(\{[\s\S]*"character"[\s\S]*\})'
52
+ json_match = re.search(json_pattern, result, re.DOTALL)
53
+
54
+ if json_match:
55
+ json_str = json_match.group(1) if json_match.group(1) else json_match.group(2)
56
+
57
+ json_data = json.loads(json_str.strip())
58
+
59
+ st.session_state.sections['metadata'] = json_data
60
+
61
+ metadata_fields = ['character', 'pain_points', 'emotional_triggers', 'obstacles', 'failed_solutions']
62
+ for field in metadata_fields:
63
+ if field in json_data:
64
+ st.session_state.sections['metadata'][field] = json_data[field]
65
+
66
+ result = re.sub(json_pattern, '', result, flags=re.DOTALL).strip()
67
+ except Exception as e:
68
+ print(f"Error processing JSON metadata: {str(e)}")
69
+
70
+ return result
71
+
72
+ def display_generated_content(column, content, key_prefix, section_name="secci贸n"):
73
+ """Display generated content with download buttons at top and bottom."""
74
+ if not content:
75
+ return
76
+
77
+ clean_section_name = section_name.split(" (")[0].lower() if " (" in section_name else section_name.lower()
78
+
79
+ timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
80
+ filename = f"sales_page_{key_prefix.replace('_', '-')}_{timestamp}.txt"
81
+
82
+ column.download_button(
83
+ label=f"Descargar secci贸n de {clean_section_name} de la Sale Page",
84
+ data=content,
85
+ file_name=filename,
86
+ mime="text/plain",
87
+ key=f"{key_prefix}_top_download"
88
+ )
89
+
90
+ column.markdown("### Contenido generado:")
91
+ column.markdown(content)
92
+
93
+ column.download_button(
94
+ label=f"Descargar secci贸n de {clean_section_name} de la Sale Page",
95
+ data=content,
96
+ file_name=filename,
97
+ mime="text/plain",
98
+ key=f"{key_prefix}_bottom_download"
99
+ )
100
+
101
+ def validate_inputs(audience, product):
102
+ """Validate that required inputs are provided."""
103
+ return audience.strip() != "" and product.strip() != ""
104
+
105
+ st.set_page_config(layout="wide")
106
+ st.title("Generador de P谩ginas de Ventas")
107
+
108
+ # Load custom CSS from the styles folder
109
+ def load_css(css_file):
110
+ with open(css_file, 'r') as f:
111
+ css = f.read()
112
+ st.markdown(f'<style>{css}</style>', unsafe_allow_html=True)
113
+
114
+ # Load the CSS file
115
+ css_path = os.path.join(os.path.dirname(__file__), "styles", "styles.css")
116
+ load_css(css_path)
117
+
118
+ # Create two columns for layout with adjusted widths (40% left, 60% right)
119
+ col1, col2 = st.columns([4, 6])
120
+
121
+ with col1:
122
+ st.subheader("Configuraci贸n")
123
+
124
+ # Input fields
125
+ sales_page_audience = st.text_input("P煤blico objetivo:",
126
+ help="Describe a qui茅n va dirigida tu p谩gina de ventas")
127
+
128
+ sales_page_product = st.text_input("Producto/Servicio:",
129
+ help="Describe el producto o servicio que est谩s vendiendo")
130
+
131
+ sales_page_offer = st.text_area("Oferta espec铆fica (opcional):",
132
+ help="Detalles espec铆ficos de tu oferta, como precio, bonos, etc.")
133
+
134
+ # Add to the section selection list
135
+ sales_page_section = st.selectbox(
136
+ "Secci贸n a generar:",
137
+ [
138
+ "Above the Fold (Encabezado)",
139
+ "Problem (Problema)",
140
+ "Solution & Benefits (Soluci贸n y Beneficios)",
141
+ "Authority (Autoridad)",
142
+ "Offer & Bonus (Oferta y Bonus)",
143
+ "Social Proof (Prueba Social)",
144
+ "Offer Summary (Resumen de Oferta)",
145
+ "Guarantees (Garant铆as)",
146
+ "FAQ (Preguntas Frecuentes)",
147
+ "Closing (Cierre)"
148
+ ]
149
+ )
150
+
151
+ sales_page_temperature = st.slider(
152
+ "Creatividad:",
153
+ min_value=0.0,
154
+ max_value=1.0,
155
+ value=0.7,
156
+ step=0.1,
157
+ help="Valores m谩s altos = m谩s creatividad, valores m谩s bajos = m谩s consistencia"
158
+ )
159
+
160
+ # Now create the submit button
161
+ submit_sales_page = st.button("Generar Secci贸n", key="generate_sales_page")
162
+
163
+ # First define all generator functions
164
+ def load_prompt_template(filename):
165
+ """Load a prompt template from the prompts directory."""
166
+ if not filename:
167
+ raise ValueError("Filename cannot be None")
168
+
169
+ prompt_path = os.path.join(os.path.dirname(__file__), "prompts", filename)
170
+ with open(prompt_path, "r", encoding="utf-8") as file:
171
+ return file.read()
172
+
173
+ def create_base_prompt(template_name, audience, product, offer=None, extra_params=None):
174
+ """Create base prompt with context for all sections."""
175
+ prompt_template = load_prompt_template(template_name)
176
+ prompt = f"{prompt_template}\n\nAUDIENCE: {audience}\nPRODUCT/SERVICE: {product}"
177
+
178
+ if offer:
179
+ prompt += f"\nOFFER{'_DETAILS' if 'offer' in template_name else ''}: {offer}"
180
+
181
+ if extra_params:
182
+ for key, value in extra_params.items():
183
+ prompt += f"\n{key}: {value}"
184
+
185
+ return prompt
186
+
187
+ def update_section_context(section_name, content):
188
+ """Update the context for a section after it's generated."""
189
+ section_key = normalize_section_key(section_name)
190
+
191
+ # Store in content dictionary
192
+ if 'content' not in st.session_state.sections:
193
+ st.session_state.sections['content'] = {}
194
+ st.session_state.sections['content'][section_key] = content
195
+
196
+ # Store in context dictionary with timestamp
197
+ if 'context' not in st.session_state.sections:
198
+ st.session_state.sections['context'] = {}
199
+
200
+ st.session_state.sections['context'][section_key] = {
201
+ 'content': content,
202
+ 'timestamp': datetime.datetime.now().isoformat()
203
+ }
204
+
205
+ def get_relevant_context(current_section):
206
+ """Get relevant context based on current section"""
207
+ context = {}
208
+
209
+ section_key = normalize_section_key(current_section)
210
+
211
+ if section_key == 'above_the_fold':
212
+ return context
213
+
214
+ specific_relationships = {
215
+ 'problem': ['above_the_fold'],
216
+ 'solution_&_benefits': ['problem'],
217
+ 'authority': ['problem', 'solution_&_benefits'],
218
+ 'offer_&_bonus': ['solution_&_benefits', 'problem'],
219
+ 'social_proof': ['offer_&_bonus', 'solution_&_benefits'],
220
+ 'offer_summary': ['offer_&_bonus', 'solution_&_benefits'],
221
+ 'guarantees': ['offer_&_bonus', 'social_proof'],
222
+ 'faq': ['offer_&_bonus', 'guarantees', 'problem'],
223
+ 'closing': ['offer_&_bonus', 'guarantees', 'problem', 'solution_&_benefits']
224
+ }
225
+
226
+ section_order = [
227
+ "above_the_fold",
228
+ "problem",
229
+ "solution_&_benefits",
230
+ "authority",
231
+ "offer_&_bonus",
232
+ "social_proof",
233
+ "offer_summary",
234
+ "guarantees",
235
+ "faq",
236
+ "closing"
237
+ ]
238
+
239
+ # First, add specific relationships if they exist
240
+ if section_key in specific_relationships:
241
+ for rel_section in specific_relationships[section_key]:
242
+ if rel_section in st.session_state.sections['context']:
243
+ context[rel_section] = st.session_state.sections['context'][rel_section]['content']
244
+
245
+ # Then, for any section after "above_the_fold", add previous sections as context
246
+ if section_key in section_order:
247
+ current_index = section_order.index(section_key)
248
+ if current_index > 0:
249
+ for prev_section in section_order[:current_index][-3:]:
250
+ if prev_section in st.session_state.sections['context'] and prev_section not in context:
251
+ context[prev_section] = st.session_state.sections['context'][prev_section]['content']
252
+
253
+ return context
254
+
255
+ # Funci贸n auxiliar para normalizar nombres de secciones
256
+ def normalize_section_key(section_name):
257
+ """Convierte nombres de secci贸n a formato de clave normalizado."""
258
+ # Extraer solo la parte en ingl茅s antes del par茅ntesis
259
+ if " (" in section_name:
260
+ section_name = section_name.split(" (")[0]
261
+ return section_name.replace(" ", "_").lower()
262
+
263
+ def generate_section(section_name, audience, product, temperature=0.7, offer=None):
264
+ """Base generator function for all sections."""
265
+ template_map = {
266
+ "above_the_fold": "above_the_fold.txt",
267
+ "problem": "problem.txt",
268
+ "solution_&_benefits": "solution_benefits.txt",
269
+ "authority": "authority.txt",
270
+ "offer_&_bonus": "offer_bonus.txt",
271
+ "social_proof": "social_proof.txt",
272
+ "offer_summary": "offer_summary.txt",
273
+ "guarantees": "guarantees.txt",
274
+ "faq": "faq.txt",
275
+ "closing": "closing.txt"
276
+ }
277
+
278
+ section_key = normalize_section_key(section_name)
279
+ template_name = template_map.get(section_key)
280
+
281
+ # Verificaci贸n m谩s detallada para depuraci贸n
282
+ if not template_name:
283
+ # Mostrar todas las claves disponibles para ayudar en la depuraci贸n
284
+ available_keys = ", ".join(template_map.keys())
285
+ raise ValueError(f"No template found for section: '{section_name}' (normalized key: '{section_key}'). Available keys: {available_keys}")
286
+
287
+ # Verificar que el archivo de plantilla existe
288
+ prompt_path = os.path.join(os.path.dirname(__file__), "prompts", template_name)
289
+ if not os.path.exists(prompt_path):
290
+ raise FileNotFoundError(f"Template file not found: {prompt_path}")
291
+
292
+ extra_params = {}
293
+
294
+ # Add context for sections that need it
295
+ context = get_relevant_context(section_name)
296
+ if context:
297
+ extra_params['CONTEXT'] = context
298
+
299
+ # Special handling for specific sections
300
+ if section_key == 'faq':
301
+ extra_params['LANGUAGE'] = 'Spanish'
302
+ elif section_key == 'closing':
303
+ extra_params['ADDITIONAL_INSTRUCTIONS'] = """
304
+ - Generate content directly in Spanish
305
+ - Do not include labels like 'BINARY CHOICE', 'FINAL REMINDER', etc.
306
+ - Do not include comments or observations in any language
307
+ - Do not include technical notes or instructions
308
+ - Write the closing text naturally and fluidly"""
309
+
310
+ prompt = create_base_prompt(template_name, audience, product, offer, extra_params)
311
+ content = generate_content(prompt, temperature)
312
+
313
+ # Update context after generation
314
+ update_section_context(section_name, content)
315
+
316
+ return content
317
+
318
+ section_functions = {
319
+ section_name: lambda audience, product, temperature=0.7, offer=None, section=section_name: generate_section(section, audience, product, temperature, offer)
320
+ for section_name in [
321
+ "Above the Fold (Encabezado)",
322
+ "Problem (Problema)",
323
+ "Solution & Benefits (Soluci贸n y Beneficios)",
324
+ "Authority (Autoridad)",
325
+ "Offer & Bonus (Oferta y Bonus)",
326
+ "Social Proof (Prueba Social)",
327
+ "Offer Summary (Resumen de Oferta)",
328
+ "Guarantees (Garant铆as)",
329
+ "FAQ (Preguntas Frecuentes)",
330
+ "Closing (Cierre)"
331
+ ]
332
+ }
333
+
334
+ if submit_sales_page:
335
+ if validate_inputs(sales_page_audience, sales_page_product):
336
+ try:
337
+ st.session_state.inputs.update({
338
+ 'audience': sales_page_audience,
339
+ 'product': sales_page_product,
340
+ 'offer': sales_page_offer
341
+ })
342
+
343
+ with col2:
344
+ with st.spinner("Generando secci贸n de p谩gina de ventas...", show_time=True):
345
+ generator_func = section_functions[sales_page_section]
346
+ generated_content = generator_func(
347
+ audience=sales_page_audience,
348
+ product=sales_page_product,
349
+ temperature=sales_page_temperature,
350
+ offer=sales_page_offer if sales_page_offer.strip() else None
351
+ )
352
+
353
+ display_generated_content(col2, generated_content, "sales_page_section", sales_page_section)
354
+
355
+ except Exception as e:
356
+ st.error(f"Error al generar la secci贸n: {str(e)}")
357
+ else:
358
+ st.warning("Por favor, completa los campos de p煤blico objetivo y producto/servicio.")
359
+ else:
360
+ section_key = normalize_section_key(sales_page_section)
361
+ if section_key in st.session_state.sections['content']:
362
  display_generated_content(col2, st.session_state.sections['content'][section_key], "sales_page_section", sales_page_section)
prompts/faq.txt CHANGED
@@ -21,7 +21,7 @@ THE EXPERT TEAM:
21
  - Creates persona-specific response strategies
22
 
23
  YOUR TASK:
24
- Create a comprehensive FAQ section with 10 questions that addresses four key belief categories:
25
 
26
  1. SELF-LIMITING BELIEFS:
27
  - Questions about personal capability
@@ -47,6 +47,17 @@ Create a comprehensive FAQ section with 10 questions that addresses four key bel
47
  - Credibility concerns
48
  - Support and guidance doubts
49
 
 
 
 
 
 
 
 
 
 
 
 
50
  EJEMPLO DE PREGUNTAS Y RESPUESTAS:
51
 
52
  Si tienes alguna duda solo lee lo siguiente, aqu铆 encontrar谩s la respuesta:
@@ -95,7 +106,7 @@ R: Es muy simple. Solo da clic en el bot贸n azul de abajo, te llevar谩 a nuestra
95
  "methodology",
96
  "authority"
97
  ],
98
- "total_questions": 6,
99
  "includes_cta": true,
100
  "support_contact": "email"
101
  }
 
21
  - Creates persona-specific response strategies
22
 
23
  YOUR TASK:
24
+ Create a comprehensive FAQ section with 10 questions that addresses the following key belief categories:
25
 
26
  1. SELF-LIMITING BELIEFS:
27
  - Questions about personal capability
 
47
  - Credibility concerns
48
  - Support and guidance doubts
49
 
50
+ IMPORTANT INSTRUCTIONS:
51
+ - Generate content directly in Spanish
52
+ - Do not include labels like "SELF-LIMITING", "OBJECTION", etc.
53
+ - Do not include comments or observations in English
54
+ - Do not include technical notes or instructions
55
+ - Do not include question classifications
56
+ - Write questions and answers naturally and fluidly
57
+ - Start directly with the title "Frequently Asked Questions" or similar
58
+ - Follow exactly the format of the example, with "Q:" for questions and "A:" for answers
59
+ - Do not include any introductory text in English
60
+
61
  EJEMPLO DE PREGUNTAS Y RESPUESTAS:
62
 
63
  Si tienes alguna duda solo lee lo siguiente, aqu铆 encontrar谩s la respuesta:
 
106
  "methodology",
107
  "authority"
108
  ],
109
+ "total_questions": 10,
110
  "includes_cta": true,
111
  "support_contact": "email"
112
  }