Spaces:
Sleeping
Sleeping
Create app.py
Browse files
app.py
ADDED
@@ -0,0 +1,184 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import gradio as gr
|
3 |
+
from groq import Groq
|
4 |
+
import pandas as pd
|
5 |
+
from datetime import datetime
|
6 |
+
from sendgrid import SendGridAPIClient
|
7 |
+
from sendgrid.helpers.mail import Mail
|
8 |
+
import json
|
9 |
+
from pathlib import Path
|
10 |
+
from typing import Dict, List, Optional
|
11 |
+
|
12 |
+
class UserProfile:
|
13 |
+
def __init__(self, storage_path: str = "profiles.xlsx"):
|
14 |
+
self.storage_path = storage_path
|
15 |
+
self._ensure_storage_exists()
|
16 |
+
|
17 |
+
def _ensure_storage_exists(self):
|
18 |
+
if not Path(self.storage_path).exists():
|
19 |
+
df = pd.DataFrame(columns=['user_id', 'name', 'industry', 'background', 'target_audience'])
|
20 |
+
df.to_excel(self.storage_path, index=False)
|
21 |
+
|
22 |
+
def save_profile(self, profile_data: Dict) -> bool:
|
23 |
+
try:
|
24 |
+
df = pd.read_excel(self.storage_path)
|
25 |
+
profile_data['user_id'] = len(df) + 1
|
26 |
+
df = pd.concat([df, pd.DataFrame([profile_data])], ignore_index=True)
|
27 |
+
df.to_excel(self.storage_path, index=False)
|
28 |
+
return True
|
29 |
+
except Exception as e:
|
30 |
+
print(f"Error saving profile: {e}")
|
31 |
+
return False
|
32 |
+
|
33 |
+
class EmailTemplate:
|
34 |
+
def __init__(self, templates_path: str = "templates.json"):
|
35 |
+
self.templates_path = templates_path
|
36 |
+
self._ensure_templates_exist()
|
37 |
+
|
38 |
+
def _ensure_templates_exist(self):
|
39 |
+
if not Path(self.templates_path).exists():
|
40 |
+
default_templates = {
|
41 |
+
"sales_pitch": {
|
42 |
+
"subject": "Innovative Solutions for {company}",
|
43 |
+
"body": "Dear {name},\n\nI hope this email finds you well..."
|
44 |
+
},
|
45 |
+
"job_application": {
|
46 |
+
"subject": "Experienced {role} Application",
|
47 |
+
"body": "Dear {hiring_manager},\n\nI am writing to express my interest..."
|
48 |
+
}
|
49 |
+
}
|
50 |
+
with open(self.templates_path, 'w') as f:
|
51 |
+
json.dump(default_templates, f)
|
52 |
+
|
53 |
+
def get_template(self, template_name: str) -> Dict:
|
54 |
+
with open(self.templates_path, 'r') as f:
|
55 |
+
templates = json.load(f)
|
56 |
+
return templates.get(template_name, {})
|
57 |
+
|
58 |
+
class EmailGenie:
|
59 |
+
def __init__(self):
|
60 |
+
self.client = Groq(api_key=os.environ.get("GROQ_API_KEY"))
|
61 |
+
self.sendgrid_client = SendGridAPIClient(api_key=os.environ.get("SENDGRID_API_KEY"))
|
62 |
+
self.user_profile = UserProfile()
|
63 |
+
self.email_template = EmailTemplate()
|
64 |
+
|
65 |
+
def structure_info(self, info: str) -> str:
|
66 |
+
prompt = f"Please structure and summarize the following information about a person or company: {info}"
|
67 |
+
chat_completion = self.client.chat.completions.create(
|
68 |
+
messages=[{"role": "user", "content": prompt}],
|
69 |
+
model="llama-3.1-8b-instant",
|
70 |
+
)
|
71 |
+
return chat_completion.choices[0].message.content
|
72 |
+
|
73 |
+
def generate_email(self, template_name: str, context: Dict) -> str:
|
74 |
+
template = self.email_template.get_template(template_name)
|
75 |
+
structured_info = self.structure_info(context.get('recipient_info', ''))
|
76 |
+
|
77 |
+
prompt = f"""
|
78 |
+
Using the following template and information, create a personalized email:
|
79 |
+
Template: {template}
|
80 |
+
Sender: {context['sender_name']}
|
81 |
+
Recipient: {context['recipient']}
|
82 |
+
Subject: {context['email_subject']}
|
83 |
+
Recipient Information: {structured_info}
|
84 |
+
"""
|
85 |
+
|
86 |
+
chat_completion = self.client.chat.completions.create(
|
87 |
+
messages=[{"role": "user", "content": prompt}],
|
88 |
+
model="llama-3.1-8b-instant",
|
89 |
+
)
|
90 |
+
return chat_completion.choices[0].message.content
|
91 |
+
|
92 |
+
def preview_email(self, email_content: str) -> str:
|
93 |
+
return f"=== Email Preview ===\n\n{email_content}"
|
94 |
+
|
95 |
+
def send_email(self, to_email: str, subject: str, content: str) -> bool:
|
96 |
+
message = Mail(
|
97 |
+
from_email=os.environ.get("SENDER_EMAIL"),
|
98 |
+
to_emails=to_email,
|
99 |
+
subject=subject,
|
100 |
+
plain_text_content=content
|
101 |
+
)
|
102 |
+
try:
|
103 |
+
self.sendgrid_client.send(message)
|
104 |
+
return True
|
105 |
+
except Exception as e:
|
106 |
+
print(f"Error sending email: {e}")
|
107 |
+
return False
|
108 |
+
|
109 |
+
def create_interface():
|
110 |
+
emailgenie = EmailGenie()
|
111 |
+
|
112 |
+
with gr.Blocks(title="EmailGenie") as demo:
|
113 |
+
gr.Markdown("# EmailGenie: AI-Powered Email Outreach")
|
114 |
+
|
115 |
+
with gr.Tab("Profile Setup"):
|
116 |
+
name_input = gr.Textbox(label="Full Name")
|
117 |
+
industry_input = gr.Textbox(label="Industry")
|
118 |
+
background_input = gr.Textbox(label="Professional Background")
|
119 |
+
target_input = gr.Textbox(label="Target Audience")
|
120 |
+
save_profile_btn = gr.Button("Save Profile")
|
121 |
+
|
122 |
+
with gr.Tab("Generate Email"):
|
123 |
+
template_dropdown = gr.Dropdown(
|
124 |
+
choices=["sales_pitch", "job_application"],
|
125 |
+
label="Select Template"
|
126 |
+
)
|
127 |
+
subject_input = gr.Textbox(label="Email Subject")
|
128 |
+
recipient_input = gr.Textbox(label="Recipient Name/Company")
|
129 |
+
recipient_info = gr.Textbox(label="Recipient Information")
|
130 |
+
generate_btn = gr.Button("Generate Email")
|
131 |
+
preview_output = gr.Textbox(label="Email Preview", lines=10)
|
132 |
+
|
133 |
+
with gr.Tab("Send Email"):
|
134 |
+
recipient_email = gr.Textbox(label="Recipient Email")
|
135 |
+
send_btn = gr.Button("Send Email")
|
136 |
+
status_output = gr.Textbox(label="Status")
|
137 |
+
|
138 |
+
def save_profile(name, industry, background, target):
|
139 |
+
profile_data = {
|
140 |
+
"name": name,
|
141 |
+
"industry": industry,
|
142 |
+
"background": background,
|
143 |
+
"target_audience": target
|
144 |
+
}
|
145 |
+
success = emailgenie.user_profile.save_profile(profile_data)
|
146 |
+
return "Profile saved successfully!" if success else "Error saving profile"
|
147 |
+
|
148 |
+
def generate_email_handler(template, subject, recipient, info):
|
149 |
+
context = {
|
150 |
+
"sender_name": "Your Name", # Could be fetched from profile
|
151 |
+
"email_subject": subject,
|
152 |
+
"recipient": recipient,
|
153 |
+
"recipient_info": info
|
154 |
+
}
|
155 |
+
email_content = emailgenie.generate_email(template, context)
|
156 |
+
return emailgenie.preview_email(email_content)
|
157 |
+
|
158 |
+
def send_email_handler(email, content):
|
159 |
+
success = emailgenie.send_email(email, "Your Subject", content)
|
160 |
+
return "Email sent successfully!" if success else "Error sending email"
|
161 |
+
|
162 |
+
save_profile_btn.click(
|
163 |
+
save_profile,
|
164 |
+
inputs=[name_input, industry_input, background_input, target_input],
|
165 |
+
outputs=gr.Textbox(label="Status")
|
166 |
+
)
|
167 |
+
|
168 |
+
generate_btn.click(
|
169 |
+
generate_email_handler,
|
170 |
+
inputs=[template_dropdown, subject_input, recipient_input, recipient_info],
|
171 |
+
outputs=preview_output
|
172 |
+
)
|
173 |
+
|
174 |
+
send_btn.click(
|
175 |
+
send_email_handler,
|
176 |
+
inputs=[recipient_email, preview_output],
|
177 |
+
outputs=status_output
|
178 |
+
)
|
179 |
+
|
180 |
+
return demo
|
181 |
+
|
182 |
+
if __name__ == "__main__":
|
183 |
+
demo = create_interface()
|
184 |
+
demo.launch()
|