Created
July 30, 2024 11:50
-
-
Save AlmogBaku/5de026a355f9ef8984fa6a5bebd8f51f to your computer and use it in GitHub Desktop.
The example of the Prompt Engineering Tips article
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This snippet is used as an example for the Prompt Engineering Tips article | |
# The code was partially generated, and NOT PRODUCTION READY at any level. It's written in a way that shows the point | |
# of each tip, and the prompts are actually bad (even though they are functional, and for a prompt engineering tips | |
# article; lol) | |
# | |
# It should be seen as a pseudocode, and not as a final implementation, production code will require carefully | |
# SOP modeling, and a much more detailed process | |
# | |
# The goal is to give you a high-level perspective of the Tips detailed in the article, for readers who need to see | |
# "the whole picture" to understand the concept | |
import asyncio | |
from enum import Enum | |
from typing import List, Dict, Any | |
import jinja2 | |
import yaml | |
from openai import AsyncOpenAI, OpenAI | |
from pydantic import BaseModel, Field, field_validator | |
client = AsyncOpenAI() | |
syncClient = OpenAI() | |
class LandingPageComponent(Enum): | |
HEADER = "header" | |
HERO = "hero" | |
FEATURES = "features" | |
TESTIMONIAL = "testimonial" | |
CTA = "cta" | |
FAQ = "faq" | |
class LandingPageInput(BaseModel): | |
brand: str | |
product_desc: str | |
campaign_desc: str | |
cta_message: str | |
target_audience: str | |
unique_selling_points: List[str] | |
class LandingPageConcept(BaseModel): | |
campaign_desc_reflection: str | |
campaign_motivation: str | |
campaign_narrative: str | |
campaign_title_types: List[str] | |
campaign_title: str = Field(..., min_length=10) | |
tone_and_style: List[str] = Field(..., min_items=2) | |
colors: List[str] = Field(..., min_items=2) | |
@field_validator("campaign_title") | |
@classmethod | |
def check_campaign_title(cls, v): | |
response = syncClient.moderations.create(input=v) | |
if response.results[0].flagged: | |
raise ValueError("The provided text violates the content policy.") | |
return v | |
class ComponentContent(BaseModel): | |
motivation: str | |
content: Any | |
class LandingPageOutput(BaseModel): | |
concept: LandingPageConcept | |
selected_components: List[LandingPageComponent] | |
component_contents: Dict[LandingPageComponent, ComponentContent] | |
html: str | |
def sanitize_code_block(code_block: str) -> str: | |
if code_block.startswith("```yaml"): | |
return code_block[7:-3].strip() | |
if code_block.startswith("```json"): | |
return code_block[7:-3].strip() | |
if code_block.startswith("```"): | |
return code_block[3:-3].strip() | |
return code_block | |
yaml.SafeDumper.default_flow_style = False | |
def string_representer(dumper, data): | |
if '\n' in data: | |
return dumper.represent_scalar('tag:yaml.org,2002:str', data, style='|') | |
return dumper.represent_scalar('tag:yaml.org,2002:str', data, style='"') | |
yaml.SafeDumper.add_representer(str, string_representer) | |
def enum_representer(dumper, data): | |
return dumper.represent_scalar('tag:yaml.org,2002:str', data.value) | |
yaml.SafeDumper.add_representer(LandingPageComponent, enum_representer) | |
def pydantic_representer(dumper, data): | |
return dumper.represent_data(data.model_dump()) | |
yaml.SafeDumper.add_multi_representer(BaseModel, pydantic_representer) | |
def to_yaml(value): | |
return yaml.safe_dump(value, sort_keys=False) | |
jinja2_env = jinja2.Environment() | |
jinja2_env.filters['to_yaml'] = to_yaml | |
generate_concept_sys = """ | |
Your task is to generate a landing page concept based on the provided input. | |
The concept should include a reflection on the campaign description, the motivation behind the campaign, a narrative for the campaign, several title suggestions, a chosen campaign title, and a list of tone and style attributes for the landing page. | |
You MUST respond ONLY in a valid YAML. | |
""" | |
select_components_sys = jinja2_env.from_string(""" | |
Your task is to select the most appropriate components for a landing page based on the provided concept. | |
Choose from the following components: | |
{% for component in components %} | |
- {{ component.value }} | |
{% endfor %} | |
You MUST respond ONLY in a valid YAML list of selected components. | |
""") | |
generate_component_content_template = jinja2_env.from_string(""" | |
Input Data: | |
{{ input | to_yaml }} | |
Campaign Concept: | |
Narrative: "{{ concept.campaign_narrative }}" | |
Title: "{{ concept.campaign_title }}" | |
Campaign's tone and style attributes: {{ concept.tone_and_style | join(', ') }} | |
""") | |
compose_html_template = jinja2_env.from_string(""" | |
Campaign Concept: | |
Narrative: "{{ concept.campaign_narrative }}" | |
Title: "{{ concept.campaign_title }}" | |
Campaign's tone and style attributes: {{ concept.tone_and_style | join(', ') }} | |
Components: | |
{{ components | to_yaml }} | |
""") | |
few_shot_general = [{ | |
"input": LandingPageInput( | |
brand="Mustacher", | |
product_desc="Luxurious mustache cream for grooming and styling", | |
campaign_desc="Father's Day special promotion for our premium mustache cream", | |
cta_message="Treat Dad to the Ultimate Mustache Care", | |
target_audience="Men aged 30-60 who take pride in their facial hair, and their adult children looking for unique gifts", | |
unique_selling_points=[ | |
"All-natural ingredients", | |
"Long-lasting hold without stiffness", | |
"Nourishes and conditions facial hair", | |
"Subtle, masculine scent", | |
"Comes in a vintage-inspired tin perfect for gifting" | |
] | |
), | |
"concept": LandingPageConcept( | |
campaign_desc_reflection="The Father's Day campaign for Mustacher's premium mustache cream presents an opportunity to celebrate fatherhood while highlighting the unique grooming needs of mustache-wearing dads.", | |
campaign_motivation="To position Mustacher's cream as the ideal Father's Day gift, appealing to both style-conscious fathers and their gift-giving children.", | |
campaign_narrative="From the handlebar to the chevron, a father's mustache is more than just facial hair—it's a symbol of wisdom, character, and timeless style. This Father's Day, honor Dad's distinctive dash with Mustacher's premium cream. Our all-natural formula doesn't just style; it nourishes, strengthens, and elevates his mustache game. Whether he's a mustache veteran or a dapper newcomer, give him the gift of impeccable grooming. With Mustacher, every twist, curl, and smooth stroke becomes a moment of self-care, a daily ritual that says, 'I've got this.' This Father's Day, let's celebrate the man who's always been there, with a gift that'll be there for his mustache, every single day.", | |
campaign_title_types=[ | |
"Emotional: 'Honor Dad's Distinction: The Art of Mustache Care'", | |
"Humorous: 'For the Man Who Nose Style: Dad's Ultimate Mustache Companion'", | |
"Product-focused: 'Mustacher: Elevating Fatherhood, One Whisker at a Time'", | |
"Benefit-oriented: 'Groom, Style, Conquer: The Father's Day Mustache Kit'" | |
], | |
campaign_title="Celebrate Dad's Dash of Distinction", | |
tone_and_style=[ | |
"Warm", | |
"Slightly humorous", | |
"Nostalgic", | |
"Masculine", | |
"Sophisticated", | |
"Modern", | |
"Emotionally resonant", | |
"Product-focused", | |
"Confidence-boosting" | |
], | |
colors=["#3D2C2E", "#E3D3A3", "#A7A2A9", "#F2E8CF", "#7D8A2E"] | |
), | |
"components": [LandingPageComponent.HEADER, LandingPageComponent.HERO, LandingPageComponent.FEATURES, | |
LandingPageComponent.TESTIMONIAL, LandingPageComponent.CTA], | |
"content": { | |
LandingPageComponent.HEADER: ComponentContent( | |
motivation="The header sets the tone for the entire landing page and reinforces brand identity.", | |
content={ | |
"logo": "Mustacher", | |
"nav_items": ["Home", "Products", "About", "Contact"] | |
} | |
), | |
LandingPageComponent.HERO: ComponentContent( | |
motivation="The hero section captures attention and communicates the core value proposition.", | |
content={ | |
"headline": "Honor Dad's Distinction", | |
"subheadline": "The Art of Mustache Care", | |
"cta_button": "Shop Now" | |
} | |
), | |
LandingPageComponent.FEATURES: ComponentContent( | |
motivation="The features section highlights the product's unique selling points and benefits to the user.", | |
content={ | |
"headline": "Why Choose Mustacher", | |
"features": [ | |
"All-natural ingredients for guilt-free grooming", | |
"Long-lasting hold without stiffness", | |
"Nourishes and conditions facial hair", | |
"Subtle, masculine scent", | |
"Vintage-inspired tin perfect for gifting" | |
] | |
} | |
), | |
LandingPageComponent.TESTIMONIAL: ComponentContent( | |
motivation="Testimonials provide social proof and build trust with potential customers.", | |
content={ | |
"quote": "Mustacher transformed my mustache game. It's the perfect blend of style and care!", | |
"author": "John D., 42, Architect", | |
"image_alt": "John proudly showing off his impeccably groomed mustache" | |
} | |
), | |
LandingPageComponent.CTA: ComponentContent( | |
motivation="The CTA motivates visitors to take the desired action, moving them closer to conversion.", | |
content={ | |
"headline": "Ready to Elevate Dad's Style?", | |
"subheadline": "Shop our premium mustache cream now", | |
"button_text": "Get the Mustacher Kit", | |
"additional_info": "30-day money-back guarantee • Free shipping on orders over $50" | |
} | |
) | |
}, | |
}] | |
async def generate_concept(input_data: LandingPageInput) -> LandingPageConcept: | |
few_shots = [ | |
{ | |
"input": few_shot_general[0]["input"], | |
"output": few_shot_general[0]["concept"] | |
}, | |
# Add more examples here | |
] | |
messages = [{"role": "system", "content": generate_concept_sys}] | |
messages.extend([ | |
message for example in few_shots for message in [ | |
{"role": "user", "content": to_yaml(example["input"])}, | |
{"role": "assistant", "content": to_yaml(example["output"])} | |
] | |
]) | |
messages.append({"role": "user", "content": to_yaml(input_data)}) | |
response = await client.chat.completions.create( | |
model="gpt-4o", | |
messages=messages | |
) | |
raw_concept = yaml.safe_load(sanitize_code_block(response.choices[0].message.content)) | |
return LandingPageConcept(**raw_concept) | |
async def select_components(concept: LandingPageConcept) -> List[LandingPageComponent]: | |
few_shots = [ | |
{ | |
"concept": few_shot_general[0]["concept"], | |
"output": few_shot_general[0]["components"] | |
}, | |
# Add more examples here | |
] | |
prompt = jinja2_env.from_string(""" | |
campaign's narrative: "{{ concept.campaign_narrative }}" | |
campaign's title: "{{ concept.campaign_title }}" | |
campaign's tone and style attributes: {{ concept.tone_and_style | join(', ') }} | |
""") | |
messages = [{"role": "system", "content": select_components_sys.render(components=LandingPageComponent)}] | |
messages.extend([ | |
message for example in few_shots for message in [ | |
{"role": "user", "content": prompt.render(concept=example["concept"])}, | |
{"role": "assistant", "content": to_yaml(example["output"])} | |
] | |
]) | |
messages.append({"role": "user", "content": prompt.render(concept=concept)}) | |
response = await client.chat.completions.create( | |
model="gpt-4o", | |
messages=messages | |
) | |
selected_components = yaml.safe_load(sanitize_code_block(response.choices[0].message.content)) | |
return [LandingPageComponent(component) for component in selected_components] | |
async def generate_component_content(input_data: LandingPageInput, concept: LandingPageConcept, | |
component: LandingPageComponent) -> ComponentContent: | |
if few_shot_general[0]["content"].get(component) is not None: | |
few_shots = [ | |
{ | |
"input": few_shot_general[0]["input"], | |
"concept": few_shot_general[0]["concept"], | |
"output": few_shot_general[0]["content"][component] | |
}, | |
# Add more examples here | |
] | |
else: | |
few_shots = [] | |
sys = ( | |
f"Craft the content of the landing page component '{component.value}' based on the provided input data and concept." | |
f"You MUST respond in a valid YAML, with a motivation and the content, as shown here." | |
f"You must include the motivation for the content you are providing as the example structure." | |
f"Only include the content for the requested component.") | |
messages = [{"role": "system", "content": sys}] | |
messages.extend([ | |
message for example in few_shots for message in [ | |
{"role": "user", "content": generate_component_content_template.render( | |
input=example["input"], | |
concept=example["concept"], | |
)}, | |
{"role": "assistant", "content": to_yaml(example["output"])} | |
] | |
]) | |
messages.append({ | |
"role": "user", | |
"content": generate_component_content_template.render( | |
input=input_data, | |
concept=concept, | |
component=component.value | |
) | |
}) | |
response = await client.chat.completions.create( | |
model="gpt-4o", | |
messages=messages | |
) | |
raw_content = yaml.safe_load(sanitize_code_block(response.choices[0].message.content)) | |
return ComponentContent(**raw_content) | |
async def compose_html(concept: LandingPageConcept, components: Dict[LandingPageComponent, ComponentContent]) -> str: | |
response = await client.chat.completions.create( | |
model="gpt-4o", | |
messages=[ | |
{ | |
"role": "system", | |
"content": "Compose HTML for a landing page based on the provided concept and component contents." | |
}, | |
{ | |
"role": "user", | |
"content": compose_html_template.render(concept=concept, components=components) | |
} | |
] | |
) | |
return response.choices[0].message.content | |
async def generate_landing_page(input_data: LandingPageInput) -> LandingPageOutput: | |
# Step 1: Conceptualize the campaign | |
concept = await generate_concept(input_data) | |
# Step 2: Select appropriate components | |
selected_components = await select_components(concept) | |
# Step 3: Generate content for each selected component | |
component_contents = {} | |
for component in selected_components: | |
component_contents[component] = await generate_component_content(input_data, concept, component) | |
# Step 4: Compose the final HTML | |
html = await compose_html(concept, component_contents) | |
return LandingPageOutput( | |
concept=concept, | |
selected_components=selected_components, | |
component_contents=component_contents, | |
html=html | |
) | |
async def main(): | |
# Example input for EcoGrow, an eco-friendly gardening product | |
input_data = LandingPageInput( | |
brand="EcoGrow", | |
product_desc="Innovative, biodegradable seed pods for effortless home gardening", | |
campaign_desc="Spring promotion to encourage sustainable home gardening practices", | |
cta_message="Grow Your Own Paradise, Sustainably", | |
target_audience="Urban dwellers aged 25-45 interested in sustainability and home gardening", | |
unique_selling_points=[ | |
"100% biodegradable pods", | |
"Pre-measured nutrients for optimal growth", | |
"Wide variety of herbs, vegetables, and flowers", | |
"Space-saving design for small apartments", | |
"Reduces water usage by 40% compared to traditional gardening" | |
] | |
) | |
result = await generate_landing_page(input_data) | |
with open(f"{result.concept.campaign_title}.html", "w") as f: | |
f.write(result.html) | |
print(to_yaml(result)) | |
if __name__ == "__main__": | |
asyncio.run(main()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment