Repository files navigation

SkillGraph

Turn a resume and job description into a prerequisite-aware learning plan.

SkillGraph extracts skills from both documents, estimates current mastery, finds gaps, and orders those gaps against a dependency graph. It then attaches learning resources from a curated catalog.

Pipeline

StageImplementationPurpose
Skill extractionall-MiniLM-L6-v2Match resume and job-description text to a predefined skill list
Optional fallbackGemini 1.5 FlashClassify sparse inputs against the same predefined list
Mastery scoringWeighted rulesCombine frequency, recency, and job relevance
Dependency graphNetworkX DAGIdentify missing prerequisites and valid next skills
Structural featureNode2Vec embeddingsRepresent each skill's position in the graph
Gap rankingLightGBM LambdaRankRank candidate skills using job weight, mastery, graph score, and degree
Path constructionGreedy frontier traversalChoose the highest-ranked skill whose prerequisites are met
Resource selectionCurated catalog lookupMatch each skill to a course or a direct learning-resource link

The local semantic matcher is the default. Gemini is used only when GEMINI_API_KEY is set and SKILLGRAPH_ENABLE_GEMINI=1.

Ranking model and evaluation

The committed LambdaRank dataset contains:

  • 1,000 synthetic profiles, split evenly across software engineering and data science
  • 19,756 skill-label pairs
  • Five features: job-description importance, Node2Vec score, mastery, in-degree, and out-degree

The checked-in training summary records NDCG@5 of 0.7913 and NDCG@10 of 0.8532 on the synthetic holdout split. These scores measure ranking agreement with paths generated by the graph algorithm. They do not measure learning outcomes or performance on real users.

Training inputs, scripts, and artifacts are committed for inspection:

ArtifactLocation
Synthetic databackend/training/synthetic_data.json
Training pipelinebackend/training/
LambdaRank modelbackend/models/ranker.lgb
Recorded metricsbackend/models/training_summary.md

Scoring logic

mastery(skill) = 0.31 * frequency + 0.336 * recency + 0.354 * job_match
gap = skill required by the job description and mastery(skill) < 0.6
priority(skill) = LightGBM(
job_importance,
node2vec_score,
mastery,
in_degree,
out_degree
)
path = repeatedly choose the highest-priority skill whose prerequisites are satisfied

Data and limits

  • The repository includes 45 curated courses. Domain filtering exposes 24 for software engineering and 22 for data science, including shared entries.
  • Skill extraction is constrained to the repository's domain lists. Unlisted skills may be missed or mapped to a nearby listed skill.
  • Course matching is deterministic, but a useful resource link is not evidence that the learning path itself is correct.
  • The ranking evaluation uses synthetic labels produced by the graph logic, not independent human labels.

The skill taxonomy and graph data reference the O*NET Occupational Database. The repository also includes links to the resume and job-description datasets used during development.

Quick start with Docker

docker compose up -d

Open the frontend at http://localhost:3000 and the API docs at http://localhost:8000/docs.

Local development

Backend

cd backend
pip install -r requirements.txt
uvicorn app.main:app --host 127.0.0.1 --port 8000 --reload

Frontend

cd frontend
npm install
npm run dev

Rebuild the model artifacts

bash backend/training/run_all_training.sh

On macOS, LightGBM may also require OpenMP:

export DYLD_LIBRARY_PATH="/opt/homebrew/opt/libomp/lib:$DYLD_LIBRARY_PATH"

About

Turn a resume and job description into a prerequisite-aware learning plan.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

SkillGraph

Turn a resume and job description into a prerequisite-aware learning plan.

SkillGraph extracts skills from both documents, estimates current mastery, finds gaps, and orders those gaps against a dependency graph. It then attaches learning resources from a curated catalog.

Pipeline

StageImplementationPurpose
Skill extractionall-MiniLM-L6-v2Match resume and job-description text to a predefined skill list
Optional fallbackGemini 1.5 FlashClassify sparse inputs against the same predefined list
Mastery scoringWeighted rulesCombine frequency, recency, and job relevance
Dependency graphNetworkX DAGIdentify missing prerequisites and valid next skills
Structural featureNode2Vec embeddingsRepresent each skill's position in the graph
Gap rankingLightGBM LambdaRankRank candidate skills using job weight, mastery, graph score, and degree
Path constructionGreedy frontier traversalChoose the highest-ranked skill whose prerequisites are met
Resource selectionCurated catalog lookupMatch each skill to a course or a direct learning-resource link

The local semantic matcher is the default. Gemini is used only when GEMINI_API_KEY is set and SKILLGRAPH_ENABLE_GEMINI=1.

Ranking model and evaluation

The committed LambdaRank dataset contains:

  • 1,000 synthetic profiles, split evenly across software engineering and data science
  • 19,756 skill-label pairs
  • Five features: job-description importance, Node2Vec score, mastery, in-degree, and out-degree

The checked-in training summary records NDCG@5 of 0.7913 and NDCG@10 of 0.8532 on the synthetic holdout split. These scores measure ranking agreement with paths generated by the graph algorithm. They do not measure learning outcomes or performance on real users.

Training inputs, scripts, and artifacts are committed for inspection:

ArtifactLocation
Synthetic databackend/training/synthetic_data.json
Training pipelinebackend/training/
LambdaRank modelbackend/models/ranker.lgb
Recorded metricsbackend/models/training_summary.md

Scoring logic

mastery(skill) = 0.31 * frequency + 0.336 * recency + 0.354 * job_match
gap = skill required by the job description and mastery(skill) < 0.6
priority(skill) = LightGBM(
job_importance,
node2vec_score,
mastery,
in_degree,
out_degree
)
path = repeatedly choose the highest-priority skill whose prerequisites are satisfied

Data and limits

  • The repository includes 45 curated courses. Domain filtering exposes 24 for software engineering and 22 for data science, including shared entries.
  • Skill extraction is constrained to the repository's domain lists. Unlisted skills may be missed or mapped to a nearby listed skill.
  • Course matching is deterministic, but a useful resource link is not evidence that the learning path itself is correct.
  • The ranking evaluation uses synthetic labels produced by the graph logic, not independent human labels.

The skill taxonomy and graph data reference the O*NET Occupational Database. The repository also includes links to the resume and job-description datasets used during development.

Quick start with Docker

docker compose up -d

Open the frontend at http://localhost:3000 and the API docs at http://localhost:8000/docs.

Local development

Backend

cd backend
pip install -r requirements.txt
uvicorn app.main:app --host 127.0.0.1 --port 8000 --reload

Frontend

cd frontend
npm install
npm run dev

Rebuild the model artifacts

bash backend/training/run_all_training.sh

On macOS, LightGBM may also require OpenMP:

export DYLD_LIBRARY_PATH="/opt/homebrew/opt/libomp/lib:$DYLD_LIBRARY_PATH"

About

Turn a resume and job description into a prerequisite-aware learning plan.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

SkillGraph

Turn a resume and job description into a prerequisite-aware learning plan.

SkillGraph extracts skills from both documents, estimates current mastery, finds gaps, and orders those gaps against a dependency graph. It then attaches learning resources from a curated catalog.

Pipeline

StageImplementationPurpose
Skill extractionall-MiniLM-L6-v2Match resume and job-description text to a predefined skill list
Optional fallbackGemini 1.5 FlashClassify sparse inputs against the same predefined list
Mastery scoringWeighted rulesCombine frequency, recency, and job relevance
Dependency graphNetworkX DAGIdentify missing prerequisites and valid next skills
Structural featureNode2Vec embeddingsRepresent each skill's position in the graph
Gap rankingLightGBM LambdaRankRank candidate skills using job weight, mastery, graph score, and degree
Path constructionGreedy frontier traversalChoose the highest-ranked skill whose prerequisites are met
Resource selectionCurated catalog lookupMatch each skill to a course or a direct learning-resource link

The local semantic matcher is the default. Gemini is used only when GEMINI_API_KEY is set and SKILLGRAPH_ENABLE_GEMINI=1.

Ranking model and evaluation

The committed LambdaRank dataset contains:

  • 1,000 synthetic profiles, split evenly across software engineering and data science
  • 19,756 skill-label pairs
  • Five features: job-description importance, Node2Vec score, mastery, in-degree, and out-degree

The checked-in training summary records NDCG@5 of 0.7913 and NDCG@10 of 0.8532 on the synthetic holdout split. These scores measure ranking agreement with paths generated by the graph algorithm. They do not measure learning outcomes or performance on real users.

Training inputs, scripts, and artifacts are committed for inspection:

ArtifactLocation
Synthetic databackend/training/synthetic_data.json
Training pipelinebackend/training/
LambdaRank modelbackend/models/ranker.lgb
Recorded metricsbackend/models/training_summary.md

Scoring logic

mastery(skill) = 0.31 * frequency + 0.336 * recency + 0.354 * job_match
gap = skill required by the job description and mastery(skill) < 0.6
priority(skill) = LightGBM(
job_importance,
node2vec_score,
mastery,
in_degree,
out_degree
)
path = repeatedly choose the highest-priority skill whose prerequisites are satisfied

Data and limits

  • The repository includes 45 curated courses. Domain filtering exposes 24 for software engineering and 22 for data science, including shared entries.
  • Skill extraction is constrained to the repository's domain lists. Unlisted skills may be missed or mapped to a nearby listed skill.
  • Course matching is deterministic, but a useful resource link is not evidence that the learning path itself is correct.
  • The ranking evaluation uses synthetic labels produced by the graph logic, not independent human labels.

The skill taxonomy and graph data reference the O*NET Occupational Database. The repository also includes links to the resume and job-description datasets used during development.

Quick start with Docker

docker compose up -d

Open the frontend at http://localhost:3000 and the API docs at http://localhost:8000/docs.

Local development

Backend

cd backend
pip install -r requirements.txt
uvicorn app.main:app --host 127.0.0.1 --port 8000 --reload

Frontend

cd frontend
npm install
npm run dev

Rebuild the model artifacts

bash backend/training/run_all_training.sh

On macOS, LightGBM may also require OpenMP:

export DYLD_LIBRARY_PATH="/opt/homebrew/opt/libomp/lib:$DYLD_LIBRARY_PATH"

About

Turn a resume and job description into a prerequisite-aware learning plan.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

SkillGraph

Turn a resume and job description into a prerequisite-aware learning plan.

SkillGraph extracts skills from both documents, estimates current mastery, finds gaps, and orders those gaps against a dependency graph. It then attaches learning resources from a curated catalog.

Pipeline

StageImplementationPurpose
Skill extractionall-MiniLM-L6-v2Match resume and job-description text to a predefined skill list
Optional fallbackGemini 1.5 FlashClassify sparse inputs against the same predefined list
Mastery scoringWeighted rulesCombine frequency, recency, and job relevance
Dependency graphNetworkX DAGIdentify missing prerequisites and valid next skills
Structural featureNode2Vec embeddingsRepresent each skill's position in the graph
Gap rankingLightGBM LambdaRankRank candidate skills using job weight, mastery, graph score, and degree
Path constructionGreedy frontier traversalChoose the highest-ranked skill whose prerequisites are met
Resource selectionCurated catalog lookupMatch each skill to a course or a direct learning-resource link

The local semantic matcher is the default. Gemini is used only when GEMINI_API_KEY is set and SKILLGRAPH_ENABLE_GEMINI=1.

Ranking model and evaluation

The committed LambdaRank dataset contains:

  • 1,000 synthetic profiles, split evenly across software engineering and data science
  • 19,756 skill-label pairs
  • Five features: job-description importance, Node2Vec score, mastery, in-degree, and out-degree

The checked-in training summary records NDCG@5 of 0.7913 and NDCG@10 of 0.8532 on the synthetic holdout split. These scores measure ranking agreement with paths generated by the graph algorithm. They do not measure learning outcomes or performance on real users.

Training inputs, scripts, and artifacts are committed for inspection:

ArtifactLocation
Synthetic databackend/training/synthetic_data.json
Training pipelinebackend/training/
LambdaRank modelbackend/models/ranker.lgb
Recorded metricsbackend/models/training_summary.md

Scoring logic

mastery(skill) = 0.31 * frequency + 0.336 * recency + 0.354 * job_match
gap = skill required by the job description and mastery(skill) < 0.6
priority(skill) = LightGBM(
job_importance,
node2vec_score,
mastery,
in_degree,
out_degree
)
path = repeatedly choose the highest-priority skill whose prerequisites are satisfied

Data and limits

  • The repository includes 45 curated courses. Domain filtering exposes 24 for software engineering and 22 for data science, including shared entries.
  • Skill extraction is constrained to the repository's domain lists. Unlisted skills may be missed or mapped to a nearby listed skill.
  • Course matching is deterministic, but a useful resource link is not evidence that the learning path itself is correct.
  • The ranking evaluation uses synthetic labels produced by the graph logic, not independent human labels.

The skill taxonomy and graph data reference the O*NET Occupational Database. The repository also includes links to the resume and job-description datasets used during development.

Quick start with Docker

docker compose up -d

Open the frontend at http://localhost:3000 and the API docs at http://localhost:8000/docs.

Local development

Backend

cd backend
pip install -r requirements.txt
uvicorn app.main:app --host 127.0.0.1 --port 8000 --reload

Frontend

cd frontend
npm install
npm run dev

Rebuild the model artifacts

bash backend/training/run_all_training.sh

On macOS, LightGBM may also require OpenMP:

export DYLD_LIBRARY_PATH="/opt/homebrew/opt/libomp/lib:$DYLD_LIBRARY_PATH"

About

Turn a resume and job description into a prerequisite-aware learning plan.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

SkillGraph

Turn a resume and job description into a prerequisite-aware learning plan.

SkillGraph extracts skills from both documents, estimates current mastery, finds gaps, and orders those gaps against a dependency graph. It then attaches learning resources from a curated catalog.

Pipeline

StageImplementationPurpose
Skill extractionall-MiniLM-L6-v2Match resume and job-description text to a predefined skill list
Optional fallbackGemini 1.5 FlashClassify sparse inputs against the same predefined list
Mastery scoringWeighted rulesCombine frequency, recency, and job relevance
Dependency graphNetworkX DAGIdentify missing prerequisites and valid next skills
Structural featureNode2Vec embeddingsRepresent each skill's position in the graph
Gap rankingLightGBM LambdaRankRank candidate skills using job weight, mastery, graph score, and degree
Path constructionGreedy frontier traversalChoose the highest-ranked skill whose prerequisites are met
Resource selectionCurated catalog lookupMatch each skill to a course or a direct learning-resource link

The local semantic matcher is the default. Gemini is used only when GEMINI_API_KEY is set and SKILLGRAPH_ENABLE_GEMINI=1.

Ranking model and evaluation

The committed LambdaRank dataset contains:

  • 1,000 synthetic profiles, split evenly across software engineering and data science
  • 19,756 skill-label pairs
  • Five features: job-description importance, Node2Vec score, mastery, in-degree, and out-degree

The checked-in training summary records NDCG@5 of 0.7913 and NDCG@10 of 0.8532 on the synthetic holdout split. These scores measure ranking agreement with paths generated by the graph algorithm. They do not measure learning outcomes or performance on real users.

Training inputs, scripts, and artifacts are committed for inspection:

ArtifactLocation
Synthetic databackend/training/synthetic_data.json
Training pipelinebackend/training/
LambdaRank modelbackend/models/ranker.lgb
Recorded metricsbackend/models/training_summary.md

Scoring logic

mastery(skill) = 0.31 * frequency + 0.336 * recency + 0.354 * job_match
gap = skill required by the job description and mastery(skill) < 0.6
priority(skill) = LightGBM(
job_importance,
node2vec_score,
mastery,
in_degree,
out_degree
)
path = repeatedly choose the highest-priority skill whose prerequisites are satisfied

Data and limits

  • The repository includes 45 curated courses. Domain filtering exposes 24 for software engineering and 22 for data science, including shared entries.
  • Skill extraction is constrained to the repository's domain lists. Unlisted skills may be missed or mapped to a nearby listed skill.
  • Course matching is deterministic, but a useful resource link is not evidence that the learning path itself is correct.
  • The ranking evaluation uses synthetic labels produced by the graph logic, not independent human labels.

The skill taxonomy and graph data reference the O*NET Occupational Database. The repository also includes links to the resume and job-description datasets used during development.

Quick start with Docker

docker compose up -d

Open the frontend at http://localhost:3000 and the API docs at http://localhost:8000/docs.

Local development

Backend

cd backend
pip install -r requirements.txt
uvicorn app.main:app --host 127.0.0.1 --port 8000 --reload

Frontend

cd frontend
npm install
npm run dev

Rebuild the model artifacts

bash backend/training/run_all_training.sh

On macOS, LightGBM may also require OpenMP:

export DYLD_LIBRARY_PATH="/opt/homebrew/opt/libomp/lib:$DYLD_LIBRARY_PATH"

About

Turn a resume and job description into a prerequisite-aware learning plan.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

SkillGraph

Turn a resume and job description into a prerequisite-aware learning plan.

SkillGraph extracts skills from both documents, estimates current mastery, finds gaps, and orders those gaps against a dependency graph. It then attaches learning resources from a curated catalog.

Pipeline

StageImplementationPurpose
Skill extractionall-MiniLM-L6-v2Match resume and job-description text to a predefined skill list
Optional fallbackGemini 1.5 FlashClassify sparse inputs against the same predefined list
Mastery scoringWeighted rulesCombine frequency, recency, and job relevance
Dependency graphNetworkX DAGIdentify missing prerequisites and valid next skills
Structural featureNode2Vec embeddingsRepresent each skill's position in the graph
Gap rankingLightGBM LambdaRankRank candidate skills using job weight, mastery, graph score, and degree
Path constructionGreedy frontier traversalChoose the highest-ranked skill whose prerequisites are met
Resource selectionCurated catalog lookupMatch each skill to a course or a direct learning-resource link

The local semantic matcher is the default. Gemini is used only when GEMINI_API_KEY is set and SKILLGRAPH_ENABLE_GEMINI=1.

Ranking model and evaluation

The committed LambdaRank dataset contains:

  • 1,000 synthetic profiles, split evenly across software engineering and data science
  • 19,756 skill-label pairs
  • Five features: job-description importance, Node2Vec score, mastery, in-degree, and out-degree

The checked-in training summary records NDCG@5 of 0.7913 and NDCG@10 of 0.8532 on the synthetic holdout split. These scores measure ranking agreement with paths generated by the graph algorithm. They do not measure learning outcomes or performance on real users.

Training inputs, scripts, and artifacts are committed for inspection:

ArtifactLocation
Synthetic databackend/training/synthetic_data.json
Training pipelinebackend/training/
LambdaRank modelbackend/models/ranker.lgb
Recorded metricsbackend/models/training_summary.md

Scoring logic

mastery(skill) = 0.31 * frequency + 0.336 * recency + 0.354 * job_match
gap = skill required by the job description and mastery(skill) < 0.6
priority(skill) = LightGBM(
job_importance,
node2vec_score,
mastery,
in_degree,
out_degree
)
path = repeatedly choose the highest-priority skill whose prerequisites are satisfied

Data and limits

  • The repository includes 45 curated courses. Domain filtering exposes 24 for software engineering and 22 for data science, including shared entries.
  • Skill extraction is constrained to the repository's domain lists. Unlisted skills may be missed or mapped to a nearby listed skill.
  • Course matching is deterministic, but a useful resource link is not evidence that the learning path itself is correct.
  • The ranking evaluation uses synthetic labels produced by the graph logic, not independent human labels.

The skill taxonomy and graph data reference the O*NET Occupational Database. The repository also includes links to the resume and job-description datasets used during development.

Quick start with Docker

docker compose up -d

Open the frontend at http://localhost:3000 and the API docs at http://localhost:8000/docs.

Local development

Backend

cd backend
pip install -r requirements.txt
uvicorn app.main:app --host 127.0.0.1 --port 8000 --reload

Frontend

cd frontend
npm install
npm run dev

Rebuild the model artifacts

bash backend/training/run_all_training.sh

On macOS, LightGBM may also require OpenMP:

export DYLD_LIBRARY_PATH="/opt/homebrew/opt/libomp/lib:$DYLD_LIBRARY_PATH"

About

Turn a resume and job description into a prerequisite-aware learning plan.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

SkillGraph

Turn a resume and job description into a prerequisite-aware learning plan.

SkillGraph extracts skills from both documents, estimates current mastery, finds gaps, and orders those gaps against a dependency graph. It then attaches learning resources from a curated catalog.

Pipeline

StageImplementationPurpose
Skill extractionall-MiniLM-L6-v2Match resume and job-description text to a predefined skill list
Optional fallbackGemini 1.5 FlashClassify sparse inputs against the same predefined list
Mastery scoringWeighted rulesCombine frequency, recency, and job relevance
Dependency graphNetworkX DAGIdentify missing prerequisites and valid next skills
Structural featureNode2Vec embeddingsRepresent each skill's position in the graph
Gap rankingLightGBM LambdaRankRank candidate skills using job weight, mastery, graph score, and degree
Path constructionGreedy frontier traversalChoose the highest-ranked skill whose prerequisites are met
Resource selectionCurated catalog lookupMatch each skill to a course or a direct learning-resource link

The local semantic matcher is the default. Gemini is used only when GEMINI_API_KEY is set and SKILLGRAPH_ENABLE_GEMINI=1.

Ranking model and evaluation

The committed LambdaRank dataset contains:

  • 1,000 synthetic profiles, split evenly across software engineering and data science
  • 19,756 skill-label pairs
  • Five features: job-description importance, Node2Vec score, mastery, in-degree, and out-degree

The checked-in training summary records NDCG@5 of 0.7913 and NDCG@10 of 0.8532 on the synthetic holdout split. These scores measure ranking agreement with paths generated by the graph algorithm. They do not measure learning outcomes or performance on real users.

Training inputs, scripts, and artifacts are committed for inspection:

ArtifactLocation
Synthetic databackend/training/synthetic_data.json
Training pipelinebackend/training/
LambdaRank modelbackend/models/ranker.lgb
Recorded metricsbackend/models/training_summary.md

Scoring logic

mastery(skill) = 0.31 * frequency + 0.336 * recency + 0.354 * job_match
gap = skill required by the job description and mastery(skill) < 0.6
priority(skill) = LightGBM(
job_importance,
node2vec_score,
mastery,
in_degree,
out_degree
)
path = repeatedly choose the highest-priority skill whose prerequisites are satisfied

Data and limits

  • The repository includes 45 curated courses. Domain filtering exposes 24 for software engineering and 22 for data science, including shared entries.
  • Skill extraction is constrained to the repository's domain lists. Unlisted skills may be missed or mapped to a nearby listed skill.
  • Course matching is deterministic, but a useful resource link is not evidence that the learning path itself is correct.
  • The ranking evaluation uses synthetic labels produced by the graph logic, not independent human labels.

The skill taxonomy and graph data reference the O*NET Occupational Database. The repository also includes links to the resume and job-description datasets used during development.

Quick start with Docker

docker compose up -d

Open the frontend at http://localhost:3000 and the API docs at http://localhost:8000/docs.

Local development

Backend

cd backend
pip install -r requirements.txt
uvicorn app.main:app --host 127.0.0.1 --port 8000 --reload

Frontend

cd frontend
npm install
npm run dev

Rebuild the model artifacts

bash backend/training/run_all_training.sh

On macOS, LightGBM may also require OpenMP:

export DYLD_LIBRARY_PATH="/opt/homebrew/opt/libomp/lib:$DYLD_LIBRARY_PATH"

About

Turn a resume and job description into a prerequisite-aware learning plan.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

SkillGraph

Turn a resume and job description into a prerequisite-aware learning plan.

SkillGraph extracts skills from both documents, estimates current mastery, finds gaps, and orders those gaps against a dependency graph. It then attaches learning resources from a curated catalog.

Pipeline

StageImplementationPurpose
Skill extractionall-MiniLM-L6-v2Match resume and job-description text to a predefined skill list
Optional fallbackGemini 1.5 FlashClassify sparse inputs against the same predefined list
Mastery scoringWeighted rulesCombine frequency, recency, and job relevance
Dependency graphNetworkX DAGIdentify missing prerequisites and valid next skills
Structural featureNode2Vec embeddingsRepresent each skill's position in the graph
Gap rankingLightGBM LambdaRankRank candidate skills using job weight, mastery, graph score, and degree
Path constructionGreedy frontier traversalChoose the highest-ranked skill whose prerequisites are met
Resource selectionCurated catalog lookupMatch each skill to a course or a direct learning-resource link

The local semantic matcher is the default. Gemini is used only when GEMINI_API_KEY is set and SKILLGRAPH_ENABLE_GEMINI=1.

Ranking model and evaluation

The committed LambdaRank dataset contains:

  • 1,000 synthetic profiles, split evenly across software engineering and data science
  • 19,756 skill-label pairs
  • Five features: job-description importance, Node2Vec score, mastery, in-degree, and out-degree

The checked-in training summary records NDCG@5 of 0.7913 and NDCG@10 of 0.8532 on the synthetic holdout split. These scores measure ranking agreement with paths generated by the graph algorithm. They do not measure learning outcomes or performance on real users.

Training inputs, scripts, and artifacts are committed for inspection:

ArtifactLocation
Synthetic databackend/training/synthetic_data.json
Training pipelinebackend/training/
LambdaRank modelbackend/models/ranker.lgb
Recorded metricsbackend/models/training_summary.md

Scoring logic

mastery(skill) = 0.31 * frequency + 0.336 * recency + 0.354 * job_match
gap = skill required by the job description and mastery(skill) < 0.6
priority(skill) = LightGBM(
job_importance,
node2vec_score,
mastery,
in_degree,
out_degree
)
path = repeatedly choose the highest-priority skill whose prerequisites are satisfied

Data and limits

  • The repository includes 45 curated courses. Domain filtering exposes 24 for software engineering and 22 for data science, including shared entries.
  • Skill extraction is constrained to the repository's domain lists. Unlisted skills may be missed or mapped to a nearby listed skill.
  • Course matching is deterministic, but a useful resource link is not evidence that the learning path itself is correct.
  • The ranking evaluation uses synthetic labels produced by the graph logic, not independent human labels.

The skill taxonomy and graph data reference the O*NET Occupational Database. The repository also includes links to the resume and job-description datasets used during development.

Quick start with Docker

docker compose up -d

Open the frontend at http://localhost:3000 and the API docs at http://localhost:8000/docs.

Local development

Backend

cd backend
pip install -r requirements.txt
uvicorn app.main:app --host 127.0.0.1 --port 8000 --reload

Frontend

cd frontend
npm install
npm run dev

Rebuild the model artifacts

bash backend/training/run_all_training.sh

On macOS, LightGBM may also require OpenMP:

export DYLD_LIBRARY_PATH="/opt/homebrew/opt/libomp/lib:$DYLD_LIBRARY_PATH"

About

Turn a resume and job description into a prerequisite-aware learning plan.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages