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): """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'] # Solo considerar como saludo si es el primer mensaje del usuario # y es un saludo simple 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 # 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""" handle_chat_title(prompt) with st.chat_message('user', avatar=USER_AVATAR_ICON): st.markdown(prompt) state.add_message('user', prompt, USER_AVATAR_ICON) # Obtener el prompt mejorado primero enhanced_prompt = get_enhanced_prompt(prompt, is_example) # Mover la respuesta del modelo después del mensaje del usuario 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): """Maneja la lógica del título del chat""" 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): """Genera el prompt mejorado según el tipo de mensaje""" 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 process_model_response(enhanced_prompt): """Procesa la respuesta del modelo""" 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) # Actualizar historial state.add_message(role=MODEL_ROLE, content=full_response, avatar=AI_AVATAR_ICON) state.gemini_history = state.chat.history state.save_chat_history() except Exception as e: st.error(f"Error: {str(e)}") def stream_response(response, message_placeholder, typing_indicator): """Maneja el streaming de la respuesta""" 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 # Función para cargar CSS personalizado def load_css(file_path): with open(file_path) as f: st.markdown(f'', 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(""" """, 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(""" """, unsafe_allow_html=True) st.image("robocopy_logo.png", width=300, use_container_width=True) # Título con diseño responsivo (eliminado el símbolo ∞) st.markdown("""

PUV Creator

""", unsafe_allow_html=True) # Subtítulo con margen superior ajustado a -30px st.markdown("""

By Jesús Cabrera

""", unsafe_allow_html=True) # Descripción con fondo eliminado y margen superior ajustado a -20px st.markdown("""

🎯 Experto en crear Propuestas de Valor Únicas que convierten audiencia en clientes

""", 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 y el chat state.initialize_model('gemini-2.0-flash') state.initialize_chat() # Siempre inicializar el chat después del modelo # 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 el prompt unificado system_prompt = get_unified_puv_prompt() if state.chat is not None: # Verificación adicional de seguridad state.chat.send_message(system_prompt) else: st.error("Error: No se pudo inicializar el chat correctamente.") # 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()