File size: 8,041 Bytes
c76bbac
 
 
 
e75a09b
c76bbac
5c64156
348d961
b1cf5e1
348d961
b1cf5e1
 
 
 
 
 
 
 
 
fa342d1
 
 
 
 
 
 
 
 
 
c0073a3
 
b1cf5e1
c0073a3
 
b1cf5e1
 
 
 
 
fa342d1
 
 
 
 
 
b1cf5e1
 
 
 
 
 
 
 
c76bbac
b1cf5e1
d8f563a
 
15d4fae
d8f563a
6a4a20b
b1cf5e1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c76bbac
b1cf5e1
 
 
 
 
 
 
 
b6b7f7a
5c64156
b6b7f7a
657617d
b6b7f7a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b1cf5e1
b6b7f7a
b1cf5e1
a6d440d
b1cf5e1
 
b6b7f7a
5c64156
b6b7f7a
5c64156
b6b7f7a
 
 
 
 
 
 
5c64156
 
 
 
d1e9ecf
 
 
 
bba5b0a
d6a1a2a
5c64156
d1e9ecf
 
 
b1cf5e1
d6a1a2a
b1cf5e1
 
 
 
 
 
 
4c826ff
b1cf5e1
 
 
4c826ff
b1cf5e1
bba5b0a
 
 
 
 
 
 
 
 
 
 
 
 
b1cf5e1
 
 
 
 
 
 
 
 
bba5b0a
b1cf5e1
 
 
bba5b0a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b1cf5e1
b6b7f7a
 
 
 
 
 
 
5c64156
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
import time
import os
import joblib
import streamlit as st
import google.generativeai as genai
from dotenv import load_dotenv
from system_prompts import get_puv_system_prompt  # Importar el prompt iterativo

# 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)

load_dotenv()
GOOGLE_API_KEY=os.environ.get('GOOGLE_API_KEY')
genai.configure(api_key=GOOGLE_API_KEY)

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

# Create a data/ folder if it doesn't already exist
try:
    os.mkdir('data/')
except:
    # data/ folder already exists
    pass

# Load past chats (if available)
try:
    past_chats: dict = joblib.load('data/past_chats_list')
except:
    past_chats = {}

# Sidebar allows a list of past chats
with st.sidebar:
    # Centrar el logo y eliminar el título de RoboCopy
    col1, col2, col3 = st.columns([1, 2, 1])
    with col2:
        st.image("assets/robocopy_logo.png", width=300)
    
    st.write('# Chats Anteriores')
    if st.session_state.get('chat_id') is None:
        st.session_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
        st.session_state.chat_id = st.selectbox(
            label='Selecciona un chat anterior',
            options=[new_chat_id, st.session_state.chat_id] + list(past_chats.keys()),
            index=1,
            format_func=lambda x: past_chats.get(x, 'Nuevo Chat' if x != st.session_state.chat_id else st.session_state.chat_title),
            placeholder='_',
        )
    # Save new chats after a message has been sent to AI
    # TODO: Give user a chance to name chat
    st.session_state.chat_title = f'SesiónChat-{st.session_state.chat_id}'

st.write('# Chatea con Gemini')

# Chat history (allows to ask multiple questions)
try:
    st.session_state.messages = joblib.load(
        f'data/{st.session_state.chat_id}-st_messages'
    )
    st.session_state.gemini_history = joblib.load(
        f'data/{st.session_state.chat_id}-gemini_messages'
    )
    print('old cache')
except:
    st.session_state.messages = []
    st.session_state.gemini_history = []
    print('new_cache made')
st.session_state.model = genai.GenerativeModel('gemini-2.0-flash')
st.session_state.chat = st.session_state.model.start_chat(
    history=st.session_state.gemini_history,
)

# Display chat messages from history on app rerun
for message in st.session_state.messages:
    with st.chat_message(
        name=message['role'],
        avatar=message.get('avatar'),
    ):
        st.markdown(message['content'])

# React to user input
if prompt := st.chat_input('¿En qué puedo ayudarte con tu Propuesta Única de Valor?'):
    # Save this as a chat for later
    if st.session_state.chat_id not in past_chats.keys():
        # Es una nueva conversación, generemos un título basado en el primer mensaje
        # Primero, guardamos un título temporal
        temp_title = f'SesiónChat-{st.session_state.chat_id}'
        past_chats[st.session_state.chat_id] = temp_title
        
        # Generamos un título basado en el contenido del mensaje
        try:
            # Usamos el mismo modelo para generar un título corto
            title_generator = genai.GenerativeModel('gemini-2.0-flash')
            title_response = title_generator.generate_content(
                f"Genera un título corto (máximo 5 palabras) que describa de qué trata esta consulta, sin usar comillas ni puntuación: '{prompt}'")
            
            # Obtenemos el título generado
            generated_title = title_response.text.strip()
            
            # Actualizamos el título en past_chats
            if generated_title:
                st.session_state.chat_title = generated_title
                past_chats[st.session_state.chat_id] = generated_title
            else:
                st.session_state.chat_title = temp_title
        except Exception as e:
            print(f"Error al generar título: {e}")
            st.session_state.chat_title = temp_title
    else:
        # Ya existe esta conversación, usamos el título guardado
        st.session_state.chat_title = past_chats[st.session_state.chat_id]
    
    joblib.dump(past_chats, 'data/past_chats_list')
    
    # Display user message in chat message container
    with st.chat_message('user', avatar=USER_AVATAR_ICON):
        st.markdown(prompt)
    
    # Add user message to chat history
    st.session_state.messages.append(
        dict(
            role='user',
            content=prompt,
        )
    )
    
    # Obtener el system prompt iterativo
    system_prompt = get_puv_system_prompt()
    
    # Crear una instancia del modelo con el system prompt
    model = genai.GenerativeModel(
        model_name='gemini-2.0-flash',
        system_instruction=system_prompt
    )
    
    # Enviar mensaje al AI con system prompt
    response_stream = model.generate_content(
        prompt,
        stream=True,
    )
    
    # Display assistant response in chat message container
    with st.chat_message(
        name=MODEL_ROLE,
        avatar=AI_AVATAR_ICON,
    ):
        message_placeholder = st.empty()
        full_response = ''
        
        # Añade un indicador de "escribiendo..."
        typing_indicator = st.empty()
        typing_indicator.markdown("*RoboCopy está escribiendo...*")
        
        # Streams in a chunk at a time
        for chunk in response_stream:
            if hasattr(chunk, 'text'):
                # Simulate stream of chunk
                words = chunk.text.split(' ')
                for i, word in enumerate(words):
                    full_response += word
                    # Añadir espacio solo si no es la última palabra del chunk
                    if i < len(words) - 1:
                        full_response += ' '
                    time.sleep(0.1)  # Velocidad ajustada para mejor legibilidad
                    # Rewrites with a cursor at end
                    message_placeholder.write(full_response + '▌')
        
        # Elimina el indicador de escritura
        typing_indicator.empty()
        # Write full message with placeholder
        message_placeholder.write(full_response)

    # Add assistant response to chat history
    st.session_state.messages.append(
        dict(
            role=MODEL_ROLE,
            content=full_response,
            avatar=AI_AVATAR_ICON,
        )
    )
    
    # Actualizar el historial de Gemini (adaptado para la nueva API)
    if not hasattr(st.session_state, 'gemini_history'):
        st.session_state.gemini_history = []
    
    st.session_state.gemini_history.append({
        'role': 'user',
        'parts': [{'text': prompt}]
    })
    
    st.session_state.gemini_history.append({
        'role': 'model',
        'parts': [{'text': full_response}]
    })
    
    # Save to file
    joblib.dump(
        st.session_state.messages,
        f'data/{st.session_state.chat_id}-st_messages',
    )
    joblib.dump(
        st.session_state.gemini_history,
        f'data/{st.session_state.chat_id}-gemini_messages',
    )