datascientist22 commited on
Commit
65a47c4
β€’
1 Parent(s): 63fbb09

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +135 -132
app.py CHANGED
@@ -11,193 +11,196 @@ from langchain_cohere import ChatCohere
11
  import random
12
 
13
  # Streamlit app
14
- st.set_page_config(page_title="JobFit CV/Resume Matcher πŸ’Ό", page_icon="πŸ’Ό", layout="wide")
15
 
16
- # Sidebar design
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.subheader("🌐 Cohere API Key")
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
- # Job description input with enhanced style
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
- # User details inputs
81
- st.subheader("πŸ‘€ Personal Information")
82
- name = st.text_input("Name", st.session_state["name"], placeholder="Enter your full name...")
83
- contact = st.text_input("Contact Information", st.session_state["contact"], placeholder="Email, phone number, or LinkedIn...")
84
-
85
- st.subheader("πŸ’Ό Professional Background")
86
- skills = st.text_area("Skills", placeholder="List your skills (one per line)...")
87
- experience = st.text_area("Experience", placeholder="Work experience details (one per line)...")
88
- education = st.text_area("Education", placeholder="Educational qualifications (one per line)...")
89
- projects = st.text_area("Projects", placeholder="Notable projects (one per line)...")
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, job_description, name, contact, skills, experience, education, projects]):
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["projects"] = projects
104
- st.success("βœ… Details Saved Successfully!")
 
105
  else:
106
- st.warning("⚠️ Please fill out all fields to proceed.")
107
 
108
  # Check if the user has saved the details
109
- if "api_key" in st.session_state:
110
- # Main layout for generating the resume
111
- st.subheader("πŸ› οΈ Generate Your Custom Resume")
112
-
113
- # Convert input fields to lists
114
- skills_list = st.session_state["skills"].splitlines()
115
- experience_list = st.session_state["experience"].splitlines()
116
- education_list = st.session_state["education"].splitlines()
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
- # Create documents for vector store
124
- skill_documents = [Document(page_content=skill, metadata={"user_id": user_id, "type": "skill"}, id=str(uuid4())) for skill in skills_list]
125
- experience_documents = [Document(page_content=exp, metadata={"user_id": user_id, "type": "experience"}, id=str(uuid4())) for exp in experience_list]
126
- education_documents = [Document(page_content=edu, metadata={"user_id": user_id, "type": "education"}, id=str(uuid4())) for edu in education_list]
127
- project_documents = [Document(page_content=proj, metadata={"user_id": user_id, "type": "project"}, id=str(uuid4())) for proj in project_list]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
128
 
129
  # Add documents to the vector store
130
- vector_store.add_documents(skill_documents + experience_documents + education_documents + project_documents)
 
 
 
131
 
132
- # Button to generate the resume
133
- if st.button("πŸ“ Generate Resume"):
 
 
134
  def remove_duplicates(results):
135
  seen = set()
136
  unique_results = []
137
  for result in results:
138
- if result.page_content not in seen:
 
139
  unique_results.append(result)
140
- seen.add(result.page_content)
141
  return unique_results
 
 
 
 
 
 
 
 
 
 
 
 
 
142
 
143
- # Search for relevant information based on the job description
144
- relevant_skills = vector_store.similarity_search_by_vector(embedding_model.embed_query(st.session_state["job_description"]), k=10, filter={"type": "skill"})
145
- relevant_experience = vector_store.similarity_search_by_vector(embedding_model.embed_query(st.session_state["job_description"]), k=4, filter={"type": "experience"})
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 results
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
- projects_content = "\n".join([doc.page_content for doc in remove_duplicates(relevant_projects)])
154
 
155
- # Create a prompt to generate the resume
156
  system_prompt = f"""
157
- Generate a well-structured resume for {st.session_state['name']} with the following details:
158
-
159
- Job Description: {st.session_state['job_description']}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
- Follow this structure:
168
- - Name and contact at the top.
169
- - Skills, experience, education, and projects listed clearly.
170
- - Use bullet points and headings where needed.
 
 
 
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 and a copy button
180
- st.subheader("πŸ“„ Generated Resume")
181
- st.text_area("Your Resume", resume_output.content, height=400)
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.warning("⚠️ Please enter your details in the sidebar.")
 
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.")