Skip to content

Commit

Permalink
SkillSync - Skill Gap Analysis for Career Growth and Course Recommend…
Browse files Browse the repository at this point in the history
…ation (#432)

## Pull Request for PyVerse 💡

### Requesting to submit a pull request to the PyVerse repository.

---

#### Issue Title
**Please enter the title of the issue related to your pull request.**  
*Enter the issue title here.* - SkillSync - Skill Gap Analysis for
Career Growth and Course Recommendation

- [x] I have provided the issue title.

---

#### Info about the Related Issue
**What's the goal of the project?**  
*Describe the aim of the project.* - The primary aim of SkillSync is to
provide a comprehensive skill gap analysis tool that assists individuals
in identifying their current skill sets relative to their career goals.
By leveraging advanced analytics and machine learning techniques, the
platform will recommend personalized learning paths and courses to
bridge identified skill gaps, thereby fostering career growth and
enhancing employability.

- [x] I have described the aim of the project.

---

#### Name
**Please mention your name.**  
*Enter your name here.* - J B Mugundh

- [x] I have provided my name.

---

#### GitHub ID
**Please mention your GitHub ID.**  
*Enter your GitHub ID here.* - https://github.com/J-B-Mugundh

- [x] I have provided my GitHub ID.

---

#### Email ID
**Please mention your email ID for further communication.**  
*Enter your email ID here.* - mugundhjb@gmail.com

- [x] I have provided my email ID.

---

#### Identify Yourself
**Mention in which program you are contributing (e.g., WoB, GSSOC, SSOC,
SWOC).**
*Enter your participant role here.* - GSSOC-EXTD

- [x] I have mentioned my participant role.

---

#### Closes
**Enter the issue number that will be closed through this PR.**  
*Closes: #issue-number* - #287

- [x] I have provided the issue number.

---

#### Describe the Add-ons or Changes You've Made
**Give a clear description of what you have added or modified.**  
*Describe your changes here.* - Added "SkillSync - Skill Gap Analysis
for Career Growth and Course Recommendation" which performs the
following

- Skill Gap Analysis: The platform utilizes algorithms to compare the
user’s existing skills with industry standards and the skills required
for specific roles. This analysis highlights gaps that need to be
addressed for career progression.
- Course Recommendation: Based on the identified skill gaps, SkillSync
will recommend relevant courses, workshops, and online resources
tailored to the user’s learning preferences. The recommendations will be
sourced from accredited platforms and institutions.
- Career Insights: The platform will provide insights into industry
trends, job market demands, and emerging skills to help users make
informed decisions about their career paths.

- [x] I have described my changes.

---

#### Type of Change
**Select the type of change:**  
- [ ] Bug fix (non-breaking change which fixes an issue)
- [x] New feature (non-breaking change which adds functionality)
- [ ] Code style update (formatting, local variables)
- [ ] Breaking change (fix or feature that would cause existing
functionality to not work as expected)
- [ ] This change requires a documentation update

---

#### How Has This Been Tested?
**Describe how your changes have been tested.**  
*Describe your testing process here.* - Manual Testing in local

- [x] I have described my testing process.

---

#### Checklist
**Please confirm the following:**  
- [x] My code follows the guidelines of this project.
- [x] I have performed a self-review of my own code.
- [x] I have commented my code, particularly wherever it was hard to
understand.
- [x] I have made corresponding changes to the documentation.
- [x] My changes generate no new warnings.
- [x] I have added things that prove my fix is effective or that my
feature works.
- [x] Any dependent changes have been merged and published in downstream
modules.
  • Loading branch information
UTSAVS26 authored Oct 11, 2024
2 parents b7b97fd + 0f9f114 commit 2c31535
Show file tree
Hide file tree
Showing 5 changed files with 373 additions and 0 deletions.
2 changes: 2 additions & 0 deletions Advanced_Projects/SkillSync/.env-sample
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
GOOGLE_API_KEY=<YOUR_GEMINI_API_KEY>
PROXYCURL_API_KEY=<YOUR_PROXYCURL_API_KEY>
96 changes: 96 additions & 0 deletions Advanced_Projects/SkillSync/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# **Skill Sync**

### 🎯 **Goal**

The primary goal of **Skill Sync** is to bridge the skill gap by analyzing an individual’s current skills against the demands of their career goals. The application helps users align their skillsets with market demands, suggesting relevant courses for upskilling and enabling seamless skill import from platforms like LinkedIn.

### 🧵 **Dataset**

**Skill Sync** does not use a pre-existing dataset. Instead, it gathers user-inputted skills or imports them from LinkedIn profiles to analyze and recommend relevant courses for skill development. The system also utilizes generative models to provide skill gap analysis and career insights.

### 🧾 **Description**

**Skill Sync** allows users to define their career goals and manually add skills or import them from LinkedIn. Using AI models, the app compares the user's current skill set with their desired career and suggests the best upskilling path.

The system helps streamline skill development by providing course recommendations, career insights, and gap analysis, improving the user's chances of achieving their career objectives.

### 🧮 **What I Had Done!**

- Implemented a **manual skill addition feature** where users can input their skills.
- Integrated **LinkedIn API** to allow users to import their skills automatically.
- Developed a **career goal matching system**, leveraging **AI** for skill gap analysis.
- Suggested **relevant courses** based on skill gaps identified during analysis.

### 🚀 **Models Implemented**

- **Generative AI**: This model generates career insights and a comprehensive skill gap analysis based on the user’s inputs.
- **Gemini AI**: Used to map and identify skill deficiencies and recommend the best learning paths.

### 📚 **Libraries Needed**

- Flask
- requests
- google-generativeai
- pandas
- dotenv

### 📊 **Exploratory Data Analysis Results**

Since **Skill Sync** deals with real-time input from users, traditional data analysis is not performed. However, the app provides insights based on real-time user data like skills vs. market requirements, skill deficiencies, and suggested learning paths.

### 📈 **Performance Metrics**

The performance of the system is assessed through:
- **Accuracy of skill analysis**: How accurately the system identifies missing skills.
- **Relevance of recommended courses**: How relevant the suggested courses are to the user's career goals.
- **User satisfaction**: Feedback collected on how effective the tool is in helping users bridge their skill gaps.

### 💻 How to Run

To get started with **Skill Sync**, follow these steps:

1. Navigate to the project directory:

```bash
cd SkillSync
```

2. (Optional) Activate a virtual environment:

```bash
conda create -n venv python=3.10+
conda activate venv
```

3. Install dependencies:

```bash
pip install -r requirements.txt
```

4. Configure environment variables:

```
Rename `.env-sample` to `.env`.
Replace with your LinkedIn and Google API Keys.
```

Kindly refer to these links for getting your own API keys:
- [LinkedIn API](https://developer.linkedin.com/) or [Proxy Curl API](https://nubela.co/proxycurl/linkedin)
- [Google Generative AI Key](https://ai.google.dev/tutorials/setup)

5. Run the application:

```bash
streamlit run app.py
```

### 📢 **Conclusion**

**Skill Sync** is an effective tool for closing the skill gap by analyzing current skillsets and recommending relevant courses. It leverages AI models to provide detailed gap analysis and offers career-oriented guidance, ensuring that users stay on track to achieve their professional goals.

### ✒️ **Signature**

**[J B Mugundh]**
GitHub: [Github](https://github.com/J-B-Mugundh)
LinkedIn: [LinkedIn](https://www.linkedin.com/in/mugundhjb/)
97 changes: 97 additions & 0 deletions Advanced_Projects/SkillSync/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
from flask import Flask, request, render_template
import google.generativeai as genai
import os
import json
import requests
from dotenv import load_dotenv

# Load environment variables from .env file
load_dotenv()

app = Flask(__name__)

# Load API keys from environment variables
PROXYCURL_API_KEY = os.getenv('PROXYCURL_API_KEY')
PROXYCURL_API_ENDPOINT = 'https://nubela.co/proxycurl/api/v2/linkedin'

def get_gemini_response(career_goal, skills):
"""Fetches response from Gemini API based on career goal and skills."""

query = f"Considering my career goal of '{career_goal}', what additional skills would I need to acquire if my current skills are {', '.join(skills)}? Just list them as a list. The skills should be actual programming or technical skills. Just give them concise, don't give extra words like Version control (eg. Git). List a maximum of 5 skills only. Display each with bulletin point."

model = genai.GenerativeModel('gemini-pro')
api_key = os.getenv("GOOGLE_API_KEY") # Retrieve Google API key from .env
genai.configure(api_key=api_key)

try:
response = model.generate_content(query)
return response.text
except Exception as e:
print(f"Error occurred during Gemini API call: {e}")
return "An error occurred while fetching data from Gemini. Please try again later."

def get_linkedin_profile(linkedin_url):
"""Fetches the LinkedIn profile using Proxycurl API."""

headers = {
'Authorization': f'Bearer {PROXYCURL_API_KEY}',
}

params = {
'linkedin_profile_url': linkedin_url,
'extra': 'include',
'skills': 'include',
'use_cache': 'if-present',
'fallback_to_cache': 'on-error',
}

try:
response = requests.get(PROXYCURL_API_ENDPOINT, params=params, headers=headers)
if response.status_code == 200:
return response.json() # Return profile data as a dictionary
else:
print(f"Error fetching LinkedIn profile: {response.status_code}")
return {"error": f"Error fetching profile, status code: {response.status_code}"}

except Exception as e:
print(f"Error occurred during LinkedIn API proxy call: {e}")
return {"error": "An error occurred while fetching data from LinkedIn. Please try again later."}

@app.route('/', methods=['GET', 'POST'])
def index():
if request.method == 'POST':
career_goal = request.form['careerGoal']
manual_skills = request.form.getlist('skill[]')
linkedin_url = request.form.get('linkedinProfileUrl') # Changed to get LinkedIn profile URL
profile_data = None

if manual_skills or linkedin_url:
if linkedin_url:
profile_data = get_linkedin_profile(linkedin_url)
if 'skills' in profile_data:
skills_data = {"skills": profile_data['skills']}
else:
skills_data = {"skills": []}
else:
skills_data = {"skills": manual_skills}

with open('skills.json', 'w') as json_file:
json.dump(skills_data, json_file)

if linkedin_url:
profile_data = get_linkedin_profile(linkedin_url)
elif manual_skills:
profile_data = manual_skills

if profile_data:
if 'error' in profile_data:
return render_template('index.html', error=profile_data['error'])
gemini_response = get_gemini_response(career_goal, profile_data['skills'] if 'skills' in profile_data else manual_skills)
return render_template('index.html', profile_data=profile_data, gemini_response=gemini_response)
else:
return render_template('index.html', error="Please enter your career goal and skills.")

return render_template('index.html')

if __name__ == '__main__':
app.run(debug=True, use_reloader=False)
5 changes: 5 additions & 0 deletions Advanced_Projects/SkillSync/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Flask
requests
google-generativeai
pandas
dotenv
173 changes: 173 additions & 0 deletions Advanced_Projects/SkillSync/templates/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Skill Sync</title>
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
<!-- FontAwesome Icons for a more polished UI -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
<style>
body {
background-color: #f8f9fa;
}
h1 {
font-size: 2.5rem;
text-align: center;
margin-bottom: 40px;
color: #007bff;
}
form {
background-color: #fff;
padding: 30px;
border-radius: 8px;
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1);
}
.form-group label {
font-weight: bold;
}
.form-check-label {
font-size: 1rem;
}
.btn {
background-color: #007bff;
border-color: #007bff;
color: white;
font-size: 1.1rem;
padding: 10px 20px;
border-radius: 5px;
}
.btn:hover {
background-color: #0056b3;
border-color: #0056b3;
}
.analysis-section {
text-align: center;
margin-top: 50px;
}
.skill-list {
list-style: none;
padding: 0;
text-align: left;
}
.skill-list li {
padding: 10px 0;
border-bottom: 1px solid #ddd;
}
.form-group .dynamic-skill {
margin-top: 10px;
}
.btn-add-skill {
background-color: #28a745;
margin-left: 10px;
}
#manualSkillsInput input {
margin-bottom: 10px;
}
.btn-proceed {
margin-top: 20px;
background-color: #28a745;
}
</style>
</head>
<body>
<div class="container mt-5">
<h1><i class="fas fa-sync-alt"></i> Skill Sync</h1>
<form action="/" method="post">
<div class="form-group">
<label for="careerGoal"><i class="fas fa-bullseye"></i> Career Goal:</label>
<input type="text" class="form-control" id="careerGoal" name="careerGoal" placeholder="Enter your career goal">
</div>

<div class="form-check mb-3">
<input type="checkbox" class="form-check-input" id="manualSkills" name="manualSkills" onchange="toggleSkillsInput()">
<label class="form-check-label" for="manualSkills"><i class="fas fa-pencil-alt"></i> Manually add skills</label>
</div>

<div id="manualSkillsInput" style="display:none;">
<div class="form-group">
<label for="skill">Skill:</label>
<input type="text" class="form-control" id="skill" name="skill[]" placeholder="Enter a skill">
<button type="button" class="btn btn-add-skill mt-2" onclick="addSkill()"><i class="fas fa-plus-circle"></i> Add Skill</button>
</div>
</div>

<div class="form-check mb-3">
<input type="checkbox" class="form-check-input" id="linkedinSkills" name="linkedinSkills" onchange="toggleLinkedinInput()">
<label class="form-check-label" for="linkedinSkills"><i class="fab fa-linkedin"></i> Import skills from LinkedIn</label>
</div>

<div id="linkedinInput" style="display:none;">
<div class="form-group">
<label for="linkedinUsername"><i class="fab fa-linkedin"></i> LinkedIn Username:</label>
<input type="text" class="form-control" id="linkedinUsername" name="linkedinUsername" placeholder="Enter your LinkedIn username">
</div>
</div>

<button type="submit" class="btn btn-primary btn-block mt-4">Submit</button>
</form>

{% if profile_data %}
<div class="analysis-section">
{% if gemini_response %}
<h2>Skill Gap Analysis</h2>
<p>{{ gemini_response }}</p>
{% endif %}
{% if courses %}
<h2>Recommended Courses</h2>
<ul class="skill-list">
{% for course in courses %}
<li>{{ course }}</li>
{% endfor %}
</ul>
<button class="btn btn-proceed btn-lg" onclick="gotoHome()">Proceed to EduConnect</button>
{% endif %}
</div>
{% endif %}
</div>

<!-- Bootstrap JS and jQuery -->
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.5.4/dist/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>

<script>
function toggleSkillsInput() {
var manualSkillsInput = document.getElementById("manualSkillsInput");
if (document.getElementById("manualSkills").checked) {
manualSkillsInput.style.display = "block";
} else {
manualSkillsInput.style.display = "none";
}
}

function toggleLinkedinInput() {
var linkedinInput = document.getElementById("linkedinInput");
if (document.getElementById("linkedinSkills").checked) {
linkedinInput.style.display = "block";
} else {
linkedinInput.style.display = "none";
}
}

function addSkill() {
var skillInput = document.createElement("input");
skillInput.setAttribute("type", "text");
skillInput.setAttribute("class", "form-control dynamic-skill");
skillInput.setAttribute("name", "skill[]");

var skill = document.getElementById("skill").value.trim();
if (skill !== "") {
skillInput.value = skill;
document.getElementById("skill").value = "";
document.getElementById("manualSkillsInput").appendChild(skillInput);
}
}

function gotoHome(){
window.location.href = "http://localhost:5000";
}
</script>
</body>
</html>

0 comments on commit 2c31535

Please sign in to comment.