sid570 commited on
Commit
e1dd2de
·
verified ·
1 Parent(s): 36e9642

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +148 -0
app.py ADDED
@@ -0,0 +1,148 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import re
3
+ import requests
4
+ import gradio as gr
5
+ from pypdf import PdfReader
6
+ from docx import Document
7
+
8
+ JSEARCH_API_KEY = os.getenv("JSEARCH_API_KEY")
9
+
10
+ SKILLS = [
11
+ "python", "java", "javascript", "html", "css", "sql", "linux",
12
+ "networking", "troubleshooting", "technical support", "it support",
13
+ "database", "cloud", "aws", "azure", "sap", "system administration",
14
+ "git", "api", "machine learning", "nlp"
15
+ ]
16
+
17
+ def extract_text(file):
18
+ if file is None:
19
+ return ""
20
+
21
+ path = file.name
22
+
23
+ if path.endswith(".pdf"):
24
+ reader = PdfReader(path)
25
+ return "\n".join(page.extract_text() or "" for page in reader.pages)
26
+
27
+ if path.endswith(".docx"):
28
+ doc = Document(path)
29
+ return "\n".join(p.text for p in doc.paragraphs)
30
+
31
+ if path.endswith(".txt"):
32
+ with open(path, "r", encoding="utf-8", errors="ignore") as f:
33
+ return f.read()
34
+
35
+ return ""
36
+
37
+ def extract_skills(cv_text):
38
+ text = cv_text.lower()
39
+ found = []
40
+
41
+ for skill in SKILLS:
42
+ if skill in text:
43
+ found.append(skill.title())
44
+
45
+ return found
46
+
47
+ def search_jobs(skills, location):
48
+ if not JSEARCH_API_KEY:
49
+ return []
50
+
51
+ query = " ".join(skills[:5]) + f" jobs in {location}"
52
+
53
+ headers = {
54
+ "X-API-Key": JSEARCH_API_KEY
55
+ }
56
+
57
+ response = requests.get(
58
+ "https://api.openwebninja.com/jsearch/search-v2",
59
+ params={"query": query},
60
+ headers=headers
61
+ )
62
+
63
+ if response.status_code != 200:
64
+ return []
65
+
66
+ data = response.json()
67
+
68
+ return data.get("jobs", data.get("data", []))
69
+
70
+ def calculate_match(cv_skills, job):
71
+ job_text = (
72
+ str(job.get("title", "")) + " " +
73
+ str(job.get("description", "")) + " " +
74
+ str(job.get("snippet", ""))
75
+ ).lower()
76
+
77
+ matched = []
78
+
79
+ for skill in cv_skills:
80
+ if skill.lower() in job_text:
81
+ matched.append(skill)
82
+
83
+ score = int((len(matched) / max(len(cv_skills), 1)) * 100)
84
+
85
+ return score, matched
86
+
87
+ def analyze_cv(file, location):
88
+ cv_text = extract_text(file)
89
+
90
+ if not cv_text.strip():
91
+ return "Could not extract text from the CV."
92
+
93
+ skills = extract_skills(cv_text)
94
+
95
+ if not skills:
96
+ return "No clear skills detected. Try uploading a more detailed CV."
97
+
98
+ jobs = search_jobs(skills, location)
99
+
100
+ if not jobs:
101
+ return f"Detected skills: {', '.join(skills)}\n\nNo jobs found. Check your API key or try another location."
102
+
103
+ results = []
104
+
105
+ for job in jobs[:10]:
106
+ score, matched = calculate_match(skills, job)
107
+
108
+ title = job.get("title", "Unknown Job")
109
+ company = job.get("company_name", job.get("company", "Unknown Company"))
110
+ location_name = job.get("location", "Not specified")
111
+ url = job.get("url", job.get("apply_link", "#"))
112
+
113
+ results.append({
114
+ "score": score,
115
+ "title": title,
116
+ "company": company,
117
+ "location": location_name,
118
+ "matched": matched,
119
+ "url": url
120
+ })
121
+
122
+ results = sorted(results, key=lambda x: x["score"], reverse=True)
123
+
124
+ output = f"## Skills Detected\n{', '.join(skills)}\n\n"
125
+ output += "## Best Job Matches\n\n"
126
+
127
+ for job in results:
128
+ output += f"### {job['title']} — {job['score']}% Match\n"
129
+ output += f"**Company:** {job['company']}\n\n"
130
+ output += f"**Location:** {job['location']}\n\n"
131
+ output += f"**Matched Skills:** {', '.join(job['matched']) if job['matched'] else 'None'}\n\n"
132
+ output += f"[Apply Here]({job['url']})\n\n---\n\n"
133
+
134
+ return output
135
+
136
+ demo = gr.Interface(
137
+ fn=analyze_cv,
138
+ inputs=[
139
+ gr.File(label="Upload your CV", file_types=[".pdf", ".docx", ".txt"]),
140
+ gr.Textbox(label="Job Location", value="Mauritius")
141
+ ],
142
+ outputs=gr.Markdown(label="Job Matches"),
143
+ title="JobFit AI",
144
+ description="Upload your CV and get real job matches based on your skills."
145
+ )
146
+
147
+ if __name__ == "__main__":
148
+ demo.launch()