Spaces:
Sleeping
Sleeping
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" | |
) |