JeCabrera commited on
Commit
a3fa03b
·
verified ·
1 Parent(s): b2dd253

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +87 -15
app.py CHANGED
@@ -13,33 +13,49 @@ state = SessionState()
13
 
14
  # Función para detectar saludos y generar respuestas personalizadas
15
  def is_greeting(text):
 
16
  text = text.lower().strip()
17
  greetings = ['hola', 'hey', 'saludos', 'buenos días', 'buenas tardes', 'buenas noches', 'hi', 'hello']
 
 
 
18
  is_simple_greeting = any(greeting in text for greeting in greetings) and len(text.split()) < 4
19
  return is_simple_greeting and len(state.messages) == 0
20
 
 
21
  def process_message(prompt, is_example=False):
 
22
  handle_chat_title(prompt)
 
23
  with st.chat_message('user', avatar=USER_AVATAR_ICON):
24
  st.markdown(prompt)
 
25
  state.add_message('user', prompt, USER_AVATAR_ICON)
 
 
26
  enhanced_prompt = get_enhanced_prompt(prompt, is_example)
 
 
27
  with st.chat_message(MODEL_ROLE, avatar=AI_AVATAR_ICON):
28
  try:
29
  message_placeholder = st.empty()
30
  typing_indicator = st.empty()
31
  typing_indicator.markdown("*Generando respuesta...*")
 
32
  response = state.send_message(enhanced_prompt)
33
  full_response = stream_response(response, message_placeholder, typing_indicator)
 
34
  if full_response:
35
  state.add_message(MODEL_ROLE, full_response, AI_AVATAR_ICON)
36
  state.gemini_history = state.chat.history
37
  state.save_chat_history()
 
38
  except Exception as e:
39
  st.error(f"Error en el streaming: {str(e)}")
40
  return
41
 
42
  def handle_chat_title(prompt):
 
43
  if state.chat_id not in past_chats:
44
  temp_title = f'SesiónChat-{state.chat_id}'
45
  generated_title = state.generate_chat_title(prompt)
@@ -50,13 +66,34 @@ def handle_chat_title(prompt):
50
  joblib.dump(past_chats, 'data/past_chats_list')
51
 
52
  def get_enhanced_prompt(prompt, is_example):
 
53
  if is_greeting(prompt):
54
  return f"El usuario te ha saludado con '{prompt}'. Preséntate brevemente, explica qué es una PUV en 1-2 líneas, y haz 1-2 preguntas iniciales para comenzar a crear la PUV del usuario (como a quién se dirige su producto/servicio o qué ofrece). Sé amigable, breve y toma la iniciativa como el experto que eres."
55
  elif is_example:
56
  return f"El usuario ha seleccionado un ejemplo: '{prompt}'. Responde de manera conversacional y sencilla, como si estuvieras hablando con un amigo. Evita tecnicismos innecesarios. Enfócate en dar información práctica que ayude al usuario a crear su PUV. Usa ejemplos concretos cuando sea posible. Termina tu respuesta con una pregunta que invite al usuario a compartir información sobre su negocio para poder ayudarle a crear su PUV personalizada."
57
  return prompt
58
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
  def stream_response(response, message_placeholder, typing_indicator):
 
60
  full_response = ''
61
  try:
62
  for chunk in response:
@@ -69,19 +106,23 @@ def stream_response(response, message_placeholder, typing_indicator):
69
  except Exception as e:
70
  st.error(f"Error en el streaming: {str(e)}")
71
  return ''
 
72
  typing_indicator.empty()
73
  message_placeholder.markdown(full_response)
74
  return full_response
75
 
 
76
  def load_css(file_path):
77
  with open(file_path) as f:
78
  st.markdown(f'<style>{f.read()}</style>', unsafe_allow_html=True)
79
 
 
80
  try:
81
  css_path = os.path.join(os.path.dirname(__file__), 'static', 'css', 'style.css')
82
  load_css(css_path)
83
  except Exception as e:
84
  print(f"Error al cargar CSS: {e}")
 
85
  st.markdown("""
86
  <style>
87
  .robocopy-title {
@@ -93,9 +134,11 @@ except Exception as e:
93
  </style>
94
  """, unsafe_allow_html=True)
95
 
 
96
  def display_initial_header():
97
  col1, col2, col3 = st.columns([1, 2, 1])
98
  with col2:
 
99
  st.markdown("""
100
  <style>
101
  div.stImage {
@@ -107,16 +150,22 @@ def display_initial_header():
107
  </style>
108
  """, unsafe_allow_html=True)
109
  st.image("robocopy_logo.png", width=300, use_container_width=True)
 
 
110
  st.markdown("""
111
  <div style='text-align: center; margin-top: -35px; width: 100%;'>
112
  <h1 class='robocopy-title' style='width: 100%; text-align: center; color: white !important; font-size: clamp(2.5em, 5vw, 4em); line-height: 1.2;'>PUV Creator</h1>
113
  </div>
114
  """, unsafe_allow_html=True)
 
 
115
  st.markdown("""
116
  <div style='text-align: center; width: 100%;'>
117
  <p style='font-size: 16px; color: white; width: 100%; text-align: center; margin-top: -20px;'>By Jesús Cabrera</p>
118
  </div>
119
  """, unsafe_allow_html=True)
 
 
120
  st.markdown("""
121
  <div style='text-align: center; width: 100%;'>
122
  <p style='font-size: 16px; background-color: transparent; padding: 12px; border-radius: 8px; margin-top: -20px; color: white; width: 100%; text-align: center;'>
@@ -125,6 +174,7 @@ def display_initial_header():
125
  </div>
126
  """, unsafe_allow_html=True)
127
 
 
128
  def display_examples():
129
  ejemplos = [
130
  {"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"},
@@ -132,6 +182,8 @@ def display_examples():
132
  {"texto": "¿Qué elementos debe tener mi PUV? ✨", "prompt": "¿Cuáles son los elementos esenciales que debe incluir una Propuesta de Valor Única exitosa?"},
133
  {"texto": "¿Cuál es la mejor fórmula para mi caso? 🤔", "prompt": "Ayúdame a elegir la fórmula más adecuada para mi Propuesta de Valor según mi tipo de negocio"}
134
  ]
 
 
135
  cols = st.columns(4)
136
  for idx, ejemplo in enumerate(ejemplos):
137
  with cols[idx]:
@@ -147,19 +199,23 @@ genai.configure(api_key=GOOGLE_API_KEY)
147
  # Configuración de la aplicación
148
  new_chat_id = f'{time.time()}'
149
  MODEL_ROLE = 'ai'
150
- AI_AVATAR_ICON = '🤖'
151
- USER_AVATAR_ICON = '👤'
152
 
 
153
  try:
154
  os.mkdir('data/')
155
  except:
 
156
  pass
157
 
 
158
  try:
159
  past_chats: dict = joblib.load('data/past_chats_list')
160
  except:
161
  past_chats = {}
162
 
 
163
  with st.sidebar:
164
  st.write('# Chats Anteriores')
165
  if state.chat_id is None:
@@ -170,6 +226,7 @@ with st.sidebar:
170
  placeholder='_',
171
  )
172
  else:
 
173
  state.chat_id = st.selectbox(
174
  label='Selecciona un chat anterior',
175
  options=[new_chat_id, state.chat_id] + list(past_chats.keys()),
@@ -177,31 +234,46 @@ with st.sidebar:
177
  format_func=lambda x: past_chats.get(x, 'Nuevo Chat' if x != state.chat_id else state.chat_title),
178
  placeholder='_',
179
  )
 
180
  state.chat_title = f'SesiónChat-{state.chat_id}'
181
 
 
182
  state.load_chat_history()
 
 
183
  state.initialize_model('gemini-2.0-flash')
184
- state.initialize_chat()
185
 
 
186
  for message in state.messages:
187
- with st.chat_message(name=message['role'], avatar=message.get('avatar')):
 
 
 
188
  st.markdown(message['content'])
189
 
190
- # NUEVO BLOQUE MODIFICADO
191
  if not state.has_messages():
 
192
  display_initial_header()
 
 
193
  display_examples()
194
- if state.prompt:
195
- process_message(state.prompt, is_example=True)
196
- state.clear_prompt()
197
  system_prompt = get_unified_puv_prompt()
198
- if state.chat is not None:
199
  state.chat.send_message(system_prompt)
200
  else:
201
  st.error("Error: No se pudo inicializar el chat correctamente.")
202
- else:
203
- if prompt := st.chat_input('Describe tu producto/servicio y audiencia objetivo...'):
204
- process_message(prompt, is_example=False)
205
- if state.has_prompt():
206
- process_message(state.prompt, is_example=True)
207
- state.clear_prompt()
 
 
 
 
 
 
13
 
14
  # Función para detectar saludos y generar respuestas personalizadas
15
  def is_greeting(text):
16
+ """Detecta si el texto es un saludo simple"""
17
  text = text.lower().strip()
18
  greetings = ['hola', 'hey', 'saludos', 'buenos días', 'buenas tardes', 'buenas noches', 'hi', 'hello']
19
+
20
+ # Solo considerar como saludo si es el primer mensaje del usuario
21
+ # y es un saludo simple
22
  is_simple_greeting = any(greeting in text for greeting in greetings) and len(text.split()) < 4
23
  return is_simple_greeting and len(state.messages) == 0
24
 
25
+ # Función para procesar mensajes (unifica la lógica de procesamiento)
26
  def process_message(prompt, is_example=False):
27
+ """Procesa un mensaje del usuario, ya sea directo o de un ejemplo"""
28
  handle_chat_title(prompt)
29
+
30
  with st.chat_message('user', avatar=USER_AVATAR_ICON):
31
  st.markdown(prompt)
32
+
33
  state.add_message('user', prompt, USER_AVATAR_ICON)
34
+
35
+ # Obtener el prompt mejorado primero
36
  enhanced_prompt = get_enhanced_prompt(prompt, is_example)
37
+
38
+ # Mover la respuesta del modelo después del mensaje del usuario
39
  with st.chat_message(MODEL_ROLE, avatar=AI_AVATAR_ICON):
40
  try:
41
  message_placeholder = st.empty()
42
  typing_indicator = st.empty()
43
  typing_indicator.markdown("*Generando respuesta...*")
44
+
45
  response = state.send_message(enhanced_prompt)
46
  full_response = stream_response(response, message_placeholder, typing_indicator)
47
+
48
  if full_response:
49
  state.add_message(MODEL_ROLE, full_response, AI_AVATAR_ICON)
50
  state.gemini_history = state.chat.history
51
  state.save_chat_history()
52
+
53
  except Exception as e:
54
  st.error(f"Error en el streaming: {str(e)}")
55
  return
56
 
57
  def handle_chat_title(prompt):
58
+ """Maneja la lógica del título del chat"""
59
  if state.chat_id not in past_chats:
60
  temp_title = f'SesiónChat-{state.chat_id}'
61
  generated_title = state.generate_chat_title(prompt)
 
66
  joblib.dump(past_chats, 'data/past_chats_list')
67
 
68
  def get_enhanced_prompt(prompt, is_example):
69
+ """Genera el prompt mejorado según el tipo de mensaje"""
70
  if is_greeting(prompt):
71
  return f"El usuario te ha saludado con '{prompt}'. Preséntate brevemente, explica qué es una PUV en 1-2 líneas, y haz 1-2 preguntas iniciales para comenzar a crear la PUV del usuario (como a quién se dirige su producto/servicio o qué ofrece). Sé amigable, breve y toma la iniciativa como el experto que eres."
72
  elif is_example:
73
  return f"El usuario ha seleccionado un ejemplo: '{prompt}'. Responde de manera conversacional y sencilla, como si estuvieras hablando con un amigo. Evita tecnicismos innecesarios. Enfócate en dar información práctica que ayude al usuario a crear su PUV. Usa ejemplos concretos cuando sea posible. Termina tu respuesta con una pregunta que invite al usuario a compartir información sobre su negocio para poder ayudarle a crear su PUV personalizada."
74
  return prompt
75
 
76
+ def process_model_response(enhanced_prompt):
77
+ """Procesa la respuesta del modelo"""
78
+ with st.chat_message(MODEL_ROLE, avatar=AI_AVATAR_ICON):
79
+ try:
80
+ message_placeholder = st.empty()
81
+ typing_indicator = st.empty()
82
+ typing_indicator.markdown("*Generando respuesta...*")
83
+
84
+ response = state.send_message(enhanced_prompt)
85
+ full_response = stream_response(response, message_placeholder, typing_indicator)
86
+
87
+ # Actualizar historial
88
+ state.add_message(role=MODEL_ROLE, content=full_response, avatar=AI_AVATAR_ICON)
89
+ state.gemini_history = state.chat.history
90
+ state.save_chat_history()
91
+
92
+ except Exception as e:
93
+ st.error(f"Error: {str(e)}")
94
+
95
  def stream_response(response, message_placeholder, typing_indicator):
96
+ """Maneja el streaming de la respuesta"""
97
  full_response = ''
98
  try:
99
  for chunk in response:
 
106
  except Exception as e:
107
  st.error(f"Error en el streaming: {str(e)}")
108
  return ''
109
+
110
  typing_indicator.empty()
111
  message_placeholder.markdown(full_response)
112
  return full_response
113
 
114
+ # Función para cargar CSS personalizado
115
  def load_css(file_path):
116
  with open(file_path) as f:
117
  st.markdown(f'<style>{f.read()}</style>', unsafe_allow_html=True)
118
 
119
+ # Intentar cargar el CSS personalizado con ruta absoluta para mayor seguridad
120
  try:
121
  css_path = os.path.join(os.path.dirname(__file__), 'static', 'css', 'style.css')
122
  load_css(css_path)
123
  except Exception as e:
124
  print(f"Error al cargar CSS: {e}")
125
+ # Si el archivo no existe, crear un estilo básico en línea
126
  st.markdown("""
127
  <style>
128
  .robocopy-title {
 
134
  </style>
135
  """, unsafe_allow_html=True)
136
 
137
+ # Función de utilidad para mostrar la carátula inicial
138
  def display_initial_header():
139
  col1, col2, col3 = st.columns([1, 2, 1])
140
  with col2:
141
+ # Centrar la imagen
142
  st.markdown("""
143
  <style>
144
  div.stImage {
 
150
  </style>
151
  """, unsafe_allow_html=True)
152
  st.image("robocopy_logo.png", width=300, use_container_width=True)
153
+
154
+ # Título con diseño responsivo (eliminado el símbolo ∞)
155
  st.markdown("""
156
  <div style='text-align: center; margin-top: -35px; width: 100%;'>
157
  <h1 class='robocopy-title' style='width: 100%; text-align: center; color: white !important; font-size: clamp(2.5em, 5vw, 4em); line-height: 1.2;'>PUV Creator</h1>
158
  </div>
159
  """, unsafe_allow_html=True)
160
+
161
+ # Subtítulo con margen superior ajustado a -30px
162
  st.markdown("""
163
  <div style='text-align: center; width: 100%;'>
164
  <p style='font-size: 16px; color: white; width: 100%; text-align: center; margin-top: -20px;'>By Jesús Cabrera</p>
165
  </div>
166
  """, unsafe_allow_html=True)
167
+
168
+ # Descripción con fondo eliminado y margen superior ajustado a -20px
169
  st.markdown("""
170
  <div style='text-align: center; width: 100%;'>
171
  <p style='font-size: 16px; background-color: transparent; padding: 12px; border-radius: 8px; margin-top: -20px; color: white; width: 100%; text-align: center;'>
 
174
  </div>
175
  """, unsafe_allow_html=True)
176
 
177
+ # Función para mostrar ejemplos de preguntas
178
  def display_examples():
179
  ejemplos = [
180
  {"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"},
 
182
  {"texto": "¿Qué elementos debe tener mi PUV? ✨", "prompt": "¿Cuáles son los elementos esenciales que debe incluir una Propuesta de Valor Única exitosa?"},
183
  {"texto": "¿Cuál es la mejor fórmula para mi caso? 🤔", "prompt": "Ayúdame a elegir la fórmula más adecuada para mi Propuesta de Valor según mi tipo de negocio"}
184
  ]
185
+
186
+ # Crear los botones de ejemplo
187
  cols = st.columns(4)
188
  for idx, ejemplo in enumerate(ejemplos):
189
  with cols[idx]:
 
199
  # Configuración de la aplicación
200
  new_chat_id = f'{time.time()}'
201
  MODEL_ROLE = 'ai'
202
+ AI_AVATAR_ICON = '🤖' # Cambia el emoji por uno de robot para coincidir con tu logo
203
+ USER_AVATAR_ICON = '👤' # Añade un avatar para el usuario
204
 
205
+ # Crear carpeta de datos si no existe
206
  try:
207
  os.mkdir('data/')
208
  except:
209
+ # data/ folder already exists
210
  pass
211
 
212
+ # Cargar chats anteriores
213
  try:
214
  past_chats: dict = joblib.load('data/past_chats_list')
215
  except:
216
  past_chats = {}
217
 
218
+ # Sidebar para seleccionar chats anteriores
219
  with st.sidebar:
220
  st.write('# Chats Anteriores')
221
  if state.chat_id is None:
 
226
  placeholder='_',
227
  )
228
  else:
229
+ # This will happen the first time AI response comes in
230
  state.chat_id = st.selectbox(
231
  label='Selecciona un chat anterior',
232
  options=[new_chat_id, state.chat_id] + list(past_chats.keys()),
 
234
  format_func=lambda x: past_chats.get(x, 'Nuevo Chat' if x != state.chat_id else state.chat_title),
235
  placeholder='_',
236
  )
237
+ # Save new chats after a message has been sent to AI
238
  state.chat_title = f'SesiónChat-{state.chat_id}'
239
 
240
+ # Cargar historial del chat
241
  state.load_chat_history()
242
+
243
+ # Inicializar el modelo y el chat
244
  state.initialize_model('gemini-2.0-flash')
245
+ state.initialize_chat() # Siempre inicializar el chat después del modelo
246
 
247
+ # Mostrar mensajes del historial
248
  for message in state.messages:
249
+ with st.chat_message(
250
+ name=message['role'],
251
+ avatar=message.get('avatar'),
252
+ ):
253
  st.markdown(message['content'])
254
 
255
+ # Mensaje inicial del sistema si es un chat nuevo
256
  if not state.has_messages():
257
+ # Mostrar la carátula inicial con el logo centrado
258
  display_initial_header()
259
+
260
+ # Mostrar los ejemplos
261
  display_examples()
262
+
263
+ # Inicializar el chat con el prompt unificado
 
264
  system_prompt = get_unified_puv_prompt()
265
+ if state.chat is not None: # Verificación adicional de seguridad
266
  state.chat.send_message(system_prompt)
267
  else:
268
  st.error("Error: No se pudo inicializar el chat correctamente.")
269
+
270
+ # Procesar entrada del usuario
271
+ if prompt := st.chat_input('Describe tu producto/servicio y audiencia objetivo...'):
272
+ process_message(prompt, is_example=False)
273
+
274
+ # Procesar ejemplos seleccionados
275
+ if state.has_prompt():
276
+ prompt = state.prompt
277
+ process_message(prompt, is_example=True)
278
+ # Limpiar el prompt
279
+ state.clear_prompt()