Upload 7 files
Browse files- app.py +51 -0
- cert_suggester.py +15 -0
- job_api.py +28 -0
- requirements.txt +6 -0
- roadmap.py +15 -0
- utils.py +39 -0
- visa_suggester.py +7 -0
app.py
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import streamlit as st
|
| 2 |
+
from utils import parse_resume, get_recommendations, load_models
|
| 3 |
+
from job_api import get_jobs
|
| 4 |
+
from visa_suggester import suggest_visas
|
| 5 |
+
from roadmap import generate_roadmap
|
| 6 |
+
from cert_suggester import suggest_certifications, suggest_degrees
|
| 7 |
+
import base64
|
| 8 |
+
|
| 9 |
+
st.set_page_config(page_title="Universal Smart CV Analyzer", layout="wide")
|
| 10 |
+
|
| 11 |
+
st.title("🌍 Universal Smart CV Analyzer & Career Roadmap Generator")
|
| 12 |
+
|
| 13 |
+
st.markdown("Upload your CV to get skill scores, job suggestions, visa paths, certifications, and a personalized roadmap.")
|
| 14 |
+
|
| 15 |
+
uploaded_file = st.file_uploader("Upload your CV (PDF or DOCX)", type=["pdf", "docx"])
|
| 16 |
+
|
| 17 |
+
if uploaded_file:
|
| 18 |
+
with st.spinner("Analyzing your CV..."):
|
| 19 |
+
resume_text = parse_resume(uploaded_file)
|
| 20 |
+
nlp_model, llm_model = load_models()
|
| 21 |
+
|
| 22 |
+
skill_score, domain, extracted_skills, education = get_recommendations(resume_text, nlp_model, llm_model)
|
| 23 |
+
|
| 24 |
+
st.subheader("🧠 CV Analysis Results")
|
| 25 |
+
st.write(f"**Detected Domain:** {domain}")
|
| 26 |
+
st.write(f"**Skill Score:** {skill_score} / 100")
|
| 27 |
+
st.write("**Extracted Skills:**", ", ".join(extracted_skills))
|
| 28 |
+
st.write("**Education/Qualification Detected:**", education)
|
| 29 |
+
|
| 30 |
+
st.subheader("📈 Career Roadmap")
|
| 31 |
+
roadmap_html = generate_roadmap(domain, extracted_skills, llm_model)
|
| 32 |
+
st.components.v1.html(roadmap_html, height=400, scrolling=True)
|
| 33 |
+
|
| 34 |
+
st.subheader("🎓 Certification & Higher Education Suggestions")
|
| 35 |
+
certs = suggest_certifications(domain, extracted_skills)
|
| 36 |
+
degrees = suggest_degrees(domain, education)
|
| 37 |
+
st.write("**Recommended Certifications:**")
|
| 38 |
+
st.write(certs)
|
| 39 |
+
st.write("**Recommended Higher Education Options:**")
|
| 40 |
+
st.write(degrees)
|
| 41 |
+
|
| 42 |
+
st.subheader("🛫 Visa & Country Guidance")
|
| 43 |
+
visa_info = suggest_visas(domain, extracted_skills)
|
| 44 |
+
st.write(visa_info)
|
| 45 |
+
|
| 46 |
+
st.subheader("💼 Job Listings (Powered by Adzuna)")
|
| 47 |
+
job_listings = get_jobs(domain)
|
| 48 |
+
for job in job_listings:
|
| 49 |
+
st.markdown(f"**{job['title']}** - {job['location']}")
|
| 50 |
+
st.markdown(f"[Apply Here]({job['url']})")
|
| 51 |
+
st.markdown("---")
|
cert_suggester.py
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
def suggest_certifications(domain, skills):
|
| 2 |
+
if domain.lower() == "engineering":
|
| 3 |
+
return "Recommended: PMP, Six Sigma, AutoCAD, MATLAB, Certified Manufacturing Engineer"
|
| 4 |
+
elif domain.lower() == "software":
|
| 5 |
+
return "Recommended: AWS Certified Developer, Google Cloud, Azure, Data Science Professional Certificate"
|
| 6 |
+
else:
|
| 7 |
+
return "Recommended: Coursera/edX certificates related to your field"
|
| 8 |
+
|
| 9 |
+
def suggest_degrees(domain, education):
|
| 10 |
+
if "Bachelor" in education or "BSc" in education:
|
| 11 |
+
return f"Consider: Master's in {domain}, MBA in Tech Management"
|
| 12 |
+
elif "Master" in education or "MSc" in education:
|
| 13 |
+
return f"Consider: PhD in {domain}, Specialized Certifications"
|
| 14 |
+
else:
|
| 15 |
+
return "Consider: Bachelors or Associate Degree in field of interest"
|
job_api.py
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import requests
|
| 2 |
+
|
| 3 |
+
ADZUNA_APP_ID = "your_adzuna_app_id"
|
| 4 |
+
ADZUNA_APP_KEY = "your_adzuna_app_key"
|
| 5 |
+
|
| 6 |
+
def get_jobs(keyword="engineer", location="USA", max_results=5):
|
| 7 |
+
url = f"https://api.adzuna.com/v1/api/jobs/us/search/1"
|
| 8 |
+
params = {
|
| 9 |
+
"app_id": ADZUNA_APP_ID,
|
| 10 |
+
"app_key": ADZUNA_APP_KEY,
|
| 11 |
+
"what": keyword,
|
| 12 |
+
"where": location,
|
| 13 |
+
"results_per_page": max_results,
|
| 14 |
+
"content-type": "application/json",
|
| 15 |
+
}
|
| 16 |
+
response = requests.get(url, params=params)
|
| 17 |
+
if response.status_code == 200:
|
| 18 |
+
data = response.json()
|
| 19 |
+
jobs = []
|
| 20 |
+
for job in data.get("results", []):
|
| 21 |
+
jobs.append({
|
| 22 |
+
"title": job["title"],
|
| 23 |
+
"location": job["location"]["display_name"],
|
| 24 |
+
"url": job["redirect_url"]
|
| 25 |
+
})
|
| 26 |
+
return jobs
|
| 27 |
+
else:
|
| 28 |
+
return [{"title": "Error fetching jobs", "location": "", "url": ""}]
|
requirements.txt
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
streamlit
|
| 2 |
+
transformers
|
| 3 |
+
spacy
|
| 4 |
+
PyPDF2
|
| 5 |
+
docx2txt
|
| 6 |
+
requests
|
roadmap.py
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from datetime import datetime
|
| 2 |
+
|
| 3 |
+
def generate_roadmap(domain, skills, llm_model):
|
| 4 |
+
prompt = f"""
|
| 5 |
+
You are a career advisor. Generate a 3-step 6-month career roadmap with bullet points for someone with skills {skills} in the field of {domain}.
|
| 6 |
+
Suggest skills to improve, certifications, and countries to target.
|
| 7 |
+
"""
|
| 8 |
+
result = llm_model(prompt, max_new_tokens=300)[0]['generated_text']
|
| 9 |
+
|
| 10 |
+
return f"""
|
| 11 |
+
<div style="border: 2px solid #ccc; padding: 1em; border-radius: 10px;">
|
| 12 |
+
<h4>📅 Roadmap from {datetime.today().strftime('%B %Y')}:</h4>
|
| 13 |
+
<pre style="white-space: pre-wrap;">{result}</pre>
|
| 14 |
+
</div>
|
| 15 |
+
"""
|
utils.py
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import docx2txt
|
| 2 |
+
import PyPDF2
|
| 3 |
+
import spacy
|
| 4 |
+
from transformers import pipeline
|
| 5 |
+
import re
|
| 6 |
+
|
| 7 |
+
def parse_resume(file):
|
| 8 |
+
if file.type == "application/pdf":
|
| 9 |
+
pdf_reader = PyPDF2.PdfReader(file)
|
| 10 |
+
text = ""
|
| 11 |
+
for page in pdf_reader.pages:
|
| 12 |
+
text += page.extract_text()
|
| 13 |
+
return text
|
| 14 |
+
elif file.type == "application/vnd.openxmlformats-officedocument.wordprocessingml.document":
|
| 15 |
+
return docx2txt.process(file)
|
| 16 |
+
else:
|
| 17 |
+
return ""
|
| 18 |
+
|
| 19 |
+
def load_models():
|
| 20 |
+
nlp_model = spacy.load("en_core_web_sm")
|
| 21 |
+
llm_model = pipeline("text-generation", model="mistralai/Mistral-7B-Instruct-v0.1")
|
| 22 |
+
return nlp_model, llm_model
|
| 23 |
+
|
| 24 |
+
def get_recommendations(text, nlp_model, llm_model):
|
| 25 |
+
doc = nlp_model(text)
|
| 26 |
+
skills = [ent.text.lower() for ent in doc.ents if ent.label_ in ["SKILL", "WORK_OF_ART", "ORG"]]
|
| 27 |
+
education = extract_education(text)
|
| 28 |
+
|
| 29 |
+
prompt = f"Given these skills: {', '.join(set(skills))}, classify the most likely job field and rate CV quality (0-100):"
|
| 30 |
+
response = llm_model(prompt, max_new_tokens=100)[0]['generated_text']
|
| 31 |
+
|
| 32 |
+
domain = "Engineering" if "engineer" in response.lower() else "General"
|
| 33 |
+
score = int("".join(filter(str.isdigit, response)))
|
| 34 |
+
|
| 35 |
+
return score, domain, list(set(skills)), education
|
| 36 |
+
|
| 37 |
+
def extract_education(text):
|
| 38 |
+
match = re.findall(r"(Bachelor|Master|PhD|MBA|BSc|MSc|B\.Tech|M\.Tech)[^\n\r]*", text, re.IGNORECASE)
|
| 39 |
+
return ", ".join(set(match)) if match else "Not detected"
|
visa_suggester.py
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
def suggest_visas(domain, skills):
|
| 2 |
+
if domain.lower() in ["engineering", "it", "software"]:
|
| 3 |
+
return "Suggested Visas: H1-B (USA), Blue Card (EU), Global Talent Visa (UK, Australia)"
|
| 4 |
+
elif domain.lower() in ["healthcare", "nursing"]:
|
| 5 |
+
return "Suggested Visas: TN Visa (Canada/USA), Skilled Worker Visa (UK)"
|
| 6 |
+
else:
|
| 7 |
+
return "Suggested Visas: General Skilled Migration (AU), Work Permit (EU), O-1 (USA)"
|