JeCabrera's picture
Update app.py
c50c598 verified
from dotenv import load_dotenv
import streamlit as st
import os
import google.generativeai as genai
from puv_formulas import puv_formulas
from styles import apply_styles
import PyPDF2
import docx
from PIL import Image
import datetime # Add this import for timestamp
# Cargar variables de entorno
load_dotenv()
# Configurar API de Google Gemini
genai.configure(api_key=os.getenv("GOOGLE_API_KEY"))
# Función para obtener la respuesta del modelo Gemini
def get_gemini_response(product_service, target_audience, skills, formula_type, temperature, file_content="", image_parts=None):
# Check if we have at least one source of information
has_file_content = bool(file_content.strip())
has_image = image_parts is not None
has_text_input = target_audience or product_service or skills
if not (has_file_content or has_image or has_text_input):
return "Debes proporcionar al menos un tipo de información: público objetivo, producto/servicio, habilidades o un archivo de referencia."
# If we only have file content but no other inputs, we can proceed
if (has_file_content or has_image) and not has_text_input:
# File-only mode
business_info = "Analyze the provided reference material to extract business information.\n"
else:
# Regular mode with validation
if not target_audience:
return "El campo de público objetivo es obligatorio cuando no se proporciona un archivo de referencia completo."
if not product_service and not skills:
return "Debes proporcionar al menos tu producto/servicio o tus habilidades cuando no se proporciona un archivo de referencia completo."
# Adjust prompt based on what's provided
business_info = f"Target Audience: {target_audience}\n"
if product_service:
business_info += f"Product/Service: {product_service}\n"
if skills:
business_info += f"My Skills/Expertise: {skills}\n"
formula = puv_formulas[formula_type]
# Add file content if available
reference_info = ""
if file_content:
reference_info = f"\nREFERENCE MATERIAL:\n{file_content}\n"
model = genai.GenerativeModel('gemini-2.0-flash')
full_prompt = f"""
You are a UVP (Unique Value Proposition) expert. Analyze (internally only, do not output the analysis) the following information:
BUSINESS INFORMATION:
{business_info}
Formula Type: {formula_type}
{formula["description"]}
{reference_info}
EXAMPLE TO FOLLOW:
{formula["examples"]}
First, analyze (but don't output) these points:
1. TARGET AUDIENCE ANALYSIS - Pain Points:
- What specific frustrations does this audience experience?
- What are their biggest daily challenges?
- What emotional problems do they face?
- What have they tried before that didn't work?
- What's stopping them from achieving their goals?
2. PRODUCT/SERVICE ANALYSIS - Benefits:
- What tangible results do clients get?
- What specific transformation does it offer?
- What's the unique method or differentiator?
- What competitive advantages does it have?
- What emotional benefits does it provide?
3. SKILLS/EXPERTISE ANALYSIS - Credibility:
- How do these skills directly address the audience's pain points?
- What unique perspective do these skills bring to the solution?
- How do these skills enhance the product/service delivery?
- What credibility elements can be highlighted?
- How do these skills differentiate from competitors?
Based on your internal analysis of the target audience pain points and product benefits (do not include this analysis in the output), create THREE different UVPs in Spanish language following the formula structure provided.
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
- DO NOT include any analysis in the output
- ONLY output the three UVPs
Output EXACTLY in this format (no additional text) in Spanish language:
1. [First UVP]
2. [Second UVP]
3. [Third UVP]
"""
# Handle text-only or text+image requests
if image_parts:
response = model.generate_content([full_prompt, image_parts], generation_config={"temperature": temperature})
else:
response = model.generate_content([full_prompt], generation_config={"temperature": temperature})
return response.parts[0].text if response and response.parts else "Error generating content."
# Configurar la aplicación Streamlit
st.set_page_config(page_title="UVP Generator", page_icon="💡", layout="wide")
# Aplicar estilos
st.markdown(apply_styles(), unsafe_allow_html=True)
# Título de la app
st.markdown("<h1>Generador de PUV</h1>", unsafe_allow_html=True)
st.markdown("<h3>Crea Propuestas Únicas de Valor poderosas que atraigan a tus clientes ideales y comuniquen tu valor de manera efectiva.</h3>", unsafe_allow_html=True)
# Sidebar manual
with open("manual.md", "r", encoding="utf-8") as file:
manual_content = file.read()
st.sidebar.markdown(manual_content)
# Crear dos columnas
col1, col2 = st.columns([1, 1])
# Columna izquierda para inputs
with col1:
product_service = st.text_area(
"¿Cuál es tu producto o servicio?",
placeholder="Ejemplo: Curso de copywriting con IA, Programa de coaching..."
)
skills = st.text_area(
"Mis habilidades:",
placeholder="Ejemplo: Experiencia en marketing digital, certificación en SEO..."
)
# Move the generate button here, right after skills
generate_button = st.button("Generar PUV")
with st.expander("Opciones avanzadas"):
target_audience = st.text_area(
"¿Cuál es tu público objetivo?",
placeholder="Ejemplo: Coaches que quieren atraer más clientes..."
)
# Añadir cargador de archivos
uploaded_file = st.file_uploader("📄 Archivo o imagen de referencia",
type=['txt', 'pdf', 'docx', 'jpg', 'jpeg', 'png'])
file_content = ""
is_image = False
image_parts = None
if uploaded_file is not None:
file_type = uploaded_file.name.split('.')[-1].lower()
# Manejar archivos de texto
if file_type in ['txt', 'pdf', 'docx']:
if file_type == 'txt':
try:
file_content = uploaded_file.read().decode('utf-8')
except Exception as e:
st.error(f"Error al leer el archivo TXT: {str(e)}")
file_content = ""
elif file_type == 'pdf':
try:
pdf_reader = PyPDF2.PdfReader(uploaded_file)
file_content = ""
for page in pdf_reader.pages:
file_content += page.extract_text() + "\n"
except Exception as e:
st.error(f"Error al leer el archivo PDF: {str(e)}")
file_content = ""
elif file_type == 'docx':
try:
doc = docx.Document(uploaded_file)
file_content = "\n".join([para.text for para in doc.paragraphs])
except Exception as e:
st.error(f"Error al leer el archivo DOCX: {str(e)}")
file_content = ""
# Manejar archivos de imagen
elif file_type in ['jpg', 'jpeg', 'png']:
try:
image = Image.open(uploaded_file)
image_bytes = uploaded_file.getvalue()
image_parts = {
"mime_type": uploaded_file.type,
"data": image_bytes
}
is_image = True
except Exception as e:
st.error(f"Error al procesar la imagen: {str(e)}")
is_image = False
formula_type = st.selectbox(
"Fórmula PUV:",
options=list(puv_formulas.keys())
)
temperature = st.slider(
"Nivel de creatividad:",
min_value=0.0,
max_value=2.0,
value=1.0,
step=0.1,
help="Valores más altos generan propuestas más creativas pero menos predecibles."
)
with col2:
if generate_button:
# Store the response in session state so it persists across reruns
with st.spinner("Creando tu PUV..."):
st.session_state.puv_response = get_gemini_response(
product_service,
target_audience,
skills,
formula_type,
temperature,
file_content,
image_parts
)
# Display the response if it exists in session state (separate from the generate button condition)
if 'puv_response' in st.session_state:
st.write("### Propuestas Únicas de Valor")
st.write(st.session_state.puv_response)
# Add download button if we have a valid response
if st.session_state.puv_response and not st.session_state.puv_response.startswith("Error") and not st.session_state.puv_response.startswith("Debes"):
# Get current timestamp for the filename
timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
# Prepare content for download
download_content = st.session_state.puv_response
# Download button
st.download_button(
label="DESCARGAR PUV",
data=download_content,
file_name=f"propuestas_unicas_valor_{timestamp}.txt",
mime="text/plain"
)