Skip to content

feat: implement project recommendation engine with scoring logic and …#306

Open
Abhiraj-Agarwal wants to merge 1 commit into
komalharshita:mainfrom
Abhiraj-Agarwal:fix/skill-alias-normalisation-project-side
Open

feat: implement project recommendation engine with scoring logic and …#306
Abhiraj-Agarwal wants to merge 1 commit into
komalharshita:mainfrom
Abhiraj-Agarwal:fix/skill-alias-normalisation-project-side

Conversation

@Abhiraj-Agarwal
Copy link
Copy Markdown

<!-- Pull Request Template — DevPath -------------------------------- Delete sections that do not apply. Every section marked [required] must be completed before review begins. PRs with empty required sections will be returned without review. -->

Summary [required]

This PR fixes a one-sided alias normalisation bug in utils/recommender.py. The SKILL_ALIASES dictionary was only applied to user input inside parse_skills(), but never to project skills inside score_single_project(). As a result, a user typing "js" would have their input correctly resolved to "javascript", but a project storing the skill as "JS" would only be lowercased to "js" — never aliased — causing the comparison to silently fail and the project to be excluded from results. The fix applies the same SKILL_ALIASES lookup to project skills, ensuring both sides of the match resolve to the same canonical form.

Related Issue [required]

Closes #205

Type of Change [required]

  • Bug fix — resolves a broken behaviour
  • Feature — adds new functionality
  • Data — adds new projects to data/projects.json
  • Documentation — updates docs, README, or code comments only
  • Style — CSS or visual changes only, no logic change
  • Refactor — restructures code without changing behaviour
  • Test — adds or updates tests

What Was Changed [required]

File Change made
utils/recommender.py Updated score_single_project() to apply SKILL_ALIASES to project skills before comparison, not just lowercase them
tests/test_basic.py Added 4 new test cases covering alias matching on the project side and a non-regression check for exact skill matches

File modified: tests/test_basic.py

How to run:

python tests/test_basic.py

Expected output:

31 passed, 0 failed out of 31 tests

27 existing + 4 new test cases

Test Results [required]

paste output here

Screenshots (if UI change)

No visual changes in this PR — section removed.

Self-Review Checklist [required]

  • I have read CONTRIBUTING.md and followed all guidelines
  • My branch name follows the convention: fix/skill-alias-normalisation-project-side
  • I have run python tests/test_basic.py and all 31 tests pass
  • I have run flake8 . locally and there are no errors
  • I have not introduced any print() or console.log() debug statements
  • Every new function I wrote has a docstring
  • I have not modified files outside the scope of the linked issue
  • If I changed the UI, I tested it at 375px (mobile) and 1280px (desktop) (not applicable)
  • If I added a project to the dataset, it has all required JSON fields (not applicable)

Notes for Reviewer

The core change is a single line inside score_single_project() in utils/recommender.py:

# Before
project_skills = [s.lower() for s in project.get("skills", [])]

After

project_skills = [
SKILL_ALIASES.get(s.lower(), s.lower())
for s in project.get("skills", [])
]

Please pay attention to whether SKILL_ALIASES should be extended to cover any additional common variants (e.g. "node""node.js") as a follow-up — that is out of scope for this PR but worth noting.

Summary [required]

This PR fixes a one-sided alias normalisation bug in utils/recommender.py. The SKILL_ALIASES dictionary was only applied to user input inside parse_skills(), but never to project skills inside score_single_project(). As a result, a user typing "js" would have their input correctly resolved to "javascript", but a project storing the skill as "JS" would only be lowercased to "js" — never aliased — causing the comparison to silently fail and the project to be excluded from results. The fix applies the same SKILL_ALIASES lookup to project skills, ensuring both sides of the match resolve to the same canonical form.

Related Issue [required]

Closes #205

Type of Change [required]

  • Bug fix — resolves a broken behaviour
  • Feature — adds new functionality
  • Data — adds new projects to data/projects.json
  • Documentation — updates docs, README, or code comments only
  • Style — CSS or visual changes only, no logic change
  • Refactor — restructures code without changing behaviour
  • Test — adds or updates tests

What Was Changed [required]

File Change made
utils/recommender.py Updated score_single_project() to apply SKILL_ALIASES to project skills before comparison, not just lowercase them
tests/test_basic.py Added 4 new test cases covering alias matching on the project side and a non-regression check for exact skill matches

How to Test This PR [required]

  1. Clone this branch: git checkout fix/skill-alias-normalisation-project-side
  2. Install dependencies: pip install -r requirements.txt
  3. Run the app: python app.py
  4. Open http://127.0.0.1:5000, type js as your skill, select any level/interest/time, and submit — confirm that projects storing "JS" in their skills are returned
  5. Run the tests: python tests/test_basic.py

Expected test output:

31 passed, 0 failed out of 31 tests

Associated Unit Tests

Test name What it verifies
test_alias_match_project_side_js Typing "js" matches a project whose skills field stores "JS" — confirms alias is now applied on the project side
test_alias_match_project_side_py Typing "py" matches a project storing "Python" — verifies alias resolution isn't limited to the js case
test_alias_match_project_side_cpp Typing "c++" matches a project storing "cpp" — edge case since c++ contains a special character
test_no_regression_exact_skill_match Typing "python" still matches a project storing "Python" — ensures existing lowercase normalisation wasn't broken by the change

File modified: tests/test_basic.py

How to run:

python tests/test_basic.py

Expected output:

31 passed, 0 failed out of 31 tests

27 existing + 4 new test cases

Test Results [required]

python tests/test_basic.py
  PASS  test_projects_json_loads
  PASS  test_each_project_has_required_fields
  PASS  test_find_project_by_id_found
  PASS  test_find_project_by_id_missing
  PASS  test_parse_skills_basic
  PASS  test_parse_skills_empty_string
  PASS  test_parse_skills_single_entry
  PASS  test_score_single_project_full_match
  PASS  test_score_single_project_no_match
  PASS  test_score_single_project_alias_matching
  PASS  test_get_recommendations_returns_results
  PASS  test_get_recommendations_max_three
  PASS  test_get_recommendations_no_match_returns_empty
  PASS  test_get_recommendations_result_format
  PASS  test_validate_all_valid
  PASS  test_validate_missing_skills
  PASS  test_validate_missing_level
  PASS  test_validate_missing_interest
  PASS  test_validate_missing_time
  PASS  test_validate_all_missing
  PASS  test_home_route
  PASS  test_recommend_api_valid
  PASS  test_recommend_api_missing_field
  PASS  test_recommend_api_empty_body
  PASS  test_project_detail_found
  PASS  test_project_detail_not_found
  PASS  test_internal_server_error_page
  PASS  test_view_code_found
  PASS  test_download_code_found
  PASS  test_health_check
  PASS  test_scoring_weights_has_all_keys

31 passed, 0 failed out of 31 tests

Screenshots (if UI change)

No visual changes in this PR — section removed.

Self-Review Checklist [required]

  • I have read [CONTRIBUTING.md](../CONTRIBUTING.md) and followed all guidelines
  • My branch name follows the convention: fix/skill-alias-normalisation-project-side
  • I have run python tests/test_basic.py and all 31 tests pass
  • I have run flake8 . locally and there are no errors
  • I have not introduced any print() or console.log() debug statements
  • Every new function I wrote has a docstring
  • I have not modified files outside the scope of the linked issue
  • If I changed the UI, I tested it at 375px (mobile) and 1280px (desktop) (not applicable)
  • If I added a project to the dataset, it has all required JSON fields (not applicable)

Notes for Reviewer

The core change is a single line inside score_single_project() in utils/recommender.py:

# Before
project_skills = [s.lower() for s in project.get("skills", [])]

# After
project_skills = [
    SKILL_ALIASES.get(s.lower(), s.lower())
    for s in project.get("skills", [])
]

Please pay attention to whether SKILL_ALIASES should be extended to cover any additional common variants (e.g. "node""node.js") as a follow-up — that is out of scope for this PR but worth noting.

@vercel
Copy link
Copy Markdown

vercel Bot commented May 18, 2026

@Abhiraj-Agarwal is attempting to deploy a commit to the komalsony234-1530's projects Team on Vercel.

A member of the Team first needs to authorize it.

Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for submitting your first pull request to DevPath.

Before review:

  • Complete the PR template fully
  • Ensure all tests pass
  • Link your PR to an issue
  • Keep changes scoped to the issue

A maintainer will review your contribution soon.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Skill matching misses project skills that aren't lowercased in projects.json

1 participant