Abdul-Haseeb commited on
Commit
90c9164
·
verified ·
1 Parent(s): 41f13b8

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +179 -0
app.py ADDED
@@ -0,0 +1,179 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import os
3
+ import re
4
+ from groq import Groq
5
+ import json
6
+
7
+ # Set up Groq client
8
+ client = Groq(api_key="")
9
+
10
+ # Define main function
11
+ def main():
12
+ st.title("AI-powered Resume Scanner")
13
+
14
+ # File upload
15
+ uploaded_file = st.file_uploader("Upload a resume", type=["pdf", "docx"])
16
+
17
+ # Job role input
18
+ job_role = st.text_input("Enter the job role")
19
+
20
+ if uploaded_file is not None and job_role:
21
+ # Process resume and get results
22
+ resume_text = parse_resume(uploaded_file)
23
+ if resume_text:
24
+ #st.write("Extracted Resume Text:")
25
+ #st.write(resume_text)
26
+
27
+ # Get resume analysis from the Groq model
28
+ name, degree, cgpa, skills, experience_score, ats_score = analyze_resume(resume_text, job_role)
29
+
30
+ # Display the results
31
+ st.write(f"**Candidate Name:** {name}")
32
+ st.write(f"**Degree:** {degree}")
33
+ st.write(f"**Latest CGPA/Percentage:** {cgpa}")
34
+ if skills:
35
+ st.write("**Skills:**")
36
+ for skill in skills:
37
+ st.write(f"- {skill}")
38
+ st.write(f"**Experience Score out of 10:** {experience_score}")
39
+ st.write(f"**ATS Score for {job_role} out of 10:** {ats_score}")
40
+
41
+ # Function to parse PDF/Word file
42
+ def parse_resume(uploaded_file):
43
+ # If PDF
44
+ if uploaded_file.type == "application/pdf":
45
+ from PyPDF2 import PdfReader
46
+ reader = PdfReader(uploaded_file)
47
+ text = ""
48
+ for page in reader.pages:
49
+ text += page.extract_text()
50
+ return text
51
+ # If Word
52
+ elif uploaded_file.type == "application/vnd.openxmlformats-officedocument.wordprocessingml.document":
53
+ from docx import Document
54
+ doc = Document(uploaded_file)
55
+ text = "\n".join([para.text for para in doc.paragraphs])
56
+ return text
57
+ else:
58
+ st.error("Unsupported file type!")
59
+ return None
60
+
61
+ # Function to analyze resume using Groq API and LLaMA 3.1
62
+ # Function to analyze resume using Groq API and LLaMA 3.1
63
+ import json
64
+
65
+ # Function to analyze resume using Groq API and LLaMA 3.1
66
+ def analyze_resume(text, job_role):
67
+ # Construct prompt for Groq API
68
+ prompt = (
69
+ f"Extract the following details from the given resume text: \n"
70
+ f"1. Candidate's Name \n"
71
+ f"2. Latest Education CGPA or Percentage \n"
72
+ f"3. List of Skills \n"
73
+ f"4. Rate experience (projects, internships) on a scale from 0 to 10 \n"
74
+ f"5. Provide an ATS score for the job role: {job_role}\n"
75
+ f"Resume Text: {text}\n"
76
+ f"Format your response in a JSON object with the following structure: \n"
77
+ f"{{\n"
78
+ f' "name": "Candidate Name",\n'
79
+ f' "Degree": "Latest Education qualification or grade:",\n'
80
+ f' "cgpa": "Latest Education CGPA or Percentage",\n'
81
+ f' "skills": ["List of skills"],\n'
82
+ f' "experience_score": "Experience Score (0 to 10)",\n'
83
+ f' "ats_score": "ATS Score for the job role"\n'
84
+ f"}}"
85
+ )
86
+
87
+ # Call Groq API for chat completion
88
+ chat_completion = client.chat.completions.create(
89
+ messages=[{"role": "user", "content": prompt}],
90
+ model="llama3-8b-8192",
91
+ temperature=0.7,
92
+ max_tokens=1024,
93
+ top_p=1,
94
+ stream=False
95
+ )
96
+
97
+ # Get the raw output from the LLM
98
+ output = chat_completion.choices[0].message.content
99
+ # Clean up the output to avoid any parsing issues
100
+ cleaned_output = re.search(r'{[^}]*}', output).group()
101
+ # Try parsing the cleaned JSON
102
+ try:
103
+ response_data = json.loads(cleaned_output)
104
+ except json.JSONDecodeError:
105
+ st.error("Failed to parse response from model.")
106
+ st.write("Model Output:")
107
+ st.write(cleaned_output)
108
+ return None, None, None, None, None
109
+
110
+ # Extract information from the parsed JSON
111
+ name = response_data.get("name", "Name not found")
112
+ degree = response_data.get("Degree", "Degree not found")
113
+ cgpa = response_data.get("cgpa", "CGPA/Percentage not found")
114
+ skills = response_data.get("skills", "Skills not found")
115
+ experience_score = response_data.get("experience_score", "Experience score not found")
116
+ ats_score = response_data.get("ats_score", "ATS score not found")
117
+
118
+ return name, degree, cgpa, skills, experience_score, ats_score
119
+
120
+
121
+
122
+ # Function to extract the candidate's name
123
+ def extract_name(text):
124
+ name_pattern = re.compile(r"(Name:?\s*)([A-Z][a-z]+(?:\s[A-Z][a-z]+)*)")
125
+ match = name_pattern.search(text)
126
+ if match:
127
+ return match.group(2)
128
+ return "Name not found"
129
+
130
+ # Function to extract CGPA or Percentage
131
+ def extract_cgpa(text):
132
+ cgpa_pattern = re.compile(r"(\bCGPA\b|\bGPA\b|\bPercentage\b):?\s*(\d+\.?\d*)")
133
+ match = cgpa_pattern.search(text)
134
+ if match:
135
+ return match.group(2)
136
+ return "CGPA/Percentage not found"
137
+
138
+ # Function to extract skills
139
+ def extract_skills(text):
140
+ skills_pattern = re.compile(r"Skills:?\s*(.*?)(?:Experience|Education|$)", re.DOTALL)
141
+ match = skills_pattern.search(text)
142
+ if match:
143
+ skills = match.group(1)
144
+ return [skill.strip() for skill in skills.split(",")]
145
+ return "Skills not found"
146
+
147
+ # Function to extract experience score
148
+ def extract_experience_score(text):
149
+ experience_pattern = re.compile(r"Experience Score:?\s*(\d{1,2})")
150
+ match = experience_pattern.search(text)
151
+ if match:
152
+ return int(match.group(1))
153
+ # Heuristic: If no explicit experience score is given, infer it based on keywords
154
+ experience_keywords = ["internship", "project", "work experience", "employment"]
155
+ experience_count = sum(text.lower().count(keyword) for keyword in experience_keywords)
156
+ return min(10, experience_count) # Cap at 10
157
+
158
+ # Function to extract ATS score
159
+ def extract_ats_score(text):
160
+ ats_pattern = re.compile(r"ATS Score:?\s*(\d+\.?\d*)")
161
+ match = ats_pattern.search(text)
162
+ if match:
163
+ return float(match.group(1))
164
+ # Heuristic to generate a score based on skill-job match
165
+ return generate_ats_score(text)
166
+
167
+ # Heuristic function to generate ATS score
168
+ def generate_ats_score(text):
169
+ # Just a dummy heuristic for now
170
+ skills = extract_skills(text)
171
+ if not skills:
172
+ return 0
173
+
174
+ required_skills = ["Python", "Machine Learning", "Data Analysis"] # Add job role specific required skills
175
+ match_count = sum(1 for skill in required_skills if skill.lower() in [s.lower() for s in skills])
176
+ return round((match_count / len(required_skills)) * 10, 2)
177
+
178
+ if __name__ == "__main__":
179
+ main()