JeCabrera's picture
Upload 10 files
e369da7 verified
raw
history blame
18.3 kB
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
# 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
st.session_state.chat_title = f'SesiónChat-{st.session_state.chat_id}'
st.write('# Generador de Propuestas de Valor Únicas (PUVs)')
st.write('Describe tu producto/servicio y audiencia objetivo para generar PUVs personalizadas.')
# 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'])
# Mensaje inicial del sistema si es un chat nuevo
if not st.session_state.messages:
system_prompt = get_puv_system_prompt()
# Mostrar la carátula inicial
st.markdown("""
<div style='text-align: center; padding: 1rem 0;'>
<h1 style='font-size: 24px; margin-bottom: 0.5rem;'>💎 RoboCopy PUV Creator</h1>
<p style='font-size: 16px; color: white;'>By Jesús Cabrera</p>
<p style='font-size: 14px; background-color: rgba(78, 205, 196, 0.1); padding: 8px; border-radius: 5px; margin-top: 10px; color: white;'>
🎯 Experto en crear Propuestas de Valor Únicas que convierten audiencia en clientes
</p>
</div>
""", unsafe_allow_html=True)
# Mostrar los ejemplos
ejemplos = [
{"texto": "¿Cuál es la mejor fórmula para mi PUV? 🤔", "prompt": "Ayúdame a elegir la mejor fórmula para mi Propuesta de Valor Única"},
{"texto": "¿Cómo hacer mi PUV más impactante? 💫", "prompt": "Dame consejos para hacer mi Propuesta de Valor más persuasiva y memorable"},
{"texto": "Necesito una PUV para mi servicio...", "prompt": "Ayúdame a crear una Propuesta de Valor para mi servicio de coaching"},
{"texto": "¿Ejemplos de PUVs efectivas? 🎯", "prompt": "Muéstrame ejemplos de Propuestas de Valor exitosas en mi industria"}
]
# 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"]):
st.session_state.prompt = ejemplo["prompt"]
st.rerun()
# Inicializar el chat con el sistema prompt
st.session_state.chat = st.session_state.model.start_chat(
history=st.session_state.gemini_history
)
# Enviar el system prompt como primer mensaje
st.session_state.chat.send_message(system_prompt)
# Solo añadir el mensaje inicial si no es un ejemplo
if not st.session_state.get('prompt'):
st.session_state.messages.append(
dict(
role=MODEL_ROLE,
content="""
Hola, soy RoboCopy tu asistente especializado en crear Propuestas de Valor Únicas.
Para ayudarte 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?
¿Empezamos con tu producto o servicio?
""",
avatar=AI_AVATAR_ICON,
)
)
# Add system message to chat history
st.session_state.messages.append(
dict(
role=MODEL_ROLE,
content="""
Hola, soy RoboCopy tu asistente especializado en crear Propuestas de Valor Únicas.
Para ayudarte 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?
¿Empezamos con tu producto o servicio?
""",
avatar=AI_AVATAR_ICON,
)
)
# React to user input
if prompt := st.chat_input('Describe tu producto/servicio y audiencia objetivo...'):
# 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,
)
)
# Construir el prompt para el modelo con todas las fórmulas disponibles
puv_expert_prompt = """You are a collaborative team of world-class experts working together to create exceptional Unique Value Propositions (UVPs) that convert audience into customers.
INTERNAL ANALYSIS (DO NOT OUTPUT):
1. DEEP AVATAR ANALYSIS:
A. Daily Life & Cultural Context:
- What daily experiences resonate with them?
- What cultural references do they understand?
- What mental images are easy for them to recall?
- What TV shows, movies, or media do they consume?
B. Pain Points & Emotional Core:
- What is their ONE main pain point?
- What consequences does this pain point trigger?
- What past painful experience influences current decisions?
- What internal conflict do they regularly experience?
- What do they need to heal or resolve to feel complete?
C. Previous Solutions:
- What have they tried before that didn't work?
- Why didn't these solutions work for them?
- What do other "experts" tell them to do?
- What false beliefs do they hold?
D. Desires & Transformations:
- What are their primary desires?
- What is their current vs. desired situation?
- What transformation are they seeking?
- Why do they need to act now?
2. PRODUCT/SERVICE ANALYSIS:
- What is the main benefit or promise?
- What makes it unique or different?
- What transformation does it offer?
- How does it help achieve results?
- Why is it superior to existing solutions?
3. MARKET CONTEXT:
- What are the common industry solutions?
- Why do these solutions fail?
- What are the typical misconceptions?
- What makes your solution unique?
Based on this internal analysis, create UVPs that:
1. Connect directly with the main pain point
2. Address deep emotional motivations
3. Contrast with failed past solutions
4. Present your unique method convincingly
5. Use familiar analogies or metaphors
THE EXPERT TEAM:
1. MASTER UVP STRATEGIST:
- Expert in UVP frameworks and conversion strategies
- Ensures the UVPs follow the selected framework structure precisely
- Focuses on strategic placement of key conversion elements
2. ELITE DIRECT RESPONSE COPYWRITER:
- Trained by Gary Halbert, Gary Bencivenga, and David Ogilvy
- Creates compelling hooks and persuasive elements
- Ensures the language resonates with the target audience
3. AUDIENCE PSYCHOLOGY SPECIALIST:
- Expert in understanding audience motivations and objections
- Creates content that builds genuine connection and trust
- Identifies and addresses hidden fears and desires
4. STORYTELLING MASTER:
- Creates compelling narratives that illustrate key points
- Makes complex concepts accessible through narrative
5. ENGAGEMENT EXPERT:
- Specializes in creating memorable and impactful statements
- Ensures the UVPs are clear, concise and compelling
You are a UVP (Unique Value Proposition) expert. Analyze (internally only, do not output the analysis) the user's message to identify information about their product/service and target audience.
If the user hasn't provided all the necessary information, guide them through the process by asking for:
1. What product/service they offer
2. Who their target audience is
3. Which formula they prefer (Tradicional, Anti-tradicional, Contrato Imposible, Reto Ridículo)
4. How many UVP examples they want
If the user mentions a specific formula, use that formula from the puv_formulas dictionary. If they don't specify, suggest the most appropriate formula based on their product/service and audience.
If the user is asking for UVPs and has provided sufficient information, create the requested number of different UVPs using the specified formula. If the user is asking a question about UVPs or marketing, answer it helpfully.
When creating UVPs, follow these CRITICAL INSTRUCTIONS:
- Each UVP must be specific and measurable
- Focus on the transformation journey
- Use natural, conversational language
- Avoid generic phrases and buzzwords
- Maximum 2 lines per UVP
If creating UVPs, output in this format:
"Basado en tu descripción, aquí tienes [número] propuestas de valor únicas (PUVs) para tu [producto/servicio] usando la fórmula [nombre de fórmula]:
1. [First UVP]
2. [Second UVP]
3. [Third UVP]
...
Estas PUVs destacan [principales beneficios]. ¿Hay alguna que te guste más o quieres que ajuste algún aspecto?"
If answering a question, provide a helpful, expert response.
"""
# Combinar el prompt del experto con el mensaje del usuario
enhanced_prompt = f"{puv_expert_prompt}\n\nUser message: {prompt}"
## Send message to AI
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("*Generando respuesta...*")
# Streams in a chunk at a time
for chunk in response:
# Simulate stream of chunk
for ch in chunk.text: # Eliminamos el split(' ') para procesar carácter por carácter
full_response += ch
time.sleep(0.01) # Más rápido
# 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
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',
)
# Cuando se selecciona un ejemplo
if 'prompt' in st.session_state and st.session_state.prompt: # Verificamos que el prompt no esté vacío
prompt = st.session_state.prompt
# Guardar el chat para después si es nuevo
if st.session_state.chat_id not in past_chats.keys():
temp_title = f'SesiónChat-{st.session_state.chat_id}'
past_chats[st.session_state.chat_id] = temp_title
joblib.dump(past_chats, 'data/past_chats_list')
# Mostrar el mensaje del usuario
with st.chat_message('user', avatar=USER_AVATAR_ICON):
st.markdown(prompt)
# Añadir el mensaje del usuario al historial
st.session_state.messages.append({
'role': 'user',
'content': prompt,
'avatar': USER_AVATAR_ICON
})
# Procesar la respuesta del modelo
if prompt.strip():
with st.chat_message(MODEL_ROLE, avatar=AI_AVATAR_ICON):
try:
response = st.session_state.chat.send_message(prompt)
st.markdown(response.text)
# Añadir la respuesta al historial
st.session_state.messages.append({
'role': MODEL_ROLE,
'content': response.text,
'avatar': AI_AVATAR_ICON
})
# Guardar el historial actualizado
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',
)
except ValueError as e:
st.error("Error: El mensaje no puede estar vacío. Por favor, escribe algo.")
# Limpiar el prompt del estado de la sesión
st.session_state.prompt = None
# Limpiar el prompt del estado de la sesión
st.session_state.prompt = None