File size: 5,491 Bytes
5585470
81dcac9
 
 
 
 
5585470
81dcac9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9d0f36f
81dcac9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
import streamlit as st
from langchain_groq import ChatGroq
from langchain_community.document_loaders import WebBaseLoader
from langchain_core.prompts import PromptTemplate
from langchain_core.output_parsers import JsonOutputParser
from PyPDF2 import PdfReader



@st.cache_resource(show_spinner=False)
def load_llm():
    llm = ChatGroq(
        temperature=0,
        groq_api_key='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',
        model_name="llama-3.3-70b-versatile"
    )
    parser = JsonOutputParser()
    return llm, parser

llm, json_parser = load_llm()

if "llm_loaded" not in st.session_state:
    st.toast("✅ LLM Loaded Successfully", icon="🤖")
    st.session_state.llm_loaded = True


def scrape_job_data(url):
    try:
        loader = WebBaseLoader(url)
        data = loader.load().pop().page_content
        return data.strip()
    except Exception as e:
        return f"Error fetching data: {e}"

def read_resume(uploaded_file):
    if uploaded_file.name.endswith(".pdf"):
        reader = PdfReader(uploaded_file)
        text = "\n".join([page.extract_text() for page in reader.pages if page.extract_text()])
    elif uploaded_file.name.endswith(".txt"):
        text = uploaded_file.read().decode("utf-8")
    else:
        text = ""
    return text.strip()


def get_job_desc_json(data):
    template = PromptTemplate.from_template(
        """
        ### SCRAPED DATA FROM WEBSITE:
        {data}

        ### INSTRUCTIONS:
        The scraped text is from the careers page of a website.
        Extract job postings and return valid JSON containing:
        'role', 'experience', 'skills', and 'description'.

        ### VALID JSON (NO PREAMBLE):
        """
    )
    chain = template | llm
    response = chain.invoke({"data": data})
    return json_parser.parse(response.content)

def get_resume_json(data):
    template = PromptTemplate.from_template(
        """
        ### SCRAPED DATA FROM RESUME:
        {resume_data}

        ### INSTRUCTIONS:
        Extract and return valid JSON containing:
        'name', 'about', 'role', 'experience', 'skills', 'projects', 'courses', and 'certificate'.

        ### VALID JSON (NO PREAMBLE):
        """
    )
    chain = template | llm
    response = chain.invoke({"resume_data": data})
    return json_parser.parse(response.content)

def get_cold_email(job, resume):
    template = PromptTemplate.from_template(
        """
        ### JOB DESCRIPTION:
        {job}

        ### RESUME:
        {resume}

        ### INSTRUCTION:
        You are the candidate described in the resume. 
        Write a concise, personalized cold email to the hiring manager expressing interest in the position.
        - Highlight relevant skills and experiences.
        - Maintain a professional yet approachable tone.
        - Avoid generic phrases; make it sound natural and tailored.
        - Keep it under 300-400 words.

        ### EMAIL (NO PREAMBLE):
        """
    )
    chain = template | llm
    response = chain.invoke({"job": job, "resume": resume})
    return response.content.strip()


# ---------------------------------------------------------
#  STREAMLIT APP UI
# ---------------------------------------------------------

st.markdown("""
# **⚡ NeoPitch** ✉️
#### "Turn job descriptions and your resume into perfect cold emails in seconds!"
""")

st.markdown("---")  


st.subheader("1️⃣ Job Description")
job_input_method = st.radio("How would you like to provide the job info?", ["Paste Text", "Enter URL"])

if "job_description" not in st.session_state:
    st.session_state.job_description = ""

if job_input_method == "Paste Text":
    st.session_state.job_description = st.text_area(
        "Paste Job Description Here 📄",
        value=st.session_state.job_description,
        height=150,
    )
else:
    url = st.text_input("Enter Job URL 🌐")
    if st.button("Fetch Job Description"):
        with st.spinner("Scraping job data... 🔍"):
            st.session_state.job_description = scrape_job_data(url)
    st.text_area(
        "Fetched Job Description 📝",
        st.session_state.job_description,
        height=150,
    )

st.markdown("---")  


st.subheader("2️⃣ Resume Input")
resume_input_method = st.radio("How would you like to provide your resume?", ["Upload File", "Paste Text"])

if "resume_data" not in st.session_state:
    st.session_state.resume_data = ""

if resume_input_method == "Upload File":
    uploaded_file = st.file_uploader("Upload Resume (PDF or TXT) 📎", type=["pdf", "txt"])
    if uploaded_file:
        st.session_state.resume_data = read_resume(uploaded_file)
else:
    st.session_state.resume_data = st.text_area(
        "Paste Resume Content Here 📝",
        value=st.session_state.resume_data,
        height=150,
    )

st.markdown("---")  


if st.button("🚀 Generate Email"):
    if not st.session_state.job_description.strip() or not st.session_state.resume_data.strip():
        st.warning("⚠️ Please provide both Job Description and Resume details.")
    else:
        with st.spinner("Analyzing and generating email... 🤖"):
            job = get_job_desc_json(st.session_state.job_description)
            resume = get_resume_json(st.session_state.resume_data)
            email = get_cold_email(job, resume)

        st.success("✅ Email Generated Successfully!")
        st.code(email, language="text")
        st.download_button("📋 Copy Email", email, file_name="cold_email.txt")