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