Spaces:
Sleeping
Sleeping
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_unified_puv_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): | |
text = text.lower().strip() | |
greetings = ['hola', 'hey', 'saludos', 'buenos días', 'buenas tardes', 'buenas noches', 'hi', 'hello'] | |
is_simple_greeting = any(greeting in text for greeting in greetings) and len(text.split()) < 4 | |
return is_simple_greeting and len(state.messages) == 0 | |
def process_message(prompt, is_example=False): | |
handle_chat_title(prompt) | |
with st.chat_message('user', avatar=USER_AVATAR_ICON): | |
st.markdown(prompt) | |
state.add_message('user', prompt, USER_AVATAR_ICON) | |
enhanced_prompt = get_enhanced_prompt(prompt, is_example) | |
with st.chat_message(MODEL_ROLE, avatar=AI_AVATAR_ICON): | |
try: | |
message_placeholder = st.empty() | |
typing_indicator = st.empty() | |
typing_indicator.markdown("*Generando respuesta...*") | |
response = state.send_message(enhanced_prompt) | |
full_response = stream_response(response, message_placeholder, typing_indicator) | |
if full_response: | |
state.add_message(MODEL_ROLE, full_response, AI_AVATAR_ICON) | |
state.gemini_history = state.chat.history | |
state.save_chat_history() | |
except Exception as e: | |
st.error(f"Error en el streaming: {str(e)}") | |
return | |
def handle_chat_title(prompt): | |
if state.chat_id not in past_chats: | |
temp_title = f'SesiónChat-{state.chat_id}' | |
generated_title = state.generate_chat_title(prompt) | |
state.chat_title = generated_title or temp_title | |
past_chats[state.chat_id] = state.chat_title | |
else: | |
state.chat_title = past_chats[state.chat_id] | |
joblib.dump(past_chats, 'data/past_chats_list') | |
def get_enhanced_prompt(prompt, is_example): | |
if is_greeting(prompt): | |
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." | |
elif is_example: | |
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." | |
return prompt | |
def stream_response(response, message_placeholder, typing_indicator): | |
full_response = '' | |
try: | |
for chunk in response: | |
if chunk.text: | |
for ch in chunk.text: | |
full_response += ch | |
time.sleep(0.01) | |
typing_indicator.markdown("*Generando respuesta...*") | |
message_placeholder.markdown(full_response + '▌') | |
except Exception as e: | |
st.error(f"Error en el streaming: {str(e)}") | |
return '' | |
typing_indicator.empty() | |
message_placeholder.markdown(full_response) | |
return full_response | |
def load_css(file_path): | |
with open(file_path) as f: | |
st.markdown(f'<style>{f.read()}</style>', unsafe_allow_html=True) | |
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}") | |
st.markdown(""" | |
<style> | |
.robocopy-title { | |
color: white !important; | |
font-weight: bold; | |
font-size: clamp(2.5em, 5vw, 4em); | |
line-height: 1.2; | |
} | |
</style> | |
""", unsafe_allow_html=True) | |
def display_initial_header(): | |
col1, col2, col3 = st.columns([1, 2, 1]) | |
with col2: | |
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) | |
st.markdown(""" | |
<div style='text-align: center; margin-top: -35px; width: 100%;'> | |
<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> | |
</div> | |
""", unsafe_allow_html=True) | |
st.markdown(""" | |
<div style='text-align: center; width: 100%;'> | |
<p style='font-size: 16px; color: white; width: 100%; text-align: center; margin-top: -20px;'>By Jesús Cabrera</p> | |
</div> | |
""", unsafe_allow_html=True) | |
st.markdown(""" | |
<div style='text-align: center; width: 100%;'> | |
<p style='font-size: 16px; background-color: transparent; padding: 12px; border-radius: 8px; margin-top: -20px; color: white; width: 100%; text-align: center;'> | |
🎯 Experto en crear Propuestas de Valor Únicas que convierten audiencia en clientes | |
</p> | |
</div> | |
""", unsafe_allow_html=True) | |
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"} | |
] | |
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 = '🤖' | |
USER_AVATAR_ICON = '👤' | |
try: | |
os.mkdir('data/') | |
except: | |
pass | |
try: | |
past_chats: dict = joblib.load('data/past_chats_list') | |
except: | |
past_chats = {} | |
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: | |
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='_', | |
) | |
state.chat_title = f'SesiónChat-{state.chat_id}' | |
state.load_chat_history() | |
state.initialize_model('gemini-2.0-flash') | |
state.initialize_chat() | |
for message in state.messages: | |
with st.chat_message(name=message['role'], avatar=message.get('avatar')): | |
st.markdown(message['content']) | |
# NUEVO BLOQUE MODIFICADO | |
if not state.has_messages(): | |
display_initial_header() | |
display_examples() | |
if state.prompt: | |
process_message(state.prompt, is_example=True) | |
state.clear_prompt() | |
system_prompt = get_unified_puv_prompt() | |
if state.chat is not None: | |
state.chat.send_message(system_prompt) | |
else: | |
st.error("Error: No se pudo inicializar el chat correctamente.") | |
else: | |
if prompt := st.chat_input('Describe tu producto/servicio y audiencia objetivo...'): | |
process_message(prompt, is_example=False) | |
if state.has_prompt(): | |
process_message(state.prompt, is_example=True) | |
state.clear_prompt() |