Spaces:
Sleeping
Sleeping
Upload 12 files
Browse files- system_prompts.py +279 -286
system_prompts.py
CHANGED
@@ -1,286 +1,279 @@
|
|
1 |
-
|
2 |
-
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
-
|
249 |
-
|
250 |
-
|
251 |
-
|
252 |
-
|
253 |
-
|
254 |
-
|
255 |
-
|
256 |
-
|
257 |
-
|
258 |
-
|
259 |
-
|
260 |
-
|
261 |
-
|
262 |
-
|
263 |
-
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
|
272 |
-
|
273 |
-
|
274 |
-
|
275 |
-
|
276 |
-
|
277 |
-
|
278 |
-
|
279 |
-
|
280 |
-
Elementos clave:
|
281 |
-
- Descripción ultra-específica del avatar enfocada en UN punto de dolor
|
282 |
-
- Promesa de transformación clara con UN beneficio principal
|
283 |
-
- Filtrado natural de clientes
|
284 |
-
- Lenguaje simple y directo
|
285 |
-
- Ser claro y conciso
|
286 |
-
"""
|
|
|
1 |
+
import time
|
2 |
+
import os
|
3 |
+
import joblib
|
4 |
+
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_unified_puv_prompt
|
9 |
+
from session_state import SessionState
|
10 |
+
|
11 |
+
# Inicializar el estado de la sesión
|
12 |
+
state = SessionState()
|
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)
|
62 |
+
state.chat_title = generated_title or temp_title
|
63 |
+
past_chats[state.chat_id] = state.chat_title
|
64 |
+
else:
|
65 |
+
state.chat_title = past_chats[state.chat_id]
|
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:
|
100 |
+
if chunk.text:
|
101 |
+
for ch in chunk.text:
|
102 |
+
full_response += ch
|
103 |
+
time.sleep(0.01)
|
104 |
+
typing_indicator.markdown("*Generando respuesta...*")
|
105 |
+
message_placeholder.markdown(full_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 {
|
129 |
+
color: white !important;
|
130 |
+
font-weight: bold;
|
131 |
+
font-size: clamp(2.5em, 5vw, 4em);
|
132 |
+
line-height: 1.2;
|
133 |
+
}
|
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 {
|
145 |
+
text-align: center;
|
146 |
+
display: block;
|
147 |
+
margin-left: auto;
|
148 |
+
margin-right: auto;
|
149 |
+
}
|
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;'>
|
172 |
+
🎯 Experto en crear Propuestas de Valor Únicas que convierten audiencia en clientes
|
173 |
+
</p>
|
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"},
|
181 |
+
{"texto": "¿Cómo puedo crear mi PUV? 📝", "prompt": "Guíame paso a paso en el proceso de crear una Propuesta de Valor Única efectiva"},
|
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]:
|
190 |
+
if st.button(ejemplo["texto"], key=f"ejemplo_{idx}", help=ejemplo["prompt"]):
|
191 |
+
state.prompt = ejemplo["prompt"]
|
192 |
+
st.rerun()
|
193 |
+
|
194 |
+
# Cargar variables de entorno
|
195 |
+
load_dotenv()
|
196 |
+
GOOGLE_API_KEY=os.environ.get('GOOGLE_API_KEY')
|
197 |
+
genai.configure(api_key=GOOGLE_API_KEY)
|
198 |
+
|
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:
|
222 |
+
state.chat_id = st.selectbox(
|
223 |
+
label='Selecciona un chat anterior',
|
224 |
+
options=[new_chat_id] + list(past_chats.keys()),
|
225 |
+
format_func=lambda x: past_chats.get(x, 'Nuevo Chat'),
|
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()),
|
233 |
+
index=1,
|
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()
|
|
|
|
|
|
|
|
|
|
|
|
|
|