Utkarsh736 commited on
Commit
f3d6510
Β·
1 Parent(s): 538765f

[Init] Setup

Browse files
Files changed (1) hide show
  1. resume_agent.py +491 -0
resume_agent.py ADDED
@@ -0,0 +1,491 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import re
3
+ from typing import Dict, List, Optional, Tuple
4
+ from dataclasses import dataclass
5
+ from abc import ABC, abstractmethod
6
+ import google.generativeai as genai
7
+ from datetime import datetime
8
+
9
+ # Configure Gemini API
10
+ genai.configure(api_key="YOUR_GEMINI_API_KEY")
11
+
12
+ @dataclass
13
+ class ResumeData:
14
+ """Data structure to hold resume information"""
15
+ personal_info: Dict
16
+ summary: str
17
+ experiences: List[Dict]
18
+ skills: List[str]
19
+ education: List[Dict]
20
+ raw_text: str
21
+
22
+ @dataclass
23
+ class JobDescription:
24
+ """Data structure for job descriptions"""
25
+ title: str
26
+ company: str
27
+ description: str
28
+ requirements: List[str]
29
+ keywords: List[str]
30
+
31
+ class Agent(ABC):
32
+ """Base agent class"""
33
+
34
+ def __init__(self, model_name: str = "gemini-1.5-flash"):
35
+ self.model = genai.GenerativeModel(model_name)
36
+
37
+ @abstractmethod
38
+ def execute(self, *args, **kwargs):
39
+ pass
40
+
41
+ def generate_response(self, prompt: str) -> str:
42
+ """Generate response using Gemini"""
43
+ try:
44
+ response = self.model.generate_content(prompt)
45
+ return response.text
46
+ except Exception as e:
47
+ return f"Error generating response: {str(e)}"
48
+
49
+ class SummaryAgent(Agent):
50
+ """Agent responsible for creating compelling professional summaries"""
51
+
52
+ def execute(self, resume_data: ResumeData, job_desc: Optional[JobDescription] = None) -> str:
53
+ context = f"""
54
+ Personal Info: {resume_data.personal_info}
55
+ Experience: {resume_data.experiences}
56
+ Skills: {resume_data.skills}
57
+ Education: {resume_data.education}
58
+ """
59
+
60
+ job_context = ""
61
+ if job_desc:
62
+ job_context = f"""
63
+ Target Job: {job_desc.title} at {job_desc.company}
64
+ Job Requirements: {job_desc.requirements}
65
+ """
66
+
67
+ prompt = f"""
68
+ Create a compelling professional summary (2-3 sentences) based on this resume information:
69
+ {context}
70
+
71
+ {job_context}
72
+
73
+ Guidelines:
74
+ - Highlight unique value proposition
75
+ - Use action-oriented language
76
+ - Focus on achievements and impact
77
+ - Keep it concise and engaging
78
+ - If job description provided, align with role requirements
79
+
80
+ Return only the professional summary text.
81
+ """
82
+
83
+ return self.generate_response(prompt)
84
+
85
+ class ExperienceMatchingAgent(Agent):
86
+ """Agent for matching experiences to job descriptions"""
87
+
88
+ def execute(self, resume_data: ResumeData, job_desc: JobDescription) -> List[Dict]:
89
+ experiences_text = json.dumps(resume_data.experiences, indent=2)
90
+
91
+ prompt = f"""
92
+ Analyze these work experiences and rank them by relevance to the target job:
93
+
94
+ EXPERIENCES:
95
+ {experiences_text}
96
+
97
+ TARGET JOB:
98
+ Title: {job_desc.title}
99
+ Company: {job_desc.company}
100
+ Description: {job_desc.description}
101
+ Requirements: {job_desc.requirements}
102
+
103
+ For each experience, provide:
104
+ 1. Relevance score (1-10)
105
+ 2. Key matching points
106
+ 3. Suggested improvements for better alignment
107
+ 4. Recommended order for resume
108
+
109
+ Return as JSON format:
110
+ {{
111
+ "ranked_experiences": [
112
+ {{
113
+ "original_experience": {{...}},
114
+ "relevance_score": 8,
115
+ "matching_points": ["point1", "point2"],
116
+ "suggested_improvements": ["improvement1", "improvement2"],
117
+ "recommended_position": 1
118
+ }}
119
+ ]
120
+ }}
121
+ """
122
+
123
+ response = self.generate_response(prompt)
124
+ try:
125
+ return json.loads(response)
126
+ except json.JSONDecodeError:
127
+ return {"error": "Failed to parse experience matching results"}
128
+
129
+ class KeywordOptimizationAgent(Agent):
130
+ """Agent for optimizing ATS keywords"""
131
+
132
+ def execute(self, resume_data: ResumeData, job_desc: JobDescription) -> Dict:
133
+ prompt = f"""
134
+ Analyze the resume and job description to optimize ATS keywords:
135
+
136
+ RESUME CONTENT:
137
+ Summary: {resume_data.summary}
138
+ Skills: {resume_data.skills}
139
+ Experiences: {json.dumps(resume_data.experiences)}
140
+
141
+ JOB DESCRIPTION:
142
+ {job_desc.description}
143
+ Requirements: {job_desc.requirements}
144
+
145
+ Provide:
146
+ 1. Missing critical keywords from job description
147
+ 2. Keyword density analysis
148
+ 3. Suggested keyword placements
149
+ 4. Industry-specific terms to include
150
+ 5. ATS optimization score (1-100)
151
+
152
+ Return as JSON:
153
+ {{
154
+ "missing_keywords": ["keyword1", "keyword2"],
155
+ "current_keyword_density": {{"keyword": "frequency"}},
156
+ "suggested_placements": [
157
+ {{
158
+ "keyword": "Python",
159
+ "sections": ["skills", "experience"],
160
+ "context": "Add to technical skills section"
161
+ }}
162
+ ],
163
+ "industry_terms": ["term1", "term2"],
164
+ "ats_score": 75,
165
+ "recommendations": ["rec1", "rec2"]
166
+ }}
167
+ """
168
+
169
+ response = self.generate_response(prompt)
170
+ try:
171
+ return json.loads(response)
172
+ except json.JSONDecodeError:
173
+ return {"error": "Failed to parse keyword optimization results"}
174
+
175
+ class DesignAgent(Agent):
176
+ """Agent for design and formatting suggestions"""
177
+
178
+ def execute(self, resume_data: ResumeData, job_desc: Optional[JobDescription] = None) -> Dict:
179
+ industry = job_desc.title.split()[0] if job_desc else "General"
180
+
181
+ prompt = f"""
182
+ Suggest design and formatting improvements for a {industry} professional's resume:
183
+
184
+ CURRENT RESUME STRUCTURE:
185
+ - Personal Info: {len(resume_data.personal_info)} fields
186
+ - Experiences: {len(resume_data.experiences)} positions
187
+ - Skills: {len(resume_data.skills)} skills listed
188
+ - Education: {len(resume_data.education)} entries
189
+
190
+ Consider:
191
+ 1. Industry standards for {industry}
192
+ 2. ATS-friendly formatting
193
+ 3. Visual hierarchy and readability
194
+ 4. Professional appearance
195
+ 5. Length optimization
196
+
197
+ Return JSON with:
198
+ {{
199
+ "recommended_template": "template_name",
200
+ "layout_suggestions": ["suggestion1", "suggestion2"],
201
+ "formatting_rules": ["rule1", "rule2"],
202
+ "color_scheme": "color_description",
203
+ "typography": "font_recommendations",
204
+ "sections_order": ["section1", "section2", "section3"],
205
+ "design_tips": ["tip1", "tip2"]
206
+ }}
207
+ """
208
+
209
+ response = self.generate_response(prompt)
210
+ try:
211
+ return json.loads(response)
212
+ except json.JSONDecodeError:
213
+ return {"error": "Failed to parse design suggestions"}
214
+
215
+ class EditingAgent(Agent):
216
+ """Agent for grammar, punctuation, and content improvement"""
217
+
218
+ def execute(self, text: str) -> Dict:
219
+ prompt = f"""
220
+ Analyze this resume text for improvements:
221
+
222
+ TEXT TO REVIEW:
223
+ {text}
224
+
225
+ Check for:
226
+ 1. Grammar and punctuation errors
227
+ 2. Clarity and conciseness
228
+ 3. Action verb usage
229
+ 4. Quantifiable achievements
230
+ 5. Professional tone
231
+ 6. Consistency in formatting
232
+
233
+ Return JSON:
234
+ {{
235
+ "grammar_errors": [
236
+ {{
237
+ "original": "original text",
238
+ "corrected": "corrected text",
239
+ "explanation": "reason for change"
240
+ }}
241
+ ],
242
+ "clarity_improvements": [
243
+ {{
244
+ "original": "original text",
245
+ "improved": "improved text",
246
+ "reason": "why it's better"
247
+ }}
248
+ ],
249
+ "action_verb_suggestions": ["verb1", "verb2"],
250
+ "quantification_opportunities": ["opportunity1", "opportunity2"],
251
+ "overall_score": 85,
252
+ "summary_feedback": "Overall assessment"
253
+ }}
254
+ """
255
+
256
+ response = self.generate_response(prompt)
257
+ try:
258
+ return json.loads(response)
259
+ except json.JSONDecodeError:
260
+ return {"error": "Failed to parse editing suggestions"}
261
+
262
+ class ResumeAgent:
263
+ """Main orchestrating agent that coordinates all sub-agents"""
264
+
265
+ def __init__(self):
266
+ self.summary_agent = SummaryAgent()
267
+ self.experience_agent = ExperienceMatchingAgent()
268
+ self.keyword_agent = KeywordOptimizationAgent()
269
+ self.design_agent = DesignAgent()
270
+ self.editing_agent = EditingAgent()
271
+
272
+ def parse_resume(self, resume_text: str) -> ResumeData:
273
+ """Simple resume parsing - can be enhanced with proper NLP"""
274
+ # This is a simplified parser - in production, you'd use more sophisticated parsing
275
+ lines = resume_text.split('\n')
276
+
277
+ # Extract basic sections (this is a simplified implementation)
278
+ personal_info = {"name": "John Doe", "email": "[email protected]"} # Placeholder
279
+ summary = ""
280
+ experiences = []
281
+ skills = []
282
+ education = []
283
+
284
+ # Simple pattern matching (enhance as needed)
285
+ current_section = None
286
+ for line in lines:
287
+ line = line.strip()
288
+ if re.match(r'(summary|profile|objective)', line.lower()):
289
+ current_section = 'summary'
290
+ elif re.match(r'(experience|work|employment)', line.lower()):
291
+ current_section = 'experience'
292
+ elif re.match(r'(skills|technical)', line.lower()):
293
+ current_section = 'skills'
294
+ elif re.match(r'(education|academic)', line.lower()):
295
+ current_section = 'education'
296
+ elif line and current_section:
297
+ if current_section == 'summary':
298
+ summary += line + " "
299
+ elif current_section == 'skills':
300
+ skills.extend([skill.strip() for skill in line.split(',')])
301
+
302
+ return ResumeData(
303
+ personal_info=personal_info,
304
+ summary=summary.strip(),
305
+ experiences=experiences,
306
+ skills=skills,
307
+ education=education,
308
+ raw_text=resume_text
309
+ )
310
+
311
+ def optimize_resume(self, resume_text: str, job_description: Optional[str] = None) -> Dict:
312
+ """Main method to optimize resume using all agents"""
313
+
314
+ # Parse resume
315
+ resume_data = self.parse_resume(resume_text)
316
+
317
+ # Parse job description if provided
318
+ job_desc = None
319
+ if job_description:
320
+ job_desc = JobDescription(
321
+ title="Target Position",
322
+ company="Target Company",
323
+ description=job_description,
324
+ requirements=[req.strip() for req in job_description.split('.') if req.strip()],
325
+ keywords=[]
326
+ )
327
+
328
+ results = {
329
+ "timestamp": datetime.now().isoformat(),
330
+ "original_resume": resume_data.__dict__,
331
+ }
332
+
333
+ # Generate new summary
334
+ print("πŸ”„ Generating compelling summary...")
335
+ results["new_summary"] = self.summary_agent.execute(resume_data, job_desc)
336
+
337
+ # Match experiences to job
338
+ if job_desc:
339
+ print("πŸ”„ Analyzing experience relevance...")
340
+ results["experience_matching"] = self.experience_agent.execute(resume_data, job_desc)
341
+
342
+ print("πŸ”„ Optimizing keywords for ATS...")
343
+ results["keyword_optimization"] = self.keyword_agent.execute(resume_data, job_desc)
344
+
345
+ # Design suggestions
346
+ print("πŸ”„ Generating design recommendations...")
347
+ results["design_suggestions"] = self.design_agent.execute(resume_data, job_desc)
348
+
349
+ # Edit and improve
350
+ print("πŸ”„ Analyzing content for improvements...")
351
+ results["editing_suggestions"] = self.editing_agent.execute(resume_text)
352
+
353
+ return results
354
+
355
+ # File handling utilities
356
+ def read_file(file_path: str) -> str:
357
+ """Read content from a file"""
358
+ try:
359
+ with open(file_path, 'r', encoding='utf-8') as file:
360
+ return file.read()
361
+ except FileNotFoundError:
362
+ print(f"❌ File not found: {file_path}")
363
+ return ""
364
+ except Exception as e:
365
+ print(f"❌ Error reading file: {str(e)}")
366
+ return ""
367
+
368
+ def get_sample_resume() -> str:
369
+ """Return sample resume text"""
370
+ return """
371
+ John Doe
372
+ Software Engineer
373
374
+ (555) 123-4567
375
+
376
+ SUMMARY
377
+ Experienced software developer with 5 years in web development and system design.
378
+
379
+ EXPERIENCE
380
+ Software Developer at TechCorp (2019-2024)
381
+ - Developed web applications using Python and JavaScript
382
+ - Worked with databases and APIs
383
+ - Collaborated with team members on agile projects
384
+ - Maintained code quality and performed code reviews
385
+
386
+ Senior Developer Intern at StartupXYZ (2018-2019)
387
+ - Built responsive web interfaces using React
388
+ - Integrated third-party APIs and services
389
+ - Participated in daily standups and sprint planning
390
+
391
+ SKILLS
392
+ Python, JavaScript, React, SQL, Git, Docker, AWS, REST APIs
393
+
394
+ EDUCATION
395
+ BS Computer Science, University XYZ (2019)
396
+ GPA: 3.7/4.0
397
+ """
398
+
399
+ def get_sample_job_description() -> str:
400
+ """Return sample job description"""
401
+ return """
402
+ Senior Python Developer position at InnovaTech
403
+
404
+ We are looking for an experienced Python developer with expertise in Django,
405
+ REST APIs, database optimization, and cloud technologies. The ideal candidate
406
+ should have 3+ years of experience, strong problem-solving skills, and
407
+ experience with AWS or Azure.
408
+
409
+ Requirements:
410
+ - 3+ years of Python development experience
411
+ - Strong knowledge of Django framework
412
+ - Experience with REST API development
413
+ - Database design and optimization skills
414
+ - Cloud platform experience (AWS/Azure)
415
+ - Git version control
416
+ - Agile development methodology
417
+ - Strong communication skills
418
+ """
419
+
420
+ # Example usage and testing
421
+ def main():
422
+ """Main function with file upload capability"""
423
+
424
+ print("πŸš€ AI Resume Optimization Agent")
425
+ print("=" * 50)
426
+
427
+ # Get resume content
428
+ resume_file = input("πŸ“„ Enter resume file path (or press Enter for sample): ").strip()
429
+ if resume_file and resume_file != "":
430
+ resume_text = read_file(resume_file)
431
+ if not resume_text:
432
+ print("πŸ“„ Using sample resume instead...")
433
+ resume_text = get_sample_resume()
434
+ else:
435
+ print("πŸ“„ Using sample resume...")
436
+ resume_text = get_sample_resume()
437
+
438
+ # Get job description
439
+ job_file = input("πŸ’Ό Enter job description file path (or press Enter for sample): ").strip()
440
+ if job_file and job_file != "":
441
+ job_description = read_file(job_file)
442
+ if not job_description:
443
+ print("πŸ’Ό Using sample job description instead...")
444
+ job_description = get_sample_job_description()
445
+ else:
446
+ print("πŸ’Ό Using sample job description...")
447
+ job_description = get_sample_job_description()
448
+
449
+ # Initialize the agent
450
+ agent = ResumeAgent()
451
+
452
+ print("\nπŸ”„ Starting Resume Optimization...")
453
+ print("=" * 50)
454
+
455
+ # Optimize resume
456
+ results = agent.optimize_resume(resume_text, job_description)
457
+
458
+ print("\nβœ… Optimization Complete!")
459
+ print("=" * 50)
460
+
461
+ # Display results
462
+ print(f"\nπŸ“ NEW SUMMARY:")
463
+ print(results.get("new_summary", ""))
464
+
465
+ if "keyword_optimization" in results:
466
+ keyword_data = results["keyword_optimization"]
467
+ if isinstance(keyword_data, dict) and "ats_score" in keyword_data:
468
+ print(f"\n🎯 ATS SCORE: {keyword_data['ats_score']}/100")
469
+
470
+ if "design_suggestions" in results:
471
+ design_data = results["design_suggestions"]
472
+ if isinstance(design_data, dict) and "recommended_template" in design_data:
473
+ print(f"\n🎨 RECOMMENDED TEMPLATE: {design_data['recommended_template']}")
474
+
475
+ print(f"\nπŸ“Š ANALYSIS COMPLETE")
476
+ print(f"Full results saved with timestamp: {results['timestamp']}")
477
+
478
+ # Save results to file
479
+ output_file = f"resume_optimization_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
480
+ try:
481
+ with open(output_file, 'w', encoding='utf-8') as f:
482
+ json.dump(results, f, indent=2, default=str)
483
+ print(f"πŸ’Ύ Results saved to: {output_file}")
484
+ except Exception as e:
485
+ print(f"❌ Error saving results: {str(e)}")
486
+
487
+ return results
488
+
489
+ if __name__ == "__main__":
490
+ # Note: Replace "YOUR_GEMINI_API_KEY" with your actual API key
491
+ main()