Jonathand2028's picture
Upload folder using huggingface_hub
873569a verified
import os
import asyncio
import nest_asyncio
from dotenv import load_dotenv
import gradio as gr
from contextlib import contextmanager
from openai import OpenAI
import sendgrid
from sendgrid.helpers.mail import Mail, Email, To, Content
from pathlib import Path
import certifi
os.environ['SSL_CERT_FILE'] = certifi.where()
# Patch event loop for notebook compatibility
nest_asyncio.apply()
env_path = Path(__file__).resolve().parents[1] / ".env"
load_dotenv(dotenv_path=env_path, override=True)
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
# --- Simple trace context manager for logging ---
@contextmanager
def trace(name):
print(f"TRACE START: {name}")
yield
print(f"TRACE END: {name}")
# --- Agent class ---
class Agent:
def __init__(self, name, instructions, model="gpt-4o-mini", tools=None, handoffs=None):
self.name = name
self.instructions = instructions
self.model = model
self.tools = tools or []
self.handoffs = handoffs or []
# --- Runner logic ---
class Runner:
@staticmethod
async def run(agent, input_text):
print(f"Running agent: {agent.name}")
# The OpenAI client call is synchronous here (no await)
response = client.chat.completions.create(
model=agent.model,
messages=[
{"role": "system", "content": agent.instructions},
{"role": "user", "content": input_text}
]
)
content = response.choices[0].message.content.strip()
return type("Result", (), {"final_output": content})
# --- Sales agents instructions ---
instructions1 = (
"You are a sales agent working for ComplAI, a company that provides a SaaS tool for ensuring SOC2 compliance "
"and preparing for audits, powered by AI. You write professional, serious cold emails."
)
instructions2 = (
"You are a humorous, engaging sales agent working for ComplAI, a company that provides a SaaS tool for "
"ensuring SOC2 compliance and preparing for audits, powered by AI. You write attention-grabbing, lighthearted cold emails."
)
instructions3 = (
"You are a busy sales agent who writes very short, direct cold emails for ComplAI, a SaaS compliance automation tool."
)
sales_agent1 = Agent("Professional Sales Agent", instructions1)
sales_agent2 = Agent("Engaging Sales Agent", instructions2)
sales_agent3 = Agent("Busy Sales Agent", instructions3)
sales_picker = Agent(
name="Sales Picker",
instructions=(
"You pick the best cold sales email from the given options. "
"Imagine you are a customer and pick the one you are most likely to respond to. "
"Do not give an explanation; reply with the selected email only."
)
)
# --- SendGrid email sending function ---
def send_email(body: str):
sg = sendgrid.SendGridAPIClient(api_key=os.getenv('SENDGRID_API_KEY'))
from_email = Email("jonathand2028@uchicago.edu") # Change to your verified sender email
to_email = To("jonathand2028@uchicago.edu") # Change to your recipient email
content = Content("text/plain", body)
mail = Mail(from_email, to_email, "Sales email", content)
response = sg.client.mail.send.post(request_body=mail.get())
return {"status": "success", "code": response.status_code}
# --- Async functions to generate emails and pick best ---
async def generate_emails_async(product_description: str):
with trace("Parallel cold emails"):
results = await asyncio.gather(
Runner.run(sales_agent1, product_description),
Runner.run(sales_agent2, product_description),
Runner.run(sales_agent3, product_description),
)
return [r.final_output for r in results]
async def pick_best_email_async(emails):
email_block = "\n\n".join(f"Option {i+1}:\n{email}" for i, email in enumerate(emails))
selection_result = await Runner.run(sales_picker, email_block)
return selection_result.final_output
# --- Format emails nicely for Markdown display ---
def format_emails_markdown(emails, best_email):
md = ""
for i, email in enumerate(emails, 1):
md += f"### Agent {i} Email:\n\n```\n{email.strip()}\n```\n\n"
md += f"## 🟢 Best Picked Email:\n\n```\n{best_email.strip()}\n```\n"
return md
# --- Sync wrapper for Gradio ---
def generate_and_select(product_description: str):
loop = asyncio.get_event_loop()
emails = loop.run_until_complete(generate_emails_async(product_description))
best = loop.run_until_complete(pick_best_email_async(emails))
send_result = send_email(best)
formatted_md = format_emails_markdown(emails, best)
return formatted_md, "" # Clear input box
# --- Gradio UI ---
with gr.Blocks() as demo:
gr.Markdown("# 💼 AI Sales Email Generator with Email Sender")
gr.Markdown(
"Enter a product or service below. Three AI sales reps will write cold emails, "
"a fourth AI will pick the best one, and it will be sent automatically."
)
with gr.Row():
with gr.Column():
input_text = gr.Textbox(label="Product or Service", placeholder="e.g. AI compliance tool for startups")
generate_btn = gr.Button("Generate Emails & Send")
with gr.Column():
output_text = gr.Markdown(label="Results")
generate_btn.click(
fn=generate_and_select,
inputs=input_text,
outputs=[output_text, input_text]
)
if __name__ == "__main__":
demo.launch()