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, format_creative_response from options import tone_options, creative_approaches 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, main_benefit, tone_of_voice, temperature, file_content="", image_parts=None, creative_approach=""): # Adjust prompt based on what's provided business_info = f"Target Audience: {target_audience}\n" business_info += f"Product/Service: {product_service}\n" business_info += f"Main Benefit: {main_benefit}\n" if tone_of_voice: business_info += f"Brand Tone of Voice: {tone_of_voice}\n" # Add creative approach to business info if provided if creative_approach: # Get the description from the dictionary from options import creative_approaches approach_description = creative_approaches.get(creative_approach, "") business_info += f"\nCREATIVE APPROACH: {creative_approach}\n" business_info += f"Description: {approach_description}\n" business_info += f"IMPORTANT: Please follow this creative approach strictly when generating concepts.\n" # 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 Creative Concept expert. Analyze (internally only, do not output the analysis) the following information: BUSINESS INFORMATION: {business_info} {reference_info} A Creative Idea is a set of pieces created to sell a brand, product, or service, united by the same idea that is transmitted through a creative concept. First, analyze (but don't output) these points: 1. TARGET AUDIENCE ANALYSIS: - What everyday concepts are they familiar with? - What TV shows, movies, or cultural references resonate with them? - What emotions and experiences are meaningful to them? - What mental images would be easy for them to recall? 2. PRODUCT/SERVICE ANALYSIS: - What is the main benefit or promise? - What makes it unique or different? - What transformation does it offer? - What process or journey does the customer go through? Based on your internal analysis, create THREE different Creative Concepts in Spanish language. Each concept should be a DIRECT ANALOGY or METAPHOR that connects your product/service to something completely different but familiar. Examples of good creative concepts: - "Escribir copy es como cocinar tu plato favorito porque necesitas los ingredientes correctos para que todos quieran probarlo" - "Tu negocio es como un equipo de fútbol: necesita buenos jugadores (productos) y una estrategia clara para ganar clientes" - "Tu curso es como Netflix: ofrece contenido que engancha y soluciones que la gente realmente quiere ver" For each concept, include: CONCEPT: A clear statement of the main benefit CREATIVITY: A direct analogy or metaphor connecting your product to something completely different but familiar CRITICAL INSTRUCTIONS: - Each concept MUST use a direct "X es como Y porque Z" structure - Use SIMPLE, EVERYDAY language that anyone can understand - Avoid technical jargon, complex words, or business terminology - Write as if you're explaining to a friend in a casual conversation - Use everyday objects, activities, movies, TV shows or cultural references everyone knows - Make the connection SURPRISING and UNEXPECTED - connect things that normally wouldn't be connected - Challenge conventional thinking by finding parallels between your product and something completely different - Create analogies that make people say "I never thought of it that way!" - Focus on the main benefit - Create clear mental images - Be easy to remember - Use the brand's tone of voice if provided - Format with proper spacing between sections Output EXACTLY in this format (no additional text) in Spanish language: CONCEPTO CREATIVO 1: Concepto: [Main message/benefit in simple, conversational language] Creatividad: [Direct analogy using everyday language: "X es como Y porque Z"] CONCEPTO CREATIVO 2: Concepto: [Main message/benefit] Creatividad: [Direct analogy: "X es como Y porque Z"] CONCEPTO CREATIVO 3: Concepto: [Main message/benefit] Creatividad: [Direct analogy: "X es como Y porque Z"] """ # 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="Generador de Ideas Creativas", page_icon="💡", layout="wide") # Aplicar estilos st.markdown(apply_styles(), unsafe_allow_html=True) # Título de la app st.markdown("

Generador de Ideas Creativas

", unsafe_allow_html=True) st.markdown("

Crea conceptos creativos poderosos que conecten con tu audiencia y transmitan el valor de tu marca de manera memorable.

", 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 # In the app.py file, update the main_benefit field label and create an accordion for tone options with col1: product_service = st.text_area( "¿Cuál es tu producto o servicio?", placeholder="Ejemplo: Curso de copywriting con IA, Programa de coaching..." ) main_benefit = st.text_area( "¿Cuál es tu Oferta Dorada/PUV?", placeholder="Ejemplo: Aprender copywriting a través de transformaciones reales de textos..." ) target_audience = st.text_area( "¿Cuál es tu público objetivo?", placeholder="Ejemplo: Emprendedores que quieren mejorar sus textos comerciales..." ) # Generate button after main inputs generate_button = st.button("Generar Ideas Creativas") with st.expander("Opciones avanzadas"): # Replace nested expanders with a selectbox for tone selection st.write("Tono de voz de la marca (opcional)") # Use selectbox for tone selection selected_tone = st.selectbox( "Selecciona un tono:", options=list(tone_options.keys()), index=0, key="tone_selectbox" ) # Display the description of the selected tone if selected_tone != "Ninguno": st.info(tone_options[selected_tone]) # Store the selected tone st.session_state.selected_tone = selected_tone else: # Clear any previously selected tone if "selected_tone" in st.session_state: del st.session_state.selected_tone # Use the stored tone or empty string tone_of_voice = st.session_state.get("selected_tone", "") # 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 # Add creative approach selector (moved outside nested expander) selected_approach = st.selectbox( "Enfoque creativo:", options=list(creative_approaches.keys()), index=0, key="approach_selectbox" ) # Display the description of the selected approach st.info(creative_approaches[selected_approach]) # Store the selected approach st.session_state.selected_approach = selected_approach # Temperature slider 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 ideas 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 tus ideas creativas..."): st.session_state.creative_response = get_gemini_response( product_service, target_audience, main_benefit, tone_of_voice, temperature, file_content, image_parts, st.session_state.get("selected_approach", "") # Removed contrast_level parameter ) # Display the response if it exists in session state if 'creative_response' in st.session_state: st.write("### Conceptos Creativos") # Format the response with custom styling formatted_response = format_creative_response(st.session_state.creative_response) # Use markdown with HTML to display the formatted response st.markdown(formatted_response, unsafe_allow_html=True) # Add download button if we have a valid response if st.session_state.creative_response and not st.session_state.creative_response.startswith("Error") and not st.session_state.creative_response.startswith("Debes"): # Get current timestamp for the filename timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S") # Prepare content for download (use the original unformatted response) download_content = st.session_state.creative_response # Download button st.download_button( label="DESCARGAR IDEAS CREATIVAS", data=download_content, file_name=f"conceptos_creativos_{timestamp}.txt", mime="text/plain" )