JeCabrera commited on
Commit
956fbae
·
verified ·
1 Parent(s): a249ce4

Upload 12 files

Browse files
Files changed (3) hide show
  1. app.py +161 -355
  2. session_state.py +156 -0
  3. system_prompts.py +154 -1
app.py CHANGED
@@ -5,7 +5,11 @@ import streamlit as st
5
  import google.generativeai as genai
6
  from dotenv import load_dotenv
7
  from puv_formulas import puv_formulas
8
- from system_prompts import get_puv_system_prompt
 
 
 
 
9
 
10
  # Función para cargar CSS personalizado
11
  def load_css(file_path):
@@ -29,81 +33,8 @@ except Exception as e:
29
  </style>
30
  """, unsafe_allow_html=True)
31
 
32
- load_dotenv()
33
- GOOGLE_API_KEY=os.environ.get('GOOGLE_API_KEY')
34
- genai.configure(api_key=GOOGLE_API_KEY)
35
-
36
- new_chat_id = f'{time.time()}'
37
- MODEL_ROLE = 'ai'
38
- AI_AVATAR_ICON = '🤖' # Cambia el emoji por uno de robot para coincidir con tu logo
39
- USER_AVATAR_ICON = '👤' # Añade un avatar para el usuario
40
-
41
- # Create a data/ folder if it doesn't already exist
42
- try:
43
- os.mkdir('data/')
44
- except:
45
- # data/ folder already exists
46
- pass
47
-
48
- # Load past chats (if available)
49
- try:
50
- past_chats: dict = joblib.load('data/past_chats_list')
51
- except:
52
- past_chats = {}
53
-
54
- # Sidebar allows a list of past chats
55
- with st.sidebar:
56
- st.write('# Chats Anteriores')
57
- if st.session_state.get('chat_id') is None:
58
- st.session_state.chat_id = st.selectbox(
59
- label='Selecciona un chat anterior',
60
- options=[new_chat_id] + list(past_chats.keys()),
61
- format_func=lambda x: past_chats.get(x, 'Nuevo Chat'),
62
- placeholder='_',
63
- )
64
- else:
65
- # This will happen the first time AI response comes in
66
- st.session_state.chat_id = st.selectbox(
67
- label='Selecciona un chat anterior',
68
- options=[new_chat_id, st.session_state.chat_id] + list(past_chats.keys()),
69
- index=1,
70
- format_func=lambda x: past_chats.get(x, 'Nuevo Chat' if x != st.session_state.chat_id else st.session_state.chat_title),
71
- placeholder='_',
72
- )
73
- # Save new chats after a message has been sent to AI
74
- st.session_state.chat_title = f'SesiónChat-{st.session_state.chat_id}'
75
-
76
- # Chat history (allows to ask multiple questions)
77
- try:
78
- st.session_state.messages = joblib.load(
79
- f'data/{st.session_state.chat_id}-st_messages'
80
- )
81
- st.session_state.gemini_history = joblib.load(
82
- f'data/{st.session_state.chat_id}-gemini_messages'
83
- )
84
- print('old cache')
85
- except:
86
- st.session_state.messages = []
87
- st.session_state.gemini_history = []
88
- print('new_cache made')
89
- st.session_state.model = genai.GenerativeModel('gemini-2.0-flash')
90
- st.session_state.chat = st.session_state.model.start_chat(
91
- history=st.session_state.gemini_history,
92
- )
93
-
94
- # Display chat messages from history on app rerun
95
- for message in st.session_state.messages:
96
- with st.chat_message(
97
- name=message['role'],
98
- avatar=message.get('avatar'),
99
- ):
100
- st.markdown(message['content'])
101
-
102
- # Mensaje inicial del sistema si es un chat nuevo
103
- if not st.session_state.messages:
104
- system_prompt = get_puv_system_prompt()
105
-
106
- # Mostrar la carátula inicial con el logo centrado
107
  col1, col2, col3 = st.columns([1, 2, 1])
108
  with col2:
109
  # Centrar la imagen
@@ -141,8 +72,9 @@ if not st.session_state.messages:
141
  </p>
142
  </div>
143
  """, unsafe_allow_html=True)
144
-
145
- # Mostrar los ejemplos
 
146
  ejemplos = [
147
  {"texto": "¿Qué es una Propuesta de Valor Única? 🎯", "prompt": "Explícame qué es una Propuesta de Valor Única (PUV) y por qué es importante para mi negocio"},
148
  {"texto": "¿Cómo puedo crear mi PUV? 📝", "prompt": "Guíame paso a paso en el proceso de crear una Propuesta de Valor Única efectiva"},
@@ -155,342 +87,216 @@ if not st.session_state.messages:
155
  for idx, ejemplo in enumerate(ejemplos):
156
  with cols[idx]:
157
  if st.button(ejemplo["texto"], key=f"ejemplo_{idx}", help=ejemplo["prompt"]):
158
- st.session_state.prompt = ejemplo["prompt"]
159
  st.rerun()
160
 
161
- # Inicializar el chat con el sistema prompt
162
- st.session_state.chat = st.session_state.model.start_chat(
163
- history=st.session_state.gemini_history
164
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
165
 
166
- # Enviar el system prompt como primer mensaje
167
- st.session_state.chat.send_message(system_prompt)
 
 
 
 
 
 
168
 
169
  # Solo añadir el mensaje inicial si no es un ejemplo
170
- if not st.session_state.get('prompt'):
171
- st.session_state.messages.append(
172
- dict(
173
- role=MODEL_ROLE,
174
- content="""
175
- Hola, soy RoboCopy tu asistente especializado en crear Propuestas de Valor Únicas.
176
-
177
- Para ayudarte a crear PUVs efectivas, necesito conocer:
178
-
179
- 1. ¿Qué producto o servicio ofreces?
180
- 2. ¿A quién va dirigido? (describe tu público objetivo)
181
- 3. ¿Qué fórmula prefieres usar? Puedo ofrecerte:
182
- - Tradicional: Clara y directa
183
- - Anti-tradicional: Innovadora y disruptiva
184
- - Contrato Imposible: Audaz y sorprendente
185
- - Reto Ridículo: Humorística y relatable
186
- 4. ¿Cuántos ejemplos de PUVs necesitas?
187
-
188
- ¿Empezamos con tu producto o servicio?
189
- """,
190
- avatar=AI_AVATAR_ICON,
191
- )
192
  )
193
 
194
- # React to user input
195
  if prompt := st.chat_input('Describe tu producto/servicio y audiencia objetivo...'):
196
- # Save this as a chat for later
197
- if st.session_state.chat_id not in past_chats.keys():
198
  # Es una nueva conversación, generemos un título basado en el primer mensaje
199
- temp_title = f'SesiónChat-{st.session_state.chat_id}'
200
- past_chats[st.session_state.chat_id] = temp_title
201
 
202
- try:
203
- # Usamos el mismo modelo para generar un título corto
204
- title_generator = genai.GenerativeModel('gemini-2.0-flash')
205
- title_response = title_generator.generate_content(
206
- f"Genera un título corto (máximo 5 palabras) que describa de qué trata esta consulta, sin usar comillas ni puntuación: '{prompt}'")
207
-
208
- # Obtenemos el título generado
209
- generated_title = title_response.text.strip()
210
-
211
- # Actualizamos el título en past_chats
212
- if generated_title:
213
- st.session_state.chat_title = generated_title
214
- past_chats[st.session_state.chat_id] = generated_title
215
- else:
216
- st.session_state.chat_title = temp_title
217
- except Exception as e:
218
- print(f"Error al generar título: {e}")
219
- st.session_state.chat_title = temp_title
220
  else:
221
  # Ya existe esta conversación, usamos el título guardado
222
- st.session_state.chat_title = past_chats[st.session_state.chat_id]
223
 
224
  joblib.dump(past_chats, 'data/past_chats_list')
225
 
226
- # Display user message in chat message container
227
  with st.chat_message('user', avatar=USER_AVATAR_ICON):
228
  st.markdown(prompt)
229
 
230
- # Add user message to chat history
231
- st.session_state.messages.append(
232
- dict(
233
- role='user',
234
- content=prompt,
235
- )
236
- )
237
-
238
- # Construir el prompt para el modelo con todas las fórmulas disponibles
239
- puv_expert_prompt = """You are a collaborative team of world-class experts working together to create exceptional Unique Value Propositions (UVPs) that convert audience into customers.
240
-
241
- IMPORTANT: Always maintain a friendly and conversational tone. When users express gratitude or make casual comments:
242
- 1. Acknowledge their message first (e.g., "¡De nada! Me alegra poder ayudarte.")
243
- 2. Then continue with the conversation naturally
244
- 3. Show personality and empathy in your responses
245
- 4. Use emojis occasionally to add warmth 😊
246
-
247
- If the user says "gracias" or similar:
248
- - Respond warmly first
249
- - Then ask if they'd like to continue working on their PUV or if tienen alguna otra pregunta
250
-
251
- INTERNAL ANALYSIS (DO NOT OUTPUT):
252
-
253
- 1. DEEP AVATAR ANALYSIS:
254
- A. Daily Life & Cultural Context:
255
- - What daily experiences resonate with them?
256
- - What cultural references do they understand?
257
- - What mental images are easy for them to recall?
258
- - What TV shows, movies, or media do they consume?
259
-
260
- B. Pain Points & Emotional Core:
261
- - What is their ONE main pain point?
262
- - What consequences does this pain point trigger?
263
- - What past painful experience influences current decisions?
264
- - What internal conflict do they regularly experience?
265
- - What do they need to heal or resolve to feel complete?
266
-
267
- C. Previous Solutions:
268
- - What have they tried before that didn't work?
269
- - Why didn't these solutions work for them?
270
- - What do other "experts" tell them to do?
271
- - What false beliefs do they hold?
272
-
273
- D. Desires & Transformations:
274
- - What are their primary desires?
275
- - What is their current vs. desired situation?
276
- - What transformation are they seeking?
277
- - Why do they need to act now?
278
-
279
- 2. PRODUCT/SERVICE ANALYSIS:
280
- - What is the main benefit or promise?
281
- - What makes it unique or different?
282
- - What transformation does it offer?
283
- - How does it help achieve results?
284
- - Why is it superior to existing solutions?
285
-
286
- 3. MARKET CONTEXT:
287
- - What are the common industry solutions?
288
- - Why do these solutions fail?
289
- - What are the typical misconceptions?
290
- - What makes your solution unique?
291
-
292
- Based on this internal analysis, create UVPs that:
293
- 1. Connect directly with the main pain point
294
- 2. Address deep emotional motivations
295
- 3. Contrast with failed past solutions
296
- 4. Present your unique method convincingly
297
- 5. Use familiar analogies or metaphors
298
-
299
- THE EXPERT TEAM:
300
- 1. MASTER UVP STRATEGIST:
301
- - Expert in UVP frameworks and conversion strategies
302
- - Ensures the UVPs follow the selected framework structure precisely
303
- - Focuses on strategic placement of key conversion elements
304
- 2. ELITE DIRECT RESPONSE COPYWRITER:
305
- - Trained by Gary Halbert, Gary Bencivenga, and David Ogilvy
306
- - Creates compelling hooks and persuasive elements
307
- - Ensures the language resonates with the target audience
308
- 3. AUDIENCE PSYCHOLOGY SPECIALIST:
309
- - Expert in understanding audience motivations and objections
310
- - Creates content that builds genuine connection and trust
311
- - Identifies and addresses hidden fears and desires
312
- 4. STORYTELLING MASTER:
313
- - Creates compelling narratives that illustrate key points
314
- - Makes complex concepts accessible through narrative
315
- 5. ENGAGEMENT EXPERT:
316
- - Specializes in creating memorable and impactful statements
317
- - Ensures the UVPs are clear, concise and compelling
318
-
319
- You are a UVP (Unique Value Proposition) expert. Analyze (internally only, do not output the analysis) the user's message to identify information about their product/service and target audience.
320
-
321
- If the user hasn't provided all the necessary information, guide them through the process by asking for:
322
- 1. What product/service they offer
323
- 2. Who their target audience is
324
- 3. Which formula they prefer (Tradicional, Anti-tradicional, Contrato Imposible, Reto Ridículo)
325
- 4. How many UVP examples they want
326
-
327
- If the user mentions a specific formula, use that formula from the puv_formulas dictionary. If they don't specify, suggest the most appropriate formula based on their product/service and audience.
328
-
329
- If the user is asking for UVPs and has provided sufficient information, create the requested number of different UVPs using the specified formula. If the user is asking a question about UVPs or marketing, answer it helpfully.
330
-
331
- When creating UVPs, follow these CRITICAL INSTRUCTIONS:
332
- - Each UVP must be specific and measurable
333
- - Focus on the transformation journey
334
- - Use natural, conversational language
335
- - Avoid generic phrases and buzzwords
336
- - Maximum 2 lines per UVP
337
 
338
- ESTRUCTURAS DE FÓRMULAS PUV:
339
-
340
- 1. FÓRMULA TRADICIONAL:
341
- Estructura obligatoria: "Yo ayudo a [AVATAR] a [TRANSFORMACIÓN]"
342
- Elementos requeridos:
343
- - Avatar específico y detallado
344
- - Transformación medible y concreta
345
- - Verbo de acción claro
346
-
347
- 2. FÓRMULA ANTI-TRADICIONAL:
348
- Estructura obligatoria: Comenzar con uno de:
349
- - "Yo transformo..."
350
- - "Me especializo en..."
351
- - "Soy experto/a en..."
352
- Elementos requeridos:
353
- - Situación actual del avatar con UN problema principal
354
- - UNA transformación clara
355
- - UN beneficio principal
356
-
357
- 3. CONTRATO IMPOSIBLE:
358
- Estructura obligatoria:
359
- 1. Opener audaz: "¿Te imaginas poder..." / "Soy el antídoto para..." / "Revoluciono la manera..."
360
- 2. Descripción del producto/servicio de forma inesperada
361
- 3. Beneficio transformador increíble
362
- 4. Diferenciador anti-tradicional
363
-
364
- 4. RETO RIDÍCULO:
365
- Estructura obligatoria:
366
- 1. Anécdota personal humorística
367
- 2. Problema específico del mercado
368
- 3. Solución obvia pero presentada de forma única
369
-
370
- PROCESO DE VALIDACIÓN:
371
- Antes de generar cada PUV, verificar:
372
- 1. ¿Sigue exactamente la estructura de la fórmula elegida?
373
- 2. ¿Incluye todos los elementos requeridos?
374
- 3. ¿Mantiene el formato específico de la fórmula?
375
- 4. ¿Comunica claramente el valor único?
376
-
377
- If creating UVPs, output in this format:
378
- "Basado en tu descripción, aquí tienes [número] propuestas de valor únicas (PUVs) para tu [producto/servicio] usando la fórmula [nombre de fórmula]:
379
-
380
- 1. [First UVP]
381
- 2. [Second UVP]
382
- 3. [Third UVP]
383
- ...
384
-
385
- Estas PUVs destacan [principales beneficios]. ¿Hay alguna que te guste más o quieres que ajuste algún aspecto?"
386
-
387
- If answering a question, provide a helpful, expert response.
388
- """
389
 
390
  # Combinar el prompt del experto con el mensaje del usuario
391
  enhanced_prompt = f"{puv_expert_prompt}\n\nUser message: {prompt}"
392
 
393
- ## Send message to AI
394
- response = st.session_state.chat.send_message(
395
  enhanced_prompt,
396
  stream=True,
397
  )
398
 
399
- # Display assistant response in chat message container
400
  with st.chat_message(
401
  name=MODEL_ROLE,
402
  avatar=AI_AVATAR_ICON,
403
  ):
404
  message_placeholder = st.empty()
405
  full_response = ''
406
- assistant_response = response
407
 
408
- # Añade un indicador de "escribiendo..."
409
  typing_indicator = st.empty()
410
  typing_indicator.markdown("*Generando respuesta...*")
411
 
412
- # Streams in a chunk at a time
413
  for chunk in response:
414
- # Simulate stream of chunk
415
- for ch in chunk.text: # Eliminamos el split(' ') para procesar carácter por carácter
416
  full_response += ch
417
- time.sleep(0.01) # Más rápido
418
- # Rewrites with a cursor at end
419
  message_placeholder.write(full_response + '▌')
420
- # Elimina el indicador de escritura
 
421
  typing_indicator.empty()
422
- # Write full message with placeholder
 
423
  message_placeholder.write(full_response)
424
 
425
- # Add assistant response to chat history
426
- st.session_state.messages.append(
427
- dict(
428
- role=MODEL_ROLE,
429
- content=st.session_state.chat.history[-1].parts[0].text,
430
- avatar=AI_AVATAR_ICON,
431
- )
432
- )
433
- st.session_state.gemini_history = st.session_state.chat.history
434
- # Save to file
435
- joblib.dump(
436
- st.session_state.messages,
437
- f'data/{st.session_state.chat_id}-st_messages',
438
- )
439
- joblib.dump(
440
- st.session_state.gemini_history,
441
- f'data/{st.session_state.chat_id}-gemini_messages',
442
  )
 
 
 
 
443
 
444
- # Cuando se selecciona un ejemplo
445
- if 'prompt' in st.session_state and st.session_state.prompt: # Verificamos que el prompt no esté vacío
446
- prompt = st.session_state.prompt
447
 
448
  # Guardar el chat para después si es nuevo
449
- if st.session_state.chat_id not in past_chats.keys():
450
- temp_title = f'SesiónChat-{st.session_state.chat_id}'
451
- past_chats[st.session_state.chat_id] = temp_title
452
  joblib.dump(past_chats, 'data/past_chats_list')
453
 
454
- # Mostrar el mensaje del usuario
455
  with st.chat_message('user', avatar=USER_AVATAR_ICON):
456
  st.markdown(prompt)
457
 
458
- # Añadir el mensaje del usuario al historial
459
- st.session_state.messages.append({
460
- 'role': 'user',
461
- 'content': prompt,
462
- 'avatar': USER_AVATAR_ICON
463
- })
464
 
465
- # Procesar la respuesta del modelo
466
  if prompt.strip():
467
  with st.chat_message(MODEL_ROLE, avatar=AI_AVATAR_ICON):
468
  try:
469
- response = st.session_state.chat.send_message(prompt)
470
  st.markdown(response.text)
471
 
472
- # Añadir la respuesta al historial
473
- st.session_state.messages.append({
474
- 'role': MODEL_ROLE,
475
- 'content': response.text,
476
- 'avatar': AI_AVATAR_ICON
477
- })
478
 
479
- # Guardar el historial actualizado
480
- joblib.dump(
481
- st.session_state.messages,
482
- f'data/{st.session_state.chat_id}-st_messages',
483
- )
484
- joblib.dump(
485
- st.session_state.gemini_history,
486
- f'data/{st.session_state.chat_id}-gemini_messages',
487
- )
488
  except ValueError as e:
489
  st.error("Error: El mensaje no puede estar vacío. Por favor, escribe algo.")
490
 
491
- # Limpiar el prompt del estado de la sesión
492
- st.session_state.prompt = None
493
-
494
- # Limpiar el prompt del estado de la sesión
495
- st.session_state.prompt = None
496
-
 
5
  import google.generativeai as genai
6
  from dotenv import load_dotenv
7
  from puv_formulas import puv_formulas
8
+ from system_prompts import get_puv_system_prompt, get_puv_expert_prompt
9
+ from session_state import SessionState
10
+
11
+ # Inicializar el estado de la sesión
12
+ state = SessionState()
13
 
14
  # Función para cargar CSS personalizado
15
  def load_css(file_path):
 
33
  </style>
34
  """, unsafe_allow_html=True)
35
 
36
+ # Función de utilidad para mostrar la carátula inicial
37
+ def display_initial_header():
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  col1, col2, col3 = st.columns([1, 2, 1])
39
  with col2:
40
  # Centrar la imagen
 
72
  </p>
73
  </div>
74
  """, unsafe_allow_html=True)
75
+
76
+ # Función para mostrar ejemplos de preguntas
77
+ def display_examples():
78
  ejemplos = [
79
  {"texto": "¿Qué es una Propuesta de Valor Única? 🎯", "prompt": "Explícame qué es una Propuesta de Valor Única (PUV) y por qué es importante para mi negocio"},
80
  {"texto": "¿Cómo puedo crear mi PUV? 📝", "prompt": "Guíame paso a paso en el proceso de crear una Propuesta de Valor Única efectiva"},
 
87
  for idx, ejemplo in enumerate(ejemplos):
88
  with cols[idx]:
89
  if st.button(ejemplo["texto"], key=f"ejemplo_{idx}", help=ejemplo["prompt"]):
90
+ state.prompt = ejemplo["prompt"]
91
  st.rerun()
92
 
93
+ # Cargar variables de entorno
94
+ load_dotenv()
95
+ GOOGLE_API_KEY=os.environ.get('GOOGLE_API_KEY')
96
+ genai.configure(api_key=GOOGLE_API_KEY)
97
+
98
+ # Configuración de la aplicación
99
+ new_chat_id = f'{time.time()}'
100
+ MODEL_ROLE = 'ai'
101
+ AI_AVATAR_ICON = '🤖' # Cambia el emoji por uno de robot para coincidir con tu logo
102
+ USER_AVATAR_ICON = '👤' # Añade un avatar para el usuario
103
+
104
+ # Crear carpeta de datos si no existe
105
+ try:
106
+ os.mkdir('data/')
107
+ except:
108
+ # data/ folder already exists
109
+ pass
110
+
111
+ # Cargar chats anteriores
112
+ try:
113
+ past_chats: dict = joblib.load('data/past_chats_list')
114
+ except:
115
+ past_chats = {}
116
+
117
+ # Sidebar para seleccionar chats anteriores
118
+ with st.sidebar:
119
+ st.write('# Chats Anteriores')
120
+ if state.chat_id is None:
121
+ state.chat_id = st.selectbox(
122
+ label='Selecciona un chat anterior',
123
+ options=[new_chat_id] + list(past_chats.keys()),
124
+ format_func=lambda x: past_chats.get(x, 'Nuevo Chat'),
125
+ placeholder='_',
126
+ )
127
+ else:
128
+ # This will happen the first time AI response comes in
129
+ state.chat_id = st.selectbox(
130
+ label='Selecciona un chat anterior',
131
+ options=[new_chat_id, state.chat_id] + list(past_chats.keys()),
132
+ index=1,
133
+ format_func=lambda x: past_chats.get(x, 'Nuevo Chat' if x != state.chat_id else state.chat_title),
134
+ placeholder='_',
135
+ )
136
+ # Save new chats after a message has been sent to AI
137
+ state.chat_title = f'SesiónChat-{state.chat_id}'
138
+
139
+ # Cargar historial del chat
140
+ state.load_chat_history()
141
+
142
+ # Inicializar el modelo
143
+ state.initialize_model('gemini-2.0-flash')
144
+ state.initialize_chat()
145
+
146
+ # Mostrar mensajes del historial
147
+ for message in state.messages:
148
+ with st.chat_message(
149
+ name=message['role'],
150
+ avatar=message.get('avatar'),
151
+ ):
152
+ st.markdown(message['content'])
153
+
154
+ # Mensaje inicial del sistema si es un chat nuevo
155
+ if not state.has_messages():
156
+ # Mostrar la carátula inicial con el logo centrado
157
+ display_initial_header()
158
 
159
+ # Mostrar los ejemplos
160
+ display_examples()
161
+
162
+ # Inicializar el chat con los prompts del sistema
163
+ system_prompt = get_puv_system_prompt()
164
+ expert_prompt = get_puv_expert_prompt()
165
+ state.chat.send_message(system_prompt)
166
+ state.chat.send_message(expert_prompt)
167
 
168
  # Solo añadir el mensaje inicial si no es un ejemplo
169
+ if not state.has_prompt():
170
+ state.add_message(
171
+ role=MODEL_ROLE,
172
+ content="""
173
+ Hola, soy RoboCopy tu asistente especializado en crear Propuestas de Valor Únicas.
174
+
175
+ Para ayudarte a crear PUVs efectivas, necesito conocer:
176
+
177
+ 1. ¿Qué producto o servicio ofreces?
178
+ 2. ¿A quién va dirigido? (describe tu público objetivo)
179
+ 3. ¿Qué fórmula prefieres usar? Puedo ofrecerte:
180
+ - Tradicional: Clara y directa
181
+ - Anti-tradicional: Innovadora y disruptiva
182
+ - Contrato Imposible: Audaz y sorprendente
183
+ - Reto Ridículo: Humorística y relatable
184
+ 4. ¿Cuántos ejemplos de PUVs necesitas?
185
+
186
+ ¿Empezamos con tu producto o servicio?
187
+ """,
188
+ avatar=AI_AVATAR_ICON,
 
 
189
  )
190
 
191
+ # Procesar entrada del usuario
192
  if prompt := st.chat_input('Describe tu producto/servicio y audiencia objetivo...'):
193
+ # Guardar el chat para después si es nuevo
194
+ if state.chat_id not in past_chats.keys():
195
  # Es una nueva conversación, generemos un título basado en el primer mensaje
196
+ temp_title = f'SesiónChat-{state.chat_id}'
197
+ past_chats[state.chat_id] = temp_title
198
 
199
+ # Generar título para el chat
200
+ generated_title = state.generate_chat_title(prompt)
201
+
202
+ # Actualizamos el título en past_chats
203
+ if generated_title:
204
+ state.chat_title = generated_title
205
+ past_chats[state.chat_id] = generated_title
206
+ else:
207
+ state.chat_title = temp_title
 
 
 
 
 
 
 
 
 
208
  else:
209
  # Ya existe esta conversación, usamos el título guardado
210
+ state.chat_title = past_chats[state.chat_id]
211
 
212
  joblib.dump(past_chats, 'data/past_chats_list')
213
 
214
+ # Mostrar mensaje del usuario
215
  with st.chat_message('user', avatar=USER_AVATAR_ICON):
216
  st.markdown(prompt)
217
 
218
+ # Añadir mensaje del usuario al historial
219
+ state.add_message('user', prompt)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
220
 
221
+ # Obtener el prompt del experto
222
+ puv_expert_prompt = get_puv_expert_prompt()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
223
 
224
  # Combinar el prompt del experto con el mensaje del usuario
225
  enhanced_prompt = f"{puv_expert_prompt}\n\nUser message: {prompt}"
226
 
227
+ # Enviar mensaje al modelo
228
+ response = state.chat.send_message(
229
  enhanced_prompt,
230
  stream=True,
231
  )
232
 
233
+ # Mostrar respuesta del asistente
234
  with st.chat_message(
235
  name=MODEL_ROLE,
236
  avatar=AI_AVATAR_ICON,
237
  ):
238
  message_placeholder = st.empty()
239
  full_response = ''
 
240
 
241
+ # Añadir indicador de "escribiendo..."
242
  typing_indicator = st.empty()
243
  typing_indicator.markdown("*Generando respuesta...*")
244
 
245
+ # Mostrar respuesta por fragmentos
246
  for chunk in response:
247
+ for ch in chunk.text:
 
248
  full_response += ch
249
+ time.sleep(0.01)
 
250
  message_placeholder.write(full_response + '▌')
251
+
252
+ # Eliminar indicador de escritura
253
  typing_indicator.empty()
254
+
255
+ # Mostrar respuesta completa
256
  message_placeholder.write(full_response)
257
 
258
+ # Añadir respuesta al historial
259
+ state.add_message(
260
+ role=MODEL_ROLE,
261
+ content=state.chat.history[-1].parts[0].text,
262
+ avatar=AI_AVATAR_ICON,
 
 
 
 
 
 
 
 
 
 
 
 
263
  )
264
+ state.gemini_history = state.chat.history
265
+
266
+ # Guardar historial
267
+ state.save_chat_history()
268
 
269
+ # Procesar ejemplos seleccionados
270
+ if state.has_prompt():
271
+ prompt = state.prompt
272
 
273
  # Guardar el chat para después si es nuevo
274
+ if state.chat_id not in past_chats.keys():
275
+ temp_title = f'SesiónChat-{state.chat_id}'
276
+ past_chats[state.chat_id] = temp_title
277
  joblib.dump(past_chats, 'data/past_chats_list')
278
 
279
+ # Mostrar mensaje del usuario
280
  with st.chat_message('user', avatar=USER_AVATAR_ICON):
281
  st.markdown(prompt)
282
 
283
+ # Añadir mensaje del usuario al historial
284
+ state.add_message('user', prompt, USER_AVATAR_ICON)
 
 
 
 
285
 
286
+ # Procesar respuesta del modelo
287
  if prompt.strip():
288
  with st.chat_message(MODEL_ROLE, avatar=AI_AVATAR_ICON):
289
  try:
290
+ response = state.chat.send_message(prompt)
291
  st.markdown(response.text)
292
 
293
+ # Añadir respuesta al historial
294
+ state.add_message(MODEL_ROLE, response.text, AI_AVATAR_ICON)
 
 
 
 
295
 
296
+ # Guardar historial actualizado
297
+ state.save_chat_history()
 
 
 
 
 
 
 
298
  except ValueError as e:
299
  st.error("Error: El mensaje no puede estar vacío. Por favor, escribe algo.")
300
 
301
+ # Limpiar el prompt
302
+ state.clear_prompt()
 
 
 
 
session_state.py ADDED
@@ -0,0 +1,156 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import time
3
+ import joblib
4
+ import google.generativeai as genai
5
+
6
+ class SessionState:
7
+ """
8
+ Clase para gestionar el estado de la sesión de Streamlit de manera centralizada.
9
+ Encapsula todas las operaciones relacionadas con st.session_state.
10
+ """
11
+
12
+ def __init__(self):
13
+ # Inicializar valores por defecto si no existen
14
+ if 'chat_id' not in st.session_state:
15
+ st.session_state.chat_id = None
16
+
17
+ if 'chat_title' not in st.session_state:
18
+ st.session_state.chat_title = None
19
+
20
+ if 'messages' not in st.session_state:
21
+ st.session_state.messages = []
22
+
23
+ if 'gemini_history' not in st.session_state:
24
+ st.session_state.gemini_history = []
25
+
26
+ if 'model' not in st.session_state:
27
+ st.session_state.model = None
28
+
29
+ if 'chat' not in st.session_state:
30
+ st.session_state.chat = None
31
+
32
+ if 'prompt' not in st.session_state:
33
+ st.session_state.prompt = None
34
+
35
+ # Getters y setters para cada propiedad
36
+ @property
37
+ def chat_id(self):
38
+ return st.session_state.chat_id
39
+
40
+ @chat_id.setter
41
+ def chat_id(self, value):
42
+ st.session_state.chat_id = value
43
+
44
+ @property
45
+ def chat_title(self):
46
+ return st.session_state.chat_title
47
+
48
+ @chat_title.setter
49
+ def chat_title(self, value):
50
+ st.session_state.chat_title = value
51
+
52
+ @property
53
+ def messages(self):
54
+ return st.session_state.messages
55
+
56
+ @messages.setter
57
+ def messages(self, value):
58
+ st.session_state.messages = value
59
+
60
+ @property
61
+ def gemini_history(self):
62
+ return st.session_state.gemini_history
63
+
64
+ @gemini_history.setter
65
+ def gemini_history(self, value):
66
+ st.session_state.gemini_history = value
67
+
68
+ @property
69
+ def model(self):
70
+ return st.session_state.model
71
+
72
+ @model.setter
73
+ def model(self, value):
74
+ st.session_state.model = value
75
+
76
+ @property
77
+ def chat(self):
78
+ return st.session_state.chat
79
+
80
+ @chat.setter
81
+ def chat(self, value):
82
+ st.session_state.chat = value
83
+
84
+ @property
85
+ def prompt(self):
86
+ return st.session_state.prompt
87
+
88
+ @prompt.setter
89
+ def prompt(self, value):
90
+ st.session_state.prompt = value
91
+
92
+ # Métodos de utilidad
93
+ def add_message(self, role, content, avatar=None):
94
+ """Añade un mensaje al historial"""
95
+ message = {
96
+ 'role': role,
97
+ 'content': content,
98
+ }
99
+ if avatar:
100
+ message['avatar'] = avatar
101
+ self.messages.append(message)
102
+
103
+ def clear_prompt(self):
104
+ """Limpia el prompt del estado de la sesión"""
105
+ self.prompt = None
106
+
107
+ def initialize_model(self, model_name='gemini-2.0-flash'):
108
+ """Inicializa el modelo de IA"""
109
+ self.model = genai.GenerativeModel(model_name)
110
+
111
+ def initialize_chat(self, history=None):
112
+ """Inicializa el chat con el modelo"""
113
+ if history is None:
114
+ history = self.gemini_history
115
+ self.chat = self.model.start_chat(history=history)
116
+
117
+ def generate_chat_title(self, prompt, model_name='gemini-2.0-flash'):
118
+ """Genera un título para el chat basado en el primer mensaje"""
119
+ try:
120
+ title_generator = genai.GenerativeModel(model_name)
121
+ title_response = title_generator.generate_content(
122
+ f"Genera un título corto (máximo 5 palabras) que describa de qué trata esta consulta, sin usar comillas ni puntuación: '{prompt}'")
123
+ return title_response.text.strip()
124
+ except Exception as e:
125
+ print(f"Error al generar título: {e}")
126
+ return None
127
+
128
+ def save_chat_history(self, chat_id=None):
129
+ """Guarda el historial del chat"""
130
+ if chat_id is None:
131
+ chat_id = self.chat_id
132
+
133
+ joblib.dump(self.messages, f'data/{chat_id}-st_messages')
134
+ joblib.dump(self.gemini_history, f'data/{chat_id}-gemini_messages')
135
+
136
+ def load_chat_history(self, chat_id=None):
137
+ """Carga el historial del chat"""
138
+ if chat_id is None:
139
+ chat_id = self.chat_id
140
+
141
+ try:
142
+ self.messages = joblib.load(f'data/{chat_id}-st_messages')
143
+ self.gemini_history = joblib.load(f'data/{chat_id}-gemini_messages')
144
+ return True
145
+ except:
146
+ self.messages = []
147
+ self.gemini_history = []
148
+ return False
149
+
150
+ def has_messages(self):
151
+ """Verifica si hay mensajes en el historial"""
152
+ return len(self.messages) > 0
153
+
154
+ def has_prompt(self):
155
+ """Verifica si hay un prompt en el estado de la sesión"""
156
+ return self.prompt is not None and self.prompt.strip() != ""
system_prompts.py CHANGED
@@ -148,4 +148,157 @@ REQUISITOS DE FORMATO:
148
  - ESCRIBE SIEMPRE EN ESPAÑOL
149
  - Usa emojis ocasionalmente para dar calidez a la conversación
150
 
151
- IMPORTANTE: Cuando tengas suficiente información, SIEMPRE ofrece múltiples versiones de PUV usando diferentes fórmulas para que el usuario pueda elegir la que mejor se adapte a su negocio."""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
148
  - ESCRIBE SIEMPRE EN ESPAÑOL
149
  - Usa emojis ocasionalmente para dar calidez a la conversación
150
 
151
+ IMPORTANTE: Cuando tengas suficiente información, SIEMPRE ofrece múltiples versiones de PUV usando diferentes fórmulas para que el usuario pueda elegir la que mejor se adapte a su negocio.
152
+ """
153
+
154
+ def get_puv_expert_prompt():
155
+ return """You are a collaborative team of world-class experts working together to create exceptional Unique Value Propositions (UVPs) that convert audience into customers.
156
+
157
+ IMPORTANT: Always maintain a friendly and conversational tone. When users express gratitude or make casual comments:
158
+ 1. Acknowledge their message first (e.g., "¡De nada! Me alegra poder ayudarte.")
159
+ 2. Then continue with the conversation naturally
160
+ 3. Show personality and empathy in your responses
161
+ 4. Use emojis occasionally to add warmth 😊
162
+
163
+ If the user says "gracias" or similar:
164
+ - Respond warmly first
165
+ - Then ask if they'd like to continue working on their PUV or if tienen alguna otra pregunta
166
+
167
+ INTERNAL ANALYSIS (DO NOT OUTPUT):
168
+
169
+ 1. DEEP AVATAR ANALYSIS:
170
+ A. Daily Life & Cultural Context:
171
+ - What daily experiences resonate with them?
172
+ - What cultural references do they understand?
173
+ - What mental images are easy for them to recall?
174
+ - What TV shows, movies, or media do they consume?
175
+
176
+ B. Pain Points & Emotional Core:
177
+ - What is their ONE main pain point?
178
+ - What consequences does this pain point trigger?
179
+ - What past painful experience influences current decisions?
180
+ - What internal conflict do they regularly experience?
181
+ - What do they need to heal or resolve to feel complete?
182
+
183
+ C. Previous Solutions:
184
+ - What have they tried before that didn't work?
185
+ - Why didn't these solutions work for them?
186
+ - What do other "experts" tell them to do?
187
+ - What false beliefs do they hold?
188
+
189
+ D. Desires & Transformations:
190
+ - What are their primary desires?
191
+ - What is their current vs. desired situation?
192
+ - What transformation are they seeking?
193
+ - Why do they need to act now?
194
+
195
+ 2. PRODUCT/SERVICE ANALYSIS:
196
+ - What is the main benefit or promise?
197
+ - What makes it unique or different?
198
+ - What transformation does it offer?
199
+ - How does it help achieve results?
200
+ - Why is it superior to existing solutions?
201
+
202
+ 3. MARKET CONTEXT:
203
+ - What are the common industry solutions?
204
+ - Why do these solutions fail?
205
+ - What are the typical misconceptions?
206
+ - What makes your solution unique?
207
+
208
+ Based on this internal analysis, create UVPs that:
209
+ 1. Connect directly with the main pain point
210
+ 2. Address deep emotional motivations
211
+ 3. Contrast with failed past solutions
212
+ 4. Present your unique method convincingly
213
+ 5. Use familiar analogies or metaphors
214
+
215
+ THE EXPERT TEAM:
216
+ 1. MASTER UVP STRATEGIST:
217
+ - Expert in UVP frameworks and conversion strategies
218
+ - Ensures the UVPs follow the selected framework structure precisely
219
+ - Focuses on strategic placement of key conversion elements
220
+ 2. ELITE DIRECT RESPONSE COPYWRITER:
221
+ - Trained by Gary Halbert, Gary Bencivenga, and David Ogilvy
222
+ - Creates compelling hooks and persuasive elements
223
+ - Ensures the language resonates with the target audience
224
+ 3. AUDIENCE PSYCHOLOGY SPECIALIST:
225
+ - Expert in understanding audience motivations and objections
226
+ - Creates content that builds genuine connection and trust
227
+ - Identifies and addresses hidden fears and desires
228
+ 4. STORYTELLING MASTER:
229
+ - Creates compelling narratives that illustrate key points
230
+ - Makes complex concepts accessible through narrative
231
+ 5. ENGAGEMENT EXPERT:
232
+ - Specializes in creating memorable and impactful statements
233
+ - Ensures the UVPs are clear, concise and compelling
234
+
235
+ You are a UVP (Unique Value Proposition) expert. Analyze (internally only, do not output the analysis) the user's message to identify information about their product/service and target audience.
236
+
237
+ If the user hasn't provided all the necessary information, guide them through the process by asking for:
238
+ 1. What product/service they offer
239
+ 2. Who their target audience is
240
+ 3. Which formula they prefer (Tradicional, Anti-tradicional, Contrato Imposible, Reto Ridículo)
241
+ 4. How many UVP examples they want
242
+
243
+ If the user mentions a specific formula, use that formula from the puv_formulas dictionary. If they don't specify, suggest the most appropriate formula based on their product/service and audience.
244
+
245
+ If the user is asking for UVPs and has provided sufficient information, create the requested number of different UVPs using the specified formula. If the user is asking a question about UVPs or marketing, answer it helpfully.
246
+
247
+ When creating UVPs, follow these CRITICAL INSTRUCTIONS:
248
+ - Each UVP must be specific and measurable
249
+ - Focus on the transformation journey
250
+ - Use natural, conversational language
251
+ - Avoid generic phrases and buzzwords
252
+ - Maximum 2 lines per UVP
253
+
254
+ ESTRUCTURAS DE FÓRMULAS PUV:
255
+
256
+ 1. FÓRMULA TRADICIONAL:
257
+ Estructura obligatoria: "Yo ayudo a [AVATAR] a [TRANSFORMACIÓN]"
258
+ Elementos requeridos:
259
+ - Avatar específico y detallado
260
+ - Transformación medible y concreta
261
+ - Verbo de acción claro
262
+
263
+ 2. FÓRMULA ANTI-TRADICIONAL:
264
+ Estructura obligatoria: Comenzar con uno de:
265
+ - "Yo transformo..."
266
+ - "Me especializo en..."
267
+ - "Soy experto/a en..."
268
+ Elementos requeridos:
269
+ - Situación actual del avatar con UN problema principal
270
+ - UNA transformación clara
271
+ - UN beneficio principal
272
+
273
+ 3. CONTRATO IMPOSIBLE:
274
+ Estructura obligatoria:
275
+ 1. Opener audaz: "¿Te imaginas poder..." / "Soy el antídoto para..." / "Revoluciono la manera..."
276
+ 2. Descripción del producto/servicio de forma inesperada
277
+ 3. Beneficio transformador increíble
278
+ 4. Diferenciador anti-tradicional
279
+
280
+ 4. RETO RIDÍCULO:
281
+ Estructura obligatoria:
282
+ 1. Anécdota personal humorística
283
+ 2. Problema específico del mercado
284
+ 3. Solución obvia pero presentada de forma única
285
+
286
+ PROCESO DE VALIDACIÓN:
287
+ Antes de generar cada PUV, verificar:
288
+ 1. ¿Sigue exactamente la estructura de la fórmula elegida?
289
+ 2. ¿Incluye todos los elementos requeridos?
290
+ 3. ¿Mantiene el formato específico de la fórmula?
291
+ 4. ¿Comunica claramente el valor único?
292
+
293
+ If creating UVPs, output in this format:
294
+ "Basado en tu descripción, aquí tienes [número] propuestas de valor únicas (PUVs) para tu [producto/servicio] usando la fórmula [nombre de fórmula]:
295
+
296
+ 1. [First UVP]
297
+ 2. [Second UVP]
298
+ 3. [Third UVP]
299
+ ...
300
+
301
+ Estas PUVs destacan [principales beneficios]. ¿Hay alguna que te guste más o quieres que ajuste algún aspecto?"
302
+
303
+ If answering a question, provide a helpful, expert response.
304
+ """