datascientist22
commited on
Commit
β’
65a47c4
1
Parent(s):
63fbb09
Update app.py
Browse files
app.py
CHANGED
@@ -11,193 +11,196 @@ from langchain_cohere import ChatCohere
|
|
11 |
import random
|
12 |
|
13 |
# Streamlit app
|
14 |
-
st.
|
15 |
|
16 |
-
# Sidebar
|
17 |
-
def apply_sidebar_colors():
|
18 |
-
st.markdown(
|
19 |
-
"""
|
20 |
-
<style>
|
21 |
-
.sidebar .sidebar-content {
|
22 |
-
background: linear-gradient(45deg, #ff6f61, #ffcc33, #6f9dff, #93f5a3);
|
23 |
-
color: white;
|
24 |
-
}
|
25 |
-
</style>
|
26 |
-
""",
|
27 |
-
unsafe_allow_html=True
|
28 |
-
)
|
29 |
-
|
30 |
-
apply_sidebar_colors()
|
31 |
-
|
32 |
-
# App title with emojis
|
33 |
-
st.title("πΌ JobFit CV/Resume Matcher")
|
34 |
-
|
35 |
-
# Sidebar for API key, job description, and user details
|
36 |
with st.sidebar:
|
37 |
-
st.header("π Enter Your Details")
|
38 |
-
|
39 |
with st.form(key="user_details_form", clear_on_submit=True):
|
|
|
40 |
# Field for API key
|
41 |
-
st.
|
42 |
st.markdown("You can get your API key from [Cohere's website](https://dashboard.cohere.com/).")
|
43 |
api_key = st.text_input("Enter your Cohere API Key", type="password")
|
44 |
|
45 |
-
#
|
46 |
-
st.subheader("π Job Description")
|
47 |
-
st.markdown("""
|
48 |
-
<style>
|
49 |
-
.job-description-textarea {
|
50 |
-
background-color: #f7f7f7;
|
51 |
-
border: 2px solid #ff6f61;
|
52 |
-
border-radius: 8px;
|
53 |
-
padding: 10px;
|
54 |
-
font-weight: bold;
|
55 |
-
font-size: 16px;
|
56 |
-
color: #333;
|
57 |
-
}
|
58 |
-
</style>
|
59 |
-
""", unsafe_allow_html=True)
|
60 |
-
|
61 |
-
# Ensure the default value is fetched from session state if it exists
|
62 |
-
job_description = st.text_area("Paste the Job Description here",
|
63 |
-
placeholder="Enter the job description you're applying for...",
|
64 |
-
height=200,
|
65 |
-
key="job_description",
|
66 |
-
help="Provide the job description for matching with your resume.",
|
67 |
-
value=st.session_state.get("job_description", ""))
|
68 |
-
|
69 |
-
# Initialize other session state variables if not present
|
70 |
if "name" not in st.session_state:
|
71 |
st.session_state["name"] = ""
|
72 |
if "contact" not in st.session_state:
|
73 |
st.session_state["contact"] = ""
|
74 |
|
|
|
75 |
if "user_id" not in st.session_state:
|
76 |
st.session_state["user_id"] = str(random.randint(1000000000, 9999999999))
|
77 |
-
|
78 |
user_id = st.session_state["user_id"]
|
79 |
-
|
80 |
-
|
81 |
-
st.
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
st.
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
submit_button = st.form_submit_button(label="Save Details")
|
92 |
-
|
93 |
-
# Save the data if all fields are filled
|
94 |
if submit_button:
|
95 |
-
if all([api_key,
|
96 |
st.session_state["api_key"] = api_key
|
97 |
st.session_state["name"] = name
|
98 |
st.session_state["contact"] = contact
|
99 |
-
st.session_state["job_description"] = job_description
|
100 |
st.session_state["skills"] = skills
|
101 |
st.session_state["experience"] = experience
|
102 |
st.session_state["education"] = education
|
103 |
-
st.session_state["
|
104 |
-
st.
|
|
|
105 |
else:
|
106 |
-
st.warning("
|
107 |
|
108 |
# Check if the user has saved the details
|
109 |
-
if "
|
110 |
-
#
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
project_list = st.session_state["projects"].splitlines()
|
118 |
-
|
119 |
-
# Initialize embeddings and vector store
|
120 |
embedding_model = CohereEmbeddings(cohere_api_key=st.session_state["api_key"], model="embed-english-light-v3.0")
|
121 |
-
vector_store = Chroma(collection_name="user_data", embedding_function=embedding_model, persist_directory="chroma")
|
122 |
|
123 |
-
#
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
128 |
|
129 |
# Add documents to the vector store
|
130 |
-
vector_store.add_documents(skill_documents
|
|
|
|
|
|
|
131 |
|
132 |
-
#
|
133 |
-
|
|
|
|
|
134 |
def remove_duplicates(results):
|
135 |
seen = set()
|
136 |
unique_results = []
|
137 |
for result in results:
|
138 |
-
|
|
|
139 |
unique_results.append(result)
|
140 |
-
seen.add(
|
141 |
return unique_results
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
142 |
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
relevant_education = vector_store.similarity_search_by_vector(embedding_model.embed_query(st.session_state["job_description"]), k=4, filter={"type": "education"})
|
147 |
-
relevant_projects = vector_store.similarity_search_by_vector(embedding_model.embed_query(st.session_state["job_description"]), k=4, filter={"type": "project"})
|
148 |
|
149 |
-
# Format the
|
150 |
skills_content = "\n".join([doc.page_content for doc in remove_duplicates(relevant_skills)])
|
151 |
experience_content = "\n".join([doc.page_content for doc in remove_duplicates(relevant_experience)])
|
152 |
education_content = "\n".join([doc.page_content for doc in remove_duplicates(relevant_education)])
|
153 |
-
|
154 |
|
155 |
-
# Create a prompt to generate
|
156 |
system_prompt = f"""
|
157 |
-
Generate a
|
158 |
-
|
159 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
160 |
Name: {st.session_state['name']}
|
161 |
Contact: {st.session_state['contact']}
|
|
|
162 |
Skills: {skills_content}
|
163 |
Experience: {experience_content}
|
164 |
Education: {education_content}
|
165 |
-
Projects: {projects_content}
|
166 |
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
|
|
|
|
|
|
171 |
"""
|
172 |
|
173 |
# Initialize ChatCohere
|
174 |
chat_model = ChatCohere(cohere_api_key=st.session_state["api_key"])
|
175 |
|
176 |
-
# Generate resume
|
177 |
resume_output = chat_model.invoke(input=system_prompt)
|
178 |
|
179 |
-
# Display the generated resume
|
180 |
-
st.subheader("
|
181 |
-
st.
|
182 |
-
st.button("π Copy Resume to Clipboard")
|
183 |
-
|
184 |
-
# Cover Letter Section
|
185 |
-
st.subheader("π© Generate Cover Letter")
|
186 |
-
cover_letter_prompt = f"""
|
187 |
-
Create a cover letter for {st.session_state['name']} for the following job description:
|
188 |
-
|
189 |
-
Job Description: {st.session_state['job_description']}
|
190 |
-
|
191 |
-
Ensure the cover letter is professional and tailored to the job.
|
192 |
-
"""
|
193 |
-
|
194 |
-
# Generate cover letter using ChatCohere
|
195 |
-
cover_letter_output = chat_model.invoke(input=cover_letter_prompt)
|
196 |
-
|
197 |
-
# Display the generated cover letter
|
198 |
-
st.subheader("π Generated Cover Letter")
|
199 |
-
st.text_area("Your Cover Letter", cover_letter_output.content, height=400)
|
200 |
-
st.button("π Copy Cover Letter to Clipboard")
|
201 |
|
202 |
else:
|
203 |
-
st.
|
|
|
11 |
import random
|
12 |
|
13 |
# Streamlit app
|
14 |
+
st.title("Resume Matcher")
|
15 |
|
16 |
+
# Sidebar for API key input and user details
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
17 |
with st.sidebar:
|
|
|
|
|
18 |
with st.form(key="user_details_form", clear_on_submit=True):
|
19 |
+
|
20 |
# Field for API key
|
21 |
+
st.header("Cohere API Key")
|
22 |
st.markdown("You can get your API key from [Cohere's website](https://dashboard.cohere.com/).")
|
23 |
api_key = st.text_input("Enter your Cohere API Key", type="password")
|
24 |
|
25 |
+
# Check if name and contact are already in session state
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
26 |
if "name" not in st.session_state:
|
27 |
st.session_state["name"] = ""
|
28 |
if "contact" not in st.session_state:
|
29 |
st.session_state["contact"] = ""
|
30 |
|
31 |
+
# Generate or retrieve a unique user ID
|
32 |
if "user_id" not in st.session_state:
|
33 |
st.session_state["user_id"] = str(random.randint(1000000000, 9999999999))
|
34 |
+
|
35 |
user_id = st.session_state["user_id"]
|
36 |
+
|
37 |
+
st.header("Enter Your Details")
|
38 |
+
name = st.text_input("Name", st.session_state["name"])
|
39 |
+
contact = st.text_input("Contact - Email, Number, links, etc", st.session_state["contact"])
|
40 |
+
skills = st.text_area("Skills - Technical, Soft, etc (one per line)", "")
|
41 |
+
experience = st.text_area("Experience - Company Name, Duration, Role, Responsibilities etc (one per line)", "")
|
42 |
+
education = st.text_area("Education - Degree Name, University Name, Duration etc (one per line)", "")
|
43 |
+
project = st.text_area("Projects - Name, Features etc (one per line)", "")
|
44 |
+
|
45 |
+
submit_button = st.form_submit_button(label="Save")
|
46 |
+
|
|
|
|
|
|
|
|
|
47 |
if submit_button:
|
48 |
+
if all([api_key, name, contact, skills, experience, education, project]):
|
49 |
st.session_state["api_key"] = api_key
|
50 |
st.session_state["name"] = name
|
51 |
st.session_state["contact"] = contact
|
|
|
52 |
st.session_state["skills"] = skills
|
53 |
st.session_state["experience"] = experience
|
54 |
st.session_state["education"] = education
|
55 |
+
st.session_state["project"] = project
|
56 |
+
st.session_state["saved"] = True
|
57 |
+
st.success("Details saved successfully!")
|
58 |
else:
|
59 |
+
st.warning("Please fill out all fields.")
|
60 |
|
61 |
# Check if the user has saved the details
|
62 |
+
if st.session_state.get("saved", False):
|
63 |
+
# Convert inputs to lists (split by new lines)
|
64 |
+
skills_list = [s.strip() for s in st.session_state["skills"].splitlines() if s.strip()]
|
65 |
+
experience_list = [e.strip() for e in st.session_state["experience"].splitlines() if e.strip()]
|
66 |
+
education_list = [e.strip() for e in st.session_state["education"].splitlines() if e.strip()]
|
67 |
+
project_list = [p.strip() for p in st.session_state["project"].splitlines() if p.strip()]
|
68 |
+
|
69 |
+
# Initialize Cohere Embeddings
|
|
|
|
|
|
|
70 |
embedding_model = CohereEmbeddings(cohere_api_key=st.session_state["api_key"], model="embed-english-light-v3.0")
|
|
|
71 |
|
72 |
+
# Initialize Chroma vector store
|
73 |
+
vector_store = Chroma(
|
74 |
+
collection_name="user_data",
|
75 |
+
embedding_function=embedding_model,
|
76 |
+
persist_directory="chroma"
|
77 |
+
)
|
78 |
+
|
79 |
+
# Create documents for skills, experience, education, and projects
|
80 |
+
skill_documents = [
|
81 |
+
Document(
|
82 |
+
page_content=skill,
|
83 |
+
metadata={"user_id": user_id, "type": "skill"},
|
84 |
+
id=str(uuid4())
|
85 |
+
)
|
86 |
+
for skill in skills_list
|
87 |
+
]
|
88 |
+
|
89 |
+
experience_documents = [
|
90 |
+
Document(
|
91 |
+
page_content=exp,
|
92 |
+
metadata={"user_id": user_id, "type": "experience"},
|
93 |
+
id=str(uuid4())
|
94 |
+
)
|
95 |
+
for exp in experience_list
|
96 |
+
]
|
97 |
+
|
98 |
+
education_documents = [
|
99 |
+
Document(
|
100 |
+
page_content=edu,
|
101 |
+
metadata={"user_id": user_id, "type": "education"},
|
102 |
+
id=str(uuid4())
|
103 |
+
)
|
104 |
+
for edu in education_list
|
105 |
+
]
|
106 |
+
|
107 |
+
project_documents = [
|
108 |
+
Document(
|
109 |
+
page_content=proj,
|
110 |
+
metadata={"user_id": user_id, "type": "project"},
|
111 |
+
id=str(uuid4())
|
112 |
+
)
|
113 |
+
for proj in project_list
|
114 |
+
]
|
115 |
|
116 |
# Add documents to the vector store
|
117 |
+
vector_store.add_documents(documents=skill_documents)
|
118 |
+
vector_store.add_documents(documents=experience_documents)
|
119 |
+
vector_store.add_documents(documents=education_documents)
|
120 |
+
vector_store.add_documents(documents=project_documents)
|
121 |
|
122 |
+
# Main app layout for job description and resume generation
|
123 |
+
job_description = st.text_area("Job Description", "")
|
124 |
+
|
125 |
+
if st.button("Generate Resume"):
|
126 |
def remove_duplicates(results):
|
127 |
seen = set()
|
128 |
unique_results = []
|
129 |
for result in results:
|
130 |
+
content = result.page_content
|
131 |
+
if content not in seen:
|
132 |
unique_results.append(result)
|
133 |
+
seen.add(content)
|
134 |
return unique_results
|
135 |
+
|
136 |
+
# Retrieve relevant information
|
137 |
+
relevant_skills = vector_store.similarity_search_by_vector(
|
138 |
+
embedding=embedding_model.embed_query(job_description), k=10, filter={"type": "skill"}
|
139 |
+
)
|
140 |
+
|
141 |
+
relevant_experience = vector_store.similarity_search_by_vector(
|
142 |
+
embedding=embedding_model.embed_query(job_description), k=4, filter={"type": "experience"}
|
143 |
+
)
|
144 |
+
|
145 |
+
relevant_education = vector_store.similarity_search_by_vector(
|
146 |
+
embedding=embedding_model.embed_query(job_description), k=4, filter={"type": "education"}
|
147 |
+
)
|
148 |
|
149 |
+
relevant_project = vector_store.similarity_search_by_vector(
|
150 |
+
embedding=embedding_model.embed_query(job_description), k=4, filter={"type": "project"}
|
151 |
+
)
|
|
|
|
|
152 |
|
153 |
+
# Format the relevant information
|
154 |
skills_content = "\n".join([doc.page_content for doc in remove_duplicates(relevant_skills)])
|
155 |
experience_content = "\n".join([doc.page_content for doc in remove_duplicates(relevant_experience)])
|
156 |
education_content = "\n".join([doc.page_content for doc in remove_duplicates(relevant_education)])
|
157 |
+
project_content = "\n".join([doc.page_content for doc in remove_duplicates(relevant_project)])
|
158 |
|
159 |
+
# Create a system prompt to generate a resume
|
160 |
system_prompt = f"""
|
161 |
+
Generate a resume with the following details:
|
162 |
+
|
163 |
+
Guidelines:
|
164 |
+
Be specific and use active voice.
|
165 |
+
Avoid errors, passive language, and personal pronouns.
|
166 |
+
Ensure consistency and readability.
|
167 |
+
|
168 |
+
Avoid:
|
169 |
+
Spelling/grammar errors, missing contact info, poor organization.
|
170 |
+
|
171 |
+
Action Verbs Examples:
|
172 |
+
Leadership: Led, Managed
|
173 |
+
Communication: Presented, Promoted
|
174 |
+
Technical: Engineered, Programmed
|
175 |
+
Organizational: Organized, Implemented
|
176 |
+
|
177 |
+
Details:
|
178 |
+
Job Description: {job_description}
|
179 |
Name: {st.session_state['name']}
|
180 |
Contact: {st.session_state['contact']}
|
181 |
+
Projects: {project_content}
|
182 |
Skills: {skills_content}
|
183 |
Experience: {experience_content}
|
184 |
Education: {education_content}
|
|
|
185 |
|
186 |
+
Formatting:
|
187 |
+
Start with name and contact.
|
188 |
+
List experience, education, projects and skills in order.
|
189 |
+
Use headings and bullet points.
|
190 |
+
|
191 |
+
Instruction:
|
192 |
+
Do not add any extra text or headings from yourself; use only the provided details.
|
193 |
"""
|
194 |
|
195 |
# Initialize ChatCohere
|
196 |
chat_model = ChatCohere(cohere_api_key=st.session_state["api_key"])
|
197 |
|
198 |
+
# Generate the resume
|
199 |
resume_output = chat_model.invoke(input=system_prompt)
|
200 |
|
201 |
+
# Display the generated resume
|
202 |
+
st.subheader("Generated Resume")
|
203 |
+
st.write(resume_output.content)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
204 |
|
205 |
else:
|
206 |
+
st.info("Please fill out your details in the sidebar and click Save to proceed.")
|