File size: 12,242 Bytes
c76bbac
 
 
 
e75a09b
c76bbac
a339470
956fbae
 
 
 
 
348d961
b1cf5e1
348d961
b1cf5e1
 
 
 
 
 
 
 
 
fa342d1
 
 
 
 
 
 
 
 
 
c0073a3
956fbae
 
9bd45f9
 
5722b78
 
 
 
 
 
 
 
 
 
 
e61bf12
5722b78
 
 
 
 
f6214f2
5722b78
 
 
 
 
 
f6214f2
5722b78
11b06cd
 
 
 
 
 
 
 
 
956fbae
 
 
dc6ebfc
e0af504
 
 
 
dc6ebfc
 
 
 
 
 
 
956fbae
dc6ebfc
 
956fbae
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
650485d
956fbae
 
 
 
 
 
 
 
97cb8fc
e369da7
956fbae
 
 
 
11b06cd
 
 
 
 
 
 
 
956fbae
11b06cd
956fbae
 
 
 
 
 
 
 
 
 
11b06cd
956fbae
 
e369da7
 
956fbae
97cb8fc
956fbae
 
b6b7f7a
956fbae
 
b6b7f7a
956fbae
 
 
 
 
 
 
 
 
b1cf5e1
b6b7f7a
956fbae
a249ce4
b1cf5e1
 
956fbae
5c64156
b6b7f7a
5c64156
956fbae
 
97cb8fc
956fbae
 
97cb8fc
 
 
 
956fbae
 
97cb8fc
d1e9ecf
b1cf5e1
d6a1a2a
956fbae
b1cf5e1
 
 
 
 
 
4c826ff
956fbae
b1cf5e1
97cb8fc
4c826ff
956fbae
97cb8fc
956fbae
923676c
956fbae
97cb8fc
956fbae
 
b1cf5e1
956fbae
 
b1cf5e1
 
956fbae
 
 
 
 
9456d19
956fbae
 
 
 
d5a01fe
956fbae
 
 
259916f
e369da7
956fbae
 
 
e369da7
 
956fbae
259916f
 
 
956fbae
 
259916f
956fbae
e369da7
e259740
 
956fbae
e259740
 
956fbae
 
e369da7
956fbae
 
e259740
 
259916f
956fbae
11b06cd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
325
326
327
328
329
330
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 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; border: 2px solid #4ECDC4; 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:
            
            1. ¿Qué producto o servicio ofreces?
            2. ¿A quién va dirigido? (describe tu público objetivo)
            3. ¿Qué fórmula prefieres usar? Puedo ofrecerte:
               - Tradicional: Clara y directa
               - Anti-tradicional: Innovadora y disruptiva
               - Contrato Imposible: Audaz y sorprendente
               - Reto Ridículo: Humorística y relatable
            4. ¿Cuántos ejemplos de PUVs necesitas?
            
            ¿Cómo quieres trabajar?
            """,
            avatar=AI_AVATAR_ICON,
        )

# Procesar entrada del usuario
if prompt := st.chat_input('Describe tu producto/servicio y audiencia objetivo...'):
    # 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)
    
    # 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}"
    
    # Enviar mensaje al modelo
    response = state.chat.send_message(
        enhanced_prompt,
        stream=True,
    )
    
    # Mostrar respuesta del asistente
    with st.chat_message(
        name=MODEL_ROLE,
        avatar=AI_AVATAR_ICON,
    ):
        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
    state.save_chat_history()

# Procesar ejemplos seleccionados
if state.has_prompt():
    prompt = state.prompt
    
    # Guardar el chat para después si es nuevo
    if state.chat_id not in past_chats.keys():
        temp_title = f'SesiónChat-{state.chat_id}'
        past_chats[state.chat_id] = temp_title
        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)
    
    # Procesar respuesta del modelo
    if prompt.strip():
        with st.chat_message(MODEL_ROLE, avatar=AI_AVATAR_ICON):
            try:
                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)
                
                # 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.")
    
    # Limpiar el prompt
    state.clear_prompt()

# 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 saludarte!

Soy el Asistente RoboCopy, especializado en crear Propuestas de Valor Únicas (PUVs) que transforman tu comunicación con clientes potenciales.

Puedo ayudarte a:
• Crear PUVs impactantes que destaquen tu oferta
• Analizar tu producto/servicio para encontrar su valor diferencial
• Adaptar tu mensaje a diferentes audiencias
• Aplicar fórmulas probadas de marketing persuasivo

¿Te gustaría que sigamos trabajando en tus Propuestas de Valor Únicas (PUVs) o tienes alguna otra pregunta en mente?"""