Email_chatbot / app.py
Prashanthsrn's picture
Update app.py
c61e520 verified
import streamlit as st
import os
from langchain_google_genai import ChatGoogleGenerativeAI
from pyairtable import Table
import PyPDF2
import docx
import resend
# Airtable setup
AIRTABLE_API_KEY = os.getenv("AIRTABLE_API_KEY")
BASE_ID = os.getenv("AIRTABLE_BASE_ID")
TABLE_NAME = "user_data"
# Function to safely initialize Airtable
def init_airtable():
if not all([AIRTABLE_API_KEY, BASE_ID, TABLE_NAME]):
st.sidebar.error("❌ Airtable configuration is incomplete. Please check your environment variables.")
return None
try:
return Table(AIRTABLE_API_KEY, BASE_ID, TABLE_NAME)
except Exception as e:
st.sidebar.error(f"❌ Failed to initialize Airtable: {str(e)}")
return None
table = init_airtable()
# Streamlit page setup
st.set_page_config(page_title="Email Genie", page_icon="🧞", layout="wide")
# Function to parse CV
def parse_cv(file):
content = ""
if file.name.endswith('.pdf'):
pdf_reader = PyPDF2.PdfReader(file)
for page in pdf_reader.pages:
content += page.extract_text()
elif file.name.endswith('.docx'):
doc = docx.Document(file)
for para in doc.paragraphs:
content += para.text + "\n"
else:
st.error("Unsupported file format. Please upload a PDF or DOCX file.")
return None
return content
# Initialize session state
if 'generated_email' not in st.session_state:
st.session_state.generated_email = ""
if 'page' not in st.session_state:
st.session_state.page = "main"
# Sidebar for user information and navigation
with st.sidebar:
st.title("🧞 Email Genie")
email = st.text_input("πŸ“§ Enter Your Email")
stored_user_data = None
if email and table:
try:
records = table.all(formula=f"{{Email}}='{email}'")
if records:
st.success("User data found in the database!")
stored_user_data = records[0]['fields']
else:
st.info("User data not found. Please fill out the remaining details.")
except Exception as e:
st.error(f"Error retrieving user data: {str(e)}")
# Use data from the database if available, otherwise allow manual input
name = st.text_input("Name", value=stored_user_data.get("Name", "") if stored_user_data else "")
profession = st.text_input("Profession", value=stored_user_data.get("Profession", "") if stored_user_data else "")
role = st.text_input("Role", value=stored_user_data.get("Role", "") if stored_user_data else "")
if st.button("Save User Data"):
if not all([name, email, profession, role]):
st.warning("Please fill in all fields before saving.")
elif table:
try:
if stored_user_data:
record_id = records[0]['id']
table.update(record_id, {
"Name": name,
"Email": email,
"Profession": profession,
"Role": role
})
st.success("User data updated successfully!")
else:
table.create({
"Name": name,
"Email": email,
"Profession": profession,
"Role": role
})
st.success("User data saved successfully!")
except Exception as e:
st.error(f"Error saving user data: {str(e)}")
else:
st.error("Unable to save user data due to Airtable configuration issues.")
# Add a sidebar option to navigate between pages
if st.button("Go to Send Email Page" if st.session_state.page == "main" else "Go to Main Page"):
st.session_state.page = "send_email" if st.session_state.page == "main" else "main"
st.rerun()
# Email template generation setup
gemini_api_key = os.getenv("GEMINI_API_KEY")
if not gemini_api_key:
st.error("❌ Gemini API key not found. Please set it as a secret.")
st.stop()
try:
llm = ChatGoogleGenerativeAI(
model="gemini-pro",
verbose=True,
temperature=0.7,
google_api_key=gemini_api_key
)
except Exception as e:
st.error(f"❌ Failed to initialize Gemini model: {str(e)}")
st.stop()
# Set up dynamic email templates as style guides
templates = {
"Job Application": """Dear {Hiring_Manager},
I am writing to apply for the position of {Job_Title} at {Company_Name}. With my experience in {Profession} and {Skills}, I believe I can make a valuable contribution to your team.
[Insert 2-3 sentences highlighting relevant experience and skills from the CV]
I look forward to the opportunity to discuss my application in more detail. Please find my attached CV for your reference.
Best regards,
{Name}""",
"Sales Pitch": """Dear {Client_Name},
I hope this message finds you well. I wanted to introduce you to {Product_Name}, a solution designed to {Value_Proposition}. With my expertise in {Profession}, I believe I can help {Client_Company} achieve {Business_Goal}.
[Insert 1-2 sentences relating the product to the client's specific needs based on research or past interactions]
I would love to schedule a meeting to discuss this in more detail. Please let me know a convenient time for you.
Best regards,
{Name}""",
"Job Offer": """Dear {Candidate_Name},
We are pleased to offer you the position of {Job_Title} at {Company_Name}. After reviewing your qualifications, we are confident that your skills in {Profession} will make you an excellent addition to our team.
[Insert 1-2 sentences highlighting specific skills or experiences from the candidate's CV that impressed the hiring team]
The starting salary for this position is {Salary}. Please review the attached offer letter for further details.
Best regards,
{Hiring_Manager_Name}
{Company_Name}"""
}
# Main Page
if st.session_state.page == "main":
st.header("🧞 Email Genie: Customizable Email Generator")
# Display email template options
st.subheader("Select an Email Type")
email_type = st.selectbox("Email Type", list(templates.keys()))
with st.expander("Email Template Preview", expanded=True):
st.code(templates[email_type], language="text")
# CV file upload (optional)
cv_file = st.file_uploader("Upload your CV (Optional, PDF or DOCX)", type=["pdf", "docx"])
cv_content = None
if cv_file is not None:
cv_content = parse_cv(cv_file)
if cv_content:
st.success("CV uploaded and parsed successfully!")
else:
st.error("Failed to parse the CV. Please check the file format and try again.")
# Merge user data with dynamic details
details = {
"Name": name,
"Profession": profession,
"Role": role,
"email": email
}
# Conditional input fields based on selected email type
st.subheader("Fill in the Details")
if email_type == "Job Application":
details["Hiring_Manager"] = st.text_input("Hiring Manager's Name")
details["Job_Title"] = st.text_input("Job Title")
details["Company_Name"] = st.text_input("Company Name")
details["Skills"] = st.text_input("Skills")
elif email_type == "Sales Pitch":
details["Client_Name"] = st.text_input("Client Name")
details["Product_Name"] = st.text_input("Product Name")
details["Value_Proposition"] = st.text_area("Value Proposition")
details["Client_Company"] = st.text_input("Client's Company Name")
details["Business_Goal"] = st.text_input("Client's Business Goal")
elif email_type == "Job Offer":
details["Candidate_Name"] = st.text_input("Candidate Name")
details["Job_Title"] = st.text_input("Job Title")
details["Company_Name"] = st.text_input("Company Name")
details["Salary"] = st.text_input("Salary")
details["Hiring_Manager_Name"] = st.text_input("Hiring Manager's Name")
# Generate email based on template style and filled-in details using LLM
if st.button("Generate Email"):
missing_fields = [field for field, value in details.items() if not value]
if missing_fields:
st.warning(f"Please fill in the following fields: {', '.join(missing_fields)}")
else:
try:
with st.spinner("🧞 Email Genie is crafting your personalized email..."):
# Update the LLM input prompt
email_prompt = f"""
Generate a professional and personalized email for {email_type} following the style and structure of this template:
{templates[email_type]}
Use these details: {details}
{"CV content: " + cv_content if cv_content else "No CV provided."}
Important:
1. Create a unique and personalized email, don't copy the template exactly.
2. Maintain a similar tone and structure to the template.
3. Include relevant information from the provided details.
4. If CV content is provided, use specific information from it to personalize the email and highlight relevant skills or experiences.
5. Ensure the email flows naturally and doesn't feel like it's just inserting information from the CV.
"""
# Generate the email using LLM
response = llm.invoke(email_prompt)
# Extract the generated email from the response
if isinstance(response, str):
st.session_state.generated_email = response
elif hasattr(response, 'content'):
st.session_state.generated_email = response.content
else:
raise ValueError("Unexpected response format from LLM")
if st.session_state.generated_email:
st.success("πŸŽ‰ Email Genie has crafted your personalized email!")
except Exception as e:
st.error(f"An unexpected error occurred: {str(e)}")
st.error("Please try again or contact support if the issue persists.")
# Display email preview
if st.session_state.generated_email:
st.subheader("Generated Email Preview")
st.text_area("Email Content", st.session_state.generated_email, height=300)
# Information about sending email
st.info("""
To send the email:
1. Navigate to the 'Send Email' page using the sidebar.
2. The generated email will be automatically loaded there.
3. Edit the email if needed.
4. Enter the recipient's email address and configure the email sending settings.
5. Click 'Send Email' to send it.
""")
# Send Email Page
elif st.session_state.page == "send_email":
st.title("πŸ§žβ€β™‚οΈ Email Genie: Send Your Crafted Email")
# Text area for editing the email
email_to_send = st.text_area("Edit your email here", value=st.session_state.get("generated_email", ""), height=300)
# Email sending configuration
st.subheader("Email Sending Configuration")
# Resend API key
resend_api_key = st.text_input("Resend API Key", type="password")
# Sender and recipient email
sender_email = st.text_input("Your Email Address (Sender)")
recipient_email = st.text_input("Recipient Email Address")
if st.button("πŸš€ Send Email"):
if not email_to_send or not recipient_email or not sender_email or not resend_api_key:
st.warning("Please ensure you have filled in all required fields.")
else:
try:
# Initialize Resend client
resend.api_key = resend_api_key
# Send email using Resend
response = resend.Emails.send({
"from": sender_email,
"to": recipient_email,
"subject": "Email from Email Genie",
"text": email_to_send
})
if response['id']:
st.success("πŸŽ‰ Email sent successfully!")
else:
st.error("Failed to send email. Please check your Resend API key and try again.")
except Exception as e:
st.error(f"Failed to send email: {str(e)}")
st.error("Please check your Resend API key and try again.")
# Add some helpful information for users
st.info("""
Note:
1. You need a Resend API key to send emails. If you don't have one, you can sign up at https://resend.com
2. Make sure your sender email is verified in your Resend account.
""")