import streamlit as st import os import re from groq import Groq import json # Set up Groq client client = Groq(api_key="") # Define main function def main(): st.title("AI-powered Resume Scanner") # File upload uploaded_file = st.file_uploader("Upload a resume", type=["pdf", "docx"]) # Job role input job_role = st.text_input("Enter the job role") if uploaded_file is not None and job_role: # Process resume and get results resume_text = parse_resume(uploaded_file) if resume_text: #st.write("Extracted Resume Text:") #st.write(resume_text) # Get resume analysis from the Groq model name, degree, cgpa, skills, experience_score, ats_score = analyze_resume(resume_text, job_role) # Display the results st.write(f"**Candidate Name:** {name}") st.write(f"**Degree:** {degree}") st.write(f"**Latest CGPA/Percentage:** {cgpa}") if skills: st.write("**Skills:**") for skill in skills: st.write(f"- {skill}") st.write(f"**Experience Score out of 10:** {experience_score}") st.write(f"**ATS Score for {job_role} out of 10:** {ats_score}") # Function to parse PDF/Word file def parse_resume(uploaded_file): # If PDF if uploaded_file.type == "application/pdf": from PyPDF2 import PdfReader reader = PdfReader(uploaded_file) text = "" for page in reader.pages: text += page.extract_text() return text # If Word elif uploaded_file.type == "application/vnd.openxmlformats-officedocument.wordprocessingml.document": from docx import Document doc = Document(uploaded_file) text = "\n".join([para.text for para in doc.paragraphs]) return text else: st.error("Unsupported file type!") return None # Function to analyze resume using Groq API and LLaMA 3.1 # Function to analyze resume using Groq API and LLaMA 3.1 import json # Function to analyze resume using Groq API and LLaMA 3.1 def analyze_resume(text, job_role): # Construct prompt for Groq API prompt = ( f"Extract the following details from the given resume text: \n" f"1. Candidate's Name \n" f"2. Latest Education CGPA or Percentage \n" f"3. List of Skills \n" f"4. Rate experience (projects, internships) on a scale from 0 to 10 \n" f"5. Provide an ATS score for the job role: {job_role}\n" f"Resume Text: {text}\n" f"Format your response in a JSON object with the following structure: \n" f"{{\n" f' "name": "Candidate Name",\n' f' "Degree": "Latest Education qualification or grade:",\n' f' "cgpa": "Latest Education CGPA or Percentage",\n' f' "skills": ["List of skills"],\n' f' "experience_score": "Experience Score (0 to 10)",\n' f' "ats_score": "ATS Score for the job role"\n' f"}}" ) # Call Groq API for chat completion chat_completion = client.chat.completions.create( messages=[{"role": "user", "content": prompt}], model="llama3-8b-8192", temperature=0.7, max_tokens=1024, top_p=1, stream=False ) # Get the raw output from the LLM output = chat_completion.choices[0].message.content # Clean up the output to avoid any parsing issues cleaned_output = re.search(r'{[^}]*}', output).group() # Try parsing the cleaned JSON try: response_data = json.loads(cleaned_output) except json.JSONDecodeError: st.error("Failed to parse response from model.") st.write("Model Output:") st.write(cleaned_output) return None, None, None, None, None # Extract information from the parsed JSON name = response_data.get("name", "Name not found") degree = response_data.get("Degree", "Degree not found") cgpa = response_data.get("cgpa", "CGPA/Percentage not found") skills = response_data.get("skills", "Skills not found") experience_score = response_data.get("experience_score", "Experience score not found") ats_score = response_data.get("ats_score", "ATS score not found") return name, degree, cgpa, skills, experience_score, ats_score # Function to extract the candidate's name def extract_name(text): name_pattern = re.compile(r"(Name:?\s*)([A-Z][a-z]+(?:\s[A-Z][a-z]+)*)") match = name_pattern.search(text) if match: return match.group(2) return "Name not found" # Function to extract CGPA or Percentage def extract_cgpa(text): cgpa_pattern = re.compile(r"(\bCGPA\b|\bGPA\b|\bPercentage\b):?\s*(\d+\.?\d*)") match = cgpa_pattern.search(text) if match: return match.group(2) return "CGPA/Percentage not found" # Function to extract skills def extract_skills(text): skills_pattern = re.compile(r"Skills:?\s*(.*?)(?:Experience|Education|$)", re.DOTALL) match = skills_pattern.search(text) if match: skills = match.group(1) return [skill.strip() for skill in skills.split(",")] return "Skills not found" # Function to extract experience score def extract_experience_score(text): experience_pattern = re.compile(r"Experience Score:?\s*(\d{1,2})") match = experience_pattern.search(text) if match: return int(match.group(1)) # Heuristic: If no explicit experience score is given, infer it based on keywords experience_keywords = ["internship", "project", "work experience", "employment"] experience_count = sum(text.lower().count(keyword) for keyword in experience_keywords) return min(10, experience_count) # Cap at 10 # Function to extract ATS score def extract_ats_score(text): ats_pattern = re.compile(r"ATS Score:?\s*(\d+\.?\d*)") match = ats_pattern.search(text) if match: return float(match.group(1)) # Heuristic to generate a score based on skill-job match return generate_ats_score(text) # Heuristic function to generate ATS score def generate_ats_score(text): # Just a dummy heuristic for now skills = extract_skills(text) if not skills: return 0 required_skills = ["Python", "Machine Learning", "Data Analysis"] # Add job role specific required skills match_count = sum(1 for skill in required_skills if skill.lower() in [s.lower() for s in skills]) return round((match_count / len(required_skills)) * 10, 2) if __name__ == "__main__": main()