Spaces:
Running
Running
File size: 12,525 Bytes
c76bbac e75a09b c76bbac a339470 956fbae 348d961 a316975 b1cf5e1 348d961 b1cf5e1 fa342d1 c0073a3 956fbae 9bd45f9 5722b78 e61bf12 5722b78 f6214f2 5722b78 f6214f2 5722b78 11b06cd a316975 11b06cd 956fbae dc6ebfc e0af504 dc6ebfc 956fbae dc6ebfc 956fbae ea00e74 956fbae 650485d 956fbae 97cb8fc e369da7 956fbae e43c82c 11b06cd e43c82c 956fbae e369da7 956fbae 97cb8fc a316975 d5a01fe 956fbae a316975 956fbae a316975 |
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 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 |
import time
import os
import joblib
import streamlit as st
import google.generativeai as genai
from dotenv import load_dotenv
from puv_formulas import puv_formulas
from system_prompts import get_puv_system_prompt, get_puv_expert_prompt
from session_state import SessionState
# Inicializar el estado de la sesión
state = SessionState()
# Función para detectar saludos y generar respuestas personalizadas
def is_greeting(text):
"""Detecta si el texto es un saludo simple"""
text = text.lower().strip()
greetings = ['hola', 'hey', 'saludos', 'buenos días', 'buenas tardes', 'buenas noches', 'hi', 'hello']
return any(greeting in text for greeting in greetings) and len(text.split()) < 4
def get_greeting_response():
"""Genera una respuesta amigable para saludos"""
return """¡Hola! 😊 ¡Qué bueno verte por aquí!
Soy RoboCopy, tu asistente personal para crear Propuestas Únicas de Valor que realmente conecten con tu audiencia.
Mi especialidad es ayudarte a destacar lo que hace único a tu negocio:
• Transformar tus características en beneficios irresistibles
• Crear mensajes que capturan la atención inmediata de tus clientes ideales
• Diferenciarte de la competencia con palabras que venden
¿Te gustaría que continuemos trabajando en tu Propuesta Única de Valor o tienes alguna otra pregunta?"""
# Función para procesar mensajes (unifica la lógica de procesamiento)
def process_message(prompt, is_example=False):
"""Procesa un mensaje del usuario, ya sea directo o de un ejemplo"""
# Guardar el chat para después si es nuevo
if state.chat_id not in past_chats.keys():
# Es una nueva conversación, generemos un título basado en el primer mensaje
temp_title = f'SesiónChat-{state.chat_id}'
past_chats[state.chat_id] = temp_title
# Generar título para el chat
generated_title = state.generate_chat_title(prompt)
# Actualizamos el título en past_chats
if generated_title:
state.chat_title = generated_title
past_chats[state.chat_id] = generated_title
else:
state.chat_title = temp_title
else:
# Ya existe esta conversación, usamos el título guardado
state.chat_title = past_chats[state.chat_id]
joblib.dump(past_chats, 'data/past_chats_list')
# Mostrar mensaje del usuario
with st.chat_message('user', avatar=USER_AVATAR_ICON):
st.markdown(prompt)
# Añadir mensaje del usuario al historial
state.add_message('user', prompt, USER_AVATAR_ICON)
# Verificar si es un saludo simple
if is_greeting(prompt):
# Mostrar respuesta personalizada para saludos
greeting_response = get_greeting_response()
with st.chat_message(name=MODEL_ROLE, avatar=AI_AVATAR_ICON):
st.markdown(greeting_response)
# Añadir respuesta al historial
state.add_message(
role=MODEL_ROLE,
content=greeting_response,
avatar=AI_AVATAR_ICON,
)
state.save_chat_history()
return
# Procesar respuesta del modelo
if prompt.strip():
# Obtener el prompt del experto
puv_expert_prompt = get_puv_expert_prompt()
# Combinar el prompt del experto con el mensaje del usuario
enhanced_prompt = f"{puv_expert_prompt}\n\nUser message: {prompt}"
with st.chat_message(MODEL_ROLE, avatar=AI_AVATAR_ICON):
try:
if is_example:
# Para ejemplos, no necesitamos streaming
response = state.chat.send_message(prompt)
st.markdown(response.text)
# Añadir respuesta al historial
state.add_message(MODEL_ROLE, response.text, AI_AVATAR_ICON)
else:
# Para entrada directa, usamos streaming
response = state.chat.send_message(
enhanced_prompt,
stream=True,
)
message_placeholder = st.empty()
full_response = ''
# Añadir indicador de "escribiendo..."
typing_indicator = st.empty()
typing_indicator.markdown("*Generando respuesta...*")
# Mostrar respuesta por fragmentos
for chunk in response:
for ch in chunk.text:
full_response += ch
time.sleep(0.01)
message_placeholder.write(full_response + '▌')
# Eliminar indicador de escritura
typing_indicator.empty()
# Mostrar respuesta completa
message_placeholder.write(full_response)
# Añadir respuesta al historial
state.add_message(
role=MODEL_ROLE,
content=state.chat.history[-1].parts[0].text,
avatar=AI_AVATAR_ICON,
)
state.gemini_history = state.chat.history
# Guardar historial actualizado
state.save_chat_history()
except ValueError as e:
st.error("Error: El mensaje no puede estar vacío. Por favor, escribe algo.")
# Función para cargar CSS personalizado
def load_css(file_path):
with open(file_path) as f:
st.markdown(f'<style>{f.read()}</style>', unsafe_allow_html=True)
# Intentar cargar el CSS personalizado con ruta absoluta para mayor seguridad
try:
css_path = os.path.join(os.path.dirname(__file__), 'static', 'css', 'style.css')
load_css(css_path)
except Exception as e:
print(f"Error al cargar CSS: {e}")
# Si el archivo no existe, crear un estilo básico en línea
st.markdown("""
<style>
.robocopy-title {
color: #4ECDC4 !important;
font-weight: bold;
font-size: 2em;
}
</style>
""", unsafe_allow_html=True)
# Función de utilidad para mostrar la carátula inicial
def display_initial_header():
col1, col2, col3 = st.columns([1, 2, 1])
with col2:
# Centrar la imagen
st.markdown("""
<style>
div.stImage {
text-align: center;
display: block;
margin-left: auto;
margin-right: auto;
}
</style>
""", unsafe_allow_html=True)
st.image("robocopy_logo.png", width=300, use_container_width=True)
# Título
st.markdown("""
<div style='text-align: center; margin-top: -35px; width: 100%;'>
<h1 class='robocopy-title' style='width: 100%; text-align: center;'>PUV Creator</h1>
</div>
""", unsafe_allow_html=True)
# Subtítulo
st.markdown("""
<div style='text-align: center; width: 100%;'>
<p style='font-size: 16px; color: #4ECDC4; width: 100%; text-align: center;'>By Jesús Cabrera</p>
</div>
""", unsafe_allow_html=True)
# Descripción (ahora fuera de la columna para ocupar todo el ancho)
st.markdown("""
<div style='text-align: center; width: 100%;'>
<p style='font-size: 16px; background-color: #1E3A5F; padding: 12px; border-radius: 8px; margin-top: 10px; color: #4ECDC4; width: 100%; text-align: center; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);'>
🎯 Experto en crear Propuestas de Valor Únicas que convierten audiencia en clientes
</p>
</div>
""", unsafe_allow_html=True)
# Función para mostrar ejemplos de preguntas
def display_examples():
ejemplos = [
{"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"},
{"texto": "¿Cómo puedo crear mi PUV? 📝", "prompt": "Guíame paso a paso en el proceso de crear una Propuesta de Valor Única efectiva"},
{"texto": "¿Qué elementos debe tener mi PUV? ✨", "prompt": "¿Cuáles son los elementos esenciales que debe incluir una Propuesta de Valor Única exitosa?"},
{"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"}
]
# Crear los botones de ejemplo
cols = st.columns(4)
for idx, ejemplo in enumerate(ejemplos):
with cols[idx]:
if st.button(ejemplo["texto"], key=f"ejemplo_{idx}", help=ejemplo["prompt"]):
state.prompt = ejemplo["prompt"]
st.rerun()
# Cargar variables de entorno
load_dotenv()
GOOGLE_API_KEY=os.environ.get('GOOGLE_API_KEY')
genai.configure(api_key=GOOGLE_API_KEY)
# Configuración de la aplicación
new_chat_id = f'{time.time()}'
MODEL_ROLE = 'ai'
AI_AVATAR_ICON = '🤖' # Cambia el emoji por uno de robot para coincidir con tu logo
USER_AVATAR_ICON = '👤' # Añade un avatar para el usuario
# Crear carpeta de datos si no existe
try:
os.mkdir('data/')
except:
# data/ folder already exists
pass
# Cargar chats anteriores
try:
past_chats: dict = joblib.load('data/past_chats_list')
except:
past_chats = {}
# Sidebar para seleccionar chats anteriores
with st.sidebar:
st.write('# Chats Anteriores')
if state.chat_id is None:
state.chat_id = st.selectbox(
label='Selecciona un chat anterior',
options=[new_chat_id] + list(past_chats.keys()),
format_func=lambda x: past_chats.get(x, 'Nuevo Chat'),
placeholder='_',
)
else:
# This will happen the first time AI response comes in
state.chat_id = st.selectbox(
label='Selecciona un chat anterior',
options=[new_chat_id, state.chat_id] + list(past_chats.keys()),
index=1,
format_func=lambda x: past_chats.get(x, 'Nuevo Chat' if x != state.chat_id else state.chat_title),
placeholder='_',
)
# Save new chats after a message has been sent to AI
state.chat_title = f'SesiónChat-{state.chat_id}'
# Cargar historial del chat
state.load_chat_history()
# Inicializar el modelo
state.initialize_model('gemini-2.0-flash')
state.initialize_chat()
# Mostrar mensajes del historial
for message in state.messages:
with st.chat_message(
name=message['role'],
avatar=message.get('avatar'),
):
st.markdown(message['content'])
# Mensaje inicial del sistema si es un chat nuevo
if not state.has_messages():
# Mostrar la carátula inicial con el logo centrado
display_initial_header()
# Mostrar los ejemplos
display_examples()
# Inicializar el chat con los prompts del sistema
system_prompt = get_puv_system_prompt()
expert_prompt = get_puv_expert_prompt()
state.chat.send_message(system_prompt)
state.chat.send_message(expert_prompt)
# Solo añadir el mensaje inicial si no es un ejemplo
if not state.has_prompt():
state.add_message(
role=MODEL_ROLE,
content="""👋 Hola, soy RoboCopy.
Tu asistente especializado en crear Propuestas de Valor Únicas (PUVs) que convierten visitantes en clientes.
Puedo ayudarte a:
✅ Crear PUVs impactantes usando diferentes fórmulas
✅ Analizar tu producto/servicio para destacar su valor único
✅ Identificar los elementos clave que atraerán a tu audiencia
✅ Optimizar tu mensaje para diferentes segmentos de mercado
Para empezar a crear PUVs efectivas, necesito conocer:
- ¿Qué producto o servicio ofreces?
- ¿A quién va dirigido? (describe tu público objetivo)
Espero ansioso tu respuesta, para crear tu Propuesta Única de Valor.""",
avatar=AI_AVATAR_ICON,
)
# Procesar entrada del usuario
if prompt := st.chat_input('Describe tu producto/servicio y audiencia objetivo...'):
process_message(prompt, is_example=False)
# Procesar ejemplos seleccionados
if state.has_prompt():
prompt = state.prompt
process_message(prompt, is_example=True)
# Limpiar el prompt
state.clear_prompt() |