File size: 12,796 Bytes
182e34e
 
 
 
6f3095d
 
 
 
 
 
 
 
 
182e34e
 
6f3095d
182e34e
 
6f3095d
 
 
 
 
 
182e34e
6f3095d
 
182e34e
6f3095d
 
 
 
 
 
 
 
182e34e
6f3095d
 
 
 
182e34e
6f3095d
 
 
 
 
 
182e34e
6f3095d
182e34e
6f3095d
 
 
 
 
 
182e34e
6f3095d
 
 
 
 
182e34e
6f3095d
 
182e34e
6f3095d
 
 
 
182e34e
6f3095d
182e34e
6f3095d
 
182e34e
6f3095d
 
 
 
 
 
 
 
 
 
 
 
 
 
182e34e
6f3095d
 
 
 
 
 
 
 
 
 
 
 
182e34e
6f3095d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
182e34e
6f3095d
 
182e34e
6f3095d
 
182e34e
6f3095d
 
 
182e34e
6f3095d
182e34e
 
 
 
6f3095d
 
182e34e
6f3095d
 
 
 
 
 
 
182e34e
6f3095d
 
 
 
182e34e
6f3095d
 
 
 
 
 
 
 
 
 
 
182e34e
6f3095d
 
 
 
 
 
 
182e34e
6f3095d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
182e34e
6f3095d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
182e34e
6f3095d
 
 
 
 
 
 
 
 
 
 
 
 
182e34e
cdfb85d
6f3095d
 
 
 
 
 
 
182e34e
6f3095d
 
182e34e
6f3095d
 
182e34e
6f3095d
 
 
 
 
 
 
 
182e34e
 
6f3095d
 
 
 
 
 
 
 
 
 
 
 
 
 
cdfb85d
6f3095d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
182e34e
6f3095d
 
182e34e
 
 
6f3095d
182e34e
6f3095d
182e34e
6f3095d
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
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("<h1>Generador de Ideas Creativas</h1>", unsafe_allow_html=True)
st.markdown("<h3>Crea conceptos creativos poderosos que conecten con tu audiencia y transmitan el valor de tu marca de manera memorable.</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
# 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"
            )