JeCabrera commited on
Commit
d08aa04
·
verified ·
1 Parent(s): 7193f1a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +287 -457
app.py CHANGED
@@ -1,467 +1,297 @@
1
- offer_system_prompt = """You are a world-class expert copywriter, experienced in creating compelling offers that connect emotionally with the target audience.
2
-
3
- OBJECTIVE:
4
- - Generate a convincing offer in Spanish
5
- - Connect emotionally with the audience
6
- - Address real desires, problems, and motivations
7
- - Maintain natural and conversational language
8
-
9
- CRITICAL OUTPUT RULES:
10
- - Output ONLY the offer itself with NO introductory text, explanations, or additional commentary
11
- - Start directly with the attention hook or opening phrase
12
- - The entire response should be ONLY the offer itself following the formula structure
13
- - Do not include phrases like "Aquí tienes una oferta convincente" or "Esta es tu oferta"
14
- """
15
-
16
- def extract_product_name(product_name_input):
17
- """
18
- Extracts the actual product name from user input, especially when it's enclosed in quotes.
19
-
20
- Args:
21
- product_name_input: The raw input string containing the product name
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
 
23
- Returns:
24
- str: The extracted product name, or empty string if generic
25
- """
26
- import re
27
-
28
- # If input is empty or None, return empty string
29
- if not product_name_input or product_name_input.strip() == "":
30
- return ""
31
-
32
- # Check if there's a name in quotes
33
- quote_pattern = r'"([^"]+)"'
34
- matches = re.findall(quote_pattern, product_name_input)
35
-
36
- if matches:
37
- # Return the first quoted string found
38
- return matches[0]
39
-
40
- # If no quotes but contains "llamado" or similar phrases, extract what follows
41
- called_patterns = [
42
- r'llamado\s+(.+?)(?:\s+que|\s+con|\s+para|\.$|$)',
43
- r'titulado\s+(.+?)(?:\s+que|\s+con|\s+para|\.$|$)',
44
- r'denominado\s+(.+?)(?:\s+que|\s+con|\s+para|\.$|$)',
45
- r'nombrado\s+(.+?)(?:\s+que|\s+con|\s+para|\.$|$)'
46
- ]
47
-
48
- for pattern in called_patterns:
49
- matches = re.search(pattern, product_name_input, re.IGNORECASE)
50
- if matches:
51
- extracted = matches.group(1).strip()
52
- # If the extracted text has quotes, remove them
53
- if extracted.startswith('"') and extracted.endswith('"'):
54
- extracted = extracted[1:-1]
55
- return extracted
56
-
57
- # Check if the input is generic (common course/product types without specific names)
58
- generic_patterns = [
59
- r'^(curso|taller|programa|webinar|entrenamiento|sistema|método|servicio|producto|aplicación|comunidad|masterclass)(\s+de\s+.+)?$',
60
- r'^(un|el|mi|nuestro)\s+(curso|taller|programa|webinar|entrenamiento|sistema|método|servicio|producto|aplicación|comunidad|masterclass)(\s+de\s+.+)?$'
61
- ]
62
-
63
- for pattern in generic_patterns:
64
- if re.match(pattern, product_name_input.lower(), re.IGNORECASE):
65
- # This is a generic description, return empty string to trigger creative name generation
66
- return ""
67
-
68
- # If no patterns match, return the original input
69
- return product_name_input.strip()
70
-
71
-
72
- def create_offer_instruction(avatar_description, product_name, selected_formula_name):
73
- """
74
- Creates instructions for generating an offer based on the selected formula.
75
-
76
- Args:
77
- avatar_description: Description of the target audience
78
- product_name: Name of the product or service
79
- selected_formula_name: Name of the formula to use ("Fórmula Sueño-Obstáculo" or "Oferta Dorada")
80
 
81
- Returns:
82
- str: Complete instruction for generating the offer
83
- """
84
- # Extract the actual product name if it's in quotes or after "llamado"
85
- extracted_name = extract_product_name(product_name)
86
-
87
- # Get the selected formula
88
- selected_formula = offer_formulas[selected_formula_name]
89
-
90
- # Add specific instructions for each formula
91
- additional_instructions = ""
92
- if selected_formula_name == "Fórmula Sueño-Obstáculo":
93
- additional_instructions = """
94
- SPECIFIC INSTRUCTIONS FOR THIS FORMULA:
95
- 1. PRODUCT/SERVICE NAME HANDLING:
96
- - CRITICAL: If a product name is provided in quotes or after words like "llamado", "titulado", etc.,
97
- YOU MUST USE THAT EXACT NAME. This is non-negotiable.
98
- - The extracted product name is: "{extracted_name}"
99
- - If this extracted name is not empty, use it EXACTLY as provided with no modifications
100
- - Only create a new name if the extracted name is empty or contains generic placeholders
101
-
102
- 2. Analyze ALL available information:
103
- - Product/service name (use the extracted name provided above)
104
- - Target audience description (avatar_description)
105
- - Content from uploaded files (if any)
106
-
107
- 3. Determine the most appropriate type (curso, webinar, entrenamiento, etc.) based on:
108
- - Any type mentioned in product_name
109
- - The nature of the solution described in avatar_description
110
- - The most suitable format for the target audience's needs
111
-
112
- 4. Create a comprehensive offer by combining:
113
- - The appropriate type (determined in step 3)
114
- - The EXACT product name as extracted (if provided)
115
- - A compelling dream based on avatar_description
116
- - A relevant obstacle based on avatar_description
117
-
118
- 5. The dream should be ambitious but believable, incorporating:
119
- - Target audience desires from avatar_description
120
- - Explicit goals mentioned in uploaded content (if any)
121
-
122
- 6. The obstacle should reflect:
123
- - Real problems mentioned in avatar_description
124
- - Challenges that would normally prevent achieving the dream
125
-
126
- 7. IMPORTANT: Vary the way you start the phrase. Instead of always using "Se trata de un...", use different openings such as:
127
- - "Presentamos un..."
128
- - "Te ofrecemos un..."
129
- - "Descubre nuestro..."
130
- - "Conoce el..."
131
- - "Hemos creado un..."
132
- - "Imagina tener acceso a un..."
133
- - "Por fin existe un..."
134
- - "Ahora puedes acceder a un..."
135
- - "Tenemos para ti un..."
136
- - "Disfruta de un..."
137
- """.format(extracted_name=extracted_name)
138
-
139
- elif selected_formula_name == "Oferta Dorada":
140
- additional_instructions = """
141
- SPECIFIC INSTRUCTIONS FOR THIS FORMULA:
142
- 1. PRODUCT/SERVICE NAME HANDLING:
143
- - CRITICAL: If a product name is provided in quotes or after words like "llamado", "titulado", etc.,
144
- YOU MUST USE THAT EXACT NAME. This is non-negotiable.
145
- - The extracted product name is: "{extracted_name}"
146
- - If this extracted name is not empty, use it EXACTLY as provided with no modifications
147
- - Only create a new name if the extracted name is empty or contains generic placeholders
148
-
149
- 2. FOLLOW THE 6-STEP PROCESS FOR CREATING AN IRRESISTIBLE OFFER:
150
-
151
- STEP 1: IDENTIFY THE MAIN PROBLEM (ATTENTION HOOK)
152
- - Analyze the avatar_description DEEPLY to understand their specific pain points
153
- - Create a powerful hook that directly addresses their biggest frustration or anxiety
154
- - Use statements that make them think "this person understands my situation exactly"
155
- - Focus on the emotional impact of their problem, not just the practical aspects
156
- - Use statistics, shocking revelations, direct statements or questions
157
- - The hook must create an immediate emotional connection
158
- - IMPORTANT: Vary your opening approach using different formats:
159
- * Direct question formats (use variety, not just "¿Estás cansado de...?"):
160
- - Problem-focused: "¿Por qué sigues luchando con...?"
161
- - Contrast: "¿Qué pasaría si pudieras...?"
162
- - Challenge: "¿Te has preguntado por qué no consigues...?"
163
- - Future-oriented: "¿Imaginas cómo sería tu vida si...?"
164
- - Reflection: "¿Cuántas veces has intentado...?"
165
- - Provocative: "¿Y si te dijera que el problema no es...?"
166
- - Empathetic: "¿También sientes que...?"
167
- - Curiosity: "¿Sabías que el 78% de las personas...?"
168
- * Shocking statistic: "El 83% de las personas..."
169
- * Bold statement: "La mayoría de métodos para..."
170
- * Empathetic observation: "Sé lo frustrante que..."
171
- * Challenge: "Imagina poder..."
172
- * Contrast: "Mientras otros..."
173
- * Revelation: "Lo que nadie te dice sobre..."
174
- * Story opener: "Hace unos años, yo también..."
175
- * Avoid always starting with "Si [problema]..." - use this format only 20% of the time
176
-
177
- STEP 2: CRAFT A QUANTIFIABLE VALUE PROMISE
178
- - Write a promise COMPLETELY IN CAPITAL LETTERS that includes:
179
- * Concrete numbers (money, time, results)
180
- * Powerful action verbs (EARN, MULTIPLY, ACHIEVE, MASTER)
181
- * Specific timeframes (EN 30 DÍAS, EN SOLO 2 SEMANAS)
182
- * Clear effort indicators (CON SOLO 15 MINUTOS DIARIOS)
183
- - Follow this structure: CÓMO [LOGRAR RESULTADO DESEADO] SIN [OBJECIÓN O CREENCIA LIMITANTE]
184
- - NEVER use exclamation marks (!) in this section
185
- - Make the promise both ambitious and believable
186
- - AVOID GENERIC PHRASES like "al otro nivel", "en tiempo récord", "como nunca antes", "revolucionario"
187
- - Instead, use SPECIFIC, MEASURABLE language that clearly states the exact benefit
188
-
189
- STEP 3: DEMONSTRATE TRUST AND AUTHORITY
190
- - Include elements that prove your system works:
191
- * Personal results ("Así como he vendido más de $250,000 USD")
192
- * Client results ("Mis clientes han vendido más de $5,000,000")
193
- * Social proof (testimonials, case studies)
194
- - Establish credibility through specific numbers and verifiable claims
195
- - Connect your authority directly to the promised result
196
-
197
- STEP 4: REDUCE DELIVERY TIME
198
- - Clearly state how quickly they will see results
199
- - Make the timeframe specific and believable
200
- - Emphasize speed without sacrificing quality
201
- - Use phrases like "en solo X días" or "desde la primera semana"
202
- - IMPORTANT: This refers to when they'll see RESULTS, not how long they need to work
203
- - Examples: "verás resultados en 30 días", "transformación completa en 8 semanas"
204
-
205
- STEP 5: MINIMIZE CLIENT EFFORT
206
- - Address the fear of complicated processes
207
- - CLEARLY specify the exact effort required from the client:
208
- * Time commitment: "con solo 15 minutos al día"
209
- * Frequency: "practicando 3 veces por semana"
210
- * Complexity: "siguiendo 5 pasos sencillos"
211
- * Prerequisites: "sin necesidad de experiencia previa"
212
- - Make the implementation process seem accessible and straightforward
213
- - Emphasize the low effort-to-results ratio
214
- - Examples: "dedicando solo 20 minutos diarios", "con 3 ejercicios simples"
215
-
216
- STEP 6: COMBINE ALL ELEMENTS INTO A COHESIVE OFFER
217
- - Ensure all elements address the SAME core problem
218
- - Create a LOGICAL PROGRESSION from problem to solution to implementation
219
- - Maintain thematic consistency throughout the entire offer
220
- - Use one of the 5 structure formats for the final benefit statement
221
- - Be SPECIFIC and CONCRETE - avoid generic superlatives and clichés
222
- - Use PRECISE language that creates a clear mental image
223
- - BANNED PHRASES: "al otro nivel", "en tiempo récord", "como nunca antes",
224
- "revolucionario", "increíble", "asombroso", "el mejor", "único"
225
-
226
- 3. FINAL STRUCTURE FORMAT:
227
- Choose one of these more concise formats for the benefit statement:
228
- 1. "[Feature] para [Benefit] + [prueba social/autoridad] en [tiempo específico]."
229
- 2. "Con [Feature] lograrás [Benefit] + [prueba social/autoridad] en [tiempo específico]."
230
- 3. "Gracias a [Feature] conseguirás [Benefit] + [prueba social/autoridad] en [tiempo específico]."
231
- 4. "Mediante [Feature] alcanzarás [Benefit] + [prueba social/autoridad] en [tiempo específico]."
232
- 5. "Usando [Feature] obtendrás [Benefit] + [prueba social/autoridad] en [tiempo específico]."
233
-
234
- IMPORTANT:
235
- - Keep this section under 30 words when possible
236
- - Focus on ONE primary benefit rather than multiple
237
- - Include ONE specific proof element (number, statistic, or result)
238
- - Specify exact timeframe (días, semanas, meses)
239
- - Eliminate redundant phrases and filler words
240
- - Use PRECISE language instead of vague superlatives
241
- - Be SPECIFIC about results (e.g., "aumentarás ventas un 27%" instead of "llevarás tu negocio al siguiente nivel")
242
- """.format(extracted_name=extracted_name)
243
-
244
- # Create the instruction using the system prompt at the beginning
245
- instruction = f"""{offer_system_prompt}
246
-
247
- FORMULA TO USE:
248
- {selected_formula["description"]}
249
-
250
- {additional_instructions}
251
-
252
- PRODUCT/SERVICE:
253
- {product_name}
254
-
255
- TARGET AUDIENCE:
256
- {avatar_description}
257
-
258
- Create a compelling offer following the formula structure exactly.
259
- """
260
-
261
- # Add examples if available
262
- if selected_formula.get("examples") and len(selected_formula["examples"]) > 0:
263
- examples_text = "\n\n".join([f"Example {i+1}:\n{example}" for i, example in enumerate(selected_formula["examples"][:3])])
264
- instruction += f"\n\nGet inspired by these examples:\n{examples_text}"
265
-
266
- return instruction
267
-
268
- def generate_complete_offer(avatar_description, product_name, selected_formula_name, include_bonuses=True):
269
- """
270
- Generates a complete offer including the main offer and optional bonuses.
271
-
272
- Args:
273
- avatar_description: Description of the target audience
274
- product_name: Name of the product or service
275
- selected_formula_name: Name of the formula to use
276
- include_bonuses: Whether to include bonuses in the offer
277
 
278
- Returns:
279
- dict: Instructions for generating the complete offer
280
- """
281
- # Create main offer instruction
282
- main_offer_instruction = create_offer_instruction(avatar_description, product_name, selected_formula_name)
283
-
284
- # Create bonus instruction if requested
285
- bonus_instruction = None
286
- if include_bonuses:
287
- # Import the bonus generator from the new module
288
- from bonuses.generator import create_bonus_instruction
289
- bonus_instruction = create_bonus_instruction(avatar_description, product_name, selected_formula_name)
290
-
291
- return {
292
- "main_offer_instruction": main_offer_instruction,
293
- "bonus_instruction": bonus_instruction
294
- }
295
-
296
- # The rest of your offer_formulas dictionary remains unchanged
297
- offer_formulas = {
298
- "Oferta Dorada": {
299
- "description": """
300
- Formula: [Attention Hook + QUANTIFIABLE PROMISE IN ALL CAPS + Benefit + Authority + Time or Effort]
301
-
302
- This formula is designed to speak directly to the avatar, capturing their attention immediately, reflecting their current situation, and showing the transformation they desire.
303
-
304
- ### **How to apply it?**
305
-
306
- #### 1 **Attention Hook**
307
- The first step is to capture the avatar's attention with a powerful hook that can be a shocking revelation, an unexpected question, or a dramatic fact. IMPORTANT: CUSTOMIZE THE HOOK BASED ON THE AVATAR AND THEIR SPECIFIC PROBLEMS. Don't use generic examples, but adapt them to the client's situation.
308
-
309
- Analyze first:
310
- - What is the avatar's biggest pain or frustration?
311
- - What are they trying to achieve without success?
312
- - What limiting beliefs do they have?
313
-
314
- ---
315
-
316
- #### 2 **QUANTIFIABLE PROMISE IN ALL CAPS**
317
- This is the most important part. You must create a specific, quantifiable promise written COMPLETELY IN CAPITAL LETTERS that immediately captures attention. It must include:
318
- - Concrete numbers (money, time, results)
319
- - Powerful action verbs (EARN, MULTIPLY, ACHIEVE, MASTER)
320
- - The specific result they will obtain
321
- - Optionally, the time or effort required
322
- - IMPORTANT: DO NOT USE EXCLAMATION MARKS (!) IN THIS SECTION UNDER ANY CIRCUMSTANCES
323
-
324
- **Incorrect example:**
325
- "Improve your sales with our system." (Vague, no numbers, no impact).
326
- "¡MULTIPLY YOUR SALES IN RECORD TIME!" (Uses exclamation marks, NEVER use them).
327
-
328
- **Correct example:**
329
- "FACTURA MAS DE $1.000 USD USANDO 15 EMAILS ESCRITOS EN 15 MINUTOS CADA UNO" (Specific, quantifiable, impactful).
330
- "MULTIPLICA POR 3 TUS INTERACCIONES EN REDES SOCIALES EN SOLO 2 SEMANAS" (Clear, measurable, with defined time).
331
-
332
- ---
333
-
334
- #### 3 **Benefit + Authority + Time or Effort**
335
- In this part, we explain the result they will obtain, supported by an authority factor (proven method, studies, experience, validations) and establishing a time frame or necessary effort to achieve it.
336
-
337
- **Structure Formats:**
338
- 1. "[Feature] para que puedas [Benefit] con lo que [Meaning]"
339
- 2. "Con [Feature] podrás [Benefit] permitiéndote [Meaning]"
340
- 3. "Gracias a [Feature] lograrás [Benefit] haciendo que [Meaning]"
341
- 4. "Mediante [Feature] conseguirás [Benefit] lo que significa [Meaning]"
342
- 5. "Usando [Feature] alcanzarás [Benefit] transformando [Meaning]"
343
-
344
- **Incorrect example:**
345
- "Grow your business with our strategy." (Doesn't say how long it will take or how reliable the strategy is).
346
-
347
- **Correct examples:**
348
- "El Sistema de emails persuasivos para que puedas convertir lectores en clientes con lo que multiplicarás tus ventas en solo 30 días."
349
- "Con nuestra metodología de copywriting podrás crear ofertas irresistibles permitiéndote aumentar tu tasa de conversión en un 200% con solo 15 minutos al día."
350
- "Gracias a nuestro framework de contenido lograrás posicionarte como autoridad haciendo que tu audiencia te busque a ti en lugar de a tu competencia."
351
- "Mediante nuestro sistema de automatización conseguirás generar ventas mientras duermes lo que significa libertad financiera real en menos de 90 días."
352
- "Usando nuestra estrategia de redes sociales alcanzarás 10.000 seguidores cualificados transformando tu presencia digital en una máquina de generación de leads."
353
-
354
- ---
355
-
356
- ### **Fixed structure:**
357
- "[Varied Attention Hook]
358
-
359
- [QUANTIFIABLE PROMISE IN ALL CAPS]
360
-
361
- [Choose one of the 5 structure formats for Benefit + Authority + Time or Effort]"
362
- """,
363
- "examples": [
364
- # Example 1 - Question format (updated with more variety)
365
- """¿Por qué sigues perdiendo oportunidades de venta a pesar de tener prospectos interesados?
366
-
367
- DESCUBRE CÓMO VENDER CON UNA SOLA LLAMADA PRODUCTOS DE MÁS DE $1,000 USD SIN MANIPULAR, MENTIR O FORZAR LA VENTA.
368
-
369
- Con nuestro proceso de venta persuasiva lograrás convertir objeciones en ventas, como ya han hecho más de 500 emprendedores en menos de 30 días.""",
370
-
371
- # Example 2 - Statistic format
372
- """El 78% de los emprendedores luchan cada mes para llegar a fin de mes, ¿eres uno de ellos?
373
-
374
- MULTIPLICA TUS INGRESOS POR 3 EN LOS PRÓXIMOS 90 DÍAS SIN TRABAJAR MÁS HORAS NI CONTRATAR PERSONAL ADICIONAL.
375
-
376
- Mediante nuestro sistema de optimización de negocios alcanzarás la rentabilidad que 327 emprendedores ya disfrutan en menos de un trimestre.""",
377
-
378
- # Example 3 - Bold statement format with clear time/effort distinction
379
- """La mayoría de dietas fallan porque atacan el síntoma y no la causa real del sobrepeso.
380
-
381
- PIERDE ENTRE 5 Y 8 KILOS EN 30 DÍAS SIN DIETAS RESTRICTIVAS, SIN PASAR HAMBRE Y SIN EFECTO REBOTE.
382
-
383
- Gracias a nuestro método de reprogramación metabólica activarás tu quema natural de grasa, avalado por estudios clínicos con 94% de efectividad. Verás los primeros resultados en solo 7 días, dedicando apenas 15 minutos diarios a los ejercicios metabólicos.""",
384
-
385
- # Example 4 - Contrast format
386
- """Mientras otros influencers consiguen miles de seguidores cada semana, tú sigues creando contenido que nadie ve.
387
-
388
- CONSIGUE 100 NUEVOS SEGUIDORES CUALIFICADOS POR SEMANA Y CONVIERTE EL 10% EN CLIENTES PAGANDO CON SOLO 3 PUBLICACIONES SEMANALES.
389
-
390
- Usando nuestra estrategia de contenido de alto impacto transformarás tu presencia en redes en un canal de ventas automático en menos de 30 días.""",
391
-
392
- # Example 5 - Empathetic format
393
- """Sé lo frustrante que es despertarse sin energía día tras día, sintiendo que nunca hay suficientes horas.
394
-
395
- AUMENTA TU ENERGÍA UN 65% Y RECUPERA 2 HORAS PRODUCTIVAS AL DÍA CON SOLO 15 MINUTOS DE RUTINA MATUTINA.
396
 
397
- El Sistema de activación bioenergética optimizará tu rendimiento físico y mental desde la primera semana, usado por los CEOs más exitosos del mundo."""
398
- ]
399
- },
400
- "Fórmula Sueño-Obstáculo": {
401
- "description": """
402
- Formula: [Type + Name + Dream + Obstacle]
403
-
404
- This formula connects directly with the client's desires and concerns:
405
-
406
- 1. Type: The type of solution (training, product, or service)
407
- 2. Name: The name of your solution
408
- 3. Dream: The big dream or result that the client wants to achieve
409
- 4. Obstacle: The obstacle that would normally prevent achieving that dream
410
-
411
- **Suggested solution types:**
412
- - Online course
413
- - Webinar
414
- - Training
415
- - Program
416
- - Workshop
417
- - Mentorship
418
- - Consulting
419
- - Membership
420
- - System
421
- - Method
422
- - Service
423
- - Product
424
- - Application
425
- - Community
426
- - Masterclass
427
-
428
- **Suggested opening variations:**
429
- - "Se trata de un..."
430
- - "Presentamos un..."
431
- - "Te ofrecemos un..."
432
- - "Descubre nuestro..."
433
- - "Conoce el..."
434
- - "Hemos creado un..."
435
- - "Imagina tener acceso a un..."
436
- - "Por fin existe un..."
437
- - "Ahora puedes acceder a un..."
438
- - "Tenemos para ti un..."
439
- - "Disfruta de un..."
440
-
441
- **Structure Format (Classic example):**
442
- "Se trata de un (training, product or service) llamado ("name of your solution") que te va a permitir (big dream) aún y cuando (big obstacle)"
443
- """,
444
- "examples": [
445
- # Example 1 - Sales Training
446
- """Se trata de mi exclusivo entrenamiento llamado "Venta Express 3.0" con el que te convertirás en todo un Rockstar de las ventas con el que conectarás con tus clientes para inspirarlos al cierre de una forma fácil y divertida aún y cuando sea la primera vez que escuchen de ti.""",
447
 
448
- # Example 2 - Fitness Program
449
- """Presentamos un programa de transformación física llamado "Metabolismo Activado" que te permitirá perder hasta 10 kilos en 8 semanas aún y cuando hayas intentado todas las dietas sin éxito.""",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
450
 
451
- # Example 3 - Digital Marketing
452
- """Descubre nuestro sistema de marketing digital llamado "Tráfico Convertidor" que te ayudará a multiplicar tus ventas online sin necesidad de gastar fortunas en publicidad aún y cuando no tengas experiencia previa en marketing.""",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
453
 
454
- # Example 4 - Personal Finance
455
- """Tenemos para ti un método financiero llamado "Libertad Financiera Acelerada" que te permitirá generar ingresos pasivos y construir patrimonio aún y cuando partas desde cero o tengas deudas actualmente.""",
 
 
 
 
 
 
 
 
456
 
457
- # Example 5 - Language Learning
458
- """Imagina tener acceso a un curso de idiomas llamado "Inglés Sin Barreras Pro" con el que dominarás el inglés conversacional en solo 90 días aún y cuando hayas fracasado con métodos tradicionales en el pasado.""",
 
 
 
 
 
 
 
 
459
 
460
- # Example 6 - Productivity
461
- """Hemos creado un workshop intensivo llamado "Productividad Imparable" que te enseñará a duplicar tus resultados trabajando menos horas aún y cuando tengas una agenda completamente saturada.""",
 
 
 
 
462
 
463
- # Example 7 - Relationships
464
- """Por fin existe un programa de coaching llamado "Conexiones Profundas" que te ayudará a encontrar y mantener relaciones saludables y satisfactorias aún y cuando hayas tenido experiencias dolorosas en el pasado."""
465
- ]
466
- }
467
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import google.generativeai as genai
3
+ import os
4
+ import time
5
+ from dotenv import load_dotenv
6
+ from styles import get_custom_css, get_response_html_wrapper
7
+ from formulas import offer_formulas
8
+ import PyPDF2
9
+ import docx
10
+ from PIL import Image
11
+ import io
12
+
13
+ # Import the bullet generator
14
+ from bullets.generator import create_bullet_instruction
15
+ # Import the bonus generator
16
+ from bonuses.generator import create_bonus_instruction
17
+
18
+ # Set page to wide mode to use full width
19
+ st.set_page_config(layout="wide")
20
+
21
+ # Load environment variables
22
+ load_dotenv()
23
+
24
+ # Configure Google Gemini API
25
+ genai.configure(api_key=os.getenv('GOOGLE_API_KEY'))
26
+ model = genai.GenerativeModel('gemini-2.0-flash')
27
+
28
+ # Import the create_offer_instruction function from formulas
29
+ from formulas import create_offer_instruction, offer_formulas
30
+
31
+ # Initialize session state variables if they don't exist
32
+ if 'submitted' not in st.session_state:
33
+ st.session_state.submitted = False
34
+ if 'offer_result' not in st.session_state:
35
+ st.session_state.offer_result = ""
36
+ if 'generated' not in st.session_state:
37
+ st.session_state.generated = False
38
+
39
+ # Hide Streamlit menu and footer
40
+ st.markdown("""
41
+ <style>
42
+ #MainMenu {visibility: hidden;}
43
+ footer {visibility: hidden;}
44
+ header {visibility: hidden;}
45
+ </style>
46
+ """, unsafe_allow_html=True)
47
+
48
+ # Custom CSS
49
+ st.markdown(get_custom_css(), unsafe_allow_html=True)
50
+
51
+ # App title and description
52
+ st.markdown('<h1 style="text-align: center;">Great Offer Generator</h1>', unsafe_allow_html=True)
53
+ st.markdown('<h3 style="text-align: center;">Transform your skills into compelling offers!</h3>', unsafe_allow_html=True)
54
+
55
+ # Create two columns for layout - left column 40%, right column 60%
56
+ col1, col2 = st.columns([4, 6])
57
+
58
+ # Main input section in left column
59
+ with col1:
60
+ # Define the generate_offer function first
61
+ def handle_generate_button(): # Renamed to avoid conflict
62
+ has_manual_input = bool(skills or product_service)
63
+ has_file_input = bool(uploaded_file is not None and not is_image)
64
+ has_image_input = bool(uploaded_file is not None and is_image)
65
+
66
+ # Simple validation - check if we have at least one input type
67
+ if not (has_manual_input or has_file_input or has_image_input):
68
+ st.error('Por favor ingresa texto o sube un archivo/imagen')
69
+ return
70
 
71
+ st.session_state.submitted = True
72
+ st.session_state.generated = False # Reset generated flag
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
73
 
74
+ # Store inputs based on what's available
75
+ if has_manual_input:
76
+ st.session_state.skills = skills if skills else ""
77
+ st.session_state.product_service = product_service if product_service else ""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
78
 
79
+ if has_file_input:
80
+ st.session_state.file_content = file_content
81
+
82
+ if has_image_input:
83
+ st.session_state.image_parts = image_parts
84
+
85
+ # Set input type based on what's available
86
+ if has_image_input:
87
+ if has_manual_input:
88
+ st.session_state.input_type = "manual_image"
89
+ else:
90
+ st.session_state.input_type = "image"
91
+ else:
92
+ if has_manual_input and has_file_input:
93
+ st.session_state.input_type = "both"
94
+ elif has_file_input:
95
+ st.session_state.input_type = "file"
96
+ elif has_manual_input:
97
+ st.session_state.input_type = "manual"
98
+
99
+ # Store common settings
100
+ st.session_state.target_audience = target_audience
101
+ st.session_state.temperature = temperature
102
+ st.session_state.formula_type = formula_type
103
+
104
+ # Keep only the manual input tab
105
+ with st.container():
106
+ skills = st.text_area('💪 Tus Habilidades', height=70,
107
+ help='Lista tus habilidades y experiencia clave')
108
+ product_service = st.text_area('🎯 Producto/Servicio', height=70,
109
+ help='Describe tu producto o servicio')
110
+
111
+ # Generate button moved here - right after product/service
112
+ st.button('Generar Oferta 🎉', on_click=handle_generate_button) # Updated function name
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
113
 
114
+ # Accordion for additional settings
115
+ with st.expander('⚙️ Configuración Avanzada'):
116
+ target_audience = st.text_area('👥 Público Objetivo', height=70,
117
+ help='Describe tu cliente o público ideal')
118
+
119
+ # Add file/image uploader here
120
+ uploaded_file = st.file_uploader("📄 Sube un archivo o imagen",
121
+ type=['txt', 'pdf', 'docx', 'jpg', 'jpeg', 'png'])
122
+
123
+ if uploaded_file is not None:
124
+ file_type = uploaded_file.name.split('.')[-1].lower()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
125
 
126
+ # Handle text files
127
+ if file_type in ['txt', 'pdf', 'docx']:
128
+ if file_type == 'txt':
129
+ try:
130
+ file_content = uploaded_file.read().decode('utf-8')
131
+ except Exception as e:
132
+ st.error(f"Error al leer el archivo TXT: {str(e)}")
133
+ file_content = ""
134
+
135
+ elif file_type == 'pdf':
136
+ try:
137
+ import PyPDF2
138
+ pdf_reader = PyPDF2.PdfReader(uploaded_file)
139
+ file_content = ""
140
+ for page in pdf_reader.pages:
141
+ file_content += page.extract_text() + "\n"
142
+ except Exception as e:
143
+ st.error(f"Error al leer el archivo PDF: {str(e)}")
144
+ file_content = ""
145
+
146
+ elif file_type == 'docx':
147
+ try:
148
+ import docx
149
+ doc = docx.Document(uploaded_file)
150
+ file_content = "\n".join([para.text for para in doc.paragraphs])
151
+ except Exception as e:
152
+ st.error(f"Error al leer el archivo DOCX: {str(e)}")
153
+ file_content = ""
154
+
155
+ # Remove success message - no notification shown
156
+
157
+ # Set file type flag
158
+ is_image = False
159
 
160
+ # Handle image files
161
+ elif file_type in ['jpg', 'jpeg', 'png']:
162
+ try:
163
+ image = Image.open(uploaded_file)
164
+ st.image(image, caption="Imagen cargada", use_container_width=True)
165
+
166
+ image_bytes = uploaded_file.getvalue()
167
+ image_parts = [
168
+ {
169
+ "mime_type": uploaded_file.type,
170
+ "data": image_bytes
171
+ }
172
+ ]
173
+
174
+ # Set file type flag
175
+ is_image = True
176
+ except Exception as e:
177
+ st.error(f"Error al procesar la imagen: {str(e)}")
178
+ is_image = False
179
+
180
+ # Selector de fórmula
181
+ formula_type = st.selectbox(
182
+ '📋 Tipo de Fórmula',
183
+ options=list(offer_formulas.keys()),
184
+ help='Selecciona el tipo de fórmula para tu oferta'
185
+ )
186
+
187
+ temperature = st.slider('🌡️ Nivel de Creatividad', min_value=0.0, max_value=2.0, value=1.0,
188
+ help='Valores más altos hacen que el resultado sea más creativo pero menos enfocado')
189
+
190
+ # Results column
191
+ # In the section where you're generating the offer
192
+ with col2:
193
+ if st.session_state.submitted and not st.session_state.generated:
194
+ with st.spinner('Creando tu oferta perfecta...'):
195
+ # Use the create_offer_instruction function to generate the prompt
196
+ avatar_description = st.session_state.target_audience if hasattr(st.session_state, 'target_audience') and st.session_state.target_audience else 'General audience'
197
+
198
+ # Determine product name based on input type
199
+ if hasattr(st.session_state, 'product_service') and st.session_state.product_service:
200
+ product_name = st.session_state.product_service
201
+ else:
202
+ product_name = "Producto/Servicio"
203
+
204
+ # Get the instruction using the formula
205
+ instruction = create_offer_instruction(
206
+ avatar_description=avatar_description,
207
+ product_name=product_name,
208
+ selected_formula_name=st.session_state.formula_type
209
+ )
210
 
211
+ # Add specific instructions for more creative hooks when using Oferta Dorada
212
+ if st.session_state.formula_type == "Oferta Dorada":
213
+ creative_hook_instruction = """
214
+ IMPORTANT INSTRUCTION FOR THE ATTENTION HOOK:
215
+ Make the first line (attention hook) extremely creative, disruptive, and emotionally impactful.
216
+ Use unexpected comparisons, shocking statistics, provocative questions, or dramatic scenarios.
217
+ The hook should be surprising and immediately grab attention with unconventional language or framing.
218
+ Avoid generic statements and create a sense of urgency or curiosity.
219
+ """
220
+ instruction += creative_hook_instruction
221
 
222
+ # Add instruction for generating benefit bullets based on the promise
223
+ bullet_content = None
224
+ if hasattr(st.session_state, 'file_content') and st.session_state.input_type in ["file", "both"]:
225
+ bullet_content = st.session_state.file_content
226
+
227
+ instruction += create_bullet_instruction(
228
+ avatar_description=avatar_description,
229
+ product_name=product_name,
230
+ uploaded_content=bullet_content
231
+ )
232
 
233
+ # Add instruction for generating bonuses that complement the offer
234
+ instruction += create_bonus_instruction(
235
+ avatar_description=avatar_description,
236
+ product_name=product_name,
237
+ selected_formula_name=st.session_state.formula_type
238
+ )
239
 
240
+ # Add additional context based on input type
241
+ if st.session_state.input_type == "manual":
242
+ additional_context = f"""
243
+ Additional information:
244
+ Skills: {st.session_state.skills}
245
+ """
246
+ instruction += additional_context
247
+ elif st.session_state.input_type == "file":
248
+ additional_context = f"""
249
+ Additional information from file:
250
+ {st.session_state.file_content}
251
+ """
252
+ instruction += additional_context
253
+ elif st.session_state.input_type == "both":
254
+ additional_context = f"""
255
+ Additional information:
256
+ Skills: {st.session_state.skills}
257
+ File content: {st.session_state.file_content}
258
+ """
259
+ instruction += additional_context
260
+
261
+ try:
262
+ generation_config = genai.GenerationConfig(temperature=st.session_state.temperature)
263
+
264
+ if "image" in st.session_state.input_type:
265
+ response = model.generate_content([instruction, st.session_state.image_parts[0]], generation_config=generation_config)
266
+ else:
267
+ response = model.generate_content(instruction, generation_config=generation_config)
268
+
269
+ st.session_state.offer_result = response.text
270
+ st.session_state.generated = True # Mark as generated
271
+
272
+ except Exception as e:
273
+ st.error(f'Ocurrió un error: {str(e)}')
274
+ st.session_state.submitted = False
275
+
276
+ # Display results if we have an offer result
277
+ if st.session_state.generated:
278
+ # With this line that uses the wrapper:
279
+ st.markdown(get_response_html_wrapper(st.session_state.offer_result), unsafe_allow_html=True)
280
+
281
+ # Add a small space
282
+ st.markdown('<div style="height: 15px;"></div>', unsafe_allow_html=True)
283
+
284
+ # Apply the custom button style before rendering the download button
285
+ st.markdown('<style>div.stDownloadButton > button {your-custom-styles-here}</style>', unsafe_allow_html=True)
286
+ st.download_button(
287
+ label="Descargar Oferta",
288
+ data=st.session_state.offer_result,
289
+ file_name="oferta_generada.txt",
290
+ mime="text/plain"
291
+ )
292
+
293
+ # Footer
294
+ st.markdown('---')
295
+ st.markdown('Made with ❤️ by Jesús Cabrera')
296
+
297
+ # Remove the duplicate functions at the bottom