Spaces:
Sleeping
Sleeping
Upload 14 files
Browse files- app.py +32 -42
- prompts.py +19 -53
app.py
CHANGED
@@ -32,7 +32,7 @@ def get_model(temperature):
|
|
32 |
return genai.GenerativeModel('gemini-2.0-flash', generation_config=generation_config)
|
33 |
|
34 |
# Function to generate headlines and select one randomly
|
35 |
-
def generate_and_select_headline(target_audience, product, temperature, selected_angle):
|
36 |
# Get the model
|
37 |
model = get_model(temperature)
|
38 |
|
@@ -40,6 +40,13 @@ def generate_and_select_headline(target_audience, product, temperature, selected
|
|
40 |
formula_name = random.choice(list(headline_formulas.keys()))
|
41 |
selected_formula = headline_formulas[formula_name]
|
42 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
43 |
# Generate 3 headlines
|
44 |
headlines = generate_headlines_with_model(
|
45 |
model=model,
|
@@ -47,7 +54,8 @@ def generate_and_select_headline(target_audience, product, temperature, selected
|
|
47 |
product=product,
|
48 |
selected_formula=selected_formula,
|
49 |
selected_angle=selected_angle,
|
50 |
-
number_of_headlines=3
|
|
|
51 |
)
|
52 |
|
53 |
# Parse the headlines (assuming they come in a numbered format)
|
@@ -291,33 +299,41 @@ with col1:
|
|
291 |
""", unsafe_allow_html=True)
|
292 |
|
293 |
# Mostrar el anuncio generado
|
294 |
-
# In the submit_ad section, modify how the headline and ad are displayed
|
295 |
-
# Modify the submit_ad section to fix the headline display issue
|
296 |
if submit_ad:
|
297 |
-
if
|
|
|
|
|
|
|
|
|
298 |
# Mostrar el spinner en la segunda columna
|
299 |
with col2:
|
300 |
with st.spinner('Generando anuncio...'):
|
301 |
-
#
|
|
|
|
|
|
|
|
|
|
|
302 |
headline = generate_and_select_headline(
|
303 |
-
|
304 |
-
|
305 |
ad_temperature,
|
306 |
-
emotional_angle
|
|
|
307 |
)
|
308 |
|
309 |
# Generate the ad with the headline
|
310 |
generated_ad = generate_fb_ad(
|
311 |
-
|
312 |
-
|
313 |
ad_temperature,
|
314 |
ad_formula,
|
315 |
emotional_angle,
|
316 |
ad_persona,
|
317 |
-
|
318 |
selected_objective,
|
319 |
-
file_content
|
320 |
-
image_parts if
|
321 |
50000,
|
322 |
headline # Pass the generated headline
|
323 |
)
|
@@ -325,10 +341,7 @@ if submit_ad:
|
|
325 |
if not isinstance(generated_ad, str):
|
326 |
st.error("Error al generar el anuncio")
|
327 |
else:
|
328 |
-
#
|
329 |
-
st.session_state.current_ad = generated_ad
|
330 |
-
|
331 |
-
# Display only the ad without separate headline
|
332 |
st.markdown(f"""
|
333 |
<div style="{styles['results_container']}">
|
334 |
<h3>Anuncio Generado:</h3>
|
@@ -355,30 +368,7 @@ if submit_ad:
|
|
355 |
)
|
356 |
else:
|
357 |
col2.warning("Por favor, completa todos los campos antes de generar el anuncio.")
|
358 |
-
#
|
359 |
-
elif 'current_ad' in st.session_state:
|
360 |
-
with col2:
|
361 |
-
st.markdown(f"""
|
362 |
-
<div style="{styles['results_container']}">
|
363 |
-
<h3>Anuncio Generado:</h3>
|
364 |
-
<p>{st.session_state.current_ad}</p>
|
365 |
-
</div>
|
366 |
-
""", unsafe_allow_html=True)
|
367 |
-
|
368 |
-
# Aplicar estilo para el botón de descarga
|
369 |
-
st.markdown(styles["download_button"], unsafe_allow_html=True)
|
370 |
-
|
371 |
-
# Get current timestamp for the filename
|
372 |
-
import datetime
|
373 |
-
timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
|
374 |
-
|
375 |
-
# Botón de descarga with timestamp in filename
|
376 |
-
st.download_button(
|
377 |
-
label="DESCARGAR ANUNCIO",
|
378 |
-
data=st.session_state.current_ad,
|
379 |
-
file_name=f"anuncio_facebook_{timestamp}.txt",
|
380 |
-
mime="text/plain"
|
381 |
-
)
|
382 |
|
383 |
# Agregar firma del autor al final de la página
|
384 |
st.markdown('---')
|
|
|
32 |
return genai.GenerativeModel('gemini-2.0-flash', generation_config=generation_config)
|
33 |
|
34 |
# Function to generate headlines and select one randomly
|
35 |
+
def generate_and_select_headline(target_audience, product, temperature, selected_angle, file_content=""):
|
36 |
# Get the model
|
37 |
model = get_model(temperature)
|
38 |
|
|
|
40 |
formula_name = random.choice(list(headline_formulas.keys()))
|
41 |
selected_formula = headline_formulas[formula_name]
|
42 |
|
43 |
+
# Create instruction with file content if available
|
44 |
+
headline_instruction = f"Generate 3 compelling headlines for {product} targeting {target_audience}. Use this formula: {selected_formula}. Apply this emotional angle: {selected_angle}."
|
45 |
+
|
46 |
+
# Add file content as context if available
|
47 |
+
if file_content:
|
48 |
+
headline_instruction += f"\n\nUse the following information as additional context:\n{file_content[:5000]}"
|
49 |
+
|
50 |
# Generate 3 headlines
|
51 |
headlines = generate_headlines_with_model(
|
52 |
model=model,
|
|
|
54 |
product=product,
|
55 |
selected_formula=selected_formula,
|
56 |
selected_angle=selected_angle,
|
57 |
+
number_of_headlines=3,
|
58 |
+
additional_context=file_content[:5000] if file_content else ""
|
59 |
)
|
60 |
|
61 |
# Parse the headlines (assuming they come in a numbered format)
|
|
|
299 |
""", unsafe_allow_html=True)
|
300 |
|
301 |
# Mostrar el anuncio generado
|
|
|
|
|
302 |
if submit_ad:
|
303 |
+
# Check if at least a file is uploaded or basic fields are filled
|
304 |
+
has_file_content = file_content.strip() != "" or is_image
|
305 |
+
has_basic_fields = ad_target_audience and ad_product
|
306 |
+
|
307 |
+
if has_file_content or has_basic_fields:
|
308 |
# Mostrar el spinner en la segunda columna
|
309 |
with col2:
|
310 |
with st.spinner('Generando anuncio...'):
|
311 |
+
# Use default values if fields are empty
|
312 |
+
target_audience = ad_target_audience if ad_target_audience else "usuarios interesados"
|
313 |
+
product = ad_product if ad_product else "este producto/servicio"
|
314 |
+
story = input_prompt if input_prompt else ""
|
315 |
+
|
316 |
+
# Generate a headline first, now passing file_content
|
317 |
headline = generate_and_select_headline(
|
318 |
+
target_audience,
|
319 |
+
product,
|
320 |
ad_temperature,
|
321 |
+
emotional_angle,
|
322 |
+
file_content # Pass file content to headline generation
|
323 |
)
|
324 |
|
325 |
# Generate the ad with the headline
|
326 |
generated_ad = generate_fb_ad(
|
327 |
+
target_audience,
|
328 |
+
product,
|
329 |
ad_temperature,
|
330 |
ad_formula,
|
331 |
emotional_angle,
|
332 |
ad_persona,
|
333 |
+
story,
|
334 |
selected_objective,
|
335 |
+
file_content, # Just pass file_content directly
|
336 |
+
image_parts if is_image else None,
|
337 |
50000,
|
338 |
headline # Pass the generated headline
|
339 |
)
|
|
|
341 |
if not isinstance(generated_ad, str):
|
342 |
st.error("Error al generar el anuncio")
|
343 |
else:
|
344 |
+
# Display only the ad without separate headline and without storing in session state
|
|
|
|
|
|
|
345 |
st.markdown(f"""
|
346 |
<div style="{styles['results_container']}">
|
347 |
<h3>Anuncio Generado:</h3>
|
|
|
368 |
)
|
369 |
else:
|
370 |
col2.warning("Por favor, completa todos los campos antes de generar el anuncio.")
|
371 |
+
# Remove the section that displays cached ads
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
372 |
|
373 |
# Agregar firma del autor al final de la página
|
374 |
st.markdown('---')
|
prompts.py
CHANGED
@@ -335,6 +335,18 @@ def create_fb_ad_instruction(target_audience, product, selected_formula, selecte
|
|
335 |
- Create a sense of community with "quienes buscan...", "para aquellos que desean..."
|
336 |
- Let the reader feel spoken to without explicitly using "tú" or its variations
|
337 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
338 |
Use this formula to structure the ad: {selected_formula['description']}
|
339 |
{formula_examples}
|
340 |
|
@@ -376,61 +388,15 @@ def create_fb_ad_instruction(target_audience, product, selected_formula, selecte
|
|
376 |
- CRITICAL: Keep the total ad length between 125-150 words maximum
|
377 |
- Focus on the most impactful points rather than trying to cover everything
|
378 |
"""
|
379 |
-
# Modify the output format instruction to be more explicit
|
380 |
-
instruction += """
|
381 |
-
|
382 |
-
# CRITICAL INSTRUCTION ABOUT OUTPUT FORMAT:
|
383 |
-
Output format MUST follow this EXACT structure:
|
384 |
-
|
385 |
-
| ANUNCIO PREMIUM #1 |
|
386 |
-
|
387 |
-
[Headline for the first ad]
|
388 |
-
|
389 |
-
[Complete text for the first ad, starting with the opening paragraph]
|
390 |
-
|
391 |
-
|
392 |
-
| ANUNCIO PREMIUM #2 |
|
393 |
-
|
394 |
-
[Headline for the second ad]
|
395 |
-
|
396 |
-
[Complete text for the second ad, starting with the opening paragraph]
|
397 |
-
|
398 |
-
|
399 |
-
| ANUNCIO PREMIUM #3 |
|
400 |
-
|
401 |
-
[Headline for the third ad]
|
402 |
-
|
403 |
-
[Complete text for the third ad, starting with the opening paragraph]
|
404 |
-
|
405 |
-
--------------------------
|
406 |
-
|
407 |
-
[Begin with a natural story opening that flows SEAMLESSLY from the headline concept. The opening paragraph must feel like a direct continuation of the headline - as if they are part of the same thought. Create curiosity by expanding on the headline's promise or concept in a way that makes the reader want to know more. The transition between headline and opening paragraph should be so smooth that the reader doesn't feel any disconnect.]
|
408 |
-
|
409 |
-
HEADLINE SELECTION CRITERIA (DO NOT INCLUDE IN OUTPUT):
|
410 |
-
When selecting the best headline for each ad, evaluate based on:
|
411 |
-
1. Which headline creates the strongest curiosity gap
|
412 |
-
2. Which headline aligns most naturally with the ad's narrative flow
|
413 |
-
3. Which headline best incorporates the story theme
|
414 |
-
4. Which headline would be most compelling to {target_audience}
|
415 |
-
5. Which headline best complements the selected angle and copywriting style
|
416 |
-
|
417 |
-
HEADLINE-STORY VERIFICATION (DO NOT INCLUDE IN OUTPUT):
|
418 |
-
Before submitting your final response, verify each ad using these criteria:
|
419 |
-
1. Does the selected headline directly connect to the main theme of the story? (Must be YES)
|
420 |
-
2. Does the opening paragraph continue the exact concept from the selected headline? (Must be YES)
|
421 |
-
3. If the selected headline uses a specific metaphor or concept, does the story maintain it? (Must be YES)
|
422 |
-
4. Would a reader feel any disconnect between the selected headline and the opening paragraph? (Must be NO)
|
423 |
-
5. Is the problem presented subtly without direct statements? (Must be YES)
|
424 |
-
6. Does the ad avoid using direct second-person pronouns (tú, te, tu, etc.)? (Must be YES)
|
425 |
-
|
426 |
-
Your goal is to inspire desire and action, avoiding explanations or categories in the response.
|
427 |
-
DO NOT include any headline separately at the beginning of your response.
|
428 |
-
DO NOT include "Anuncio Generado:" or any other text before the ad format.
|
429 |
-
The headline should appear on its own line, separated from the ad text by a blank line.
|
430 |
-
"""
|
431 |
-
|
432 |
# If a headline is provided, make the instruction even more explicit
|
433 |
if headline:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
434 |
instruction += f"""
|
435 |
|
436 |
IMPORTANTE SOBRE EL TITULAR:
|
|
|
335 |
- Create a sense of community with "quienes buscan...", "para aquellos que desean..."
|
336 |
- Let the reader feel spoken to without explicitly using "tú" or its variations
|
337 |
|
338 |
+
Examples of creative, high-converting headlines:
|
339 |
+
- "They Laughed When I Sat Down At The Piano. But When I Started to Play..."
|
340 |
+
- "Your Body Is Water Starving (Even If Your Mouth Isn't Dry)"
|
341 |
+
- "Warning: Your Productivity Software Is Secretly Making You Less Productive"
|
342 |
+
- "The 'Ugly' Truth About Your Morning Routine That No One Talks About"
|
343 |
+
- "Fired From My 9-5, Now I Make $300/Day With This Weird Trick"
|
344 |
+
- "Is Your Website a Ghost Town? Here's Why Nobody's Visiting"
|
345 |
+
- "The 7-Minute Ritual That Transformed My Sleep Quality"
|
346 |
+
- "What Netflix Knows About You That You Don't Know About Yourself"
|
347 |
+
- "The Counterintuitive Reason Most Diets Fail (It's Not What You Think)"
|
348 |
+
- "Your Competition Is Already Using This Tool. Are You?"
|
349 |
+
|
350 |
Use this formula to structure the ad: {selected_formula['description']}
|
351 |
{formula_examples}
|
352 |
|
|
|
388 |
- CRITICAL: Keep the total ad length between 125-150 words maximum
|
389 |
- Focus on the most impactful points rather than trying to cover everything
|
390 |
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
391 |
# If a headline is provided, make the instruction even more explicit
|
392 |
if headline:
|
393 |
+
# Replace the first ad format with the provided headline
|
394 |
+
instruction = instruction.replace(
|
395 |
+
"| ANUNCIO PREMIUM #1 |\n\n[Headline for the first ad]",
|
396 |
+
f"| ANUNCIO PREMIUM #1 |\n\n{headline}"
|
397 |
+
)
|
398 |
+
|
399 |
+
# Add verification instructions
|
400 |
instruction += f"""
|
401 |
|
402 |
IMPORTANTE SOBRE EL TITULAR:
|