Aditya Patkar commited on
Commit
6c6956f
·
1 Parent(s): c5be740

Added cover letter generator module

Browse files
Files changed (4) hide show
  1. app.py +42 -2
  2. cover_letter_generator.py +23 -0
  3. loaders.py +59 -0
  4. requirements.txt +4 -1
app.py CHANGED
@@ -2,11 +2,13 @@
2
  This is the main file of the app. This file contains the code for the streamlit app.
3
  '''
4
 
 
5
  import streamlit as st
6
  from streamlit_chat import message
7
 
8
  from job_description_generator import predict_job_description, get_job_description_conversation
9
  from job_description_fixer import fix_job_description, get_job_description_fixer_conversation
 
10
 
11
  conversation = get_job_description_conversation()
12
  if 'generator_conversation' not in st.session_state:
@@ -67,13 +69,14 @@ def main():
67
  st.sidebar.markdown("---")
68
  #selector
69
  page = st.sidebar.selectbox(
70
- "Select a page", ["Home", "Job Description Generator", "Job Description Fixer"])
71
  if page == "Home":
72
  st.title("JobGPT")
73
  st.write("Select a page in the sidebar to get started.")
74
  st.write("### Available options:")
75
  st.write("1. Job Description Generator")
76
  st.write("2. Job Description Fixer")
 
77
  st.markdown("---")
78
 
79
  elif page == "Job Description Generator":
@@ -107,7 +110,7 @@ def main():
107
  message_writer(input_text, response)
108
  elif page == "Job Description Fixer":
109
  container_two = st.container()
110
- container_two.title("JobGPT: A Job Description Fixing Chatbot")
111
  container_two.markdown(
112
  "JobGPT is a chatbot that fixes job descriptions. This is built just for demo purpose."
113
  )
@@ -134,4 +137,41 @@ def main():
134
  input_text, st.session_state['fixer_conversation'])
135
  message_writer(input_text, response)
136
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
137
  main()
 
2
  This is the main file of the app. This file contains the code for the streamlit app.
3
  '''
4
 
5
+ import time
6
  import streamlit as st
7
  from streamlit_chat import message
8
 
9
  from job_description_generator import predict_job_description, get_job_description_conversation
10
  from job_description_fixer import fix_job_description, get_job_description_fixer_conversation
11
+ from cover_letter_generator import get_cover_letter
12
 
13
  conversation = get_job_description_conversation()
14
  if 'generator_conversation' not in st.session_state:
 
69
  st.sidebar.markdown("---")
70
  #selector
71
  page = st.sidebar.selectbox(
72
+ "Select a page", ["Home", "Job Description Generator", "Job Description Fixer", "Cover Letter Generator"])
73
  if page == "Home":
74
  st.title("JobGPT")
75
  st.write("Select a page in the sidebar to get started.")
76
  st.write("### Available options:")
77
  st.write("1. Job Description Generator")
78
  st.write("2. Job Description Fixer")
79
+ st.write("3. Cover Letter Generator")
80
  st.markdown("---")
81
 
82
  elif page == "Job Description Generator":
 
110
  message_writer(input_text, response)
111
  elif page == "Job Description Fixer":
112
  container_two = st.container()
113
+ container_two.title("A Job Description Fixing Chatbot")
114
  container_two.markdown(
115
  "JobGPT is a chatbot that fixes job descriptions. This is built just for demo purpose."
116
  )
 
137
  input_text, st.session_state['fixer_conversation'])
138
  message_writer(input_text, response)
139
 
140
+ elif page == "Cover Letter Generator":
141
+ container_three = st.container()
142
+ container_three.title("A Cover Letter Generating Chatbot")
143
+ container_three.markdown( "JobGPT is a chatbot that generates cover letters. \
144
+ This is built just for demo purpose.")
145
+ container_three.markdown("---")
146
+ #upload file
147
+ uploaded_file = container_three.file_uploader("Upload your resume", type=["pdf"])
148
+ if uploaded_file is not None:
149
+ #store it as a pdf
150
+ with open("resume.pdf", "wb") as file_io:
151
+ file_io.write(uploaded_file.getbuffer())
152
+
153
+ #show a loading bar
154
+ with st.spinner('Uploading...'):
155
+ time.sleep(1)
156
+ container_three.success('Uploaded!')
157
+ container_three.markdown("---")
158
+ #add a form to get title, company and more info from the user
159
+ form = container_three.form(key='my_form')
160
+ title = form.text_input("Job Title (required)", placeholder="VP of Engineering")
161
+ company = form.text_input("Company Name (required)", placeholder="Google")
162
+ more_info = form.text_area("More Info",
163
+ help="Add more info about you or the job in natural language",
164
+ placeholder="I am a software engineer with 5 years of experience. The job focuses on building a new product in healthcare sector.")
165
+ submit_button = form.form_submit_button(label='Submit')
166
+ if submit_button:
167
+ if title == "":
168
+ st.error("Please enter a job title")
169
+ elif company == "":
170
+ st.error("Please enter a company name")
171
+ else:
172
+ cover_letter = get_cover_letter(title, company, more_info, "resume.pdf")
173
+ container_three.markdown("---")
174
+ container_three.markdown("### Cover Letter:")
175
+ container_three.write(cover_letter)
176
+
177
  main()
cover_letter_generator.py ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ '''
2
+ This module generates cover letter from resume
3
+ '''
4
+
5
+ from loaders import get_chain_for_pdf
6
+
7
+ def generate_query(title:str, company:str, more_info = None):
8
+ '''
9
+ Generate a query from a title and company
10
+ '''
11
+ query = f"Write a professional and well-formatted cover letter based on the given resume for the job of {title} at {company}.\n"
12
+ if more_info:
13
+ query += f"More info: {more_info}\n"
14
+ return query
15
+
16
+ def get_cover_letter(title:str, company:str, more_info = None, resume_path = "resume.pdf"):
17
+ '''
18
+ Generate a cover letter from a title and company
19
+ '''
20
+ query = generate_query(title, company, more_info)
21
+ chain = get_chain_for_pdf(resume_path)
22
+ response = chain({"query": query})
23
+ return response['result']
loaders.py ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ '''
2
+ This module contains all the loaders
3
+ '''
4
+
5
+ import os
6
+ from langchain.document_loaders import PyPDFLoader
7
+ from langchain.text_splitter import CharacterTextSplitter
8
+ from langchain.embeddings import OpenAIEmbeddings
9
+ from langchain.vectorstores import Chroma
10
+ from langchain.chains import RetrievalQA
11
+ from langchain.chat_models import ChatOpenAI
12
+
13
+ openai_api_key=os.environ['OPENAI_API_KEY']
14
+
15
+ def load_pdf(path: str = "resume.pdf"):
16
+ '''
17
+ Load a pdf file from a stringio object
18
+ '''
19
+ pdf_loader = PyPDFLoader(path)
20
+ documents = pdf_loader.load()
21
+ return documents
22
+
23
+ def get_embeddings(documents):
24
+ '''
25
+ Get embeddings from a list of documents
26
+ '''
27
+ splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
28
+ texts = splitter.split_documents(documents)
29
+ embeddings = OpenAIEmbeddings(openai_api_key=openai_api_key)
30
+ return texts, embeddings
31
+
32
+ def get_db(texts, embeddings):
33
+ '''
34
+ Get a vectorstore from a list of texts and embeddings
35
+ '''
36
+ db = Chroma.from_documents(texts, embeddings)
37
+ return db
38
+
39
+ def get_retriever(db):
40
+ '''
41
+ Get a retriever from a vectorstore
42
+ '''
43
+ retriever = db.as_retriever(search_type="similarity", search_kwargs={"k":1})
44
+ return retriever
45
+
46
+ def get_chain_for_pdf(path):
47
+ '''
48
+ Get a conversation chain from a path
49
+ '''
50
+ documents = load_pdf(path)
51
+ texts, embeddings = get_embeddings(documents)
52
+ db = get_db(texts, embeddings)
53
+ retriever = get_retriever(db)
54
+ chain = RetrievalQA.from_chain_type(
55
+ llm=ChatOpenAI(temperature=0, openai_api_key=openai_api_key),
56
+ chain_type="stuff",
57
+ retriever=retriever,
58
+ return_source_documents=True)
59
+ return chain
requirements.txt CHANGED
@@ -1,4 +1,7 @@
1
- langchain==0.0.194
2
  openai==0.27.8
3
  streamlit==1.23.1
4
  streamlit_chat==0.0.2.2
 
 
 
 
1
+ langchain==0.0.198
2
  openai==0.27.8
3
  streamlit==1.23.1
4
  streamlit_chat==0.0.2.2
5
+ pypdf==3.9.1
6
+ chromadb==0.3.26
7
+ tiktoken==0.4.0