JeCabrera's picture
Upload app.py
657617d verified
raw
history blame
14.6 kB
import time
import os
import joblib
import streamlit as st
import google.generativeai as genai
from dotenv import load_dotenv
# 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'])
# Inicializar variables de estado
if 'show_examples' not in st.session_state:
st.session_state.show_examples = True
if 'selected_persona' not in st.session_state:
st.session_state.selected_persona = "estratega"
# Función para seleccionar persona
def select_puv_persona():
st.sidebar.write("## 🧠 Selecciona un Experto")
# Inicializar la selección de persona si no existe
if 'selected_persona' not in st.session_state:
st.session_state.selected_persona = "estratega"
# Crear botones para cada persona
cols = st.sidebar.columns(len(PUV_PERSONAS))
for i, (persona_id, persona) in enumerate(PUV_PERSONAS.items()):
with cols[i]:
if st.button(f"{persona['emoji']}\n{persona['nombre']}", key=f"btn_{persona_id}"):
st.session_state.selected_persona = persona_id
st.rerun()
# Mostrar descripción de la persona seleccionada
persona_actual = PUV_PERSONAS[st.session_state.selected_persona]
st.sidebar.markdown(f"**{persona_actual['emoji']} {persona_actual['nombre']}**")
st.sidebar.markdown(f"_{persona_actual['descripcion']}_")
return st.session_state.selected_persona
# Función para modificar el prompt con la personalidad seleccionada
def apply_persona_to_prompt(prompt, persona_id):
if persona_id in PUV_PERSONAS:
persona = PUV_PERSONAS[persona_id]
return f"{persona['prompt_prefix']}\n\nConsulta original: {prompt}"
return prompt
# Función para manejar mensajes
def add_message(role, content, avatar=None):
message = {
'role': role,
'content': content
}
if avatar:
message['avatar'] = avatar
st.session_state.messages.append(message)
return message
# Función para guardar el estado del chat
def save_chat_state():
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',
)
# Función para generar título de chat
def generate_chat_title(prompt):
temp_title = f'SesiónChat-{st.session_state.chat_id}'
try:
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}'")
generated_title = title_response.text.strip()
if generated_title:
return generated_title
except Exception as e:
print(f"Error al generar título: {e}")
return temp_title
# Función para operaciones con manejo de errores
def safe_operation(operation, default_value, error_message="Error en operación"):
try:
return operation()
except Exception as e:
print(f"{error_message}: {e}")
return default_value
# Definición de perfiles de expertos en PUV
PUV_PERSONAS = {
"estratega": {
"nombre": "Estratega de Marketing",
"descripcion": "Experto en posicionamiento estratégico y diferenciación de marca",
"prompt_prefix": "Como estratega de marketing especializado en posicionamiento de marca, voy a ayudarte a crear una PUV que destaque tu ventaja competitiva. ",
"emoji": "🎯"
},
"copywriter": {
"nombre": "Copywriter Persuasivo",
"descripcion": "Especialista en redacción persuasiva y mensajes de alto impacto",
"prompt_prefix": "Como copywriter especializado en mensajes persuasivos, voy a ayudarte a crear una PUV que conecte emocionalmente con tu audiencia. ",
"emoji": "✍️"
},
"analista": {
"nombre": "Analista de Mercado",
"descripcion": "Experto en análisis de mercado y comportamiento del consumidor",
"prompt_prefix": "Como analista de mercado especializado en comportamiento del consumidor, voy a ayudarte a crear una PUV basada en insights de tu audiencia. ",
"emoji": "📊"
},
"innovador": {
"nombre": "Innovador Disruptivo",
"descripcion": "Especialista en propuestas innovadoras y disruptivas",
"prompt_prefix": "Como especialista en innovación disruptiva, voy a ayudarte a crear una PUV que rompa con los paradigmas de tu industria. ",
"emoji": "💡"
}
}
# Modificar el procesamiento del prompt
if prompt := st.chat_input('¿En qué puedo ayudarte hoy con tu Propuesta Única de Valor?'):
# Guardar el prompt original
original_prompt = prompt
# Aplicar la personalidad seleccionada al prompt
enhanced_prompt = apply_persona_to_prompt(prompt, st.session_state.selected_persona)
# Generar título para el chat si es nuevo
if st.session_state.chat_id not in past_chats.keys():
st.session_state.chat_title = generate_chat_title(original_prompt)
past_chats[st.session_state.chat_id] = st.session_state.chat_title
else:
st.session_state.chat_title = past_chats[st.session_state.chat_id]
joblib.dump(past_chats, 'data/past_chats_list')
# Mostrar mensaje del usuario (siempre el original)
with st.chat_message('user', avatar=USER_AVATAR_ICON):
st.markdown(original_prompt)
# Añadir mensaje a la historia
add_message('user', original_prompt, USER_AVATAR_ICON)
# Enviar el prompt mejorado al modelo
response = st.session_state.chat.send_message(
enhanced_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 = ''
assistant_response = 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:
# Simulate stream of chunk
for word in chunk.text.split(' '):
full_response += word + ' '
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=st.session_state.chat.history[-1].parts[0].text,
avatar=AI_AVATAR_ICON,
)
)
st.session_state.gemini_history = st.session_state.chat.history
# Save to file
# Función para manejar mensajes
def add_message(role, content, avatar=None):
message = {
'role': role,
'content': content
}
if avatar:
message['avatar'] = avatar
st.session_state.messages.append(message)
return message
# Función para guardar el estado del chat
def save_chat_state():
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',
)
# Función para generar título de chat
def generate_chat_title(prompt):
temp_title = f'SesiónChat-{st.session_state.chat_id}'
try:
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}'")
generated_title = title_response.text.strip()
if generated_title:
return generated_title
except Exception as e:
print(f"Error al generar título: {e}")
return temp_title
# Función para operaciones con manejo de errores
def safe_operation(operation, default_value, error_message="Error en operación"):
try:
return operation()
except Exception as e:
print(f"{error_message}: {e}")
return default_value
# Definición de perfiles de expertos en PUV
PUV_PERSONAS = {
"estratega": {
"nombre": "Estratega de Marketing",
"descripcion": "Experto en posicionamiento estratégico y diferenciación de marca",
"prompt_prefix": "Como estratega de marketing especializado en posicionamiento de marca, voy a ayudarte a crear una PUV que destaque tu ventaja competitiva. ",
"emoji": "🎯"
},
"copywriter": {
"nombre": "Copywriter Persuasivo",
"descripcion": "Especialista en redacción persuasiva y mensajes de alto impacto",
"prompt_prefix": "Como copywriter especializado en mensajes persuasivos, voy a ayudarte a crear una PUV que conecte emocionalmente con tu audiencia. ",
"emoji": "✍️"
},
"analista": {
"nombre": "Analista de Mercado",
"descripcion": "Experto en análisis de mercado y comportamiento del consumidor",
"prompt_prefix": "Como analista de mercado especializado en comportamiento del consumidor, voy a ayudarte a crear una PUV basada en insights de tu audiencia. ",
"emoji": "📊"
},
"innovador": {
"nombre": "Innovador Disruptivo",
"descripcion": "Especialista en propuestas innovadoras y disruptivas",
"prompt_prefix": "Como especialista en innovación disruptiva, voy a ayudarte a crear una PUV que rompa con los paradigmas de tu industria. ",
"emoji": "💡"
}
}
# Función para seleccionar persona
def select_puv_persona():
st.sidebar.write("## 🧠 Selecciona un Experto")
# Inicializar la selección de persona si no existe
if 'selected_persona' not in st.session_state:
st.session_state.selected_persona = "estratega"
# Crear botones para cada persona
cols = st.sidebar.columns(len(PUV_PERSONAS))
for i, (persona_id, persona) in enumerate(PUV_PERSONAS.items()):
with cols[i]:
if st.button(f"{persona['emoji']}\n{persona['nombre']}", key=f"btn_{persona_id}"):
st.session_state.selected_persona = persona_id
st.rerun()
# Mostrar descripción de la persona seleccionada
persona_actual = PUV_PERSONAS[st.session_state.selected_persona]
st.sidebar.markdown(f"**{persona_actual['emoji']} {persona_actual['nombre']}**")
st.sidebar.markdown(f"_{persona_actual['descripcion']}_")
return st.session_state.selected_persona
# Función para modificar el prompt con la personalidad seleccionada
def apply_persona_to_prompt(prompt, persona_id):
if persona_id in PUV_PERSONAS:
persona = PUV_PERSONAS[persona_id]
return f"{persona['prompt_prefix']}\n\nConsulta original: {prompt}"
return prompt