jaothan commited on
Commit
cab5c74
·
verified ·
1 Parent(s): 2414e7f

Upload 3 files

Browse files
Files changed (3) hide show
  1. LangChainConnect.py +63 -0
  2. app.py +67 -0
  3. requirements.txt +175 -0
LangChainConnect.py ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from langchain_groq import ChatGroq
3
+ from langchain_core.prompts import PromptTemplate
4
+ from langchain_core.output_parsers import JsonOutputParser
5
+ from langchain_community.document_loaders import WebBaseLoader
6
+ from langchain_core.exceptions import OutputParserException
7
+
8
+ from dotenv import load_dotenv
9
+
10
+ load_dotenv()
11
+
12
+ class LangChainConnect:
13
+ def __init__(self):
14
+ self.llm=ChatGroq(
15
+ model="llama3-8b-8192",
16
+ temperature=0,
17
+ groq_api_key=os.getenv("GROQ_API_KEY"))
18
+
19
+
20
+ def extract_job_content(self, job_text:str)->dict:
21
+ """extract the job content in a json format from the url that was passed in"""
22
+ prompt_extract = PromptTemplate.from_template(
23
+ """
24
+ ###SCRAPED TEXT FROM WEBSITE: {job_description}
25
+ ###INSTRUCTION: The scarped text is a job posting. Extract the title and skills needed for this job in a JSON format, include company name from the link in the url as a field too.
26
+ ###VALID JSON (NO PREAMBLE)""")
27
+ chain_news_extract = prompt_extract | self.llm
28
+ response = chain_news_extract.invoke(input={'job_description': job_text})
29
+ try:
30
+ json_parser = JsonOutputParser()
31
+ json_content = json_parser.parse(response.content)
32
+ except OutputParserException:
33
+ raise OutputParserException(f"content cannot be parsed {response.content}")
34
+ return json_content
35
+
36
+
37
+ def write_cover_letter(self,job_content:dict, profile:str, name:str, experience:str, job_link:str, pdf_resume:list)->str:
38
+ """create the cover letter prompting with the job description, pdf resume and relevant information like name and experience"""
39
+ prompt_email = PromptTemplate.from_template("""
40
+ ###JOB DESCRIPTION:
41
+ {job_description}
42
+ ###INSTRUCTION:
43
+ Add a subject line for this email
44
+ You are {name} a Machine Learning Engineer with {experience} of experience looking for better advancements in the careers.
45
+ Pick the company name from the job link and use that in the text of the cover letter
46
+ You should add information from the provided resume in this letter {pdf_resume} that applies to the specific job description provided
47
+ You should include the email address, and phone number in the letter body itself.
48
+ Don't add anything that is not mentioned in the resume or in the inputs.
49
+ Make sure to thank the hiring manager as the last sentence of the letter.
50
+ Add a signature to the email with the github link, linkedin link.
51
+ ###EMAIL (NO PREAMBLE)
52
+ Don't add footer for the email.
53
+ """)
54
+
55
+ chain_email = prompt_email | self.llm
56
+ response_email = chain_email.invoke({"job_description": str(job_content), "name":name,"experience":experience,"job_link":job_link,"pdf_resume":pdf_resume})
57
+ return response_email.content
58
+
59
+
60
+
61
+
62
+
63
+
app.py ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import streamlit as st
3
+ from langchain_community.document_loaders import WebBaseLoader
4
+ from LangChainConnect import LangChainConnect
5
+ from langchain_community.document_loaders import PyPDFLoader
6
+
7
+ class CoverLetterGenerator:
8
+ def __init__(self):
9
+ st.title('Cover letter generator')
10
+ self.url_input=st.text_input("Enter the Job URL: *", value=None)
11
+ self.tell_about_yourself_name=st.text_input("Your name: *", value=None)
12
+ self.tell_about_yourself_experience=st.text_input("Years of experience: *", value=None)
13
+ self. resume_file = st.file_uploader(label="Upload your resume in PDF format: *")
14
+ self.submit_button = st.button("submit")
15
+ self.lang_chain_connect = LangChainConnect()
16
+
17
+ def check_button_click(self):
18
+ if self.submit_button:
19
+ if self.url_input is None or self.tell_about_yourself_name is None or self.tell_about_yourself_experience is None or self.resume_file is None:
20
+ st.code("Job URL,Name,Experience and Resume are mandatory fields", language='markdown')
21
+ exit(0)
22
+ try:
23
+ cover_letter_content = self.generate_cover_letter()
24
+ st.code(f"{cover_letter_content}", language='markdown')
25
+ except Exception as e:
26
+ raise Exception(f"Exception occured {e}")
27
+
28
+ def save_resume(self):
29
+ if self.resume_file:
30
+ file_path = f"./{self.resume_file.name}"
31
+ # Save the uploaded file to the working directory
32
+ with open(file_path, "wb") as f:
33
+ f.write(self.resume_file.getbuffer())
34
+ return file_path
35
+ else:
36
+ st.code("Invalid Resume")
37
+ exit(0)
38
+
39
+ def load_resume_pdf(self, file_path):
40
+ pages = []
41
+ loader = PyPDFLoader(file_path)
42
+ pages_lazy = loader.lazy_load()
43
+ for page in pages_lazy:
44
+ pages.append(page)
45
+ return pages
46
+
47
+
48
+ def generate_cover_letter(self):
49
+ loader = WebBaseLoader([self.url_input])
50
+ docs=loader.load().pop().page_content
51
+ json_content_description = self.lang_chain_connect.extract_job_content(docs)
52
+ resume_path = self.save_resume()
53
+ pdf_resume = self.load_resume_pdf(resume_path)
54
+ resume_content = ""
55
+ for page in pdf_resume:
56
+ resume_content += page.page_content
57
+ resume_content+="\n"
58
+ # st.code(f"{resume_content}", language='markdown')
59
+ # exit(0)
60
+ os.remove(resume_path)
61
+ cover_letter_content = self.lang_chain_connect.write_cover_letter(json_content_description,"sample",self.tell_about_yourself_name,self.tell_about_yourself_experience,self.url_input, resume_content)
62
+ return cover_letter_content
63
+
64
+
65
+ if __name__ == "__main__":
66
+ cover_letter = CoverLetterGenerator()
67
+ cover_letter.check_button_click()
requirements.txt ADDED
@@ -0,0 +1,175 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ accelerate==1.0.1
2
+ aiohappyeyeballs==2.4.3
3
+ aiohttp==3.10.10
4
+ aiosignal==1.3.1
5
+ annotated-types==0.7.0
6
+ anyconfig==0.14.0
7
+ anyio==4.6.2.post1
8
+ argon2-cffi==23.1.0
9
+ argon2-cffi-bindings==21.2.0
10
+ arrow==1.3.0
11
+ asttokens==2.4.1
12
+ async-lru==2.0.4
13
+ attrs==24.2.0
14
+ babel==2.16.0
15
+ beautifulsoup4==4.12.3
16
+ black==24.10.0
17
+ bleach==6.2.0
18
+ certifi==2024.8.30
19
+ cffi==1.17.1
20
+ chardet==5.2.0
21
+ charset-normalizer==3.4.0
22
+ click==8.1.7
23
+ colorama==0.4.6
24
+ comm==0.2.2
25
+ cycler==0.12.1
26
+ datasets==3.0.2
27
+ debugpy==1.8.7
28
+ decorator==5.1.1
29
+ defusedxml==0.7.1
30
+ dill==0.3.8
31
+ distro==1.9.0
32
+ et_xmlfile==2.0.0
33
+ evaluate==0.4.3
34
+ executing==2.1.0
35
+ fastapi==0.115.3
36
+ fastjsonschema==2.20.0
37
+ filelock==3.16.1
38
+ fonttools==4.54.1
39
+ fqdn==1.5.1
40
+ frozenlist==1.5.0
41
+ fsspec==2024.9.0
42
+ graphviz==0.20.3
43
+ greenlet==3.1.1
44
+ groq==0.12.0
45
+ h11==0.14.0
46
+ httpcore==1.0.7
47
+ httpx==0.27.2
48
+ huggingface-hub==0.26.1
49
+ idna==3.10
50
+ ijson==3.3.0
51
+ ipykernel==6.29.5
52
+ ipython==8.29.0
53
+ ipywidgets==8.1.5
54
+ isodate==0.7.2
55
+ isoduration==20.11.0
56
+ jedi==0.19.2
57
+ Jinja2==3.1.4
58
+ joblib==1.4.2
59
+ json5==0.9.25
60
+ jsonify==0.5
61
+ jsonpatch==1.33
62
+ jsonpointer==3.0.0
63
+ jsonschema==4.23.0
64
+ jsonschema-specifications==2024.10.1
65
+ jupyter==1.1.1
66
+ jupyter_client==8.6.3
67
+ jupyter-console==6.6.3
68
+ jupyter_core==5.7.2
69
+ jupyter-events==0.10.0
70
+ jupyter-lsp==2.2.5
71
+ jupyter_server==2.14.2
72
+ jupyter_server_terminals==0.5.3
73
+ jupyterlab==4.2.6
74
+ jupyterlab_pygments==0.3.0
75
+ jupyterlab_server==2.27.3
76
+ jupyterlab_widgets==3.0.13
77
+ kiwisolver==1.4.7
78
+ langchain==0.3.7
79
+ langchain-core==0.3.19
80
+ langchain-groq==0.2.1
81
+ langchain-text-splitters==0.3.2
82
+ langsmith==0.1.144
83
+ MarkupSafe==3.0.1
84
+ matplotlib-inline==0.1.7
85
+ mistune==3.0.2
86
+ mpmath==1.3.0
87
+ multidict==6.1.0
88
+ multiprocess==0.70.16
89
+ mypy-extensions==1.0.0
90
+ nbclient==0.10.0
91
+ nbconvert==7.16.4
92
+ nbformat==5.10.4
93
+ nest-asyncio==1.6.0
94
+ networkx==3.4.1
95
+ notebook==7.2.2
96
+ notebook_shim==0.2.4
97
+ numpy==1.26.4
98
+ openpyxl==3.1.5
99
+ orjson==3.10.11
100
+ overrides==7.7.0
101
+ packaging==24.1
102
+ pandas==2.2.3
103
+ pandocfilters==1.5.1
104
+ parso==0.8.4
105
+ pathspec==0.12.1
106
+ pillow==11.0.0
107
+ pip==24.2
108
+ platformdirs==4.3.6
109
+ portalocker==2.10.1
110
+ prometheus_client==0.21.0
111
+ prompt_toolkit==3.0.48
112
+ propcache==0.2.0
113
+ psutil==6.1.0
114
+ pure_eval==0.2.3
115
+ pyarrow==17.0.0
116
+ pycparser==2.22
117
+ pydantic==2.9.2
118
+ pydantic_core==2.23.4
119
+ Pygments==2.18.0
120
+ PyJWT==2.9.0
121
+ pyparsing==3.2.0
122
+ python-dateutil==2.9.0.post0
123
+ python-json-logger==2.0.7
124
+ referencing==0.35.1
125
+ regex==2024.9.11
126
+ reportlab==4.2.5
127
+ requests==2.32.3
128
+ requests-toolbelt==1.0.0
129
+ rfc3339-validator==0.1.4
130
+ rfc3986-validator==0.1.1
131
+ rpds-py==0.20.0
132
+ safetensors==0.4.5
133
+ scikit-learn==1.5.2
134
+ scipy==1.14.1
135
+ Send2Trash==1.8.3
136
+ setuptools==75.2.0
137
+ six==1.16.0
138
+ sniffio==1.3.1
139
+ soupsieve==2.6
140
+ SQLAlchemy==2.0.36
141
+ stack-data==0.6.3
142
+ starlette==0.41.0
143
+ sympy==1.13.1
144
+ tenacity==9.0.0
145
+ terminado==0.18.1
146
+ threadpoolctl==3.5.0
147
+ tinycss2==1.3.0
148
+ tokenizers==0.20.1
149
+ toml==0.10.2
150
+ tomli==2.0.2
151
+ torch==2.5.0
152
+ torchvision==0.20.0
153
+ tornado==6.4.1
154
+ tqdm==4.66.5
155
+ traitlets==5.14.3
156
+ transformers==4.45.2
157
+ types-python-dateutil==2.9.0.20241003
158
+ typing_extensions==4.12.2
159
+ tzdata==2024.2
160
+ uri-template==1.3.0
161
+ urllib3==2.2.3
162
+ uvicorn==0.32.0
163
+ wcwidth==0.2.13
164
+ webcolors==24.8.0
165
+ webencodings==0.5.1
166
+ websocket-client==1.8.0
167
+ widgetsnbextension==4.0.13
168
+ xxhash==3.5.0
169
+ yarl==1.16.0
170
+ zipp==3.20.2
171
+ langchain
172
+ langchain_groq
173
+ langchain_core
174
+ langchain_community
175
+ pypdf