Sobit commited on
Commit
e46f973
·
verified ·
1 Parent(s): 34bda2a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +143 -37
app.py CHANGED
@@ -59,6 +59,53 @@ def extract_text(uploaded_file):
59
  if not uploaded_file:
60
  return ""
61
  return extract_text_from_pdf(uploaded_file) if uploaded_file.type == "application/pdf" else extract_text_from_image(uploaded_file)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
 
63
  def extract_professor_details(text):
64
  professor_pattern = r"(Dr\.|Professor|Prof\.?)\s+([A-Z][a-z]+\s[A-Z][a-z]+)"
@@ -164,56 +211,98 @@ templates = {
164
  'email': PromptTemplate.from_template("""
165
  Write ONLY a formal cold email for a research position.
166
  Start with 'Dear Professor' and end with a signature.
167
- Include only 2-3 most relevant highlights from the CV.
168
- Do not include any other text or formatting.
169
 
170
- Details to use:
 
 
 
 
 
 
 
171
  Professor: {professor_name}
172
  University: {university_name}
173
  Research Interests: {research_interests}
174
  Why This Lab: {reason}
 
 
 
 
 
 
 
175
  """),
176
 
177
  'cover_letter': PromptTemplate.from_template("""
178
  Write ONLY a professional cover letter.
179
- Start with a formal greeting and end with a signature.
180
- Focus on relevant experience and skills.
181
- Do not include any headers or additional formatting.
 
 
 
182
 
183
- Details to use:
184
  Job Title: {job_title}
185
  Company: {company}
186
- Key Skills: {key_skills}
187
- Relevant Experience: {resume_text}
 
 
 
 
 
 
188
  """),
189
 
190
  'research_statement': PromptTemplate.from_template("""
191
- Write ONLY a research statement.
192
- Focus on research background, achievements, and future goals.
193
- Maintain a professional and academic tone.
194
- Do not include any headers or section titles.
 
 
 
195
 
196
- Content to include:
197
- Background: {research_background}
198
  Key Projects: {key_projects}
199
  Future Goals: {future_goals}
 
 
 
 
 
 
 
200
  """),
201
 
202
  'sop': PromptTemplate.from_template("""
203
- Write ONLY a Statement of Purpose.
204
- Focus on academic journey, research interests, and career goals.
205
- Maintain a personal yet professional tone.
206
- Do not include any headers or section titles.
 
 
 
207
 
208
- Details to use:
209
  Motivation: {motivation}
210
- Academic Background: {academic_background}
211
- Research Experience: {research_experiences}
212
- Career Goals: {career_goals}
213
- Program Fit: {why_this_program}
 
 
 
 
 
 
 
214
  """)
215
  }
216
 
 
217
  # Create LangChain instances
218
  chains = {key: LLMChain(llm=llm, prompt=template) for key, template in templates.items()}
219
 
@@ -237,12 +326,20 @@ with tab1:
237
  if job_opening_text and cv_resume_text:
238
  with st.spinner("Generating..."):
239
  try:
 
 
 
 
240
  generated_email = chains['email'].run({
241
  "professor_name": professor_name,
242
  "university_name": university_name,
243
  "research_interests": research_interests,
244
  "reason": reason,
245
- "resume_text": cv_resume_text
 
 
 
 
246
  })
247
  st.session_state.generated_content['email'] = clean_email_output(generated_email)
248
  except Exception as e:
@@ -250,13 +347,6 @@ with tab1:
250
  else:
251
  st.error("Please provide all required inputs")
252
 
253
- if st.session_state.generated_content['email']:
254
- st.markdown('<div class="output-container">', unsafe_allow_html=True)
255
- st.markdown(st.session_state.generated_content['email'])
256
- st.download_button("Download Email", st.session_state.generated_content['email'],
257
- file_name="cold_email.txt", key="email_download")
258
- st.markdown('</div>', unsafe_allow_html=True)
259
-
260
  # Cover Letter Tab
261
  with tab2:
262
  job_title = st.text_input("Job Title")
@@ -267,11 +357,15 @@ with tab2:
267
  if job_opening_text and cv_resume_text:
268
  with st.spinner("Generating..."):
269
  try:
 
270
  generated_letter = chains['cover_letter'].run({
271
  "job_title": job_title,
272
  "company": company_name,
273
  "key_skills": key_skills,
274
- "resume_text": cv_resume_text
 
 
 
275
  })
276
  st.session_state.generated_content['cover_letter'] = clean_cover_letter_output(generated_letter)
277
  except Exception as e:
@@ -295,8 +389,15 @@ with tab3:
295
  if st.button("Generate Research Statement", key="research_stmt_btn"):
296
  with st.spinner("Generating..."):
297
  try:
 
298
  generated_statement = chains['research_statement'].run({
299
- "research_background": research_background,
 
 
 
 
 
 
300
  "key_projects": key_projects,
301
  "future_goals": future_goals
302
  })
@@ -322,12 +423,17 @@ with tab4:
322
  if st.button("Generate SOP", key="sop_btn"):
323
  with st.spinner("Generating..."):
324
  try:
 
325
  generated_sop = chains['sop'].run({
326
  "motivation": motivation,
327
- "academic_background": academic_background,
328
- "research_experiences": research_experiences,
329
  "career_goals": career_goals,
330
- "why_this_program": why_this_program
 
 
 
 
331
  })
332
  st.session_state.generated_content['sop'] = clean_sop_output(generated_sop)
333
  except Exception as e:
 
59
  if not uploaded_file:
60
  return ""
61
  return extract_text_from_pdf(uploaded_file) if uploaded_file.type == "application/pdf" else extract_text_from_image(uploaded_file)
62
+ def parse_resume(resume_text):
63
+ """Extract key information from resume text"""
64
+ parsed_info = {
65
+ 'education': [],
66
+ 'skills': [],
67
+ 'experience': [],
68
+ 'projects': [],
69
+ 'publications': []
70
+ }
71
+
72
+ # Find education details
73
+ edu_markers = ['Education:', 'EDUCATION', 'Academic Background']
74
+ exp_markers = ['Experience:', 'EXPERIENCE', 'Work History', 'Employment']
75
+ skill_markers = ['Skills:', 'SKILLS', 'Technical Skills', 'Technologies']
76
+ proj_markers = ['Projects:', 'PROJECTS', 'Key Projects']
77
+ pub_markers = ['Publications:', 'PUBLICATIONS', 'Research Papers']
78
+
79
+ # Helper function to extract section content
80
+ def extract_section(text, start_markers, end_markers):
81
+ content = []
82
+ for start in start_markers:
83
+ start_idx = text.find(start)
84
+ if start_idx != -1:
85
+ section_start = start_idx + len(start)
86
+ section_end = len(text)
87
+
88
+ # Find the next section marker
89
+ for end in end_markers:
90
+ next_section = text.find(end, section_start)
91
+ if next_section != -1:
92
+ section_end = min(section_end, next_section)
93
+
94
+ section_content = text[section_start:section_end].strip()
95
+ content.append(section_content)
96
+
97
+ return '\n'.join(content)
98
+
99
+ # Extract sections
100
+ all_markers = edu_markers + exp_markers + skill_markers + proj_markers + pub_markers
101
+
102
+ parsed_info['education'] = extract_section(resume_text, edu_markers, all_markers)
103
+ parsed_info['experience'] = extract_section(resume_text, exp_markers, all_markers)
104
+ parsed_info['skills'] = extract_section(resume_text, skill_markers, all_markers)
105
+ parsed_info['projects'] = extract_section(resume_text, proj_markers, all_markers)
106
+ parsed_info['publications'] = extract_section(resume_text, pub_markers, all_markers)
107
+
108
+ return parsed_info
109
 
110
  def extract_professor_details(text):
111
  professor_pattern = r"(Dr\.|Professor|Prof\.?)\s+([A-Z][a-z]+\s[A-Z][a-z]+)"
 
211
  'email': PromptTemplate.from_template("""
212
  Write ONLY a formal cold email for a research position.
213
  Start with 'Dear Professor' and end with a signature.
 
 
214
 
215
+ Use these specific details from the CV:
216
+ Education: {education}
217
+ Relevant Experience: {experience}
218
+ Key Skills: {skills}
219
+ Notable Projects: {projects}
220
+ Publications: {publications}
221
+
222
+ Additional Context:
223
  Professor: {professor_name}
224
  University: {university_name}
225
  Research Interests: {research_interests}
226
  Why This Lab: {reason}
227
+
228
+ Guidelines:
229
+ 1. Keep the email concise (max 400 words)
230
+ 2. Focus on the most relevant experience and skills that match the lab's research
231
+ 3. Mention 1-2 specific projects or publications that align with the lab's work
232
+ 4. Include a clear statement of interest and why you're a good fit
233
+ 5. End with your contact information
234
  """),
235
 
236
  'cover_letter': PromptTemplate.from_template("""
237
  Write ONLY a professional cover letter.
238
+ Use these specific details from the CV:
239
+ Education: {education}
240
+ Relevant Experience: {experience}
241
+ Technical Skills: {skills}
242
+ Notable Projects: {projects}
243
+ Publications: {publications}
244
 
245
+ Position Details:
246
  Job Title: {job_title}
247
  Company: {company}
248
+ Required Skills: {key_skills}
249
+
250
+ Guidelines:
251
+ 1. Start with a formal greeting
252
+ 2. Focus on experiences and skills that directly match the job requirements
253
+ 3. Provide specific examples from your projects and work history
254
+ 4. Demonstrate how your background makes you an ideal candidate
255
+ 5. End with a professional closing
256
  """),
257
 
258
  'research_statement': PromptTemplate.from_template("""
259
+ Write ONLY a research statement focused on your academic journey and research goals.
260
+ Use these specific details from your background:
261
+ Education: {education}
262
+ Research Experience: {experience}
263
+ Technical Skills: {skills}
264
+ Research Projects: {projects}
265
+ Publications: {publications}
266
 
267
+ Additional Context:
268
+ Research Background: {research_background}
269
  Key Projects: {key_projects}
270
  Future Goals: {future_goals}
271
+
272
+ Guidelines:
273
+ 1. Describe your research journey and motivation
274
+ 2. Highlight key research achievements and findings
275
+ 3. Connect past work to future research goals
276
+ 4. Demonstrate technical expertise and methodological knowledge
277
+ 5. End with your vision for future contributions to the field
278
  """),
279
 
280
  'sop': PromptTemplate.from_template("""
281
+ Write ONLY a Statement of Purpose (SOP).
282
+ Use these specific details from your background:
283
+ Education: {education}
284
+ Research Experience: {experience}
285
+ Technical Skills: {skills}
286
+ Notable Projects: {projects}
287
+ Publications: {publications}
288
 
289
+ Additional Context:
290
  Motivation: {motivation}
291
+ Academic Goals: {academic_background}
292
+ Research Interests: {research_experiences}
293
+ Career Objectives: {career_goals}
294
+ Program Interest: {why_this_program}
295
+
296
+ Guidelines:
297
+ 1. Tell a coherent story about your academic journey
298
+ 2. Connect your background to your future goals
299
+ 3. Demonstrate why you're prepared for graduate study
300
+ 4. Show alignment between your interests and the program
301
+ 5. Make a compelling case for why you should be admitted
302
  """)
303
  }
304
 
305
+
306
  # Create LangChain instances
307
  chains = {key: LLMChain(llm=llm, prompt=template) for key, template in templates.items()}
308
 
 
326
  if job_opening_text and cv_resume_text:
327
  with st.spinner("Generating..."):
328
  try:
329
+ # Parse resume information
330
+ resume_info = parse_resume(cv_resume_text)
331
+
332
+ # Generate email with parsed information
333
  generated_email = chains['email'].run({
334
  "professor_name": professor_name,
335
  "university_name": university_name,
336
  "research_interests": research_interests,
337
  "reason": reason,
338
+ "education": resume_info['education'],
339
+ "experience": resume_info['experience'],
340
+ "skills": resume_info['skills'],
341
+ "projects": resume_info['projects'],
342
+ "publications": resume_info['publications']
343
  })
344
  st.session_state.generated_content['email'] = clean_email_output(generated_email)
345
  except Exception as e:
 
347
  else:
348
  st.error("Please provide all required inputs")
349
 
 
 
 
 
 
 
 
350
  # Cover Letter Tab
351
  with tab2:
352
  job_title = st.text_input("Job Title")
 
357
  if job_opening_text and cv_resume_text:
358
  with st.spinner("Generating..."):
359
  try:
360
+ resume_info = parse_resume(cv_resume_text)
361
  generated_letter = chains['cover_letter'].run({
362
  "job_title": job_title,
363
  "company": company_name,
364
  "key_skills": key_skills,
365
+ "reason": reason,
366
+ "skills": resume_info['skills'],
367
+ "education": resume_info['education'],
368
+ "experience": resume_info['experience']
369
  })
370
  st.session_state.generated_content['cover_letter'] = clean_cover_letter_output(generated_letter)
371
  except Exception as e:
 
389
  if st.button("Generate Research Statement", key="research_stmt_btn"):
390
  with st.spinner("Generating..."):
391
  try:
392
+ resume_info = parse_resume(cv_resume_text)
393
  generated_statement = chains['research_statement'].run({
394
+ "reason": reason,
395
+ "education": resume_info['education'],
396
+ "experience": resume_info['experience'],
397
+ "skills": resume_info['skills'],
398
+ "projects": resume_info['projects'],
399
+ "publications": resume_info['publications']
400
+ "research_background": resume_info['publications'],
401
  "key_projects": key_projects,
402
  "future_goals": future_goals
403
  })
 
423
  if st.button("Generate SOP", key="sop_btn"):
424
  with st.spinner("Generating..."):
425
  try:
426
+ resume_info = parse_resume(cv_resume_text)
427
  generated_sop = chains['sop'].run({
428
  "motivation": motivation,
429
+ "academic_background": resume_info['education'],
430
+ "research_experiences": resume_info['publications'],
431
  "career_goals": career_goals,
432
+ "why_this_program": why_this_program,
433
+ "experience": resume_info['experience'],
434
+ "skills": resume_info['skills'],
435
+ "projects": resume_info['projects']
436
+
437
  })
438
  st.session_state.generated_content['sop'] = clean_sop_output(generated_sop)
439
  except Exception as e: