|
|
import os |
|
|
from typing import Dict, Any |
|
|
from langchain_openai import ChatOpenAI |
|
|
from langchain.prompts import PromptTemplate |
|
|
from langchain.chains import LLMChain |
|
|
|
|
|
class LangflowChain: |
|
|
def __init__(self): |
|
|
"""Initialize the LangflowChain with OpenAI LLM""" |
|
|
self.llm = ChatOpenAI( |
|
|
model="gpt-3.5-turbo", |
|
|
temperature=0.2 |
|
|
) |
|
|
|
|
|
self.template = """ |
|
|
You are an expert resume analyzer and career advisor. Your task is to analyze the resume details provided |
|
|
and generate actionable insights. |
|
|
|
|
|
Resume Details: |
|
|
{resume_data} |
|
|
|
|
|
Based on the resume details above, please provide the following: |
|
|
|
|
|
1. Suitable Job Roles: List the top 5 job roles that match this candidate's skills and experience. |
|
|
2. Skill Gap Analysis: Identify important skills that are missing for the suggested job roles and |
|
|
recommend courses or certifications to acquire these skills. |
|
|
3. Resume Improvement Tips: Provide specific, actionable recommendations for enhancing the resume. |
|
|
|
|
|
Format your response as a JSON object with the following structure: |
|
|
{{ |
|
|
"job_matches": [ |
|
|
{{ |
|
|
"title": "Job Title 1", |
|
|
"match_score": 85, |
|
|
"key_matching_skills": ["Skill 1", "Skill 2", "Skill 3"], |
|
|
"description": "Brief description of why this role is suitable" |
|
|
}}, |
|
|
// Other job matches... |
|
|
], |
|
|
"skill_gaps": [ |
|
|
{{ |
|
|
"skill": "Missing Skill 1", |
|
|
"importance": "High", |
|
|
"acquisition_recommendation": "Specific course, certification, or project to gain this skill" |
|
|
}}, |
|
|
// Other skill gaps... |
|
|
], |
|
|
"improvement_tips": [ |
|
|
"Specific tip 1 for improving the resume", |
|
|
"Specific tip 2 for improving the resume", |
|
|
// Other tips... |
|
|
] |
|
|
}} |
|
|
|
|
|
Ensure your response is properly formatted as valid JSON. |
|
|
""" |
|
|
|
|
|
self.prompt = PromptTemplate( |
|
|
input_variables=["resume_data"], |
|
|
template=self.template |
|
|
) |
|
|
|
|
|
self.chain = LLMChain( |
|
|
llm=self.llm, |
|
|
prompt=self.prompt |
|
|
) |
|
|
|
|
|
def analyze_resume(self, resume_data: Any) -> Dict[str, Any]: |
|
|
""" |
|
|
Analyze a resume and generate insights using the LLM chain |
|
|
|
|
|
Args: |
|
|
resume_data: Structured resume data |
|
|
|
|
|
Returns: |
|
|
Dictionary containing job matches, skill gaps, and improvement tips |
|
|
""" |
|
|
|
|
|
resume_str = self._format_resume_data(resume_data) |
|
|
|
|
|
|
|
|
try: |
|
|
result = self.chain.invoke({"resume_data": resume_str}) |
|
|
|
|
|
|
|
|
response_text = result.get("text", "{}") |
|
|
|
|
|
|
|
|
|
|
|
import json |
|
|
try: |
|
|
return json.loads(response_text) |
|
|
except json.JSONDecodeError: |
|
|
|
|
|
return self._create_mock_response() |
|
|
|
|
|
except Exception as e: |
|
|
print(f"Error in LLM chain: {e}") |
|
|
return self._create_mock_response() |
|
|
|
|
|
def _format_resume_data(self, resume_data: Any) -> str: |
|
|
"""Format resume data into a string for the prompt""" |
|
|
if hasattr(resume_data, "dict"): |
|
|
|
|
|
data_dict = resume_data.dict() |
|
|
else: |
|
|
|
|
|
data_dict = resume_data |
|
|
|
|
|
formatted_str = "" |
|
|
|
|
|
|
|
|
personal_info = data_dict.get("personal_info", {}) |
|
|
formatted_str += "Personal Information:\n" |
|
|
for key, value in personal_info.items(): |
|
|
if value: |
|
|
formatted_str += f"- {key.replace('_', ' ').title()}: {value}\n" |
|
|
|
|
|
|
|
|
education = data_dict.get("education", []) |
|
|
formatted_str += "\nEducation:\n" |
|
|
for edu in education: |
|
|
if isinstance(edu, dict): |
|
|
inst = edu.get("institution", "") |
|
|
degree = edu.get("degree", "") |
|
|
formatted_str += f"- {degree} at {inst}\n" |
|
|
else: |
|
|
formatted_str += f"- {str(edu)}\n" |
|
|
|
|
|
|
|
|
work_exp = data_dict.get("work_experience", []) |
|
|
formatted_str += "\nWork Experience:\n" |
|
|
for exp in work_exp: |
|
|
if isinstance(exp, dict): |
|
|
company = exp.get("company", "") |
|
|
position = exp.get("position", "") |
|
|
formatted_str += f"- {position} at {company}\n" |
|
|
else: |
|
|
formatted_str += f"- {str(exp)}\n" |
|
|
|
|
|
|
|
|
skills = data_dict.get("skills", []) |
|
|
formatted_str += "\nSkills:\n" |
|
|
for skill in skills: |
|
|
formatted_str += f"- {skill}\n" |
|
|
|
|
|
|
|
|
certifications = data_dict.get("certifications", []) |
|
|
formatted_str += "\nCertifications:\n" |
|
|
for cert in certifications: |
|
|
formatted_str += f"- {cert}\n" |
|
|
|
|
|
return formatted_str |
|
|
|
|
|
def _create_mock_response(self) -> Dict[str, Any]: |
|
|
"""Create a mock response for testing or fallback""" |
|
|
return { |
|
|
"job_matches": [ |
|
|
{ |
|
|
"title": "Data Scientist", |
|
|
"match_score": 85, |
|
|
"key_matching_skills": ["Python", "Data Analysis", "Machine Learning"], |
|
|
"description": "Your strong analytical skills and programming experience make you well-suited for this role." |
|
|
}, |
|
|
{ |
|
|
"title": "Software Engineer", |
|
|
"match_score": 80, |
|
|
"key_matching_skills": ["Python", "JavaScript", "Git"], |
|
|
"description": "Your technical skills and project experience align well with software engineering positions." |
|
|
} |
|
|
], |
|
|
"skill_gaps": [ |
|
|
{ |
|
|
"skill": "Cloud Computing (AWS/Azure)", |
|
|
"importance": "High", |
|
|
"acquisition_recommendation": "AWS Certified Solutions Architect or Azure Fundamentals certification" |
|
|
}, |
|
|
{ |
|
|
"skill": "SQL and Database Management", |
|
|
"importance": "Medium", |
|
|
"acquisition_recommendation": "Take an online course on SQL and database design" |
|
|
} |
|
|
], |
|
|
"improvement_tips": [ |
|
|
"Quantify your achievements with specific metrics and results", |
|
|
"Add a professional summary section highlighting your key strengths", |
|
|
"Reorganize your skills section to prioritize the most relevant skills for your target roles" |
|
|
] |
|
|
} |