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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +111 -53
app.py CHANGED
@@ -1,59 +1,117 @@
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}
54
-
55
- Job Description:
56
- {job_description}
57
- """
58
  }
59
- ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import gradio as gr
3
+ import PyPDF2
4
+ import docx
5
+ import requests
6
+ import json
7
+
8
+ # Function to extract text from PDF (unchanged)
9
+ def extract_text_from_pdf(file):
10
+ pdf_reader = PyPDF2.PdfReader(file)
11
+ text = ""
12
+ for page in pdf_reader.pages:
13
+ text += page.extract_text()
14
+ return text
15
+
16
+ # Function to extract text from Word document (unchanged)
17
+ def extract_text_from_docx(file):
18
+ doc = docx.Document(file)
19
+ text = "\n".join([para.text for para in doc.paragraphs])
20
+ return text
21
+
22
+ # Function to process uploaded file (only added case-insensitive check)
23
+ def process_uploaded_file(file):
24
+ filename = file.name.lower() # Case-insensitive check
25
+ if filename.endswith(".pdf"):
26
+ return extract_text_from_pdf(file)
27
+ elif filename.endswith(".docx"):
28
+ return extract_text_from_docx(file)
29
+ else:
30
+ raise ValueError("Unsupported file format. Please upload a PDF or Word document.")
31
+
32
+ # Function to call Together API (unchanged except for timeout)
33
+ def analyze_with_mistral(resume_text, job_description):
34
+ TOGETHER_API_KEY = os.getenv("HUGGINGFACE_API_KEY")
35
+ url = "https://api.together.xyz/v1/chat/completions"
36
+
37
+ [
38
  {
39
  "role": "system",
40
+ "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 structured JSON format. You must strictly follow the JSON schema provided and output ONLY JSON."
41
  },
42
  {
43
  "role": "user",
44
+ "content": f"""Analyze the provided resume against the job description for ATS compatibility. Evaluate **keywords, formatting, skills, experience relevance, and education** based on ATS best practices.\n\nStrict Instructions:\n- **Return ONLY valid JSON** that matches the exact schema below. NO explanations, comments, or extra text.\n- **Ensure all fields are populated** (use empty lists or defaults if no suggestions apply).\n- **Use integer values (0-100)** for scores.\n- **Ensure 'Overall' is the rounded average** of all score fields.\n\n### **JSON Schema:**\n```json\n{\n \"ATS Parameters\": {\n \"Keywords\": {\n \"Match\": <integer 0-100>,\n \"Recommendation\": [<list of 0-5 strings>]\n },\n \"Formatting\": {\n \"Match\": <integer 0-100>,\n \"Recommendation\": [<list of 0-5 strings>]\n },\n \"Skills Match\": {\n \"Match\": <integer 0-100>,\n \"Recommendation\": [<list of 0-5 strings>]\n },\n \"Experience Relevance\": {\n \"Match\": <integer 0-100>,\n \"Recommendation\": [<list of 0-5 strings>]\n },\n \"Education\": {\n \"Match\": <integer 0-100>,\n \"Recommendation\": [<list of 0-5 strings>]\n }\n },\n \"Score\": {\n \"Keywords\": <integer 0-100>,\n \"Formatting\": <integer 0-100>,\n \"Skills Match\": <integer 0-100>,\n \"Experience Relevance\": <integer 0-100>,\n \"Education\": <integer 0-100>,\n \"Overall\": <integer 0-100, rounded average of all scores>\n }\n}\n```\n\n### **Processing Rules:**\n- **Score Calculation:** Base your evaluation on **ATS resume best practices** (keyword density, formatting simplicity, skills relevance, etc.).\n- **Recommendations:** Provide actionable suggestions to improve compatibility.\n- **Strict JSON Format:** No preamble, no explanations—return ONLY the completed JSON.\n\nResume:\n{resume_text}\n\nJob Description:\n{job_description}"""
45
+ }
46
+ ]
47
+
48
+
49
+
50
+ payload = {
51
+ "model": "mistralai/Mistral-7B-Instruct-v0.3",
52
+ "messages": messages,
53
+ "max_tokens": 1500,
54
+ "temperature": 0.7,
55
+ "top_p": 0.9,
56
+ "response_format": {"type": "json_object"}
57
+ }
58
+
59
+ headers = {
60
+ "Authorization": f"Bearer {TOGETHER_API_KEY}",
61
+ "Content-Type": "application/json",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
  }
63
+
64
+ try:
65
+ response = requests.post(url, json=payload, headers=headers, timeout=30)
66
+ response.raise_for_status()
67
+ result = response.json()
68
+ content = result.get("choices", [{}])[0].get("message", {}).get("content", "{}")
69
+
70
+ # Parse and validate the JSON structure
71
+ parsed = json.loads(content)
72
+ if "ATS Parameters" not in parsed or "Score" not in parsed:
73
+ raise ValueError("API returned invalid format")
74
+ return parsed
75
+
76
+ except Exception as e:
77
+ return {"error": f"API request failed: {str(e)}"}
78
+
79
+ # Main function (only added JSON validation)
80
+ def analyze_resume(file, job_description):
81
+ try:
82
+ resume_text = process_uploaded_file(file)
83
+ result = analyze_with_mistral(resume_text, job_description)
84
+
85
+ # Ensure the output matches your original format
86
+ if isinstance(result, dict) and "error" in result:
87
+ return json.dumps(result, indent=2)
88
+ return result
89
+
90
+ except Exception as e:
91
+ return json.dumps({"error": str(e)}, indent=2)
92
+
93
+ # Gradio interface (only changed file component type)
94
+ with gr.Blocks(fill_height=True, title="Smart ATS Resume Analyzer") as demo:
95
+ with gr.Sidebar():
96
+ gr.Markdown("# Smart ATS Resume Analyzer")
97
+ gr.Markdown("Upload your resume (PDF/Word) and enter a job description to get an ATS compatibility score.")
98
+
99
+ with gr.Row():
100
+ with gr.Column(scale=1):
101
+ resume_upload = gr.File(
102
+ label="Upload Resume (PDF or Word)",
103
+ file_types=[".pdf", ".docx"],
104
+ type="filepath" # Only this line changed
105
+ )
106
+ job_desc = gr.Textbox(label="Job Description", lines=10, placeholder="Paste the job description here...")
107
+ submit_btn = gr.Button("Analyze Resume")
108
+ with gr.Column(scale=2):
109
+ output = gr.JSON(label="ATS Analysis Result")
110
+
111
+ submit_btn.click(
112
+ fn=analyze_resume,
113
+ inputs=[resume_upload, job_desc],
114
+ outputs=output
115
+ )
116
+
117
+ demo.launch()