Mangesh223 commited on
Commit
81f139f
·
verified ·
1 Parent(s): 1e625b3

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +26 -182
app.py CHANGED
@@ -1,109 +1,53 @@
1
- import os
2
- import gradio as gr
3
- import PyPDF2
4
- import docx
5
- import requests
6
- import json
7
- import re # Added for regex pattern replacement
8
-
9
- # Function to extract text from PDF
10
- def extract_text_from_pdf(file):
11
- pdf_reader = PyPDF2.PdfReader(file)
12
- text = ""
13
- for page in pdf_reader.pages:
14
- text += page.extract_text()
15
- return text
16
-
17
- # Function to extract text from Word document
18
- def extract_text_from_docx(file):
19
- doc = docx.Document(file)
20
- text = "\n".join([para.text for para in doc.paragraphs])
21
- return text
22
-
23
- # Function to process uploaded file
24
- def process_uploaded_file(file):
25
- filename = file.name.lower() # Case-insensitive check
26
- if filename.endswith(".pdf"):
27
- return extract_text_from_pdf(file)
28
- elif filename.endswith(".docx"):
29
- return extract_text_from_docx(file)
30
- else:
31
- raise ValueError("Unsupported file format. Please upload a PDF or Word document.")
32
-
33
- # Function to clean JSON string with escaped backslashes
34
- def clean_json_string(json_str):
35
- # Replace escaped backslashes with a temporary marker
36
- temp_str = json_str.replace('\\_', '__UNDERSCORE__')
37
-
38
- # Attempt to fix any other common escape sequence issues
39
- temp_str = temp_str.replace('\\n', '\n')
40
- temp_str = temp_str.replace('\\t', '\t')
41
- temp_str = temp_str.replace('\\r', '\r')
42
-
43
- # Remove any remaining unmatched backslashes
44
- temp_str = temp_str.replace('\\', '')
45
-
46
- # Restore underscores
47
- cleaned_str = temp_str.replace('__UNDERSCORE__', '_')
48
-
49
- return cleaned_str
50
-
51
- # Function to call Together API
52
- def analyze_with_mistral(resume_text, job_description):
53
- TOGETHER_API_KEY = os.getenv("HUGGINGFACE_API_KEY")
54
- url = "https://api.together.xyz/v1/chat/completions"
55
-
56
- messages = [
57
  {
58
  "role": "system",
59
- "content": "You are an AI expert in Applicant Tracking System (ATS) resume analysis. Your task is to evaluate resumes for ATS compatibility based on provided job descriptions and return results in a specific JSON format."
60
  },
61
  {
62
  "role": "user",
63
  "content": """
64
- Analyze the provided resume against the job description for ATS compatibility. Assess how well the resume aligns with ATS requirements and the job description in terms of keywords, formatting, skills, experience relevance, and education. Provide concise, actionable recommendations for improvement.
65
 
66
- Return the output in EXACTLY this JSON format, with no deviations, ensuring the full structure is complete:
67
  {
68
  "ATS Parameters": {
69
  "Keywords": {
70
- "Match": <integer score between 0 and 100>,
71
- "Recommendation": [<list of 2-5 specific keywords to add or emphasize>]
72
  },
73
  "Formatting": {
74
- "Match": <integer score between 0 and 100>,
75
- "Recommendation": [<list of 2-5 specific formatting suggestions>]
76
  },
77
  "Skills Match": {
78
- "Match": <integer score between 0 and 100>,
79
- "Recommendation": [<list of 2-5 specific skills to include or highlight>]
80
  },
81
  "Experience Relevance": {
82
- "Match": <integer score between 0 and 100>,
83
- "Recommendation": [<list of 2-5 suggestions to improve experience alignment>]
84
  },
85
  "Education": {
86
- "Match": <integer score between 0 and 100>,
87
- "Recommendation": [<list of 2-5 suggestions to improve education section>]
88
  }
89
  },
90
  "Score": {
91
- "Keywords": <integer score between 0 and 100>,
92
- "Formatting": <integer score between 0 and 100>,
93
- "Skills Match": <integer score between 0 and 100>,
94
- "Experience Relevance": <integer score between 0 and 100>,
95
- "Education": <integer score between 0 and 100>,
96
- "Overall": <integer average score between 0 and 100>
97
  }
98
  }
99
 
100
  Rules:
101
- - All "Match" values must be integers between 0 and 100.
102
- - All "Recommendation" fields must be lists of strings (2-5 items max), or empty lists ([]) if no suggestions apply.
103
- - "Overall" score is the average of the five "Score" values, rounded to the nearest integer.
104
- - Base analysis on typical ATS requirements (e.g., keyword density, simple formatting, clear sections) and the job description.
105
- - Ensure the ENTIRE JSON structure is returned, even if recommendations are minimal.
106
- - Keep recommendations concise to fit within response limits.
107
 
108
  Resume:
109
  {resume_text}
@@ -112,104 +56,4 @@ def analyze_with_mistral(resume_text, job_description):
112
  {job_description}
113
  """
114
  }
115
- ]
116
-
117
- payload = {
118
- "model": "mistralai/Mistral-7B-Instruct-v0.3",
119
- "messages": messages,
120
- "max_tokens": 1500,
121
- "temperature": 0.7,
122
- "top_p": 0.9,
123
- "response_format": {"type": "json_object"}
124
- }
125
-
126
- headers = {
127
- "Authorization": f"Bearer {TOGETHER_API_KEY}",
128
- "Content-Type": "application/json",
129
- }
130
-
131
- try:
132
- response = requests.post(url, json=payload, headers=headers, timeout=30)
133
- response.raise_for_status()
134
- result = response.json()
135
- content = result.get("choices", [{}])[0].get("message", {}).get("content", "{}")
136
-
137
- # Clean the JSON string before parsing
138
- cleaned_content = clean_json_string(content)
139
-
140
- try:
141
- parsed = json.loads(cleaned_content)
142
- # Check if the JSON structure is valid for our use case
143
- if "ATS_Compatibility" not in parsed or "Overall_Assessment" not in parsed:
144
- return {
145
- "error": "API returned unexpected JSON structure",
146
- "raw_content": cleaned_content[:500] + "..." if len(cleaned_content) > 500 else cleaned_content
147
- }
148
- return parsed
149
- except json.JSONDecodeError as e:
150
- # Try a more aggressive approach to fix the JSON
151
- try:
152
- # Sometimes the model might include trailing characters
153
- # Try to find the closing bracket of the main JSON object
154
- match = re.search(r'(\{.*\})', cleaned_content, re.DOTALL)
155
- if match:
156
- extracted_json = match.group(1)
157
- parsed = json.loads(extracted_json)
158
- if "ATS_Compatibility" in parsed and "Overall_Assessment" in parsed:
159
- return parsed
160
- except:
161
- pass
162
-
163
- # If all attempts fail, return the error
164
- return {
165
- "error": f"Failed to parse API response: {str(e)}",
166
- "raw_content": cleaned_content[:500] + "..." if len(cleaned_content) > 500 else cleaned_content
167
- }
168
-
169
- except requests.exceptions.RequestException as e:
170
- return {"error": f"API request failed: {str(e)}"}
171
- except Exception as e:
172
- return {"error": f"Unexpected error: {str(e)}"}
173
-
174
- # Main function
175
- def analyze_resume(file, job_description):
176
- try:
177
- if not file:
178
- return json.dumps({"error": "Please upload a resume file"}, indent=2)
179
- if not job_description:
180
- return json.dumps({"error": "Please enter a job description"}, indent=2)
181
-
182
- resume_text = process_uploaded_file(file)
183
- result = analyze_with_mistral(resume_text, job_description)
184
-
185
- # Return as formatted JSON string for better display
186
- return json.dumps(result, indent=2, ensure_ascii=False)
187
-
188
- except Exception as e:
189
- return json.dumps({"error": f"Error analyzing resume: {str(e)}"}, indent=2)
190
-
191
- # Gradio interface
192
- with gr.Blocks(fill_height=True, title="Smart ATS Resume Analyzer") as demo:
193
- with gr.Sidebar():
194
- gr.Markdown("# Smart ATS Resume Analyzer")
195
- gr.Markdown("Upload your resume (PDF/Word) and enter a job description to get an ATS compatibility score.")
196
-
197
- with gr.Row():
198
- with gr.Column(scale=1):
199
- resume_upload = gr.File(
200
- label="Upload Resume (PDF or Word)",
201
- file_types=[".pdf", ".docx"],
202
- type="filepath"
203
- )
204
- job_desc = gr.Textbox(label="Job Description", lines=10, placeholder="Paste the job description here...")
205
- submit_btn = gr.Button("Analyze Resume")
206
- with gr.Column(scale=2):
207
- output = gr.JSON(label="ATS Analysis Result")
208
-
209
- submit_btn.click(
210
- fn=analyze_resume,
211
- inputs=[resume_upload, job_desc],
212
- outputs=output
213
- )
214
-
215
- demo.launch()
 
1
+ messages = [
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  {
3
  "role": "system",
4
+ "content": "You are an AI expert in ATS resume analysis. Your task is to analyze a resume against a job description for ATS compatibility and return the result in a specific JSON format."
5
  },
6
  {
7
  "role": "user",
8
  "content": """
9
+ Analyze the provided resume against the job description for ATS compatibility. Assess keywords, formatting, skills, experience relevance, and education. Return the result by filling in the EXACT JSON template below with appropriate values and recommendations. Output ONLY the completed JSON, with no additional text, comments, or explanations. Ensure all fields are populated, even if with empty lists or default scores.
10
 
11
+ JSON Template to Fill:
12
  {
13
  "ATS Parameters": {
14
  "Keywords": {
15
+ "Match": <integer 0-100>,
16
+ "Recommendation": [<list of 0-5 strings>]
17
  },
18
  "Formatting": {
19
+ "Match": <integer 0-100>,
20
+ "Recommendation": [<list of 0-5 strings>]
21
  },
22
  "Skills Match": {
23
+ "Match": <integer 0-100>,
24
+ "Recommendation": [<list of 0-5 strings>]
25
  },
26
  "Experience Relevance": {
27
+ "Match": <integer 0-100>,
28
+ "Recommendation": [<list of 0-5 strings>]
29
  },
30
  "Education": {
31
+ "Match": <integer 0-100>,
32
+ "Recommendation": [<list of 0-5 strings>]
33
  }
34
  },
35
  "Score": {
36
+ "Keywords": <integer 0-100>,
37
+ "Formatting": <integer 0-100>,
38
+ "Skills Match": <integer 0-100>,
39
+ "Experience Relevance": <integer 0-100>,
40
+ "Education": <integer 0-100>,
41
+ "Overall": <integer 0-100, average of above scores>
42
  }
43
  }
44
 
45
  Rules:
46
+ - Replace <integer 0-100> with an integer score between 0 and 100.
47
+ - Replace <list of 0-5 strings> with a list of 0 to 5 concise string recommendations (e.g., [] if none).
48
+ - "Overall" is the rounded average of the five "Score" values.
49
+ - Base analysis on ATS requirements (keyword density, simple formatting, etc.) and the job description.
50
+ - Output ONLY the filled JSON template, nothing else.
 
51
 
52
  Resume:
53
  {resume_text}
 
56
  {job_description}
57
  """
58
  }
59
+ ]